Files
shopdb-flask/frontend/CLAUDE.md
cproudlock 245f94d344
Some checks failed
CI / backend (push) Failing after 8s
CI / naming (push) Successful in 2s
CI / frontend (push) Successful in 8s
CI / migrations-mysql (push) Failing after 7s
Stop two dialogs going see-through in dark mode
--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.
2026-08-07 10:30:45 -04:00

6.0 KiB

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:

--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:

.my-card {
  background: white;
  color: #1a1a1a;
}

Good:

.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)