Use type PNG badges instead of colored text spans
Replace inline typeColors maps in PokemonCard and StatusChangeModal
with a shared TypeBadge component that renders the type icon PNGs
from /types/{type}.png.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@@ -1,11 +1,11 @@
|
|||||||
---
|
---
|
||||||
# nuzlocke-tracker-rkyc
|
# nuzlocke-tracker-rkyc
|
||||||
title: Dupes Clause & Shiny Clause enforcement
|
title: Dupes Clause & Shiny Clause enforcement
|
||||||
status: todo
|
status: completed
|
||||||
type: feature
|
type: feature
|
||||||
priority: low
|
priority: low
|
||||||
created_at: 2026-02-05T12:25:19Z
|
created_at: 2026-02-05T12:25:19Z
|
||||||
updated_at: 2026-02-07T19:52:42Z
|
updated_at: 2026-02-07T20:11:59Z
|
||||||
---
|
---
|
||||||
|
|
||||||
Implement active enforcement for Dupes Clause and Shiny Clause in the encounter flow.
|
Implement active enforcement for Dupes Clause and Shiny Clause in the encounter flow.
|
||||||
|
|||||||
BIN
frontend/public/types/bug.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
frontend/public/types/dark.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
frontend/public/types/dragon.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
frontend/public/types/electric.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
frontend/public/types/fairy.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
frontend/public/types/fighting.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
frontend/public/types/fire.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
frontend/public/types/flying.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
frontend/public/types/ghost.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
frontend/public/types/grass.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
BIN
frontend/public/types/ground.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
frontend/public/types/ice.png
Normal file
|
After Width: | Height: | Size: 1.4 KiB |
BIN
frontend/public/types/normal.png
Normal file
|
After Width: | Height: | Size: 2.2 KiB |
BIN
frontend/public/types/poison.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
frontend/public/types/psychic.png
Normal file
|
After Width: | Height: | Size: 2.0 KiB |
BIN
frontend/public/types/rock.png
Normal file
|
After Width: | Height: | Size: 1.9 KiB |
BIN
frontend/public/types/steel.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
frontend/public/types/water.png
Normal file
|
After Width: | Height: | Size: 2.3 KiB |
@@ -1,4 +1,5 @@
|
|||||||
import type { EncounterDetail } from '../types'
|
import type { EncounterDetail } from '../types'
|
||||||
|
import { TypeBadge } from './TypeBadge'
|
||||||
|
|
||||||
interface PokemonCardProps {
|
interface PokemonCardProps {
|
||||||
encounter: EncounterDetail
|
encounter: EncounterDetail
|
||||||
@@ -6,27 +7,6 @@ interface PokemonCardProps {
|
|||||||
onClick?: () => void
|
onClick?: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
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, onClick }: PokemonCardProps) {
|
export function PokemonCard({ encounter, showFaintLevel, onClick }: PokemonCardProps) {
|
||||||
const { pokemon, currentPokemon, route, nickname, catchLevel, faintLevel, deathCause } = encounter
|
const { pokemon, currentPokemon, route, nickname, catchLevel, faintLevel, deathCause } = encounter
|
||||||
const isDead = faintLevel !== null
|
const isDead = faintLevel !== null
|
||||||
@@ -68,12 +48,7 @@ export function PokemonCard({ encounter, showFaintLevel, onClick }: PokemonCardP
|
|||||||
|
|
||||||
<div className="flex gap-1 mt-1">
|
<div className="flex gap-1 mt-1">
|
||||||
{displayPokemon.types.map((type) => (
|
{displayPokemon.types.map((type) => (
|
||||||
<span
|
<TypeBadge key={type} type={type} />
|
||||||
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>
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import { useState } from 'react'
|
import { useState } from 'react'
|
||||||
import type { EncounterDetail, UpdateEncounterInput } from '../types'
|
import type { EncounterDetail, UpdateEncounterInput } from '../types'
|
||||||
import { useEvolutions } from '../hooks/useEncounters'
|
import { useEvolutions } from '../hooks/useEncounters'
|
||||||
|
import { TypeBadge } from './TypeBadge'
|
||||||
|
|
||||||
interface StatusChangeModalProps {
|
interface StatusChangeModalProps {
|
||||||
encounter: EncounterDetail
|
encounter: EncounterDetail
|
||||||
@@ -13,27 +14,6 @@ interface StatusChangeModalProps {
|
|||||||
region?: string
|
region?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
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',
|
|
||||||
}
|
|
||||||
|
|
||||||
function formatEvolutionMethod(evo: { trigger: string; minLevel: number | null; item: string | null; heldItem: string | null; condition: string | null }): string {
|
function formatEvolutionMethod(evo: { trigger: string; minLevel: number | null; item: string | null; heldItem: string | null; condition: string | null }): string {
|
||||||
const parts: string[] = []
|
const parts: string[] = []
|
||||||
if (evo.trigger === 'level-up' && evo.minLevel) {
|
if (evo.trigger === 'level-up' && evo.minLevel) {
|
||||||
@@ -149,12 +129,7 @@ export function StatusChangeModal({
|
|||||||
)}
|
)}
|
||||||
<div className="flex gap-1 mt-1">
|
<div className="flex gap-1 mt-1">
|
||||||
{displayPokemon.types.map((type) => (
|
{displayPokemon.types.map((type) => (
|
||||||
<span
|
<TypeBadge key={type} type={type} />
|
||||||
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>
|
||||||
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
<div className="text-xs text-gray-500 dark:text-gray-400 mt-1">
|
||||||
|
|||||||
15
frontend/src/components/TypeBadge.tsx
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
interface TypeBadgeProps {
|
||||||
|
type: string
|
||||||
|
size?: 'sm' | 'md'
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TypeBadge({ type, size = 'sm' }: TypeBadgeProps) {
|
||||||
|
const height = size === 'md' ? 'h-5' : 'h-4'
|
||||||
|
return (
|
||||||
|
<img
|
||||||
|
src={`/types/${type}.png`}
|
||||||
|
alt={type}
|
||||||
|
className={`${height} w-auto`}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
@@ -13,3 +13,4 @@ export { RuleToggle } from './RuleToggle'
|
|||||||
export { RulesConfiguration } from './RulesConfiguration'
|
export { RulesConfiguration } from './RulesConfiguration'
|
||||||
export { StatCard } from './StatCard'
|
export { StatCard } from './StatCard'
|
||||||
export { StepIndicator } from './StepIndicator'
|
export { StepIndicator } from './StepIndicator'
|
||||||
|
export { TypeBadge } from './TypeBadge'
|
||||||
|
|||||||