summaryrefslogtreecommitdiff
path: root/apps/web/app/reader/settings/_components/appearance-settings.tsx
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-07 01:42:57 -0800
committerFuwn <[email protected]>2026-02-07 01:42:57 -0800
commit5c5b1993edd890a80870ee05607ac5f088191d4e (patch)
treea721b76bcd49ba10826c53efc87302c7a689512f /apps/web/app/reader/settings/_components/appearance-settings.tsx
downloadasa.news-5c5b1993edd890a80870ee05607ac5f088191d4e.tar.xz
asa.news-5c5b1993edd890a80870ee05607ac5f088191d4e.zip
feat: asa.news RSS reader with developer tier, REST API, and webhooks
Full-stack RSS reader SaaS: Supabase + Next.js + Go worker. Includes three subscription tiers (free/pro/developer), API key auth, read-only REST API, webhook push notifications, Stripe billing with proration, and PWA support.
Diffstat (limited to 'apps/web/app/reader/settings/_components/appearance-settings.tsx')
-rw-r--r--apps/web/app/reader/settings/_components/appearance-settings.tsx123
1 files changed, 123 insertions, 0 deletions
diff --git a/apps/web/app/reader/settings/_components/appearance-settings.tsx b/apps/web/app/reader/settings/_components/appearance-settings.tsx
new file mode 100644
index 0000000..9c0e214
--- /dev/null
+++ b/apps/web/app/reader/settings/_components/appearance-settings.tsx
@@ -0,0 +1,123 @@
+"use client"
+
+import { useTheme } from "next-themes"
+import { useUserInterfaceStore } from "@/lib/stores/user-interface-store"
+
+export function AppearanceSettings() {
+ const { theme, setTheme } = useTheme()
+ const entryListViewMode = useUserInterfaceStore(
+ (state) => state.entryListViewMode
+ )
+ const setEntryListViewMode = useUserInterfaceStore(
+ (state) => state.setEntryListViewMode
+ )
+ const displayDensity = useUserInterfaceStore(
+ (state) => state.displayDensity
+ )
+ const setDisplayDensity = useUserInterfaceStore(
+ (state) => state.setDisplayDensity
+ )
+ const showFeedFavicons = useUserInterfaceStore(
+ (state) => state.showFeedFavicons
+ )
+ const setShowFeedFavicons = useUserInterfaceStore(
+ (state) => state.setShowFeedFavicons
+ )
+ const focusFollowsInteraction = useUserInterfaceStore(
+ (state) => state.focusFollowsInteraction
+ )
+ const setFocusFollowsInteraction = useUserInterfaceStore(
+ (state) => state.setFocusFollowsInteraction
+ )
+
+ return (
+ <div className="px-4 py-3">
+ <div className="mb-6">
+ <h3 className="mb-2 text-text-primary">theme</h3>
+ <p className="mb-3 text-text-dim">
+ controls the colour scheme of the application
+ </p>
+ <select
+ value={theme ?? "system"}
+ onChange={(event) => setTheme(event.target.value)}
+ className="border border-border bg-background-primary px-3 py-2 text-text-primary outline-none focus:border-text-dim"
+ >
+ <option value="system">system</option>
+ <option value="light">light</option>
+ <option value="dark">dark</option>
+ </select>
+ </div>
+ <div className="mb-6">
+ <h3 className="mb-2 text-text-primary">display density</h3>
+ <p className="mb-3 text-text-dim">
+ controls the overall text size and spacing
+ </p>
+ <select
+ value={displayDensity}
+ onChange={(event) =>
+ setDisplayDensity(
+ event.target.value as "compact" | "default" | "spacious"
+ )
+ }
+ className="border border-border bg-background-primary px-3 py-2 text-text-primary outline-none focus:border-text-dim"
+ >
+ <option value="compact">compact</option>
+ <option value="default">default</option>
+ <option value="spacious">spacious</option>
+ </select>
+ </div>
+ <div className="mb-6">
+ <h3 className="mb-2 text-text-primary">entry list view</h3>
+ <p className="mb-3 text-text-dim">
+ controls how entries are displayed in the list
+ </p>
+ <select
+ value={entryListViewMode}
+ onChange={(event) =>
+ setEntryListViewMode(
+ event.target.value as "compact" | "comfortable" | "expanded"
+ )
+ }
+ className="border border-border bg-background-primary px-3 py-2 text-text-primary outline-none focus:border-text-dim"
+ >
+ <option value="compact">compact</option>
+ <option value="comfortable">comfortable</option>
+ <option value="expanded">expanded</option>
+ </select>
+ </div>
+ <div className="mb-6">
+ <h3 className="mb-2 text-text-primary">feed favicons</h3>
+ <p className="mb-3 text-text-dim">
+ show website icons next to feed names in the sidebar
+ </p>
+ <label className="flex cursor-pointer items-center gap-2 text-text-primary">
+ <input
+ type="checkbox"
+ checked={showFeedFavicons}
+ onChange={(event) => setShowFeedFavicons(event.target.checked)}
+ className="accent-text-primary"
+ />
+ <span>show favicons</span>
+ </label>
+ </div>
+ <div>
+ <h3 className="mb-2 text-text-primary">focus follows interaction</h3>
+ <p className="mb-3 text-text-dim">
+ automatically move keyboard panel focus to the last pane you
+ interacted with (clicked or scrolled)
+ </p>
+ <label className="flex cursor-pointer items-center gap-2 text-text-primary">
+ <input
+ type="checkbox"
+ checked={focusFollowsInteraction}
+ onChange={(event) =>
+ setFocusFollowsInteraction(event.target.checked)
+ }
+ className="accent-text-primary"
+ />
+ <span>enable focus follows interaction</span>
+ </label>
+ </div>
+ </div>
+ )
+}