From 7dbf3772dfed5eec2fff09c2b4691974a1df318d Mon Sep 17 00:00:00 2001 From: Julian Tabel Date: Sat, 7 Feb 2026 21:29:14 +0100 Subject: [PATCH] Improve run creation workflow with filters, local box art, and sticky nav Use local /boxart/{slug}.png images instead of database boxArtUrl with color-swatch fallback. Add region filter pills and run-status checkboxes (hide active/completed) to GameGrid. Move the Next button into a sticky top bar showing selected game summary so it's always visible. Capitalize region names in all display locations. Co-Authored-By: Claude Opus 4.6 --- ...-o7il--improve-run-creation-workflow-ux.md | 21 +++ frontend/src/components/GameCard.tsx | 10 +- frontend/src/components/GameGrid.tsx | 124 ++++++++++++++---- frontend/src/pages/NewRun.tsx | 84 ++++++++++-- frontend/src/pages/RunDashboard.tsx | 2 +- frontend/src/pages/RunEncounters.tsx | 2 +- frontend/src/pages/admin/AdminGameDetail.tsx | 2 +- 7 files changed, 199 insertions(+), 46 deletions(-) create mode 100644 .beans/nuzlocke-tracker-o7il--improve-run-creation-workflow-ux.md diff --git a/.beans/nuzlocke-tracker-o7il--improve-run-creation-workflow-ux.md b/.beans/nuzlocke-tracker-o7il--improve-run-creation-workflow-ux.md new file mode 100644 index 0000000..cf1492b --- /dev/null +++ b/.beans/nuzlocke-tracker-o7il--improve-run-creation-workflow-ux.md @@ -0,0 +1,21 @@ +--- +# nuzlocke-tracker-o7il +title: Improve run creation workflow UX +status: completed +type: feature +priority: normal +created_at: 2026-02-07T20:26:26Z +updated_at: 2026-02-07T20:27:46Z +--- + +Box art from local files, capitalize regions everywhere, add region filter + run-status filters to GameGrid, sticky top bar with selected game summary + Next button in NewRun step 1. + +## Checklist +- [ ] GameCard: box art from /boxart/{slug}.png with color fallback, capitalize region +- [ ] GameGrid: add runs prop, region filter pills, run-status checkboxes, capitalize regions +- [ ] NewRun: add useRuns(), pass runs to GameGrid, sticky top bar with game summary + Next button +- [ ] RunEncounters: capitalize region display +- [ ] RunDashboard: capitalize region display +- [ ] AdminGameDetail: capitalize region display +- [ ] NewRun step 3 summary: capitalize region display +- [ ] Verify: npx tsc --noEmit clean compile \ No newline at end of file diff --git a/frontend/src/components/GameCard.tsx b/frontend/src/components/GameCard.tsx index dfb4d73..5d96e27 100644 --- a/frontend/src/components/GameCard.tsx +++ b/frontend/src/components/GameCard.tsx @@ -1,3 +1,4 @@ +import { useState } from 'react' import type { Game } from '../types' const DEFAULT_COLOR = '#6366f1' // indigo-500 @@ -10,6 +11,8 @@ interface GameCardProps { export function GameCard({ game, selected, onSelect }: GameCardProps) { const backgroundColor = game.color ?? DEFAULT_COLOR + const [imgError, setImgError] = useState(false) + const boxArtSrc = `/boxart/${game.slug}.png` return ( - {generations.map((gen) => ( +
+
+ Gen: - ))} + {generations.map((gen) => ( + + ))} +
+ +
+ Region: + + {regions.map((region) => ( + + ))} +
+ + {runs && ( +
+ + +
+ )}
{grouped.map(({ generation, games }) => ( diff --git a/frontend/src/pages/NewRun.tsx b/frontend/src/pages/NewRun.tsx index 3b8a04e..51e05e0 100644 --- a/frontend/src/pages/NewRun.tsx +++ b/frontend/src/pages/NewRun.tsx @@ -2,13 +2,16 @@ import { useState } from 'react' import { useNavigate } from 'react-router-dom' import { GameGrid, RulesConfiguration, StepIndicator } from '../components' import { useGames } from '../hooks/useGames' -import { useCreateRun } from '../hooks/useRuns' +import { useCreateRun, useRuns } from '../hooks/useRuns' import type { Game, NuzlockeRules } from '../types' import { DEFAULT_RULES } from '../types' +const DEFAULT_COLOR = '#6366f1' + export function NewRun() { const navigate = useNavigate() const { data: games, isLoading, error } = useGames() + const { data: runs } = useRuns() const createRun = useCreateRun() const [step, setStep] = useState(1) @@ -55,6 +58,44 @@ export function NewRun() { Choose a Game +
+ {selectedGame ? ( +
+
+ +
+

+ {selectedGame.name} +

+

+ {selectedGame.region.charAt(0).toUpperCase() + selectedGame.region.slice(1)} +

+
+
+ +
+ ) : ( +
+

+ Select a game to continue +

+ +
+ )} +
+ {isLoading && (
@@ -72,19 +113,9 @@ export function NewRun() { games={games} selectedId={selectedGame?.id ?? null} onSelect={handleGameSelect} + runs={runs} /> )} - -
- -
)} @@ -149,7 +180,7 @@ export function NewRun() {
Region
- {selectedGame?.region} + {selectedGame && (selectedGame.region.charAt(0).toUpperCase() + selectedGame.region.slice(1))}
@@ -190,3 +221,30 @@ export function NewRun() {
) } + +function SelectedGameThumb({ game }: { game: Game }) { + const [imgError, setImgError] = useState(false) + const backgroundColor = game.color ?? DEFAULT_COLOR + + if (imgError) { + return ( +
+ + {game.name.replace('Pokemon ', '').slice(0, 3)} + +
+ ) + } + + return ( + {game.name} setImgError(true)} + /> + ) +} diff --git a/frontend/src/pages/RunDashboard.tsx b/frontend/src/pages/RunDashboard.tsx index 843c181..024ca32 100644 --- a/frontend/src/pages/RunDashboard.tsx +++ b/frontend/src/pages/RunDashboard.tsx @@ -82,7 +82,7 @@ export function RunDashboard() { {run.name}

- {run.game.name} · {run.game.region} · Started{' '} + {run.game.name} · {run.game.region.charAt(0).toUpperCase() + run.game.region.slice(1)} · Started{' '} {new Date(run.startedAt).toLocaleDateString(undefined, { year: 'numeric', month: 'short', diff --git a/frontend/src/pages/RunEncounters.tsx b/frontend/src/pages/RunEncounters.tsx index 919e8f9..5a44402 100644 --- a/frontend/src/pages/RunEncounters.tsx +++ b/frontend/src/pages/RunEncounters.tsx @@ -580,7 +580,7 @@ export function RunEncounters() { {run.name}

- {run.game.name} · {run.game.region} · Started{' '} + {run.game.name} · {run.game.region.charAt(0).toUpperCase() + run.game.region.slice(1)} · Started{' '} {new Date(run.startedAt).toLocaleDateString(undefined, { year: 'numeric', month: 'short', diff --git a/frontend/src/pages/admin/AdminGameDetail.tsx b/frontend/src/pages/admin/AdminGameDetail.tsx index e307175..e8e3a00 100644 --- a/frontend/src/pages/admin/AdminGameDetail.tsx +++ b/frontend/src/pages/admin/AdminGameDetail.tsx @@ -152,7 +152,7 @@ export function AdminGameDetail() {

{game.name}

- {game.region} · Gen {game.generation} + {game.region.charAt(0).toUpperCase() + game.region.slice(1)} · Gen {game.generation} {game.releaseYear ? ` \u00b7 ${game.releaseYear}` : ''}