From 5efb29cda9e73d94e7acbb9aa23b9657099a7e0b Mon Sep 17 00:00:00 2001 From: Richard R Date: Thu, 14 May 2026 10:01:51 -0600 Subject: [PATCH] refactor(ui): restructure settings modal navigation and changelog panel logic Update SettingsModal to use conditional rendering for the changelog panel, displaying the main settings navigation only when the changelog is closed. Refactor mobile and desktop navigation layout to improve maintainability. Add missing ChevronRightIcon import for icon consistency. --- src/components/SettingsModal.tsx | 153 +++++++++++++++++-------------- 1 file changed, 85 insertions(+), 68 deletions(-) diff --git a/src/components/SettingsModal.tsx b/src/components/SettingsModal.tsx index eeeb4a2..c9bc620 100644 --- a/src/components/SettingsModal.tsx +++ b/src/components/SettingsModal.tsx @@ -17,7 +17,7 @@ import { import Link from 'next/link'; import { useTheme } from '@/contexts/ThemeContext'; import { useConfig } from '@/contexts/ConfigContext'; -import { ChevronUpDownIcon, CheckIcon, SettingsIcon, KeyIcon, PaletteIcon, DocumentIcon, UserIcon, DownloadIcon } from '@/components/icons/Icons'; +import { ChevronUpDownIcon, CheckIcon, SettingsIcon, KeyIcon, PaletteIcon, DocumentIcon, UserIcon, DownloadIcon, ChevronRightIcon } from '@/components/icons/Icons'; import { getAppConfig, getFirstVisit, setFirstVisit } from '@/lib/client/dexie'; import { useDocuments } from '@/contexts/DocumentContext'; import { ConfirmDialog } from '@/components/ConfirmDialog'; @@ -574,36 +574,36 @@ export function SettingsModal({ className = '' }: { className?: string }) { - {isChangelogOpen && ( + {isChangelogOpen ? ( setIsChangelogOpen(false)} /> - )} + ) : ( + <> + {/* Mobile: 2x2 grid nav */} +
+ {visibleSections.map((section) => { + const Icon = section.icon; + return ( + + ); + })} +
- {/* Mobile: 2x2 grid nav */} -
- {visibleSections.map((section) => { - const Icon = section.icon; - return ( - - ); - })} -
- -
+
{/* Desktop: vertical sidebar */}
-
+ + + )} @@ -1391,6 +1393,11 @@ function SettingsChangelogPanel({ const [expanded, setExpanded] = useState>({}); const [bodies, setBodies] = useState>({}); const normalizedAppVersion = normalizeVersion(appVersion || ''); + const isAbortError = (err: unknown): boolean => { + return err instanceof DOMException + ? err.name === 'AbortError' + : !!(typeof err === 'object' && err && 'name' in err && (err as { name?: string }).name === 'AbortError'); + }; useEffect(() => { const controller = new AbortController(); @@ -1406,9 +1413,10 @@ function SettingsChangelogPanel({ setExpanded((prev) => ({ ...prev, [entry.tag_name]: true })); } } catch (err) { + if (isAbortError(err)) return; setError(err instanceof Error ? err.message : 'Failed to load changelog'); } finally { - setLoading(false); + if (!controller.signal.aborted) setLoading(false); } } void loadManifest(); @@ -1429,7 +1437,8 @@ function SettingsChangelogPanel({ try { const body = await fetchChangelogReleaseBody(manifestUrl, entry.body_path, controller.signal); setBodies((prev) => ({ ...prev, [tag]: body })); - } catch { + } catch (err) { + if (isAbortError(err)) return; // Keep entry expanded; inline fallback appears below. } })); @@ -1439,8 +1448,18 @@ function SettingsChangelogPanel({ }, [expanded, manifest, manifestUrl, bodies]); return ( -
-
+
+
+

Changelog

@@ -1449,30 +1468,24 @@ function SettingsChangelogPanel({ : 'Release history from GitHub'}

-
-
+
{loading && ( -
+
Loading changelog…
)} {!loading && error && ( -
+

Could not load changelog right now.

{error}

Open GitHub Releases @@ -1480,7 +1493,7 @@ function SettingsChangelogPanel({ )} {!loading && !error && manifest.length === 0 && ( -
+
No releases found.
)} @@ -1489,42 +1502,46 @@ function SettingsChangelogPanel({ const isCurrent = normalizedAppVersion && normalizeVersion(entry.tag_name) === normalizedAppVersion; const body = bodies[entry.tag_name]; const isExpanded = !!expanded[entry.tag_name]; + const normalizedTag = normalizeVersion(entry.tag_name); + const normalizedName = normalizeVersion(entry.name || ''); + const showName = Boolean(entry.name) && normalizedName !== normalizedTag; return ( -
+
{isExpanded && ( -
+
{body ? (
@@ -1538,7 +1555,7 @@ function SettingsChangelogPanel({ href={entry.html_url} target="_blank" rel="noreferrer" - className="text-xs font-medium text-accent hover:underline" + className="inline-flex text-xs font-medium text-accent hover:underline transition-all duration-200 ease-in-out transform hover:scale-[1.02]" > View on GitHub