feat(home): redesign home page to showcase complete platform

Replace outdated "flashcard generator" landing page with comprehensive
platform showcase highlighting all three pillars: arcade games,
interactive learning, and flashcard creation.

**New Home Page Structure:**
- Compact hero with 3 CTAs: Play Games, Learn, Create
- 4 arcade game cards with player counts and mode tags
- Two-column feature sections for Learning & Flashcards
- Multiplayer features grid (4 cards)
- Stats banner: 4 games, 8 max players, 3 learning modes, 4+ formats

**Visual Design:**
- Smaller, denser components to fit more content
- Information-rich showcase vs marketing fluff
- Purple gradient hero matching guide branding
- Responsive grid layouts for all screen sizes

**Result:**
Home page now accurately represents the full platform:
multiplayer arcade games + interactive tutorials + flashcard tools.

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

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-10-18 17:32:51 -05:00
parent 9b9f0cdbcb
commit ee6c4f2f4f
2 changed files with 376 additions and 121 deletions

View File

@ -97,7 +97,8 @@
"Bash(pnpm exec turbo build --filter=@soroban/web)",
"Bash(do gh run list --limit 1 --json conclusion,status,name,databaseId --jq '.[0] | \"\"\\(.status) - \\(.conclusion // \"\"running\"\")\"\"')",
"Bash(do gh run list --limit 1 --json conclusion,status,name --jq '.[0] | \"\"\\(.status) - \\(.conclusion // \"\"running\"\") - \\(.name)\"\"')",
"Bash(do gh run list --limit 1 --workflow=\"Build and Deploy\" --json conclusion,status --jq '.[0] | \"\"\\(.status) - \\(.conclusion // \"\"running\"\")\"\"')"
"Bash(do gh run list --limit 1 --workflow=\"Build and Deploy\" --json conclusion,status --jq '.[0] | \"\"\\(.status) - \\(.conclusion // \"\"running\"\")\"\"')",
"WebFetch(domain:abaci.one)"
],
"deny": [],
"ask": []

View File

@ -3,133 +3,400 @@
import Link from 'next/link'
import { PageWithNav } from '@/components/PageWithNav'
import { css } from '../../styled-system/css'
import { container, hstack, stack } from '../../styled-system/patterns'
import { container, grid, hstack, stack } from '../../styled-system/patterns'
export default function HomePage() {
return (
<PageWithNav navTitle="Soroban Flashcards" navEmoji="🧮">
<div
className={css({
minHeight: '100vh',
bg: 'gradient-to-br from-brand.50 to-brand.100',
})}
>
{/* Hero Section */}
<main className={container({ maxW: '6xl', px: '4' })}>
<div
className={stack({
gap: '12',
py: '16',
align: 'center',
textAlign: 'center',
})}
>
{/* Hero Content */}
<div className={stack({ gap: '6', maxW: '4xl' })}>
<PageWithNav navTitle="Soroban Mastery Platform" navEmoji="🧮">
<div className={css({ bg: 'gray.50', minHeight: '100vh' })}>
{/* Compact Hero */}
<div
className={css({
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
py: { base: '8', md: '12' },
})}
>
<div className={container({ maxW: '6xl', px: '4' })}>
<div className={css({ textAlign: 'center', maxW: '4xl', mx: 'auto' })}>
<h1
className={css({
fontSize: { base: '4xl', md: '6xl' },
fontSize: { base: '3xl', md: '5xl' },
fontWeight: 'bold',
color: 'gray.900',
mb: '4',
lineHeight: 'tight',
})}
>
Beautiful Soroban <span className={css({ color: 'brand.600' })}>Flashcards</span>
Master Soroban Through{' '}
<span className={css({ color: 'yellow.300' })}>Play & Practice</span>
</h1>
<p
className={css({
fontSize: { base: 'lg', md: 'xl' },
color: 'gray.600',
maxW: '2xl',
mx: 'auto',
})}
>
Create stunning, educational flashcards with authentic Japanese abacus
representations. Perfect for teachers, students, and mental math enthusiasts.
<p className={css({ fontSize: { base: 'md', md: 'lg' }, opacity: 0.95, mb: '6' })}>
Interactive tutorials, multiplayer games, and beautiful flashcardsyour complete
soroban learning ecosystem
</p>
<div className={hstack({ gap: '4', justify: 'center', mt: '8' })}>
<div className={hstack({ gap: '3', justify: 'center', flexWrap: 'wrap' })}>
<Link
href="/create"
href="/arcade"
className={css({
px: '8',
py: '4',
bg: 'brand.600',
color: 'white',
fontSize: 'lg',
fontWeight: 'semibold',
rounded: 'xl',
shadow: 'card',
px: '6',
py: '3',
bg: 'yellow.400',
color: 'gray.900',
fontWeight: 'bold',
rounded: 'lg',
shadow: 'lg',
_hover: { bg: 'yellow.300', transform: 'translateY(-2px)' },
transition: 'all',
_hover: {
bg: 'brand.700',
transform: 'translateY(-2px)',
shadow: 'modal',
},
})}
>
Start Creating
🎮 Play Games
</Link>
<Link
href="/guide"
className={css({
px: '8',
py: '4',
px: '6',
py: '3',
bg: 'white',
color: 'brand.700',
fontSize: 'lg',
fontWeight: 'semibold',
rounded: 'xl',
shadow: 'card',
border: '2px solid',
borderColor: 'brand.200',
color: 'purple.700',
fontWeight: 'bold',
rounded: 'lg',
shadow: 'lg',
_hover: { bg: 'gray.100', transform: 'translateY(-2px)' },
transition: 'all',
_hover: {
borderColor: 'brand.400',
transform: 'translateY(-2px)',
},
})}
>
📚 Learn Soroban
📚 Learn
</Link>
<Link
href="/create"
className={css({
px: '6',
py: '3',
bg: 'purple.600',
color: 'white',
fontWeight: 'bold',
rounded: 'lg',
shadow: 'lg',
_hover: { bg: 'purple.700', transform: 'translateY(-2px)' },
transition: 'all',
})}
>
🎨 Create
</Link>
</div>
</div>
</div>
</div>
{/* Features Grid */}
<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
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',
})}
>
📚 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>
</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>
{/* Quick Stats */}
<section
className={css({
display: 'grid',
gridTemplateColumns: { base: '1', md: '3' },
gap: '8',
mt: '16',
w: 'full',
bg: 'gradient-to-r',
gradientFrom: 'purple.600',
gradientTo: 'indigo.600',
rounded: 'xl',
p: '6',
color: 'white',
})}
>
<FeatureCard
icon="🎨"
title="Beautiful Design"
description="Vector graphics, color schemes, authentic bead positioning"
/>
<FeatureCard
icon="⚡"
title="Instant Generation"
description="Create PDFs, interactive HTML, PNGs, and SVGs in seconds"
/>
<FeatureCard
icon="🎯"
title="Educational Focus"
description="Perfect for teachers, students, and soroban enthusiasts"
/>
</div>
<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>
</main>
</div>
</div>
</PageWithNav>
)
}
function GameCard({
icon,
title,
description,
players,
tags,
}: {
icon: string
title: string
description: string
players: string
tags: string[]
}) {
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)' },
})}
>
<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>
</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,
@ -142,44 +409,31 @@ function FeatureCard({
return (
<div
className={css({
p: '8',
bg: 'white',
rounded: '2xl',
shadow: 'card',
rounded: 'lg',
p: '4',
shadow: 'sm',
border: '1px solid',
borderColor: 'gray.200',
textAlign: 'center',
transition: 'all',
_hover: {
transform: 'translateY(-4px)',
shadow: 'modal',
},
})}
>
<div
className={css({
fontSize: '4xl',
mb: '4',
})}
>
{icon}
</div>
<h3
className={css({
fontSize: 'xl',
fontWeight: 'bold',
color: 'gray.900',
mb: '3',
})}
>
<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({
color: 'gray.600',
lineHeight: 'relaxed',
})}
>
<p className={css({ fontSize: 'xs', color: 'gray.600', lineHeight: 'relaxed' })}>
{description}
</p>
</div>
)
}
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>
)
}