Add genlocke creation wizard with backend API and 4-step frontend

Implements the genlocke creation feature end-to-end: Genlocke and
GenlockeLeg models with migration, POST /genlockes endpoint that
creates the genlocke with all legs and auto-starts the first run,
and a 4-step wizard UI (Name, Select Games with preset templates,
Rules, Confirm) at /genlockes/new.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Julian Tabel
2026-02-09 09:23:48 +01:00
parent aaaeb2146e
commit 7851e14c2f
18 changed files with 923 additions and 29 deletions

View File

@@ -28,6 +28,12 @@ export function Layout() {
>
My Runs
</Link>
<Link
to="/genlockes/new"
className="px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-100 dark:hover:bg-gray-700"
>
Genlockes
</Link>
<Link
to="/stats"
className="px-3 py-2 rounded-md text-sm font-medium hover:bg-gray-100 dark:hover:bg-gray-700"
@@ -93,6 +99,13 @@ export function Layout() {
>
My Runs
</Link>
<Link
to="/genlockes/new"
onClick={() => setMenuOpen(false)}
className="block px-3 py-2 rounded-md text-base font-medium hover:bg-gray-100 dark:hover:bg-gray-700"
>
Genlockes
</Link>
<Link
to="/stats"
onClick={() => setMenuOpen(false)}

View File

@@ -1,15 +1,16 @@
const STEPS = ['Select Game', 'Configure Rules', 'Create Run']
const DEFAULT_STEPS = ['Select Game', 'Configure Rules', 'Create Run']
interface StepIndicatorProps {
currentStep: number
onStepClick: (step: number) => void
steps?: string[]
}
export function StepIndicator({ currentStep, onStepClick }: StepIndicatorProps) {
export function StepIndicator({ currentStep, onStepClick, steps = DEFAULT_STEPS }: StepIndicatorProps) {
return (
<nav aria-label="Progress" className="mb-8">
<ol className="flex items-center">
{STEPS.map((label, i) => {
{steps.map((label, i) => {
const step = i + 1
const isCompleted = step < currentStep
const isCurrent = step === currentStep
@@ -17,7 +18,7 @@ export function StepIndicator({ currentStep, onStepClick }: StepIndicatorProps)
return (
<li
key={label}
className={`flex items-center ${i < STEPS.length - 1 ? 'flex-1' : ''}`}
className={`flex items-center ${i < steps.length - 1 ? 'flex-1' : ''}`}
>
<button
type="button"
@@ -60,7 +61,7 @@ export function StepIndicator({ currentStep, onStepClick }: StepIndicatorProps)
</span>
<span className="hidden sm:inline">{label}</span>
</button>
{i < STEPS.length - 1 && (
{i < steps.length - 1 && (
<div
className={`flex-1 h-0.5 mx-3 ${
step < currentStep