diff options
| author | Fuwn <[email protected]> | 2026-02-10 02:23:37 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-10 02:23:37 -0800 |
| commit | d7051b1f6450a3de7fd2a89357780a83cf3db80e (patch) | |
| tree | e9249a5cf98d9cbc4f9faed979dd3146da0c5c69 | |
| parent | fix: remove font size selector, always use default text-base (diff) | |
| download | asa.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.css | 43 | ||||
| -rw-r--r-- | apps/web/app/providers.tsx | 17 | ||||
| -rw-r--r-- | apps/web/app/reader/settings/_components/appearance-settings.tsx | 25 | ||||
| -rw-r--r-- | apps/web/lib/stores/user-interface-store.ts | 8 |
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, |