develop #21

Merged
TheFurya merged 8 commits from develop into main 2026-02-14 10:01:44 +01:00
4 changed files with 69 additions and 4 deletions
Showing only changes of commit 867ded8fa2 - Show all commits

View File

@@ -1,11 +1,11 @@
--- ---
# nuzlocke-tracker-36wg # nuzlocke-tracker-36wg
title: Make footer stick to bottom of viewport title: Make footer stick to bottom of viewport
status: in-progress status: completed
type: bug type: bug
priority: normal priority: normal
created_at: 2026-02-13T07:47:48Z 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). 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", "version": "0.0.0",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "frontend", "name": "nuzlocke-tracker-frontend",
"version": "0.0.0", "version": "0.0.0",
"dependencies": { "dependencies": {
"@dnd-kit/core": "^6.3.1", "@dnd-kit/core": "^6.3.1",

View File

@@ -43,9 +43,11 @@ import type { CreateBossBattleInput, UpdateBossBattleInput } from '../../types/a
function SortableRouteRow({ function SortableRouteRow({
route, route,
gameId,
onClick, onClick,
}: { }: {
route: GameRoute route: GameRoute
gameId: number
onClick: (r: GameRoute) => void onClick: (r: GameRoute) => void
}) { }) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = const { attributes, listeners, setNodeRef, transform, transition, isDragging } =
@@ -83,15 +85,31 @@ function SortableRouteRow({
</td> </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 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">{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> </tr>
) )
} }
function SortableBossRow({ function SortableBossRow({
boss, boss,
routes,
onPositionChange,
onClick, onClick,
}: { }: {
boss: BossBattle boss: BossBattle
routes: GameRoute[]
onPositionChange: (bossId: number, afterRouteId: number | null) => void
onClick: (b: BossBattle) => void onClick: (b: BossBattle) => void
}) { }) {
const { attributes, listeners, setNodeRef, transform, transition, isDragging } = const { attributes, listeners, setNodeRef, transform, transition, isDragging } =
@@ -137,6 +155,24 @@ function SortableBossRow({
</td> </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.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">{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.levelCap}</td>
<td className="px-4 py-3 text-sm whitespace-nowrap">{boss.pokemon.length}</td> <td className="px-4 py-3 text-sm whitespace-nowrap">{boss.pokemon.length}</td>
</tr> </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"> <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Name Name
</th> </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> </tr>
</thead> </thead>
<DndContext <DndContext
@@ -330,6 +372,7 @@ export function AdminGameDetail() {
<SortableRouteRow <SortableRouteRow
key={route.id} key={route.id}
route={route} route={route}
gameId={id}
onClick={(r) => setEditing(r)} 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"> <th className="px-4 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
Location Location
</th> </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"> <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 Lv Cap
</th> </th>
@@ -465,6 +511,13 @@ export function AdminGameDetail() {
<SortableBossRow <SortableBossRow
key={boss.id} key={boss.id}
boss={boss} boss={boss}
routes={routes}
onPositionChange={(bossId, afterRouteId) =>
updateBoss.mutate({
bossId,
data: { afterRouteId } as UpdateBossBattleInput,
})
}
onClick={(b) => setEditingBoss(b)} onClick={(b) => setEditingBoss(b)}
/> />
))} ))}