Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,15 @@ const withTM = require('next-transpile-modules')(['@react-chess/chessground'])
module.exports = withTM({
reactStrictMode: false,
output: 'standalone',
async redirects() {
return [
{
source: '/openings',
destination: '/drills',
permanent: true,
},
]
},
async rewrites() {
return [
{
Expand Down
10 changes: 5 additions & 5 deletions src/components/Common/Header.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -209,10 +209,10 @@ export const Header: React.FC = () => {
PUZZLES
</Link>
<Link
href="/openings"
className={`px-2 py-1 transition-all duration-200 hover:!text-primary ${router.pathname.startsWith('/openings') ? '!text-primary' : '!text-primary/80'}`}
href="/drills"
className={`px-2 py-1 transition-all duration-200 hover:!text-primary ${router.pathname.startsWith('/drills') ? '!text-primary' : '!text-primary/80'}`}
>
PRACTICE
DRILLS
</Link>
<Link
href="/turing"
Expand Down Expand Up @@ -391,8 +391,8 @@ export const Header: React.FC = () => {
<Link href="/puzzles" className="uppercase">
Puzzles
</Link>
<Link href="/openings" className="uppercase">
Practice
<Link href="/drills" className="uppercase">
Drills
</Link>
<Link href="/turing" className="uppercase">
Bot-or-not
Expand Down
4 changes: 2 additions & 2 deletions src/components/Home/HomeHero.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,9 @@ export const HomeHero: React.FC<Props> = ({ scrollHandler }: Props) => {
/>
<FeatureCard
icon="play_lesson"
title="Practice"
title="Drill"
description="Learn and practice chess openings with Maia"
href="/openings"
href="/drills"
index={4}
featureKey="openings"
/>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Home/Sections/AdditionalFeaturesSection.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -135,10 +135,10 @@ export const AdditionalFeaturesSection = ({
const features: Feature[] = [
{
icon: <StarIcon />,
title: 'Practice',
title: 'Drill',
description:
"Drill chess openings against Maia models calibrated to specific rating levels, allowing you to practice against opponents similar to those you'll face.",
action: { type: 'link', href: '/openings', label: 'Practice' },
action: { type: 'link', href: '/drills', label: 'Drill' },
iconBgColor: 'bg-human-3/10',
iconTextColor: 'text-human-3',
},
Expand Down
88 changes: 51 additions & 37 deletions src/components/Openings/DrillPerformanceModal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ interface Props {
performanceData: DrillPerformanceData
onContinueAnalyzing: () => void
onNextDrill: () => void
isLastDrill: boolean
onReconfigureDrills: () => void
}

// Helper function to extract move number from FEN string
Expand Down Expand Up @@ -769,7 +769,7 @@ const DesktopLayout: React.FC<{
performanceData: DrillPerformanceData
onContinueAnalyzing: () => void
onNextDrill: () => void
isLastDrill: boolean
onReconfigureDrills: () => void
gameTree: GameTree
openingEndNode: GameNode
playerMoveCount: number
Expand All @@ -788,7 +788,7 @@ const DesktopLayout: React.FC<{
performanceData,
onContinueAnalyzing,
onNextDrill,
isLastDrill,
onReconfigureDrills,
gameTree,
openingEndNode,
playerMoveCount,
Expand All @@ -812,9 +812,7 @@ const DesktopLayout: React.FC<{
{/* Header */}
<div className="flex items-center justify-between border-b border-glass-border p-4">
<div>
<h2 className="text-xl font-bold text-primary">
Opening Analysis Complete
</h2>
<h2 className="text-xl font-bold text-primary">Drill Review</h2>
<div className="mt-1">
<p className="text-base font-medium text-secondary">
{drill.selection.opening.name}
Expand Down Expand Up @@ -1064,23 +1062,29 @@ const DesktopLayout: React.FC<{
</div>

{/* Action Buttons */}
<div className="flex gap-3 border-t border-glass-border p-4">
<button
onClick={onContinueAnalyzing}
className={`${
isLastDrill ? 'w-full' : 'flex-1'
} rounded border border-glass-border bg-white/5 py-2 font-medium backdrop-blur-sm transition-colors hover:bg-white/10`}
>
Analyze
</button>
{!isLastDrill && (
<div className="border-t border-glass-border p-4">
<div className="flex gap-3">
<button
onClick={onContinueAnalyzing}
className="flex-1 rounded bg-human-4 py-2 font-medium text-white transition-colors hover:bg-human-4/80"
>
Analyze
</button>
<button
onClick={onNextDrill}
className="flex-1 rounded bg-human-4 py-2 font-medium transition-colors hover:bg-human-4/80"
className="flex-1 rounded bg-human-4 py-2 font-medium text-white transition-colors hover:bg-human-4/80"
>
Next Drill
</button>
)}
</div>
<div className="mt-3 flex justify-center">
<button
onClick={onReconfigureDrills}
className="text-sm font-medium text-white/55 transition-colors hover:text-white/80"
>
Reconfigure Drills
</button>
</div>
</div>
</div>
)
Expand All @@ -1093,7 +1097,7 @@ const MobileLayout: React.FC<{
performanceData: DrillPerformanceData
onContinueAnalyzing: () => void
onNextDrill: () => void
isLastDrill: boolean
onReconfigureDrills: () => void
activeTab: 'replay' | 'analysis' | 'insights'
setActiveTab: (tab: 'replay' | 'analysis' | 'insights') => void
gameTree: GameTree
Expand All @@ -1114,7 +1118,7 @@ const MobileLayout: React.FC<{
performanceData,
onContinueAnalyzing,
onNextDrill,
isLastDrill,
onReconfigureDrills,
activeTab,
setActiveTab,
gameTree,
Expand All @@ -1140,7 +1144,7 @@ const MobileLayout: React.FC<{
{/* Header */}
<div className="flex items-center justify-between border-b border-glass-border p-4">
<div className="min-w-0 flex-1">
<h2 className="text-lg font-bold text-primary">Analysis Complete</h2>
<h2 className="text-lg font-bold text-primary">Drill Review</h2>
<div className="mt-1">
<p className="text-sm font-medium text-secondary">
{drill.selection.opening.name}
Expand Down Expand Up @@ -1280,19 +1284,29 @@ const MobileLayout: React.FC<{
</div>

{/* Action Buttons */}
<div className="flex gap-3 border-t border-glass-border p-4">
<button
onClick={onContinueAnalyzing}
className="flex-1 rounded border border-glass-border bg-white/5 py-2 font-medium backdrop-blur-sm transition-colors hover:bg-white/10"
>
Analyze
</button>
<button
onClick={onNextDrill}
className="flex-1 rounded bg-human-4 py-2 font-medium transition-colors hover:bg-human-4/80"
>
{isLastDrill ? 'Summary' : 'Next'}
</button>
<div className="border-t border-glass-border p-4">
<div className="flex gap-3">
<button
onClick={onContinueAnalyzing}
className="flex-1 rounded bg-human-4 py-2 font-medium text-white transition-colors hover:bg-human-4/80"
>
Analyze
</button>
<button
onClick={onNextDrill}
className="flex-1 rounded bg-human-4 py-2 font-medium text-white transition-colors hover:bg-human-4/80"
>
Next Drill
</button>
</div>
<div className="mt-3 flex justify-center">
<button
onClick={onReconfigureDrills}
className="text-sm font-medium text-white/55 transition-colors hover:text-white/80"
>
Reconfigure Drills
</button>
</div>
</div>
</div>
)
Expand All @@ -1301,7 +1315,7 @@ export const DrillPerformanceModal: React.FC<Props> = ({
performanceData,
onContinueAnalyzing,
onNextDrill,
isLastDrill,
onReconfigureDrills,
}) => {
const { isMobile } = useContext(WindowSizeContext)
const [activeTab, setActiveTab] = useState<
Expand Down Expand Up @@ -1490,7 +1504,7 @@ export const DrillPerformanceModal: React.FC<Props> = ({
performanceData={performanceData}
onContinueAnalyzing={onContinueAnalyzing}
onNextDrill={onNextDrill}
isLastDrill={isLastDrill}
onReconfigureDrills={onReconfigureDrills}
activeTab={activeTab}
setActiveTab={setActiveTab}
gameTree={gameTree}
Expand All @@ -1510,7 +1524,7 @@ export const DrillPerformanceModal: React.FC<Props> = ({
performanceData={performanceData}
onContinueAnalyzing={onContinueAnalyzing}
onNextDrill={onNextDrill}
isLastDrill={isLastDrill}
onReconfigureDrills={onReconfigureDrills}
gameTree={gameTree}
openingEndNode={openingEndNode}
playerMoveCount={playerMoveCount}
Expand Down
126 changes: 80 additions & 46 deletions src/components/Openings/OpeningDrillSidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ export const OpeningDrillSidebar: React.FC<Props> = ({
const currentIsEndgame = currentDrill?.opening.categoryType === 'endgame'
const currentTraitLabel = currentDrill?.endgameMeta?.traitLabel
const currentGroupLabel = currentDrill?.endgameMeta?.groupLabel
const currentPoolSelectionId = currentDrill
? currentDrill.endgameMeta?.groupId ||
currentDrill.id.replace(/__attempt_\d+$/, '')
: null

const poolCategory =
selectionPool[0]?.opening.categoryType ??
Expand Down Expand Up @@ -245,61 +249,91 @@ export const OpeningDrillSidebar: React.FC<Props> = ({
</div>
<div className="flex flex-col gap-1 border-t border-glass-border px-0 py-2">
<h3 className="px-4 text-sm font-medium text-white/90">
Active {poolLabel} Pool ({selectionPool.length})
Active Drill Pool ({selectionPool.length})
</h3>
{selectionPool.length === 0 ? (
<p className="mt-2 text-xs text-white/70">
Add {poolLabelPlural.toLowerCase()} to begin drilling.
</p>
) : (
<div className="flex w-full flex-col">
{selectionPool.map((selection, index) => (
<div
key={`pool-${selection.id}-${index}`}
className="flex w-full items-center gap-2 px-4 py-1"
>
{selection.opening.categoryType === 'endgame' ? (
<span className="material-symbols-outlined text-sm text-human-3 md:text-base">
trophy
</span>
) : (
<div className="relative h-4 w-4 flex-shrink-0">
<Image
src={
selection.playerColor === 'white'
? '/assets/pieces/white king.svg'
: '/assets/pieces/black king.svg'
}
fill={true}
alt={`${selection.playerColor} king`}
/>
</div>
)}
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-center gap-2">
<p className="truncate text-xs font-medium text-white/90">
{selection.opening.name}
</p>
{selection.opening.isCustom && (
<span className="rounded border border-human-4/40 bg-human-4/10 px-2 py-0.5 text-xxs font-semibold uppercase tracking-wide text-human-2">
Custom
</span>
)}
</div>
{selection.opening.categoryType === 'endgame'
? selection.endgameMeta?.traitLabel && (
<p className="text-xxs text-human-3">
{selection.endgameMeta.traitLabel}
</p>
)
: selection.variation && (
<p className="truncate text-[11px] text-white/60">
{selection.variation.name}
</p>
{selectionPool.map((selection, index) => {
const isCurrentPoolSelection =
currentPoolSelectionId === selection.id

return (
<div
key={`pool-${selection.id}-${index}`}
className={`relative mx-2 flex w-auto items-center gap-2 rounded-md border px-3 py-2 transition-colors ${
isCurrentPoolSelection
? 'bg-human-4/32 border-human-4/50'
: 'border-transparent bg-transparent'
}`}
>
{isCurrentPoolSelection && (
<span className="absolute inset-y-2 left-0 w-px rounded-full bg-human-4" />
)}
{selection.opening.categoryType === 'endgame' ? (
<span className="material-symbols-outlined text-sm text-human-3 md:text-base">
trophy
</span>
) : (
<div className="relative h-4 w-4 flex-shrink-0">
<Image
src={
selection.playerColor === 'white'
? '/assets/pieces/white king.svg'
: '/assets/pieces/black king.svg'
}
fill={true}
alt={`${selection.playerColor} king`}
/>
</div>
)}
<div className="min-w-0 flex-1">
<div className="flex flex-wrap items-center gap-2">
<p
className={`truncate text-xs font-medium ${
isCurrentPoolSelection
? 'text-white'
: 'text-white/90'
}`}
>
{selection.opening.name}
</p>
{selection.opening.isCustom && (
<span className="rounded border border-human-4/40 bg-human-4/10 px-2 py-0.5 text-xxs font-semibold uppercase tracking-wide text-human-2">
Custom
</span>
)}
</div>
{selection.opening.categoryType === 'endgame'
? selection.endgameMeta?.traitLabel && (
<p
className={`text-xxs ${
isCurrentPoolSelection
? 'text-human-1'
: 'text-human-3'
}`}
>
{selection.endgameMeta.traitLabel}
</p>
)
: selection.variation && (
<p
className={`truncate text-[11px] ${
isCurrentPoolSelection
? 'text-white/85'
: 'text-white/60'
}`}
>
{selection.variation.name}
</p>
)}
</div>
</div>
</div>
))}
)
})}
</div>
)}
</div>
Expand Down
Loading
Loading