Compare commits

...

21 Commits

Author SHA1 Message Date
semantic-release-bot
474d31576f chore(release): 4.13.7 [skip ci]
## [4.13.7](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.6...v4.13.7) (2025-10-18)

### Bug Fixes

* add dark color for abacus numerals ([73ff32c](73ff32c243)), closes [#1f2937](https://github.com/antialias/soroban-abacus-flashcards/issues/1f2937)
* use app-wide abacus config and remove instruction text ([0a50c73](0a50c733b0))
2025-10-18 23:07:53 +00:00
Thomas Hallock
73ff32c243 fix: add dark color for abacus numerals
Added customStyles to make numerals dark gray (#1f2937) with bold weight
for good contrast on white background.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 18:06:47 -05:00
Thomas Hallock
0a50c733b0 fix: use app-wide abacus config and remove instruction text
- Added useAbacusConfig() hook to get app-wide settings
- AbacusReact now respects beadShape, colorScheme, hideInactiveBeads from app config
- Removed "Click the beads to interact!" instruction text
- Simplified pane layout (just centered)

Now matches the styling/settings used throughout the rest of the app.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 18:06:47 -05:00
semantic-release-bot
1386378ca1 chore(release): 4.13.6 [skip ci]
## [4.13.6](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.5...v4.13.6) (2025-10-18)

### Bug Fixes

* simplify abacus pane with light background ([30f48ab](30f48ab897))
2025-10-18 23:05:58 +00:00
Thomas Hallock
30f48ab897 fix: simplify abacus pane with light background
- Changed background from dark to white for better contrast
- Removed duplicate number display (abacus has built-in numerals)
- Removed custom styles (defaults work well on light background)
- Updated instruction text color to gray.700 for readability

Abacus component isn't designed for dark mode yet, so light pane is simpler.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 18:04:49 -05:00
semantic-release-bot
d2f6b8b46c chore(release): 4.13.5 [skip ci]
## [4.13.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.4...v4.13.5) (2025-10-18)

### Bug Fixes

* correct AbacusReact API usage and add structural styling ([247377f](247377fca3)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78)
2025-10-18 23:01:22 +00:00
Thomas Hallock
247377fca3 fix: correct AbacusReact API usage and add structural styling
Fixed critical issues based on storybook examples:
- Changed callback syntax: onValueChange prop directly (not in callbacks object)
- Added reckoningBar styling: golden stroke (#fbbf24, 4px width)
- Added columnPosts styling: purple stroke (#a78bfa, 3px width)
- Now structural elements are visible on dark background and interactive works

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 18:00:23 -05:00
semantic-release-bot
be39401716 chore(release): 4.13.4 [skip ci]
## [4.13.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.3...v4.13.4) (2025-10-18)

### Bug Fixes

* **card-sorting:** increase card tile sizes to contain abacuses ([d2a3b7a](d2a3b7ae2e))
2025-10-18 22:56:13 +00:00
Thomas Hallock
d2a3b7ae2e fix(card-sorting): increase card tile sizes to contain abacuses
Make card tiles larger to properly contain AbacusReact SVGs without overflow.

**Issue:**
Card tiles were too small (90px × 90px and 90px × 110px) to contain the
AbacusReact SVGs, causing abacuses to overflow their containers.

**Fix:**
- **Available cards**: Increased from 90px × 90px to 140px × 140px
- **Position slots**: Increased from 90px × 110px to 140px × 160px

**Result:**
Abacus SVGs now fit comfortably within their card containers without
overflowing, while maintaining the overflow: hidden constraint as a
safety measure.

src/arcade-games/card-sorting/components/PlayingPhase.tsx:283-284,419-420

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:55:15 -05:00
semantic-release-bot
39ab605279 chore(release): 4.13.3 [skip ci]
## [4.13.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.2...v4.13.3) (2025-10-18)

### Bug Fixes

* **card-sorting:** increase SVG size to fill card containers ([cf9d893](cf9d893f3f))
2025-10-18 22:53:10 +00:00
Thomas Hallock
cf9d893f3f fix(card-sorting): increase SVG size to fill card containers
Make AbacusReact SVGs larger by allowing them to fill their containers.

**Issue:**
SVG containers were set to fixed small sizes (74px × 74px and 70px × 70px),
making the abacuses appear too small within their cards.

**Fix:**
- **Available cards**: Changed SVG container from 74px × 74px to 100% × 100%
  to fill the entire 90px card (accounting for 8px padding)
- **Position slots**: Changed SVG container from 70px × 70px to flex: 1,
  width: 100% to fill available space while leaving room for label

**Result:**
Abacuses now appear larger and fill their card containers better while
still being constrained by overflow: hidden to prevent breaking out.

src/arcade-games/card-sorting/components/PlayingPhase.tsx:314-329,456-473

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:51:57 -05:00
semantic-release-bot
e6d0bd4953 chore(release): 4.13.2 [skip ci]
## [4.13.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.1...v4.13.2) (2025-10-18)

### Bug Fixes

* show initial value and improve numeral contrast ([1b57f6d](1b57f6ddec)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
2025-10-18 22:51:19 +00:00
Thomas Hallock
1b57f6ddec fix: show initial value and improve numeral contrast
- Changed back to controlled value (with state update) to display initial 1234567
- Added customStyles for numerals: golden color (#fbbf24), bold, larger font
- Numerals now have excellent contrast against dark background

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:50:12 -05:00
semantic-release-bot
d38ea312a7 chore(release): 4.13.1 [skip ci]
## [4.13.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.0...v4.13.1) (2025-10-18)

### Bug Fixes

* use defaultValue for interactive abacus control ([06aca98](06aca986ac))
2025-10-18 22:47:40 +00:00
Thomas Hallock
06aca986ac fix: use defaultValue for interactive abacus control
Changed from controlled (value) to uncontrolled (defaultValue) pattern
to allow AbacusReact to fully manage its own state and be interactive.
Still tracks value changes via onValueChange callback for display.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:46:32 -05:00
semantic-release-bot
a126466037 chore(release): 4.13.0 [skip ci]
## [4.13.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.12.0...v4.13.0) (2025-10-18)

### Features

* make home page abacus interactive with audio ([9a53d7e](9a53d7e5db))
2025-10-18 22:45:39 +00:00
Thomas Hallock
9a53d7e5db feat: make home page abacus interactive with audio
Enhanced the hero abacus to be a fully interactive showcase:
- Increased size from default to 2.2x scale factor
- Enabled interactive mode (click beads to change value)
- Enabled smooth animations for bead movements
- Enabled audio feedback with volume at 0.4
- Added live value display below abacus in large golden text
- Added instructional text "Click the beads to interact!"
- Shows place value numbers on each column

The abacus now serves as a "try it now" demo right on the landing page.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:44:40 -05:00
semantic-release-bot
d2d8f7740f chore(release): 4.12.0 [skip ci]
## [4.12.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.11.1...v4.12.0) (2025-10-18)

### Features

* redesign home page with component showcase ([29af265](29af265958))
2025-10-18 22:44:06 +00:00
Thomas Hallock
29af265958 feat: redesign home page with component showcase
Replaced outdated landing page with component-based "storybook" design:
- Large featured AbacusReact component (1,234,567 with place-value colors)
- Color scheme showcase with 4 actual AbacusReact instances
- Dark, fancy theme with purple gradients and golden accents
- All game links now point to /games instead of /arcade
- Hover animations and visual polish throughout
- Dot pattern background texture

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:42:55 -05:00
semantic-release-bot
291bcc581d chore(release): 4.11.1 [skip ci]
## [4.11.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.11.0...v4.11.1) (2025-10-18)

### Bug Fixes

* **card-sorting:** center AbacusReact SVGs in card tiles ([26edec1](26edec1bbf))
2025-10-18 22:41:08 +00:00
Thomas Hallock
26edec1bbf fix(card-sorting): center AbacusReact SVGs in card tiles
Improve centering of abacus SVGs within both available cards and position slots.

**Issue:**
AbacusReact SVGs were not properly centered within their card containers,
appearing off-center or misaligned.

**Fix:**
- **Available cards**: Added maxHeight: '100%' constraint and display: 'block'
  with margin: '0 auto' to SVG styling
- **Position slots**: Changed container to use flex: 1 and proper flex centering,
  constrained SVG to maxWidth: '70px' with centering styles

**Changes:**
- Available card SVG container: Added display flex with center alignment
- Available card SVG: maxHeight: '100%', display: 'block', margin: '0 auto'
- Position slot SVG container: width: '100%', flex: 1, flex centering
- Position slot SVG: maxWidth: '70px', maxHeight: '100%', display: 'block', margin: '0 auto'

Now AbacusReact SVGs render centered within their card tiles regardless of
the actual SVG dimensions.

src/arcade-games/card-sorting/components/PlayingPhase.tsx:314-330,457-475

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-18 17:40:03 -05:00
4 changed files with 556 additions and 347 deletions

View File

@@ -1,3 +1,74 @@
## [4.13.7](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.6...v4.13.7) (2025-10-18)
### Bug Fixes
* add dark color for abacus numerals ([73ff32c](https://github.com/antialias/soroban-abacus-flashcards/commit/73ff32c2432beb62710e57aa8b3b4793eca43fda)), closes [#1f2937](https://github.com/antialias/soroban-abacus-flashcards/issues/1f2937)
* use app-wide abacus config and remove instruction text ([0a50c73](https://github.com/antialias/soroban-abacus-flashcards/commit/0a50c733b089c7c341f0fdef47da78d1c61a3cb5))
## [4.13.6](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.5...v4.13.6) (2025-10-18)
### Bug Fixes
* simplify abacus pane with light background ([30f48ab](https://github.com/antialias/soroban-abacus-flashcards/commit/30f48ab8976976688e089b07ece7fdae6d7ada79))
## [4.13.5](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.4...v4.13.5) (2025-10-18)
### Bug Fixes
* correct AbacusReact API usage and add structural styling ([247377f](https://github.com/antialias/soroban-abacus-flashcards/commit/247377fca35ee3433e02ad594ecc1c4f391f0143)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24) [#a78](https://github.com/antialias/soroban-abacus-flashcards/issues/a78)
## [4.13.4](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.3...v4.13.4) (2025-10-18)
### Bug Fixes
* **card-sorting:** increase card tile sizes to contain abacuses ([d2a3b7a](https://github.com/antialias/soroban-abacus-flashcards/commit/d2a3b7ae2e3f6819b8d9ace32be22f04f748d1bc))
## [4.13.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.2...v4.13.3) (2025-10-18)
### Bug Fixes
* **card-sorting:** increase SVG size to fill card containers ([cf9d893](https://github.com/antialias/soroban-abacus-flashcards/commit/cf9d893f3fdbef6e91cd0ba283d602b9215569f1))
## [4.13.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.1...v4.13.2) (2025-10-18)
### Bug Fixes
* show initial value and improve numeral contrast ([1b57f6d](https://github.com/antialias/soroban-abacus-flashcards/commit/1b57f6ddecf3a118f2e4fadd1a91be1256f5a034)), closes [#fbbf24](https://github.com/antialias/soroban-abacus-flashcards/issues/fbbf24)
## [4.13.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.13.0...v4.13.1) (2025-10-18)
### Bug Fixes
* use defaultValue for interactive abacus control ([06aca98](https://github.com/antialias/soroban-abacus-flashcards/commit/06aca986ace4d76b70f2fd2f5e57f66758185b38))
## [4.13.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.12.0...v4.13.0) (2025-10-18)
### Features
* make home page abacus interactive with audio ([9a53d7e](https://github.com/antialias/soroban-abacus-flashcards/commit/9a53d7e5db18853aca4e2e0c7abc799217feaecf))
## [4.12.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.11.1...v4.12.0) (2025-10-18)
### Features
* redesign home page with component showcase ([29af265](https://github.com/antialias/soroban-abacus-flashcards/commit/29af265958f9fdab0253b92e153c01575840454d))
## [4.11.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.11.0...v4.11.1) (2025-10-18)
### Bug Fixes
* **card-sorting:** center AbacusReact SVGs in card tiles ([26edec1](https://github.com/antialias/soroban-abacus-flashcards/commit/26edec1bbf038264405ec9d161edcd18f67a6fc6))
## [4.11.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v4.10.6...v4.11.0) (2025-10-18)

View File

@@ -1,52 +1,121 @@
'use client'
import { useState } from 'react'
import Link from 'next/link'
import { PageWithNav } from '@/components/PageWithNav'
import { AbacusReact, useAbacusConfig } from '@soroban/abacus-react'
import { css } from '../../styled-system/css'
import { container, grid, hstack, stack } from '../../styled-system/patterns'
export default function HomePage() {
const [abacusValue, setAbacusValue] = useState(1234567)
const appConfig = useAbacusConfig()
return (
<PageWithNav navTitle="Soroban Mastery Platform" navEmoji="🧮">
<div className={css({ bg: 'gray.50', minHeight: '100vh' })}>
{/* Compact Hero */}
<div className={css({ bg: 'gray.900', minHeight: '100vh' })}>
{/* Hero with Large Abacus */}
<div
className={css({
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
background:
'linear-gradient(135deg, rgba(17, 24, 39, 1) 0%, rgba(88, 28, 135, 0.3) 50%, rgba(17, 24, 39, 1) 100%)',
color: 'white',
py: { base: '8', md: '12' },
py: { base: '12', md: '20' },
position: 'relative',
overflow: 'hidden',
})}
>
<div className={container({ maxW: '6xl', px: '4' })}>
<div className={css({ textAlign: 'center', maxW: '4xl', mx: 'auto' })}>
<div
className={css({
position: 'absolute',
inset: 0,
opacity: 0.1,
backgroundImage:
'radial-gradient(circle at 2px 2px, rgba(255, 255, 255, 0.15) 1px, transparent 0)',
backgroundSize: '40px 40px',
})}
/>
<div className={container({ maxW: '6xl', px: '4', position: 'relative' })}>
<div className={css({ textAlign: 'center', maxW: '5xl', mx: 'auto' })}>
<h1
className={css({
fontSize: { base: '3xl', md: '5xl' },
fontSize: { base: '3xl', md: '5xl', lg: '6xl' },
fontWeight: 'bold',
mb: '4',
mb: '6',
lineHeight: 'tight',
background: 'linear-gradient(135deg, #fbbf24 0%, #f59e0b 50%, #fbbf24 100%)',
backgroundClip: 'text',
color: 'transparent',
})}
>
Master Soroban Through{' '}
<span className={css({ color: 'yellow.300' })}>Play & Practice</span>
Master the Soroban
</h1>
<p className={css({ fontSize: { base: 'md', md: 'lg' }, opacity: 0.95, mb: '6' })}>
{/* Large Featured Abacus */}
<div
className={css({
display: 'flex',
justifyContent: 'center',
my: '10',
p: '8',
bg: 'white',
borderRadius: '2xl',
border: '2px solid',
borderColor: 'purple.500/30',
boxShadow: '0 25px 50px -12px rgba(139, 92, 246, 0.25)',
})}
>
<AbacusReact
value={abacusValue}
columns={7}
beadShape={appConfig.beadShape}
colorScheme={appConfig.colorScheme}
hideInactiveBeads={appConfig.hideInactiveBeads}
interactive={true}
animated={true}
soundEnabled={true}
soundVolume={0.4}
scaleFactor={2.2}
showNumbers={true}
customStyles={{
numerals: {
fill: '#1f2937',
fontWeight: 'bold',
},
}}
onValueChange={(newValue: number) => setAbacusValue(newValue)}
/>
</div>
<p
className={css({
fontSize: { base: 'lg', md: 'xl' },
color: 'gray.300',
mb: '8',
maxW: '3xl',
mx: 'auto',
})}
>
Interactive tutorials, multiplayer games, and beautiful flashcardsyour complete
soroban learning ecosystem
</p>
<div className={hstack({ gap: '3', justify: 'center', flexWrap: 'wrap' })}>
<div className={hstack({ gap: '4', justify: 'center', flexWrap: 'wrap' })}>
<Link
href="/arcade"
href="/games"
className={css({
px: '6',
py: '3',
bg: 'yellow.400',
px: '8',
py: '4',
bg: 'linear-gradient(135deg, #fbbf24, #f59e0b)',
color: 'gray.900',
fontWeight: 'bold',
rounded: 'lg',
shadow: 'lg',
_hover: { bg: 'yellow.300', transform: 'translateY(-2px)' },
transition: 'all',
fontSize: 'lg',
rounded: 'xl',
shadow: '0 10px 40px rgba(251, 191, 36, 0.3)',
_hover: {
transform: 'translateY(-2px)',
shadow: '0 20px 50px rgba(251, 191, 36, 0.4)',
},
transition: 'all 0.3s ease',
})}
>
🎮 Play Games
@@ -54,15 +123,20 @@ export default function HomePage() {
<Link
href="/guide"
className={css({
px: '6',
py: '3',
bg: 'white',
color: 'purple.700',
px: '8',
py: '4',
bg: 'rgba(139, 92, 246, 0.2)',
color: 'white',
fontWeight: 'bold',
rounded: 'lg',
shadow: 'lg',
_hover: { bg: 'gray.100', transform: 'translateY(-2px)' },
transition: 'all',
fontSize: 'lg',
rounded: 'xl',
border: '2px solid',
borderColor: 'purple.500',
_hover: {
bg: 'rgba(139, 92, 246, 0.3)',
transform: 'translateY(-2px)',
},
transition: 'all 0.3s ease',
})}
>
📚 Learn
@@ -70,15 +144,20 @@ export default function HomePage() {
<Link
href="/create"
className={css({
px: '6',
py: '3',
bg: 'purple.600',
px: '8',
py: '4',
bg: 'rgba(139, 92, 246, 0.2)',
color: 'white',
fontWeight: 'bold',
rounded: 'lg',
shadow: 'lg',
_hover: { bg: 'purple.700', transform: 'translateY(-2px)' },
transition: 'all',
fontSize: 'lg',
rounded: 'xl',
border: '2px solid',
borderColor: 'purple.500',
_hover: {
bg: 'rgba(139, 92, 246, 0.3)',
transform: 'translateY(-2px)',
},
transition: 'all 0.3s ease',
})}
>
🎨 Create
@@ -88,343 +167,383 @@ export default function HomePage() {
</div>
</div>
{/* Main Content Grid */}
<div className={container({ maxW: '7xl', px: '4', py: '8' })}>
<div className={stack({ gap: '8' })}>
{/* Arcade Games Section */}
<section>
<div className={hstack({ justify: 'space-between', mb: '4' })}>
<h2 className={css({ fontSize: '2xl', fontWeight: 'bold', color: 'gray.900' })}>
🕹 Multiplayer Arcade
</h2>
<Link
href="/arcade"
className={css({
fontSize: 'sm',
color: 'purple.600',
fontWeight: 'semibold',
_hover: { color: 'purple.700' },
})}
>
View All
</Link>
</div>
<div className={grid({ columns: { base: 1, sm: 2, lg: 4 }, gap: '4' })}>
<GameCard
icon="🧠"
title="Memory Lightning"
description="Memorize soroban numbers"
players="1-8 players"
tags={['Co-op', 'Competitive']}
/>
<GameCard
icon="⚔️"
title="Matching Pairs"
description="Turn-based card battles"
players="1-4 players"
tags={['Pattern Recognition']}
/>
<GameCard
icon="🏁"
title="Speed Race"
description="Race AI with complements"
players="1-4 players + AI"
tags={['Practice', 'Sprint', 'Survival']}
/>
<GameCard
icon="🔢"
title="Card Sorting"
description="Arrange cards visually"
players="Solo challenge"
tags={['Visual Literacy']}
/>
</div>
</section>
{/* Two Column Layout */}
<div className={grid({ columns: { base: 1, lg: 2 }, gap: '6' })}>
{/* Interactive Learning */}
<section
{/* Color Scheme Showcase */}
<div className={container({ maxW: '7xl', px: '4', py: '12' })}>
<section className={stack({ gap: '8' })}>
<div className={css({ textAlign: 'center' })}>
<h2
className={css({
bg: 'white',
rounded: 'xl',
p: '6',
shadow: 'sm',
border: '1px solid',
borderColor: 'gray.200',
fontSize: { base: '2xl', md: '3xl' },
fontWeight: 'bold',
color: 'white',
mb: '3',
})}
>
<h2
className={css({
fontSize: 'xl',
fontWeight: 'bold',
color: 'gray.900',
mb: '4',
})}
>
📚 Interactive Learning
</h2>
<div className={stack({ gap: '3' })}>
<FeatureItem
icon="🔍"
title="Reading Numbers"
description="Visual tutorials on interpreting bead positions"
/>
<FeatureItem
icon="🧮"
title="Arithmetic Operations"
description="Step-by-step interactive practice: +, , ×, ÷"
/>
<FeatureItem
icon="🎯"
title="Guided Tutorials"
description="Hands-on exercises with instant feedback"
/>
</div>
<Link
href="/guide"
className={css({
display: 'block',
mt: '4',
py: '2',
textAlign: 'center',
bg: 'purple.50',
color: 'purple.700',
fontWeight: 'semibold',
rounded: 'lg',
_hover: { bg: 'purple.100' },
})}
>
Start Learning
</Link>
</section>
{/* Flashcard Creator */}
<section
className={css({
bg: 'white',
rounded: 'xl',
p: '6',
shadow: 'sm',
border: '1px solid',
borderColor: 'gray.200',
})}
>
<h2
className={css({
fontSize: 'xl',
fontWeight: 'bold',
color: 'gray.900',
mb: '4',
})}
>
🎨 Flashcard Creator
</h2>
<div className={stack({ gap: '3' })}>
<FeatureItem
icon="📄"
title="Multiple Formats"
description="PDF, PNG, SVG, interactive HTML"
/>
<FeatureItem
icon="🎨"
title="Custom Styling"
description="Bead shapes, color schemes, fonts, layouts"
/>
<FeatureItem
icon="📐"
title="Paper Options"
description="A3, A4, A5, US Letter • Portrait/Landscape"
/>
</div>
<Link
href="/create"
className={css({
display: 'block',
mt: '4',
py: '2',
textAlign: 'center',
bg: 'blue.50',
color: 'blue.700',
fontWeight: 'semibold',
rounded: 'lg',
_hover: { bg: 'blue.100' },
})}
>
Create Flashcards
</Link>
</section>
Beautiful Color Schemes
</h2>
<p className={css({ color: 'gray.400', fontSize: 'lg' })}>
Choose from multiple visual styles to enhance learning
</p>
</div>
{/* Multiplayer Features */}
<section>
<h2
className={css({ fontSize: '2xl', fontWeight: 'bold', color: 'gray.900', mb: '4' })}
>
🌐 Multiplayer Features
</h2>
<div className={grid({ columns: { base: 1, sm: 2, md: 4 }, gap: '4' })}>
<FeatureCard
icon="🎭"
title="Player Characters"
description="Custom names, emojis, and colors for each player"
/>
<FeatureCard
icon="🏠"
title="Private Rooms"
description="Create rooms with codes, passwords, or approval-only access"
/>
<FeatureCard
icon="⚡"
title="Real-time Play"
description="Socket.io powered instant multiplayer sync"
/>
<FeatureCard
icon="📊"
title="Stats & Progress"
description="Track wins, accuracy, and performance across games"
/>
</div>
</section>
<div className={grid({ columns: { base: 1, sm: 2, lg: 4 }, gap: '6' })}>
<ColorSchemeCard
title="Monochrome"
description="Classic, minimalist design"
colorScheme="monochrome"
value={42}
beadShape="diamond"
/>
<ColorSchemeCard
title="Place Value"
description="Each column has its own color"
colorScheme="place-value"
value={789}
beadShape="circle"
/>
<ColorSchemeCard
title="Heaven & Earth"
description="Distinct heaven and earth beads"
colorScheme="heaven-earth"
value={156}
beadShape="square"
/>
<ColorSchemeCard
title="Alternating"
description="Alternating column colors"
colorScheme="alternating"
value={234}
beadShape="diamond"
/>
</div>
</section>
{/* Quick Stats */}
<section
{/* Arcade Games Section */}
<section className={stack({ gap: '6', mt: '16' })}>
<div className={hstack({ justify: 'space-between', alignItems: 'center' })}>
<div>
<h2
className={css({
fontSize: { base: '2xl', md: '3xl' },
fontWeight: 'bold',
color: 'white',
mb: '2',
})}
>
🕹 Multiplayer Arcade
</h2>
<p className={css({ color: 'gray.400', fontSize: 'md' })}>
Compete with friends in real-time soroban games
</p>
</div>
<Link
href="/games"
className={css({
fontSize: 'md',
color: 'yellow.400',
fontWeight: 'semibold',
_hover: { color: 'yellow.300' },
display: { base: 'none', md: 'block' },
})}
>
View All
</Link>
</div>
<div className={grid({ columns: { base: 1, sm: 2, lg: 4 }, gap: '5' })}>
<GameCard
icon="🧠"
title="Memory Lightning"
description="Memorize soroban numbers"
players="1-8 players"
tags={['Co-op', 'Competitive']}
gradient="linear-gradient(135deg, #667eea 0%, #764ba2 100%)"
href="/games"
/>
<GameCard
icon="⚔️"
title="Matching Pairs"
description="Turn-based card battles"
players="1-4 players"
tags={['Pattern Recognition']}
gradient="linear-gradient(135deg, #f093fb 0%, #f5576c 100%)"
href="/games"
/>
<GameCard
icon="🏁"
title="Speed Race"
description="Race AI with complements"
players="1-4 players + AI"
tags={['Practice', 'Sprint', 'Survival']}
gradient="linear-gradient(135deg, #4facfe 0%, #00f2fe 100%)"
href="/games"
/>
<GameCard
icon="🔢"
title="Card Sorting"
description="Arrange cards visually"
players="Solo challenge"
tags={['Visual Literacy']}
gradient="linear-gradient(135deg, #43e97b 0%, #38f9d7 100%)"
href="/games"
/>
</div>
</section>
{/* Interactive Learning & Flashcard Creator */}
<div className={grid({ columns: { base: 1, lg: 2 }, gap: '8', mt: '16' })}>
<FeaturePanel
icon="📚"
title="Interactive Learning"
description="Master soroban through hands-on guided tutorials"
features={[
'Visual tutorials on reading bead positions',
'Step-by-step arithmetic operations',
'Interactive exercises with instant feedback',
]}
ctaText="Start Learning →"
ctaHref="/guide"
accentColor="purple"
/>
<FeaturePanel
icon="🎨"
title="Flashcard Creator"
description="Design beautiful soroban flashcards for any purpose"
features={[
'Multiple export formats: PDF, PNG, SVG, HTML',
'Custom bead shapes, colors, and layouts',
'All paper sizes: A3, A4, A5, US Letter',
]}
ctaText="Create Flashcards →"
ctaHref="/create"
accentColor="blue"
/>
</div>
{/* Stats Banner */}
<section
className={css({
bg: 'linear-gradient(135deg, rgba(139, 92, 246, 0.2) 0%, rgba(59, 130, 246, 0.2) 100%)',
rounded: '2xl',
p: '10',
mt: '16',
border: '2px solid',
borderColor: 'purple.500/20',
})}
>
<h2
className={css({
bg: 'gradient-to-r',
gradientFrom: 'purple.600',
gradientTo: 'indigo.600',
rounded: 'xl',
p: '6',
fontSize: { base: 'xl', md: '2xl' },
fontWeight: 'bold',
mb: '8',
textAlign: 'center',
color: 'white',
})}
>
<h2
className={css({
fontSize: 'xl',
fontWeight: 'bold',
mb: '4',
textAlign: 'center',
})}
>
Complete Soroban Learning Platform
</h2>
<div className={grid({ columns: { base: 2, md: 4 }, gap: '6', textAlign: 'center' })}>
<StatItem number="4" label="Arcade Games" />
<StatItem number="8" label="Max Players" />
<StatItem number="3" label="Learning Modes" />
<StatItem number="4+" label="Export Formats" />
</div>
</section>
</div>
Complete Soroban Learning Platform
</h2>
<div className={grid({ columns: { base: 2, md: 4 }, gap: '8', textAlign: 'center' })}>
<StatItem number="4" label="Arcade Games" />
<StatItem number="8" label="Max Players" />
<StatItem number="3" label="Learning Modes" />
<StatItem number="4+" label="Export Formats" />
</div>
</section>
</div>
</div>
</PageWithNav>
)
}
function ColorSchemeCard({
title,
description,
colorScheme,
value,
beadShape,
}: {
title: string
description: string
colorScheme: 'monochrome' | 'place-value' | 'heaven-earth' | 'alternating'
value: number
beadShape: 'diamond' | 'circle' | 'square'
}) {
return (
<div
className={css({
bg: 'rgba(0, 0, 0, 0.4)',
rounded: 'xl',
p: '6',
border: '2px solid',
borderColor: 'gray.700',
transition: 'all 0.3s ease',
_hover: {
borderColor: 'purple.500',
transform: 'translateY(-4px)',
boxShadow: '0 20px 40px rgba(139, 92, 246, 0.2)',
},
})}
>
<h3
className={css({
fontSize: 'lg',
fontWeight: 'bold',
color: 'white',
mb: '2',
})}
>
{title}
</h3>
<p className={css({ fontSize: 'sm', color: 'gray.400', mb: '4' })}>{description}</p>
<div
className={css({
display: 'flex',
justifyContent: 'center',
p: '4',
bg: 'rgba(255, 255, 255, 0.05)',
rounded: 'lg',
})}
>
<AbacusReact
value={value}
columns={3}
beadShape={beadShape}
colorScheme={colorScheme}
hideInactiveBeads={false}
/>
</div>
</div>
)
}
function GameCard({
icon,
title,
description,
players,
tags,
gradient,
href,
}: {
icon: string
title: string
description: string
players: string
tags: string[]
gradient: string
href: string
}) {
return (
<Link href={href}>
<div
className={css({
background: gradient,
rounded: 'xl',
p: '6',
shadow: 'lg',
transition: 'all 0.3s ease',
cursor: 'pointer',
_hover: {
transform: 'translateY(-6px) scale(1.02)',
shadow: '0 25px 50px rgba(0, 0, 0, 0.3)',
},
})}
>
<div className={css({ fontSize: '3xl', mb: '3' })}>{icon}</div>
<h3 className={css({ fontSize: 'lg', fontWeight: 'bold', color: 'white', mb: '2' })}>
{title}
</h3>
<p className={css({ fontSize: 'sm', color: 'rgba(255, 255, 255, 0.9)', mb: '2' })}>
{description}
</p>
<p className={css({ fontSize: 'xs', color: 'rgba(255, 255, 255, 0.7)', mb: '3' })}>
{players}
</p>
<div className={hstack({ gap: '2', flexWrap: 'wrap' })}>
{tags.map((tag) => (
<span
key={tag}
className={css({
fontSize: 'xs',
px: '2',
py: '1',
bg: 'rgba(255, 255, 255, 0.2)',
color: 'white',
rounded: 'full',
fontWeight: 'semibold',
})}
>
{tag}
</span>
))}
</div>
</div>
</Link>
)
}
function FeaturePanel({
icon,
title,
description,
features,
ctaText,
ctaHref,
accentColor,
}: {
icon: string
title: string
description: string
features: string[]
ctaText: string
ctaHref: string
accentColor: 'purple' | 'blue'
}) {
const borderColor = accentColor === 'purple' ? 'purple.500/30' : 'blue.500/30'
const bgColor = accentColor === 'purple' ? 'purple.500/10' : 'blue.500/10'
const hoverBg = accentColor === 'purple' ? 'purple.500/20' : 'blue.500/20'
return (
<div
className={css({
bg: 'white',
rounded: 'lg',
p: '4',
shadow: 'sm',
border: '1px solid',
borderColor: 'gray.200',
transition: 'all',
_hover: { shadow: 'md', transform: 'translateY(-2px)' },
bg: 'rgba(0, 0, 0, 0.4)',
rounded: 'xl',
p: '8',
border: '2px solid',
borderColor,
})}
>
<div className={css({ fontSize: '2xl', mb: '2' })}>{icon}</div>
<h3 className={css({ fontSize: 'md', fontWeight: 'bold', color: 'gray.900', mb: '1' })}>
{title}
</h3>
<p className={css({ fontSize: 'sm', color: 'gray.600', mb: '2' })}>{description}</p>
<p className={css({ fontSize: 'xs', color: 'gray.500', mb: '2' })}>{players}</p>
<div className={hstack({ gap: '1', flexWrap: 'wrap' })}>
{tags.map((tag) => (
<span
key={tag}
className={css({
fontSize: 'xs',
px: '2',
py: '0.5',
bg: 'purple.100',
color: 'purple.700',
rounded: 'full',
})}
>
{tag}
</span>
<div className={hstack({ gap: '3', mb: '4' })}>
<span className={css({ fontSize: '3xl' })}>{icon}</span>
<h2 className={css({ fontSize: '2xl', fontWeight: 'bold', color: 'white' })}>{title}</h2>
</div>
<p className={css({ fontSize: 'md', color: 'gray.300', mb: '6' })}>{description}</p>
<div className={stack({ gap: '3', mb: '6' })}>
{features.map((feature, i) => (
<div key={i} className={hstack({ gap: '3' })}>
<span className={css({ color: 'yellow.400', fontSize: 'lg' })}></span>
<span className={css({ color: 'gray.300', fontSize: 'sm' })}>{feature}</span>
</div>
))}
</div>
</div>
)
}
function FeatureItem({
icon,
title,
description,
}: {
icon: string
title: string
description: string
}) {
return (
<div className={hstack({ gap: '3', alignItems: 'flex-start' })}>
<div className={css({ fontSize: 'xl', flexShrink: 0 })}>{icon}</div>
<div>
<h4 className={css({ fontSize: 'sm', fontWeight: 'semibold', color: 'gray.900' })}>
{title}
</h4>
<p className={css({ fontSize: 'xs', color: 'gray.600' })}>{description}</p>
</div>
</div>
)
}
function FeatureCard({
icon,
title,
description,
}: {
icon: string
title: string
description: string
}) {
return (
<div
className={css({
bg: 'white',
rounded: 'lg',
p: '4',
shadow: 'sm',
border: '1px solid',
borderColor: 'gray.200',
textAlign: 'center',
})}
>
<div className={css({ fontSize: '2xl', mb: '2' })}>{icon}</div>
<h3 className={css({ fontSize: 'sm', fontWeight: 'bold', color: 'gray.900', mb: '1' })}>
{title}
</h3>
<p className={css({ fontSize: 'xs', color: 'gray.600', lineHeight: 'relaxed' })}>
{description}
</p>
<Link
href={ctaHref}
className={css({
display: 'block',
textAlign: 'center',
py: '3',
px: '6',
bg: bgColor,
color: 'white',
fontWeight: 'bold',
rounded: 'lg',
border: '2px solid',
borderColor,
_hover: { bg: hoverBg },
transition: 'all 0.2s ease',
})}
>
{ctaText}
</Link>
</div>
)
}
@@ -432,8 +551,19 @@ function FeatureCard({
function StatItem({ number, label }: { number: string; label: string }) {
return (
<div>
<div className={css({ fontSize: '3xl', fontWeight: 'bold', mb: '1' })}>{number}</div>
<div className={css({ fontSize: 'sm', opacity: 0.9 })}>{label}</div>
<div
className={css({
fontSize: { base: '3xl', md: '4xl' },
fontWeight: 'bold',
mb: '2',
background: 'linear-gradient(135deg, #fbbf24, #f59e0b)',
backgroundClip: 'text',
color: 'transparent',
})}
>
{number}
</div>
<div className={css({ fontSize: 'sm', color: 'gray.300' })}>{label}</div>
</div>
)
}

View File

@@ -280,8 +280,8 @@ export function PlayingPhase() {
key={card.id}
onClick={() => handleCardClick(card.id)}
className={css({
width: '90px',
height: '90px',
width: '140px',
height: '140px',
padding: '8px',
border: '2px solid',
borderColor: selectedCardId === card.id ? '#1976d2' : 'transparent',
@@ -319,9 +319,11 @@ export function PlayingPhase() {
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
'& svg': {
maxWidth: '100%',
height: 'auto',
width: '100%',
height: '100%',
display: 'block',
},
})}
/>
@@ -414,8 +416,8 @@ export function PlayingPhase() {
key={`slot-${index}`}
onClick={() => handleSlotClick(index)}
className={css({
width: '90px',
height: '110px',
width: '140px',
height: '160px',
padding: '0.5rem',
borderRadius: '8px',
border: '2px solid',
@@ -456,10 +458,16 @@ export function PlayingPhase() {
__html: card.svgContent,
}}
className={css({
width: '70px',
flex: 1,
width: '100%',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
'& svg': {
width: '100%',
height: 'auto',
height: '100%',
display: 'block',
},
})}
/>

View File

@@ -1,6 +1,6 @@
{
"name": "soroban-monorepo",
"version": "4.11.0",
"version": "4.13.7",
"private": true,
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
"workspaces": [