Simplify modal, badge, and component styles to dark-first (#29)
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 #29.
This commit is contained in:
@@ -5,7 +5,7 @@ status: in-progress
|
|||||||
type: feature
|
type: feature
|
||||||
priority: normal
|
priority: normal
|
||||||
created_at: 2026-02-17T19:16:39Z
|
created_at: 2026-02-17T19:16:39Z
|
||||||
updated_at: 2026-02-17T19:45:49Z
|
updated_at: 2026-02-17T20:01:32Z
|
||||||
---
|
---
|
||||||
|
|
||||||
Overhaul the UI to a dark-first, techy aesthetic with a cohesive brand identity derived from the ANT steel ant logo.
|
Overhaul the UI to a dark-first, techy aesthetic with a cohesive brand identity derived from the ANT steel ant logo.
|
||||||
@@ -89,10 +89,10 @@ Self-host **Geist** (or Inter/JetBrains Mono pairing):
|
|||||||
- [x] Redesign home page hero section
|
- [x] Redesign home page hero section
|
||||||
- [x] Update card/surface styles globally (Layout, PokemonCard, StatCard, GameCard)
|
- [x] Update card/surface styles globally (Layout, PokemonCard, StatCard, GameCard)
|
||||||
- [x] Update all page-level backgrounds and containers
|
- [x] Update all page-level backgrounds and containers
|
||||||
- [ ] Update modal styles (EncounterModal, StatusChangeModal, etc.)
|
- [x] Update modal styles (EncounterModal, StatusChangeModal, etc.)
|
||||||
- [ ] Update badge/indicator styles (TypeBadge, RuleBadges, EncounterMethodBadge)
|
- [x] Update badge/indicator styles (TypeBadge, RuleBadges, EncounterMethodBadge)
|
||||||
- [ ] Add dark/light mode toggle to nav
|
- [ ] Add dark/light mode toggle to nav
|
||||||
- [ ] Polish hover states and transitions across all interactive elements
|
- [x] Polish hover states and transitions across all interactive elements
|
||||||
- [ ] Verify mobile layout and touch targets
|
- [ ] Verify mobile layout and touch targets
|
||||||
- [ ] Verify accessibility (contrast ratios, focus indicators)
|
- [ ] Verify accessibility (contrast ratios, focus indicators)
|
||||||
|
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export function BossDefeatModal({
|
|||||||
onClick={() => setSelectedVariant(label)}
|
onClick={() => setSelectedVariant(label)}
|
||||||
className={`px-2 py-0.5 text-xs font-medium rounded-full transition-colors ${
|
className={`px-2 py-0.5 text-xs font-medium rounded-full transition-colors ${
|
||||||
selectedVariant === label
|
selectedVariant === label
|
||||||
? 'bg-blue-600 text-white'
|
? 'bg-accent-600 text-white'
|
||||||
: 'bg-surface-2 text-text-secondary hover:bg-surface-3'
|
: 'bg-surface-2 text-text-secondary hover:bg-surface-3'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -1,20 +1,8 @@
|
|||||||
const CONDITION_CONFIG: Record<string, { label: string; color: string }> = {
|
const CONDITION_CONFIG: Record<string, { label: string; color: string }> = {
|
||||||
'Mega Evolution': {
|
'Mega Evolution': { label: 'Mega', color: 'bg-fuchsia-900/40 text-fuchsia-300' },
|
||||||
label: 'Mega',
|
Gigantamax: { label: 'G-Max', color: 'bg-red-900/40 text-red-300' },
|
||||||
color: 'bg-fuchsia-100 text-fuchsia-800 dark:bg-fuchsia-900/40 dark:text-fuchsia-300',
|
Dynamax: { label: 'D-Max', color: 'bg-rose-900/40 text-rose-300' },
|
||||||
},
|
Terastallize: { label: 'Tera', color: 'bg-teal-900/40 text-teal-300' },
|
||||||
Gigantamax: {
|
|
||||||
label: 'G-Max',
|
|
||||||
color: 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300',
|
|
||||||
},
|
|
||||||
Dynamax: {
|
|
||||||
label: 'D-Max',
|
|
||||||
color: 'bg-rose-100 text-rose-800 dark:bg-rose-900/40 dark:text-rose-300',
|
|
||||||
},
|
|
||||||
Terastallize: {
|
|
||||||
label: 'Tera',
|
|
||||||
color: 'bg-teal-100 text-teal-800 dark:bg-teal-900/40 dark:text-teal-300',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ConditionBadge({
|
export function ConditionBadge({
|
||||||
|
|||||||
@@ -77,13 +77,13 @@ export function EggEncounterModal({
|
|||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||||
<div className="fixed inset-0 bg-black/50" onClick={onClose} />
|
<div className="fixed inset-0 bg-black/50" onClick={onClose} />
|
||||||
<div className="relative bg-surface-1 rounded-xl shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto">
|
<div className="relative bg-surface-1 rounded-xl shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto">
|
||||||
<div className="sticky top-0 bg-surface-1 border-b border-green-300 dark:border-green-600 px-6 py-4 rounded-t-xl">
|
<div className="sticky top-0 bg-surface-1 border-b border-green-600 px-6 py-4 rounded-t-xl">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-lg font-semibold text-text-primary flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-text-primary flex items-center gap-2">
|
||||||
<span className="text-green-500">🥚</span>
|
<span className="text-green-500">🥚</span>
|
||||||
Log Egg Hatch
|
Log Egg Hatch
|
||||||
</h2>
|
</h2>
|
||||||
<button onClick={onClose} className="text-gray-400 hover:text-text-primary">
|
<button onClick={onClose} className="text-text-tertiary hover:text-text-primary">
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
@@ -123,7 +123,7 @@ export function EggEncounterModal({
|
|||||||
<div>
|
<div>
|
||||||
<label className="block text-sm font-medium text-text-secondary mb-1">Pokemon</label>
|
<label className="block text-sm font-medium text-text-secondary mb-1">Pokemon</label>
|
||||||
{selectedPokemon ? (
|
{selectedPokemon ? (
|
||||||
<div className="flex items-center gap-3 p-3 rounded-lg border border-green-300 dark:border-green-600 bg-green-50 dark:bg-green-900/20">
|
<div className="flex items-center gap-3 p-3 rounded-lg border border-green-600 bg-green-900/20">
|
||||||
{selectedPokemon.spriteUrl ? (
|
{selectedPokemon.spriteUrl ? (
|
||||||
<img
|
<img
|
||||||
src={selectedPokemon.spriteUrl}
|
src={selectedPokemon.spriteUrl}
|
||||||
@@ -144,7 +144,7 @@ export function EggEncounterModal({
|
|||||||
setSearch('')
|
setSearch('')
|
||||||
setSearchResults([])
|
setSearchResults([])
|
||||||
}}
|
}}
|
||||||
className="ml-auto text-sm text-gray-500 hover:text-text-secondary"
|
className="ml-auto text-sm text-text-tertiary hover:text-text-secondary"
|
||||||
>
|
>
|
||||||
Change
|
Change
|
||||||
</button>
|
</button>
|
||||||
@@ -170,7 +170,7 @@ export function EggEncounterModal({
|
|||||||
key={p.id}
|
key={p.id}
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setSelectedPokemon(p)}
|
onClick={() => setSelectedPokemon(p)}
|
||||||
className="flex flex-col items-center p-2 rounded-lg border border-border-default hover:border-green-400 dark:hover:border-green-600 text-center transition-colors"
|
className="flex flex-col items-center p-2 rounded-lg border border-border-default hover:border-green-600 text-center transition-colors"
|
||||||
>
|
>
|
||||||
{p.spriteUrl ? (
|
{p.spriteUrl ? (
|
||||||
<img src={p.spriteUrl} alt={p.name} className="w-10 h-10" />
|
<img src={p.spriteUrl} alt={p.name} className="w-10 h-10" />
|
||||||
|
|||||||
@@ -1,56 +1,17 @@
|
|||||||
export const METHOD_CONFIG: Record<string, { label: string; color: string }> = {
|
export const METHOD_CONFIG: Record<string, { label: string; color: string }> = {
|
||||||
starter: {
|
starter: { label: 'Starter', color: 'bg-yellow-900/40 text-yellow-300' },
|
||||||
label: 'Starter',
|
gift: { label: 'Gift', color: 'bg-pink-900/40 text-pink-300' },
|
||||||
color: 'bg-yellow-100 text-yellow-800 dark:bg-yellow-900/40 dark:text-yellow-300',
|
fossil: { label: 'Fossil', color: 'bg-amber-900/40 text-amber-300' },
|
||||||
},
|
trade: { label: 'Trade', color: 'bg-emerald-900/40 text-emerald-300' },
|
||||||
gift: {
|
walk: { label: 'Grass', color: 'bg-green-900/40 text-green-300' },
|
||||||
label: 'Gift',
|
headbutt: { label: 'Headbutt', color: 'bg-lime-900/40 text-lime-300' },
|
||||||
color: 'bg-pink-100 text-pink-800 dark:bg-pink-900/40 dark:text-pink-300',
|
surf: { label: 'Surfing', color: 'bg-blue-900/40 text-blue-300' },
|
||||||
},
|
'rock-smash': { label: 'Rock Smash', color: 'bg-orange-900/40 text-orange-300' },
|
||||||
fossil: {
|
'old-rod': { label: 'Old Rod', color: 'bg-cyan-900/40 text-cyan-300' },
|
||||||
label: 'Fossil',
|
'good-rod': { label: 'Good Rod', color: 'bg-sky-900/40 text-sky-300' },
|
||||||
color: 'bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300',
|
'super-rod': { label: 'Super Rod', color: 'bg-indigo-900/40 text-indigo-300' },
|
||||||
},
|
horde: { label: 'Horde', color: 'bg-rose-900/40 text-rose-300' },
|
||||||
trade: {
|
sos: { label: 'SOS', color: 'bg-violet-900/40 text-violet-300' },
|
||||||
label: 'Trade',
|
|
||||||
color: 'bg-emerald-100 text-emerald-800 dark:bg-emerald-900/40 dark:text-emerald-300',
|
|
||||||
},
|
|
||||||
walk: {
|
|
||||||
label: 'Grass',
|
|
||||||
color: 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300',
|
|
||||||
},
|
|
||||||
headbutt: {
|
|
||||||
label: 'Headbutt',
|
|
||||||
color: 'bg-lime-100 text-lime-800 dark:bg-lime-900/40 dark:text-lime-300',
|
|
||||||
},
|
|
||||||
surf: {
|
|
||||||
label: 'Surfing',
|
|
||||||
color: 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300',
|
|
||||||
},
|
|
||||||
'rock-smash': {
|
|
||||||
label: 'Rock Smash',
|
|
||||||
color: 'bg-orange-100 text-orange-800 dark:bg-orange-900/40 dark:text-orange-300',
|
|
||||||
},
|
|
||||||
'old-rod': {
|
|
||||||
label: 'Old Rod',
|
|
||||||
color: 'bg-cyan-100 text-cyan-800 dark:bg-cyan-900/40 dark:text-cyan-300',
|
|
||||||
},
|
|
||||||
'good-rod': {
|
|
||||||
label: 'Good Rod',
|
|
||||||
color: 'bg-sky-100 text-sky-800 dark:bg-sky-900/40 dark:text-sky-300',
|
|
||||||
},
|
|
||||||
'super-rod': {
|
|
||||||
label: 'Super Rod',
|
|
||||||
color: 'bg-indigo-100 text-indigo-800 dark:bg-indigo-900/40 dark:text-indigo-300',
|
|
||||||
},
|
|
||||||
horde: {
|
|
||||||
label: 'Horde',
|
|
||||||
color: 'bg-rose-100 text-rose-800 dark:bg-rose-900/40 dark:text-rose-300',
|
|
||||||
},
|
|
||||||
sos: {
|
|
||||||
label: 'SOS',
|
|
||||||
color: 'bg-violet-100 text-violet-800 dark:bg-violet-900/40 dark:text-violet-300',
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Display order for encounter method groups */
|
/** Display order for encounter method groups */
|
||||||
@@ -78,9 +39,7 @@ export function getMethodLabel(method: string): string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function getMethodColor(method: string): string {
|
export function getMethodColor(method: string): string {
|
||||||
return (
|
return METHOD_CONFIG[method]?.color ?? 'bg-surface-3 text-text-secondary'
|
||||||
METHOD_CONFIG[method]?.color ?? 'bg-gray-100 text-gray-800 dark:bg-gray-700 dark:text-gray-300'
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function EncounterMethodBadge({
|
export function EncounterMethodBadge({
|
||||||
|
|||||||
@@ -43,14 +43,12 @@ const statusOptions: {
|
|||||||
{
|
{
|
||||||
value: 'caught',
|
value: 'caught',
|
||||||
label: 'Caught',
|
label: 'Caught',
|
||||||
color:
|
color: 'bg-green-900/40 text-green-300 border-green-700',
|
||||||
'bg-green-100 text-green-800 border-green-300 dark:bg-green-900/40 dark:text-green-300 dark:border-green-700',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'fainted',
|
value: 'fainted',
|
||||||
label: 'Fainted',
|
label: 'Fainted',
|
||||||
color:
|
color: 'bg-red-900/40 text-red-300 border-red-700',
|
||||||
'bg-red-100 text-red-800 border-red-300 dark:bg-red-900/40 dark:text-red-300 dark:border-red-700',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
value: 'missed',
|
value: 'missed',
|
||||||
@@ -266,7 +264,7 @@ export function EncounterModal({
|
|||||||
<h2 className="text-lg font-semibold text-text-primary">
|
<h2 className="text-lg font-semibold text-text-primary">
|
||||||
{isEditing ? 'Edit Encounter' : 'Log Encounter'}
|
{isEditing ? 'Edit Encounter' : 'Log Encounter'}
|
||||||
</h2>
|
</h2>
|
||||||
<button onClick={onClose} className="text-gray-400 hover:text-text-primary">
|
<button onClick={onClose} className="text-text-tertiary hover:text-text-primary">
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
@@ -301,7 +299,7 @@ export function EncounterModal({
|
|||||||
setSelectedPokemon(pickRandomPokemon(routePokemon, dupedPokemonIds))
|
setSelectedPokemon(pickRandomPokemon(routePokemon, dupedPokemonIds))
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="px-2.5 py-1 text-xs font-medium rounded-lg border border-purple-300 dark:border-purple-600 text-purple-600 dark:text-purple-400 hover:bg-purple-50 dark:hover:bg-purple-900/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
className="px-2.5 py-1 text-xs font-medium rounded-lg border border-purple-600 text-purple-400 hover:bg-purple-900/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||||
>
|
>
|
||||||
{selectedPokemon ? 'Re-roll' : 'Randomize'}
|
{selectedPokemon ? 'Re-roll' : 'Randomize'}
|
||||||
</button>
|
</button>
|
||||||
@@ -309,7 +307,7 @@ export function EncounterModal({
|
|||||||
</div>
|
</div>
|
||||||
{loadingPokemon ? (
|
{loadingPokemon ? (
|
||||||
<div className="flex items-center justify-center py-4">
|
<div className="flex items-center justify-center py-4">
|
||||||
<div className="w-10 h-10 border-2 border-blue-600 border-t-transparent rounded-full animate-spin" />
|
<div className="w-10 h-10 border-2 border-accent-400 border-t-transparent rounded-full animate-spin" />
|
||||||
</div>
|
</div>
|
||||||
) : filteredPokemon && filteredPokemon.length > 0 ? (
|
) : filteredPokemon && filteredPokemon.length > 0 ? (
|
||||||
<>
|
<>
|
||||||
@@ -329,8 +327,8 @@ export function EncounterModal({
|
|||||||
onClick={() => setSelectedCondition(null)}
|
onClick={() => setSelectedCondition(null)}
|
||||||
className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors ${
|
className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors ${
|
||||||
selectedCondition === null
|
selectedCondition === null
|
||||||
? 'bg-purple-100 border-purple-300 text-purple-800 dark:bg-purple-900/40 dark:border-purple-600 dark:text-purple-300'
|
? 'bg-purple-900/40 border-purple-600 text-purple-300'
|
||||||
: 'border-border-default text-text-tertiary hover:border-purple-300 dark:hover:border-purple-600'
|
: 'border-border-default text-text-tertiary hover:border-purple-600'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
All
|
All
|
||||||
@@ -342,8 +340,8 @@ export function EncounterModal({
|
|||||||
onClick={() => setSelectedCondition(cond)}
|
onClick={() => setSelectedCondition(cond)}
|
||||||
className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors capitalize ${
|
className={`px-2.5 py-1 text-xs font-medium rounded-full border transition-colors capitalize ${
|
||||||
selectedCondition === cond
|
selectedCondition === cond
|
||||||
? 'bg-purple-100 border-purple-300 text-purple-800 dark:bg-purple-900/40 dark:border-purple-600 dark:text-purple-300'
|
? 'bg-purple-900/40 border-purple-600 text-purple-300'
|
||||||
: 'border-border-default text-text-tertiary hover:border-purple-300 dark:hover:border-purple-600'
|
: 'border-border-default text-text-tertiary hover:border-purple-600'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{cond}
|
{cond}
|
||||||
@@ -376,7 +374,7 @@ export function EncounterModal({
|
|||||||
isDuped
|
isDuped
|
||||||
? 'opacity-40 cursor-not-allowed border-border-default'
|
? 'opacity-40 cursor-not-allowed border-border-default'
|
||||||
: isSelected
|
: isSelected
|
||||||
? 'border-blue-500 bg-blue-50 dark:bg-blue-900/30'
|
? 'border-accent-400 bg-accent-900/30'
|
||||||
: 'border-border-default hover:border-border-default'
|
: 'border-border-default hover:border-border-default'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -395,7 +393,7 @@ export function EncounterModal({
|
|||||||
{rp.pokemon.name}
|
{rp.pokemon.name}
|
||||||
</span>
|
</span>
|
||||||
{isDuped && (
|
{isDuped && (
|
||||||
<span className="text-[10px] text-gray-400 italic">
|
<span className="text-[10px] text-text-tertiary italic">
|
||||||
{retiredPokemonIds?.has(rp.pokemonId)
|
{retiredPokemonIds?.has(rp.pokemonId)
|
||||||
? 'retired (HoF)'
|
? 'retired (HoF)'
|
||||||
: 'already caught'}
|
: 'already caught'}
|
||||||
@@ -405,19 +403,19 @@ export function EncounterModal({
|
|||||||
<EncounterMethodBadge method={rp.encounterMethod} />
|
<EncounterMethodBadge method={rp.encounterMethod} />
|
||||||
)}
|
)}
|
||||||
{!isDuped && displayRate !== null && displayRate !== undefined && (
|
{!isDuped && displayRate !== null && displayRate !== undefined && (
|
||||||
<span className="text-[10px] text-purple-500 dark:text-purple-400 font-medium">
|
<span className="text-[10px] text-purple-400 font-medium">
|
||||||
{displayRate}%
|
{displayRate}%
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!isDuped &&
|
{!isDuped &&
|
||||||
selectedCondition === null &&
|
selectedCondition === null &&
|
||||||
conditions.length > 0 && (
|
conditions.length > 0 && (
|
||||||
<span className="text-[10px] text-purple-500 dark:text-purple-400">
|
<span className="text-[10px] text-purple-400">
|
||||||
{conditions.join(', ')}
|
{conditions.join(', ')}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{!isDuped && (
|
{!isDuped && (
|
||||||
<span className="text-[10px] text-gray-400">
|
<span className="text-[10px] text-text-tertiary">
|
||||||
Lv. {rp.minLevel}
|
Lv. {rp.minLevel}
|
||||||
{rp.maxLevel !== rp.minLevel && `–${rp.maxLevel}`}
|
{rp.maxLevel !== rp.minLevel && `–${rp.maxLevel}`}
|
||||||
</span>
|
</span>
|
||||||
@@ -454,7 +452,7 @@ export function EncounterModal({
|
|||||||
<div className="font-medium text-text-primary capitalize">
|
<div className="font-medium text-text-primary capitalize">
|
||||||
{existing.pokemon.name}
|
{existing.pokemon.name}
|
||||||
</div>
|
</div>
|
||||||
<div className="text-xs text-gray-500">
|
<div className="text-xs text-text-tertiary">
|
||||||
Caught at Lv. {existing.catchLevel ?? '?'}
|
Caught at Lv. {existing.catchLevel ?? '?'}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -473,7 +471,7 @@ export function EncounterModal({
|
|||||||
className={`flex-1 px-3 py-2 rounded-lg border text-sm font-medium transition-colors ${
|
className={`flex-1 px-3 py-2 rounded-lg border text-sm font-medium transition-colors ${
|
||||||
status === opt.value
|
status === opt.value
|
||||||
? opt.color
|
? opt.color
|
||||||
: 'border-border-default text-text-tertiary hover:border-gray-300'
|
: 'border-border-default text-text-tertiary hover:border-border-accent'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{opt.label}
|
{opt.label}
|
||||||
@@ -507,7 +505,7 @@ export function EncounterModal({
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={() => regenerate()}
|
onClick={() => regenerate()}
|
||||||
disabled={loadingSuggestions}
|
disabled={loadingSuggestions}
|
||||||
className="text-xs text-text-link hover:text-blue-700 dark:hover:text-blue-300 disabled:opacity-50 transition-colors"
|
className="text-xs text-text-link hover:text-accent-300 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
{loadingSuggestions ? 'Loading...' : 'Regenerate'}
|
{loadingSuggestions ? 'Loading...' : 'Regenerate'}
|
||||||
</button>
|
</button>
|
||||||
@@ -520,8 +518,8 @@ export function EncounterModal({
|
|||||||
onClick={() => setNickname(name)}
|
onClick={() => setNickname(name)}
|
||||||
className={`px-2.5 py-1 text-xs rounded-full border transition-colors ${
|
className={`px-2.5 py-1 text-xs rounded-full border transition-colors ${
|
||||||
nickname === name
|
nickname === name
|
||||||
? 'bg-blue-100 border-blue-300 text-blue-800 dark:bg-blue-900/40 dark:border-blue-600 dark:text-blue-300'
|
? 'bg-accent-900/40 border-accent-600 text-accent-300'
|
||||||
: 'border-border-default text-text-secondary hover:border-blue-300 dark:hover:border-blue-600 hover:bg-blue-50 dark:hover:bg-blue-900/20'
|
: 'border-border-default text-text-secondary hover:border-accent-600 hover:bg-accent-900/20'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{name}
|
{name}
|
||||||
@@ -567,7 +565,7 @@ export function EncounterModal({
|
|||||||
htmlFor="faint-level"
|
htmlFor="faint-level"
|
||||||
className="block text-sm font-medium text-text-secondary mb-1"
|
className="block text-sm font-medium text-text-secondary mb-1"
|
||||||
>
|
>
|
||||||
Faint Level <span className="font-normal text-gray-400">(mark as dead)</span>
|
Faint Level <span className="font-normal text-text-tertiary">(mark as dead)</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="faint-level"
|
id="faint-level"
|
||||||
@@ -585,7 +583,7 @@ export function EncounterModal({
|
|||||||
htmlFor="death-cause"
|
htmlFor="death-cause"
|
||||||
className="block text-sm font-medium text-text-secondary mb-1"
|
className="block text-sm font-medium text-text-secondary mb-1"
|
||||||
>
|
>
|
||||||
Cause of Death <span className="font-normal text-gray-400">(optional)</span>
|
Cause of Death <span className="font-normal text-text-tertiary">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="death-cause"
|
id="death-cause"
|
||||||
@@ -613,7 +611,7 @@ export function EncounterModal({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={!canSubmit || isPending}
|
disabled={!canSubmit || isPending}
|
||||||
onClick={handleSubmit}
|
onClick={handleSubmit}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
className="px-4 py-2 bg-accent-600 text-white rounded-lg font-medium hover:bg-accent-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||||
>
|
>
|
||||||
{isPending ? 'Saving...' : isEditing ? 'Update' : 'Log Encounter'}
|
{isPending ? 'Saving...' : isEditing ? 'Update' : 'Log Encounter'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ export function EndRunModal({ onConfirm, onClose, isPending, genlockeContext }:
|
|||||||
<button
|
<button
|
||||||
onClick={() => onConfirm('completed')}
|
onClick={() => onConfirm('completed')}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
className="w-full px-4 py-3 rounded-lg font-medium text-left border-2 border-blue-200 dark:border-blue-800 bg-blue-50 dark:bg-blue-900/20 text-blue-700 dark:text-blue-300 hover:border-blue-400 dark:hover:border-blue-600 disabled:opacity-50 transition-colors"
|
className="w-full px-4 py-3 rounded-lg font-medium text-left border-2 border-blue-800 bg-blue-900/20 text-blue-300 hover:border-blue-600 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="font-semibold">Victory</div>
|
<div className="font-semibold">Victory</div>
|
||||||
<div className="text-sm opacity-80">{victoryDescription}</div>
|
<div className="text-sm opacity-80">{victoryDescription}</div>
|
||||||
@@ -39,7 +39,7 @@ export function EndRunModal({ onConfirm, onClose, isPending, genlockeContext }:
|
|||||||
<button
|
<button
|
||||||
onClick={() => onConfirm('failed')}
|
onClick={() => onConfirm('failed')}
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
className="w-full px-4 py-3 rounded-lg font-medium text-left border-2 border-red-200 dark:border-red-800 bg-status-failed-bg text-red-700 dark:text-red-300 hover:border-red-400 dark:hover:border-red-600 disabled:opacity-50 transition-colors"
|
className="w-full px-4 py-3 rounded-lg font-medium text-left border-2 border-red-800 bg-status-failed-bg text-red-300 hover:border-red-600 disabled:opacity-50 transition-colors"
|
||||||
>
|
>
|
||||||
<div className="font-semibold">Defeat</div>
|
<div className="font-semibold">Defeat</div>
|
||||||
<div className="text-sm opacity-80">{defeatDescription}</div>
|
<div className="text-sm opacity-80">{defeatDescription}</div>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function GameCard({ game, selected, onSelect }: GameCardProps) {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => onSelect(game)}
|
onClick={() => onSelect(game)}
|
||||||
className={`relative w-full rounded-lg overflow-hidden transition-all duration-200 hover:scale-105 hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2 dark:focus:ring-offset-gray-900 ${
|
className={`relative w-full rounded-lg overflow-hidden transition-all duration-200 hover:scale-105 hover:shadow-lg focus:outline-none focus:ring-2 focus:ring-accent-400 focus:ring-offset-2 focus:ring-offset-surface-0 ${
|
||||||
selected ? 'ring-2 ring-accent-500 scale-105 shadow-lg' : 'shadow'
|
selected ? 'ring-2 ring-accent-500 scale-105 shadow-lg' : 'shadow'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ function GraveyardCard({ entry }: { entry: GraveyardEntry }) {
|
|||||||
|
|
||||||
<div className="text-xs text-text-muted mt-0.5">{entry.routeName}</div>
|
<div className="text-xs text-text-muted mt-0.5">{entry.routeName}</div>
|
||||||
|
|
||||||
<div className="text-[10px] text-purple-600 dark:text-purple-400 mt-0.5 font-medium">
|
<div className="text-[10px] text-purple-400 mt-0.5 font-medium">
|
||||||
Leg {entry.legOrder} — {entry.gameName}
|
Leg {entry.legOrder} — {entry.gameName}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ function LegDot({ leg }: { leg: LineageLegEntry }) {
|
|||||||
return (
|
return (
|
||||||
<div className="group relative flex flex-col items-center">
|
<div className="group relative flex flex-col items-center">
|
||||||
<div
|
<div
|
||||||
className={`w-4 h-4 rounded-full ${color} ring-2 ring-offset-1 ring-offset-white dark:ring-offset-gray-800 ring-gray-200 dark:ring-gray-600`}
|
className={`w-4 h-4 rounded-full ${color} ring-2 ring-offset-1 ring-offset-surface-1 ring-border-default`}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/* Tooltip */}
|
{/* Tooltip */}
|
||||||
@@ -156,8 +156,8 @@ function LineageCard({ lineage, allLegOrders }: { lineage: LineageEntry; allLegO
|
|||||||
<span
|
<span
|
||||||
className={`px-2.5 py-1 rounded-full text-xs font-medium ${
|
className={`px-2.5 py-1 rounded-full text-xs font-medium ${
|
||||||
lineage.status === 'alive'
|
lineage.status === 'alive'
|
||||||
? 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300'
|
? 'bg-green-900/40 text-green-300'
|
||||||
: 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300'
|
: 'bg-red-900/40 text-red-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{lineage.status === 'alive' ? 'Alive' : 'Dead'}
|
{lineage.status === 'alive' ? 'Alive' : 'Dead'}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function HofTeamModal({ alive, onSubmit, onSkip, isPending }: HofTeamModa
|
|||||||
disabled={atMax}
|
disabled={atMax}
|
||||||
className={`flex flex-col items-center p-3 rounded-lg border-2 text-center transition-colors ${
|
className={`flex flex-col items-center p-3 rounded-lg border-2 text-center transition-colors ${
|
||||||
isSelected
|
isSelected
|
||||||
? 'border-yellow-500 bg-yellow-50 dark:bg-yellow-900/20'
|
? 'border-yellow-500 bg-yellow-900/20'
|
||||||
: atMax
|
: atMax
|
||||||
? 'border-border-default opacity-40 cursor-not-allowed'
|
? 'border-border-default opacity-40 cursor-not-allowed'
|
||||||
: 'border-border-default hover:border-border-default'
|
: 'border-border-default hover:border-border-default'
|
||||||
@@ -74,7 +74,7 @@ export function HofTeamModal({ alive, onSubmit, onSkip, isPending }: HofTeamModa
|
|||||||
{enc.nickname || displayPokemon.name}
|
{enc.nickname || displayPokemon.name}
|
||||||
</span>
|
</span>
|
||||||
{enc.nickname && (
|
{enc.nickname && (
|
||||||
<span className="text-[10px] text-gray-400">{displayPokemon.name}</span>
|
<span className="text-[10px] text-text-tertiary">{displayPokemon.name}</span>
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
@@ -97,7 +97,7 @@ export function HofTeamModal({ alive, onSubmit, onSkip, isPending }: HofTeamModa
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={selected.size === 0 || isPending}
|
disabled={selected.size === 0 || isPending}
|
||||||
onClick={() => onSubmit([...selected])}
|
onClick={() => onSubmit([...selected])}
|
||||||
className="px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
className="px-4 py-2 bg-accent-600 text-white rounded-lg font-medium hover:bg-accent-500 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
|
||||||
>
|
>
|
||||||
{isPending ? 'Saving...' : 'Confirm'}
|
{isPending ? 'Saving...' : 'Confirm'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ export function RuleBadges({ rules }: RuleBadgesProps) {
|
|||||||
title={def.description}
|
title={def.description}
|
||||||
className={`px-2 py-0.5 rounded-full text-xs font-medium ${
|
className={`px-2 py-0.5 rounded-full text-xs font-medium ${
|
||||||
def.category === 'core'
|
def.category === 'core'
|
||||||
? 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300'
|
? 'bg-blue-900/40 text-blue-300'
|
||||||
: def.category === 'completion'
|
: def.category === 'completion'
|
||||||
? 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300'
|
? 'bg-green-900/40 text-green-300'
|
||||||
: 'bg-amber-100 text-amber-800 dark:bg-amber-900/40 dark:text-amber-300'
|
: 'bg-amber-900/40 text-amber-300'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{def.name}
|
{def.name}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export function RuleToggle({ name, description, enabled, onChange }: RuleToggleP
|
|||||||
<span className="font-medium text-text-primary">{name}</span>
|
<span className="font-medium text-text-primary">{name}</span>
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="text-gray-400 hover:text-text-secondary"
|
className="text-text-tertiary hover:text-text-secondary"
|
||||||
onMouseEnter={() => setShowTooltip(true)}
|
onMouseEnter={() => setShowTooltip(true)}
|
||||||
onMouseLeave={() => setShowTooltip(false)}
|
onMouseLeave={() => setShowTooltip(false)}
|
||||||
onClick={() => setShowTooltip(!showTooltip)}
|
onClick={() => setShowTooltip(!showTooltip)}
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ export function RulesConfiguration({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleResetToDefault}
|
onClick={handleResetToDefault}
|
||||||
className="text-sm text-blue-600 hover:text-blue-700 dark:text-blue-400 dark:hover:text-blue-300"
|
className="text-sm text-text-link hover:text-accent-300"
|
||||||
>
|
>
|
||||||
Reset to Default
|
Reset to Default
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -8,8 +8,8 @@ interface ShinyBoxProps {
|
|||||||
|
|
||||||
export function ShinyBox({ encounters, onEncounterClick }: ShinyBoxProps) {
|
export function ShinyBox({ encounters, onEncounterClick }: ShinyBoxProps) {
|
||||||
return (
|
return (
|
||||||
<div className="border-2 border-yellow-400 dark:border-yellow-600 rounded-lg p-4">
|
<div className="border-2 border-yellow-600 rounded-lg p-4">
|
||||||
<h3 className="text-sm font-semibold text-yellow-600 dark:text-yellow-400 mb-3 flex items-center gap-1.5">
|
<h3 className="text-sm font-semibold text-yellow-400 mb-3 flex items-center gap-1.5">
|
||||||
<span>✦</span>
|
<span>✦</span>
|
||||||
Shiny Box
|
Shiny Box
|
||||||
<span className="text-xs font-normal text-text-muted ml-1">
|
<span className="text-xs font-normal text-text-muted ml-1">
|
||||||
|
|||||||
@@ -93,13 +93,13 @@ export function ShinyEncounterModal({
|
|||||||
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
<div className="fixed inset-0 z-50 flex items-center justify-center p-4">
|
||||||
<div className="fixed inset-0 bg-black/50" onClick={onClose} />
|
<div className="fixed inset-0 bg-black/50" onClick={onClose} />
|
||||||
<div className="relative bg-surface-1 rounded-xl shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto">
|
<div className="relative bg-surface-1 rounded-xl shadow-xl max-w-lg w-full max-h-[90vh] overflow-y-auto">
|
||||||
<div className="sticky top-0 bg-surface-1 border-b border-yellow-300 dark:border-yellow-600 px-6 py-4 rounded-t-xl">
|
<div className="sticky top-0 bg-surface-1 border-b border-yellow-600 px-6 py-4 rounded-t-xl">
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
<h2 className="text-lg font-semibold text-text-primary flex items-center gap-2">
|
<h2 className="text-lg font-semibold text-text-primary flex items-center gap-2">
|
||||||
<span className="text-yellow-500">✦</span>
|
<span className="text-yellow-500">✦</span>
|
||||||
Log Shiny Encounter
|
Log Shiny Encounter
|
||||||
</h2>
|
</h2>
|
||||||
<button onClick={onClose} className="text-gray-400 hover:text-text-primary">
|
<button onClick={onClose} className="text-text-tertiary hover:text-text-primary">
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
@@ -110,7 +110,7 @@ export function ShinyEncounterModal({
|
|||||||
</svg>
|
</svg>
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<p className="text-sm text-yellow-600 dark:text-yellow-400 mt-1">
|
<p className="text-sm text-yellow-400 mt-1">
|
||||||
Shiny catches bypass the one-per-route rule
|
Shiny catches bypass the one-per-route rule
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -169,7 +169,7 @@ export function ShinyEncounterModal({
|
|||||||
onClick={() => setSelectedPokemon(rp)}
|
onClick={() => setSelectedPokemon(rp)}
|
||||||
className={`flex flex-col items-center p-2 rounded-lg border text-center transition-colors ${
|
className={`flex flex-col items-center p-2 rounded-lg border text-center transition-colors ${
|
||||||
selectedPokemon?.id === rp.id
|
selectedPokemon?.id === rp.id
|
||||||
? 'border-yellow-500 bg-yellow-50 dark:bg-yellow-900/30'
|
? 'border-yellow-500 bg-yellow-900/30'
|
||||||
: 'border-border-default hover:border-border-default'
|
: 'border-border-default hover:border-border-default'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -190,7 +190,7 @@ export function ShinyEncounterModal({
|
|||||||
{SPECIAL_METHODS.includes(rp.encounterMethod) && (
|
{SPECIAL_METHODS.includes(rp.encounterMethod) && (
|
||||||
<EncounterMethodBadge method={rp.encounterMethod} />
|
<EncounterMethodBadge method={rp.encounterMethod} />
|
||||||
)}
|
)}
|
||||||
<span className="text-[10px] text-gray-400">
|
<span className="text-[10px] text-text-tertiary">
|
||||||
Lv. {rp.minLevel}
|
Lv. {rp.minLevel}
|
||||||
{rp.maxLevel !== rp.minLevel && `–${rp.maxLevel}`}
|
{rp.maxLevel !== rp.minLevel && `–${rp.maxLevel}`}
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -97,7 +97,7 @@ export function StatusChangeModal({
|
|||||||
<h2 className="text-lg font-semibold text-text-primary">
|
<h2 className="text-lg font-semibold text-text-primary">
|
||||||
{isDead ? 'Death Details' : 'Pokemon Status'}
|
{isDead ? 'Death Details' : 'Pokemon Status'}
|
||||||
</h2>
|
</h2>
|
||||||
<button onClick={onClose} className="text-gray-400 hover:text-text-primary">
|
<button onClick={onClose} className="text-text-tertiary hover:text-text-primary">
|
||||||
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
<svg className="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
||||||
<path
|
<path
|
||||||
strokeLinecap="round"
|
strokeLinecap="round"
|
||||||
@@ -170,7 +170,7 @@ export function StatusChangeModal({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowEvolve(true)}
|
onClick={() => setShowEvolve(true)}
|
||||||
className="flex-1 px-4 py-2 bg-blue-600 text-white rounded-lg font-medium hover:bg-blue-700 transition-colors"
|
className="flex-1 px-4 py-2 bg-accent-600 text-white rounded-lg font-medium hover:bg-accent-500 transition-colors"
|
||||||
>
|
>
|
||||||
Evolve
|
Evolve
|
||||||
</button>
|
</button>
|
||||||
@@ -201,7 +201,7 @@ export function StatusChangeModal({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowEvolve(false)}
|
onClick={() => setShowEvolve(false)}
|
||||||
className="text-xs text-gray-500 hover:text-text-secondary"
|
className="text-xs text-text-tertiary hover:text-text-secondary"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
@@ -220,7 +220,7 @@ export function StatusChangeModal({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
onClick={() => handleEvolve(evo.toPokemon.id)}
|
onClick={() => handleEvolve(evo.toPokemon.id)}
|
||||||
className="w-full flex items-center gap-3 p-3 rounded-lg border border-border-default hover:bg-blue-50 dark:hover:bg-blue-900/20 hover:border-blue-300 dark:hover:border-blue-600 transition-colors disabled:opacity-50"
|
className="w-full flex items-center gap-3 p-3 rounded-lg border border-border-default hover:bg-accent-900/20 hover:border-accent-600 transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{evo.toPokemon.spriteUrl ? (
|
{evo.toPokemon.spriteUrl ? (
|
||||||
<img
|
<img
|
||||||
@@ -261,12 +261,12 @@ export function StatusChangeModal({
|
|||||||
setShedNickname('')
|
setShedNickname('')
|
||||||
setShowEvolve(true)
|
setShowEvolve(true)
|
||||||
}}
|
}}
|
||||||
className="text-xs text-gray-500 hover:text-text-secondary"
|
className="text-xs text-text-tertiary hover:text-text-secondary"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div className="bg-amber-50 dark:bg-amber-900/20 border border-amber-200 dark:border-amber-700 rounded-lg p-3">
|
<div className="bg-amber-900/20 border border-amber-700 rounded-lg p-3">
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{shedCompanion.toPokemon.spriteUrl ? (
|
{shedCompanion.toPokemon.spriteUrl ? (
|
||||||
<img
|
<img
|
||||||
@@ -279,7 +279,7 @@ export function StatusChangeModal({
|
|||||||
{shedCompanion.toPokemon.name[0]?.toUpperCase()}
|
{shedCompanion.toPokemon.name[0]?.toUpperCase()}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
<p className="text-sm text-amber-800 dark:text-amber-300">
|
<p className="text-sm text-amber-300">
|
||||||
{displayPokemon.name} shed its shell! Would you also like to add{' '}
|
{displayPokemon.name} shed its shell! Would you also like to add{' '}
|
||||||
<span className="font-semibold">{shedCompanion.toPokemon.name}</span>?
|
<span className="font-semibold">{shedCompanion.toPokemon.name}</span>?
|
||||||
</p>
|
</p>
|
||||||
@@ -290,7 +290,7 @@ export function StatusChangeModal({
|
|||||||
htmlFor="shed-nickname"
|
htmlFor="shed-nickname"
|
||||||
className="block text-sm font-medium text-text-secondary mb-1"
|
className="block text-sm font-medium text-text-secondary mb-1"
|
||||||
>
|
>
|
||||||
Nickname <span className="font-normal text-gray-400">(optional)</span>
|
Nickname <span className="font-normal text-text-tertiary">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="shed-nickname"
|
id="shed-nickname"
|
||||||
@@ -331,7 +331,7 @@ export function StatusChangeModal({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowFormChange(false)}
|
onClick={() => setShowFormChange(false)}
|
||||||
className="text-xs text-gray-500 hover:text-text-secondary"
|
className="text-xs text-text-tertiary hover:text-text-secondary"
|
||||||
>
|
>
|
||||||
Back
|
Back
|
||||||
</button>
|
</button>
|
||||||
@@ -344,7 +344,7 @@ export function StatusChangeModal({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={isPending}
|
disabled={isPending}
|
||||||
onClick={() => handleEvolve(form.id)}
|
onClick={() => handleEvolve(form.id)}
|
||||||
className="w-full flex items-center gap-3 p-3 rounded-lg border border-border-default hover:bg-purple-50 dark:hover:bg-purple-900/20 hover:border-purple-300 dark:hover:border-purple-600 transition-colors disabled:opacity-50"
|
className="w-full flex items-center gap-3 p-3 rounded-lg border border-border-default hover:bg-purple-900/20 hover:border-purple-600 transition-colors disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{form.spriteUrl ? (
|
{form.spriteUrl ? (
|
||||||
<img src={form.spriteUrl} alt={form.name} className="w-10 h-10" />
|
<img src={form.spriteUrl} alt={form.name} className="w-10 h-10" />
|
||||||
@@ -382,7 +382,7 @@ export function StatusChangeModal({
|
|||||||
htmlFor="death-level"
|
htmlFor="death-level"
|
||||||
className="block text-sm font-medium text-text-secondary mb-1"
|
className="block text-sm font-medium text-text-secondary mb-1"
|
||||||
>
|
>
|
||||||
Level at Death <span className="font-normal text-gray-400">(optional)</span>
|
Level at Death <span className="font-normal text-text-tertiary">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="death-level"
|
id="death-level"
|
||||||
@@ -401,7 +401,7 @@ export function StatusChangeModal({
|
|||||||
htmlFor="death-cause"
|
htmlFor="death-cause"
|
||||||
className="block text-sm font-medium text-text-secondary mb-1"
|
className="block text-sm font-medium text-text-secondary mb-1"
|
||||||
>
|
>
|
||||||
Cause of Death <span className="font-normal text-gray-400">(optional)</span>
|
Cause of Death <span className="font-normal text-text-tertiary">(optional)</span>
|
||||||
</label>
|
</label>
|
||||||
<input
|
<input
|
||||||
id="death-cause"
|
id="death-cause"
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ export function StepIndicator({
|
|||||||
disabled={!isCompleted}
|
disabled={!isCompleted}
|
||||||
className={`flex items-center gap-2 text-sm font-medium ${
|
className={`flex items-center gap-2 text-sm font-medium ${
|
||||||
isCompleted
|
isCompleted
|
||||||
? 'text-text-link cursor-pointer hover:text-blue-700 dark:hover:text-blue-300'
|
? 'text-text-link cursor-pointer hover:text-accent-300'
|
||||||
: isCurrent
|
: isCurrent
|
||||||
? 'text-text-primary'
|
? 'text-text-primary'
|
||||||
: 'text-text-muted cursor-default'
|
: 'text-text-muted cursor-default'
|
||||||
@@ -38,7 +38,7 @@ export function StepIndicator({
|
|||||||
isCompleted
|
isCompleted
|
||||||
? 'bg-blue-600 text-white'
|
? 'bg-blue-600 text-white'
|
||||||
: isCurrent
|
: isCurrent
|
||||||
? 'border-2 border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400'
|
? 'border-2 border-accent-400 text-accent-400'
|
||||||
: 'border-2 border-border-default text-text-muted'
|
: 'border-2 border-border-default text-text-muted'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export function TransferModal({ hofTeam, onSubmit, onSkip, isPending }: Transfer
|
|||||||
onClick={() => toggle(enc.id)}
|
onClick={() => toggle(enc.id)}
|
||||||
className={`flex flex-col items-center p-3 rounded-lg border-2 text-center transition-colors ${
|
className={`flex flex-col items-center p-3 rounded-lg border-2 text-center transition-colors ${
|
||||||
isSelected
|
isSelected
|
||||||
? 'border-indigo-500 bg-indigo-50 dark:bg-indigo-900/20'
|
? 'border-indigo-500 bg-indigo-900/20'
|
||||||
: 'border-border-default hover:border-border-default'
|
: 'border-border-default hover:border-border-default'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -67,9 +67,9 @@ export function TransferModal({ hofTeam, onSubmit, onSkip, isPending }: Transfer
|
|||||||
{enc.nickname || displayPokemon.name}
|
{enc.nickname || displayPokemon.name}
|
||||||
</span>
|
</span>
|
||||||
{enc.nickname && (
|
{enc.nickname && (
|
||||||
<span className="text-[10px] text-gray-400">{displayPokemon.name}</span>
|
<span className="text-[10px] text-text-tertiary">{displayPokemon.name}</span>
|
||||||
)}
|
)}
|
||||||
<span className="text-[10px] text-gray-400 mt-0.5">{enc.route.name}</span>
|
<span className="text-[10px] text-text-tertiary mt-0.5">{enc.route.name}</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@@ -21,9 +21,7 @@ export function AdminLayout() {
|
|||||||
to={item.to}
|
to={item.to}
|
||||||
className={({ isActive }) =>
|
className={({ isActive }) =>
|
||||||
`block px-3 py-2 rounded-md text-sm font-medium whitespace-nowrap ${
|
`block px-3 py-2 rounded-md text-sm font-medium whitespace-nowrap ${
|
||||||
isActive
|
isActive ? 'bg-accent-900/40 text-accent-300' : 'hover:bg-surface-2'
|
||||||
? 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-200'
|
|
||||||
: 'hover:bg-surface-2'
|
|
||||||
}`
|
}`
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -175,7 +175,7 @@ export function BossTeamEditor({ boss, onSave, onClose, isSaving }: BossTeamEdit
|
|||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
removeVariant(i)
|
removeVariant(i)
|
||||||
}}
|
}}
|
||||||
className="ml-1.5 text-gray-400 hover:text-red-500 cursor-pointer"
|
className="ml-1.5 text-text-tertiary hover:text-red-500 cursor-pointer"
|
||||||
title="Remove variant"
|
title="Remove variant"
|
||||||
>
|
>
|
||||||
✕
|
✕
|
||||||
@@ -187,7 +187,7 @@ export function BossTeamEditor({ boss, onSave, onClose, isSaving }: BossTeamEdit
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowAddVariant(true)}
|
onClick={() => setShowAddVariant(true)}
|
||||||
className="px-2 py-1.5 text-sm text-text-link hover:text-blue-700 dark:hover:text-blue-300"
|
className="px-2 py-1.5 text-sm text-text-link hover:text-accent-300"
|
||||||
title="Add variant"
|
title="Add variant"
|
||||||
>
|
>
|
||||||
+
|
+
|
||||||
@@ -219,7 +219,7 @@ export function BossTeamEditor({ boss, onSave, onClose, isSaving }: BossTeamEdit
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowAddVariant(false)}
|
onClick={() => setShowAddVariant(false)}
|
||||||
className="px-1 py-1 text-sm text-gray-400"
|
className="px-1 py-1 text-sm text-text-tertiary"
|
||||||
>
|
>
|
||||||
✕
|
✕
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -77,7 +77,7 @@ export function BulkImportModal({
|
|||||||
)}
|
)}
|
||||||
|
|
||||||
{result && (
|
{result && (
|
||||||
<div className="p-3 bg-green-50 dark:bg-green-900/30 text-green-700 dark:text-green-300 rounded-md text-sm">
|
<div className="p-3 bg-green-900/30 text-green-300 rounded-md text-sm">
|
||||||
<p>
|
<p>
|
||||||
{createdLabel}: {result.created}, {updatedLabel}: {result.updated}
|
{createdLabel}: {result.created}, {updatedLabel}: {result.updated}
|
||||||
</p>
|
</p>
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export function FormModal({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onBlur={() => setConfirmingDelete(false)}
|
onBlur={() => setConfirmingDelete(false)}
|
||||||
className="px-4 py-2 text-sm font-medium rounded-md text-status-failed border border-red-300 dark:border-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 disabled:opacity-50"
|
className="px-4 py-2 text-sm font-medium rounded-md text-status-failed border border-red-600 hover:bg-red-900/20 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isDeleting ? 'Deleting...' : confirmingDelete ? 'Confirm?' : 'Delete'}
|
{isDeleting ? 'Deleting...' : confirmingDelete ? 'Confirm?' : 'Delete'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export function PokemonFormModal({
|
|||||||
const tabClass = (tab: Tab) =>
|
const tabClass = (tab: Tab) =>
|
||||||
`px-3 py-1.5 text-sm font-medium rounded-t-md border-b-2 transition-colors ${
|
`px-3 py-1.5 text-sm font-medium rounded-t-md border-b-2 transition-colors ${
|
||||||
activeTab === tab
|
activeTab === tab
|
||||||
? 'border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400'
|
? 'border-accent-400 text-accent-400'
|
||||||
: 'border-transparent text-text-tertiary hover:text-text-secondary'
|
: 'border-transparent text-text-tertiary hover:text-text-secondary'
|
||||||
}`
|
}`
|
||||||
|
|
||||||
@@ -184,7 +184,7 @@ export function PokemonFormModal({
|
|||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
onBlur={() => setConfirmingDelete(false)}
|
onBlur={() => setConfirmingDelete(false)}
|
||||||
className="px-4 py-2 text-sm font-medium rounded-md text-status-failed border border-red-300 dark:border-red-600 hover:bg-red-50 dark:hover:bg-red-900/20 disabled:opacity-50"
|
className="px-4 py-2 text-sm font-medium rounded-md text-status-failed border border-red-600 hover:bg-red-900/20 disabled:opacity-50"
|
||||||
>
|
>
|
||||||
{isDeleting ? 'Deleting...' : confirmingDelete ? 'Confirm?' : 'Delete'}
|
{isDeleting ? 'Deleting...' : confirmingDelete ? 'Confirm?' : 'Delete'}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ export function PokemonSelector({
|
|||||||
setOpen(false)
|
setOpen(false)
|
||||||
}}
|
}}
|
||||||
className={`px-3 py-2 cursor-pointer hover:bg-surface-2 text-sm flex items-center gap-2 ${
|
className={`px-3 py-2 cursor-pointer hover:bg-surface-2 text-sm flex items-center gap-2 ${
|
||||||
p.id === selectedId ? 'bg-blue-50 dark:bg-blue-900/30' : ''
|
p.id === selectedId ? 'bg-accent-900/30' : ''
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{p.spriteUrl && <img src={p.spriteUrl} alt="" className="w-6 h-6" />}
|
{p.spriteUrl && <img src={p.spriteUrl} alt="" className="w-6 h-6" />}
|
||||||
|
|||||||
@@ -18,9 +18,9 @@ const statusRing: Record<RunStatus, string> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const statusStyles: Record<RunStatus, string> = {
|
const statusStyles: Record<RunStatus, string> = {
|
||||||
active: 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300',
|
active: 'bg-green-900/40 text-green-300',
|
||||||
completed: 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300',
|
completed: 'bg-blue-900/40 text-blue-300',
|
||||||
failed: 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300',
|
failed: 'bg-red-900/40 text-red-300',
|
||||||
}
|
}
|
||||||
|
|
||||||
function LegIndicator({ leg }: { leg: GenlockeLegDetail }) {
|
function LegIndicator({ leg }: { leg: GenlockeLegDetail }) {
|
||||||
@@ -29,7 +29,7 @@ function LegIndicator({ leg }: { leg: GenlockeLegDetail }) {
|
|||||||
|
|
||||||
const dot = status ? (
|
const dot = status ? (
|
||||||
<div
|
<div
|
||||||
className={`w-4 h-4 rounded-full ${statusColors[status]} ring-2 ring-offset-2 ring-offset-white dark:ring-offset-gray-900 ${statusRing[status]}`}
|
className={`w-4 h-4 rounded-full ${statusColors[status]} ring-2 ring-offset-2 ring-offset-surface-0 ${statusRing[status]}`}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<div className="w-4 h-4 rounded-full bg-surface-3" />
|
<div className="w-4 h-4 rounded-full bg-surface-3" />
|
||||||
@@ -213,7 +213,7 @@ export function GenlockeDetail() {
|
|||||||
<h3 className="text-sm font-medium text-text-tertiary mb-2">Genlocke Rules</h3>
|
<h3 className="text-sm font-medium text-text-tertiary mb-2">Genlocke Rules</h3>
|
||||||
<div className="flex flex-wrap gap-1.5">
|
<div className="flex flex-wrap gap-1.5">
|
||||||
{genlocke.genlockeRules.retireHoF ? (
|
{genlocke.genlockeRules.retireHoF ? (
|
||||||
<span className="px-2 py-0.5 rounded-full text-xs font-medium bg-purple-100 text-purple-800 dark:bg-purple-900/40 dark:text-purple-300">
|
<span className="px-2 py-0.5 rounded-full text-xs font-medium bg-purple-900/40 text-purple-300">
|
||||||
Retire HoF Teams
|
Retire HoF Teams
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ import { useGenlockes } from '../hooks/useGenlockes'
|
|||||||
import type { RunStatus } from '../types'
|
import type { RunStatus } from '../types'
|
||||||
|
|
||||||
const statusStyles: Record<RunStatus, string> = {
|
const statusStyles: Record<RunStatus, string> = {
|
||||||
active: 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300',
|
active: 'bg-green-900/40 text-green-300',
|
||||||
completed: 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300',
|
completed: 'bg-blue-900/40 text-blue-300',
|
||||||
failed: 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300',
|
failed: 'bg-red-900/40 text-red-300',
|
||||||
}
|
}
|
||||||
|
|
||||||
export function GenlockeList() {
|
export function GenlockeList() {
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ export function NewGenlocke() {
|
|||||||
onClick={() => handlePresetSelect(type)}
|
onClick={() => handlePresetSelect(type)}
|
||||||
className={`flex-1 p-4 rounded-lg border-2 text-left transition-colors ${
|
className={`flex-1 p-4 rounded-lg border-2 text-left transition-colors ${
|
||||||
isActive
|
isActive
|
||||||
? 'border-blue-600 bg-blue-50 dark:bg-blue-900/20'
|
? 'border-accent-600 bg-accent-900/20'
|
||||||
: 'border-border-default hover:border-border-default'
|
: 'border-border-default hover:border-border-default'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -498,7 +498,7 @@ function LegRow({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={index === 0}
|
disabled={index === 0}
|
||||||
onClick={() => onMove('up')}
|
onClick={() => onMove('up')}
|
||||||
className="p-1 text-gray-400 hover:text-text-secondary disabled:opacity-30 disabled:cursor-not-allowed"
|
className="p-1 text-text-tertiary hover:text-text-secondary disabled:opacity-30 disabled:cursor-not-allowed"
|
||||||
title="Move up"
|
title="Move up"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@@ -515,7 +515,7 @@ function LegRow({
|
|||||||
type="button"
|
type="button"
|
||||||
disabled={index === total - 1}
|
disabled={index === total - 1}
|
||||||
onClick={() => onMove('down')}
|
onClick={() => onMove('down')}
|
||||||
className="p-1 text-gray-400 hover:text-text-secondary disabled:opacity-30 disabled:cursor-not-allowed"
|
className="p-1 text-text-tertiary hover:text-text-secondary disabled:opacity-30 disabled:cursor-not-allowed"
|
||||||
title="Move down"
|
title="Move down"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@@ -531,7 +531,7 @@ function LegRow({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={onRemove}
|
onClick={onRemove}
|
||||||
className="p-1 text-red-400 hover:text-red-600 dark:hover:text-red-300"
|
className="p-1 text-red-400 hover:text-red-300"
|
||||||
title="Remove leg"
|
title="Remove leg"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
@@ -563,7 +563,7 @@ function AddLegDropdown({
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setOpen(true)}
|
onClick={() => setOpen(true)}
|
||||||
className="flex items-center gap-2 text-sm text-text-link hover:text-blue-700 dark:hover:text-blue-300 font-medium"
|
className="flex items-center gap-2 text-sm text-text-link hover:text-accent-300 font-medium"
|
||||||
>
|
>
|
||||||
<svg
|
<svg
|
||||||
className="w-4 h-4"
|
className="w-4 h-4"
|
||||||
|
|||||||
@@ -31,9 +31,9 @@ function sortEncounters(encounters: EncounterDetail[], key: TeamSortKey): Encoun
|
|||||||
}
|
}
|
||||||
|
|
||||||
const statusStyles: Record<RunStatus, string> = {
|
const statusStyles: Record<RunStatus, string> = {
|
||||||
active: 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300',
|
active: 'bg-green-900/40 text-green-300',
|
||||||
completed: 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300',
|
completed: 'bg-blue-900/40 text-blue-300',
|
||||||
failed: 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300',
|
failed: 'bg-red-900/40 text-red-300',
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDuration(start: string, end: string) {
|
function formatDuration(start: string, end: string) {
|
||||||
@@ -136,8 +136,8 @@ export function RunDashboard() {
|
|||||||
<div
|
<div
|
||||||
className={`rounded-lg p-4 mb-6 ${
|
className={`rounded-lg p-4 mb-6 ${
|
||||||
run.status === 'completed'
|
run.status === 'completed'
|
||||||
? 'bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800'
|
? 'bg-blue-900/20 border border-blue-800'
|
||||||
: 'bg-status-failed-bg border border-red-200 dark:border-red-800'
|
: 'bg-status-failed-bg border border-red-800'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
@@ -147,9 +147,7 @@ export function RunDashboard() {
|
|||||||
<div>
|
<div>
|
||||||
<p
|
<p
|
||||||
className={`font-semibold ${
|
className={`font-semibold ${
|
||||||
run.status === 'completed'
|
run.status === 'completed' ? 'text-blue-200' : 'text-red-200'
|
||||||
? 'text-blue-800 dark:text-blue-200'
|
|
||||||
: 'text-red-800 dark:text-red-200'
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{run.status === 'completed' ? 'Victory!' : 'Defeat'}
|
{run.status === 'completed' ? 'Victory!' : 'Defeat'}
|
||||||
|
|||||||
@@ -59,9 +59,9 @@ function sortEncounters(encounters: EncounterDetail[], key: TeamSortKey): Encoun
|
|||||||
}
|
}
|
||||||
|
|
||||||
const statusStyles: Record<RunStatus, string> = {
|
const statusStyles: Record<RunStatus, string> = {
|
||||||
active: 'bg-green-100 text-green-800 dark:bg-green-900/40 dark:text-green-300',
|
active: 'bg-green-900/40 text-green-300',
|
||||||
completed: 'bg-blue-100 text-blue-800 dark:bg-blue-900/40 dark:text-blue-300',
|
completed: 'bg-blue-900/40 text-blue-300',
|
||||||
failed: 'bg-red-100 text-red-800 dark:bg-red-900/40 dark:text-red-300',
|
failed: 'bg-red-900/40 text-red-300',
|
||||||
}
|
}
|
||||||
|
|
||||||
function formatDuration(start: string, end: string) {
|
function formatDuration(start: string, end: string) {
|
||||||
@@ -83,12 +83,12 @@ const statusIndicator: Record<RouteStatus, { dot: string; label: string; bg: str
|
|||||||
caught: {
|
caught: {
|
||||||
dot: 'bg-green-500',
|
dot: 'bg-green-500',
|
||||||
label: 'Caught',
|
label: 'Caught',
|
||||||
bg: 'bg-green-50 dark:bg-green-900/10',
|
bg: 'bg-green-900/10',
|
||||||
},
|
},
|
||||||
fainted: {
|
fainted: {
|
||||||
dot: 'bg-red-500',
|
dot: 'bg-red-500',
|
||||||
label: 'Fainted',
|
label: 'Fainted',
|
||||||
bg: 'bg-red-50 dark:bg-red-900/10',
|
bg: 'bg-red-900/10',
|
||||||
},
|
},
|
||||||
missed: {
|
missed: {
|
||||||
dot: 'bg-gray-400',
|
dot: 'bg-gray-400',
|
||||||
@@ -335,7 +335,7 @@ function RouteGroup({
|
|||||||
</div>
|
</div>
|
||||||
<span className="text-xs text-text-muted shrink-0">{si.label}</span>
|
<span className="text-xs text-text-muted shrink-0">{si.label}</span>
|
||||||
<svg
|
<svg
|
||||||
className={`w-4 h-4 text-gray-400 transition-transform ${isExpanded ? 'rotate-180' : ''}`}
|
className={`w-4 h-4 text-text-tertiary transition-transform ${isExpanded ? 'rotate-180' : ''}`}
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -801,7 +801,7 @@ export function RunEncounters() {
|
|||||||
})}
|
})}
|
||||||
</p>
|
</p>
|
||||||
{run.genlocke && (
|
{run.genlocke && (
|
||||||
<p className="text-sm text-purple-600 dark:text-purple-400 mt-1 font-medium">
|
<p className="text-sm text-purple-400 mt-1 font-medium">
|
||||||
Leg {run.genlocke.legOrder} of {run.genlocke.totalLegs} —{' '}
|
Leg {run.genlocke.legOrder} of {run.genlocke.totalLegs} —{' '}
|
||||||
{run.genlocke.genlockeName}
|
{run.genlocke.genlockeName}
|
||||||
</p>
|
</p>
|
||||||
@@ -811,7 +811,7 @@ export function RunEncounters() {
|
|||||||
{isActive && run.rules?.shinyClause && (
|
{isActive && run.rules?.shinyClause && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowShinyModal(true)}
|
onClick={() => setShowShinyModal(true)}
|
||||||
className="px-3 py-1 text-sm border border-yellow-400 dark:border-yellow-600 text-yellow-600 dark:text-yellow-400 rounded-full font-medium hover:bg-yellow-50 dark:hover:bg-yellow-900/20 transition-colors"
|
className="px-3 py-1 text-sm border border-yellow-600 text-yellow-400 rounded-full font-medium hover:bg-yellow-900/20 transition-colors"
|
||||||
>
|
>
|
||||||
✦ Log Shiny
|
✦ Log Shiny
|
||||||
</button>
|
</button>
|
||||||
@@ -819,7 +819,7 @@ export function RunEncounters() {
|
|||||||
{isActive && (
|
{isActive && (
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowEggModal(true)}
|
onClick={() => setShowEggModal(true)}
|
||||||
className="px-3 py-1 text-sm border border-green-400 dark:border-green-600 text-status-active rounded-full font-medium hover:bg-green-50 dark:hover:bg-green-900/20 transition-colors"
|
className="px-3 py-1 text-sm border border-green-600 text-status-active rounded-full font-medium hover:bg-green-900/20 transition-colors"
|
||||||
>
|
>
|
||||||
🥚 Log Egg
|
🥚 Log Egg
|
||||||
</button>
|
</button>
|
||||||
@@ -846,8 +846,8 @@ export function RunEncounters() {
|
|||||||
<div
|
<div
|
||||||
className={`rounded-lg p-4 mb-6 ${
|
className={`rounded-lg p-4 mb-6 ${
|
||||||
run.status === 'completed'
|
run.status === 'completed'
|
||||||
? 'bg-blue-50 dark:bg-blue-900/20 border border-blue-200 dark:border-blue-800'
|
? 'bg-blue-900/20 border border-blue-800'
|
||||||
: 'bg-status-failed-bg border border-red-200 dark:border-red-800'
|
: 'bg-status-failed-bg border border-red-800'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-between">
|
<div className="flex items-center justify-between">
|
||||||
@@ -858,9 +858,7 @@ export function RunEncounters() {
|
|||||||
<div>
|
<div>
|
||||||
<p
|
<p
|
||||||
className={`font-semibold ${
|
className={`font-semibold ${
|
||||||
run.status === 'completed'
|
run.status === 'completed' ? 'text-blue-200' : 'text-red-200'
|
||||||
? 'text-blue-800 dark:text-blue-200'
|
|
||||||
: 'text-red-800 dark:text-red-200'
|
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{run.status === 'completed'
|
{run.status === 'completed'
|
||||||
@@ -924,7 +922,7 @@ export function RunEncounters() {
|
|||||||
</div>
|
</div>
|
||||||
{/* HoF Team Display */}
|
{/* HoF Team Display */}
|
||||||
{run.status === 'completed' && (
|
{run.status === 'completed' && (
|
||||||
<div className="mt-3 pt-3 border-t border-blue-200 dark:border-blue-800">
|
<div className="mt-3 pt-3 border-t border-blue-800">
|
||||||
<div className="flex items-center justify-between mb-2">
|
<div className="flex items-center justify-between mb-2">
|
||||||
<span className="text-xs font-medium text-text-link uppercase tracking-wider">
|
<span className="text-xs font-medium text-text-link uppercase tracking-wider">
|
||||||
Hall of Fame
|
Hall of Fame
|
||||||
@@ -932,7 +930,7 @@ export function RunEncounters() {
|
|||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setShowHofModal(true)}
|
onClick={() => setShowHofModal(true)}
|
||||||
className="text-xs text-blue-500 dark:text-blue-400 hover:text-blue-700 dark:hover:text-blue-300"
|
className="text-xs text-blue-400 hover:text-accent-300"
|
||||||
>
|
>
|
||||||
{hofTeam ? 'Edit' : 'Select team'}
|
{hofTeam ? 'Edit' : 'Select team'}
|
||||||
</button>
|
</button>
|
||||||
@@ -958,9 +956,7 @@ export function RunEncounters() {
|
|||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<p className="text-xs text-blue-500/60 dark:text-blue-400/60 italic">
|
<p className="text-xs text-blue-400/60 italic">No HoF team selected yet</p>
|
||||||
No HoF team selected yet
|
|
||||||
</p>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1017,8 +1013,8 @@ export function RunEncounters() {
|
|||||||
<div
|
<div
|
||||||
className={`w-6 h-6 rounded-full border-2 flex items-center justify-center text-xs font-bold ${
|
className={`w-6 h-6 rounded-full border-2 flex items-center justify-center text-xs font-bold ${
|
||||||
earned
|
earned
|
||||||
? 'border-yellow-500 bg-yellow-100 dark:bg-yellow-900/40 text-yellow-700 dark:text-yellow-300'
|
? 'border-yellow-500 bg-yellow-900/40 text-yellow-300'
|
||||||
: 'border-border-default text-gray-400'
|
: 'border-border-default text-text-tertiary'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
{boss.order}
|
{boss.order}
|
||||||
@@ -1055,7 +1051,7 @@ export function RunEncounters() {
|
|||||||
{dead.length > 0 ? `, ${dead.length} dead` : ''}
|
{dead.length > 0 ? `, ${dead.length} dead` : ''}
|
||||||
</span>
|
</span>
|
||||||
<svg
|
<svg
|
||||||
className={`w-4 h-4 text-gray-400 transition-transform ${showTeam ? 'rotate-180' : ''}`}
|
className={`w-4 h-4 text-text-tertiary transition-transform ${showTeam ? 'rotate-180' : ''}`}
|
||||||
fill="none"
|
fill="none"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
@@ -1127,9 +1123,7 @@ export function RunEncounters() {
|
|||||||
{/* Transfer Encounters */}
|
{/* Transfer Encounters */}
|
||||||
{transferEncounters.length > 0 && (
|
{transferEncounters.length > 0 && (
|
||||||
<div className="mb-6">
|
<div className="mb-6">
|
||||||
<h2 className="text-sm font-medium text-indigo-600 dark:text-indigo-400 mb-2">
|
<h2 className="text-sm font-medium text-indigo-400 mb-2">Transferred Pokemon</h2>
|
||||||
Transferred Pokemon
|
|
||||||
</h2>
|
|
||||||
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-2">
|
<div className="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 gap-2">
|
||||||
{transferEncounters.map((enc) => (
|
{transferEncounters.map((enc) => (
|
||||||
<PokemonCard
|
<PokemonCard
|
||||||
@@ -1159,7 +1153,7 @@ export function RunEncounters() {
|
|||||||
bulkRandomize.mutate()
|
bulkRandomize.mutate()
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
className="px-2.5 py-1 text-xs font-medium rounded-lg border border-purple-300 dark:border-purple-600 text-purple-600 dark:text-purple-400 hover:bg-purple-50 dark:hover:bg-purple-900/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
className="px-2.5 py-1 text-xs font-medium rounded-lg border border-purple-600 text-purple-400 hover:bg-purple-900/20 disabled:opacity-40 disabled:cursor-not-allowed transition-colors"
|
||||||
>
|
>
|
||||||
{bulkRandomize.isPending ? 'Randomizing...' : 'Randomize All'}
|
{bulkRandomize.isPending ? 'Randomizing...' : 'Randomize All'}
|
||||||
</button>
|
</button>
|
||||||
@@ -1303,14 +1297,14 @@ export function RunEncounters() {
|
|||||||
other: 'Boss',
|
other: 'Boss',
|
||||||
}
|
}
|
||||||
const bossTypeColors: Record<string, string> = {
|
const bossTypeColors: Record<string, string> = {
|
||||||
gym_leader: 'border-yellow-400 dark:border-yellow-600',
|
gym_leader: 'border-yellow-600',
|
||||||
elite_four: 'border-purple-400 dark:border-purple-600',
|
elite_four: 'border-purple-600',
|
||||||
champion: 'border-red-400 dark:border-red-600',
|
champion: 'border-red-600',
|
||||||
rival: 'border-blue-400 dark:border-blue-600',
|
rival: 'border-blue-600',
|
||||||
evil_team: 'border-gray-500 dark:border-gray-400',
|
evil_team: 'border-gray-400',
|
||||||
kahuna: 'border-orange-400 dark:border-orange-600',
|
kahuna: 'border-orange-600',
|
||||||
totem: 'border-teal-400 dark:border-teal-600',
|
totem: 'border-teal-600',
|
||||||
other: 'border-gray-400 dark:border-gray-500',
|
other: 'border-gray-500',
|
||||||
}
|
}
|
||||||
|
|
||||||
const isBossExpanded = expandedBosses.has(boss.id)
|
const isBossExpanded = expandedBosses.has(boss.id)
|
||||||
@@ -1327,7 +1321,7 @@ export function RunEncounters() {
|
|||||||
<div key={`boss-${boss.id}`}>
|
<div key={`boss-${boss.id}`}>
|
||||||
<div
|
<div
|
||||||
className={`my-2 rounded-lg border-2 ${bossTypeColors[boss.bossType] ?? bossTypeColors['other']} ${
|
className={`my-2 rounded-lg border-2 ${bossTypeColors[boss.bossType] ?? bossTypeColors['other']} ${
|
||||||
isDefeated ? 'bg-green-50/50 dark:bg-green-900/10' : 'bg-surface-1'
|
isDefeated ? 'bg-green-900/10' : 'bg-surface-1'
|
||||||
} px-4 py-3`}
|
} px-4 py-3`}
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
@@ -1336,7 +1330,7 @@ export function RunEncounters() {
|
|||||||
>
|
>
|
||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
<svg
|
<svg
|
||||||
className={`w-4 h-4 text-gray-400 transition-transform ${isBossExpanded ? 'rotate-90' : ''}`}
|
className={`w-4 h-4 text-text-tertiary transition-transform ${isBossExpanded ? 'rotate-90' : ''}`}
|
||||||
fill="none"
|
fill="none"
|
||||||
viewBox="0 0 24 24"
|
viewBox="0 0 24 24"
|
||||||
stroke="currentColor"
|
stroke="currentColor"
|
||||||
@@ -1364,7 +1358,7 @@ export function RunEncounters() {
|
|||||||
</div>
|
</div>
|
||||||
<div onClick={(e) => e.stopPropagation()}>
|
<div onClick={(e) => e.stopPropagation()}>
|
||||||
{isDefeated ? (
|
{isDefeated ? (
|
||||||
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium rounded-full bg-green-100 dark:bg-green-900/40 text-green-700 dark:text-green-300">
|
<span className="inline-flex items-center gap-1 px-2 py-1 text-xs font-medium rounded-full bg-green-900/40 text-green-300">
|
||||||
Defeated ✓
|
Defeated ✓
|
||||||
</span>
|
</span>
|
||||||
) : isActive ? (
|
) : isActive ? (
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ function SortableRouteGroup({
|
|||||||
<tbody
|
<tbody
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
style={style}
|
style={style}
|
||||||
className={`${isDragging ? 'opacity-50 bg-blue-50 dark:bg-blue-900/20' : ''} divide-y divide-border-default`}
|
className={`${isDragging ? 'opacity-50 bg-accent-900/20' : ''} divide-y divide-border-default`}
|
||||||
>
|
>
|
||||||
<tr className="hover:bg-surface-2 cursor-pointer" onClick={() => onClick(group)}>
|
<tr className="hover:bg-surface-2 cursor-pointer" onClick={() => onClick(group)}>
|
||||||
<td className="px-4 py-3 text-sm w-12">
|
<td className="px-4 py-3 text-sm w-12">
|
||||||
@@ -103,7 +103,7 @@ function SortableRouteGroup({
|
|||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
className="cursor-grab active:cursor-grabbing text-gray-400 hover:text-text-secondary touch-none"
|
className="cursor-grab active:cursor-grabbing text-text-tertiary hover:text-text-secondary touch-none"
|
||||||
title="Drag to reorder"
|
title="Drag to reorder"
|
||||||
>
|
>
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||||
@@ -189,7 +189,7 @@ function SortableBossRow({
|
|||||||
<tr
|
<tr
|
||||||
ref={setNodeRef}
|
ref={setNodeRef}
|
||||||
style={style}
|
style={style}
|
||||||
className={`${isDragging ? 'opacity-50 bg-blue-50 dark:bg-blue-900/20' : ''} hover:bg-surface-2 cursor-pointer`}
|
className={`${isDragging ? 'opacity-50 bg-accent-900/20' : ''} hover:bg-surface-2 cursor-pointer`}
|
||||||
onClick={() => onClick(boss)}
|
onClick={() => onClick(boss)}
|
||||||
>
|
>
|
||||||
<td className="px-4 py-3 text-sm w-12">
|
<td className="px-4 py-3 text-sm w-12">
|
||||||
@@ -197,7 +197,7 @@ function SortableBossRow({
|
|||||||
{...attributes}
|
{...attributes}
|
||||||
{...listeners}
|
{...listeners}
|
||||||
onClick={(e) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
className="cursor-grab active:cursor-grabbing text-gray-400 hover:text-text-secondary touch-none"
|
className="cursor-grab active:cursor-grabbing text-text-tertiary hover:text-text-secondary touch-none"
|
||||||
title="Drag to reorder"
|
title="Drag to reorder"
|
||||||
>
|
>
|
||||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
<svg width="16" height="16" viewBox="0 0 16 16" fill="currentColor">
|
||||||
@@ -287,8 +287,8 @@ export function AdminGameDetail() {
|
|||||||
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
useSensor(KeyboardSensor, { coordinateGetter: sortableKeyboardCoordinates })
|
||||||
)
|
)
|
||||||
|
|
||||||
if (isLoading) return <div className="py-8 text-center text-gray-500">Loading...</div>
|
if (isLoading) return <div className="py-8 text-center text-text-secondary">Loading...</div>
|
||||||
if (!game) return <div className="py-8 text-center text-gray-500">Game not found</div>
|
if (!game) return <div className="py-8 text-center text-text-secondary">Game not found</div>
|
||||||
|
|
||||||
const routes = game.routes ?? []
|
const routes = game.routes ?? []
|
||||||
const routeGroups = organizeRoutes(routes)
|
const routeGroups = organizeRoutes(routes)
|
||||||
@@ -362,7 +362,7 @@ export function AdminGameDetail() {
|
|||||||
onClick={() => setTab('routes')}
|
onClick={() => setTab('routes')}
|
||||||
className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${
|
className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${
|
||||||
tab === 'routes'
|
tab === 'routes'
|
||||||
? 'border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400'
|
? 'border-accent-400 text-accent-400'
|
||||||
: 'border-transparent text-text-tertiary hover:text-text-secondary'
|
: 'border-transparent text-text-tertiary hover:text-text-secondary'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
@@ -372,7 +372,7 @@ export function AdminGameDetail() {
|
|||||||
onClick={() => setTab('bosses')}
|
onClick={() => setTab('bosses')}
|
||||||
className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${
|
className={`px-4 py-2 text-sm font-medium border-b-2 -mb-px ${
|
||||||
tab === 'bosses'
|
tab === 'bosses'
|
||||||
? 'border-blue-600 text-blue-600 dark:border-blue-400 dark:text-blue-400'
|
? 'border-accent-400 text-accent-400'
|
||||||
: 'border-transparent text-text-tertiary hover:text-text-secondary'
|
: 'border-transparent text-text-tertiary hover:text-text-secondary'
|
||||||
}`}
|
}`}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -28,8 +28,9 @@ export function AdminGenlockeDetail() {
|
|||||||
const [addingLeg, setAddingLeg] = useState(false)
|
const [addingLeg, setAddingLeg] = useState(false)
|
||||||
const [selectedGameId, setSelectedGameId] = useState<number | ''>('')
|
const [selectedGameId, setSelectedGameId] = useState<number | ''>('')
|
||||||
|
|
||||||
if (isLoading) return <div className="py-8 text-center text-gray-500">Loading...</div>
|
if (isLoading) return <div className="py-8 text-center text-text-secondary">Loading...</div>
|
||||||
if (!genlocke) return <div className="py-8 text-center text-gray-500">Genlocke not found</div>
|
if (!genlocke)
|
||||||
|
return <div className="py-8 text-center text-text-secondary">Genlocke not found</div>
|
||||||
|
|
||||||
const editName = name ?? genlocke.name
|
const editName = name ?? genlocke.name
|
||||||
const editStatus = status ?? genlocke.status
|
const editStatus = status ?? genlocke.status
|
||||||
@@ -108,7 +109,7 @@ export function AdminGenlockeDetail() {
|
|||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => setShowDelete(true)}
|
onClick={() => setShowDelete(true)}
|
||||||
className="px-4 py-2 text-sm font-medium rounded-md border border-red-300 dark:border-red-600 text-status-failed hover:bg-red-50 dark:hover:bg-red-900/20"
|
className="px-4 py-2 text-sm font-medium rounded-md border border-red-600 text-status-failed hover:bg-red-900/20"
|
||||||
>
|
>
|
||||||
Delete
|
Delete
|
||||||
</button>
|
</button>
|
||||||
@@ -229,7 +230,7 @@ export function AdminGenlockeDetail() {
|
|||||||
Run #{leg.runId}
|
Run #{leg.runId}
|
||||||
</Link>
|
</Link>
|
||||||
) : (
|
) : (
|
||||||
<span className="text-gray-400">—</span>
|
<span className="text-text-tertiary">—</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3 text-sm whitespace-nowrap">
|
<td className="px-4 py-3 text-sm whitespace-nowrap">
|
||||||
@@ -246,7 +247,7 @@ export function AdminGenlockeDetail() {
|
|||||||
{leg.runStatus}
|
{leg.runStatus}
|
||||||
</span>
|
</span>
|
||||||
) : (
|
) : (
|
||||||
<span className="text-gray-400">—</span>
|
<span className="text-text-tertiary">—</span>
|
||||||
)}
|
)}
|
||||||
</td>
|
</td>
|
||||||
<td className="px-4 py-3 text-sm whitespace-nowrap">{leg.encounterCount}</td>
|
<td className="px-4 py-3 text-sm whitespace-nowrap">{leg.encounterCount}</td>
|
||||||
@@ -260,7 +261,7 @@ export function AdminGenlockeDetail() {
|
|||||||
? 'Cannot remove a leg with a linked run'
|
? 'Cannot remove a leg with a linked run'
|
||||||
: 'Remove leg'
|
: 'Remove leg'
|
||||||
}
|
}
|
||||||
className="text-status-failed hover:text-red-800 dark:hover:text-red-300 disabled:opacity-30 disabled:cursor-not-allowed"
|
className="text-status-failed hover:text-red-300 disabled:opacity-30 disabled:cursor-not-allowed"
|
||||||
>
|
>
|
||||||
Remove
|
Remove
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
Reference in New Issue
Block a user