diff options
| author | Fuwn <[email protected]> | 2026-02-10 02:11:41 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-10 02:11:41 -0800 |
| commit | 566aff236740d82def2a51c73642fdcbaf382931 (patch) | |
| tree | 2d8c5e20071f4e25bb10ecb0d0c637ba0a1b6d9e /apps | |
| parent | feat: add Go worker tests and include in CI (diff) | |
| download | asa.news-566aff236740d82def2a51c73642fdcbaf382931.tar.xz asa.news-566aff236740d82def2a51c73642fdcbaf382931.zip | |
feat: add unread priority option to push unread entries to top
Adds a persisted appearance setting (disabled by default) that
partitions the entry list into unread-first, preserving original
order within each group.
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/app/reader/_components/entry-list.tsx | 15 | ||||
| -rw-r--r-- | apps/web/app/reader/settings/_components/appearance-settings.tsx | 21 | ||||
| -rw-r--r-- | apps/web/lib/stores/user-interface-store.ts | 7 |
3 files changed, 42 insertions, 1 deletions
diff --git a/apps/web/app/reader/_components/entry-list.tsx b/apps/web/app/reader/_components/entry-list.tsx index cf75620..7786e55 100644 --- a/apps/web/app/reader/_components/entry-list.tsx +++ b/apps/web/app/reader/_components/entry-list.tsx @@ -72,7 +72,20 @@ export function EntryList({ (state) => state.setNavigableEntryIdentifiers ) - const allEntries = data?.pages.flatMap((page) => page) ?? [] + const prioritiseUnreadEntries = useUserInterfaceStore( + (state) => state.prioritiseUnreadEntries + ) + + const allEntries = useMemo(() => { + const flatEntries = data?.pages.flatMap((page) => page) ?? [] + + if (!prioritiseUnreadEntries) return flatEntries + + const unreadEntries = flatEntries.filter((entry) => !entry.isRead) + const readEntries = flatEntries.filter((entry) => entry.isRead) + + return [...unreadEntries, ...readEntries] + }, [data, prioritiseUnreadEntries]) const scrollContainerReference = useRef<HTMLDivElement>(null) const firstEntryIdentifier = allEntries[0]?.entryIdentifier diff --git a/apps/web/app/reader/settings/_components/appearance-settings.tsx b/apps/web/app/reader/settings/_components/appearance-settings.tsx index 9d2d146..9e03702 100644 --- a/apps/web/app/reader/settings/_components/appearance-settings.tsx +++ b/apps/web/app/reader/settings/_components/appearance-settings.tsx @@ -80,6 +80,12 @@ export function AppearanceSettings() { const setShowFoldersAboveFeeds = useUserInterfaceStore( (state) => state.setShowFoldersAboveFeeds ) + const prioritiseUnreadEntries = useUserInterfaceStore( + (state) => state.prioritiseUnreadEntries + ) + const setPrioritiseUnreadEntries = useUserInterfaceStore( + (state) => state.setPrioritiseUnreadEntries + ) const autoRefreshTimeline = useUserInterfaceStore( (state) => state.autoRefreshTimeline ) @@ -249,6 +255,21 @@ export function AppearanceSettings() { <option value="absolute">absolute</option> </select> </div> + <div> + <h3 className="mb-2 text-text-primary">unread priority</h3> + <p className="mb-3 text-text-dim"> + push unread articles to the top of the entry list + </p> + <label className="flex cursor-pointer items-center gap-2 text-text-primary"> + <input + type="checkbox" + checked={prioritiseUnreadEntries} + onChange={(event) => setPrioritiseUnreadEntries(event.target.checked)} + className="accent-text-primary" + /> + <span>prioritise unread entries</span> + </label> + </div> </SettingsSection> <SettingsSection title="sidebar"> diff --git a/apps/web/lib/stores/user-interface-store.ts b/apps/web/lib/stores/user-interface-store.ts index 814b0d6..808273c 100644 --- a/apps/web/lib/stores/user-interface-store.ts +++ b/apps/web/lib/stores/user-interface-store.ts @@ -46,6 +46,7 @@ interface UserInterfaceState { showFoldersAboveFeeds: boolean showEntryFavicons: boolean autoRefreshTimeline: boolean + prioritiseUnreadEntries: boolean toolbarPosition: ToolbarPosition isEntryListAtTop: boolean isShortcutsDialogOpen: boolean @@ -79,6 +80,7 @@ interface UserInterfaceState { setShowFoldersAboveFeeds: (show: boolean) => void setShowEntryFavicons: (show: boolean) => void setAutoRefreshTimeline: (enabled: boolean) => void + setPrioritiseUnreadEntries: (enabled: boolean) => void setToolbarPosition: (position: ToolbarPosition) => void setIsEntryListAtTop: (isAtTop: boolean) => void setShortcutsDialogOpen: (isOpen: boolean) => void @@ -112,6 +114,7 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( showFoldersAboveFeeds: false, showEntryFavicons: false, autoRefreshTimeline: false, + prioritiseUnreadEntries: false, toolbarPosition: "top", isEntryListAtTop: true, isShortcutsDialogOpen: false, @@ -176,6 +179,9 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( setAutoRefreshTimeline: (enabled) => set({ autoRefreshTimeline: enabled }), + setPrioritiseUnreadEntries: (enabled) => + set({ prioritiseUnreadEntries: enabled }), + setToolbarPosition: (position) => set({ toolbarPosition: position }), setIsEntryListAtTop: (isAtTop) => set({ isEntryListAtTop: isAtTop }), @@ -233,6 +239,7 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( showFoldersAboveFeeds: state.showFoldersAboveFeeds, showEntryFavicons: state.showEntryFavicons, autoRefreshTimeline: state.autoRefreshTimeline, + prioritiseUnreadEntries: state.prioritiseUnreadEntries, toolbarPosition: state.toolbarPosition, }), } |