Navigation restructure: five-tab bottom bar, no phone drawer

Drawer removed (phones only; desktop rail untouched)
- MobileSidebar, sidebarOpen/useSidebarOpen, MenuIcon and the drawer's
  back-gesture layer are gone; the shared nav content now serves only
  the desktop rail (dead mobile branches deleted). No drawer-specific
  CSS existed; the three drawer strings (header.openMenu,
  sidebar.closeMenu, common.menu) and library.importAria are removed.
- The header drops the hamburger: logo + name on the left, the single
  theme chip on the right.

Five-tab bottom bar
- Library / Progress / New deck (prominent centre +) / Exam / Settings,
  in that order; Progress and Exam reuse the existing /stats and /exam
  screens, Settings keeps opening the dialog. Sliding pill, icon bounce,
  press feedback, re-tap-to-top and safe-area padding kept; every item
  is >=44px (72px wide at 360px).
- New short tab.* keys (EN + CS) so all five labels stay on one line at
  360px — 'Zkouškový režim' became 'Zkouška'. No ellipsis anywhere.
- The bar is mounted once in AppHeader so library, progress, exam and
  share get it; the wizards keep their own bottom action bar and the
  tab bar steps aside there, exactly as before.

Re-homed drawer destinations
- Smart Review card loses the Exam link (it is a tab now); Review due
  and Mistakes stay.
- New deck screen (and /homework) get a Study deck / Make my homework
  segmented switch; the library's homework empty-state button stays.
- The phone import icon becomes a ... button opening a sheet with
  Import JSON and New folder (back-gesture and Escape close it); folder
  chips still appear only once at least one folder exists, and folder
  creation stays in the New deck options step.

Verified: mobile suite 134 checks (no hamburger/drawer, tab order and
44px targets, label matrix at 360/390 x EN/CS x dark/light x reduced
motion, per-tab routing, deep links, Back from every tab, the ... sheet
with folder creation) plus regression 74/74, wizard 83/83, declutter
116/116, animation 8/8, native 35/35, i18n 25/25, phase1 38/38, phase2
43/43, phase3 20/20, freeze-loading 6/6. Key parity 740/740. Lint +
build clean. SW freezmo-v28.
This commit is contained in:
Martin Dvořák 2026-10-10 16:53:55 +00:00
commit 8557b04621
19 changed files with 357 additions and 325 deletions

View file

@ -0,0 +1,39 @@
"use client";
import Link from "next/link";
import { SegmentedPill } from "@/components/SegmentedPill";
import { useI18n } from "@/lib/i18n";
import { useIsPhone } from "@/lib/use-phone";
import { cn } from "@/lib/utils";
/**
* In-page switch between the two wizards (New deck ⇄ Make my homework).
* Phones reach both through this control and the centre tab; desktop keeps
* the rail rows as well.
*/
export function WizardModeSwitch({ mode }: { mode: "deck" | "homework" }) {
const { t } = useI18n();
const isPhone = useIsPhone();
return (
<div className="segmented mb-5" role="group" aria-label={t("wizard.mode.aria")}>
<Link
href="/create"
aria-current={mode === "deck" ? "page" : undefined}
className={cn("relative", isPhone && "seg-slide")}
>
{isPhone && mode === "deck" ? <SegmentedPill layoutId="wizard-mode" /> : null}
<span className="seg-label relative z-10">{t("wizard.mode.deck")}</span>
</Link>
<Link
href="/homework"
aria-current={mode === "homework" ? "page" : undefined}
className={cn("relative", isPhone && "seg-slide")}
>
{isPhone && mode === "homework" ? <SegmentedPill layoutId="wizard-mode" /> : null}
<span className="seg-label relative z-10">{t("wizard.mode.homework")}</span>
</Link>
</div>
);
}