Sichtbare Texte in einstellungen/page.tsx und settings-tabs.tsx von ASCII-Ersatz (ae/oe/ue/ss) auf echte Umlaute (ä/ö/ü/ß) umgestellt: Ernährung, Präferenzen, persönlich, Straße, Eiweiß, Kochvorgänge, Passwörter, für, über, groß u. a. Tab-id-Slug "ernaehrung" bleibt ASCII (URL-Parameter). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
83 lines
2.5 KiB
TypeScript
83 lines
2.5 KiB
TypeScript
"use client";
|
|
|
|
import { useRouter, useSearchParams } from "next/navigation";
|
|
import { useCallback } from "react";
|
|
|
|
export type SettingsTabId =
|
|
| "profil"
|
|
| "ernaehrung"
|
|
| "ziele"
|
|
| "sicherheit"
|
|
| "anwendung";
|
|
|
|
const tabs: { id: SettingsTabId; label: string; description: string }[] = [
|
|
{ id: "profil", label: "Profil", description: "Persönliche Daten und Kontakt" },
|
|
{ id: "ernaehrung", label: "Ernährung", description: "Rezept- und Mahlzeiten-Präferenzen" },
|
|
{ id: "ziele", label: "Ziele", description: "Kalorien, Makros, Gewicht, Fasten" },
|
|
{ id: "sicherheit", label: "Sicherheit", description: "2FA, Passkeys, Passwort" },
|
|
{ id: "anwendung", label: "Anwendung", description: "Erscheinungsbild und Erinnerungen" },
|
|
];
|
|
|
|
export function useSettingsTab(): {
|
|
active: SettingsTabId;
|
|
setActive: (id: SettingsTabId) => void;
|
|
} {
|
|
const router = useRouter();
|
|
const search = useSearchParams();
|
|
const tabParam = search.get("tab");
|
|
const active: SettingsTabId =
|
|
tabs.find((tab) => tab.id === tabParam)?.id ?? "profil";
|
|
|
|
const setActive = useCallback(
|
|
(id: SettingsTabId) => {
|
|
const params = new URLSearchParams(search.toString());
|
|
params.set("tab", id);
|
|
router.replace(`/einstellungen?${params.toString()}`, { scroll: false });
|
|
},
|
|
[router, search],
|
|
);
|
|
|
|
return { active, setActive };
|
|
}
|
|
|
|
export function SettingsTabs({
|
|
active,
|
|
onChange,
|
|
}: {
|
|
active: SettingsTabId;
|
|
onChange: (id: SettingsTabId) => void;
|
|
}) {
|
|
const activeMeta = tabs.find((tab) => tab.id === active);
|
|
return (
|
|
<div className="space-y-3">
|
|
<div
|
|
role="tablist"
|
|
aria-label="Einstellungs-Kategorien"
|
|
className="-mx-1 flex gap-2 overflow-x-auto px-1 pb-1"
|
|
>
|
|
{tabs.map((tab) => {
|
|
const isActive = tab.id === active;
|
|
return (
|
|
<button
|
|
key={tab.id}
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={isActive}
|
|
onClick={() => onChange(tab.id)}
|
|
className={`shrink-0 rounded-full px-4 py-2 text-sm font-semibold transition-colors ${
|
|
isActive
|
|
? "bg-[#0F766E] text-white shadow-sm"
|
|
: "bg-white text-gray-600 ring-1 ring-gray-200 hover:bg-gray-50"
|
|
}`}
|
|
>
|
|
{tab.label}
|
|
</button>
|
|
);
|
|
})}
|
|
</div>
|
|
{activeMeta?.description ? (
|
|
<p className="px-1 text-sm text-gray-500">{activeMeta.description}</p>
|
|
) : null}
|
|
</div>
|
|
);
|
|
}
|