summaryrefslogtreecommitdiff
path: root/apps/web/app/reader/settings/_components/folders-settings.tsx
diff options
context:
space:
mode:
authorFuwn <[email protected]>2026-02-07 03:26:15 -0800
committerFuwn <[email protected]>2026-02-07 03:26:15 -0800
commitf2a5d1c04b9787bbd9f41af699345be6c0345ca8 (patch)
treeffbbacd807f0d3d30efb7110058bd70d6404681e /apps/web/app/reader/settings/_components/folders-settings.tsx
parentstyle: lowercase all user-facing strings and add custom eslint rule (diff)
downloadasa.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/settings/_components/folders-settings.tsx')
-rw-r--r--apps/web/app/reader/settings/_components/folders-settings.tsx80
1 files changed, 50 insertions, 30 deletions
diff --git a/apps/web/app/reader/settings/_components/folders-settings.tsx b/apps/web/app/reader/settings/_components/folders-settings.tsx
index 8a0012e..2c3d5f2 100644
--- a/apps/web/app/reader/settings/_components/folders-settings.tsx
+++ b/apps/web/app/reader/settings/_components/folders-settings.tsx
@@ -92,11 +92,13 @@ export function FoldersSettings() {
key={folder.folderIdentifier}
folderIdentifier={folder.folderIdentifier}
name={folder.name}
+ iconUrl={folder.iconUrl}
feedCount={feedCountForFolder(folder.folderIdentifier)}
- onRename={(name) =>
+ onSave={(name, iconUrl) =>
renameFolder.mutate({
folderIdentifier: folder.folderIdentifier,
name,
+ iconUrl,
})
}
onDelete={() =>
@@ -115,25 +117,28 @@ export function FoldersSettings() {
function FolderRow({
folderIdentifier,
name,
+ iconUrl,
feedCount,
- onRename,
+ onSave,
onDelete,
}: {
folderIdentifier: string
name: string
+ iconUrl: string | null
feedCount: number
- onRename: (name: string) => void
+ onSave: (name: string, iconUrl: string | null) => void
onDelete: () => void
}) {
const [isEditing, setIsEditing] = useState(false)
const [editedName, setEditedName] = useState(name)
+ const [editedIconUrl, setEditedIconUrl] = useState(iconUrl ?? "")
const [showDeleteConfirm, setShowDeleteConfirm] = useState(false)
function handleSave() {
const trimmedName = editedName.trim()
- if (trimmedName && trimmedName !== name) {
- onRename(trimmedName)
+ if (trimmedName) {
+ onSave(trimmedName, editedIconUrl.trim() || null)
}
setIsEditing(false)
@@ -143,36 +148,51 @@ function FolderRow({
<div className="flex items-center justify-between border-b border-border px-4 py-3 last:border-b-0">
<div className="min-w-0 flex-1">
{isEditing ? (
- <div className="flex items-center gap-2">
+ <div className="space-y-2">
+ <div className="flex items-center gap-2">
+ <input
+ type="text"
+ value={editedName}
+ onChange={(event) => setEditedName(event.target.value)}
+ className="min-w-0 flex-1 border border-border bg-background-primary px-2 py-1 text-text-primary outline-none focus:border-text-dim"
+ onKeyDown={(event) => {
+ if (event.key === "Enter") handleSave()
+ if (event.key === "Escape") setIsEditing(false)
+ }}
+ autoFocus
+ />
+ </div>
<input
type="text"
- value={editedName}
- onChange={(event) => setEditedName(event.target.value)}
- className="min-w-0 flex-1 border border-border bg-background-primary px-2 py-1 text-text-primary outline-none focus:border-text-dim"
- onKeyDown={(event) => {
- if (event.key === "Enter") handleSave()
- if (event.key === "Escape") setIsEditing(false)
- }}
- autoFocus
+ value={editedIconUrl}
+ onChange={(event) => setEditedIconUrl(event.target.value)}
+ placeholder="icon url (optional)"
+ className="w-full border border-border bg-background-primary px-2 py-1 text-text-primary outline-none placeholder:text-text-dim focus:border-text-dim"
/>
- <button
- onClick={handleSave}
- className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
- >
- save
- </button>
- <button
- onClick={() => {
- setEditedName(name)
- setIsEditing(false)
- }}
- className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
- >
- cancel
- </button>
+ <div className="flex gap-2">
+ <button
+ onClick={handleSave}
+ className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
+ >
+ save
+ </button>
+ <button
+ onClick={() => {
+ setEditedName(name)
+ setEditedIconUrl(iconUrl ?? "")
+ setIsEditing(false)
+ }}
+ className="px-2 py-1 text-text-secondary transition-colors hover:text-text-primary"
+ >
+ cancel
+ </button>
+ </div>
</div>
) : (
<div className="flex items-center gap-2">
+ {iconUrl && (
+ <img src={iconUrl} alt="" width={16} height={16} className="shrink-0" />
+ )}
<span className="text-text-primary">{name}</span>
<span className="text-text-dim">
({feedCount} feed{feedCount !== 1 && "s"})
@@ -181,7 +201,7 @@ function FolderRow({
onClick={() => setIsEditing(true)}
className="px-2 py-1 text-text-dim transition-colors hover:text-text-secondary"
>
- rename
+ edit
</button>
</div>
)}