mirror of
https://github.com/MBombeck/HealthLog.git
synced 2026-11-09 21:10:59 +00:00
Appearance ("Darstellung") stacked every module's view and ordering
settings on one long page. Split it into a hub that lists the modules as
navigable rows, each opening its own /settings/layout/<module> subpage
with a back link — the per-module settings move verbatim, no restyling.
The module routes now redirect to those subpages instead of an in-page
anchor, and the in-app cogs link straight to them.
66 lines
2.4 KiB
TypeScript
66 lines
2.4 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { ChevronRight } from "lucide-react";
|
|
|
|
import { useAuth } from "@/hooks/use-auth";
|
|
import { useMounted } from "@/hooks/use-mounted";
|
|
import { useTranslations } from "@/lib/i18n/context";
|
|
import { SettingsCard } from "./settings-card";
|
|
import { LAYOUT_GROUPS } from "./layout-groups";
|
|
|
|
/**
|
|
* v1.25.11 (#148) — the "Appearance" hub (slug stays `layout`).
|
|
*
|
|
* The hub is a navigable index, NOT a stacked composition: it lists each
|
|
* module as a clickable row (title + description + chevron) that opens the
|
|
* module's own subpage at `/settings/layout/<id>`. Nothing is stacked inline;
|
|
* the per-module view/sort surfaces live on their subpages so the hub reads as
|
|
* a short, scannable directory. The visible page heading + subtitle
|
|
* ("Appearance" / "Personalize how …") are painted by `SettingsShell` from the
|
|
* `layout` slug; this body renders only the row list.
|
|
*
|
|
* Per-module gating fails OPEN (`!== false`): a missing key reads as enabled so
|
|
* a section never silently disappears. Groups with no `moduleGate` always
|
|
* render. The filter is gated on a post-mount flag (`useMounted()`) so SSR and
|
|
* the first client paint ALWAYS emit the same fail-open list — the same
|
|
* hydration-stability contract the shell nav uses, so the module filter can
|
|
* never produce a React #418 mismatch on this surface.
|
|
*/
|
|
export function LayoutSection() {
|
|
const { t } = useTranslations();
|
|
const { user } = useAuth();
|
|
|
|
const hydrated = useMounted();
|
|
const modules = user?.modules;
|
|
const visibleGroups = LAYOUT_GROUPS.filter(
|
|
(group) =>
|
|
!hydrated || !group.moduleGate || modules?.[group.moduleGate] !== false,
|
|
);
|
|
|
|
return (
|
|
<SettingsCard className="divide-border divide-y overflow-hidden p-0 md:p-0">
|
|
{visibleGroups.map((group) => (
|
|
<Link
|
|
key={group.id}
|
|
href={`/settings/layout/${group.id}`}
|
|
className="hover:bg-accent/50 flex items-center justify-between gap-4 p-4 transition-colors md:p-6"
|
|
>
|
|
<div className="min-w-0 space-y-0.5">
|
|
<p className="text-foreground text-sm font-medium">
|
|
{t(group.titleKey)}
|
|
</p>
|
|
<p className="text-muted-foreground text-sm">
|
|
{t(group.descriptionKey)}
|
|
</p>
|
|
</div>
|
|
<ChevronRight
|
|
className="text-muted-foreground h-5 w-5 shrink-0"
|
|
aria-hidden="true"
|
|
/>
|
|
</Link>
|
|
))}
|
|
</SettingsCard>
|
|
);
|
|
}
|