diff options
| author | Fuwn <[email protected]> | 2026-02-08 00:11:57 -0800 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2026-02-08 00:11:57 -0800 |
| commit | 6398c56662c9c078db411f382bfac0f3b0803a07 (patch) | |
| tree | f8e67acbb1ebe6c9bc90d84b13ebeaad3d7c7ae6 /apps | |
| parent | feat: add appearance option to toggle folders above/below ungrouped feeds in ... (diff) | |
| download | asa.news-6398c56662c9c078db411f382bfac0f3b0803a07.tar.xz asa.news-6398c56662c9c078db411f382bfac0f3b0803a07.zip | |
feat: add option to show favicons next to feed names in entry list
Diffstat (limited to 'apps')
| -rw-r--r-- | apps/web/app/reader/_components/entry-list-item.tsx | 23 | ||||
| -rw-r--r-- | apps/web/app/reader/settings/_components/appearance-settings.tsx | 21 | ||||
| -rw-r--r-- | apps/web/lib/stores/user-interface-store.ts | 6 |
3 files changed, 50 insertions, 0 deletions
diff --git a/apps/web/app/reader/_components/entry-list-item.tsx b/apps/web/app/reader/_components/entry-list-item.tsx index 1669658..7473037 100644 --- a/apps/web/app/reader/_components/entry-list-item.tsx +++ b/apps/web/app/reader/_components/entry-list-item.tsx @@ -6,6 +6,15 @@ import { useUserInterfaceStore } from "@/lib/stores/user-interface-store" import type { TimelineEntry } from "@/lib/types/timeline" import type { VirtualItem } from "@tanstack/react-virtual" +function getEntryFaviconUrl(entryUrl: string): string | null { + try { + const hostname = new URL(entryUrl).hostname + return `https://www.google.com/s2/favicons?domain=${hostname}&sz=16` + } catch { + return null + } +} + interface EntryListItemProperties { entry: TimelineEntry isSelected: boolean @@ -35,6 +44,11 @@ export function EntryListItem({ const showEntryImages = useUserInterfaceStore( (state) => state.showEntryImages ) + const showEntryFavicons = useUserInterfaceStore( + (state) => state.showEntryFavicons + ) + + const faviconUrl = showEntryFavicons ? getEntryFaviconUrl(entry.entryUrl) : null const formattedTimestamp = entry.publishedAt ? timeDisplayFormat === "absolute" @@ -64,6 +78,9 @@ export function EntryListItem({ > {viewMode === "compact" && ( <div className="flex items-center gap-2 py-2.5"> + {faviconUrl && ( + <img src={faviconUrl} alt="" width={16} height={16} className="shrink-0" loading="lazy" /> + )} <span className="shrink-0 text-text-dim">{displayTitle}</span> {entry.enclosureUrl && ( <span className="shrink-0 text-text-dim" title="podcast episode">♫</span> @@ -79,6 +96,9 @@ export function EntryListItem({ <div className="py-2.5"> <div className="truncate text-text-primary">{entry.entryTitle}</div> <div className="mt-0.5 flex items-center gap-2 text-text-dim"> + {faviconUrl && ( + <img src={faviconUrl} alt="" width={16} height={16} className="shrink-0" loading="lazy" /> + )} <span>{displayTitle}</span> {entry.enclosureUrl && ( <span title="podcast episode">♫</span> @@ -107,6 +127,9 @@ export function EntryListItem({ </p> )} <div className="mt-1 flex items-center gap-2 text-text-dim"> + {faviconUrl && ( + <img src={faviconUrl} alt="" width={16} height={16} className="shrink-0" loading="lazy" /> + )} <span>{displayTitle}</span> {entry.enclosureUrl && ( <span title="podcast episode">♫</span> diff --git a/apps/web/app/reader/settings/_components/appearance-settings.tsx b/apps/web/app/reader/settings/_components/appearance-settings.tsx index aaf499a..458d2b6 100644 --- a/apps/web/app/reader/settings/_components/appearance-settings.tsx +++ b/apps/web/app/reader/settings/_components/appearance-settings.tsx @@ -49,6 +49,12 @@ export function AppearanceSettings() { const setShowReadingTime = useUserInterfaceStore( (state) => state.setShowReadingTime ) + const showEntryFavicons = useUserInterfaceStore( + (state) => state.showEntryFavicons + ) + const setShowEntryFavicons = useUserInterfaceStore( + (state) => state.setShowEntryFavicons + ) const showFoldersAboveFeeds = useUserInterfaceStore( (state) => state.showFoldersAboveFeeds ) @@ -126,6 +132,21 @@ export function AppearanceSettings() { </label> </div> <div className="mb-6"> + <h3 className="mb-2 text-text-primary">entry favicons</h3> + <p className="mb-3 text-text-dim"> + show website icons next to feed names in the entry list + </p> + <label className="flex cursor-pointer items-center gap-2 text-text-primary"> + <input + type="checkbox" + checked={showEntryFavicons} + onChange={(event) => setShowEntryFavicons(event.target.checked)} + className="accent-text-primary" + /> + <span>show entry favicons</span> + </label> + </div> + <div className="mb-6"> <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 diff --git a/apps/web/lib/stores/user-interface-store.ts b/apps/web/lib/stores/user-interface-store.ts index f25152c..3d3b0b6 100644 --- a/apps/web/lib/stores/user-interface-store.ts +++ b/apps/web/lib/stores/user-interface-store.ts @@ -42,6 +42,7 @@ interface UserInterfaceState { showEntryImages: boolean showReadingTime: boolean showFoldersAboveFeeds: boolean + showEntryFavicons: boolean isShortcutsDialogOpen: boolean expandedFolderIdentifiers: string[] navigableEntryIdentifiers: string[] @@ -67,6 +68,7 @@ interface UserInterfaceState { setShowEntryImages: (show: boolean) => void setShowReadingTime: (show: boolean) => void setShowFoldersAboveFeeds: (show: boolean) => void + setShowEntryFavicons: (show: boolean) => void setShortcutsDialogOpen: (isOpen: boolean) => void toggleShortcutsDialog: () => void toggleFolderExpansion: (folderIdentifier: string) => void @@ -96,6 +98,7 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( showEntryImages: true, showReadingTime: true, showFoldersAboveFeeds: false, + showEntryFavicons: false, isShortcutsDialogOpen: false, expandedFolderIdentifiers: [], navigableEntryIdentifiers: [], @@ -145,6 +148,8 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( setShowFoldersAboveFeeds: (show) => set({ showFoldersAboveFeeds: show }), + setShowEntryFavicons: (show) => set({ showEntryFavicons: show }), + setShortcutsDialogOpen: (isOpen) => set({ isShortcutsDialogOpen: isOpen }), @@ -196,6 +201,7 @@ export const useUserInterfaceStore = create<UserInterfaceState>()( showEntryImages: state.showEntryImages, showReadingTime: state.showReadingTime, showFoldersAboveFeeds: state.showFoldersAboveFeeds, + showEntryFavicons: state.showEntryFavicons, }), } ) |