# Frontend Development Standards ## Naming Convention (LOCKED) The shopdb-flask naming convention lives in the root `CONTRIBUTING.md`. Read it before naming any variable, component, API param, or CSS class. Frontend-specific reminders pulled from the convention: - Variables holding API field values: match the API field name exactly. Do NOT convert to camelCase. (`response.machineid`, NOT `response.machineId`) - Pure JS variables: camelCase (`currentUser`, `isLoading`) - Vue components: PascalCase, spelled out (`AssetDetail.vue`, `MachineForm.vue`) - CSS classes: lowercase with dashes (`asset-detail`, `machine-form`) - API params sent to backend: match DB column names without underscores (`params.locationid = 5`, NOT `params.location_id`) - No emojis, em-dashes, smart quotes, or Unicode arrows anywhere. Plain ASCII only. - Banned shorthand as standalone variables: `cfg`, `ctx`, `mgr`, `req`, `res`, `env`, `util`, `helper`. Spell them out (`canvasContext`, `response`, `manager`, etc.). Suffix usage like `printers_bp` is allowed. Pre-commit hook at `scripts/check-naming-and-style.sh` enforces these rules. ## CSS Styling Standards ### Use CSS Variables for ALL Colors **NEVER hardcode colors in component styles.** Always use CSS variables defined in `src/assets/style.css`. Available variables: ```css --primary /* Primary brand color */ --primary-dark /* Darker primary for hover states */ --secondary /* Secondary/muted color */ --success /* Success states (green) */ --warning /* Warning states (orange) */ --danger /* Error/danger states (red) */ --bg /* Page background */ --bg-card /* Card/panel background */ --text /* Primary text color */ --text-light /* Secondary/muted text */ --border /* Border color */ --link /* Link color (bright blue in dark mode) */ ``` **Bad:** ```css .my-card { background: white; color: #1a1a1a; } ``` **Good:** ```css .my-card { background: var(--bg-card); color: var(--text); } ``` ### Detail Pages - Use Global Styles All detail pages (MachineDetail, PCDetail, PrinterDetail, ApplicationDetail) should use the **unified global styles** from `style.css`: - `.detail-page` - Container wrapper - `.hero-card` - Main hero section with image and info - `.hero-image`, `.hero-content`, `.hero-title`, `.hero-meta`, `.hero-details` - `.section-card` - Info sections - `.section-title` - Section headers - `.info-list`, `.info-row`, `.info-label`, `.info-value` - `.content-grid`, `.content-column` - Two-column layout - `.audit-footer` - Created/modified timestamps **Only add scoped styles for page-specific elements** (e.g., supplies grid for printers, version list for applications). ### PrinterDetail.vue is the Master Template for Detail Pages Use `PrinterDetail.vue` as the reference for new detail pages. Follow its structure and styling patterns. ### List Pages - Use Global Styles All list pages should use the **unified global styles** from `style.css`: - `.page-header` - Header with title and action button - `.filters` - Search and filter controls - `.card` - Main content container - `.table-container` - Scrollable table wrapper - `table`, `th`, `td` - Table styling - `.pagination` - Page navigation - `.badge`, `.badge-success`, etc. - Status badges - `.actions` - Action button column **PrintersList.vue is the Master Template for List Pages** Use `PrintersList.vue` as the reference for new list pages. It has NO scoped styles - everything uses global CSS. **Only add scoped styles for page-specific elements** (e.g., icon cells for applications, stats badge for knowledge base). ### Dark Mode Support Dark mode is automatic via `@media (prefers-color-scheme: dark)`. Using CSS variables ensures colors adapt automatically - no extra work needed per page. ## Data Entry: Page or Modal Both patterns are in use on purpose. Pick by what the record IS, not by how big the form feels today. **Routed form page** (`views/Form.vue` + a route) when the record has its own detail page and its own URL: machines, PCs, printers, network devices, measuring tools, USB devices, applications, knowledge-base articles, notifications, printed items. These forms are long, often carry an image upload, a map-position picker or relationship editing, and someone will want to link straight to one. **Modal over its list** when the record is reference data that only exists inside the list it belongs to: every `*TypesList`, plus locations, vendors, models, VLANs, subnets, support teams, custom fields, API tokens, printer drivers, dashboard defaults. The form is a handful of fields, and keeping the list visible behind the dialog is the point. Rule of thumb: **a thing with a detail page gets a form page; a lookup row gets a modal.** Modal rules (from the overlay-close fix, commit d8fe0a4): - A modal holding typed input must NOT close on overlay click or Escape. Losing a part-filled form to a stray click is not an acceptable failure. - A confirmation dialog MAY close on overlay click (`@click.self`), since it holds nothing to lose. - The panel background is `var(--bg-card-solid)`, never `var(--bg-card)`: the card variable is translucent in dark mode, which leaves a dialog see-through over the overlay. The shared `.modal` in `style.css` already does this; hand-rolled `.modal-panel` rules must too. ## Component Organization - **Global styles**: `src/assets/style.css` - **Page-specific styles**: Scoped `