mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 04:50:59 +00:00
fix(settings): fold the About section into the user-card dropdown
Eleven sections on the settings sidebar was one over the comfort line. About is three small cards (identity, links, update check) that collectively get read once or twice a year and didn't earn a top-level slot. Hide it from the in-shell nav and surface it as "About HealthLog" in the sidebar user-card dropdown (mobile dropdown mirrors). The `/settings/about` route stays alive so direct links, the public `/about` permalink, and the dropdown entry continue to resolve.
This commit is contained in:
1 parent
bececda630
commit
0de1e2ebe7
10 files changed
+59
-9
No files matched your search
@@ -169,6 +169,7 @@
|
||||
"admin": "Admin-Konsole",
|
||||
"logout": "Abmelden",
|
||||
"login": "Anmelden",
|
||||
"about": "Über HealthLog",
|
||||
"notifications": "Benachrichtigungs-Center",
|
||||
"theme": "Darstellung",
|
||||
"themeSystem": "System",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"admin": "Admin Console",
|
||||
"logout": "Sign out",
|
||||
"login": "Sign in",
|
||||
"about": "About HealthLog",
|
||||
"notifications": "Notification Center",
|
||||
"theme": "Appearance",
|
||||
"themeSystem": "System",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"admin": "Admin Console",
|
||||
"logout": "Sign out",
|
||||
"login": "Iniciar sesión",
|
||||
"about": "Acerca de HealthLog",
|
||||
"notifications": "Centro de notificaciones",
|
||||
"theme": "Apariencia",
|
||||
"themeSystem": "Sistema",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"admin": "Admin Console",
|
||||
"logout": "Sign out",
|
||||
"login": "Se connecter",
|
||||
"about": "À propos de HealthLog",
|
||||
"notifications": "Centre de notifications",
|
||||
"theme": "Apparence",
|
||||
"themeSystem": "Système",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"admin": "Admin Console",
|
||||
"logout": "Sign out",
|
||||
"login": "Accedi",
|
||||
"about": "Informazioni su HealthLog",
|
||||
"notifications": "Centro notifiche",
|
||||
"theme": "Aspetto",
|
||||
"themeSystem": "Sistema",
|
||||
|
||||
@@ -169,6 +169,7 @@
|
||||
"admin": "Admin Console",
|
||||
"logout": "Sign out",
|
||||
"login": "Zaloguj się",
|
||||
"about": "O HealthLog",
|
||||
"notifications": "Centrum powiadomień",
|
||||
"theme": "Wygląd",
|
||||
"themeSystem": "Systemowy",
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
ChevronsLeft,
|
||||
ChevronsRight,
|
||||
Home,
|
||||
Info,
|
||||
Lightbulb,
|
||||
LogOut,
|
||||
Monitor,
|
||||
@@ -143,6 +144,17 @@ function SidebarUserSection({ collapsed }: { collapsed: boolean }) {
|
||||
{t("nav.notifications")}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
{/* v1.4.33 IW7 — "About" used to live as its own Settings
|
||||
section but the three small cards inside (identity / links /
|
||||
update check) collectively get read once or twice a year, so
|
||||
the top-level slot has been collapsed into this dropdown. The
|
||||
route stays alive at `/settings/about`. */}
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href="/settings/about" className="cursor-pointer">
|
||||
<Info className="mr-2 h-4 w-4" />
|
||||
{t("nav.about")}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
{themeIcon}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import {
|
||||
Bell,
|
||||
ChevronDown,
|
||||
Info,
|
||||
LogIn,
|
||||
LogOut,
|
||||
Monitor,
|
||||
@@ -82,6 +83,15 @@ export function TopBar() {
|
||||
{t("nav.notifications")}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
{/* v1.4.33 IW7 — "About" folded out of Settings into the
|
||||
user-card dropdown; mobile dropdown mirrors the
|
||||
desktop sidebar so the entry shows up here too. */}
|
||||
<DropdownMenuItem asChild>
|
||||
<Link href="/settings/about" className="cursor-pointer">
|
||||
<Info className="mr-2 h-4 w-4" />
|
||||
{t("nav.about")}
|
||||
</Link>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSub>
|
||||
<DropdownMenuSubTrigger>
|
||||
{themeIcon}
|
||||
|
||||
@@ -80,9 +80,16 @@ describe("SETTINGS_SECTION_SLUGS", () => {
|
||||
});
|
||||
|
||||
describe("<SettingsShell>", () => {
|
||||
it("renders every section link — once for the mobile strip and once for the desktop sidebar", () => {
|
||||
it("renders every navigable section link — once for the mobile strip and once for the desktop sidebar", () => {
|
||||
const html = renderShell({ active: "account" });
|
||||
for (const slug of SETTINGS_SECTION_SLUGS) {
|
||||
// v1.4.33 IW7 — the `about` slug is alive as a route
|
||||
// (`/settings/about` still resolves and `generateStaticParams()`
|
||||
// still emits the page) but it is hidden from the in-shell nav.
|
||||
// The user-card dropdown owns the link now. Iterate the visible
|
||||
// sections list, not the slug list, when asserting on rendered
|
||||
// markup.
|
||||
const navigableSlugs = SETTINGS_SECTIONS.map((section) => section.slug);
|
||||
for (const slug of navigableSlugs) {
|
||||
const matches = html.match(new RegExp(`href="/settings/${slug}"`, "g"));
|
||||
// Two renders — mobile strip + desktop sidebar — guarantee the link
|
||||
// exists in both layouts. Tablet/desktop hide the strip with `md:`,
|
||||
@@ -90,6 +97,8 @@ describe("<SettingsShell>", () => {
|
||||
// before media queries resolve.
|
||||
expect(matches?.length ?? 0).toBe(2);
|
||||
}
|
||||
// The hidden `about` slug must NOT appear in the in-shell nav.
|
||||
expect(html).not.toContain('href="/settings/about"');
|
||||
});
|
||||
|
||||
it("links use the correct `/settings/<slug>` href — regression guard against typos", () => {
|
||||
@@ -149,7 +158,10 @@ describe("<SettingsShell>", () => {
|
||||
// entry in the sidebar; the link must be present in both locales.
|
||||
expect(html).toContain('href="/settings/export"');
|
||||
expect(html).toContain("Advanced");
|
||||
expect(html).toContain("About");
|
||||
// v1.4.33 IW7 — About is no longer in the settings nav; it lives
|
||||
// in the sidebar user-card dropdown. Route `/settings/about` is
|
||||
// still alive for direct links.
|
||||
expect(html).not.toContain('href="/settings/about"');
|
||||
});
|
||||
|
||||
it("resolves every section title via the i18n provider — German", () => {
|
||||
@@ -172,7 +184,9 @@ describe("<SettingsShell>", () => {
|
||||
// API & Tokens is identical in both locales (proper noun + ampersand)
|
||||
expect(html).toContain("API & Tokens");
|
||||
expect(html).toContain("Erweitert");
|
||||
expect(html).toContain("Über");
|
||||
// v1.4.33 IW7 — "Über" (About) section removed from the in-shell
|
||||
// nav, folded into the sidebar user-card dropdown ("Über HealthLog").
|
||||
expect(html).not.toContain('href="/settings/about"');
|
||||
});
|
||||
|
||||
it("does NOT surface the raw key when a translation resolves — guards against missing JSON entries", () => {
|
||||
|
||||
@@ -20,7 +20,6 @@ import { usePathname } from "next/navigation";
|
||||
import {
|
||||
Bell,
|
||||
Download,
|
||||
Info,
|
||||
KeyRound,
|
||||
Layers,
|
||||
LayoutDashboard,
|
||||
@@ -61,9 +60,19 @@ interface SettingsSection {
|
||||
}
|
||||
|
||||
/**
|
||||
* Source of truth for the section list. Order matches the in-app navigation
|
||||
* order so the sidebar, mobile strip, and `generateStaticParams()` all line
|
||||
* up. Don't reorder without updating tests.
|
||||
* Source of truth for the section list that the settings shell renders
|
||||
* in its sidebar + mobile chip-strip. Order matches the in-app
|
||||
* navigation order. Don't reorder without updating tests.
|
||||
*
|
||||
* v1.4.33 IW7 — "About" was folded into the sidebar user-card
|
||||
* dropdown (sidebar-nav.tsx -> "Über HealthLog" / "About HealthLog")
|
||||
* because its three small cards (identity / links / update check)
|
||||
* collectively read once or twice a year and didn't earn a top-level
|
||||
* settings slot. The route `/settings/about` is still alive — the
|
||||
* slug stays in `SETTINGS_SECTION_SLUGS` so `generateStaticParams()`
|
||||
* keeps emitting the page — but it no longer appears in the in-page
|
||||
* navigation. Direct links (the user-card dropdown, the public
|
||||
* `/about` permalink) continue to resolve to the same component.
|
||||
*/
|
||||
export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||
{ slug: "account", titleKey: "settings.sections.account.title", icon: User },
|
||||
@@ -104,7 +113,6 @@ export const SETTINGS_SECTIONS: readonly SettingsSection[] = [
|
||||
titleKey: "settings.sections.advanced.title",
|
||||
icon: Settings2,
|
||||
},
|
||||
{ slug: "about", titleKey: "settings.sections.about.title", icon: Info },
|
||||
] as const;
|
||||
|
||||
export interface SettingsShellProps {
|
||||
|
||||
Reference in new issue
Block a user