Add run dashboard and encounter tracking interface
Run list at /runs shows all runs with status badges. Run dashboard at /runs/:id displays stats, active team, graveyard, and rule badges. Encounter tracking at /runs/:runId/encounters shows route list with status indicators, progress bar, filters, and a modal for logging or editing encounters with pokemon picker. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
82
frontend/src/components/PokemonCard.tsx
Normal file
82
frontend/src/components/PokemonCard.tsx
Normal file
@@ -0,0 +1,82 @@
|
||||
import type { EncounterDetail } from '../types'
|
||||
|
||||
interface PokemonCardProps {
|
||||
encounter: EncounterDetail
|
||||
showFaintLevel?: boolean
|
||||
}
|
||||
|
||||
const typeColors: Record<string, string> = {
|
||||
normal: 'bg-gray-400',
|
||||
fire: 'bg-red-500',
|
||||
water: 'bg-blue-500',
|
||||
electric: 'bg-yellow-400',
|
||||
grass: 'bg-green-500',
|
||||
ice: 'bg-cyan-300',
|
||||
fighting: 'bg-red-700',
|
||||
poison: 'bg-purple-500',
|
||||
ground: 'bg-amber-600',
|
||||
flying: 'bg-indigo-300',
|
||||
psychic: 'bg-pink-500',
|
||||
bug: 'bg-lime-500',
|
||||
rock: 'bg-amber-700',
|
||||
ghost: 'bg-purple-700',
|
||||
dragon: 'bg-indigo-600',
|
||||
dark: 'bg-gray-700',
|
||||
steel: 'bg-gray-400',
|
||||
fairy: 'bg-pink-300',
|
||||
}
|
||||
|
||||
export function PokemonCard({ encounter, showFaintLevel }: PokemonCardProps) {
|
||||
const { pokemon, route, nickname, catchLevel, faintLevel } = encounter
|
||||
const isDead = faintLevel !== null
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`bg-white dark:bg-gray-800 rounded-lg shadow p-4 flex flex-col items-center text-center ${
|
||||
isDead ? 'opacity-60 grayscale' : ''
|
||||
}`}
|
||||
>
|
||||
{pokemon.spriteUrl ? (
|
||||
<img
|
||||
src={pokemon.spriteUrl}
|
||||
alt={pokemon.name}
|
||||
className="w-16 h-16"
|
||||
/>
|
||||
) : (
|
||||
<div className="w-16 h-16 rounded-full bg-gray-300 dark:bg-gray-600 flex items-center justify-center text-xl font-bold text-gray-600 dark:text-gray-300">
|
||||
{pokemon.name[0].toUpperCase()}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="mt-2 font-semibold text-gray-900 dark:text-gray-100 text-sm">
|
||||
{nickname || pokemon.name}
|
||||
</div>
|
||||
{nickname && (
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400">
|
||||
{pokemon.name}
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div className="flex gap-1 mt-1">
|
||||
{pokemon.types.map((type) => (
|
||||
<span
|
||||
key={type}
|
||||
className={`px-1.5 py-0.5 rounded text-[10px] font-medium text-white ${typeColors[type] ?? 'bg-gray-500'}`}
|
||||
>
|
||||
{type}
|
||||
</span>
|
||||
))}
|
||||
</div>
|
||||
|
||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||
{showFaintLevel && isDead
|
||||
? `Lv. ${catchLevel} → ${faintLevel}`
|
||||
: `Lv. ${catchLevel ?? '?'}`}
|
||||
</div>
|
||||
|
||||
<div className="text-xs text-gray-400 dark:text-gray-500 mt-0.5">
|
||||
{route.name}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user