Fix the mode-choice redundancy: standardized names, deep links, compact switch

Terminology (lib/i18n-dict.ts)
- One name per mode everywhere: "Study Deck" / "Studijní balíček" and
  "Homework Solver" / "Řešitel úkolů". The library empty-state cards and the
  /create switcher now read the same, so the choice no longer changes name
  between screens.

Deep links
- Library quick actions carry the mode: /create?mode=deck and
  /homework?mode=homework.
- Both pages canonicalize: /create?mode=homework redirects to the homework
  flow and /homework?mode=deck redirects to /create, so a mode link always
  opens that mode directly.

/create
- The two bulky square cards (106px tall, wrapping/clipping "Study Deck &
  Qu…" on phones) are replaced by a compact segmented control (52px) placed
  directly above "1. Add your notes": ice pill, snowflake/sparkles icons,
  44px segments and one-line labels at 360px. The pill slides to the chosen
  segment and the route follows ~190ms later, so toggling reads as one smooth
  transition (immediate under prefers-reduced-motion).

Service worker: freezmo-v9.

Verified: mode-switch suite 26/26 (deep links, cross-mode redirects, 52px
control, 44px segments, no clipping/wrapping at 360px, "1. Add your notes" at
y=394 of 740 with the upload controls above the fold, pill slide, axe contrast,
en+cs, phone+desktop), mobile 49/49, i18n 27/27, desktop regression 73/73.
Lint + build clean.
This commit is contained in:
Martin Dvořák 2026-10-08 19:38:02 +00:00
commit 461dd2ffcf
7 changed files with 118 additions and 46 deletions

View file

@ -1,7 +1,6 @@
"use client";
import { motion } from "framer-motion";
import Link from "next/link";
import { useRouter } from "next/navigation";
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
@ -33,7 +32,8 @@ import { UNORGANIZED_ID, type Difficulty } from "@/lib/schemas";
import { upsertDeck } from "@/lib/storage";
import { openSettings } from "@/lib/ui-events";
import { cn, uid } from "@/lib/utils";
import { CameraIcon, FolderIcon, IceCubeIcon, PlusIcon, SnowflakeIcon, SparklesIcon, SunIcon } from "@/components/icons";
import { CameraIcon, FolderIcon, IceCubeIcon, PlusIcon, SnowflakeIcon, SunIcon } from "@/components/icons";
import { ModeSwitch } from "@/components/ModeSwitch";
import { Button, ProgressBar } from "@/components/ui";
type Phase = "idle" | "preparing" | "loading" | "error";
@ -321,39 +321,9 @@ export function UploadScreen() {
</p>
</section>
{/* Mode switcher: this page builds a study deck from notes; the other
card hands the same intake over to the homework flow. */}
<div className="grid grid-cols-2 gap-2.5 sm:gap-3">
<Link
href="/create"
aria-current="page"
className="card touch-target flex flex-col items-start gap-2 rounded-2xl border-accent-400/60 bg-accent-50/60 p-3 ring-2 ring-accent-400/30 sm:flex-row sm:items-center sm:gap-3 sm:p-3.5 dark:bg-accent-500/15"
>
<span
aria-hidden
className="grad-ice grid size-9 shrink-0 place-items-center rounded-xl text-[#06111f]"
>
<SnowflakeIcon className="size-5" />
</span>
<span className="min-w-0 text-[13px] font-semibold leading-snug text-[var(--text)] sm:text-[13.5px]">
{t("actionStudyDeck")}
</span>
</Link>
<Link
href="/homework"
className="card card-hover touch-target flex flex-col items-start gap-2 rounded-2xl p-3 sm:flex-row sm:items-center sm:gap-3 sm:p-3.5"
>
<span
aria-hidden
className="grid size-9 shrink-0 place-items-center rounded-xl bg-[var(--surface-sunken)] text-[var(--text-muted)]"
>
<SparklesIcon className="size-5" />
</span>
<span className="min-w-0 text-[13px] font-semibold leading-snug text-[var(--text)] sm:text-[13.5px]">
{t("actionHomework")}
</span>
</Link>
</div>
{/* Mode switcher: a compact segmented control. This page is the Study
Deck side; the other segment opens the homework flow. */}
<ModeSwitch current="deck" />
{error ? (