diff options
| author | Fuwn <[email protected]> | 2026-02-07 03:26:15 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-07 03:26:15 -0800 |
| commit | f2a5d1c04b9787bbd9f41af699345be6c0345ca8 (patch) | |
| tree | ffbbacd807f0d3d30efb7110058bd70d6404681e /apps/web/app/reader/_components/sidebar-content.tsx | |
| parent | style: lowercase all user-facing strings and add custom eslint rule (diff) | |
| download | asa.news-f2a5d1c04b9787bbd9f41af699345be6c0345ca8.tar.xz asa.news-f2a5d1c04b9787bbd9f41af699345be6c0345ca8.zip | |
feat: pre-ship polish — UI improvements, keyboard shortcuts, appearance settings
- Rename "muted keywords" to "muted phrases" throughout settings UI
- Add header with navigation to auth pages (sign-in, sign-up, etc.)
- Merge security tab (TOTP setup) into account settings tab
- Fix TOTP name input truncation on Safari (w-64 → flex-1 min-w-0)
- Add appearance settings: font size, time display format, entry images toggle, reading time toggle
- Add keyboard shortcuts dialog (? key) with all keybindings documented
- Add extended vim shortcuts: gg, G, n/N (next/prev unread), Ctrl+h/l (panel focus)
- Add command palette shortcut (⌘K) to shortcuts dialog
- Add icon URL fields for folders and custom feeds (DB + queries + settings UI)
- Add data-has-unreads attribute for sidebar keyboard navigation
- Fix SSR prerendering crash from Zustand persist and react-resizable-panels localStorage access
- Add detail panel layout persistence via useDefaultLayout
- Update marketing copy to advertise vim-like keyboard navigation
Diffstat (limited to 'apps/web/app/reader/_components/sidebar-content.tsx')
| -rw-r--r-- | apps/web/app/reader/_components/sidebar-content.tsx | 22 |
1 files changed, 15 insertions, 7 deletions
diff --git a/apps/web/app/reader/_components/sidebar-content.tsx b/apps/web/app/reader/_components/sidebar-content.tsx index ee5c873..be59390 100644 --- a/apps/web/app/reader/_components/sidebar-content.tsx +++ b/apps/web/app/reader/_components/sidebar-content.tsx @@ -96,7 +96,6 @@ export function SidebarContent() { const focusedSidebarIndex = useUserInterfaceStore( (state) => state.focusedSidebarIndex ) - function closeSidebarOnMobile() { if (typeof window !== "undefined" && window.innerWidth < 768) { toggleSidebar() @@ -138,6 +137,7 @@ export function SidebarContent() { <Link href="/reader" data-sidebar-nav-item + {...(totalUnreadCount > 0 ? { "data-has-unreads": "" } : {})} onClick={closeSidebarOnMobile} className={classNames( NAVIGATION_LINK_CLASS, @@ -189,7 +189,6 @@ export function SidebarContent() { > shares </Link> - {customFeedsData && customFeedsData.length > 0 && ( <div className="mt-3 space-y-0.5"> {customFeedsData.map((customFeed) => ( @@ -200,13 +199,16 @@ export function SidebarContent() { onClick={closeSidebarOnMobile} className={classNames( NAVIGATION_LINK_CLASS, - "truncate pl-4 text-[0.85em]", + "flex items-center gap-2 truncate pl-4 text-[0.85em]", activeCustomFeedIdentifier === customFeed.identifier && ACTIVE_LINK_CLASS, sidebarFocusClass(focusedPanel, focusedSidebarIndex, navIndex++) )} > - {customFeed.name} + {customFeed.iconUrl && ( + <img src={customFeed.iconUrl} alt="" width={16} height={16} className="shrink-0" loading="lazy" /> + )} + <span className="truncate">{customFeed.name}</span> </Link> ))} </div> @@ -219,6 +221,7 @@ export function SidebarContent() { key={subscription.subscriptionIdentifier} href={`/reader?feed=${subscription.feedIdentifier}`} data-sidebar-nav-item + {...((unreadCounts?.[subscription.feedIdentifier] ?? 0) > 0 ? { "data-has-unreads": "" } : {})} onClick={closeSidebarOnMobile} className={classNames( NAVIGATION_LINK_CLASS, @@ -268,6 +271,7 @@ export function SidebarContent() { <div key={folder.folderIdentifier} className="mt-2"> <div data-sidebar-nav-item + {...(folderUnreadCount > 0 ? { "data-has-unreads": "" } : {})} className={classNames( "flex w-full items-center gap-1 px-2 py-1", sidebarFocusClass(focusedPanel, focusedSidebarIndex, folderNavIndex) @@ -286,12 +290,15 @@ export function SidebarContent() { href={`/reader?folder=${folder.folderIdentifier}`} onClick={closeSidebarOnMobile} className={classNames( - "flex-1 truncate text-text-secondary transition-colors hover:text-text-primary", + "flex flex-1 items-center gap-2 truncate text-text-secondary transition-colors hover:text-text-primary", activeFolderIdentifier === folder.folderIdentifier && "text-text-primary" )} > - {folder.name} + {folder.iconUrl && ( + <img src={folder.iconUrl} alt="" width={16} height={16} className="shrink-0" loading="lazy" /> + )} + <span className="truncate">{folder.name}</span> </Link> <UnreadBadge count={folderUnreadCount} /> </div> @@ -302,6 +309,7 @@ export function SidebarContent() { key={subscription.subscriptionIdentifier} href={`/reader?feed=${subscription.feedIdentifier}`} data-sidebar-nav-item + {...((unreadCounts?.[subscription.feedIdentifier] ?? 0) > 0 ? { "data-has-unreads": "" } : {})} onClick={closeSidebarOnMobile} className={classNames( NAVIGATION_LINK_CLASS, @@ -338,7 +346,7 @@ export function SidebarContent() { ) })} - <div className="mt-3"> + <div className="mt-3 space-y-0.5"> <button type="button" data-sidebar-nav-item |