All checks were successful
CI/CD / detect-changes (push) Successful in 4s
CI/CD / test-runners (push) Has been skipped
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Successful in 2m51s
CI/CD / test-sqlite (push) Successful in 2m51s
CI/CD / build-and-deploy (push) Successful in 39s
Co-authored-by: Jeffrey Smith <jasafpro@gmail.com> Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
197 lines
6.1 KiB
Markdown
197 lines
6.1 KiB
Markdown
# Extension CSS Contract
|
|
|
|
> **Version**: v0.6.13 — Responsive & Spacing
|
|
|
|
This document defines the CSS contract between the Armature kernel and extension
|
|
packages. Extensions **must** follow these rules; the kernel guarantees the listed
|
|
classes and variables are stable public API.
|
|
|
|
---
|
|
|
|
## Naming Rule
|
|
|
|
All class selectors in extension CSS (`packages/{slug}/css/main.css`) must start
|
|
with `.ext-{slug}-`. The `{slug}` is the package directory name.
|
|
|
|
```css
|
|
/* Good */
|
|
.ext-my-app-sidebar { ... }
|
|
.ext-my-app-card { ... }
|
|
|
|
/* Bad — will be rejected by the linter */
|
|
.sidebar { ... }
|
|
.my-sidebar { ... }
|
|
```
|
|
|
|
**Compound selectors**: Descendant classes scoped under your `.ext-{slug}` root
|
|
are allowed to reference kernel classes or state modifiers:
|
|
|
|
```css
|
|
/* Allowed — kernel class scoped under extension namespace */
|
|
.ext-my-app .sw-btn { margin-top: 8px; }
|
|
|
|
/* Allowed — state modifier on an extension element */
|
|
.ext-my-app-item.active { ... }
|
|
```
|
|
|
|
Run `bash scripts/lint-package-css.sh` to validate. The linter checks that the
|
|
**first** class selector in every rule starts with `.ext-{slug}`.
|
|
|
|
---
|
|
|
|
## Stable Kernel Classes
|
|
|
|
Extensions may reference these classes in compound selectors. They are part of
|
|
the public API and will not change without a major version bump.
|
|
|
|
### Components (from `sw-primitives.css`)
|
|
|
|
| Class pattern | Component |
|
|
|---------------|-----------|
|
|
| `.sw-btn`, `.sw-btn--{variant}`, `.sw-btn--{size}` | Buttons |
|
|
| `.sw-input` | Text inputs |
|
|
| `.sw-field`, `.sw-field__label`, `.sw-field__hint` | Form fields |
|
|
| `.sw-dialog`, `.sw-dialog__header`, `.sw-dialog__body`, `.sw-dialog__footer` | Dialogs |
|
|
| `.sw-toast`, `.sw-toast-container` | Toast notifications |
|
|
| `.sw-menu`, `.sw-menu-item` | Context menus |
|
|
| `.sw-tabs`, `.sw-tab-btn` | Tab strips |
|
|
| `.sw-dropdown` | Custom dropdowns |
|
|
| `.sw-spinner` | Loading spinners |
|
|
| `.sw-avatar` | User avatars |
|
|
| `.sw-drawer` | Slide-out drawers |
|
|
| `.sw-banner` | Banner bars |
|
|
| `.sw-tooltip` | Tooltips |
|
|
|
|
### Extension Mount
|
|
|
|
The extension surface container has a `data-ext` attribute set to the package
|
|
slug. Use this for scoping if needed:
|
|
|
|
```css
|
|
[data-ext="my-app"] .ext-my-app-sidebar { ... }
|
|
```
|
|
|
|
---
|
|
|
|
## Stable CSS Variables
|
|
|
|
All variables from `variables.css` are public API. Extensions should use these
|
|
instead of hardcoded colors to respect the user's theme.
|
|
|
|
### Colors
|
|
|
|
| Variable | Purpose |
|
|
|----------|---------|
|
|
| `--bg` | Page background |
|
|
| `--bg-secondary` | Secondary/darker background |
|
|
| `--bg-elevated` | Elevated surface background |
|
|
| `--bg-raised` | Raised card background |
|
|
| `--bg-surface` | Surface-level background |
|
|
| `--bg-hover` | Hover state background |
|
|
| `--bg-active` | Active/pressed state background |
|
|
| `--bg-code` | Code block background |
|
|
| `--text` | Primary text color |
|
|
| `--text-2` | Secondary text color |
|
|
| `--text-3` | Tertiary/muted text color |
|
|
| `--text-on-color` | Text on colored backgrounds |
|
|
| `--accent` | Primary accent color |
|
|
| `--accent-dim` | Dimmed accent for backgrounds |
|
|
| `--accent-hover` | Accent hover state |
|
|
| `--accent-light` | Light accent variant |
|
|
| `--border` | Default border color |
|
|
| `--border-light` | Light border variant |
|
|
| `--border-elevated` | Border for elevated surfaces |
|
|
| `--danger` | Error/destructive color |
|
|
| `--danger-dim` | Dimmed danger background |
|
|
| `--danger-light` | Light danger variant |
|
|
| `--success` | Success/positive color |
|
|
| `--success-dim` | Dimmed success background |
|
|
| `--success-light` | Light success variant |
|
|
| `--warning` | Warning/caution color |
|
|
| `--warning-dim` | Dimmed warning background |
|
|
| `--warning-light` | Light warning variant |
|
|
| `--purple` | Purple accent |
|
|
| `--purple-dim` | Dimmed purple background |
|
|
|
|
### Spacing
|
|
|
|
Use spacing tokens instead of hardcoded values for padding, margin, and gap.
|
|
For sub-4px values (1px, 2px, 3px) used in borders and fine detail, hardcoded
|
|
values are acceptable.
|
|
|
|
| Variable | Value | Computed |
|
|
|----------|-------|---------|
|
|
| `--sp-1` | `0.25rem` | 4px |
|
|
| `--sp-1h` | `0.375rem` | 6px |
|
|
| `--sp-2` | `0.5rem` | 8px |
|
|
| `--sp-2h` | `0.625rem` | 10px |
|
|
| `--sp-3` | `0.75rem` | 12px |
|
|
| `--sp-4` | `1rem` | 16px |
|
|
| `--sp-5` | `1.25rem` | 20px |
|
|
| `--sp-6` | `1.5rem` | 24px |
|
|
| `--sp-8` | `2rem` | 32px |
|
|
| `--sp-10` | `2.5rem` | 40px |
|
|
| `--sp-12` | `3rem` | 48px |
|
|
|
|
Example:
|
|
|
|
```css
|
|
.ext-my-app-card {
|
|
padding: var(--sp-3) var(--sp-4); /* 12px 16px */
|
|
gap: var(--sp-2); /* 8px */
|
|
margin-bottom: var(--sp-4); /* 16px */
|
|
}
|
|
```
|
|
|
|
### Layout & Typography
|
|
|
|
| Variable | Purpose |
|
|
|----------|---------|
|
|
| `--font` | Primary font family (self-hosted, no external requests) |
|
|
| `--mono` | Monospace font family (self-hosted) |
|
|
| `--radius-sm` | Small border-radius (4px) — badges, inline controls |
|
|
| `--radius` | Default border-radius (8px) — buttons, inputs, cards |
|
|
| `--radius-lg` | Large border-radius (12px) — modals, dialogs, large cards |
|
|
| `--transition` | Default transition timing |
|
|
| `--shadow-lg` | Large elevation shadow |
|
|
| `--overlay` | Modal overlay color |
|
|
| `--glass` | Glassmorphism backdrop |
|
|
| `--input-bg` | Form input background |
|
|
| `--sidebar-w` | Sidebar width |
|
|
|
|
---
|
|
|
|
## Responsive Breakpoints
|
|
|
|
The kernel uses these standard breakpoints. Extensions should use the same
|
|
values for consistency.
|
|
|
|
| Name | Media Query | Use Case |
|
|
|------|-------------|----------|
|
|
| Mobile | `@media (max-width: 768px)` | Phone-sized, single column |
|
|
| Tablet | `@media (max-width: 1024px)` | Tablet/small laptop, narrower sidebars |
|
|
| Desktop | Default (no query) | Full layout |
|
|
|
|
CSS custom properties cannot be used in `@media` queries — use the pixel
|
|
values directly.
|
|
|
|
---
|
|
|
|
## What Is Internal
|
|
|
|
Everything not listed above is **internal kernel CSS** and may change between
|
|
minor versions. Extensions must not depend on:
|
|
|
|
- Kernel layout classes (`.admin-*`, `.surface-*`, `.sidebar`, etc.)
|
|
- Kernel CSS file load order
|
|
- Specific HTML structure of the shell or topbar
|
|
- Undocumented CSS variables
|
|
|
|
---
|
|
|
|
## Enforcement
|
|
|
|
The linter script `scripts/lint-package-css.sh` runs against all
|
|
`packages/*/css/main.css` files. It exits non-zero if any rule's first class
|
|
selector does not start with `.ext-{slug}`.
|