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
This commit is contained in:
Forbes
2026-02-13 13:21:54 -06:00
parent 65063c9ee7
commit 2585305590
13 changed files with 716 additions and 90 deletions

515
docs/STYLE.md Normal file
View File

@@ -0,0 +1,515 @@
# 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;
}
```

View File

@@ -422,9 +422,10 @@ const tdStyle: React.CSSProperties = {
const toolBtnStyle: React.CSSProperties = { const toolBtnStyle: React.CSSProperties = {
padding: "0.25rem 0.5rem", padding: "0.25rem 0.5rem",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.3rem", borderRadius: "0.375rem",
backgroundColor: "var(--ctp-surface1)", backgroundColor: "var(--ctp-surface1)",
color: "var(--ctp-text)", color: "var(--ctp-text)",
cursor: "pointer", cursor: "pointer",
@@ -436,14 +437,17 @@ const actionBtnStyle: React.CSSProperties = {
color: "var(--ctp-subtext1)", color: "var(--ctp-subtext1)",
cursor: "pointer", cursor: "pointer",
fontSize: "0.75rem", fontSize: "0.75rem",
fontWeight: 500,
padding: "0.1rem 0.3rem", padding: "0.1rem 0.3rem",
borderRadius: "0.375rem",
}; };
const saveBtnStyle: React.CSSProperties = { const saveBtnStyle: React.CSSProperties = {
padding: "0.2rem 0.4rem", padding: "0.2rem 0.4rem",
fontSize: "0.75rem", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.25rem", borderRadius: "0.375rem",
backgroundColor: "var(--ctp-green)", backgroundColor: "var(--ctp-green)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
cursor: "pointer", cursor: "pointer",
@@ -472,8 +476,9 @@ const manualBadge: React.CSSProperties = {
const cancelBtnStyle: React.CSSProperties = { const cancelBtnStyle: React.CSSProperties = {
padding: "0.2rem 0.4rem", padding: "0.2rem 0.4rem",
fontSize: "0.75rem", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.25rem", borderRadius: "0.375rem",
backgroundColor: "var(--ctp-surface1)", backgroundColor: "var(--ctp-surface1)",
color: "var(--ctp-subtext1)", color: "var(--ctp-subtext1)",
cursor: "pointer", cursor: "pointer",

View File

@@ -96,10 +96,10 @@ export function CategoryPicker({
}} }}
style={{ style={{
padding: "0.2rem 0.5rem", padding: "0.2rem 0.5rem",
fontSize: "0.7rem", fontSize: "0.75rem",
fontWeight: isActive ? 600 : 400, fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.25rem", borderRadius: "0.375rem",
cursor: "pointer", cursor: "pointer",
backgroundColor: isActive backgroundColor: isActive
? "rgba(203,166,247,0.2)" ? "rgba(203,166,247,0.2)"

View File

@@ -671,9 +671,10 @@ const headerStyle: React.CSSProperties = {
const actionBtnStyle: React.CSSProperties = { const actionBtnStyle: React.CSSProperties = {
padding: "0.3rem 0.75rem", padding: "0.3rem 0.75rem",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.3rem", borderRadius: "0.375rem",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
cursor: "pointer", cursor: "pointer",
}; };
@@ -683,8 +684,10 @@ const cancelBtnStyle: React.CSSProperties = {
border: "none", border: "none",
cursor: "pointer", cursor: "pointer",
color: "var(--ctp-subtext1)", color: "var(--ctp-subtext1)",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
padding: "0.2rem 0.4rem", padding: "0.2rem 0.4rem",
borderRadius: "0.375rem",
}; };
const inputStyle: React.CSSProperties = { const inputStyle: React.CSSProperties = {

View File

@@ -1,5 +1,5 @@
import { useState } from 'react'; import { useState } from "react";
import { del } from '../../api/client'; import { del } from "../../api/client";
interface DeleteItemPaneProps { interface DeleteItemPaneProps {
partNumber: string; partNumber: string;
@@ -7,7 +7,11 @@ interface DeleteItemPaneProps {
onCancel: () => void; onCancel: () => void;
} }
export function DeleteItemPane({ partNumber, onDeleted, onCancel }: DeleteItemPaneProps) { export function DeleteItemPane({
partNumber,
onDeleted,
onCancel,
}: DeleteItemPaneProps) {
const [deleting, setDeleting] = useState(false); const [deleting, setDeleting] = useState(false);
const [error, setError] = useState<string | null>(null); const [error, setError] = useState<string | null>(null);
@@ -18,59 +22,133 @@ export function DeleteItemPane({ partNumber, onDeleted, onCancel }: DeleteItemPa
await del(`/api/items/${encodeURIComponent(partNumber)}`); await del(`/api/items/${encodeURIComponent(partNumber)}`);
onDeleted(); onDeleted();
} catch (e) { } catch (e) {
setError(e instanceof Error ? e.message : 'Failed to delete item'); setError(e instanceof Error ? e.message : "Failed to delete item");
} finally { } finally {
setDeleting(false); setDeleting(false);
} }
}; };
return ( return (
<div style={{ display: 'flex', flexDirection: 'column', height: '100%' }}> <div style={{ display: "flex", flexDirection: "column", height: "100%" }}>
<div style={{ <div
display: 'flex', alignItems: 'center', gap: '0.75rem', style={{
padding: '0.5rem 0.75rem', display: "flex",
borderBottom: '1px solid var(--ctp-surface1)', alignItems: "center",
backgroundColor: 'var(--ctp-mantle)', gap: "0.75rem",
flexShrink: 0, padding: "0.5rem 0.75rem",
}}> borderBottom: "1px solid var(--ctp-surface1)",
<span style={{ color: 'var(--ctp-red)', fontWeight: 600, fontSize: '0.9rem' }}>Delete Item</span> backgroundColor: "var(--ctp-mantle)",
flexShrink: 0,
}}
>
<span
style={{
color: "var(--ctp-red)",
fontWeight: 600,
fontSize: "0.9rem",
}}
>
Delete Item
</span>
<span style={{ flex: 1 }} /> <span style={{ flex: 1 }} />
<button onClick={onCancel} style={headerBtnStyle}>Cancel</button> <button onClick={onCancel} style={headerBtnStyle}>
Cancel
</button>
</div> </div>
<div style={{ flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', padding: '2rem', gap: '1rem' }}> <div
style={{
flex: 1,
display: "flex",
flexDirection: "column",
alignItems: "center",
justifyContent: "center",
padding: "2rem",
gap: "1rem",
}}
>
{error && ( {error && (
<div style={{ color: 'var(--ctp-red)', backgroundColor: 'rgba(243,139,168,0.1)', padding: '0.5rem 1rem', borderRadius: '0.3rem', fontSize: '0.85rem', width: '100%', textAlign: 'center' }}> <div
style={{
color: "var(--ctp-red)",
backgroundColor: "rgba(243,139,168,0.1)",
padding: "0.5rem 1rem",
borderRadius: "0.3rem",
fontSize: "0.85rem",
width: "100%",
textAlign: "center",
}}
>
{error} {error}
</div> </div>
)} )}
<div style={{ textAlign: 'center' }}> <div style={{ textAlign: "center" }}>
<p style={{ fontSize: '0.9rem', color: 'var(--ctp-text)', marginBottom: '0.5rem' }}> <p
style={{
fontSize: "0.9rem",
color: "var(--ctp-text)",
marginBottom: "0.5rem",
}}
>
Permanently delete item Permanently delete item
</p> </p>
<p style={{ fontFamily: "'JetBrains Mono', monospace", color: 'var(--ctp-peach)', fontSize: '1.1rem', fontWeight: 600 }}> <p
style={{
fontFamily: "'JetBrains Mono', monospace",
color: "var(--ctp-peach)",
fontSize: "1.1rem",
fontWeight: 600,
}}
>
{partNumber} {partNumber}
</p> </p>
</div> </div>
<p style={{ color: 'var(--ctp-subtext0)', fontSize: '0.85rem', textAlign: 'center', maxWidth: 300 }}> <p
This will permanently remove this item, all its revisions, BOM entries, and file attachments. This action cannot be undone. style={{
color: "var(--ctp-subtext0)",
fontSize: "0.85rem",
textAlign: "center",
maxWidth: 300,
}}
>
This will permanently remove this item, all its revisions, BOM
entries, and file attachments. This action cannot be undone.
</p> </p>
<div style={{ display: 'flex', gap: '0.75rem', marginTop: '0.5rem' }}> <div style={{ display: "flex", gap: "0.75rem", marginTop: "0.5rem" }}>
<button onClick={onCancel} style={{ <button
padding: '0.5rem 1.25rem', fontSize: '0.85rem', border: 'none', borderRadius: '0.4rem', onClick={onCancel}
backgroundColor: 'var(--ctp-surface1)', color: 'var(--ctp-text)', cursor: 'pointer', style={{
}}> padding: "0.5rem 1.25rem",
fontSize: "0.75rem",
fontWeight: 500,
border: "none",
borderRadius: "0.375rem",
backgroundColor: "var(--ctp-surface1)",
color: "var(--ctp-text)",
cursor: "pointer",
}}
>
Cancel Cancel
</button> </button>
<button onClick={() => void handleDelete()} disabled={deleting} style={{ <button
padding: '0.5rem 1.25rem', fontSize: '0.85rem', border: 'none', borderRadius: '0.4rem', onClick={() => void handleDelete()}
backgroundColor: 'var(--ctp-red)', color: 'var(--ctp-crust)', cursor: 'pointer', disabled={deleting}
opacity: deleting ? 0.6 : 1, style={{
}}> padding: "0.5rem 1.25rem",
{deleting ? 'Deleting...' : 'Delete Permanently'} fontSize: "0.75rem",
fontWeight: 500,
border: "none",
borderRadius: "0.375rem",
backgroundColor: "var(--ctp-red)",
color: "var(--ctp-crust)",
cursor: "pointer",
opacity: deleting ? 0.6 : 1,
}}
>
{deleting ? "Deleting..." : "Delete Permanently"}
</button> </button>
</div> </div>
</div> </div>
@@ -79,6 +157,12 @@ export function DeleteItemPane({ partNumber, onDeleted, onCancel }: DeleteItemPa
} }
const headerBtnStyle: React.CSSProperties = { const headerBtnStyle: React.CSSProperties = {
background: 'none', border: 'none', cursor: 'pointer', background: "none",
color: 'var(--ctp-subtext1)', fontSize: '0.8rem', padding: '0.2rem 0.4rem', border: "none",
cursor: "pointer",
color: "var(--ctp-subtext1)",
fontSize: "0.75rem",
fontWeight: 500,
padding: "0.2rem 0.4rem",
borderRadius: "0.375rem",
}; };

View File

@@ -90,9 +90,10 @@ export function EditItemPane({
disabled={saving} disabled={saving}
style={{ style={{
padding: "0.3rem 0.75rem", padding: "0.3rem 0.75rem",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.3rem", borderRadius: "0.375rem",
backgroundColor: "var(--ctp-blue)", backgroundColor: "var(--ctp-blue)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
cursor: "pointer", cursor: "pointer",
@@ -215,6 +216,8 @@ const headerBtnStyle: React.CSSProperties = {
border: "none", border: "none",
cursor: "pointer", cursor: "pointer",
color: "var(--ctp-subtext1)", color: "var(--ctp-subtext1)",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
padding: "0.2rem 0.4rem", padding: "0.2rem 0.4rem",
borderRadius: "0.375rem",
}; };

View File

@@ -185,9 +185,10 @@ export function ImportItemsPane({
disabled={!file || importing} disabled={!file || importing}
style={{ style={{
padding: "0.4rem 0.75rem", padding: "0.4rem 0.75rem",
fontSize: "0.85rem", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.3rem", borderRadius: "0.375rem",
backgroundColor: "var(--ctp-yellow)", backgroundColor: "var(--ctp-yellow)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
cursor: "pointer", cursor: "pointer",
@@ -202,9 +203,10 @@ export function ImportItemsPane({
disabled={importing || (result?.error_count ?? 0) > 0} disabled={importing || (result?.error_count ?? 0) > 0}
style={{ style={{
padding: "0.4rem 0.75rem", padding: "0.4rem 0.75rem",
fontSize: "0.85rem", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.3rem", borderRadius: "0.375rem",
backgroundColor: "var(--ctp-green)", backgroundColor: "var(--ctp-green)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
cursor: "pointer", cursor: "pointer",
@@ -289,6 +291,8 @@ const headerBtnStyle: React.CSSProperties = {
border: "none", border: "none",
cursor: "pointer", cursor: "pointer",
color: "var(--ctp-subtext1)", color: "var(--ctp-subtext1)",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
padding: "0.2rem 0.4rem", padding: "0.2rem 0.4rem",
borderRadius: "0.375rem",
}; };

View File

@@ -385,7 +385,8 @@ const actionBtnStyle: React.CSSProperties = {
border: "none", border: "none",
color: "var(--ctp-subtext1)", color: "var(--ctp-subtext1)",
cursor: "pointer", cursor: "pointer",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
padding: "0.15rem 0.4rem", padding: "0.15rem 0.4rem",
borderRadius: "0.25rem", borderRadius: "0.375rem",
}; };

View File

@@ -37,9 +37,10 @@ export function ItemsToolbar({
onClick={() => onFilterChange({ searchScope: scope })} onClick={() => onFilterChange({ searchScope: scope })}
style={{ style={{
padding: "var(--d-input-py) var(--d-input-px)", padding: "var(--d-input-py) var(--d-input-px)",
fontSize: "var(--d-input-font)", fontSize: "0.75rem",
fontWeight: 500,
border: "none", border: "none",
borderRadius: "0.3rem", borderRadius: "0.375rem",
cursor: "pointer", cursor: "pointer",
backgroundColor: backgroundColor:
filters.searchScope === scope filters.searchScope === scope
@@ -173,8 +174,9 @@ const toolBtnStyle: React.CSSProperties = {
padding: "var(--d-input-py) var(--d-input-px)", padding: "var(--d-input-py) var(--d-input-px)",
backgroundColor: "var(--ctp-surface1)", backgroundColor: "var(--ctp-surface1)",
border: "none", border: "none",
borderRadius: "0.4rem", borderRadius: "0.375rem",
color: "var(--ctp-text)", color: "var(--ctp-text)",
fontSize: "var(--d-input-font)", fontSize: "0.75rem",
fontWeight: 500,
cursor: "pointer", cursor: "pointer",
}; };

View File

@@ -162,9 +162,9 @@ const btnPrimaryStyle: React.CSSProperties = {
display: "block", display: "block",
width: "100%", width: "100%",
padding: "0.75rem 1.5rem", padding: "0.75rem 1.5rem",
borderRadius: "0.5rem", borderRadius: "0.375rem",
fontWeight: 600, fontWeight: 500,
fontSize: "1rem", fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
border: "none", border: "none",
backgroundColor: "var(--ctp-mauve)", backgroundColor: "var(--ctp-mauve)",
@@ -187,9 +187,9 @@ const btnOidcStyle: React.CSSProperties = {
display: "block", display: "block",
width: "100%", width: "100%",
padding: "0.75rem 1.5rem", padding: "0.75rem 1.5rem",
borderRadius: "0.5rem", borderRadius: "0.375rem",
fontWeight: 600, fontWeight: 500,
fontSize: "1rem", fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
border: "none", border: "none",
backgroundColor: "var(--ctp-blue)", backgroundColor: "var(--ctp-blue)",

View File

@@ -443,43 +443,45 @@ export function ProjectsPage() {
// Styles // Styles
const btnPrimaryStyle: React.CSSProperties = { const btnPrimaryStyle: React.CSSProperties = {
padding: "0.5rem 1rem", padding: "0.5rem 1rem",
borderRadius: "0.4rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-mauve)", backgroundColor: "var(--ctp-mauve)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
fontWeight: 600, fontWeight: 500,
fontSize: "0.85rem", fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
}; };
const btnSecondaryStyle: React.CSSProperties = { const btnSecondaryStyle: React.CSSProperties = {
padding: "0.5rem 1rem", padding: "0.5rem 1rem",
borderRadius: "0.4rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-surface1)", backgroundColor: "var(--ctp-surface1)",
color: "var(--ctp-text)", color: "var(--ctp-text)",
fontSize: "0.85rem", fontWeight: 500,
fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
}; };
const btnDangerStyle: React.CSSProperties = { const btnDangerStyle: React.CSSProperties = {
padding: "0.5rem 1rem", padding: "0.5rem 1rem",
borderRadius: "0.4rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-red)", backgroundColor: "var(--ctp-red)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
fontWeight: 600, fontWeight: 500,
fontSize: "0.85rem", fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
}; };
const btnSmallStyle: React.CSSProperties = { const btnSmallStyle: React.CSSProperties = {
padding: "0.3rem 0.6rem", padding: "0.3rem 0.6rem",
borderRadius: "0.3rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-surface1)", backgroundColor: "var(--ctp-surface1)",
color: "var(--ctp-text)", color: "var(--ctp-text)",
fontSize: "0.8rem", fontWeight: 500,
fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
}; };
@@ -504,8 +506,9 @@ const formCloseStyle: React.CSSProperties = {
border: "none", border: "none",
color: "inherit", color: "inherit",
cursor: "pointer", cursor: "pointer",
fontSize: "0.85rem", fontSize: "0.75rem",
fontWeight: 600, fontWeight: 500,
borderRadius: "0.375rem",
}; };
const errorBannerStyle: React.CSSProperties = { const errorBannerStyle: React.CSSProperties = {

View File

@@ -706,22 +706,23 @@ const tdStyle: React.CSSProperties = {
const btnTinyStyle: React.CSSProperties = { const btnTinyStyle: React.CSSProperties = {
padding: "0.2rem 0.5rem", padding: "0.2rem 0.5rem",
borderRadius: "0.25rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-surface1)", backgroundColor: "var(--ctp-surface1)",
color: "var(--ctp-text)", color: "var(--ctp-text)",
fontSize: "0.75rem", fontSize: "0.75rem",
fontWeight: 500,
cursor: "pointer", cursor: "pointer",
}; };
const btnTinyPrimaryStyle: React.CSSProperties = { const btnTinyPrimaryStyle: React.CSSProperties = {
padding: "0.2rem 0.5rem", padding: "0.2rem 0.5rem",
borderRadius: "0.25rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-mauve)", backgroundColor: "var(--ctp-mauve)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
fontSize: "0.75rem", fontSize: "0.75rem",
fontWeight: 600, fontWeight: 500,
cursor: "pointer", cursor: "pointer",
}; };

View File

@@ -404,12 +404,12 @@ const inputStyle: React.CSSProperties = {
const btnPrimaryStyle: React.CSSProperties = { const btnPrimaryStyle: React.CSSProperties = {
padding: "0.5rem 1rem", padding: "0.5rem 1rem",
borderRadius: "0.4rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-mauve)", backgroundColor: "var(--ctp-mauve)",
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
fontWeight: 600, fontWeight: 500,
fontSize: "0.85rem", fontSize: "0.75rem",
cursor: "pointer", cursor: "pointer",
whiteSpace: "nowrap", whiteSpace: "nowrap",
}; };
@@ -418,19 +418,22 @@ const btnCopyStyle: React.CSSProperties = {
padding: "0.4rem 0.75rem", padding: "0.4rem 0.75rem",
background: "var(--ctp-surface1)", background: "var(--ctp-surface1)",
border: "none", border: "none",
borderRadius: "0.4rem", borderRadius: "0.375rem",
color: "var(--ctp-text)", color: "var(--ctp-text)",
cursor: "pointer", cursor: "pointer",
fontSize: "0.85rem", fontSize: "0.75rem",
fontWeight: 500,
}; };
const btnDismissStyle: React.CSSProperties = { const btnDismissStyle: React.CSSProperties = {
padding: "0.4rem 0.75rem", padding: "0.4rem 0.75rem",
background: "none", background: "none",
border: "none", border: "none",
borderRadius: "0.375rem",
color: "var(--ctp-subtext0)", color: "var(--ctp-subtext0)",
cursor: "pointer", cursor: "pointer",
fontSize: "0.85rem", fontSize: "0.75rem",
fontWeight: 500,
}; };
const btnDangerStyle: React.CSSProperties = { const btnDangerStyle: React.CSSProperties = {
@@ -438,9 +441,10 @@ const btnDangerStyle: React.CSSProperties = {
color: "var(--ctp-red)", color: "var(--ctp-red)",
border: "none", border: "none",
padding: "0.3rem 0.6rem", padding: "0.3rem 0.6rem",
borderRadius: "0.3rem", borderRadius: "0.375rem",
cursor: "pointer", cursor: "pointer",
fontSize: "0.8rem", fontSize: "0.75rem",
fontWeight: 500,
}; };
const btnRevokeConfirmStyle: React.CSSProperties = { const btnRevokeConfirmStyle: React.CSSProperties = {
@@ -448,19 +452,20 @@ const btnRevokeConfirmStyle: React.CSSProperties = {
color: "var(--ctp-crust)", color: "var(--ctp-crust)",
border: "none", border: "none",
padding: "0.2rem 0.5rem", padding: "0.2rem 0.5rem",
borderRadius: "0.25rem", borderRadius: "0.375rem",
cursor: "pointer", cursor: "pointer",
fontSize: "0.75rem", fontSize: "0.75rem",
fontWeight: 600, fontWeight: 500,
}; };
const btnTinyStyle: React.CSSProperties = { const btnTinyStyle: React.CSSProperties = {
padding: "0.2rem 0.5rem", padding: "0.2rem 0.5rem",
borderRadius: "0.25rem", borderRadius: "0.375rem",
border: "none", border: "none",
backgroundColor: "var(--ctp-surface1)", backgroundColor: "var(--ctp-surface1)",
color: "var(--ctp-text)", color: "var(--ctp-text)",
fontSize: "0.75rem", fontSize: "0.75rem",
fontWeight: 500,
cursor: "pointer", cursor: "pointer",
}; };