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
516 lines
16 KiB
Markdown
516 lines
16 KiB
Markdown
# 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;
|
||
}
|
||
```
|