From a47fbef7857cf198c37a46b31bdc31b0903c4d17 Mon Sep 17 00:00:00 2001 From: Gulum Date: Sat, 6 Jun 2026 00:47:07 +0200 Subject: [PATCH] FEAT-7: AppShell 'Mehr' overflow nav (phone: 4 tabs + Mehr sheet; desktop: all 7) + de.nav.more Co-Authored-By: Claude Opus 4.8 (1M context) --- .../src/components/AppShell.tsx | 82 +++++++++++++------ .../src/components/appShell.css | 67 +++++++++++++++ gerbil-manager-web/src/strings/de.ts | 2 + 3 files changed, 126 insertions(+), 25 deletions(-) create mode 100644 gerbil-manager-web/src/components/appShell.css diff --git a/gerbil-manager-web/src/components/AppShell.tsx b/gerbil-manager-web/src/components/AppShell.tsx index 631bd60..8fedf11 100644 --- a/gerbil-manager-web/src/components/AppShell.tsx +++ b/gerbil-manager-web/src/components/AppShell.tsx @@ -1,24 +1,40 @@ +import { useState } from 'react' import { NavLink, Outlet } from 'react-router-dom' import { de } from '../strings/de' +import './appShell.css' -const navItems = [ +interface NavItem { + to: string + label: string + icon: string + end?: boolean +} + +// Primary items are always visible in the phone bottom bar; secondary items +// move into the "Mehr" sheet on phones and appear inline in the desktop sidebar. +const PRIMARY: NavItem[] = [ { to: '/', label: de.nav.home, icon: '🏠', end: true }, - { to: '/rennmaeuse', label: de.nav.gerbils, icon: '🐭', end: false }, - { to: '/wuerfe', label: de.nav.litters, icon: '🍼', end: false }, - { to: '/becken', label: de.nav.enclosures, icon: '🛁', end: false }, - { to: '/kontakte', label: de.nav.contacts, icon: '📇', end: false }, - { to: '/genetik', label: de.nav.genetics, icon: '🧬', end: false }, - // FEAT-7: vorerst 7. Tab; „Mehr“-Overflow für das Smartphone ist mit Kevin - // abgestimmt (FEAT-7-Konversation) und ersetzt diesen Eintrag dann. - { to: '/statistik', label: de.nav.statistics, icon: '📊', end: false }, + { to: '/rennmaeuse', label: de.nav.gerbils, icon: '🐭' }, + { to: '/wuerfe', label: de.nav.litters, icon: '🍼' }, + { to: '/genetik', label: de.nav.genetics, icon: '🧬' }, ] +const SECONDARY: NavItem[] = [ + { to: '/becken', label: de.nav.enclosures, icon: '🛁' }, + { to: '/kontakte', label: de.nav.contacts, icon: '📇' }, + { to: '/statistik', label: de.nav.statistics, icon: '📊' }, +] + +const linkClass = ({ isActive }: { isActive: boolean }) => + isActive ? 'nav-link nav-link--active' : 'nav-link' /** * App-Grundgerüst, mobile-first: - * - Smartphone: Kopfzeile oben, Tab-Leiste unten - * - Laptop (ab 768px): Seitenleiste links, Inhalt rechts + * - Smartphone: Kopfzeile oben, Tab-Leiste unten (4 Haupt-Tabs + „Mehr“). + * - Laptop (ab 768px): Seitenleiste links mit allen Einträgen, kein „Mehr“. */ export default function AppShell() { + const [moreOpen, setMoreOpen] = useState(false) + return (
@@ -27,21 +43,37 @@ export default function AppShell() {
diff --git a/gerbil-manager-web/src/components/appShell.css b/gerbil-manager-web/src/components/appShell.css new file mode 100644 index 0000000..b229cb5 --- /dev/null +++ b/gerbil-manager-web/src/components/appShell.css @@ -0,0 +1,67 @@ +/* + * AppShell navigation overflow ("Mehr") — co-located with the component to keep + * index.css contention-free (shared-file rule). Overrides the base .app-nav + * layout from index.css; loaded after it, so these rules win. + * + * Phone: bottom bar shows 4 primary tabs + a "Mehr" button; the secondary items + * live in a sheet that opens ABOVE the bar. Laptop (>=768px): full sidebar, all + * items inline, no "Mehr" button. + */ + +/* --- Phone (base) --- */ +.app-nav { + /* column-reverse so .nav-secondary (2nd in DOM) renders ABOVE the bar */ + flex-direction: column-reverse; + justify-content: flex-start; + padding: 0; +} + +.nav-primary { + display: flex; + justify-content: space-around; +} + +.nav-more-btn { + background: none; + border: none; + cursor: pointer; + font: inherit; +} + +.nav-secondary { + display: none; + flex-direction: column; + background: var(--color-surface); + border-bottom: 1px solid var(--color-border); + box-shadow: 0 -4px 12px rgba(0, 0, 0, 0.08); +} + +.nav-secondary--open { + display: flex; +} + +/* --- Laptop / Tablet (>=768px): full sidebar, no overflow --- */ +@media (min-width: 768px) { + .app-nav { + flex-direction: column; + padding: 1rem 0.5rem; + } + + .nav-primary { + flex-direction: column; + gap: 0.25rem; + } + + .nav-more-btn { + display: none; + } + + .nav-secondary { + display: flex; + gap: 0.25rem; + background: none; + border-bottom: none; + box-shadow: none; + margin-top: 0.25rem; + } +} diff --git a/gerbil-manager-web/src/strings/de.ts b/gerbil-manager-web/src/strings/de.ts index 51365a0..edf9f18 100644 --- a/gerbil-manager-web/src/strings/de.ts +++ b/gerbil-manager-web/src/strings/de.ts @@ -19,6 +19,8 @@ export const de = { contacts: 'Kontakte', // FEAT-7 (Kelly): Statistik statistics: 'Statistik', + // FEAT-7 (Kevin): „Mehr“-Overflow auf dem Smartphone + more: 'Mehr', openMenu: 'Menü öffnen', closeMenu: 'Menü schließen', mainNavigation: 'Hauptnavigation',