Compare commits

...

10 Commits

Author SHA1 Message Date
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 543 additions and 344 deletions

View File

@@ -1,3 +1,38 @@
## [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,146 @@
'use client'
import { useState } from 'react'
import Link from 'next/link'
import { PageWithNav } from '@/components/PageWithNav'
import { AbacusReact } 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)
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',
flexDirection: 'column',
alignItems: 'center',
gap: '4',
my: '10',
p: '8',
bg: 'rgba(0, 0, 0, 0.4)',
borderRadius: '2xl',
border: '2px solid',
borderColor: 'purple.500/30',
boxShadow: '0 25px 50px -12px rgba(139, 92, 246, 0.25)',
})}
>
<div
className={css({
fontSize: 'lg',
fontWeight: 'semibold',
color: 'gray.300',
mb: '2',
})}
>
Click the beads to interact!
</div>
<AbacusReact
value={abacusValue}
columns={7}
beadShape="diamond"
colorScheme="place-value"
hideInactiveBeads={false}
interactive={true}
animated={true}
soundEnabled={true}
soundVolume={0.4}
scaleFactor={2.2}
showNumbers={true}
customStyles={{
numerals: {
fill: '#fbbf24',
fontWeight: 'bold',
fontSize: '18px',
},
}}
callbacks={{
onValueChange: (newValue: number) => setAbacusValue(newValue),
}}
/>
<div
className={css({
fontSize: '4xl',
fontWeight: 'bold',
color: 'yellow.400',
fontFamily: 'mono',
letterSpacing: 'wide',
})}
>
{abacusValue.toLocaleString()}
</div>
</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 +148,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 +169,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 +192,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 +576,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

@@ -314,14 +314,16 @@ export function PlayingPhase() {
<div
dangerouslySetInnerHTML={{ __html: card.svgContent }}
className={css({
width: '100%',
height: '100%',
width: '74px',
height: '74px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
'& svg': {
maxWidth: '100%',
height: 'auto',
width: '100%',
height: '100%',
display: 'block',
},
})}
/>
@@ -457,9 +459,16 @@ export function PlayingPhase() {
}}
className={css({
width: '70px',
height: '70px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center',
overflow: 'hidden',
margin: '0 auto',
'& 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.2",
"private": true,
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
"workspaces": [