--bg-card is deliberately translucent in dark mode (rgba(0,0,61,0.4)) so cards glass over the page; --bg-card-solid exists for the things that must not. Two hand-rolled modal panels used the former, leaving the notification-type and access-protocol editors transparent over the overlay with the table legible through them. The shared .modal in style.css already got this right. Also writes down the page-vs-modal rule the codebase already follows, since nothing stated it: a record with a detail page gets a routed form page, a lookup row that only exists inside its list gets a modal over that list. Plus the modal rules from the overlay-close fix - data entry never closes on a stray click, confirmations may, and panels are painted solid.
137 lines
6.0 KiB
Markdown
137 lines
6.0 KiB
Markdown
# 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/<Thing>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 `<style scoped>` block, only for unique elements
|
|
- **Font sizes**: Use `rem` units, base is 18px for readability on 1080p
|
|
|
|
## File Structure
|
|
|
|
```
|
|
src/
|
|
assets/
|
|
style.css # Global styles, CSS variables, detail page styles
|
|
views/
|
|
machines/
|
|
MachineDetail.vue # Uses global styles only
|
|
pcs/
|
|
PCDetail.vue # Global + PC-specific (app-list, etc.)
|
|
printers/
|
|
PrinterDetail.vue # Global + printer-specific (supplies-grid)
|
|
applications/
|
|
ApplicationDetail.vue # Global + app-specific (version-list, pc-list)
|
|
```
|