Skip to content

Latest commit

 

History

History

README.md

UI — icons, navigation, and component kit

Contributor docs for shared UI conventions in the SPA.

Implementation status

Area Status Notes
Icon library (@tabler/icons-react) Shipped #64
Shared size constants Shipped src/lib/iconSizes.ts
Display conventions Shipped display-conventions.md
Two-section navigation Shipped #81AppNav, SectionNav, src/nav/
Layout & component kit Shipped #105src/components/ui/, /#/styleguide
Standardised datatables Shipped #138 — sort, sticky header, toolbar
List table persistence Shipped #146 — filters, sort, columns in localStorage
CRUD actions Shipped List/detail/edit routes, ConfirmDeleteModal, ZoneMemberPicker
Import/export/workflows Shipped ImportDropzone, Export, SummaryCard, ProjectList
Map/location Shipped MapControls, UseMyLocationButton

Documentation map

Doc Purpose
icons-progress.md Icons rollout log
icons-outstanding.md Icons debt
nav-progress.md Two-section nav execution log (#81)
nav-outstanding.md Nav debt discovered during #81
component-kit-progress.md Component kit execution log (#105)
component-kit-outstanding.md Kit debt discovered during #105
datatable-progress.md DataTable depth pass (#138)
datatable-outstanding.md DataTable debt discovered during #138
list-prefs-progress.md List table persistence log (#146)
list-prefs-outstanding.md List prefs debt discovered during #146
display-conventions.md Icons, badges, nav layout

Layout & component kit

Shared page chrome lives in src/components/ui/. Reference layout: import/export (src/routes/ImportExport.tsx) — page title + dimmed description, bordered section cards in a responsive grid.

Page width tokens

Defined in tokens.ts and applied via Page:

Variant Mantine Container size Typical routes
narrow sm Home, Settings
default lg CRUD, import/export, report
wide xl Reserved for data-heavy reference pages

Spacing conventions

Token Value Use
PAGE_STACK_GAP lg Between major page blocks
PAGE_HEADER_GAP xs Title + description
PAGE_SECTION_GAP md Inside bordered section cards
Section card Paper withBorder, p="md", radius="md" Grouped settings, import/export panels

Styleguide

Hidden dev route (no nav link): /#/styleguide — demos every kit primitive.

Primitives inventory

Component Role
Page Outer shell — width, vertical padding
PageHeader Title order={1} + description + optional actions
PageSection Bordered card with optional title/description
PageSectionGrid Responsive 1–2 column section layout
ListPage List-route shell
FormPage Edit-route shell with sticky mobile footer
FormSection Titled field group
DataTable Entity list table — sort, sticky header, toolbar, optional selection
EmptyState Zero-row / empty project placeholder

List datatable contract (#138)

DataTable sidecar: DataTable.md.

Variant Toolbar Sort Typical routes
list Search (?q= via useListNameQuery on simple lists), optional-column picker (localStorage key per list), result count Click column headers; channels also sync name/distance with URL sort Entity list routes
embedded None Header sort only Detail-page member/usage tables

Channels: band/mode/duplex/distance filters stay in ChannelsListSectionNav; optional columns use per-project mm9pdy-codeplug-tool.list.channels.{projectId}.columns via columnVisibilityStorageKey.

Simple lists: name search moved from section nav into the table toolbar; EntityListSectionNav keeps only the New action.

List table state (#146)

Entity list filters, column sort, and channel optional columns persist in browser localStorage, scoped per active project (mm9pdy-codeplug-tool.list.<entity>.<projectId>).

State Storage Notes
Name search, channel filters URL + localStorage write-through useChannelListQuery, useListNameQuery(entity)
Column header sort localStorage only usePersistedEntityListSort, usePersistedChannelColumnSort
Channel optional columns Per-project localStorage columnVisibilityStorageKey + columnVisibilityLoad

Restore: when a list route loads with no relevant URL params, hooks hydrate the URL from stored prefs for that project.

URL wins: landing with query params (bookmark/shared link) uses URL values for that visit; subsequent edits update storage.

Code: src/lib/listPrefs/, useChannelListQuery, useListNameQuery.

Two-section navigation architecture

┌──────────────┬─────────────────┬──────────────────────────┐
│  AppNav      │  SectionNav     │  Routes (main content)   │
│  (primary)   │  (secondary)    │                          │
└──────────────┴─────────────────┴──────────────────────────┘
Piece Path Role
Primary nav src/components/AppNav/ Project routes, ActiveProjectBar, Reference/Settings
Secondary nav src/components/SectionNav/ Section filters, New actions, sub-links
Registry src/nav/sectionNavRegistry.ts Pathname prefix → section component
Nav config src/nav/primaryNavItems.ts Icons, labels, entity count keys

Desktop: both columns in AppShell.Navbar (~480px when secondary visible). Mobile: useMediaQuery shows secondary as a Paper toolbar above <Routes>.

Summary (/summary) has no registry entry — secondary column hidden.

State: URL search params for shareable filters (useChannelListQuery, useListNameQuery, useVendorFormatParam); list filters/sort/columns also in per-project localStorage (#146 — see List table state).

Concepts

Icons use Tabler Icons via @tabler/icons-react. Import by name per file; do not barrel-re-export.

Icons aid scanning and primary actions (nav, New/Edit/Delete, import/export). Data-dense surfaces (tables, badges, frequency text) stay text-first.

Entity icon mapping (navbar + summary cards)

Entity Icon
Summary IconLayoutDashboard
Channels IconAntenna
Zones IconFolders
Talk groups IconUsersGroup
Contacts IconAddressBook
RX Group Lists IconListDetails
Import & export IconArrowsLeftRight
Reference IconBook
Settings IconSettings

Related

  • Tracking: codeplug-tool#64 (icons), #81 (nav), #138 (datatables), #146 (list persistence)
  • Component sidecars: AppNav.md, SectionNav.md, DataTable.md