freezmo/lib/deck-seed.ts
Martin Dvorak 5ca0de920c Chat mode, phase 2: local history, answer actions, motion polish
- Conversations in a versioned IndexedDB store (freezmo-chat v1, zod
  validated with the same schema backup/sync use, capped at 100 x 300).
  Settled turns persist (question always; answer when produced, partial
  stops included); ?c=<id> keeps reloads on the conversation via
  history.replaceState (no router round-trip mid-chat).
- History UI: desktop column, phone sheet (spring, backdrop, Escape),
  auto titles from the first question, inline rename, delete with an
  Undo toast, diacritic-folding search over titles and message text.
  Scope and model are remembered per conversation; history is readable
  offline.
- Assistant actions: Turn into flashcards (New deck with the answer as
  notes, landing on the options step - deck seed gained step) and Save
  to notes (appends to the single scoped deck, trimmed at 40k).
- Chats travel in the backup export (preview counts them) and in the
  encrypted sync payload; still never the key.
- Motion from lib/motion.ts: message fade-up, sheet springs for the
  model/context/history sheets, 150ms composer height transition, all
  skipped under reduced motion.
- Tests: chat suite 63 -> 89 checks (history, reload, rename/search/
  delete/undo, actions, export, two-device sync round-trip, offline,
  desktop panel). Full set: 12/12 suites, 513 checks. SW -> freezmo-v33.

Also: tests/model-compare.mjs benchmark (diagnostic) for deciding the
default text model on numbers; defaults unchanged.
2026-10-11 19:03:48 +00:00

38 lines
1,002 B
TypeScript

"use client";
/**
* Hand-off from a homework result to the New deck flow: the content travels in
* sessionStorage and the wizard picks it up on mount, with the options step
* pre-filled. One-shot, like the share-target payload.
*/
export type DeckSeed = {
text: string;
difficulty?: "easy" | "medium" | "hard";
count?: number;
/** Wizard step to land on (chat's "turn into flashcards" opens options). */
step?: 1 | 2 | 3;
};
const KEY = "freezmo.deck.seed.v1";
export function setDeckSeed(seed: DeckSeed): void {
try {
window.sessionStorage.setItem(KEY, JSON.stringify(seed));
} catch {
/* private mode */
}
}
export function takeDeckSeed(): DeckSeed | null {
try {
const raw = window.sessionStorage.getItem(KEY);
if (!raw) return null;
window.sessionStorage.removeItem(KEY);
const parsed = JSON.parse(raw) as DeckSeed;
if (typeof parsed.text !== "string" || !parsed.text.trim()) return null;
return parsed;
} catch {
return null;
}
}