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:
@@ -3,16 +3,18 @@
|
||||
import { useCallback, useEffect, useMemo, useState } from "react";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { Row, Col, Card, Form, Button, Alert, Table, Badge } from "react-bootstrap";
|
||||
import ZxdbBreadcrumbs from "@/app/zxdb/components/ZxdbBreadcrumbs";
|
||||
import Pagination from "@/components/explorer/Pagination";
|
||||
|
||||
type Genre = { id: number; name: string };
|
||||
type Paged<T> = { items: T[]; page: number; pageSize: number; total: number };
|
||||
import type { PagedResult } from "@/types/zxdb";
|
||||
|
||||
export default function GenresSearch({ initial, initialQ }: { initial?: Paged<Genre>; initialQ?: string }) {
|
||||
type Genre = { id: number; name: string };
|
||||
|
||||
export default function GenresSearch({ initial, initialQ }: { initial?: PagedResult<Genre>; initialQ?: string }) {
|
||||
const router = useRouter();
|
||||
const [q, setQ] = useState(initialQ ?? "");
|
||||
const [data, setData] = useState<Paged<Genre> | null>(initial ?? null);
|
||||
const [data, setData] = useState<PagedResult<Genre> | null>(initial ?? null);
|
||||
const totalPages = useMemo(() => (data ? Math.max(1, Math.ceil(data.total / data.pageSize)) : 1), [data]);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -54,49 +56,48 @@ export default function GenresSearch({ initial, initialQ }: { initial?: Paged<Ge
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="row g-3">
|
||||
<div className="col-lg-3">
|
||||
<div className="card shadow-sm">
|
||||
<div className="card-body">
|
||||
<form className="d-flex flex-column gap-2" onSubmit={submit}>
|
||||
<div>
|
||||
<label className="form-label small text-secondary">Search</label>
|
||||
<input className="form-control" placeholder="Search genres..." value={q} onChange={(e) => setQ(e.target.value)} />
|
||||
</div>
|
||||
<Row className="g-3">
|
||||
<Col lg={3}>
|
||||
<Card className="shadow-sm">
|
||||
<Card.Body>
|
||||
<Form className="d-flex flex-column gap-2" onSubmit={submit}>
|
||||
<Form.Group>
|
||||
<Form.Label className="small text-secondary">Search</Form.Label>
|
||||
<Form.Control placeholder="Search genres..." value={q} onChange={(e) => setQ(e.target.value)} />
|
||||
</Form.Group>
|
||||
<div className="d-grid">
|
||||
<button className="btn btn-primary">Search</button>
|
||||
<Button variant="primary" type="submit">Search</Button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Form>
|
||||
</Card.Body>
|
||||
</Card>
|
||||
</Col>
|
||||
|
||||
<div className="col-lg-9">
|
||||
{data && data.items.length === 0 && <div className="alert alert-warning">No genres found.</div>}
|
||||
<Col lg={9}>
|
||||
{data && data.items.length === 0 && <Alert variant="warning">No genres found.</Alert>}
|
||||
{data && data.items.length > 0 && (
|
||||
<div className="table-responsive">
|
||||
<table className="table table-striped table-hover align-middle">
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width: 120 }}>ID</th>
|
||||
<th>Name</th>
|
||||
<Table striped hover className="align-middle">
|
||||
<caption className="visually-hidden">Genres search results</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
<th style={{ width: 120 }}>ID</th>
|
||||
<th>Name</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.items.map((g) => (
|
||||
<tr key={g.id}>
|
||||
<td><Badge bg="light" text="dark">#{g.id}</Badge></td>
|
||||
<td>
|
||||
<Link href={`/zxdb/genres/${g.id}`}>{g.name}</Link>
|
||||
</td>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.items.map((g) => (
|
||||
<tr key={g.id}>
|
||||
<td><span className="badge text-bg-light">#{g.id}</span></td>
|
||||
<td>
|
||||
<Link href={`/zxdb/genres/${g.id}`}>{g.name}</Link>
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
))}
|
||||
</tbody>
|
||||
</Table>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
<Pagination
|
||||
page={data?.page ?? 1}
|
||||
|
||||
Reference in New Issue
Block a user