feat(worksheets): Phase 8 - Update preview and example routes for operator

Updates worksheet generation routes to support operator selection:

Example route (example/route.ts):
- Add operator, minuend, subtrahend fields to ExampleRequest
- Split generateExampleTypst into addition/subtraction branches
- Use generateSubtractionProblems for subtraction examples
- Render with subtraction-problem-stack function

Preview generation (generatePreview.ts):
- Import subtraction and mixed problem generators
- Dispatch to correct generator based on operator field
- Support addition, subtraction, and mixed modes

Both routes now correctly generate previews for all three operator modes.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock
2025-11-07 22:30:05 -06:00
parent 01d095942d
commit 010606848d
2 changed files with 104 additions and 27 deletions

View File

@@ -10,11 +10,16 @@
import { type NextRequest, NextResponse } from 'next/server'
import { execSync } from 'child_process'
import { generateProblems } from '@/app/create/worksheets/addition/problemGenerator'
import {
generateProblems,
generateSubtractionProblems,
} from '@/app/create/worksheets/addition/problemGenerator'
import {
generateTypstHelpers,
generateProblemStackFunction,
generateSubtractionProblemStackFunction,
} from '@/app/create/worksheets/addition/typstHelpers'
import type { WorksheetOperator } from '@/app/create/worksheets/addition/types'
export const dynamic = 'force-dynamic'
@@ -27,8 +32,13 @@ interface ExampleRequest {
showTenFrames?: boolean
showTenFramesForAll?: boolean
fontSize?: number
operator?: WorksheetOperator
// For addition
addend1?: number
addend2?: number
// For subtraction
minuend?: number
subtrahend?: number
}
/**
@@ -36,21 +46,7 @@ interface ExampleRequest {
* Uses the EXACT same Typst structure as the full worksheet generator
*/
function generateExampleTypst(config: ExampleRequest): string {
// Use custom addends if provided, otherwise generate a problem
let a: number
let b: number
if (config.addend1 !== undefined && config.addend2 !== undefined) {
a = config.addend1
b = config.addend2
} else {
// Generate a simple 2-digit + 2-digit problem with carries
const problems = generateProblems(1, 0.8, 0.5, false, 12345)
const problem = problems[0]
a = problem.a
b = problem.b
}
const operator = config.operator ?? 'addition'
const fontSize = config.fontSize || 14
const cellSize = 0.35 // Compact cell size for examples
@@ -62,7 +58,23 @@ function generateExampleTypst(config: ExampleRequest): string {
const showTenFrames = config.showTenFrames ?? false
const showTenFramesForAll = config.showTenFramesForAll ?? false
return String.raw`
if (operator === 'addition') {
// Use custom addends if provided, otherwise generate a problem
let a: number
let b: number
if (config.addend1 !== undefined && config.addend2 !== undefined) {
a = config.addend1
b = config.addend2
} else {
// Generate a simple 2-digit + 2-digit problem with carries
const problems = generateProblems(1, 0.8, 0.5, false, 12345)
const problem = problems[0]
a = problem.a
b = problem.b
}
return String.raw`
#set page(width: auto, height: auto, margin: 8pt, fill: white)
#set text(size: ${fontSize}pt, font: "New Computer Modern Math")
@@ -85,6 +97,47 @@ ${generateProblemStackFunction(cellSize, 3)}
#problem-stack(a, b, if show-numbers { 0 } else { none }, show-carries, show-answers, show-colors, show-ten-frames, show-numbers)
]
`
} else {
// Subtraction
let minuend: number
let subtrahend: number
if (config.minuend !== undefined && config.subtrahend !== undefined) {
minuend = config.minuend
subtrahend = config.subtrahend
} else {
// Generate a simple 2-digit - 2-digit problem with borrows
const digitRange = { min: 2, max: 2 }
const problems = generateSubtractionProblems(1, digitRange, 0.8, 0.5, false, 12345)
const problem = problems[0]
minuend = problem.minuend
subtrahend = problem.subtrahend
}
return String.raw`
#set page(width: auto, height: auto, margin: 8pt, fill: white)
#set text(size: ${fontSize}pt, font: "New Computer Modern Math")
#let heavy-stroke = 0.8pt
#let show-borrows = ${showCarries ? 'true' : 'false'}
#let show-answers = ${showAnswers ? 'true' : 'false'}
#let show-colors = ${showColors ? 'true' : 'false'}
#let show-numbers = ${showNumbers ? 'true' : 'false'}
#let show-ten-frames = ${showTenFrames ? 'true' : 'false'}
#let show-ten-frames-for-all = ${showTenFramesForAll ? 'true' : 'false'}
${generateTypstHelpers(cellSize)}
${generateSubtractionProblemStackFunction(cellSize, 3)}
#let minuend = ${minuend}
#let subtrahend = ${subtrahend}
#align(center + horizon)[
#subtraction-problem-stack(minuend, subtrahend, if show-numbers { 0 } else { none }, show-borrows, show-answers, show-colors, show-ten-frames, show-numbers)
]
`
}
}
export async function POST(request: NextRequest) {

View File

@@ -2,7 +2,11 @@
import { execSync } from 'child_process'
import { validateWorksheetConfig } from './validation'
import { generateProblems } from './problemGenerator'
import {
generateProblems,
generateSubtractionProblems,
generateMixedProblems,
} from './problemGenerator'
import { generateTypstSource } from './typstGenerator'
import type { WorksheetFormState } from './types'
@@ -31,15 +35,35 @@ export function generateWorksheetPreview(config: WorksheetFormState): PreviewRes
const validatedConfig = validation.config
// Generate all problems for full preview
const problems = generateProblems(
validatedConfig.total,
validatedConfig.pAnyStart,
validatedConfig.pAllStart,
validatedConfig.interpolate,
validatedConfig.seed,
validatedConfig.digitRange // V4: Pass digit range
)
// Generate all problems for full preview based on operator
const operator = validatedConfig.operator ?? 'addition'
const problems =
operator === 'addition'
? generateProblems(
validatedConfig.total,
validatedConfig.pAnyStart,
validatedConfig.pAllStart,
validatedConfig.interpolate,
validatedConfig.seed,
validatedConfig.digitRange
)
: operator === 'subtraction'
? generateSubtractionProblems(
validatedConfig.total,
validatedConfig.digitRange,
validatedConfig.pAnyStart,
validatedConfig.pAllStart,
validatedConfig.interpolate,
validatedConfig.seed
)
: generateMixedProblems(
validatedConfig.total,
validatedConfig.digitRange,
validatedConfig.pAnyStart,
validatedConfig.pAllStart,
validatedConfig.interpolate,
validatedConfig.seed
)
// Generate Typst sources (one per page)
const typstSources = generateTypstSource(validatedConfig, problems)