Compare commits
9 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a33ac58b1f | ||
|
|
64dc94e91e | ||
|
|
193df4327f | ||
|
|
26077de78b | ||
|
|
ccca3d3415 | ||
|
|
8de4015250 | ||
|
|
4c338726c1 | ||
|
|
7e4d32460a | ||
|
|
f0bb411573 |
27
.github/workflows/deploy-storybook.yml
vendored
27
.github/workflows/deploy-storybook.yml
vendored
@@ -31,7 +31,7 @@ jobs:
|
||||
- name: Setup Node.js
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: '18'
|
||||
node-version: '20'
|
||||
|
||||
- name: Setup pnpm
|
||||
uses: pnpm/action-setup@v2
|
||||
@@ -44,7 +44,7 @@ jobs:
|
||||
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
|
||||
|
||||
- name: Setup pnpm cache
|
||||
uses: actions/cache@v3
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: ${{ env.STORE_PATH }}
|
||||
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('**/pnpm-lock.yaml') }}
|
||||
@@ -56,14 +56,27 @@ jobs:
|
||||
|
||||
- name: Generate Panda CSS
|
||||
working-directory: apps/web
|
||||
run: pnpm panda codegen
|
||||
run: |
|
||||
pnpm panda codegen
|
||||
npx @pandacss/dev cssgen || echo "CSS generation had warnings but continued"
|
||||
ls -la styled-system/
|
||||
echo "Generated CSS files:"
|
||||
ls -la styled-system/*.css || echo "No CSS files found"
|
||||
|
||||
- name: Build abacus-react package
|
||||
run: pnpm --filter @soroban/abacus-react build
|
||||
|
||||
- name: Build web Storybook
|
||||
working-directory: apps/web
|
||||
run: pnpm build-storybook --output-dir ../../storybook-web
|
||||
run: |
|
||||
echo "Current directory contents:"
|
||||
ls -la
|
||||
echo "Styled-system directory contents:"
|
||||
ls -la styled-system/ || echo "No styled-system directory found"
|
||||
echo "Checking for styles.css:"
|
||||
ls -la styled-system/styles.css || echo "styles.css not found"
|
||||
echo "Starting Storybook build..."
|
||||
pnpm build-storybook --output-dir ../../storybook-web
|
||||
|
||||
- name: Build abacus-react Storybook
|
||||
working-directory: packages/abacus-react
|
||||
@@ -173,15 +186,15 @@ jobs:
|
||||
|
||||
- name: Setup Pages
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/configure-pages@v3
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Upload artifact
|
||||
if: github.ref == 'refs/heads/main'
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: ./pages
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
if: github.ref == 'refs/heads/main'
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v2
|
||||
uses: actions/deploy-pages@v3
|
||||
28
CHANGELOG.md
28
CHANGELOG.md
@@ -1,3 +1,31 @@
|
||||
# [1.2.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v1.1.3...v1.2.0) (2025-09-28)
|
||||
|
||||
|
||||
### Features
|
||||
|
||||
* trigger storybook deployment after enabling GitHub Pages ([64dc94e](https://github.com/antialias/soroban-abacus-flashcards/commit/64dc94e91e089fadbdb75fbbf3a6164a2d224ef4))
|
||||
|
||||
## [1.1.3](https://github.com/antialias/soroban-abacus-flashcards/compare/v1.1.2...v1.1.3) (2025-09-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* add cssgen step to generate styles.css for Storybook ([26077de](https://github.com/antialias/soroban-abacus-flashcards/commit/26077de78bccf8549e1e9a0ac9c08742c61c8d28))
|
||||
|
||||
## [1.1.2](https://github.com/antialias/soroban-abacus-flashcards/compare/v1.1.1...v1.1.2) (2025-09-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* upgrade Node.js to version 20 for Storybook compatibility ([4c33872](https://github.com/antialias/soroban-abacus-flashcards/commit/4c338726c13af623b1536f75fe6a18e0ab529377))
|
||||
|
||||
## [1.1.1](https://github.com/antialias/soroban-abacus-flashcards/compare/v1.1.0...v1.1.1) (2025-09-28)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* update GitHub Actions to use latest action versions for Storybook deployment ([f0bb411](https://github.com/antialias/soroban-abacus-flashcards/commit/f0bb411573c8496d11d560fa7efe9324015412b2))
|
||||
|
||||
# [1.1.0](https://github.com/antialias/soroban-abacus-flashcards/compare/v1.0.0...v1.1.0) (2025-09-28)
|
||||
|
||||
|
||||
|
||||
@@ -690,7 +690,7 @@ export function EnhancedChampionArena({ onGameModeChange, onConfigurePlayer, cla
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Prominent Game Selector - takes remaining space */}
|
||||
{/* Prominent Game Selector - constrained to available space */}
|
||||
<div className={css({
|
||||
flex: 1,
|
||||
mt: { base: '1', md: '2' },
|
||||
@@ -698,7 +698,9 @@ export function EnhancedChampionArena({ onGameModeChange, onConfigurePlayer, cla
|
||||
borderTop: '2px solid',
|
||||
borderColor: 'gray.200',
|
||||
minHeight: 0,
|
||||
overflow: 'auto'
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column'
|
||||
})}>
|
||||
<GameSelector
|
||||
variant="detailed"
|
||||
|
||||
@@ -42,7 +42,7 @@ export function GameCard({
|
||||
className={css({
|
||||
background: config.gradient || 'white',
|
||||
rounded: variant === 'compact' ? 'xl' : '2xl',
|
||||
p: variant === 'compact' ? '4' : '8',
|
||||
p: variant === 'compact' ? '3' : { base: '3', md: '4', lg: '6' },
|
||||
border: '2px solid',
|
||||
borderColor: available ? config.borderColor || 'blue.200' : 'gray.200',
|
||||
boxShadow: variant === 'compact'
|
||||
@@ -52,7 +52,10 @@ export function GameCard({
|
||||
cursor: available ? 'pointer' : 'not-allowed',
|
||||
transition: 'all 0.4s cubic-bezier(0.175, 0.885, 0.32, 1.275)',
|
||||
position: 'relative',
|
||||
overflow: 'visible',
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
height: '100%',
|
||||
_hover: available ? {
|
||||
transform: variant === 'compact' ? 'translateY(-2px) scale(1.02)' : 'translateY(-8px) scale(1.02)',
|
||||
boxShadow: variant === 'compact'
|
||||
@@ -65,100 +68,125 @@ export function GameCard({
|
||||
{/* Game icon with enhanced styling */}
|
||||
<div className={css({
|
||||
textAlign: 'center',
|
||||
mb: variant === 'compact' ? '2' : '4'
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'space-between',
|
||||
minHeight: 0
|
||||
})}>
|
||||
{/* Top section - icon and title */}
|
||||
<div className={css({
|
||||
fontSize: variant === 'compact' ? '2xl' : '4xl',
|
||||
mb: variant === 'compact' ? '2' : '3',
|
||||
display: 'inline-block',
|
||||
transform: 'perspective(1000px)',
|
||||
transition: 'all 0.3s ease'
|
||||
flexShrink: 0
|
||||
})}>
|
||||
{config.icon}
|
||||
<div className={css({
|
||||
fontSize: variant === 'compact' ? 'xl' : { base: 'xl', md: '2xl', lg: '3xl' },
|
||||
mb: variant === 'compact' ? '1' : { base: '1', md: '2' },
|
||||
display: 'inline-block',
|
||||
transform: 'perspective(1000px)',
|
||||
transition: 'all 0.3s ease'
|
||||
})}>
|
||||
{config.icon}
|
||||
</div>
|
||||
|
||||
<h4 className={css({
|
||||
fontSize: variant === 'compact' ? 'md' : { base: 'lg', md: 'xl', lg: '2xl' },
|
||||
fontWeight: 'bold',
|
||||
color: 'gray.900',
|
||||
mb: variant === 'compact' ? '0.5' : { base: '1', md: '2' }
|
||||
})}>
|
||||
{variant === 'detailed' ? config.fullName || config.name : config.name}
|
||||
</h4>
|
||||
</div>
|
||||
|
||||
<h4 className={css({
|
||||
fontSize: variant === 'compact' ? 'lg' : '2xl',
|
||||
fontWeight: 'bold',
|
||||
color: 'gray.900',
|
||||
mb: variant === 'compact' ? '1' : '3'
|
||||
})}>
|
||||
{variant === 'detailed' ? config.fullName || config.name : config.name}
|
||||
</h4>
|
||||
|
||||
{/* Middle section - description (flexible) */}
|
||||
{variant === 'detailed' && (
|
||||
<p className={css({
|
||||
fontSize: 'base',
|
||||
color: 'gray.600',
|
||||
mb: '4',
|
||||
lineHeight: 'relaxed'
|
||||
})}>
|
||||
{config.longDescription || config.description}
|
||||
</p>
|
||||
)}
|
||||
|
||||
{/* Feature chips */}
|
||||
{variant === 'detailed' && config.chips && (
|
||||
<div className={css({
|
||||
flex: 1,
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: '2',
|
||||
flexDirection: 'column',
|
||||
justifyContent: 'center',
|
||||
mb: '4'
|
||||
minHeight: 0
|
||||
})}>
|
||||
{config.chips.map((chip, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className={css({
|
||||
px: '3',
|
||||
py: '1',
|
||||
background: config.color === 'green'
|
||||
? 'linear-gradient(135deg, #d1fae5, #a7f3d0)'
|
||||
: config.color === 'purple'
|
||||
? 'linear-gradient(135deg, #e0e7ff, #c7d2fe)'
|
||||
: 'linear-gradient(135deg, #dbeafe, #bfdbfe)',
|
||||
color: config.color === 'green'
|
||||
? 'green.800'
|
||||
: config.color === 'purple'
|
||||
? 'indigo.800'
|
||||
: 'blue.800',
|
||||
rounded: 'full',
|
||||
fontSize: 'xs',
|
||||
fontWeight: 'semibold',
|
||||
border: '1px solid',
|
||||
borderColor: config.color === 'green'
|
||||
? 'green.200'
|
||||
: config.color === 'purple'
|
||||
? 'indigo.200'
|
||||
: 'blue.200',
|
||||
opacity: available ? 1 : 0.8
|
||||
})}
|
||||
>
|
||||
{chip}
|
||||
</span>
|
||||
))}
|
||||
<p className={css({
|
||||
fontSize: { base: 'xs', md: 'sm', lg: 'base' },
|
||||
color: 'gray.600',
|
||||
lineHeight: 'relaxed',
|
||||
display: { base: 'none', sm: 'block' },
|
||||
overflow: 'hidden'
|
||||
})}>
|
||||
{config.description}
|
||||
</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Player availability indicator */}
|
||||
{/* Bottom section - chips and status */}
|
||||
<div className={css({
|
||||
fontSize: variant === 'compact' ? 'xs' : 'sm',
|
||||
color: available ? 'green.600' : 'red.600',
|
||||
fontWeight: 'semibold',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '1',
|
||||
px: '2',
|
||||
py: '1',
|
||||
background: available ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)',
|
||||
rounded: 'full',
|
||||
border: '1px solid',
|
||||
borderColor: available ? 'green.200' : 'red.200'
|
||||
flexShrink: 0,
|
||||
mt: 'auto'
|
||||
})}>
|
||||
{activePlayerCount <= config.maxPlayers
|
||||
? `✓ ${activePlayerCount}/${config.maxPlayers} ${activePlayerCount === 1 ? 'player' : 'players'}`
|
||||
: `✗ Too many players (max ${config.maxPlayers})`
|
||||
}
|
||||
{/* Feature chips */}
|
||||
{variant === 'detailed' && config.chips && (
|
||||
<div className={css({
|
||||
display: 'flex',
|
||||
flexWrap: 'wrap',
|
||||
gap: { base: '1', md: '2' },
|
||||
justifyContent: 'center',
|
||||
mb: { base: '2', md: '3' }
|
||||
})}>
|
||||
{config.chips.slice(0, 2).map((chip, index) => (
|
||||
<span
|
||||
key={index}
|
||||
className={css({
|
||||
px: { base: '2', md: '3' },
|
||||
py: { base: '0.5', md: '1' },
|
||||
background: config.color === 'green'
|
||||
? 'linear-gradient(135deg, #d1fae5, #a7f3d0)'
|
||||
: config.color === 'purple'
|
||||
? 'linear-gradient(135deg, #e0e7ff, #c7d2fe)'
|
||||
: 'linear-gradient(135deg, #dbeafe, #bfdbfe)',
|
||||
color: config.color === 'green'
|
||||
? 'green.800'
|
||||
: config.color === 'purple'
|
||||
? 'indigo.800'
|
||||
: 'blue.800',
|
||||
rounded: 'full',
|
||||
fontSize: { base: '2xs', md: 'xs' },
|
||||
fontWeight: 'semibold',
|
||||
border: '1px solid',
|
||||
borderColor: config.color === 'green'
|
||||
? 'green.200'
|
||||
: config.color === 'purple'
|
||||
? 'indigo.200'
|
||||
: 'blue.200',
|
||||
opacity: available ? 1 : 0.8
|
||||
})}
|
||||
>
|
||||
{chip}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
{/* Player availability indicator */}
|
||||
<div className={css({
|
||||
fontSize: variant === 'compact' ? '2xs' : { base: '2xs', md: 'xs', lg: 'sm' },
|
||||
color: available ? 'green.600' : 'red.600',
|
||||
fontWeight: 'semibold',
|
||||
display: 'inline-flex',
|
||||
alignItems: 'center',
|
||||
gap: '1',
|
||||
px: { base: '1.5', md: '2' },
|
||||
py: { base: '0.5', md: '1' },
|
||||
background: available ? 'rgba(16, 185, 129, 0.1)' : 'rgba(239, 68, 68, 0.1)',
|
||||
rounded: 'full',
|
||||
border: '1px solid',
|
||||
borderColor: available ? 'green.200' : 'red.200'
|
||||
})}>
|
||||
{activePlayerCount <= config.maxPlayers
|
||||
? `✓ ${activePlayerCount}/${config.maxPlayers} ${activePlayerCount === 1 ? 'player' : 'players'}`
|
||||
: `✗ Too many players (max ${config.maxPlayers})`
|
||||
}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -84,14 +84,20 @@ export function GameSelector({
|
||||
const { activePlayerCount } = useGameMode()
|
||||
|
||||
return (
|
||||
<div className={className}>
|
||||
<div className={css({
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
flexDirection: 'column',
|
||||
overflow: 'hidden'
|
||||
}, className)}>
|
||||
{showHeader && (
|
||||
<h3 className={css({
|
||||
fontSize: variant === 'compact' ? 'lg' : 'xl',
|
||||
fontSize: variant === 'compact' ? 'lg' : { base: 'lg', md: 'xl' },
|
||||
fontWeight: 'bold',
|
||||
color: 'gray.800',
|
||||
mb: '4',
|
||||
textAlign: 'center'
|
||||
mb: { base: '2', md: '3' },
|
||||
textAlign: 'center',
|
||||
flexShrink: 0
|
||||
})}>
|
||||
🎮 Available Games
|
||||
</h3>
|
||||
@@ -111,8 +117,12 @@ export function GameSelector({
|
||||
) : (
|
||||
<div className={css({
|
||||
display: 'grid',
|
||||
gridTemplateColumns: { base: '1fr', md: variant === 'compact' ? 'repeat(2, 1fr)' : 'repeat(2, 1fr)' },
|
||||
gap: variant === 'compact' ? '3' : '4'
|
||||
gridTemplateColumns: { base: '1fr', md: 'repeat(2, 1fr)' },
|
||||
gridTemplateRows: { base: 'repeat(4, 1fr)', md: 'repeat(2, 1fr)' },
|
||||
gap: variant === 'compact' ? '2' : { base: '2', md: '3' },
|
||||
flex: 1,
|
||||
minHeight: 0,
|
||||
overflow: 'hidden'
|
||||
})}>
|
||||
{Object.entries(GAMES_CONFIG).map(([gameType, config]) => (
|
||||
<GameCard
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "soroban-monorepo",
|
||||
"version": "1.1.0",
|
||||
"version": "1.2.0",
|
||||
"private": true,
|
||||
"description": "Beautiful Soroban Flashcard Generator - Monorepo",
|
||||
"workspaces": [
|
||||
|
||||
Reference in New Issue
Block a user