fix(worksheets): enable borrowNotation and borrowingHints in smart difficulty mode
Remove hardcoded false values for showBorrowNotation and showBorrowingHints that were preventing these subtraction-specific scaffolds from displaying in smart difficulty mode. The displayOptions object already includes these fields from the resolved display rules, so spreading displayOptions now correctly applies them. This was work from a previous session that got lost during a git stash/pull. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -1,24 +1,27 @@
|
||||
// Typst document generator for addition worksheets
|
||||
|
||||
import type { WorksheetProblem, WorksheetConfig } from './types'
|
||||
import type { WorksheetProblem, WorksheetConfig } from "./types";
|
||||
import {
|
||||
generateTypstHelpers,
|
||||
generateProblemStackFunction,
|
||||
generateSubtractionProblemStackFunction,
|
||||
generatePlaceValueColors,
|
||||
} from './typstHelpers'
|
||||
import { analyzeProblem, analyzeSubtractionProblem } from './problemAnalysis'
|
||||
import { resolveDisplayForProblem } from './displayRules'
|
||||
} from "./typstHelpers";
|
||||
import { analyzeProblem, analyzeSubtractionProblem } from "./problemAnalysis";
|
||||
import { resolveDisplayForProblem } from "./displayRules";
|
||||
|
||||
/**
|
||||
* Chunk array into pages of specified size
|
||||
*/
|
||||
function chunkProblems(problems: WorksheetProblem[], pageSize: number): WorksheetProblem[][] {
|
||||
const pages: WorksheetProblem[][] = []
|
||||
function chunkProblems(
|
||||
problems: WorksheetProblem[],
|
||||
pageSize: number,
|
||||
): WorksheetProblem[][] {
|
||||
const pages: WorksheetProblem[][] = [];
|
||||
for (let i = 0; i < problems.length; i += pageSize) {
|
||||
pages.push(problems.slice(i, i + pageSize))
|
||||
pages.push(problems.slice(i, i + pageSize));
|
||||
}
|
||||
return pages
|
||||
return pages;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -26,22 +29,22 @@ function chunkProblems(problems: WorksheetProblem[], pageSize: number): Workshee
|
||||
* Returns max digits across all operands (handles both addition and subtraction)
|
||||
*/
|
||||
function calculateMaxDigits(problems: WorksheetProblem[]): number {
|
||||
let maxDigits = 1
|
||||
let maxDigits = 1;
|
||||
for (const problem of problems) {
|
||||
if (problem.operator === '+') {
|
||||
const digitsA = problem.a.toString().length
|
||||
const digitsB = problem.b.toString().length
|
||||
const maxProblemDigits = Math.max(digitsA, digitsB)
|
||||
maxDigits = Math.max(maxDigits, maxProblemDigits)
|
||||
if (problem.operator === "+") {
|
||||
const digitsA = problem.a.toString().length;
|
||||
const digitsB = problem.b.toString().length;
|
||||
const maxProblemDigits = Math.max(digitsA, digitsB);
|
||||
maxDigits = Math.max(maxDigits, maxProblemDigits);
|
||||
} else {
|
||||
// Subtraction
|
||||
const digitsMinuend = problem.minuend.toString().length
|
||||
const digitsSubtrahend = problem.subtrahend.toString().length
|
||||
const maxProblemDigits = Math.max(digitsMinuend, digitsSubtrahend)
|
||||
maxDigits = Math.max(maxDigits, maxProblemDigits)
|
||||
const digitsMinuend = problem.minuend.toString().length;
|
||||
const digitsSubtrahend = problem.subtrahend.toString().length;
|
||||
const maxProblemDigits = Math.max(digitsMinuend, digitsSubtrahend);
|
||||
maxDigits = Math.max(maxDigits, maxProblemDigits);
|
||||
}
|
||||
}
|
||||
return maxDigits
|
||||
return maxDigits;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,48 +54,60 @@ function generatePageTypst(
|
||||
config: WorksheetConfig,
|
||||
pageProblems: WorksheetProblem[],
|
||||
problemOffset: number,
|
||||
rowsPerPage: number
|
||||
rowsPerPage: number,
|
||||
): string {
|
||||
console.log('[typstGenerator] generatePageTypst called with config:', {
|
||||
console.log("[typstGenerator] generatePageTypst called with config:", {
|
||||
mode: config.mode,
|
||||
displayRules: config.mode === 'smart' ? config.displayRules : 'N/A (manual mode)',
|
||||
showTenFrames: config.mode === 'manual' ? config.showTenFrames : 'N/A (smart mode)',
|
||||
})
|
||||
displayRules:
|
||||
config.mode === "smart" ? config.displayRules : "N/A (manual mode)",
|
||||
showTenFrames:
|
||||
config.mode === "manual" ? config.showTenFrames : "N/A (smart mode)",
|
||||
});
|
||||
|
||||
// Calculate maximum digits for proper column layout
|
||||
const maxDigits = calculateMaxDigits(pageProblems)
|
||||
console.log('[typstGenerator] Max digits on this page:', maxDigits)
|
||||
const maxDigits = calculateMaxDigits(pageProblems);
|
||||
console.log("[typstGenerator] Max digits on this page:", maxDigits);
|
||||
|
||||
// Enrich problems with display options based on mode
|
||||
const enrichedProblems = pageProblems.map((p, index) => {
|
||||
if (config.mode === 'smart') {
|
||||
if (config.mode === "smart") {
|
||||
// Smart mode: Per-problem conditional display based on problem complexity
|
||||
const meta =
|
||||
p.operator === '+'
|
||||
p.operator === "+"
|
||||
? analyzeProblem(p.a, p.b)
|
||||
: analyzeSubtractionProblem(p.minuend, p.subtrahend)
|
||||
const displayOptions = resolveDisplayForProblem(config.displayRules, meta)
|
||||
: analyzeSubtractionProblem(p.minuend, p.subtrahend);
|
||||
const displayOptions = resolveDisplayForProblem(
|
||||
config.displayRules,
|
||||
meta,
|
||||
);
|
||||
|
||||
if (index === 0) {
|
||||
const problemStr = p.operator === '+' ? `${p.a} + ${p.b}` : `${p.minuend} − ${p.subtrahend}`
|
||||
console.log('[typstGenerator] Smart mode - First problem display options:', {
|
||||
problem: problemStr,
|
||||
meta,
|
||||
displayOptions,
|
||||
})
|
||||
const problemStr =
|
||||
p.operator === "+"
|
||||
? `${p.a} + ${p.b}`
|
||||
: `${p.minuend} − ${p.subtrahend}`;
|
||||
console.log(
|
||||
"[typstGenerator] Smart mode - First problem display options:",
|
||||
{
|
||||
problem: problemStr,
|
||||
meta,
|
||||
displayOptions,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
return {
|
||||
...p,
|
||||
...displayOptions,
|
||||
showBorrowNotation: false, // Smart mode doesn't have borrow notation (yet)
|
||||
showBorrowingHints: false, // Smart mode doesn't have borrowing hints (yet)
|
||||
}
|
||||
...displayOptions, // Now includes showBorrowNotation and showBorrowingHints from resolved rules
|
||||
};
|
||||
} else {
|
||||
// Manual mode: Uniform display across all problems
|
||||
if (index === 0) {
|
||||
const problemStr = p.operator === '+' ? `${p.a} + ${p.b}` : `${p.minuend} − ${p.subtrahend}`
|
||||
console.log('[typstGenerator] Manual mode - Uniform display options:', {
|
||||
const problemStr =
|
||||
p.operator === "+"
|
||||
? `${p.a} + ${p.b}`
|
||||
: `${p.minuend} − ${p.subtrahend}`;
|
||||
console.log("[typstGenerator] Manual mode - Uniform display options:", {
|
||||
problem: problemStr,
|
||||
showCarryBoxes: config.showCarryBoxes,
|
||||
showAnswerBoxes: config.showAnswerBoxes,
|
||||
@@ -100,7 +115,7 @@ function generatePageTypst(
|
||||
showTenFrames: config.showTenFrames,
|
||||
showProblemNumbers: config.showProblemNumbers,
|
||||
showCellBorder: config.showCellBorder,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
@@ -111,40 +126,44 @@ function generatePageTypst(
|
||||
showTenFrames: config.showTenFrames,
|
||||
showProblemNumbers: config.showProblemNumbers,
|
||||
showCellBorder: config.showCellBorder,
|
||||
showBorrowNotation: 'showBorrowNotation' in config ? config.showBorrowNotation : true,
|
||||
showBorrowingHints: 'showBorrowingHints' in config ? config.showBorrowingHints : false,
|
||||
}
|
||||
showBorrowNotation:
|
||||
"showBorrowNotation" in config ? config.showBorrowNotation : true,
|
||||
showBorrowingHints:
|
||||
"showBorrowingHints" in config ? config.showBorrowingHints : false,
|
||||
};
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
// Generate Typst problem data with per-problem display flags
|
||||
const problemsTypst = enrichedProblems
|
||||
.map((p) => {
|
||||
if (p.operator === '+') {
|
||||
return ` (operator: "+", a: ${p.a}, b: ${p.b}, showCarryBoxes: ${p.showCarryBoxes}, showAnswerBoxes: ${p.showAnswerBoxes}, showPlaceValueColors: ${p.showPlaceValueColors}, showTenFrames: ${p.showTenFrames}, showProblemNumbers: ${p.showProblemNumbers}, showCellBorder: ${p.showCellBorder}, showBorrowNotation: ${p.showBorrowNotation}, showBorrowingHints: ${p.showBorrowingHints}),`
|
||||
if (p.operator === "+") {
|
||||
return ` (operator: "+", a: ${p.a}, b: ${p.b}, showCarryBoxes: ${p.showCarryBoxes}, showAnswerBoxes: ${p.showAnswerBoxes}, showPlaceValueColors: ${p.showPlaceValueColors}, showTenFrames: ${p.showTenFrames}, showProblemNumbers: ${p.showProblemNumbers}, showCellBorder: ${p.showCellBorder}, showBorrowNotation: ${p.showBorrowNotation}, showBorrowingHints: ${p.showBorrowingHints}),`;
|
||||
} else {
|
||||
return ` (operator: "−", minuend: ${p.minuend}, subtrahend: ${p.subtrahend}, showCarryBoxes: ${p.showCarryBoxes}, showAnswerBoxes: ${p.showAnswerBoxes}, showPlaceValueColors: ${p.showPlaceValueColors}, showTenFrames: ${p.showTenFrames}, showProblemNumbers: ${p.showProblemNumbers}, showCellBorder: ${p.showCellBorder}, showBorrowNotation: ${p.showBorrowNotation}, showBorrowingHints: ${p.showBorrowingHints}),`
|
||||
return ` (operator: "−", minuend: ${p.minuend}, subtrahend: ${p.subtrahend}, showCarryBoxes: ${p.showCarryBoxes}, showAnswerBoxes: ${p.showAnswerBoxes}, showPlaceValueColors: ${p.showPlaceValueColors}, showTenFrames: ${p.showTenFrames}, showProblemNumbers: ${p.showProblemNumbers}, showCellBorder: ${p.showCellBorder}, showBorrowNotation: ${p.showBorrowNotation}, showBorrowingHints: ${p.showBorrowingHints}),`;
|
||||
}
|
||||
})
|
||||
.join('\n')
|
||||
.join("\n");
|
||||
|
||||
// Calculate actual number of rows on this page
|
||||
const actualRows = Math.ceil(pageProblems.length / config.cols)
|
||||
const actualRows = Math.ceil(pageProblems.length / config.cols);
|
||||
|
||||
// Use smaller margins to maximize space
|
||||
const margin = 0.4
|
||||
const contentWidth = config.page.wIn - margin * 2
|
||||
const contentHeight = config.page.hIn - margin * 2
|
||||
const margin = 0.4;
|
||||
const contentWidth = config.page.wIn - margin * 2;
|
||||
const contentHeight = config.page.hIn - margin * 2;
|
||||
|
||||
// Calculate grid spacing based on ACTUAL rows on this page
|
||||
const headerHeight = 0.35 // inches for header
|
||||
const availableHeight = contentHeight - headerHeight
|
||||
const problemBoxHeight = availableHeight / actualRows
|
||||
const problemBoxWidth = contentWidth / config.cols
|
||||
const headerHeight = 0.35; // inches for header
|
||||
const availableHeight = contentHeight - headerHeight;
|
||||
const problemBoxHeight = availableHeight / actualRows;
|
||||
const problemBoxWidth = contentWidth / config.cols;
|
||||
|
||||
// Calculate cell size assuming MAXIMUM possible embellishments
|
||||
// Check if ANY problem on this page might show ten-frames
|
||||
const anyProblemMayShowTenFrames = enrichedProblems.some((p) => p.showTenFrames)
|
||||
const anyProblemMayShowTenFrames = enrichedProblems.some(
|
||||
(p) => p.showTenFrames,
|
||||
);
|
||||
|
||||
// Calculate cell size to fill the entire problem box
|
||||
// Base vertical stack: carry row + addend1 + addend2 + line + answer = 5 rows
|
||||
@@ -153,13 +172,13 @@ function generatePageTypst(
|
||||
//
|
||||
// Horizontal constraint: maxDigits columns + 1 for + sign
|
||||
// Cell size must fit: (maxDigits + 1) * cellSize <= problemBoxWidth
|
||||
const maxCellSizeForWidth = problemBoxWidth / (maxDigits + 1)
|
||||
const maxCellSizeForWidth = problemBoxWidth / (maxDigits + 1);
|
||||
const maxCellSizeForHeight = anyProblemMayShowTenFrames
|
||||
? problemBoxHeight / 6.0
|
||||
: problemBoxHeight / 4.5
|
||||
: problemBoxHeight / 4.5;
|
||||
|
||||
// Use the smaller of width/height constraints
|
||||
const cellSize = Math.min(maxCellSizeForWidth, maxCellSizeForHeight)
|
||||
const cellSize = Math.min(maxCellSizeForWidth, maxCellSizeForHeight);
|
||||
|
||||
return String.raw`
|
||||
// addition-worksheet-page.typ (auto-generated)
|
||||
@@ -177,13 +196,13 @@ function generatePageTypst(
|
||||
|
||||
#let heavy-stroke = 0.8pt
|
||||
#let show-ten-frames-for-all = ${
|
||||
config.mode === 'manual'
|
||||
config.mode === "manual"
|
||||
? config.showTenFramesForAll
|
||||
? 'true'
|
||||
: 'false'
|
||||
: config.displayRules.tenFrames === 'always'
|
||||
? 'true'
|
||||
: 'false'
|
||||
? "true"
|
||||
: "false"
|
||||
: config.displayRules.tenFrames === "always"
|
||||
? "true"
|
||||
: "false"
|
||||
}
|
||||
|
||||
${generatePlaceValueColors()}
|
||||
@@ -261,7 +280,7 @@ ${problemsTypst}
|
||||
)
|
||||
|
||||
] // End of constrained block
|
||||
`
|
||||
`;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,17 +288,22 @@ ${problemsTypst}
|
||||
*/
|
||||
export function generateTypstSource(
|
||||
config: WorksheetConfig,
|
||||
problems: WorksheetProblem[]
|
||||
problems: WorksheetProblem[],
|
||||
): string[] {
|
||||
// Use the problemsPerPage directly from config (primary state)
|
||||
const problemsPerPage = config.problemsPerPage
|
||||
const rowsPerPage = problemsPerPage / config.cols
|
||||
const problemsPerPage = config.problemsPerPage;
|
||||
const rowsPerPage = problemsPerPage / config.cols;
|
||||
|
||||
// Chunk problems into discrete pages
|
||||
const pages = chunkProblems(problems, problemsPerPage)
|
||||
const pages = chunkProblems(problems, problemsPerPage);
|
||||
|
||||
// Generate separate Typst source for each page
|
||||
return pages.map((pageProblems, pageIndex) =>
|
||||
generatePageTypst(config, pageProblems, pageIndex * problemsPerPage, rowsPerPage)
|
||||
)
|
||||
generatePageTypst(
|
||||
config,
|
||||
pageProblems,
|
||||
pageIndex * problemsPerPage,
|
||||
rowsPerPage,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user