summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-10 02:23:37 -0800
committerFuwn <[email protected]>2026-02-10 02:23:37 -0800
commitd7051b1f6450a3de7fd2a89357780a83cf3db80e (patch)
treee9249a5cf98d9cbc4f9faed979dd3146da0c5c69
parentfix: remove font size selector, always use default text-base (diff)
downloadasa.news-d7051b1f6450a3de7fd2a89357780a83cf3db80e.tar.xz
asa.news-d7051b1f6450a3de7fd2a89357780a83cf3db80e.zip
feat: add scrollbar style setting (themed/native/hidden)
Themed scrollbars (default) use 6px thin bars matching the existing colour palette. Synced to body via class toggle in Providers.
-rw-r--r--apps/web/app/globals.css43
-rw-r--r--apps/web/app/providers.tsx17
-rw-r--r--apps/web/app/reader/settings/_components/appearance-settings.tsx25
-rw-r--r--apps/web/lib/stores/user-interface-store.ts8
4 files changed, 93 insertions, 0 deletions
diff --git a/apps/web/app/globals.css b/apps/web/app/globals.css
index c97ddb2..7c693e9 100644
--- a/apps/web/app/globals.css
+++ b/apps/web/app/globals.css
@@ -220,3 +220,46 @@ body {
background-color: rgba(234, 179, 8, 0.15);
border-bottom-color: rgba(234, 179, 8, 0.35);
}
+
+.scrollbar-custom ::-webkit-scrollbar {
+ width: 6px;
+ height: 6px;
+}
+
+.scrollbar-custom ::-webkit-scrollbar-track {
+ background: transparent;
+}
+
+.scrollbar-custom ::-webkit-scrollbar-thumb {
+ background: var(--color-border);
+}
+
+.scrollbar-custom ::-webkit-scrollbar-thumb:hover {
+ background: var(--color-text-dim);
+}
+
+.scrollbar-custom ::-webkit-scrollbar-corner {
+ background: transparent;
+}
+
+.scrollbar-custom {
+ scrollbar-width: thin;
+ scrollbar-color: var(--color-border) transparent;
+}
+
+.scrollbar-custom * {
+ scrollbar-width: thin;
+ scrollbar-color: var(--color-border) transparent;
+}
+
+.scrollbar-hidden ::-webkit-scrollbar {
+ display: none;
+}
+
+.scrollbar-hidden {
+ scrollbar-width: none;
+}
+
+.scrollbar-hidden * {
+ scrollbar-width: none;
+}
diff --git a/apps/web/app/providers.tsx b/apps/web/app/providers.tsx
index 550b30c..45f5c1b 100644
--- a/apps/web/app/providers.tsx
+++ b/apps/web/app/providers.tsx
@@ -6,6 +6,7 @@ import { Toaster } from "sonner"
import { createQueryClient, MUTATION_KEYS } from "@/lib/query-client"
import { createIndexedDatabasePersister } from "@/lib/indexed-database-persister"
import { createSupabaseBrowserClient } from "@/lib/supabase/client"
+import { useUserInterfaceStore } from "@/lib/stores/user-interface-store"
const PERSISTABLE_QUERY_KEY_PREFIXES = [
"timeline",
@@ -89,11 +90,27 @@ function useResumableMutations(queryClient: ReturnType<typeof createQueryClient>
}, [queryClient])
}
+function useScrollbarStyleSync() {
+ const scrollbarStyle = useUserInterfaceStore((state) => state.scrollbarStyle)
+
+ useEffect(() => {
+ const bodyElement = document.body
+ bodyElement.classList.remove("scrollbar-custom", "scrollbar-hidden")
+
+ if (scrollbarStyle === "custom") {
+ bodyElement.classList.add("scrollbar-custom")
+ } else if (scrollbarStyle === "hidden") {
+ bodyElement.classList.add("scrollbar-hidden")
+ }
+ }, [scrollbarStyle])
+}
+
export function Providers({ children }: { children: React.ReactNode }) {
const [queryClient] = useState(createQueryClient)
const [persister] = useState(createIndexedDatabasePersister)
useResumableMutations(queryClient)
+ useScrollbarStyleSync()
return (
<PersistQueryClientProvider
diff --git a/apps/web/app/reader/settings/_components/appearance-settings.tsx b/apps/web/app/reader/settings/_components/appearance-settings.tsx
index 5068937..e1a6ecf 100644
--- a/apps/web/app/reader/settings/_components/appearance-settings.tsx
+++ b/apps/web/app/reader/settings/_components/appearance-settings.tsx
@@ -90,6 +90,12 @@ export function AppearanceSettings() {
const setAutoRefreshTimeline = useUserInterfaceStore(
(state) => state.setAutoRefreshTimeline
)
+ const scrollbarStyle = useUserInterfaceStore(
+ (state) => state.scrollbarStyle
+ )
+ const setScrollbarStyle = useUserInterfaceStore(
+ (state) => state.setScrollbarStyle
+ )
const toolbarPosition = useUserInterfaceStore(
(state) => state.toolbarPosition
)
@@ -150,6 +156,25 @@ export function AppearanceSettings() {
<option value="bottom">bottom</option>
</select>
</div>
+ <div>
+ <h3 className="mb-2 text-text-primary">scrollbars</h3>
+ <p className="mb-3 text-text-dim">
+ choose between themed scrollbars, platform native, or hidden
+ </p>
+ <select
+ value={scrollbarStyle}
+ onChange={(event) =>
+ setScrollbarStyle(
+ event.target.value as "custom" | "native" | "hidden"
+ )
+ }
+ className="border border-border bg-background-primary px-3 py-2 text-text-primary outline-none focus:border-text-dim"
+ >
+ <option value="custom">themed</option>
+ <option value="native">native</option>
+ <option value="hidden">hidden</option>
+ </select>
+ </div>
</SettingsSection>
<SettingsSection title="entry list">
diff --git a/apps/web/lib/stores/user-interface-store.ts b/apps/web/lib/stores/user-interface-store.ts
index 808273c..29841ec 100644
--- a/apps/web/lib/stores/user-interface-store.ts
+++ b/apps/web/lib/stores/user-interface-store.ts
@@ -9,6 +9,8 @@ type FontSize = "small" | "default" | "large"
type TimeDisplayFormat = "relative" | "absolute"
+type ScrollbarStyle = "custom" | "native" | "hidden"
+
type ToolbarPosition = "top" | "bottom"
type FocusedPanel = "sidebar" | "entryList" | "detailPanel"
@@ -45,6 +47,7 @@ interface UserInterfaceState {
showReadingTime: boolean
showFoldersAboveFeeds: boolean
showEntryFavicons: boolean
+ scrollbarStyle: ScrollbarStyle
autoRefreshTimeline: boolean
prioritiseUnreadEntries: boolean
toolbarPosition: ToolbarPosition
@@ -79,6 +82,7 @@ interface UserInterfaceState {
setShowReadingTime: (show: boolean) => void
setShowFoldersAboveFeeds: (show: boolean) => void
setShowEntryFavicons: (show: boolean) => void
+ setScrollbarStyle: (style: ScrollbarStyle) => void
setAutoRefreshTimeline: (enabled: boolean) => void
setPrioritiseUnreadEntries: (enabled: boolean) => void
setToolbarPosition: (position: ToolbarPosition) => void
@@ -113,6 +117,7 @@ export const useUserInterfaceStore = create<UserInterfaceState>()(
showReadingTime: true,
showFoldersAboveFeeds: false,
showEntryFavicons: false,
+ scrollbarStyle: "custom",
autoRefreshTimeline: false,
prioritiseUnreadEntries: false,
toolbarPosition: "top",
@@ -176,6 +181,8 @@ export const useUserInterfaceStore = create<UserInterfaceState>()(
setShowEntryFavicons: (show) => set({ showEntryFavicons: show }),
+ setScrollbarStyle: (style) => set({ scrollbarStyle: style }),
+
setAutoRefreshTimeline: (enabled) =>
set({ autoRefreshTimeline: enabled }),
@@ -238,6 +245,7 @@ export const useUserInterfaceStore = create<UserInterfaceState>()(
showReadingTime: state.showReadingTime,
showFoldersAboveFeeds: state.showFoldersAboveFeeds,
showEntryFavicons: state.showEntryFavicons,
+ scrollbarStyle: state.scrollbarStyle,
autoRefreshTimeline: state.autoRefreshTimeline,
prioritiseUnreadEntries: state.prioritiseUnreadEntries,
toolbarPosition: state.toolbarPosition,