docs(guide): add platform.frontend-template module (#14)
CD - Develop (guide → bcos.dev) / build-and-deploy (push) Failing after 31m32s
CD - Develop (guide → bcos.dev) / build-and-deploy (push) Failing after 31m32s
Guide had no coverage for hiveops-template, so the copy-don't-rewrite rule and the TemplatePage-vs-TablePage decision were only in a stale CLAUDE.md. - decision table for which page to copy; ask the user when not obvious - assigned dev ports read from the actual vite configs (next free = 5191; CLAUDE.md still claims 5180, which is adoons) - canonical .page-right spacing is 0.65rem/0.5rem, not the documented 1rem/0.75rem - dark-mode filter-header values + collapsed-by-default sidebar Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,129 @@
|
||||
---
|
||||
module: platform.frontend-template
|
||||
title: Frontend Template — starting a new SPA
|
||||
tab: Overview
|
||||
order: 55
|
||||
audience: dev
|
||||
---
|
||||
|
||||
> **Repo:** `hiveops-template` · **Live component demos:** `design-system.html` (open in a browser)
|
||||
>
|
||||
> Every HiveIQ SPA starts as a copy of this repo. It is a scaffold, not a deployed service — it has
|
||||
> no endpoints, tables, or Kafka topics.
|
||||
|
||||
## Which page do I copy?
|
||||
|
||||
| Your page has… | Copy |
|
||||
|---|---|
|
||||
| severity/status badges (incidents, alerts, events) | `TemplatePage.svelte` |
|
||||
| a plain list/table, no badges | `TablePage.svelte` |
|
||||
|
||||
**If the request does not make this obvious, ASK the user which one before copying. Do not guess.**
|
||||
A page copied from the wrong base has to be rebuilt — the two differ in the badge colour maps and in
|
||||
the filter-chip markup, not just in styling.
|
||||
|
||||
## COPY, do not rewrite
|
||||
|
||||
Never write a new page from scratch. Physically copy the canonical file, then edit it:
|
||||
|
||||
```bash
|
||||
cp /source/hiveops-src/hiveops-template/frontend/src/components/TemplatePage.svelte \
|
||||
/source/hiveops-src/hiveops-MYAPP/frontend/src/components/MyPage.svelte
|
||||
```
|
||||
|
||||
Only these things may change in the copied file:
|
||||
|
||||
1. Page `<h1>` title and `<p>` subtitle in the header
|
||||
2. The `ALL_ITEMS` array and its interface → your data type and real API call
|
||||
3. Table columns (`<th>` / `<td>`) → your fields
|
||||
4. Filter `<select>` options → your filter values
|
||||
5. The `SEV_DOT` / `STS_DOT` colour maps → your badge colours
|
||||
6. The slide-in panel fields → your Add/Edit form fields
|
||||
|
||||
Never rewrite or replace these — they are tuned and they break silently:
|
||||
|
||||
| Component | Reason |
|
||||
|---|---|
|
||||
| `.filter-sidebar` HTML + CSS | Exact structure required; pills break the layout |
|
||||
| `.active-filters` + `.filter-tag` chips | The `border-left-color` accent is specific |
|
||||
| `.content-frame` + `.page-right` structure | Padding/gap must match the form-card |
|
||||
| `.table-card` border | Always `1px solid #e5e7eb` — never override in dark mode |
|
||||
| All `:global(.dark-mode)` rules | Tuned; do not remove or rewrite |
|
||||
| `Pagination` placement | Top of `.table-card`, never below |
|
||||
|
||||
### Canonical spacing (code, not docs)
|
||||
|
||||
`.page-right` is `padding: 0.65rem; gap: 0.5rem`, and `.content-frame` carries **no** `margin-top` —
|
||||
the `gap` provides that spacing. Setting both double-spaces the frame.
|
||||
|
||||
> The `hiveops-template/CLAUDE.md` table still says `padding: 1rem; gap: 0.75rem`. That is stale.
|
||||
> The `.svelte` source is the truth.
|
||||
|
||||
### Filter sidebar defaults
|
||||
|
||||
`let filterSidebarCollapsed = true;` — the sidebar starts collapsed on every page. Light-mode filter
|
||||
header CSS is identical across both templates. In dark mode the active-filter bar stays neutral
|
||||
(`#111827`, border `#374151`) with a muted-gray `#9ca3af` label — it does **not** turn blue, and the
|
||||
label and toggle button both need `!important` to hold that colour.
|
||||
|
||||
## Starting a new app
|
||||
|
||||
```bash
|
||||
cp -r /source/hiveops-src/hiveops-template/frontend /source/hiveops-src/hiveops-MYAPP/frontend
|
||||
```
|
||||
|
||||
Search `APPNAME` to find every placeholder, then edit:
|
||||
|
||||
- `frontend/package.json` → `"name": "hiveops-MYAPP-frontend"`
|
||||
- `frontend/vite.config.ts` → `port:` (see below — **the template ships on 5179, which collides with claims**)
|
||||
- `frontend/Dockerfile` → `EXPOSE` + `CMD` port
|
||||
- `frontend/index.html` → `<title>`
|
||||
- `frontend/src/App.svelte` → `FAV_KEY` localStorage key, imports, nav groups, views
|
||||
- `build.sh` → `IMAGE_NAME="hiveiq-MYAPP-frontend"`
|
||||
|
||||
Do **not** remove `src/vite-env.d.ts`. It declares `__APP_VERSION__`, which `vite.config.ts` defines
|
||||
from `package.json`; without it `svelte-check` errors. Delete `src/components/ExampleView/` once your
|
||||
real views exist.
|
||||
|
||||
### Assigned dev ports
|
||||
|
||||
Read from each app's `vite.config.ts` (verified 2026-07-09), not from any CLAUDE.md:
|
||||
|
||||
| Port | App | Port | App |
|
||||
|---|---|---|---|
|
||||
| 5173 | incident | 5182 | reports |
|
||||
| 5174 | analytics | 5183 | website |
|
||||
| 5175 | recon | 5184 | profile |
|
||||
| 5176 | fleet | 5185 | vault |
|
||||
| 5177 | devices | 5186 | msp |
|
||||
| 5178 | transactions | 5187 | aria |
|
||||
| 5179 | claims | 5188 | guide |
|
||||
| 5180 | adoons | 5190 | feedback |
|
||||
| 5181 | dashboard | | |
|
||||
|
||||
**5189 is free; the next new app takes 5191.** The template itself is checked in on 5179 as a
|
||||
placeholder — always change it as the first edit after copying.
|
||||
|
||||
## Verify before finishing
|
||||
|
||||
Open the page **in dark mode** and confirm all six:
|
||||
|
||||
1. Filter sidebar collapses/expands
|
||||
2. Selecting a filter shows a colored chip ABOVE the content frame, with a visible gap
|
||||
3. The chip has a thick colored left border — not a pill, not a badge
|
||||
4. Toolbar (`N records` + action button) is INSIDE the white-bordered content frame
|
||||
5. Pagination is at the TOP of the table, inside the frame
|
||||
6. Sidebar labels (SEARCH, SEVERITY, STATUS) are muted gray, not white
|
||||
|
||||
Frontend work is never committed unverified — render it, let the user confirm, then commit.
|
||||
|
||||
## Gotchas
|
||||
|
||||
- **CSS lives in the Svelte `<style>` block.** Never `import './X.css'` — global CSS bleeds by Vite
|
||||
bundle order and the last-loaded duplicate class silently wins.
|
||||
- **Dark mode needs explicit `tbody tr` backgrounds.** `overflow: auto` makes an opaque region; the
|
||||
parent card's dark background does not show through.
|
||||
- **`td` font-size is always `var(--font-size-label)`** (0.85rem), never `--font-size-body`.
|
||||
- **`html, body` must set `font-size: 14px`** — every `rem` in the design system depends on it.
|
||||
- **Never add a local `.header {}` block** — it overrides the global gradient in `App.svelte`.
|
||||
- **`toLowerCase()` before title-casing enums**, or `CARD_READER_FAIL` renders as all-caps.
|
||||
Reference in New Issue
Block a user