From fb80146430a59cbc1e0e5d0d7f21e84ab7575ce2 Mon Sep 17 00:00:00 2001 From: Anders Olsson Date: Sat, 6 Jun 2026 21:50:13 +0200 Subject: [PATCH] docs(specs): objects data-overview table + responsive shell (#44, subsumes #58) Co-Authored-By: Claude Opus 4.8 (1M context) --- ...26-06-06-objects-table-and-shell-design.md | 187 ++++++++++++++++++ 1 file changed, 187 insertions(+) create mode 100644 docs/superpowers/specs/2026-06-06-objects-table-and-shell-design.md diff --git a/docs/superpowers/specs/2026-06-06-objects-table-and-shell-design.md b/docs/superpowers/specs/2026-06-06-objects-table-and-shell-design.md new file mode 100644 index 0000000..9ca76a6 --- /dev/null +++ b/docs/superpowers/specs/2026-06-06-objects-table-and-shell-design.md @@ -0,0 +1,187 @@ +# Objects Data-Overview Table + Responsive Shell — Design + +**Date:** 2026-06-06 +**Status:** Approved (brainstorming) — ready for implementation planning. +**Issues:** #44 (object list → table); subsumes #58 (responsive layout) for the shell. + +## Context + +The Objects screen is where curators triage hundreds of records daily, but today +`web/src/objects/object-list.tsx` renders a **thin 20rem list** (object_number + name + +visibility badge) inside a master/detail grid, with no columns, sort, or filter. The +backend `GET /api/admin/objects` (`list_objects_paged`) takes only `limit`/`offset` and +orders by `object_number`. A *separate* `search-panel.tsx` (Meilisearch full-text, infinite +scroll, visibility filter) is a parallel browse UI with different ergonomics. Goal: a real, +scannable, sortable, filterable **data-overview table** plus a shell that adapts to viewport +width and gives every object a shareable URL. + +### Facts established during exploration +- **Timestamps already exist.** The `object` table has `created_at` + `updated_at` + (`migrations/0003_object.sql`); `updated_at` is set to `now()` on every write; the db layer + already reads them into `CatalogueObject`. They are simply **not exposed in + `AdminObjectView`** — so adding an "Updated" column needs *no migration*, just two fields on + `AdminObjectView::from_object`. +- **Search is best-effort/optional** (`AppState.search: None` → the search endpoint 503s). So + the **Postgres-backed list must remain the always-available browse surface**; full-text + search is a layer on top, not a replacement. +- **No new dependencies needed:** `lucide-react` is already installed (nav icons); Base UI + ships `drawer`, `collapsible`, and `tooltip` primitives (the slide-in detail + sidebar). + +### Decisions (from brainstorming) +1. **Layout:** a Linear/email-style shell — collapsible **icon sidebar**; a **full-width + objects table** as the overview; selecting a row opens detail as a **right-hand pane on + wide viewports / a slide-in drawer when narrow**; **`/objects/:id` is a canonical, + shareable URL**. +2. **Search:** **table-first.** The table gets Postgres-backed sort + visibility filter + a + quick text filter (object number/name). The dedicated Meilisearch Search screen stays as-is; + folding full-text into the table's search box is a **deferred follow-up**. +3. One milestone, **built in phases** (backend → table → shell/responsive/detail). +4. **Storybook** stories for meaningful new components (per the standing preference). + +## 1. Shell: collapsible icon sidebar + responsive frame +`web/src/shell/app-shell.tsx`: +- The sidebar gains a **collapse toggle**; expanded = `w-44` (icon + label), collapsed = an + icon rail (`~w-14`, icon-only). State persisted in `localStorage` (e.g. `sidebar-collapsed`). +- Each nav item (`objects`, `vocabularies`, `authorities`, `search`, `fields`) gets a + `lucide-react` icon. When collapsed, the label is shown via a Base UI **`Tooltip`** on hover + and as the `aria-label`/`title` for AT. +- Below a width breakpoint the sidebar **auto-collapses** to the rail (the user can still + toggle). Nav `NavLink` active state + focus-visible rings preserved/added. +- This resolves #58 at the shell level (the per-screen master/detail responsiveness is handled + in §3). + +## 2. Objects table (`/objects`) +Replace the narrow list with a **full-width table** filling the main content area. + +**Columns (default):** Object № (sortable) · Name (sortable) · Visibility (badge; filterable) +· Current location · # objects · Updated (sortable). Real `` semantics with +`scope="col"` headers and `aria-sort` on the active sort column. + +**Toolbar (above the table):** +- A debounced **quick text filter** (`q`) — Postgres `ILIKE` on `object_number` + `object_name` + (always available; distinct from the Meili Search screen which searches descriptions/fields). +- **Visibility filter chips** (`all` / `draft` / `internal` / `public`), mirroring the search + panel's pattern (honest `