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
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
import ReleasesExplorer from "./ReleasesExplorer";
|
||||
import { listCasetypes, listFiletypes, listLanguages, listMachinetypes, listSchemetypes, listSourcetypes, searchReleases } from "@/server/repo/zxdb";
|
||||
import { listCasetypes, listFiletypes, listLanguages, listMachinetypes, listSchemetypes, listSourcetypes, searchReleases } from "@/server/repo";
|
||||
import { parseIdList } from "@/utils/params";
|
||||
import { serialize } from "@/utils/serialize";
|
||||
|
||||
export const metadata = {
|
||||
title: "ZXDB Releases",
|
||||
@@ -7,16 +9,6 @@ export const metadata = {
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
function parseIdList(value: string | string[] | undefined) {
|
||||
if (!value) return undefined;
|
||||
const raw = Array.isArray(value) ? value.join(",") : value;
|
||||
const ids = raw
|
||||
.split(",")
|
||||
.map((id) => Number(id.trim()))
|
||||
.filter((id) => Number.isFinite(id) && id > 0);
|
||||
return ids.length ? ids : undefined;
|
||||
}
|
||||
|
||||
export default async function Page({ searchParams }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }> }) {
|
||||
const sp = await searchParams;
|
||||
const hasParams = Object.values(sp).some((value) => value !== undefined);
|
||||
@@ -47,20 +39,17 @@ export default async function Page({ searchParams }: { searchParams: Promise<{ [
|
||||
listCasetypes(),
|
||||
]);
|
||||
|
||||
// Ensure the object passed to a Client Component is a plain JSON value
|
||||
const initialPlain = JSON.parse(JSON.stringify(initial));
|
||||
|
||||
return (
|
||||
<ReleasesExplorer
|
||||
initial={initialPlain}
|
||||
initialLists={{
|
||||
languages: JSON.parse(JSON.stringify(langs)),
|
||||
machinetypes: JSON.parse(JSON.stringify(machines)),
|
||||
filetypes: JSON.parse(JSON.stringify(filetypes)),
|
||||
schemetypes: JSON.parse(JSON.stringify(schemes)),
|
||||
sourcetypes: JSON.parse(JSON.stringify(sources)),
|
||||
casetypes: JSON.parse(JSON.stringify(cases)),
|
||||
}}
|
||||
initial={serialize(initial)}
|
||||
initialLists={serialize({
|
||||
languages: langs,
|
||||
machinetypes: machines,
|
||||
filetypes,
|
||||
schemetypes: schemes,
|
||||
sourcetypes: sources,
|
||||
casetypes: cases,
|
||||
})}
|
||||
initialUrlState={{ q, page, year: yearStr, sort, dLanguageId, dMachinetypeId: dMachinetypeIdStr, filetypeId: filetypeIdStr, schemetypeId, sourcetypeId, casetypeId, isDemo: isDemoStr }}
|
||||
initialUrlHasParams={hasParams}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user