feature/boss-sprites-and-badges (#22)
All checks were successful
CI / backend-lint (push) Successful in 8s
CI / frontend-lint (push) Successful in 32s

Reviewed-on: TheFurya/nuzlocke-tracker#22
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 #22.
This commit is contained in:
2026-02-14 11:04:08 +01:00
committed by TheFurya
parent 3412d6c6fd
commit ebdc9b2f28
225 changed files with 879 additions and 130 deletions

View File

@@ -1376,7 +1376,7 @@ export function RunEncounters() {
<path strokeLinecap="round" strokeLinejoin="round" d="M9 5l7 7-7 7" />
</svg>
{boss.spriteUrl && (
<img src={boss.spriteUrl} alt={boss.name} className="w-10 h-10" />
<img src={boss.spriteUrl} alt={boss.name} className="h-10 w-auto" />
)}
<div>
<div className="flex items-center gap-2">

View File

@@ -21,7 +21,7 @@ import { RouteFormModal } from '../../components/admin/RouteFormModal'
import { BossBattleFormModal } from '../../components/admin/BossBattleFormModal'
import { BossTeamEditor } from '../../components/admin/BossTeamEditor'
import { TypeBadge } from '../../components/TypeBadge'
import { useGame } from '../../hooks/useGames'
import { useGame, useGames } from '../../hooks/useGames'
import { useGameBosses } from '../../hooks/useBosses'
import {
useCreateRoute,
@@ -162,11 +162,13 @@ function SortableRouteGroup({
function SortableBossRow({
boss,
routes,
games,
onPositionChange,
onClick,
}: {
boss: BossBattle
routes: GameRoute[]
games: import('../../types/game').Game[]
onPositionChange: (bossId: number, afterRouteId: number | null) => void
onClick: (b: BossBattle) => void
}) {
@@ -204,7 +206,17 @@ function SortableBossRow({
</button>
</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">{boss.order}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap font-medium">{boss.name}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap font-medium">
{boss.name}
{boss.gameId != null && (() => {
const g = games.find((g) => g.id === boss.gameId)
return g ? (
<span className="ml-2 text-xs px-1.5 py-0.5 rounded bg-gray-100 dark:bg-gray-700 text-gray-500 dark:text-gray-400">
{g.name}
</span>
) : null
})()}
</td>
<td className="px-4 py-3 text-sm whitespace-nowrap capitalize">
{boss.bossType.replace('_', ' ')}
</td>
@@ -247,7 +259,8 @@ export function AdminGameDetail() {
const deleteRoute = useDeleteRoute(id)
const reorderRoutes = useReorderRoutes(id)
const bulkImportRoutes = useBulkImportRoutes(id)
const { data: bosses } = useGameBosses(id)
const { data: bosses } = useGameBosses(id, true)
const { data: allGames } = useGames()
const createBoss = useCreateBossBattle(id)
const updateBoss = useUpdateBossBattle(id)
const deleteBoss = useDeleteBossBattle(id)
@@ -273,6 +286,9 @@ export function AdminGameDetail() {
const routes = game.routes ?? []
const routeGroups = organizeRoutes(routes)
const versionGroupGames = (allGames ?? []).filter(
(g) => g.versionGroupId === game.versionGroupId,
)
const handleDragEnd = (event: DragEndEvent) => {
const { active, over } = event
@@ -573,6 +589,7 @@ export function AdminGameDetail() {
key={boss.id}
boss={boss}
routes={routes}
games={versionGroupGames}
onPositionChange={(bossId, afterRouteId) =>
updateBoss.mutate({
bossId,
@@ -596,6 +613,7 @@ export function AdminGameDetail() {
{showCreateBoss && (
<BossBattleFormModal
routes={routes}
games={versionGroupGames}
nextOrder={bosses ? Math.max(0, ...bosses.map((b) => b.order)) + 1 : 1}
onSubmit={(data) =>
createBoss.mutate(data as CreateBossBattleInput, {
@@ -611,6 +629,7 @@ export function AdminGameDetail() {
<BossBattleFormModal
boss={editingBoss}
routes={routes}
games={versionGroupGames}
nextOrder={editingBoss.order}
onSubmit={(data) =>
updateBoss.mutate(