import { scaleIn, slideInUp } from "$lib/animations"; import { api } from "$lib/api"; import type { Grade, ReviewCard } from "$lib/model"; import { Button } from "$ui/Button"; import { Dialog } from "$ui/Dialog"; import { ProgressBar } from "$ui/ProgressBar"; import { type Component, createEffect, createSignal, For, onCleanup, onMount, Show } from "solid-js"; import { Motion } from "solid-motionone"; type StudySessionProps = { cards: ReviewCard[]; onComplete: () => void; onExit: () => void }; const GRADE_LABELS: { [key in Grade]: { label: string; color: string; key: string } } = { 0: { label: "Again", color: "text-red-500", key: "1" }, 1: { label: "Hard", color: "text-orange-500", key: "2" }, 2: { label: "Okay", color: "text-yellow-500", key: "3" }, 3: { label: "Good", color: "text-green-500", key: "4" }, 4: { label: "Easy", color: "text-emerald-500", key: "5" }, 5: { label: "Perfect", color: "text-cyan-500", key: "6" }, }; export const StudySession: Component = (props) => { const [currentIndex, setCurrentIndex] = createSignal(0); const [isFlipped, setIsFlipped] = createSignal(false); const [isSubmitting, setIsSubmitting] = createSignal(false); const [showEditDialog, setShowEditDialog] = createSignal(false); const currentCard = () => props.cards[currentIndex()]; const progress = () => ((currentIndex() + 1) / props.cards.length) * 100; const isComplete = () => currentIndex() >= props.cards.length; const handleFlip = () => setIsFlipped((f) => !f); const handleGrade = async (grade: Grade) => { const card = currentCard(); if (!card || isSubmitting()) return; setIsSubmitting(true); try { const response = await api.submitReview(card.card_id, grade); if (response.ok) { await response.json(); setIsFlipped(false); setCurrentIndex((i) => i + 1); } } catch (err) { console.error("Failed to submit review:", err); } finally { setIsSubmitting(false); } }; const handleKeyDown = (e: KeyboardEvent) => { if (showEditDialog()) return; switch (e.key) { case " ": e.preventDefault(); handleFlip(); break; case "1": if (isFlipped()) handleGrade(0); break; case "2": if (isFlipped()) handleGrade(1); break; case "3": if (isFlipped()) handleGrade(2); break; case "4": if (isFlipped()) handleGrade(3); break; case "5": if (isFlipped()) handleGrade(4); break; case "6": if (isFlipped()) handleGrade(5); break; case "e": case "E": setShowEditDialog(true); break; case "Escape": props.onExit(); break; } }; onMount(() => { window.addEventListener("keydown", handleKeyDown); }); onCleanup(() => { window.removeEventListener("keydown", handleKeyDown); }); createEffect(() => { if (isComplete()) { props.onComplete(); } }); return (
Card {currentIndex() + 1} of {props.cards.length}
{(card) => (
{card.deck_title}

{card.front}

Press Space or click to reveal

Answer

{card.back}

0}>
{(hint) =>

💡 {hint}

}
)}

How well did you know this?

{(grade) => ( )}
Space: Flip 1-6: Grade E: Edit Esc: Exit
setShowEditDialog(false)} title="Edit Card"> {(card) => (

{card().front}

{card().back}

Full editing coming soon.

)}
); };