[session 1] docs(guide): frontend-template Rules & Gotchas tab (#36)
CD - Develop (guide → bcos.dev) / build-and-deploy (push) Has started running
CD - Develop (guide → bcos.dev) / build-and-deploy (push) Has started running
This commit was merged in pull request #36.
This commit is contained in:
@@ -0,0 +1,76 @@
|
|||||||
|
---
|
||||||
|
module: platform.frontend-template
|
||||||
|
title: Frontend Template — starting a new SPA
|
||||||
|
tab: Rules & Gotchas
|
||||||
|
order: 20
|
||||||
|
audience: dev
|
||||||
|
---
|
||||||
|
|
||||||
|
# Design-system rules & hard-won gotchas
|
||||||
|
|
||||||
|
The canonical CSS to **copy verbatim** lives in the template repo's
|
||||||
|
`frontend/src/components/TablePage.svelte` (plain list/table pages) and `TemplatePage.svelte`
|
||||||
|
(pages with severity/status badges) — copy those files, don't rewrite. This tab captures the
|
||||||
|
**rules and gotchas** that aren't obvious from the files.
|
||||||
|
|
||||||
|
## Colors
|
||||||
|
|
||||||
|
| Token | Value | Used for |
|
||||||
|
|-------|-------|----------|
|
||||||
|
| `--color-primary` / `-hover` | `#2563eb` / `#1d4ed8` | buttons, links, active highlights |
|
||||||
|
| `--color-danger` | `#d32f2f` | delete/error |
|
||||||
|
| `--color-success` / `--color-warning` | `#2e7d32` / `#b45309` | badges |
|
||||||
|
| `--color-border` | `#e0e0e0` | card/table borders |
|
||||||
|
| `--color-text-primary` / `-secondary` | `#1a1a1a` / `#666` | body / muted |
|
||||||
|
|
||||||
|
**Sidebar gradient (canonical — do not change per app):**
|
||||||
|
Light `linear-gradient(180deg, #081651 0%, #1c49b8 100%)` · Dark `linear-gradient(180deg, #050e2e 0%, #0f2460 100%)`.
|
||||||
|
(For brand/customer-facing artifacts use the BCOS palette instead — see `platform.branding`. The
|
||||||
|
`#2563eb` above is the app-template blue, not the brand.)
|
||||||
|
|
||||||
|
## Base font size — CRITICAL
|
||||||
|
|
||||||
|
Every app **must** set `font-size: 14px` on `html, body`. All `rem` values are relative to it;
|
||||||
|
omit it and the browser defaults to 16px → every nav item, cell, and badge is ~14% too large.
|
||||||
|
|
||||||
|
```css
|
||||||
|
:global(html), :global(body) { font-size: 14px; } /* required — do not omit */
|
||||||
|
```
|
||||||
|
|
||||||
|
Typography scale (relative to 14px): page-title `1.4rem` · section-title `1.1rem` · body `0.95rem` ·
|
||||||
|
body-sm `0.9rem` · **label `0.85rem` (table cells, form labels)** · caption `0.8rem` · tiny `0.75rem`
|
||||||
|
(uppercase table headers) · subtitle `0.85rem` (`.header p`) · icon `1.1rem` · stat-value `2rem`.
|
||||||
|
|
||||||
|
## CSS isolation — four rules (these burned real hours)
|
||||||
|
|
||||||
|
1. **Use Svelte `<style>` blocks, never a globally imported `.css` file.** Svelte scopes them
|
||||||
|
(`td.svelte-abc123`) so they can't bleed. Dark mode still needs `:global(.dark-mode) .x { … }`
|
||||||
|
*inside* the `<style>` block.
|
||||||
|
2. **If a global `.css` is unavoidable, prefix EVERY class** with a component abbreviation
|
||||||
|
(`ah-col-id`, `il-incidents-table`). Vite bundles global CSS in dependency order; two components
|
||||||
|
sharing a generic class like `.col-id` → the last-bundled one silently wins, no warning. **Grep
|
||||||
|
for a class before adding `:global()`.**
|
||||||
|
3. **Always set `tbody tr` background explicitly in dark mode.** Any `overflow:auto` container
|
||||||
|
(`.table-wrapper`) creates an opaque scroll region — the card's dark bg does NOT show through, the
|
||||||
|
browser fills white. Set `:global(.dark-mode) tbody tr { background:#1f2937 }` (+ `:hover #374151`,
|
||||||
|
and `table`/`.table-wrapper` `background:transparent`). Every table, every time.
|
||||||
|
4. **Table `td` font-size is ALWAYS `var(--font-size-label)` (0.85rem)** — never `--font-size-body`
|
||||||
|
(0.95rem). The 0.95 vs 0.85 difference makes the whole table look ~12% larger than every other app.
|
||||||
|
|
||||||
|
## Data formatting
|
||||||
|
|
||||||
|
**`toLowerCase()` before title-casing enum strings.** Backend enums arrive as
|
||||||
|
`SCREAMING_SNAKE_CASE`; a title-case that skips lowercasing yields `CARD READER FAIL` (all-caps,
|
||||||
|
visually larger) instead of `Card Reader Fail`:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
type.replace(/_/g, ' ').toLowerCase().replace(/\b\w/g, c => c.toUpperCase()); // "Card Reader Fail"
|
||||||
|
```
|
||||||
|
|
||||||
|
## Header & structure (also enforced by the `svelte-template-lint` hook)
|
||||||
|
|
||||||
|
Header is **text only** — action buttons (Add/Refresh/Compose) go in `.toolbar-right` inside the
|
||||||
|
content frame, never in `.header`. Add/Edit forms are **slide-in panels**, not centered modals.
|
||||||
|
Locked structure: `.filter-sidebar` · `.content-frame` · `.table-card` border · active-filter chips ·
|
||||||
|
`Pagination` at top-of-table. New page → **copy** TablePage/TemplatePage first; existing page → verify
|
||||||
|
it conforms before building on it (many drifted).
|
||||||
Reference in New Issue
Block a user