Files
silo/docs/STYLE.md
Forbes 2585305590 fix(web): standardize button borderRadius, fontSize, fontWeight (#68)
All button style objects now use:
- borderRadius: 0.375rem
- fontSize: 0.75rem
- fontWeight: 500

Files: CreateItemPane, EditItemPane, DeleteItemPane, BOMTab,
CategoryPicker, ProjectsPage, SchemasPage, LoginPage,
ItemsToolbar, SettingsPage, ImportItemsPane, ItemTable

Closes #68
2026-02-13 13:21:54 -06:00

516 lines
16 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Silo Style Guide
> Living reference for the Silo web UI. All modules must follow these conventions to maintain visual consistency across the platform.
---
## Color System
Silo uses the [Catppuccin Mocha](https://github.com/catppuccin/catppuccin) palette exclusively. All colors are referenced via CSS custom properties defined at `:root`.
### Palette
```
--ctp-rosewater: #f5e0dc
--ctp-flamingo: #f2cdcd
--ctp-pink: #f5c2e7
--ctp-mauve: #cba6f7
--ctp-red: #f38ba8
--ctp-maroon: #eba0ac
--ctp-peach: #fab387
--ctp-yellow: #f9e2af
--ctp-green: #a6e3a1
--ctp-teal: #94e2d5
--ctp-sky: #89dceb
--ctp-sapphire: #74c7ec
--ctp-blue: #89b4fa
--ctp-lavender: #b4befe
--ctp-text: #cdd6f4
--ctp-subtext1: #bac2de
--ctp-subtext0: #a6adc8
--ctp-overlay2: #9399b2
--ctp-overlay1: #7f849c
--ctp-overlay0: #6c7086
--ctp-surface2: #585b70
--ctp-surface1: #45475a
--ctp-surface0: #313244
--ctp-base: #1e1e2e
--ctp-mantle: #181825
--ctp-crust: #11111b
```
### Semantic Roles
| Role | Token | Usage |
|------|-------|-------|
| Page background | `--ctp-base` | Main content area |
| Panel background | `--ctp-mantle` | Sidebars, detail panes, headers |
| Inset/input background | `--ctp-crust` | Form inputs, code blocks, drop zones |
| Primary accent | `--ctp-mauve` | Primary buttons, active states, links, selection highlights |
| Secondary accent | `--ctp-blue` | Informational highlights, secondary actions |
| Success | `--ctp-green` | Confirmations, positive status |
| Warning | `--ctp-yellow` | Caution states, pending actions |
| Danger | `--ctp-red` | Destructive actions, errors, required indicators |
| Informational | `--ctp-teal` | Auto-generated metadata, system-assigned values |
| Body text | `--ctp-text` | Primary content |
| Secondary text | `--ctp-subtext1` | Descriptions, timestamps |
| Muted text | `--ctp-overlay1` | Placeholders, disabled states |
| Borders | `--ctp-surface0` | Dividers, panel edges |
| Hover borders | `--ctp-surface1` | Interactive element borders, row separators |
| Focus ring | `rgba(203, 166, 247, 0.25)` | `box-shadow` on focused inputs (mauve at 25%) |
### Accent Usage for Data Types
| Data type | Color | Token |
|-----------|-------|-------|
| Assembly | `--ctp-mauve` | Badge, icon tint |
| Part | `--ctp-green` | Badge, icon tint |
| Document | `--ctp-blue` | Badge, icon tint |
| Purchased | `--ctp-peach` | Badge, icon tint |
| Phantom | `--ctp-overlay1` | Badge, icon tint |
These mappings are used anywhere item types appear: list badges, detail pane headers, BOM entries, tree views.
---
## Typography
### Scale
| Role | Size | Weight | Token/Color | Transform |
|------|------|--------|-------------|-----------|
| Page title | 1.1rem | 600 | `--ctp-text` | None |
| Section header | 11px | 600 | `--ctp-overlay0` | Uppercase, `letter-spacing: 0.06em` |
| Form label | 11px | 600 | `--ctp-overlay1` | Uppercase, `letter-spacing: 0.05em` |
| Body text | 13px | 400 | `--ctp-text` | None |
| Table cell | 12px | 400 | `--ctp-text` | None |
| Caption / metadata | 11px | 400 | `--ctp-subtext0` | None |
| Badge text | 10px | 600 | Varies | Uppercase |
| Breadcrumb segment | 13px | 500 | `--ctp-subtext1` | None |
| Breadcrumb active | 13px | 600 | `--ctp-text` | None |
### Font Stack
```css
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', system-ui, sans-serif;
```
No external font dependencies. System fonts ensure fast rendering and native feel across platforms.
### Rules
- Never use font sizes below 10px.
- Use `font-weight: 600` for emphasis instead of bold (700). Reserve 700 for page titles only when extra weight is needed.
- `text-transform: uppercase` is reserved for section headers, form labels, and badges. Never uppercase body text or descriptions.
---
## Spacing
Base unit: **4px**. All spacing values are multiples of 4.
| Token | Value | Usage |
|-------|-------|-------|
| `xs` | 4px (0.25rem) | Tight gaps: icon-to-label, tag internal padding |
| `sm` | 8px (0.5rem) | Compact spacing: between related fields, badge padding |
| `md` | 12px (0.75rem) | Standard: form group gaps, sidebar section padding |
| `lg` | 16px (1rem) | Section separation, card padding |
| `xl` | 24px (1.5rem) | Page-level padding, major section breaks |
| `2xl` | 32px (2rem) | Page horizontal padding |
### Application
- **Page padding:** `1.5rem 2rem` (24px vertical, 32px horizontal)
- **Sidebar section padding:** `1rem 1.25rem`
- **Form grid gap:** `1.25rem 1.5rem` (row gap × column gap)
- **Table row height:** 36px minimum (padding included)
- **Table cell padding:** `0.4rem 0.75rem`
---
## Layout
### Page Structure
Every module page follows the same shell:
```
┌─────────────────────────────────────────────────┐
│ Top Nav (52px) │
├──────────┬──────────────────────────────────────┤
│ App Menu │ Page Header (58px) │
│ (icons) ├──────────────────────┬───────────────┤
│ │ Content Area │ Detail Pane │
│ │ │ (360px) │
│ │ │ │
│ │ │ │
└──────────┴──────────────────────┴───────────────┘
```
- **Top nav:** `52px` height, `--ctp-mantle` background, `1px solid --ctp-surface0` bottom border.
- **App menu sidebar:** Icon strip on the left. Module icons, tooltips on hover. Active module highlighted with `--ctp-mauve` indicator.
- **Page header:** `58px` height, `--ctp-mantle` background. Contains page title (with module icon), action buttons right-aligned.
- **Content area:** `--ctp-base` background. Scrollable. Contains list views, kanban boards, or other primary content.
- **Detail pane:** `360px` fixed width, `--ctp-mantle` background, `1px solid --ctp-surface0` left border. Appears on record selection.
### Grid Patterns
**Two-column form:**
```css
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.25rem 1.5rem;
max-width: 800px;
```
**List + detail:**
```css
display: grid;
grid-template-columns: 1fr 360px;
min-height: calc(100vh - 52px - 58px);
```
### Breakpoints
Not currently required. Silo targets desktop browsers on engineering workstations. If mobile support is added later, breakpoints will be defined at `768px` and `1024px`.
---
## Components
### Buttons
Four tiers. All buttons share a base style:
```css
display: inline-flex;
align-items: center;
gap: 0.35rem;
padding: 0.4rem 0.85rem;
border-radius: 6px;
font-size: 12px;
font-weight: 500;
cursor: pointer;
transition: all 0.15s;
```
| Tier | Name | Background | Border | Text | Hover |
|------|------|-----------|--------|------|-------|
| Primary | `.btn-primary` | `--ctp-mauve` | `--ctp-mauve` | `--ctp-crust` | `--ctp-lavender` bg + border |
| Secondary | `.btn` (default) | `--ctp-surface0` | `--ctp-surface1` | `--ctp-text` | `--ctp-surface1` bg, `--ctp-overlay0` border |
| Ghost | `.btn-ghost` | transparent | transparent | `--ctp-subtext0` | `--ctp-surface0` bg, `--ctp-text` text |
| Danger | `.btn-danger` | transparent | `--ctp-surface1` | `--ctp-red` | `rgba(243, 139, 168, 0.1)` bg, `--ctp-red` border |
Primary is used once per visible context (the main action). All other actions use secondary or ghost. Danger is only for destructive actions and always requires confirmation.
### Badges
Used for type indicators, status labels, and tags.
```css
display: inline-flex;
align-items: center;
padding: 0.15rem 0.5rem;
border-radius: 4px;
font-size: 10px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.03em;
```
Badges use a translucent background derived from their accent color:
```css
/* Example: assembly badge */
background: rgba(203, 166, 247, 0.15); /* --ctp-mauve at 15% */
color: var(--ctp-mauve);
```
Standard badge colors follow the [accent usage table](#accent-usage-for-data-types). Status badges:
| Status | Color |
|--------|-------|
| Active / Released | `--ctp-green` |
| Draft / In Progress | `--ctp-blue` |
| Review / Pending | `--ctp-yellow` |
| Obsolete / Rejected | `--ctp-red` |
| Locked | `--ctp-overlay1` |
### Form Inputs
All inputs share a base style:
```css
background: var(--ctp-crust);
border: 1px solid var(--ctp-surface1);
border-radius: 6px;
padding: 0.45rem 0.65rem;
font-size: 12px;
color: var(--ctp-text);
transition: border-color 0.15s;
```
| State | Border | Shadow |
|-------|--------|--------|
| Default | `--ctp-surface1` | None |
| Hover | `--ctp-overlay0` | None |
| Focus | `--ctp-mauve` | `0 0 0 0.2rem rgba(203, 166, 247, 0.25)` |
| Error | `--ctp-red` | `0 0 0 0.2rem rgba(243, 139, 168, 0.15)` |
| Disabled | `--ctp-surface0` | None, `opacity: 0.5` |
Placeholder text: `--ctp-overlay0`. Labels sit above inputs (never inline or floating).
### Tag Input
Used for multi-value fields (projects, tags):
```css
display: flex;
flex-wrap: wrap;
gap: 0.3rem;
padding: 0.35rem 0.5rem;
background: var(--ctp-crust);
border: 1px solid var(--ctp-surface1);
border-radius: 6px;
min-height: 36px;
```
Individual tags use the badge pattern: `rgba(accent, 0.15)` background with accent text. Remove button (×) at `opacity: 0.6`, `1.0` on hover.
### Tables
```css
width: 100%;
border-collapse: collapse;
font-size: 12px;
```
| Element | Style |
|---------|-------|
| Header row | `background: --ctp-mantle`, `font-size: 11px`, uppercase, `--ctp-overlay1` text |
| Body row | `border-bottom: 1px solid --ctp-surface0` |
| Row hover | `background: --ctp-surface0` |
| Row selected | `background: rgba(203, 166, 247, 0.08)` |
| Cell padding | `0.4rem 0.75rem` |
| Text columns | Left-aligned |
| Number columns | Right-aligned |
| Date columns | Right-aligned |
| Action columns | Center-aligned |
Row actions use icon buttons (not text links). Icons at 14px, `--ctp-overlay1` default, `--ctp-text` on hover.
### Tabs
Used in detail panes and module sub-views:
```css
display: flex;
gap: 0;
border-bottom: 2px solid var(--ctp-surface0);
```
| State | Style |
|-------|-------|
| Default | `padding: 0.5rem 1rem`, `--ctp-subtext0` text, no border |
| Hover | `--ctp-text` text |
| Active | `--ctp-text` text, `font-weight: 600`, `border-bottom: 2px solid --ctp-mauve` (overlaps container border) |
### Section Dividers
Used to visually group form fields:
```css
display: flex;
align-items: center;
gap: 0.75rem;
grid-column: 1 / -1; /* span full form grid */
margin-top: 0.75rem;
```
Contains a label (`11px`, uppercase, `--ctp-overlay0`) and a horizontal line (`flex: 1`, `1px solid --ctp-surface0`).
### Sidebar Sections
Stacked vertically within detail panes:
```css
padding: 1rem 1.25rem;
border-bottom: 1px solid var(--ctp-surface0);
```
Last section has no bottom border. Section titles follow the section header typography (11px, uppercase, `--ctp-overlay0`).
### Tooltips
Appear on hover after a 300ms delay. Position: above the target element by default, flip below if insufficient space.
```css
background: var(--ctp-surface0);
border: 1px solid var(--ctp-surface1);
border-radius: 4px;
padding: 0.3rem 0.6rem;
font-size: 11px;
color: var(--ctp-text);
box-shadow: 0 4px 12px rgba(17, 17, 27, 0.4);
```
### Breadcrumbs
Module navigation breadcrumbs:
```
Module Name > List View > Record Name > Sub-view
```
Separator: `>` character in `--ctp-overlay0`. Segments are clickable links in `--ctp-subtext1`. Active (final) segment is `--ctp-text` at `font-weight: 600`.
### Dropdowns / Selects
Follow the input base style. The dropdown menu:
```css
background: var(--ctp-surface0);
border: 1px solid var(--ctp-surface1);
border-radius: 6px;
box-shadow: 0 8px 24px rgba(17, 17, 27, 0.5);
padding: 0.25rem;
max-height: 240px;
overflow-y: auto;
```
Menu items:
```css
padding: 0.4rem 0.65rem;
border-radius: 4px;
font-size: 12px;
color: var(--ctp-text);
cursor: pointer;
```
Hover: `background: --ctp-surface1`. Selected: `background: rgba(203, 166, 247, 0.12)`, `color: --ctp-mauve`, `font-weight: 600`.
---
## Icons
Use [Lucide](https://lucide.dev) icons. Size: 14px for inline/table contexts, 16px for buttons and navigation, 20px for page headers and empty states.
Stroke width: 1.5px (Lucide default). Color inherits from parent text color unless explicitly set.
Do not mix icon libraries. If Lucide does not have a suitable icon, request one be added or create a custom SVG following Lucide's 24×24 grid and stroke conventions.
---
## Transitions & Animation
All interactive state changes use `transition: all 0.15s ease`. This applies to hover, focus, active, and open/close states.
No entrance animations on page load. Content renders immediately. Skeleton loaders are acceptable for async data using a pulsing `--ctp-surface0``--ctp-surface1` gradient.
Dropdown menus and tooltips appear instantly (no slide/fade). Collapse/expand panels (if used) transition `max-height` at `0.2s ease`.
---
## Styling Implementation
Silo's React frontend uses **inline `React.CSSProperties` objects** with `var(--ctp-*)` token references. This is the project convention and must not be changed.
### Rules
- No CSS modules, no Tailwind, no external CSS-in-JS libraries.
- Styles are defined as `const` objects at the top of each component file.
- Shared style patterns (button base, input base) can be extracted to a `styles/` directory as exported `CSSProperties` objects.
- Use `as const` or `as React.CSSProperties` for type safety.
- Pseudo-classes (`:hover`, `:focus`) require state-driven inline styles or a thin CSS file for the base pseudo-class rules.
### Example
```typescript
const styles = {
container: {
display: 'grid',
gridTemplateColumns: '1fr 360px',
height: '100%',
overflow: 'hidden',
} as React.CSSProperties,
sidebar: {
background: 'var(--ctp-mantle)',
borderLeft: '1px solid var(--ctp-surface0)',
display: 'flex',
flexDirection: 'column' as const,
overflowY: 'auto' as const,
} as React.CSSProperties,
};
```
### Pseudo-class CSS
A single `silo-base.css` file provides pseudo-class rules that cannot be expressed inline:
```css
/* Hover, focus, and active states for core interactive elements */
.silo-input:hover { border-color: var(--ctp-overlay0); }
.silo-input:focus { border-color: var(--ctp-mauve); box-shadow: 0 0 0 0.2rem rgba(203, 166, 247, 0.25); }
.silo-btn:hover { /* per-tier overrides */ }
.silo-row:hover { background: var(--ctp-surface0); }
```
Components apply the corresponding class names alongside their inline styles. This is the only place class-based styling is used.
---
## Do / Don't
| Do | Don't |
|----|-------|
| Use `var(--ctp-*)` for every color | Hardcode hex values |
| Use the 4px spacing scale | Use arbitrary padding/margins |
| Use Lucide icons at standard sizes | Mix icon libraries |
| Use inline `CSSProperties` | Use CSS modules or Tailwind |
| One primary button per visible context | Multiple competing primary buttons |
| Use translucent accent backgrounds for badges | Use solid bright backgrounds for badges |
| Use icon buttons for row-level table actions | Use text links in table rows |
| Define styles as `const` at file top | Inline style objects in JSX |
| Show tooltips on icon-only buttons | Leave icon buttons unlabeled |
| Use section dividers to group form fields | Use cards or borders around field groups |
| Follow the breadcrumb pattern for navigation | Use nested tab bars |
---
## Appendix: CSS Custom Properties Block
Paste this at the root of the application stylesheet:
```css
:root {
--ctp-rosewater: #f5e0dc;
--ctp-flamingo: #f2cdcd;
--ctp-pink: #f5c2e7;
--ctp-mauve: #cba6f7;
--ctp-red: #f38ba8;
--ctp-maroon: #eba0ac;
--ctp-peach: #fab387;
--ctp-yellow: #f9e2af;
--ctp-green: #a6e3a1;
--ctp-teal: #94e2d5;
--ctp-sky: #89dceb;
--ctp-sapphire: #74c7ec;
--ctp-blue: #89b4fa;
--ctp-lavender: #b4befe;
--ctp-text: #cdd6f4;
--ctp-subtext1: #bac2de;
--ctp-subtext0: #a6adc8;
--ctp-overlay2: #9399b2;
--ctp-overlay1: #7f849c;
--ctp-overlay0: #6c7086;
--ctp-surface2: #585b70;
--ctp-surface1: #45475a;
--ctp-surface0: #313244;
--ctp-base: #1e1e2e;
--ctp-mantle: #181825;
--ctp-crust: #11111b;
}
```