From 26a08859d795a4d7b3643756cb2a8d64a56bf6dc Mon Sep 17 00:00:00 2001 From: Thomas Hallock Date: Mon, 10 Nov 2025 09:49:30 -0600 Subject: [PATCH] feat(worksheets): restore mastery progression UI with 3-way mode selector MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Restore the mastery progression worksheet mode that was previously working but got disconnected during recent development. Changes: - Add 'mastery' mode option to ModeSelector (Smart/Manual/Mastery Progression) - Wire ProgressionModePanel into ConfigPanel's mode selection logic - Add currentStepId field to WorksheetFormState for tracking progression step - Mastery mode displays 6-step scaffolding fade progression slider The mastery progression system uses a 1D slider mapped to a 6-step path through 3D difficulty space (digit count × regrouping complexity × scaffolding). Scaffolding cycles back when moving to higher digit counts, following a pedagogically sound pattern. Components progressionPath.ts and ProgressionModePanel.tsx already existed (dated Nov 9) but were not integrated into the UI flow. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude --- .../addition/components/ConfigPanel.tsx | 111 ++++---- .../addition/components/ModeSelector.tsx | 246 +++++++++--------- .../app/create/worksheets/addition/types.ts | 71 ++--- 3 files changed, 219 insertions(+), 209 deletions(-) diff --git a/apps/web/src/app/create/worksheets/addition/components/ConfigPanel.tsx b/apps/web/src/app/create/worksheets/addition/components/ConfigPanel.tsx index 7dee44c4..95b26ca8 100644 --- a/apps/web/src/app/create/worksheets/addition/components/ConfigPanel.tsx +++ b/apps/web/src/app/create/worksheets/addition/components/ConfigPanel.tsx @@ -1,44 +1,40 @@ -"use client"; +'use client' -import { stack } from "../../../../../../styled-system/patterns"; -import type { WorksheetFormState } from "../types"; -import { defaultAdditionConfig } from "@/app/create/worksheets/config-schemas"; -import { ModeSelector } from "./ModeSelector"; -import { StudentNameInput } from "./config-panel/StudentNameInput"; -import { DigitRangeSection } from "./config-panel/DigitRangeSection"; -import { OperatorSection } from "./config-panel/OperatorSection"; -import { ProgressiveDifficultyToggle } from "./config-panel/ProgressiveDifficultyToggle"; -import { SmartModeControls } from "./config-panel/SmartModeControls"; -import { ManualModeControls } from "./config-panel/ManualModeControls"; +import { stack } from '../../../../../../styled-system/patterns' +import type { WorksheetFormState } from '../types' +import { defaultAdditionConfig } from '@/app/create/worksheets/config-schemas' +import { ModeSelector } from './ModeSelector' +import { StudentNameInput } from './config-panel/StudentNameInput' +import { DigitRangeSection } from './config-panel/DigitRangeSection' +import { OperatorSection } from './config-panel/OperatorSection' +import { ProgressiveDifficultyToggle } from './config-panel/ProgressiveDifficultyToggle' +import { SmartModeControls } from './config-panel/SmartModeControls' +import { ManualModeControls } from './config-panel/ManualModeControls' +import { ProgressionModePanel } from './config-panel/ProgressionModePanel' interface ConfigPanelProps { - formState: WorksheetFormState; - onChange: (updates: Partial) => void; - isDark?: boolean; + formState: WorksheetFormState + onChange: (updates: Partial) => void + isDark?: boolean } -export function ConfigPanel({ - formState, - onChange, - isDark = false, -}: ConfigPanelProps) { +export function ConfigPanel({ formState, onChange, isDark = false }: ConfigPanelProps) { // Handler for mode switching - const handleModeChange = (newMode: "smart" | "manual") => { + const handleModeChange = (newMode: 'smart' | 'manual' | 'mastery') => { if (formState.mode === newMode) { - return; // No change needed + return // No change needed } - if (newMode === "smart") { + if (newMode === 'smart') { // Switching to Smart mode // Use current displayRules if available, otherwise default to earlyLearner - const displayRules = - formState.displayRules ?? defaultAdditionConfig.displayRules; + const displayRules = formState.displayRules ?? defaultAdditionConfig.displayRules onChange({ - mode: "smart", + mode: 'smart', displayRules, - difficultyProfile: "earlyLearner", - } as unknown as Partial); - } else { + difficultyProfile: 'earlyLearner', + } as unknown as Partial) + } else if (newMode === 'manual') { // Switching to Manual mode // Convert current displayRules to boolean flags if available let booleanFlags = { @@ -49,32 +45,38 @@ export function ConfigPanel({ showProblemNumbers: true, showCellBorder: true, showTenFramesForAll: false, - }; + } if (formState.displayRules) { // Convert 'always' to true, everything else to false booleanFlags = { - showCarryBoxes: formState.displayRules.carryBoxes === "always", - showAnswerBoxes: formState.displayRules.answerBoxes === "always", - showPlaceValueColors: - formState.displayRules.placeValueColors === "always", - showTenFrames: formState.displayRules.tenFrames === "always", - showProblemNumbers: - formState.displayRules.problemNumbers === "always", - showCellBorder: formState.displayRules.cellBorders === "always", + showCarryBoxes: formState.displayRules.carryBoxes === 'always', + showAnswerBoxes: formState.displayRules.answerBoxes === 'always', + showPlaceValueColors: formState.displayRules.placeValueColors === 'always', + showTenFrames: formState.displayRules.tenFrames === 'always', + showProblemNumbers: formState.displayRules.problemNumbers === 'always', + showCellBorder: formState.displayRules.cellBorders === 'always', showTenFramesForAll: false, - }; + } } onChange({ - mode: "manual", + mode: 'manual', ...booleanFlags, - } as unknown as Partial); + } as unknown as Partial) + } else { + // Switching to Mastery mode + // Mastery mode uses Smart mode under the hood with skill-based configuration + const displayRules = formState.displayRules ?? defaultAdditionConfig.displayRules + onChange({ + mode: 'mastery', + displayRules, + } as unknown as Partial) } - }; + } return ( -
+
{/* Student Name */} @@ -111,22 +113,19 @@ export function ConfigPanel({ /> {/* Smart Mode Controls */} - {(!formState.mode || formState.mode === "smart") && ( - + {(!formState.mode || formState.mode === 'smart') && ( + )} {/* Manual Mode Controls */} - {formState.mode === "manual" && ( - + {formState.mode === 'manual' && ( + + )} + + {/* Mastery Mode Controls */} + {formState.mode === 'mastery' && ( + )}
- ); + ) } diff --git a/apps/web/src/app/create/worksheets/addition/components/ModeSelector.tsx b/apps/web/src/app/create/worksheets/addition/components/ModeSelector.tsx index 9229e421..5e988cbf 100644 --- a/apps/web/src/app/create/worksheets/addition/components/ModeSelector.tsx +++ b/apps/web/src/app/create/worksheets/addition/components/ModeSelector.tsx @@ -1,42 +1,38 @@ -"use client"; +'use client' -import { css } from "../../../../../../styled-system/css"; +import { css } from '../../../../../../styled-system/css' interface ModeSelectorProps { - currentMode: "smart" | "manual"; - onChange: (mode: "smart" | "manual") => void; - isDark?: boolean; + currentMode: 'smart' | 'manual' | 'mastery' + onChange: (mode: 'smart' | 'manual' | 'mastery') => void + isDark?: boolean } /** * Mode selector for worksheet generation - * Allows switching between Smart Difficulty and Manual Control modes + * Allows switching between Smart Difficulty, Manual Control, and Mastery Progression modes */ -export function ModeSelector({ - currentMode, - onChange, - isDark = false, -}: ModeSelectorProps) { +export function ModeSelector({ currentMode, onChange, isDark = false }: ModeSelectorProps) { return (

Worksheet Mode @@ -45,67 +41,52 @@ export function ModeSelector({
{/* Smart Difficulty Mode Button */} @@ -132,59 +107,43 @@ export function ModeSelector({ + + {/* Mastery Progression Mode Button */} +

- ); + ) } diff --git a/apps/web/src/app/create/worksheets/addition/types.ts b/apps/web/src/app/create/worksheets/addition/types.ts index 3b854467..43831a63 100644 --- a/apps/web/src/app/create/worksheets/addition/types.ts +++ b/apps/web/src/app/create/worksheets/addition/types.ts @@ -4,7 +4,7 @@ import type { AdditionConfigV4, AdditionConfigV4Smart, AdditionConfigV4Manual, -} from "../config-schemas"; +} from '../config-schemas' /** * Complete, validated configuration for worksheet generation @@ -18,25 +18,25 @@ import type { */ export type WorksheetConfig = AdditionConfigV4 & { // Problem set - DERIVED state - total: number; // total = problemsPerPage * pages - rows: number; // rows = (problemsPerPage / cols) * pages + total: number // total = problemsPerPage * pages + rows: number // rows = (problemsPerPage / cols) * pages // Personalization - date: string; - seed: number; + date: string + seed: number // Layout page: { - wIn: number; - hIn: number; - }; + wIn: number + hIn: number + } margins: { - left: number; - right: number; - top: number; - bottom: number; - }; -}; + left: number + right: number + top: number + bottom: number + } +} /** * Partial form state - user may be editing, fields optional @@ -52,55 +52,56 @@ export type WorksheetConfig = AdditionConfigV4 & { * This type is intentionally permissive during form editing to allow fields from * both modes to exist temporarily. Validation will enforce mode consistency. */ -export type WorksheetFormState = Partial< - Omit -> & - Partial> & { +export type WorksheetFormState = Partial> & + Partial> & { // DERIVED state (calculated from primary state) - rows?: number; - total?: number; - date?: string; - seed?: number; - }; + rows?: number + total?: number + date?: string + seed?: number + + // Mastery progression mode + currentStepId?: string // Current step in progression path + } /** * Worksheet operator type */ -export type WorksheetOperator = "addition" | "subtraction" | "mixed"; +export type WorksheetOperator = 'addition' | 'subtraction' | 'mixed' /** * A single addition problem */ export interface AdditionProblem { - a: number; - b: number; - operator: "+"; + a: number + b: number + operator: '+' } /** * A single subtraction problem */ export interface SubtractionProblem { - minuend: number; - subtrahend: number; - operator: "−"; // Proper minus sign (U+2212) + minuend: number + subtrahend: number + operator: '−' // Proper minus sign (U+2212) } /** * Unified problem type (addition or subtraction) */ -export type WorksheetProblem = AdditionProblem | SubtractionProblem; +export type WorksheetProblem = AdditionProblem | SubtractionProblem /** * Validation result */ export interface ValidationResult { - isValid: boolean; - config?: WorksheetConfig; - errors?: string[]; + isValid: boolean + config?: WorksheetConfig + errors?: string[] } /** * Problem category for difficulty control */ -export type ProblemCategory = "non" | "onesOnly" | "both"; +export type ProblemCategory = 'non' | 'onesOnly' | 'both'