Add pinwheel, encounters link, and boss position columns to admin tables

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Julian Tabel
2026-02-13 14:10:28 +01:00
parent 29a5c84651
commit 867ded8fa2
4 changed files with 69 additions and 4 deletions

View File

@@ -1,11 +1,11 @@
---
# nuzlocke-tracker-36wg
title: Make footer stick to bottom of viewport
status: in-progress
status: completed
type: bug
priority: normal
created_at: 2026-02-13T07:47:48Z
updated_at: 2026-02-13T12:51:48Z
updated_at: 2026-02-13T12:59:22Z
---
On pages with little content, the footer appears right after the content instead of staying at the bottom of the viewport. The footer should always be at the bottom of the browser window, pushing down when there's enough content but not floating in the middle of the page when content is short (sticky footer pattern).

View File

@@ -0,0 +1,12 @@
---
# nuzlocke-tracker-6r4z
title: 'Admin table improvements: Routes and Bosses'
status: completed
type: task
priority: normal
created_at: 2026-02-13T13:01:55Z
updated_at: 2026-02-13T13:06:08Z
---
1. Routes table: add column for 'pinwheel close' and a column for quicklink to encounters
2. Bosses table: add column for Position after route column, ideally as an inline dropdown for mass editing

View File

@@ -1,11 +1,11 @@
{
"name": "frontend",
"name": "nuzlocke-tracker-frontend",
"version": "0.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "frontend",
"name": "nuzlocke-tracker-frontend",
"version": "0.0.0",
"dependencies": {
"@dnd-kit/core": "^6.3.1",

View File

@@ -43,9 +43,11 @@ import type { CreateBossBattleInput, UpdateBossBattleInput } from '../../types/a
function SortableRouteRow({
route,
gameId,
onClick,
}: {
route: GameRoute
gameId: number
onClick: (r: GameRoute) => void
}) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } =
@@ -83,15 +85,31 @@ function SortableRouteRow({
</td>
<td className="px-4 py-3 text-sm whitespace-nowrap w-16">{route.order}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">{route.name}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap text-center">
{route.pinwheelZone != null ? route.pinwheelZone : '\u2014'}
</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">
<Link
to={`/admin/games/${gameId}/routes/${route.id}`}
onClick={(e) => e.stopPropagation()}
className="text-blue-600 dark:text-blue-400 hover:underline"
>
Encounters
</Link>
</td>
</tr>
)
}
function SortableBossRow({
boss,
routes,
onPositionChange,
onClick,
}: {
boss: BossBattle
routes: GameRoute[]
onPositionChange: (bossId: number, afterRouteId: number | null) => void
onClick: (b: BossBattle) => void
}) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } =
@@ -137,6 +155,24 @@ function SortableBossRow({
</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">{boss.section ?? '\u2014'}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">{boss.location}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">
<select
value={boss.afterRouteId ?? ''}
onClick={(e) => e.stopPropagation()}
onChange={(e) => {
const value = e.target.value === '' ? null : Number(e.target.value)
onPositionChange(boss.id, value)
}}
className="text-sm border border-gray-300 dark:border-gray-600 rounded px-1.5 py-0.5 bg-white dark:bg-gray-800 text-gray-900 dark:text-gray-100 max-w-[180px]"
>
<option value=""></option>
{routes.map((r) => (
<option key={r.id} value={r.id}>
{r.name}
</option>
))}
</select>
</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">{boss.levelCap}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">{boss.pokemon.length}</td>
</tr>
@@ -314,6 +350,12 @@ export function AdminGameDetail() {
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Name
</th>
<th className="px-4 py-3 text-center text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-24">
Pinwheel
</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-28">
Links
</th>
</tr>
</thead>
<DndContext
@@ -330,6 +372,7 @@ export function AdminGameDetail() {
<SortableRouteRow
key={route.id}
route={route}
gameId={id}
onClick={(r) => setEditing(r)}
/>
))}
@@ -443,6 +486,9 @@ export function AdminGameDetail() {
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Location
</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Position
</th>
<th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider w-20">
Lv Cap
</th>
@@ -465,6 +511,13 @@ export function AdminGameDetail() {
<SortableBossRow
key={boss.id}
boss={boss}
routes={routes}
onPositionChange={(bossId, afterRouteId) =>
updateBoss.mutate({
bossId,
data: { afterRouteId } as UpdateBossBattleInput,
})
}
onClick={(b) => setEditingBoss(b)}
/>
))}