Files
explorer/src/app/zxdb/labels/[id]/page.tsx
D. Rimron-Soutter e803274af4 react-bootstrap migration, review & parser fixes
UI / react-bootstrap:
Migrate client components to react-bootstrap (Card, Table, Form,
Alert, Badge, Nav, Button, Spinner, Row, Col): the ZXDB explorers
and detail pages (Labels, Genres, Languages, MachineTypes, Releases,
Entries), TapeIdentifier, home page, Navbar and ThemeDropdown.
Server components (home, zxdb hub, magazines, issues) keep raw
HTML+className — react-bootstrap barrel imports resolve to undefined
under Turbopack in server components. Replace bi bi-* CSS icons with
react-bootstrap-icons. Add aria-labels to search inputs and
visually-hidden captions to data tables.

Code-review remediation (docs/todo.md):
- FileViewer: replace useState-as-effect with a proper useEffect.
- register.service: restore request-level caching of parsed registers.
- middleware: convert .js to .ts, dev-only request logging.
- Extract shared types to src/types/zxdb.ts; add src/server/repo
  barrel for incremental per-domain splitting.
- Extract helpers: parseIdList (params.ts), serialize (serialize.ts),
  buildRegisterSummary/isInfoLine (register_helpers.ts).
- Add loading.tsx skeletons for dynamic ZXDB detail routes.
- generateMetadata + notFound() on entry/release/label detail pages.
- opengraph-image: stable keys; ThemeDropdown: drop hardcoded cookie
  domain; remove unused page.module.css.

Register parser & data:
- Update data/nextreg.txt from upstream tbblue (SpectrumNext FPGA):
  0x04/0x0A/0x0F/0x80/0x81 bit changes, new Issue 5 board id, 0x43
  renamed "Palette Control", 0xF0/0xF8/0xF9/0xFA now "Issues 4 and 5
  Only".
- Add reg_44 custom parser for 0x44 (Palette Value 9-bit): the two
  consecutive writes render as separate "1st write" / "2nd write"
  modes.
- Skip commented-out register headers so the disabled 0xA3 block no
  longer leaks a phantom register.
- Add detailHasContent guard so body-less registers (0xC7/0xCB/0xCF/
  0xFF) and 0xF0's leading blank no longer emit empty tab strips.
- Capture 0xF0's leading "Issues 4 and 5 Only" line as register text.
- Add isIssueRestricted (case-sensitive) to detect the issue badge
  across rewording without flagging per-bit "(issue 5 only)" notes;
  update badge label to "Issues 4 & 5 Only".

claude-opus-4-8@lucy
2026-06-08 22:47:37 +01:00

31 lines
1.6 KiB
TypeScript

import type { Metadata } from "next";
import LabelDetailClient from "./LabelDetail";
import { getLabelById, getLabelAuthoredEntries, getLabelPublishedEntries } from "@/server/repo";
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }): Promise<Metadata> {
const { id } = await params;
const label = await getLabelById(Number(id));
if (!label) return { title: "Label Not Found | ZXDB" };
return { title: `${label.name} | ZXDB Label` };
}
// Depends on searchParams (?page=, ?tab=). Force dynamic so each request renders correctly.
export const dynamic = "force-dynamic";
export default async function Page({ params, searchParams }: { params: Promise<{ id: string }>;
searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) {
const [{ id }, sp] = await Promise.all([params, searchParams]);
const numericId = Number(id);
const page = Math.max(1, Number(Array.isArray(sp.page) ? sp.page[0] : sp.page) || 1);
const tab = (Array.isArray(sp.tab) ? sp.tab[0] : sp.tab) as "authored" | "published" | undefined;
const q = (Array.isArray(sp.q) ? sp.q[0] : sp.q) ?? "";
const [label, authored, published] = await Promise.all([
getLabelById(numericId),
getLabelAuthoredEntries(numericId, { page, pageSize: 20, q: q || undefined }),
getLabelPublishedEntries(numericId, { page, pageSize: 20, q: q || undefined }),
]);
// Let the client component handle the "not found" simple state
return <LabelDetailClient id={numericId} initial={{ label: label, authored: authored, published: published }} initialTab={tab} initialQ={q} />;
}