Commit Graph

1479 Commits

Author SHA1 Message Date
Thomas Hallock d6f1c13317 fix(404): reset easter egg config on page reload/close
Fix easter egg persistence bug where custom bead styles from the 404
page easter eggs (200, 404, 666, etc.) would persist across page reloads
and browser sessions when they should only last for the current session.

Root cause:
- Easter eggs call updateConfig() which saves to localStorage
- AbacusDisplayProvider loads from localStorage on mount
- Easter egg customization persisted indefinitely

Solution:
- Save original abacus config on 404 page mount
- Restore original config on beforeunload event
- Easter eggs persist while navigating site (client-side routing)
- Easter eggs reset on page reload or tab close

Behavior:
 Easter egg persists across Next.js navigation (Link, router.push)
 Easter egg resets on page reload (F5, Cmd+R)
 Easter egg resets on tab/window close
 Restores user's original bead style, not just defaults

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 20:33:36 -06:00
Thomas Hallock d992e98d77 feat: enable production source maps for easier debugging
Added productionBrowserSourceMaps: true to Next.js config to enable
source maps in production builds. This will make client-side errors
much easier to debug by showing the original TypeScript source files
and line numbers instead of minified JavaScript.

Trade-off: Slightly larger build artifacts, but worth it for the
improved debugging experience. Source maps are downloaded on-demand
only when DevTools are open.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 20:32:06 -06:00
Thomas Hallock 69f759a178 fix(tutorial): expose activeGroupTargetColumn state to context
Fixed production runtime error "TypeError: d.value is not a function"
in tutorial component caused by missing context values.

Root cause:
- TutorialContext interface declared activeGroupTargetColumn and
  setActiveGroupTargetColumn properties
- State variables were defined with underscore prefixes (_activeGroupTargetColumn)
  indicating they were unused
- These values were not included in the context value object
- Components attempting to call setActiveGroupTargetColumn() received
  undefined and crashed with "is not a function"

Fix:
- Removed underscore prefixes from state variable declarations
- Added activeGroupTargetColumn and setActiveGroupTargetColumn to
  context value object
- Components now receive proper state and setter functions

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 20:31:47 -06:00
Thomas Hallock cd75df7221 chore: restore stashed work from previous session
Recover all changes from stash including:
- Linter/formatter updates across codebase
- Settings permission updates for git checkout

This commit captures the complete state of work that was
stashed during the previous session's git operations.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:59:40 -06:00
Thomas Hallock 3f700af643 fix(worksheets): add borrowNotation and borrowingHints to validation fallback
Add missing subtraction-specific scaffold fields to the fallback displayRules
object in validation.ts to ensure all DisplayRules fields have defaults.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:58:01 -06:00
Thomas Hallock 5a8fc5735d chore: update Claude settings 2025-11-08 14:58:01 -06:00
Thomas Hallock b956e2d605 fix(worksheets): add backward compatibility for displayRules in SmartModeControls
Use type casting to safely access borrowNotation and borrowingHints fields
from formState.displayRules, which may not have these fields if coming from
old worksheet configurations.

Provides fallback to profile defaults when fields are missing.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:58:01 -06:00
Thomas Hallock 3b908ac453 fix(worksheets): add borrowNotation and borrowingHints to DisplayRules interfaces
Add missing subtraction-specific scaffold fields to DisplayRules and
ResolvedDisplayOptions interfaces, and include them in resolveDisplayForProblem.

This fixes TypeScript errors and ensures these fields are properly resolved
for each problem in smart difficulty mode.

Part of subtraction scaffolding integration that was lost during git stash.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:58:01 -06:00
Thomas Hallock 8020ee835e 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>
2025-11-08 14:50:05 -06:00
Thomas Hallock e5262e5007 feat: remove redundant navigation buttons from 404 page
Remove the three navigation buttons (Home, Games, Create) since the app
already has a navigation bar. Keep the page clean and focused on the
interactive abacus easter egg experience.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:44:41 -06:00
Thomas Hallock 17561829ef feat: remove all easter egg hints from 404 page
Completely remove the hint text to preserve the mystery and joy of discovery.
Let users find the easter eggs on their own!

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:43:57 -06:00
Thomas Hallock c2c71531ae feat: hide easter egg hint until first discovery
Remove the "Try other HTTP status codes..." hint from the default 404 page.
Now the hint only appears AFTER discovering the first easter egg, preserving
the element of surprise and discovery.

Let users stumble upon the easter eggs organically!

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:43:07 -06:00
Thomas Hallock e88380a48d feat: add smooth fade-in animation for 404 message text changes
When the user changes the abacus value to trigger different easter eggs,
the message text now fades in smoothly with a subtle upward motion.

- Add fadeKey state that increments on text changes
- Use key prop on h1 to force re-mount and trigger animation
- Custom fadeInText keyframe: opacity 0→1 with translateY(-10px→0)
- 0.5s ease-out animation timing
- Prevents jarring text swaps, creates polished UX

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:41:29 -06:00
Thomas Hallock dd14062112 feat: add themed backgrounds and enhanced styling to 404 page
Transform 404 page into a vibrant, playful experience with:

Themed Backgrounds:
- Each HTTP status code has custom gradient background
- Animated radial glow effects that pulse with theme colors
- Smooth transitions between themes (0.6s ease-in-out)
- 14 unique color schemes matching easter egg personality

Enhanced Typography:
- Responsive font sizes (1.75rem mobile → 4rem desktop)
- Black font weight for maximum impact
- Dynamic text colors matching each theme
- Glowing text shadows for easter egg modes
- Tight letter spacing (-0.02em) for modern look

Navigation Buttons:
- Added emoji icons (🏠 🎮 )
- Lift-and-scale hover animation
- Colored shadows matching button colors
- Responsive sizing for mobile
- Smooth cubic-bezier transitions

Responsive Layout:
- Increased spacing between abacus and text (2-4rem)
- Mobile-optimized gaps and padding
- Text pushed down to prevent overlap with large abacus
- Smaller screens get appropriate scaling

Dynamic Hints:
- Changes based on active easter egg
- "Try other codes..." vs "Click beads to discover more..."
- Themed text color and opacity
- Italic, medium weight for subtle emphasis

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:36:02 -06:00
Thomas Hallock 41de25238f feat: make 404 page abacus hero-sized and responsive
Scale the interactive 404 abacus to match the hero section sizing with
responsive breakpoints:
- Mobile (base): 1.5x scale
- Small (sm): 2x scale
- Medium (md): 2.5x scale
- Large (lg): 3x scale

Prevent layout dominance on small screens with maxWidth constraints
and centered positioning.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:30:35 -06:00
Thomas Hallock fde5ae9164 feat: add function-based custom bead rendering and HTTP status code easter eggs
Add dynamic custom bead rendering system that allows beads to change appearance
based on their context (active state, position, place value, type, etc.).

Custom Bead Features:
- Add emoji-function, image-function, and svg-function types
- Functions receive CustomBeadContext with bead state and style info
- Support for dynamic rendering based on: active state, position, place value,
  bead type (heaven/earth), color, and size
- Enables creative visualizations like traffic lights, themed symbols, etc.

404 Page Easter Eggs:
- Create interactive 404 page with manipulable abacus
- Add 14 HTTP status code easter eggs (200, 201, 301, 400, 401, 403, 418,
  420, 451, 500, 503, 666, 777, 911)
- Each code triggers site-wide custom bead transformation
- Use function-based rendering for variety (different emojis per bead
  position/state)
- Easter eggs persist until page reload via global AbacusDisplayContext

Storybook Documentation:
- Add comprehensive custom bead stories showing static and function-based usage
- Include examples: active/inactive states, heaven/earth types, place value
  colors, traffic lights, color theming
- Document CustomBeadContext API and usage patterns

Technical Implementation:
- Extend CustomBeadContent union type in AbacusContext
- Update AbacusStaticBead and AbacusAnimatedBead to handle function types
- Pass bead context (type, value, active, position, placeValue, color, size)
  to custom render functions
- Maintain consistency across static (SSR) and animated (client) rendering

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock 8407b070f9 feat(worksheets): filter operator-specific scaffolds from preset summaries
When displaying difficulty preset descriptions in dropdown, filter out
scaffolds that don't apply to the current operator:

- Addition-only: hide borrowNotation, borrowingHints from summaries
- Subtraction-only: hide carryBoxes, tenFrames from summaries
- Mixed: show all scaffolds

Updated function:
- getScaffoldingSummary(): added operator parameter with conditional
  scaffold checking based on operator type

Fixes issue where preset dropdown showed subtraction-specific scaffolds
(borrow notation, borrowing hints) even for addition-only worksheets.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock cace1c75c6 feat(worksheets): filter operator-specific scaffolds from difficulty change descriptions
When adjusting difficulty via Make Harder/Easier buttons, filter out
scaffolds that don't apply to the current operator:

- Addition-only: hide borrowNotation, borrowingHints from descriptions
- Subtraction-only: hide carryBoxes, tenFrames from descriptions
- Mixed: show all scaffolds

Updated functions:
- describeScaffoldingChange(): added operator parameter with filtering logic
- makeHarder(): passes operator to describeScaffoldingChange
- makeEasier(): passes operator to describeScaffoldingChange
- SmartModeControls: passes formState.operator to both functions

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock d23b606642 fix(worksheets): Add "Practice" difficulty profile for scaffolded regrouping mastery
CRITICAL PEDAGOGICAL FIX: The difficulty progression was removing scaffolding
at the same time regrouping was being introduced, which is backwards!

The Problem:
- Beginner: 0% regrouping, 100% scaffolding ✓
- Early Learner: 25% regrouping, 100% scaffolding ✓
- Intermediate: 75% regrouping, 50% scaffolding ✗ WRONG!
- Advanced/Expert: 90% regrouping, 0% scaffolding ✗ WRONG!

Students were losing scaffolds (answer boxes, place value colors, ten-frames)
exactly when they needed them most - during intensive regrouping practice.

The Fix:
Added new "Practice" difficulty profile between Early Learner and Intermediate:

- Beginner: 0% regrouping, 100% scaffolding (learn structure)
- Early Learner: 25% regrouping, 100% scaffolding (introduce regrouping)
- **Practice: 75% regrouping, 100% scaffolding** ← NEW! (master WITH support)
- Intermediate: 75% regrouping, 50% scaffolding (begin removing support)
- Advanced/Expert: 90% regrouping, 0% scaffolding (full mastery)

Practice Profile Details:
- regrouping: { pAllStart: 0.25, pAnyStart: 0.75 } (same as Intermediate)
- carryBoxes: 'whenRegrouping' (show borrow/carry boxes when needed)
- answerBoxes: 'always' (keep guiding placement during intensive practice)
- placeValueColors: 'always' (keep visual support)
- tenFrames: 'whenRegrouping' (visual aid for regrouping)

Pedagogical Rationale:
Students need a "plateau phase" where they practice regrouping frequently
WITH full scaffolding support before we start removing training wheels.

This is especially critical for subtraction borrowing:
- First encounter borrowing with low frequency (Early Learner)
- Then practice borrowing intensively WITH scaffolds (Practice)
- Then gradually remove scaffolds as mastery develops (Intermediate → Expert)

Impact:
- Teachers selecting "Practice" mode get frequent regrouping with full support
- Smart difficulty progression no longer removes scaffolds prematurely
- Addresses user feedback: "we start turning off scaffolding for subtraction
  as soon as we introduce regrouping, which defeats the whole point"

Updated DIFFICULTY_PROGRESSION:
['beginner', 'earlyLearner', 'practice', 'intermediate', 'advanced', 'expert']

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 14:28:58 -06:00
Thomas Hallock 693b679965 feat: add theme support to worksheet preview
Add light/dark mode support to WorksheetPreview component:
- Preview title and subtitle text adapt to theme
- SVG preview container uses themed background
- Pagination text adjusts for readability
- Info box uses blue theme variants (light or dark)
- Maintains brand button colors across themes
- Pass isDark through Suspense boundary

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock e38775b991 feat: add theme support to orientation and generate panels
Add light/dark mode support to OrientationPanel and GenerateButton:
- OrientationPanel: themed backgrounds for all sections
- Orientation buttons adapt to theme (selected/unselected states)
- Page number buttons use themed backgrounds
- Problems per page dropdown has themed content
- Dropdown items and labels adjust for readability
- Total badge remains consistent (brand colors)
- GenerateButton panel uses themed background

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock c8684213fa feat: add theme support to config panel components
Add light/dark mode support to all config panel components:
- StudentNameInput: themed input backgrounds and borders
- DigitRangeSection: themed section backgrounds and text
- OperatorSection: themed button states
- ModeSelector: themed mode selection cards
- ProgressiveDifficultyToggle: themed switch and backgrounds
- ToggleOption: themed toggle containers and text
- SmartModeControls & ManualModeControls: pass isDark prop through

All components now respond to light/dark theme with appropriate
backgrounds, borders, and text colors for optimal readability.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock 5c14925d7d feat: add theme support to worksheet page container
Add light/dark mode support to AdditionWorksheetClient:
- Page background adapts to theme
- Header text colors adjust for readability
- Card panels use theme-appropriate backgrounds
- Settings status messages use themed colors
- Pass isDark prop to all child components

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock 8d8e55d5c4 fix(worksheets): Fix subtraction regrouping frequency bug
CRITICAL BUG FIX: Subtraction problems weren't generating with expected
borrowing frequency when pAllStart/pAnyStart were set to 100%.

Root Cause:
The old `generateBothBorrow()` used naive digit comparison (digitM < digitS)
to count borrows, which:
1. Doesn't account for cascading borrows across zeros (e.g., 100 - 1)
2. Returns ZERO problems for 2-digit numbers (mathematically impossible
   to have both digits show digitM < digitS without negative result)

When user set regrouping to 100%, generator tried to create "both" problems
but failed every time, falling back to random problems or duplicates.

Fixes:
1. Added `countBorrows()` function that simulates actual subtraction algorithm
   - Tracks borrow operations through place values
   - Counts cascading borrows across zeros correctly
   - Example: 100 - 1 = 2 borrows (hundreds → tens → ones)

2. Updated `generateBothBorrow()` to:
   - Fall back to ones-only borrowing for 1-2 digit ranges (impossible to get 2+ borrows)
   - Favor higher digit counts (3+) when possible
   - Use correct borrow counting via `countBorrows()`

3. Changed fallback from [93, 57] (1 borrow) to [100, 1] or [534, 178] (2+ borrows)

Impact:
- 2-digit subtraction with pAll=100% now generates maximum difficulty (ones-only borrowing)
- 3+ digit subtraction with pAll=100% now correctly generates 2+ borrow problems
- User will see appropriate borrowing frequency at all difficulty settings

Test Examples:
- 52 - 17: 1 borrow ✓
- 100 - 1: 2 borrows ✓
- 534 - 178: 2 borrows ✓
- 1000 - 1: 3 borrows ✓

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 13:11:41 -06:00
Thomas Hallock 702c1c9af2 feat: add theme support to MyAbacus button
Add light/dark mode responsiveness to the floating MyAbacus button:
- Light mode: white background with golden accent border
- Dark mode: dark background with golden accent border
- Theme-aware box shadows for better visibility in each mode
- Maintains golden glow effect across both themes

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:25:41 -06:00
Thomas Hallock 515e4c4f98 refactor: convert LanguageSelector to Radix UI with theme support
Replace native <select> element with Radix UI DropdownMenu and add
full light/dark theme support.

Changes:
- Replace native select with Radix UI DropdownMenu
- Add useTheme hook to detect current theme (light/dark)
- Theme-aware button styling:
  - Dark mode: gray.800 background with gray.700 border
  - Light mode: white background with gray.300 border
  - Fullscreen: black transparent with purple border
- Theme-aware dropdown content:
  - Dark mode: gray.900 background
  - Light mode: white background
  - Proper contrast for all text and hover states
- Add dropdown chevron icon that rotates when open
- Add checkmark (✓) for currently selected language
- Both variants (dropdown-item and inline) now use Radix UI
- Highlight selected language with background color
- Smooth transitions and proper hover states for both themes

Improves accessibility and consistency with other dropdowns.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:18:43 -06:00
Thomas Hallock 2e294ee820 feat: add theme support to abacus style dropdown
Make AbacusDisplayDropdown respond to light/dark mode.

Changes:
- Integrate useTheme hook to detect current theme
- Update button styling:
  - Dark mode: gray.800 background with gray.700 border
  - Light mode: white background with gray.200 border
- Update dropdown content styling:
  - Dark mode: gray.900 background with gray.800 border
  - Light mode: white background with gray.200 border
- Update all text colors for theme contrast:
  - Headers, labels, descriptions adapt to theme
- Update form controls for theme:
  - Switch backgrounds (gray.700 dark, gray.300 light)
  - Radio button borders and backgrounds
  - Volume slider track (gray.700 dark, gray.200 light)

All components now properly support light/dark themes while
maintaining existing fullscreen mode styling.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:17:26 -06:00
Thomas Hallock ab9272bee6 feat: add theme support to desktop hamburger menu
Make desktop dropdown menu and button respond to light/dark mode.

Changes:
- Desktop hamburger button background:
  - Dark mode: rgba(31, 41, 55, 0.9) with gray border
  - Light mode: white with light gray border
- Desktop hamburger button icon color:
  - Dark mode: light gray text
  - Light mode: dark gray text
- Desktop dropdown content background:
  - Dark mode: dark gray gradient
  - Light mode: white/light gray gradient
- Desktop dropdown box shadow:
  - Dark mode: darker shadow with purple border
  - Light mode: lighter shadow with subtle purple border

Maintains existing fullscreen mode styling (black background).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:14:29 -06:00
Thomas Hallock b57458b039 feat: implement two-column landscape layout with smart viewport-based flexbox
- Add two-column CSS Grid layout for landscape orientation (≥480px)
- Implement proper flexbox sizing chain to prevent scrolling:
  - Use minHeight: 0 and flex: 1 1 auto throughout container hierarchy
  - Only allow overflow on grid container when content truly exceeds viewport
- Compact spacing for better viewport fit:
  - Reduced padding: 8px 12px (from 16px 20px)
  - Reduced font size: 14px (from 18px)
  - Reduced icon size: 18px (from 24px)
  - Reduced gaps: 16px base, 20px landscape, 8px on short screens
- Responsive gap sizing based on viewport height
- Column 1: Navigation + Controls
- Column 2: Abacus Style + Language + Theme

The menu now uses proper CSS layout techniques to fit within viewport
bounds, only scrolling when content genuinely exceeds available space.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:11:49 -06:00
Thomas Hallock 3ad244f2d3 feat: make mobile menu more responsive with larger touch targets
Improve mobile full-screen menu to better utilize screen space with
larger, more touch-friendly UI elements.

Changes:
- Increase font sizes on mobile (18px links, 24px icons vs 14px/16px)
- Larger padding and gaps (16px-20px vs 10px-14px on desktop)
- Bigger border radius on mobile (12px vs 8px) for modern feel
- Increase section header spacing and size
- Add centered max-width container (600px) with top padding for close button
- Extract controlButtonStyle helper to avoid duplication
- Update all hover states to be theme-aware (light/dark)

Layout improvements:
- Content centered with max-width constraint
- Top padding (60px) to avoid close button overlap
- Consistent spacing between sections (20px margins)
- Icons scale appropriately (24px on mobile vs 16px desktop)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:11:49 -06:00
Thomas Hallock ea41b323d0 feat: add close button and theme support to mobile menu
Improve mobile full-screen menu UX with explicit close button and
light/dark theme responsiveness.

Changes:
- Add fixed close button (X) in top-right corner of mobile menu
- Integrate useTheme hook to detect current theme (light/dark)
- Theme-aware styling for menu background, text, and hover states
  - Dark mode: Dark gray gradients, light text
  - Light mode: Light gray gradients, dark text
- Pass resolvedTheme to MenuContent for consistent theming
- Update hover colors to match theme (purple variants)

UX improvements:
- Close button provides clear affordance for dismissing menu
- Clicking backdrop still closes menu as before
- Menu visually adapts to system/user theme preference

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 12:11:49 -06:00
Thomas Hallock 615cd28829 feat: implement full-screen mobile hamburger menu with portal
Refactor hamburger menu to use custom full-screen overlay on mobile
instead of Radix UI dropdown, fixing z-index stacking context issues.

Key changes:
- Extract MenuContent component for shared rendering logic between
  mobile and desktop versions
- Implement custom full-screen mobile menu with viewport detection
- Use React Portal to render mobile menu outside header's stacking
  context, ensuring it layers above hero abacus (z-index 9999 > 10)
- Desktop continues using Radix UI dropdown menu as before
- Mobile menu closes on navigation and backdrop click

Technical details:
- Header's opacity: 0.95 creates stacking context, constraining child
  z-indexes. Portal breaks out to document.body for global z-index.
- Conditional rendering based on viewport width (640px breakpoint)
- Shared MenuContent adapts rendering (plain divs vs Radix components)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 85db052f07 refactor(worksheets): Phase 5 - Final ConfigPanel cleanup
Final optimization of ConfigPanel.tsx:
- Removed all unused helper functions (getDefaultColsForProblemsPerPage, calculateDerivedState)
- Removed unused state variables (currentOrientation, currentProblemsPerPage, currentCols, currentPages)
- Removed unused handleDifficultyChange function (now in SmartModeControls)
- Removed all console.log debugging statements
- Added missing defaultAdditionConfig import
- ConfigPanel reduced to 105 lines (95.9% reduction from original 2550 lines)

Fixed ManualModeControls:
- Added missing Slider import from @radix-ui/react-slider
- Fixed runtime error: "ReferenceError: Slider is not defined"

Cleanup:
- Removed ConfigPanel.tsx.bak backup file
- Removed temporary shell scripts (/tmp/create_manual_mode.sh, /tmp/replace_manual_mode.sh)

ConfigPanel now contains ONLY:
- Props interface
- Mode switching handler (smart ↔ manual)
- Clean JSX rendering extracted components

All 5 phases of refactoring complete:
 Phase 1: Helper components (utils, SubOption, ToggleOption)
 Phase 2: Shared sections (StudentName, DigitRange, Operator, ProgressiveDifficulty)
 Phase 3: Smart Mode controls (1412 lines → SmartModeControls.tsx)
 Phase 4: Manual Mode controls (339 lines → ManualModeControls.tsx)
 Phase 5: Final cleanup (2550 lines → 105 lines)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 4cf6fcab15 refactor(worksheets): Phase 4 - Extract Manual Mode controls
Extract Manual Mode section from ConfigPanel into dedicated component:
- Created ManualModeControls.tsx (339 lines)
- Display options toggles with Check All/Uncheck All buttons
- Live preview panel (DisplayOptionsPreview)
- Regrouping frequency double-thumb slider
- ConfigPanel reduced to 207 lines (91.9% reduction from original 2550)

Removed from ConfigPanel:
- SubOption, ToggleOption, DisplayOptionsPreview imports
- defaultAdditionConfig import
- useTranslations hook and 't' variable
- Entire Manual Mode section (lines 210-531)

Fixed parsing error in ManualModeControls:
- Removed extra closing paren from fragment structure
- Formatted with biome

All display options now properly organized:
- Answer boxes, carry/borrow boxes, place value colors
- Ten-frames with sub-option for all problems
- Borrowing notation and hints (conditional on operator)
- Problem numbers, cell borders

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 76a6168b00 refactor(worksheets): extract Smart Mode controls (Phase 3 complete)
Extracted the massive Smart Mode section (~1384 lines) into a dedicated
SmartModeControls component. This section includes difficulty presets,
easier/harder buttons, and the interactive 2D difficulty visualization.

Extracted component:
- SmartModeControls.tsx: Complete smart mode UI (~1412 lines)
  - Difficulty preset dropdown
  - Make easier/harder buttons with alternative modes
  - Overall difficulty slider
  - 2D difficulty space visualizer with interactive SVG
  - Hover preview and snap-to-preset functionality

Changes:
- Removed unused imports from ConfigPanel (React, Slider, Tooltip, DropdownMenu, difficulty functions)
- Removed unused state variables (showDebugPlot, hoverPoint, hoverPreview)
- Updated ConfigPanel to import and use SmartModeControls
- File size reduced: 1942 → 534 lines (-1408 lines, 72.5% reduction!)

Total progress: 2550 → 534 lines (-2016 lines, 79.1% reduction)

Zero functionality change - all smart mode features work identically.
Phase 3 of 5 complete.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock d27e2c03bd refactor(worksheets): extract shared ConfigPanel sections (Phase 2 complete)
Extracted all shared UI sections that appear in both smart and manual modes
to separate components for improved modularity and reusability.

Extracted components:
- DigitRangeSection.tsx: Digit range slider with tick marks (~170 lines)
- OperatorSection.tsx: Operator selection buttons (~120 lines)
- ProgressiveDifficultyToggle.tsx: Progressive difficulty toggle (~90 lines)

Changes:
- Removed unused imports (Slider, Switch - now in extracted components)
- Updated ConfigPanel.tsx to use new components
- File size reduced: 2286 → 1942 lines (-344 lines)

Total progress so far: 2550 → 1942 lines (-608 lines, 23.8% reduction)

Zero functionality change - all components work identically.
Phase 2 of 5 complete.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock cbe29d5c54 refactor(worksheets): extract StudentNameInput component (Phase 2 - partial)
Extracted Student Name input field to separate component as part of Phase 2.

Changes:
- Created StudentNameInput.tsx component (32 lines)
- Updated ConfigPanel.tsx to use new component
- File size reduced: 2306 → 2286 lines (-20 lines)

Remaining Phase 2 work: Extract DigitRangeSection, OperatorSection, and ProgressiveDifficultyToggle components.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 3656800534 refactor(worksheets): extract ConfigPanel helper components (Phase 1)
Created config-panel/ subdirectory and extracted reusable UI components
from the monolithic 2550-line ConfigPanel.tsx file.

Extracted components:
- utils.tsx: getScaffoldingSummary() function
- SubOption.tsx: Nested toggle UI component
- ToggleOption.tsx: Main toggle option with description

Changes:
- Created src/app/create/worksheets/addition/components/config-panel/ directory
- Moved 3 helper functions/components to separate files (~240 lines)
- Updated ConfigPanel.tsx to import from new locations
- Removed unused imports (Checkbox, findNearestPreset)
- File size reduced: 2550 → 2306 lines (-244 lines)

Zero functionality change - all components work identically.
Part 1 of 5-phase refactoring plan.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock 15bded1ab8 feat(worksheets): integrate subtraction scaffolding into smart difficulty mode
Previously, smart mode hardcoded showBorrowNotation and showBorrowingHints
to false. Now these fields are properly integrated into the display rules
system and scaffolding progression.

Changes:
- Extended DisplayRules interface with borrowNotation and borrowingHints fields
- Added fields to all 13 scaffolding levels and 5 difficulty profiles
- Updated config schemas (V2, V3, V4) with backward-compatible migrations
- Removed hardcoded false values in typstGenerator.ts
- Updated getScaffoldingSummary() to show new scaffolding aids
- Fixed typstGenerator subtraction parameter ordering (showCarryBoxes → showBorrowNotation)
- Fixed borrow hint text rendering (removed extra box wrapper)

Subtraction worksheets now receive the same conditional scaffolding
treatment as addition, with hints appearing at appropriate difficulty
levels and fading as students progress.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 11:50:49 -06:00
Thomas Hallock d05c6a8664 fix: use semantic tokens for nav bar transparent mode on hero
Replace hardcoded white colors in transparent nav mode with semantic tokens
that adapt to light/dark themes:

Transparent mode (hero overlay):
- Text: white → text.primary / text.secondary
- Background: rgba(255,255,255,0.08) → bg.subtle / bg.muted
- Borders: rgba(255,255,255,0.15) → border.subtle / border.default
- Hover: rgba(255,255,255,0.25) → interactive.hover

This fixes invisible white text on light backgrounds when viewing the
homepage hero in light mode.

Non-transparent mode (regular nav) remains unchanged with existing colors.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:09:46 -06:00
Thomas Hallock d9c58d74b5 Revert "fix: replace hardcoded colors with semantic tokens in nav bar links"
This reverts commit fc19a70a96.
2025-11-08 10:08:53 -06:00
Thomas Hallock fc19a70a96 fix: replace hardcoded colors with semantic tokens in nav bar links
Convert NavLink component from hardcoded light colors to semantic tokens:

- Inactive links: rgba(209, 213, 219, 0.9) → text.primary
- Active links: rgba(196, 181, 253, 1) → accent.emphasis
- Active background: rgba(139, 92, 246, 0.2) → accent.subtle
- Hover background: rgba(139, 92, 246, 0.25) → accent.muted

This fixes white/light gray text on white background in light mode for
Create, Guide, Games, and Blog navigation links.

Transparent mode (hero overlay) remains unchanged with white text.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:08:08 -06:00
Thomas Hallock ea10249e94 fix: add light/dark mode support to tutorial tooltips and decomposition UI
Use CSS light-dark() function to support both color schemes:

Decomposition reasoning tooltips:
- Background: white → dark in dark mode
- Borders: light gray → darker in dark mode
- Text: dark → light in dark mode
- Code blocks and steps: proper contrast in both modes

Tutorial player tooltips:
- Blue background adapts to theme
- Text remains white for good contrast

Fixes unreadable light text on light backgrounds in light mode.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:06:35 -06:00
Thomas Hallock e124096914 fix: replace hardcoded colors with semantic tokens in HomeBlogSection
Convert blog section from hardcoded rgba colors (dark mode only) to semantic
theme tokens that adapt to light/dark mode:

- text.primary, text.secondary, text.muted for content
- accent.subtle, accent.muted, accent.default for backgrounds/borders
- accent.emphasis for interactive text

This fixes unreadable white text on light backgrounds in light mode.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 10:02:46 -06:00
Thomas Hallock fcbf0f5421 fix(abacus-react): remove duplicate numeral rendering and fix dark mode colors
Two critical issues fixed:

1. **Duplicate numerals**: Both AbacusSVGRenderer and AbacusReact were rendering
   numerals when showNumbers={true}, causing two overlapping number displays.
   - Disabled SVG text numerals in AbacusSVGRenderer (line 436: added `false &&`)
   - NumberFlow provides better animated numerals, keep only those

2. **White numerals in dark mode**: NumberFlow components were inheriting CSS
   color from parent, turning white in dark mode (unreadable on light frames).
   - Added explicit color style to NumberFlow: uses themeAwareCustomStyles
   - Now consistently dark (rgba(0,0,0,0.8)) regardless of page theme

This was the root cause of the "white numerals everywhere" issue - the
NumberFlow components were inheriting dark mode CSS colors.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:43:18 -06:00
Thomas Hallock bc7ca12158 fix: add missing color definitions to example route
The example route was also missing generatePlaceValueColors() calls,
causing "unknown variable: color-ones" errors when rendering subtraction
examples. Added color definitions to both addition and subtraction templates.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:33:58 -06:00
Thomas Hallock 8b8dfeefbd fix: PDF generation now respects operator and digitRange settings
The PDF generation route was ignoring the operator and digitRange settings,
always generating 2-digit addition problems regardless of configuration.
The preview worked correctly but PDF generation was broken.

Changes:
- Add conditional logic to call appropriate problem generator based on operator
- Pass digitRange parameter to all problem generators
- Add generatePlaceValueColors() to Typst template for color definitions
- Import DisplayOptions type for internal use in typstHelpers

Fixes worksheet PDF generation for subtraction, mixed, and multi-digit problems.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:31:57 -06:00
Thomas Hallock a769fe1e20 refactor: complete subtraction modularization - 793 lines → modular structure
Major refactoring milestone: Successfully modularized subtraction problem
rendering from a monolithic 360-line function into focused, composable components.

File size reduction:
- typstHelpers.ts: 793 lines → 356 lines (55% reduction)
- Subtraction function: 360 lines → distributed across 6 focused files

New modular structure:
├── subtraction/
│   ├── problemStack.ts (120 lines) - Main composition function
│   ├── borrowBoxes.ts (94 lines) - Borrow boxes with hints/arrows
│   ├── minuendRow.ts (96 lines) - Top number with scratch boxes
│   ├── subtrahendRow.ts (75 lines) - Bottom number with − sign
│   └── answerRow.ts (126 lines) - Line, ten-frames, answer boxes
└── index.ts - Re-exports for backward compatibility

Benefits achieved:
 No file exceeds 130 lines (was 793 lines)
 Each component has single, clear responsibility
 Easier to locate and edit specific features
 Centralized constants (TYPST_CONSTANTS)
 Better separation of concerns
 Backward compatibility maintained via re-exports

Implementation details:
- Updated typstHelpers.ts to re-export from modular structure
- Removed old 360-line generateSubtractionProblemStackFunction
- All imports remain unchanged (backward compatible)
- No functional changes - pure refactoring

Next phase:
- Extract addition components (carry boxes, addend rows)
- Validate output matches current worksheets byte-for-byte
- Add unit tests for individual components

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 09:20:18 -06:00
Thomas Hallock b42daf9a4b refactor: begin modularizing typstHelpers.ts - extract shared components
Phase 1 of typstHelpers.ts refactoring (793 lines → modular structure)

Created new directory structure:
- typstHelpers/shared/ - Colors, helpers, types
- typstHelpers/addition/ - Addition-specific components (future)
- typstHelpers/subtraction/ - Subtraction-specific components

Extracted components:
- shared/colors.ts - Place value color definitions
- shared/types.ts - TypeScript types and constants
- shared/helpers.ts - Reusable Typst helpers (ten-frames, diagonal-split-box)
- subtraction/borrowBoxes.ts - Borrow boxes row rendering with hints/arrows

Benefits:
- Smaller, focused files (50-100 lines each vs 350+ line functions)
- Centralized constants (arrow positioning, stroke widths)
- Better separation of concerns
- Easier to locate and edit specific features

Next steps:
- Extract remaining subtraction rows (minuend, subtrahend, answer)
- Refactor main function to compose extracted components
- Maintain backward compatibility via facade pattern
- Validate output matches current worksheets byte-for-byte

See TYPST_HELPERS_REFACTOR_PLAN.md for complete plan.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:04:50 -06:00
Thomas Hallock b4586bac8e fix: disable place value colors in subtraction borrow boxes to fix arrow layering
The arrows in borrowing hints were being covered by the diagonal-split-box
colored backgrounds in adjacent cells. This occurred because Typst renders
elements in document order, and arrows placed inside colored boxes appear
below backgrounds from cells rendered later.

Solution: Disable place value colors in borrow boxes entirely. Borrow boxes
now always use stroke-only rendering (no colored backgrounds), which ensures
arrows are never covered. Place value colors still work everywhere else
(minuend, subtrahend, and answer rows).

This is simpler and more maintainable than complex double-render or
compositing approaches, and avoids the fundamental layering limitation.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-08 08:00:55 -06:00