Redesign the quick-action CTAs: two ways in (study deck vs. homework)

Library empty state ("Your icebox")
- Replace the single "Make your first deck" button with two quick-action
  cards: "Create interactive test" (primary, ice-gradient icon + subtle
  accent border) and "Help me with my homework" (glass card, sparkles
  icon). Stacked on phones, side by side from 640px up; both >=44px tall.

/create
- Replace the "Got homework instead of notes?" banner with a two-card mode
  switcher above "1. Add your notes": "Study Deck & Quizzes" (the current
  view — aria-current, accent tint, ice icon) and "Homework Solver" (a
  shortcut to /homework). Icon-on-top tiles on phones, inline rows from
  640px up; glass tokens + backdrop blur in both themes.

Strings
- New keys in both dictionaries: emptyStateCreateDeck, emptyStateHomework,
  actionStudyDeck, actionHomework. Drop the now-unused homework.entry and
  library.makeFirst keys.

Drive-by AA fix (light mode, /create only)
- The "New folder" dashed button and the difficulty blurbs move from
  frost-500 to frost-600 (4.0:1 -> ~6:1). Dark mode is unchanged.

Service worker: freezmo-v8.

Verified: redesign suite 32/32 (stacked/side-by-side layouts, 360/390/1280,
dark+light, en+cs, >=44px targets, both cards navigate, no overflow, axe
contrast), 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:19:20 +00:00
commit 22af888ec0
4 changed files with 81 additions and 28 deletions

View file

@ -5,7 +5,7 @@ import { useMemo, useRef, useState, useSyncExternalStore } from "react";
import { DeckCard } from "@/components/DeckCard";
import { FolderBar } from "@/components/FolderBar";
import { FolderIcon, UploadIcon } from "@/components/icons";
import { FolderIcon, SnowflakeIcon, SparklesIcon, UploadIcon } from "@/components/icons";
import { Button, EmptyState } from "@/components/ui";
import { folderStore, renameFolder } from "@/lib/folders";
import { useI18n } from "@/lib/i18n";
@ -224,9 +224,38 @@ export function LibraryScreen() {
<EmptyState
title={t("library.noDecks")}
action={
<Link href="/create" className="btn-primary touch-target h-10 px-4 text-sm">
{t("library.makeFirst")}
</Link>
/* Two ways in: build a study deck from notes, or hand over an
assignment. Stacked on phones, side by side from 640px up. */
<div className="grid w-[min(24rem,calc(100vw_-_3rem))] gap-3 sm:w-[36rem] sm:grid-cols-2">
<Link
href="/create"
className="card card-hover touch-target flex items-center gap-3 border-accent-400/60 p-3.5 text-left sm:p-4"
>
<span
aria-hidden
className="grad-ice grid size-11 shrink-0 place-items-center rounded-2xl text-[#06111f]"
>
<SnowflakeIcon className="size-5" />
</span>
<span className="min-w-0 text-[14px] font-semibold leading-snug text-[var(--text)]">
{t("emptyStateCreateDeck")}
</span>
</Link>
<Link
href="/homework"
className="card card-hover touch-target flex items-center gap-3 p-3.5 text-left sm:p-4"
>
<span
aria-hidden
className="grid size-11 shrink-0 place-items-center rounded-2xl bg-[var(--surface-sunken)] text-[var(--text-muted)]"
>
<SparklesIcon className="size-5" />
</span>
<span className="min-w-0 text-[14px] font-semibold leading-snug text-[var(--text)]">
{t("emptyStateHomework")}
</span>
</Link>
</div>
}
>
{t("library.emptyBody")}