Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion src/app/(teacher)/layout.tsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
import { Nav } from '@/components/Nav';

/** "learning-commons" → "Learning Commons" for the nav's source indicator. */
function activeSourceLabel(): string {
const id = (process.env.STANDARDS_SOURCE ?? 'learning-commons').split(',')[0]?.trim() ?? '';
return id
.split('-')
.map((word) => (word ? word[0].toUpperCase() + word.slice(1) : word))
.join(' ');
}

export default function TeacherLayout({ children }: { children: React.ReactNode }) {
return (
<div className="flex min-h-full flex-col">
<Nav />
<Nav sourceLabel={activeSourceLabel()} />
{children}
</div>
);
Expand Down
5 changes: 2 additions & 3 deletions src/app/(teacher)/pathways/[sessionId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,16 +23,15 @@ export default async function PathwayReportPage({
href="/pathways"
className="text-sm text-muted-foreground hover:text-foreground transition-colors"
>
← All Pathways
← All pathways
</Link>
<h1 className="font-heading text-2xl font-bold mt-2">
{session?.topic ?? 'Pathway Report'}
{session?.topic ?? 'Pathway report'}
</h1>
</div>

<SessionReportPage
sessionId={sessionId}
topic={session?.topic ?? ''}
parentPreview={parentPreview}
/>
</main>
Expand Down
3 changes: 1 addition & 2 deletions src/app/(teacher)/pathways/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@ export const metadata = { title: 'Pathways' };

export default function PathwaysPage() {
return (
<main className="mx-auto w-full max-w-3xl px-6 py-10">
<h1 className="font-heading text-2xl font-bold mb-6">Pathways</h1>
<main className="mx-auto w-full max-w-6xl px-6 py-10">
<PathwaysDashboard />
</main>
);
Expand Down
2 changes: 1 addition & 1 deletion src/app/(teacher)/roster/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Suspense } from 'react';
import { RosterPage } from '@/components/roster/RosterPage';

export const metadata = { title: 'Class Roster' };
export const metadata = { title: 'Class roster' };

export default function Page() {
return (
Expand Down
9 changes: 8 additions & 1 deletion src/app/api/telemetry/route.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,14 @@ export async function POST(request: Request) {
learningComponentId: event.learningComponentId,
elapsedMs: event.elapsedMs,
correct: event.correct,
payload: truncate(event.payload),
// stepIndex rides inside payload — the interactions table has no
// column for it, and the report's per-step evidence strip reads it
// back out. Dropping it here is what made per-step reporting
// impossible before.
payload:
event.stepIndex != null
? { ...truncate(event.payload), stepIndex: event.stepIndex }
: truncate(event.payload),
})),
);
} catch (error) {
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/defend-claim/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export default function DefendClaimDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-3xl font-semibold tracking-tight">Defend a Claim</h1>
<h1 className="text-3xl font-semibold tracking-tight">Defend a claim</h1>
<p className="mt-2 text-muted-foreground">
Take a side on a claim historians argue about, defend it from the sources, then ask for
feedback and revise. Nothing is judged until you press the button — and every reading
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/draft-meter/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ export default function DraftMeterDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-3xl font-semibold tracking-tight">Draft Meter</h1>
<h1 className="text-3xl font-semibold tracking-tight">Draft meter</h1>
<p className="mt-2 text-muted-foreground">
Question, textbox, one line. Same component and same scoring call in all four of these —
what changes is the three things each one is looking for, and those come from the standard.
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/draw-the-curve/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -156,7 +156,7 @@ export default function DrawTheCurveDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-2xl font-semibold tracking-tight">Draw the Curve</h1>
<h1 className="text-2xl font-semibold tracking-tight">Draw the curve</h1>
<p className="mt-1 text-sm text-muted-foreground">
Shape the line by dragging its points, then see the real one drawn over your guess. Checked
on shape, not numbers — so a story&apos;s tension arc works the same way a motion graph does.
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/find-the-flaw/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export default function FindTheFlawDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-2xl font-semibold tracking-tight">Find the Flaw</h1>
<h1 className="text-2xl font-semibold tracking-tight">Find the flaw</h1>
<p className="mt-1 text-sm text-muted-foreground">
A worked example with one mistake in it. Find where it goes wrong, then say why — the same
interaction whether the work is a calculation, an experiment, an argument or an explanation.
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/fraction-area-model/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function FractionAreaModelDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="mt-2 text-2xl font-semibold tracking-tight">Fraction Area Model</h1>
<h1 className="mt-2 text-2xl font-semibold tracking-tight">Fraction area model</h1>
<p className="mt-1 text-sm text-muted-foreground">
Partition a whole into equal parts and select segments to build a target fraction.
Switch denominator choices to explore equivalent forms.
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/markdown-card/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ export default function MarkdownCardDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-2xl font-semibold tracking-tight">Markdown Card</h1>
<h1 className="text-2xl font-semibold tracking-tight">Markdown card</h1>
<p className="mt-1 text-sm text-muted-foreground">
Renders LLM-generated markdown as a reading card for reinforcement.
</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/narrated-card/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ export default function NarratedCardDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-2xl font-semibold tracking-tight">Narrated Card</h1>
<h1 className="text-2xl font-semibold tracking-tight">Narrated card</h1>
<p className="mt-1 text-sm text-muted-foreground">
Reads content aloud sentence by sentence, highlighting each sentence as it is spoken.
</p>
Expand Down
22 changes: 11 additions & 11 deletions src/app/demo/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,28 @@ import { WidgetThumb } from '@/components/demo/WidgetThumb';
const WIDGETS = [
{
slug: 'fraction-area-model',
name: 'Fraction Area Model',
name: 'Fraction area model',
description:
'Partition a whole into equal parts and select segments to build a target fraction. Supports bar and circle representations with equivalent-fraction detection.',
tags: ['fractions', 'visual', 'manipulative'],
},
{
slug: 'swiper-flashcard',
name: 'Swiper Flashcard',
name: 'Swiper flashcard',
description:
'Swipe a card up or down to answer a question or sort a statement into a category. Supports drag gestures and emits a completion event with per-card results.',
tags: ['flashcards', 'true/false', 'sorting'],
},
{
slug: 'draft-meter',
name: 'Draft Meter',
name: 'Draft meter',
description:
'Write a short response and one line scores how strong the argument is, from a live model call on a debounce. Optionally supplies a source passage, so "evidence" means citing the text.',
tags: ['writing', 'argument', 'live scoring'],
},
{
slug: 'draw-the-curve',
name: 'Draw the Curve',
name: 'Draw the curve',
description:
'Shape a line by dragging its points to predict how something changes, then see the real curve drawn over your guess. Checked on shape rather than numbers, so a story arc works the same way a motion graph does.',
tags: ['predict-then-reveal', 'any subject', 'chart'],
Expand All @@ -41,28 +41,28 @@ const WIDGETS = [
},
{
slug: 'writing-workshop',
name: 'Writing Workshop',
name: 'Writing workshop',
description:
'Long-form writing — essay, lab report, research proposal, short story — reviewed only when the student asks, and marked up on the sentences themselves with a note on each.',
tags: ['long-form', 'on demand', 'annotation'],
},
{
slug: 'find-the-flaw',
name: 'Find the Flaw',
name: 'Find the flaw',
description:
'A worked example with one deliberate mistake — a solution, an experiment, an argument, an explanation. The student finds the step where it goes wrong, then diagnoses why. Checked locally, so there is no wait.',
tags: ['error analysis', 'any subject', 'metacognition'],
},
{
slug: 'defend-claim',
name: 'Defend a Claim',
name: 'Defend a claim',
description:
'Take a side on a contestable historical claim, defend it from two conflicting sources, then request feedback and revise. Every reading answers with a counterargument. Typed or dictated. History, grade 7+.',
tags: ['history', 'argument', 'voice', 'revision'],
},
{
slug: 'timeline-builder',
name: 'Timeline Builder',
name: 'Timeline builder',
description:
'Drag historical events from a bank into labeled period zones on a horizontal timeline. Supports 3–5 zones with per-event correctness feedback.',
tags: ['history', 'sequencing', 'timeline'],
Expand Down Expand Up @@ -90,20 +90,20 @@ const WIDGETS = [
},
{
slug: 'narrated-card',
name: 'Narrated Card',
name: 'Narrated card',
description:
'Reads content aloud using the browser\'s text-to-speech engine, revealing each sentence as it is spoken. Steps stack up as they complete.',
tags: ['audio', 'narration', 'accessibility'],
},
{
slug: 'step-reveal',
name: 'Step Reveal',
name: 'Step reveal',
description: 'Walk through a concept or worked example one step at a time. Each step stacks up so students can follow the full chain of reasoning.',
tags: ['worked example', 'step-by-step', 'reasoning'],
},
{
slug: 'markdown-card',
name: 'Markdown Card',
name: 'Markdown card',
description:
'Renders LLM-generated markdown as a clean reading card — headings, bold, bullets, blockquotes, and an optional tip callout. Used to re-teach a concept a student is struggling with.',
tags: ['reading', 'remediation', 'markdown'],
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/step-reveal/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ export default function StepRevealDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-2xl font-semibold tracking-tight">Step Reveal</h1>
<h1 className="text-2xl font-semibold tracking-tight">Step reveal</h1>
<p className="mt-1 text-sm text-muted-foreground">
Walk through a worked example one step at a time. Each step stacks up so students can follow the full chain of reasoning.
</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/swiper-flashcard/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ export default function SwiperFlashcardDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="mt-2 text-2xl font-semibold tracking-tight">Swiper Flashcard</h1>
<h1 className="mt-2 text-2xl font-semibold tracking-tight">Swiper flashcard</h1>
<p className="mt-1 text-sm text-muted-foreground">
Sort each clue into the correct plate boundary type. Drag the card up or down — or use the buttons. An{' '}
<code className="rounded bg-muted px-1 py-0.5 font-mono text-xs">onComplete</code>{' '}
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/timeline-builder/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export default function TimelineBuilderDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-2xl font-semibold tracking-tight">Timeline Builder</h1>
<h1 className="text-2xl font-semibold tracking-tight">Timeline builder</h1>
<p className="mt-1 text-sm text-muted-foreground">
Drag events from the bank into the correct period on the timeline.
</p>
Expand Down
2 changes: 1 addition & 1 deletion src/app/demo/writing-workshop/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ export default function WritingWorkshopDemo() {
>
<span aria-hidden="true">←</span> Widget gallery
</Link>
<h1 className="text-2xl font-semibold tracking-tight">Writing Workshop</h1>
<h1 className="text-2xl font-semibold tracking-tight">Writing workshop</h1>
<p className="mt-1 text-sm text-muted-foreground">
Long-form writing, marked up when <em>you</em> ask. Nothing watches while you draft — then
the read comes back on the sentences themselves, underlined where they work and where they
Expand Down
4 changes: 2 additions & 2 deletions src/app/games/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@ type GameType = 'menu' | 'memory' | 'scramble' | 'pacman';
const GAMES = [
{
id: 'memory' as const,
name: 'Memory Match',
name: 'Memory match',
emoji: '🎴',
description: 'Find matching pairs',
component: MemoryMatch,
},
{
id: 'scramble' as const,
name: 'Word Scramble',
name: 'Word scramble',
emoji: '🔤',
description: 'Unscramble the letters',
component: WordScramble,
Expand Down
Loading
Loading