fix(StartPracticeModal): responsive improvements + integrated tutorial CTA

- Full-screen mode at ≤700px height for iPhone SE support
- Two-column grid layout for settings in landscape mode
- Integrated tutorial CTA: combines unlock banner + start button
- Fixed collapsed mode clipping of target skills section
- Made "focusing on weak skills" visible on all screen sizes
- Fixed duplicate CSS media query breakpoints
- BKT: changed computeBktFromHistory to accept Partial<BktComputeExtendedOptions>

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-12-18 10:49:49 -06:00
parent 5735ff0810
commit 56742c511d
2 changed files with 577 additions and 349 deletions

File diff suppressed because it is too large Load Diff

View File

@ -75,8 +75,10 @@ function applyTimeDecay(
*/ */
export function computeBktFromHistory( export function computeBktFromHistory(
results: ProblemResultWithContext[], results: ProblemResultWithContext[],
options: BktComputeExtendedOptions = DEFAULT_BKT_OPTIONS options: Partial<BktComputeExtendedOptions> = {}
): BktComputeResult { ): BktComputeResult {
// Merge with defaults so callers can override just what they need
const opts: BktComputeExtendedOptions = { ...DEFAULT_BKT_OPTIONS, ...options }
// Sort by timestamp to replay in chronological order // Sort by timestamp to replay in chronological order
// Note: timestamp may be a Date or a string (from JSON serialization) // Note: timestamp may be a Date or a string (from JSON serialization)
const sorted = [...results].sort((a, b) => { const sorted = [...results].sort((a, b) => {
@ -126,7 +128,7 @@ export function computeBktFromHistory(
const evidenceWeight = helpWeight * rtWeight const evidenceWeight = helpWeight * rtWeight
// Compute BKT updates (conjunctive model) // Compute BKT updates (conjunctive model)
const blameMethod = options.blameMethod ?? 'heuristic' const blameMethod = opts.blameMethod ?? 'heuristic'
const updates = result.isCorrect const updates = result.isCorrect
? updateOnCorrect(skillRecords) ? updateOnCorrect(skillRecords)
: updateOnIncorrectWithMethod(skillRecords, blameMethod) : updateOnIncorrectWithMethod(skillRecords, blameMethod)
@ -158,13 +160,13 @@ export function computeBktFromHistory(
// Apply decay if enabled // Apply decay if enabled
let finalPKnown = state.pKnown let finalPKnown = state.pKnown
if (options.applyDecay && state.lastPracticedAt) { if (opts.applyDecay && state.lastPracticedAt) {
const daysSinceLastPractice = const daysSinceLastPractice =
(now.getTime() - state.lastPracticedAt.getTime()) / (1000 * 60 * 60 * 24) (now.getTime() - state.lastPracticedAt.getTime()) / (1000 * 60 * 60 * 24)
finalPKnown = applyTimeDecay( finalPKnown = applyTimeDecay(
state.pKnown, state.pKnown,
daysSinceLastPractice, daysSinceLastPractice,
options.decayHalfLifeDays, opts.decayHalfLifeDays,
state.params.pInit state.params.pInit
) )
} }
@ -175,7 +177,7 @@ export function computeBktFromHistory(
const masteryClassification = classifyMastery( const masteryClassification = classifyMastery(
finalPKnown, finalPKnown,
confidence, confidence,
options.confidenceThreshold opts.confidenceThreshold
) )
skills.push({ skills.push({