Implement dark-first design system with Geist typography (#28)
All checks were successful
CI / backend-lint (push) Successful in 10s
CI / actions-lint (push) Successful in 16s
CI / frontend-lint (push) Successful in 21s

Co-authored-by: Julian Tabel <juliantabel.jt@gmail.com>
Co-committed-by: Julian Tabel <juliantabel.jt@gmail.com>
This commit was merged in pull request #28.
This commit is contained in:
2026-02-17 20:48:42 +01:00
committed by TheFurya
parent e3b3dc5317
commit 42b66ee9a2
56 changed files with 1151 additions and 1067 deletions

View File

@@ -57,27 +57,23 @@ export function NewRun() {
return (
<div className="max-w-4xl mx-auto p-8">
<h1 className="text-3xl font-bold text-gray-900 dark:text-gray-100 mb-2">New Nuzlocke Run</h1>
<p className="text-gray-600 dark:text-gray-400 mb-6">Set up your run in a few steps.</p>
<h1 className="text-3xl font-bold text-text-primary mb-2">New Nuzlocke Run</h1>
<p className="text-text-tertiary mb-6">Set up your run in a few steps.</p>
<StepIndicator currentStep={step} onStepClick={setStep} />
{step === 1 && (
<div>
<h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-4">
Choose a Game
</h2>
<h2 className="text-xl font-semibold text-text-primary mb-4">Choose a Game</h2>
<div className="sticky top-0 z-10 bg-gray-50 dark:bg-gray-900 py-3 mb-4 border-b border-gray-200 dark:border-gray-700">
<div className="sticky top-0 z-10 bg-surface-0 py-3 mb-4 border-b border-border-default">
{selectedGame ? (
<div className="flex items-center justify-between">
<div className="flex items-center gap-3">
<SelectedGameThumb game={selectedGame} />
<div>
<p className="font-medium text-gray-900 dark:text-gray-100">
{selectedGame.name}
</p>
<p className="text-sm text-gray-500 dark:text-gray-400">
<p className="font-medium text-text-primary">{selectedGame.name}</p>
<p className="text-sm text-text-tertiary">
{selectedGame.region.charAt(0).toUpperCase() + selectedGame.region.slice(1)}
</p>
</div>
@@ -85,16 +81,14 @@ export function NewRun() {
<button
type="button"
onClick={() => setStep(2)}
className="px-6 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
className="px-6 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2 transition-colors"
>
Next
</button>
</div>
) : (
<div className="flex items-center justify-between">
<p className="text-sm text-gray-500 dark:text-gray-400">
Select a game to continue
</p>
<p className="text-sm text-text-tertiary">Select a game to continue</p>
<button
type="button"
disabled
@@ -113,7 +107,7 @@ export function NewRun() {
)}
{error && (
<div className="rounded-lg bg-red-50 dark:bg-red-900/20 p-4 text-red-700 dark:text-red-400">
<div className="rounded-lg bg-status-failed-bg p-4 text-status-failed">
Failed to load games. Please try again.
</div>
)}
@@ -137,14 +131,14 @@ export function NewRun() {
<button
type="button"
onClick={() => setStep(1)}
className="px-6 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 transition-colors"
className="px-6 py-2 text-text-secondary bg-surface-2 rounded-lg font-medium hover:bg-surface-3 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 transition-colors"
>
Back
</button>
<button
type="button"
onClick={() => setStep(3)}
className="px-6 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
className="px-6 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2 transition-colors"
>
Next
</button>
@@ -154,15 +148,13 @@ export function NewRun() {
{step === 3 && (
<div>
<h2 className="text-xl font-semibold text-gray-900 dark:text-gray-100 mb-4">
Name Your Run
</h2>
<h2 className="text-xl font-semibold text-text-primary mb-4">Name Your Run</h2>
<div className="bg-white dark:bg-gray-800 rounded-lg shadow p-6 space-y-4">
<div className="bg-surface-1 rounded-lg shadow p-6 space-y-4">
<div>
<label
htmlFor="run-name"
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
className="block text-sm font-medium text-text-secondary mb-1"
>
Run Name
</label>
@@ -171,7 +163,7 @@ export function NewRun() {
type="text"
value={runName}
onChange={(e) => setRunName(e.target.value)}
className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
className="w-full px-3 py-2 rounded-lg border border-border-default bg-surface-2 text-text-primary focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-transparent"
placeholder="My Nuzlocke Run"
/>
</div>
@@ -180,7 +172,7 @@ export function NewRun() {
<div>
<label
htmlFor="naming-scheme"
className="block text-sm font-medium text-gray-700 dark:text-gray-300 mb-1"
className="block text-sm font-medium text-text-secondary mb-1"
>
Naming Scheme
</label>
@@ -188,7 +180,7 @@ export function NewRun() {
id="naming-scheme"
value={namingScheme ?? ''}
onChange={(e) => setNamingScheme(e.target.value || null)}
className="w-full px-3 py-2 rounded-lg border border-gray-300 dark:border-gray-600 bg-white dark:bg-gray-700 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:border-transparent"
className="w-full px-3 py-2 rounded-lg border border-border-default bg-surface-2 text-text-primary focus:outline-none focus:ring-2 focus:ring-accent-400 focus:border-transparent"
>
<option value="">None (manual nicknames)</option>
{namingCategories.map((cat) => (
@@ -197,37 +189,35 @@ export function NewRun() {
</option>
))}
</select>
<p className="mt-1 text-xs text-gray-500 dark:text-gray-400">
<p className="mt-1 text-xs text-text-tertiary">
Get nickname suggestions from a themed word list when catching Pokemon.
</p>
</div>
)}
<div className="border-t border-gray-200 dark:border-gray-700 pt-4">
<h3 className="text-sm font-medium text-gray-500 dark:text-gray-400 mb-2">Summary</h3>
<div className="border-t border-border-default pt-4">
<h3 className="text-sm font-medium text-text-tertiary mb-2">Summary</h3>
<dl className="space-y-1 text-sm">
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">Game</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
{selectedGame?.name}
</dd>
<dt className="text-text-tertiary">Game</dt>
<dd className="text-text-primary font-medium">{selectedGame?.name}</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">Region</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
<dt className="text-text-tertiary">Region</dt>
<dd className="text-text-primary font-medium">
{selectedGame &&
selectedGame.region.charAt(0).toUpperCase() + selectedGame.region.slice(1)}
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">Rules</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
<dt className="text-text-tertiary">Rules</dt>
<dd className="text-text-primary font-medium">
{enabledRuleCount} of {totalRuleCount} enabled
</dd>
</div>
<div className="flex justify-between">
<dt className="text-gray-600 dark:text-gray-400">Naming Scheme</dt>
<dd className="text-gray-900 dark:text-gray-100 font-medium">
<dt className="text-text-tertiary">Naming Scheme</dt>
<dd className="text-text-primary font-medium">
{namingScheme
? namingScheme.charAt(0).toUpperCase() + namingScheme.slice(1)
: 'None'}
@@ -238,7 +228,7 @@ export function NewRun() {
</div>
{createRun.error && (
<div className="mt-4 rounded-lg bg-red-50 dark:bg-red-900/20 p-4 text-red-700 dark:text-red-400">
<div className="mt-4 rounded-lg bg-status-failed-bg p-4 text-status-failed">
Failed to create run. Please try again.
</div>
)}
@@ -247,7 +237,7 @@ export function NewRun() {
<button
type="button"
onClick={() => setStep(2)}
className="px-6 py-2 text-gray-700 dark:text-gray-300 bg-gray-100 dark:bg-gray-700 rounded-lg font-medium hover:bg-gray-200 dark:hover:bg-gray-600 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 transition-colors"
className="px-6 py-2 text-text-secondary bg-surface-2 rounded-lg font-medium hover:bg-surface-3 focus:outline-none focus:ring-2 focus:ring-gray-400 focus:ring-offset-2 transition-colors"
>
Back
</button>
@@ -255,7 +245,7 @@ export function NewRun() {
type="button"
disabled={!runName.trim() || createRun.isPending}
onClick={handleCreate}
className="px-6 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
className="px-6 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
>
{createRun.isPending ? 'Creating...' : 'Create Run'}
</button>