Rewrite the README around purpose, architecture, quickstart, and status. Add contributing/security policies plus a docs index with audience front matter across existing docs.
202 lines
7.7 KiB
Markdown
202 lines
7.7 KiB
Markdown
---
|
|
title: "Design System"
|
|
audience: [developer]
|
|
summary: "Bootstrap-first UI conventions, the custom HTMX primitives, and the WCAG 2.1 AA baseline for building the UI."
|
|
---
|
|
|
|
# Design System
|
|
|
|
This is a **Bootstrap usage guide plus a custom-primitives reference** — not a
|
|
standalone design system. The member-console UI is Bootstrap-first: it uses
|
|
[Bootstrap 5.3.6](https://getbootstrap.com/) components and utilities directly,
|
|
and supplements them only where Bootstrap genuinely falls short.
|
|
|
|
Status: M7c deliverable. Reused downstream by M8/M9 member-side UX.
|
|
|
|
---
|
|
|
|
## 1. Foundation
|
|
|
|
### Bootstrap-first
|
|
|
|
There is **no custom token layer and no parallel utility system**. Spacing,
|
|
typography, colors, breakpoints, and layout all come from Bootstrap. Reach for a
|
|
Bootstrap utility class or component before writing CSS.
|
|
|
|
### Role of `app.css`
|
|
|
|
`internal/embeds/static/app.css` is **supplemental only**. A rule belongs there
|
|
only when Bootstrap genuinely cannot express it. Today that is:
|
|
|
|
- the HTMX loading-indicator hook (`.htmx-indicator` / `.htmx-request`)
|
|
- fixed `.toast-container` positioning
|
|
- cross-browser `<meter>` styling (Bootstrap does not style `<meter>`)
|
|
- the operator nav-tab active-state weight
|
|
|
|
The file carries a contract comment block at the top stating this. Keep it
|
|
short; if it starts to grow a token system, that is a signal to stop.
|
|
|
|
### Bootstrap CSS variable convention
|
|
|
|
Do **not** hardcode color values in `app.css` or templates. Reference Bootstrap's
|
|
CSS variables so the UI stays in sync if Bootstrap's defaults change:
|
|
|
|
```css
|
|
/* no */ background: #0d6efd;
|
|
/* yes */ background: var(--bs-primary);
|
|
```
|
|
|
|
Common ones: `--bs-primary`, `--bs-secondary`, `--bs-body-color`,
|
|
`--bs-border-color`, `--bs-success`, `--bs-danger`.
|
|
|
|
### Future theming hook
|
|
|
|
Bootstrap 5's CSS-variable architecture is the intended seam for per-deployment
|
|
theming (see the "Custom theming (two-tier)" backlog item in
|
|
`status/milestones.md`). Tier 1 = operator overrides a handful of `--bs-*`
|
|
variables; Tier 2 = unrestricted custom CSS. Nothing is built yet — but because
|
|
`app.css` references `--bs-*` instead of hex values, that feature stays a small
|
|
server-side addition rather than a refactor.
|
|
|
|
---
|
|
|
|
## 2. Approved component palette
|
|
|
|
### Buttons
|
|
|
|
| Variant | Use for | Notes |
|
|
|---|---|---|
|
|
| `btn-primary` | The single primary action on a screen/form | |
|
|
| `btn-outline-primary` | Emphasis secondary actions | |
|
|
| `btn-outline-secondary` | Neutral secondary actions (navigate, view, sub-views) | Default for "show me more" buttons |
|
|
| `btn-danger` / `btn-outline-danger` | Destructive actions | Pair with the confirm modal (§3) |
|
|
| `btn-link` | Tertiary / inline actions | |
|
|
|
|
**Retired — do not use:**
|
|
|
|
| Variant | Color | Contrast on white | Why |
|
|
|---|---|---|---|
|
|
| `btn-outline-info` | `#0dcaf0` cyan | ~1.8:1 | Fails WCAG 2.1 AA (needs 4.5:1) |
|
|
| `btn-outline-warning` | `#ffc107` yellow | ~1.28:1 | Fails WCAG 2.1 AA (needs 4.5:1) |
|
|
|
|
Both outline variants render unreadable text against the app's white
|
|
background. Replace neutral uses with `btn-outline-secondary` and emphasis uses
|
|
with `btn-outline-primary`. (The *solid* `btn-info` / `btn-warning` and the
|
|
`text-bg-*` badge variants are unaffected — only the outline button variants are
|
|
retired.)
|
|
|
|
### Badges
|
|
|
|
Use `text-bg-*` badge variants (`text-bg-secondary`, `text-bg-success`, etc.)
|
|
rather than bare `bg-*` where contrast matters — `text-bg-*` pairs the
|
|
background with a contrast-checked foreground.
|
|
|
|
### Alerts
|
|
|
|
`alert-success` / `alert-danger` / `alert-warning` are fine for **in-page,
|
|
persistent** messaging (e.g. validation summaries rendered into a swap target).
|
|
For **transient** success/error feedback that must survive an HTMX swap or
|
|
navigation, use the toast primitives (§3) instead.
|
|
|
|
---
|
|
|
|
## 3. Custom primitives
|
|
|
|
### Confirm modal
|
|
|
|
A single shared, accessible confirmation dialog replaces htmx's native
|
|
`hx-confirm`. Implemented by `static/confirm-action-modal.js`; the modal markup
|
|
lives in the operator layout (`#confirmActionModal`).
|
|
|
|
Trigger contract — `data-*` attributes on any trigger element:
|
|
|
|
| Attribute | Required | Meaning |
|
|
|---|---|---|
|
|
| `data-bs-toggle="modal" data-bs-target="#confirmActionModal"` | yes | Opens the modal |
|
|
| `data-action-url` | yes | Endpoint to call |
|
|
| `data-action-method` | yes | `post` or `delete` |
|
|
| `data-action-target` | yes | CSS selector for the HTMX swap target |
|
|
| `data-action-title` | no | Modal title (default `Confirm`) |
|
|
| `data-action-body` | no | Modal body text/HTML |
|
|
| `data-action-confirm-label` | no | Submit button label (default `Confirm`) |
|
|
| `data-action-style` | no | `danger` \| `primary` \| `warning` (default `danger`) |
|
|
| `data-action-fields` | no | JSON object of hidden form fields |
|
|
|
|
Behavior: a successful (2xx/3xx) response closes the modal; a failed request
|
|
leaves it open so the operator can read the error in the swap target and retry.
|
|
|
|
### Error toast
|
|
|
|
Transient error feedback. Markup (`#errorToast`) lives in each layout's
|
|
`.toast-container`; behavior in `static/error-handler.js`. It is shown
|
|
automatically by the `htmx:beforeSwap` handler for 4xx/5xx/network failures, and
|
|
can be shown manually via `showErrorToast(message)`.
|
|
|
|
- `role="alert"`, `aria-live="assertive"` — interrupts the screen reader, because
|
|
an error needs immediate attention.
|
|
|
|
### Success toast
|
|
|
|
Transient success feedback. Markup (`#successToast`) lives in each layout's
|
|
`.toast-container`; behavior in `static/success-toast.js`.
|
|
|
|
Triggered from the server via an `HX-Trigger` response header:
|
|
|
|
```go
|
|
// Works for both HTMX partial swaps and hx-boost navigations.
|
|
w.Header().Set("HX-Trigger", `{"showSuccessToast": "Product created"}`)
|
|
```
|
|
|
|
- `role="status"`, `aria-live="polite"` — announced without interrupting,
|
|
because success is not urgent.
|
|
- The `.toast-container` lives outside any HTMX swap target, so the toast
|
|
survives partial swaps and `hx-boost` full-page navigations.
|
|
An inline `alert-success` in a POST response body would be discarded by the
|
|
redirect target and never seen — that is why this primitive exists.
|
|
|
|
Existing templates are **not** migrated to this primitive in M7c; M7e owns the
|
|
convention and timing for adopting it across flows.
|
|
|
|
### Loading states
|
|
|
|
HTMX request indicators use the `.htmx-indicator` hook (styled in `app.css`).
|
|
Place a `.htmx-indicator` element inside the triggering control and let HTMX
|
|
toggle it via `.htmx-request`. For destructive forms, also use
|
|
`hx-disabled-elt` to disable the submit button during the request (see the
|
|
confirm modal form).
|
|
|
|
### Empty states
|
|
|
|
Empty collections render a centered, muted message rather than a bare blank
|
|
area:
|
|
|
|
```html
|
|
<div class="text-center py-4">
|
|
<p class="text-muted mb-0">No plan ladders found.</p>
|
|
</div>
|
|
```
|
|
|
|
Keep the copy specific ("No plan ladders found") rather than generic ("No
|
|
data").
|
|
|
|
---
|
|
|
|
## 4. WCAG 2.1 AA baseline
|
|
|
|
- **Contrast.** Text and meaningful UI must meet 4.5:1 (3:1 for large text /
|
|
components). The two retired outline button variants (§2) failed this; check
|
|
any new color use against it.
|
|
- **`aria-live` for async regions.** Content that appears without a navigation —
|
|
toasts, and HTMX swap targets that surface validation or results — must be in
|
|
an `aria-live` region so screen readers announce the change. Use `assertive`
|
|
only for errors; `polite` for everything else.
|
|
- **Focus management.** Modals trap and restore focus (Bootstrap handles this for
|
|
`.modal`). Do not remove focus outlines. Interactive controls must be
|
|
reachable and operable by keyboard.
|
|
- **Semantic markup.** Use real `<button>`/`<a>` elements (not clickable
|
|
`<div>`s), associate every form control with a `<label>`, and give icon-only
|
|
controls an `aria-label`.
|
|
- **Audit.** M7f runs the formal axe + Lighthouse a11y pass and keyboard-nav
|
|
review across all operator screens; this section is the standing checklist
|
|
that pass measures against.
|