Commit graph

10 commits

Author SHA1 Message Date
33c3f11bb7 Match the deck-creation CTA to the homework CTA layout
- "Freeze my deck" is now a full-width (w-full) button in its sticky bar,
  like "Make my homework", instead of a compact left-aligned button in a
  flex row.
- The status/validation line ("Add a photo or a document (or some text) to
  start.") moved from above the button to centred directly underneath it,
  with the same 12px muted styling the homework flow uses.
- Both flows now share the Button size="lg" shape (44px tall, 14px radius,
  same muted disabled chip, centred text); hover/disabled behaviour comes
  from the same .btn-primary/.btn-disabled classes.

Service worker: freezmo-v12.

Verified: CTA-parity suite 32/32 (full-width ratio ~1.0 at 390px and 1280px,
44px height, centred helper under the button on both pages, identical radius
and disabled chip, enabled ice gradient), mobile 51/51, i18n 27/27, desktop
regression 74/74. Lint + build clean.
2026-10-09 06:12:48 +00:00
8c44f47881 Separate Study Decks and Homework in the library; drop the /create mode switch
Library ("Your icebox")
- Two tabs, never mixed: Study Decks (the folder + card library) and Homework
  (saved solutions and step-by-step guides). The active tab lives in the URL
  (/?tab=homework), so the sections are linkable and survive a reload.
- Decks tab keeps Import, the folder bar, stats and its own empty state — now
  a single decks-only CTA.
- Homework tab lists saved results as cards (mode icon, date, step count,
  preview) with Open and delete-with-confirm; its empty state has its own CTA
  ("Homework Solver") that opens the solver directly. Opening a card
  deep-links to /homework?open=<id>, which the screen opens on arrival.
- .segmented now also styles link segments (same control as settings).

/create
- The redundant "Study Deck | Homework Solver" toggle is gone: /create is the
  deck uploader only, and the bottom bar's + goes straight to it. Homework has
  its own screen, reached from the library tab, the drawer and CTAs.

Copy
- New keys (en + cs): tabDecks, tabHomework, homeworkHeroTitle, plus homework
  empty-state/open/step-count strings. The homework hero is now "Solve your
  homework" / "Vyřeš svůj úkol" — no study-deck text in the homework flow.
- Removed the now-unused ModeSwitch component and homework.title key.

Service worker: freezmo-v10.

Verified: library-tabs suite 37/37 (tab switching, context empty states,
deep-link opening, deletion, no switch on /create, heroes, redirects, desktop
grid, 360px + 44px targets, axe contrast en+cs light+dark), mobile 49/49,
i18n 27/27, desktop regression 74/74. Lint + build clean.
2026-10-08 21:26:08 +00:00
461dd2ffcf 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.
2026-10-08 19:38:02 +00:00
22af888ec0 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.
2026-10-08 19:19:20 +00:00
ef2a6a3589 Add “Make my homework”, and finish the mobile polish pass
Homework (/homework — entry points in the drawer and on the create screen)

- Assignment intake reuses the study pipeline: pasted text, photos
  (camera/picker, compressed in the browser) and documents (PDF/DOCX/PPTX/
  ODT/text) through lib/image + lib/documents, the same vision step and the
  same language guard. Raw files never leave the device — only text and JPEG
  data URLs reach the server.
- Two large choice cards: “Just make it” returns the finished homework
  (answer only, plain text, copy + make it again); “Explain how to make this
  homework” builds an interactive guide.
- The guide is one step per screen in the study-feed snap layout:
  explanation, three progressive hints (nudge -> hint -> the answer) and an
  optional checkpoint rendered by the existing activity components (graded
  through /api/grade). The last screen assembles the solution from the step
  answers, with a copy button. Checkpoints carry xp 0 so the guide stays free
  of XP/streak chrome.
- Results live in freezmo.homework.v1 with a small history (open/delete);
  “Make it again” re-runs from the stored assignment text (the vision
  transcription when photos were used) — no original files are stored.
- The answer and the guide are written in the assignment's language, never
  translated into the UI language.

Server

- POST /api/homework: NDJSON stage events like /api/generate, the same
  http-guard, auth checked before parsing, and its own RATE_LIMIT_HOMEWORK
  (documented in .env.example + the README table).
- New prompts in lib/prompts.ts and zod schemas in lib/schemas.ts with the
  same single repair retry; TEXT_MODEL for content, VISION_MODEL only for
  photos. New shared client pieces: useNotesIntake, lib/homework store,
  lib/clipboard, and a shared NDJSON reader in lib/client-api.

Also finishing the mobile polish pass from the previous request

- Phone ice scene: the top-left orb moved behind the glass header (it sat
  behind the page heading/subtitle). The settings sheet's scroll cue is now a
  bare chevron inside a content fade (mask) instead of a chip over the status
  banner, and the API key card's note/disclosure/actions are tightened.
- theme-color now follows the in-app theme (SSR metas still fall back to the
  OS preference); apple-mobile-web-app-status-bar-style stays “default”
  because iOS fixes the status-bar text colour at launch.

Verified: 78/78 homework checks (text/photo/PDF, both modes, EN+CS, dark+light,
360/390px, copy, history persistence, storage privacy, API language, axe), plus
the existing suites re-run (mobile 47/47, pixel contrast 0 below AA, i18n 27/27,
desktop regression 72/72). Lint + build clean; service worker freezmo-v6.
2026-10-08 18:30:33 +00:00
618ad5fb9c Add an English/Czech interface language switch
English stays the default; Czech is a full translation. Only the app chrome
is translated - notes and generated decks keep their own language, which is a
core feature, not a setting.

i18n
- lib/i18n-dict.ts: flat en/cs dictionaries (441 keys each), translate() and
  translatePlural() with real Czech plural rules (1 sada / 2-4 sady / 5+ sad).
  English is the default and the fallback for a missing key.
- lib/i18n.ts: browser store (freezmo.locale.v1), useI18n() hook, and the
  x-freezmo-locale header. The hook's t/plural are bound to the locale React
  is rendering with, so the first client render matches the server HTML and
  then re-renders in the stored language; module-level t is only for event
  handlers and non-React helpers.
- <html lang> follows the choice (inline script + setLocale).

UI
- Settings -> Language segmented control (English / Cestina), plus an EN/CS
  button on the key gate for first run.
- Every screen translated: sidebar, header, tab bar, library, deck cards,
  folder bar, create flow, all seven activities, study chrome, results,
  settings + health panel, API-key gate and help, install sheet, offline and
  the deck-not-found page.
- Plural-aware counts everywhere (decks, folders, activities, runs, photos,
  documents, pages, words, wrong attempts).

Server
- API routes and guards (generate, grade, health, http-guard, rate-limit,
  ollama error mapping) answer in the request's language, so error cards and
  the health panel never fall back to English mid-sentence.

Fixes
- A hydration mismatch when a non-default locale was stored silently dropped
  the .dark class after hydration; render-time t() is now bound to the
  hook's locale (UploadScreen.describeExtraction, ResultsScreen.answerFor,
  DeckCard's folder fallback).
- Bumped the service worker cache to freezmo-v4 for this deploy.

Tests: i18n 27/27 (gate toggle, persistence, html lang, Czech plurals,
settings switch) and a rebuilt regression suite 72/72 (English default,
library, create, all 7 activity types, results, settings, install sheet,
offline, PWA, security, Czech smoke).
2026-10-08 13:56:32 +00:00
52cce42cde Frosted ice glass restyle
Rebuilds the look around the spec: an ice scene, one shared glass
recipe, icy accents and glass on every large surface. Visual only —
layout, behaviour, copy and functionality are untouched.

Background
- .ice-scene: fixed, z-index -1, pointer-events none. Navy base
  (#070b16 to #0c1426) in dark, pale (#f4f9ff to #e6f1fb) in light,
  four drifting glacier blobs (#38bdf8/#60a5fa/#818cf8, 30-60s
  transform-only loops), five glossy ice orbs (40-220px radial
  gradients with a highlight at 30% 25% and a blue shadow) placed so the
  glass blurs them, and an SVG feTurbulence grain at 4-5%.
- prefers-reduced-motion stops the drift; phones get two blobs and two
  orbs fewer.

Glass
- One shared recipe (.glass-panel, .card, .sidebar-surface,
  .study-chrome, .tabbar, .glass, .gate-card): rgba(255,255,255,.06)
  dark / .55 light, blur(24px) saturate(140%) (16px on phones), a bright
  1px rim, an inset top highlight and a blue-tinted outer shadow.
- Nested glass (chips, inputs, secondary buttons) is more opaque and
  never adds a second blur layer. @supports fallback for no
  backdrop-filter. Radii: 24-28px cards/sheets, 14px inputs/buttons,
  pills for chips. Cards hover brighter + cyan rim + 2px lift, 180ms.

Colour and type
- Accent is glacier cyan (#38bdf8) to ice blue (#0ea5e9); progress bars
  and selected states use the gradient; the active sidebar item is a
  frosted highlight with a cyan rim.
- Primary CTA: icy gradient — white to #bfe3ff with ink text in dark,
  deep blue in light (biased so the label sits on the darker half and
  keeps 5.6:1).
- Leftover slate/black greys replaced with navy-tinted frost tokens.
- Headings are semibold with tighter tracking.

Screens
- Dashboard: the sidebar is one tall inset rounded glass panel; deck
  cards are glass.
- Gate: one centred glass card over the scene, orbs visible behind it.
- Sheets/modals: glass over the dimmed, lightly blurred backdrop.
- Study view: question card more opaque (.glass-solid); top bar and
  pager are slim glass pills.

Perf: measured on a phone viewport with 4x CPU throttling. The animated
blobs' filter: blur() was the whole cost (150ms vs 33ms per frame), so
they are soft radial gradients with no filter now; idle 60fps, ~17ms
median while scrolling.

Tests updated for the new tokens: contrast 18/18 AA, deck chrome 15/15,
key gate 49/49, install sheet 64/64, deck fixes 15/15, retry 14/14,
zoom 6/6, final ux 12/12, security 8/8, pwa 16/16.
2026-10-08 10:11:55 +00:00
9e4ecd3ee0 Deck chrome: neutral surfaces, borders and text (no navy leftovers)
- The study feed's progress header and bottom pager no longer use the old
  navy glass: new .study-chrome class uses the neutral surface token
  (same gray as the cards, #2f2f2f in dark), the neutral border
  (8% white in dark, #e5e5e5 in light) and a neutral shadow.
- Close tile, streak pill and XP pill now use --surface-sunken /
  --text-muted, matching the app's other buttons and chips; the close
  glyph is the shared XIcon.
- Bottom pager: counter in --text, arrows in --text-muted.
- .glass (mobile header) no longer has the hardcoded #101720 navy; it is
  now color-mix of the surface token. Removed the unused --color-night-*
  tokens and the last night- usage (create screen sticky bar).
- Hidden the 'Swipe up' hint on desktop, where it collided with the
  bottom pager.

New deck-chrome suite: 15/15 (computed surfaces/borders/text in both
themes, no navy); pwa 16/16, final-ux 12/12, security 8/8, contrast 20/20.
2026-10-07 09:06:18 +00:00
dfa7b7502a Add full-screen API-key gate
In user-key mode a browser with no stored Ollama key now gets a polished
gate instead of the app shell: one masked input with a show/hide toggle,
a single Continue button, inline validation errors, and a "?" help sheet
with the steps to a free key.

- Validates the draft key through /api/health (real 1-token probe) before
  saving; invalid-key and network failures read differently.
- Key still lives only in this browser's localStorage; nothing server-side.
- Gate wraps /, /create and deck study; server-key and local-daemon modes
  skip it; removing the key in Settings brings it back.
- Removes the now-redundant dashboard/create API-key banner.
- Monochrome corner glows (dark near-black / light near-white), 24px card,
  48px field and button, gentle fade/slide-in, reduced-motion aware.
- Help modal: centred dialog on desktop, bottom sheet on mobile, closes via
  X, Escape or backdrop.
- README and browser suites updated (34 gate checks, 15 key-flow checks,
  12 shipped-default checks; ui/folders/docs/pwa/security/contrast green).
2026-10-06 21:20:22 +00:00
3ea2cea100 Freezmo: self-hosted notes-to-activities study app
Next.js 15 app that turns photos, PDFs, DOCX/PPTX and text into a swipeable
feed of AI-generated activities (flashcards, multiple choice, true/false,
fill-in-the-blank, matching, ordering, short answer) using the user's own
Ollama models.

Highlights:
- All AI calls run in server route handlers; the browser never talks to Ollama.
- Bring-your-own-key mode (default): the key lives only in the browser and is
  sent per-request; server, local-daemon and shared-key modes also supported.
- Client-side document extraction (pdf.js, mammoth, jszip) with scanned-PDF
  page rendering for the vision model; notes stay in their original language.
- ChatGPT-style shell: collapsible sidebar / mobile drawer, neutral token-based
  light + dark themes, folder organisation, PWA (manifest, SW, offline page).
- Strict JSON validation with zod + auto-repair, rate limiting, and request
  guards (cross-origin, body-size, API-key sanitising).
- setup.sh bootstraps deps, .env.local and a production build.

Gitignore excludes .env*, the generated pdf.js worker and local scratch files.
2026-10-06 20:56:55 +00:00