Add Vapor shell palette presets and contract docs

This commit is contained in:
2026-02-28 18:37:53 +03:00
parent 1553eb1394
commit 0e710ec4ce
8 changed files with 507 additions and 62 deletions

View File

@@ -14,3 +14,4 @@ Contents:
- `static/vapor.css` - active stylesheet baseline
- `templates/icon_sprite.html` - active icon sprite
- `notes.md` - usage boundaries and integration rules
- `palette-catalog.md` - preset list for app-shell header and accent colors

View File

@@ -9,14 +9,19 @@ This module is the active reusable theme source for design-code consumers.
- table/filter/toolbar primitives
- icon rendering baseline and shared sprite usage
- modal and status component style language
- app-shell color/height presets for host-level branding fit within Vapor aesthetics
## How to use
- Use this module as the visual baseline for host projects that adopt the canonical demo style.
- Pattern contracts should reference shared behavior contracts and rely on this module for visual primitives.
- When baseline visuals change, update this module first to keep downstream integration deterministic.
- For shell color selection, use `palette-catalog.md` and set `data-vapor-shell` on `<html>`.
- Keep host-specific brand overrides outside this module unless they are reusable presets.
## Boundary
- This module standardizes visual language only.
- Domain behavior, labels, and business workflow semantics belong to pattern contracts.
- Preset palette IDs are part of the reusable contract; host projects may choose one, but should not
rename/remove preset IDs in downstream copies without migration notes.

View File

@@ -0,0 +1,39 @@
# Vapor Shell Palette Catalog
This catalog defines reusable `app-shell` presets for host projects that consume `theme-vapor`.
Apply a preset on the root element:
```html
<html data-vapor-shell="miami-sunset">
```
Optional: host project can override shell height without changing preset IDs:
```css
:root { --shell-height: 72px; }
```
## Presets (Header + Accent)
| Preset ID | Header core | Accent core | Default shell height |
|---|---|---|---|
| `miami-sunset` | `#fbe5f8` | `#ff7ec7` | `66px` |
| `neon-grid` | `#f5eeff` | `#ff4fd8` | `64px` |
| `laser-flamingo` | `#ffe8f4` | `#ff6fae` | `70px` |
| `synth-lagoon` | `#e8f6ff` | `#67d7ff` | `62px` |
| `mall-soft` | `#fff1f8` | `#ffb5d7` | `68px` |
| `hologram-sky` | `#edf9ff` | `#5ce4ff` | `64px` |
| `peach-drive` | `#fff0e6` | `#ff9a6a` | `72px` |
| `ultraviolet-plaza` | `#f0e8ff` | `#b26dff` | `66px` |
| `cyber-mint` | `#ebfff7` | `#57f0c1` | `62px` |
## Token Surface
Each preset resolves these tokens in `static/vapor.css`:
- `--shell-height`
- `--shell-bg-light`, `--shell-bg-dark`
- `--shell-border-light`, `--shell-border-dark`
- `--shell-accent-light`, `--shell-accent-dark`
- `--shell-accent-line-light`, `--shell-accent-line-dark`

View File

@@ -93,6 +93,8 @@ body {
padding: 20px 16px 56px;
}
.app-shell {
position: relative;
min-height: var(--shell-height, 64px);
border-bottom: 1px solid rgba(176, 189, 206, 0.78);
background:
linear-gradient(180deg, rgba(255,255,255,0.72), rgba(255,255,255,0.20) 34%, rgba(255,255,255,0.02) 35%, rgba(255,255,255,0)),
@@ -102,10 +104,22 @@ body {
inset 0 1px 0 rgba(255,255,255,0.86),
inset 0 -1px 0 rgba(145, 160, 179, 0.10);
}
.app-shell::after {
content: "";
position: absolute;
left: 0;
right: 0;
bottom: -1px;
height: 3px;
background: var(--shell-accent, linear-gradient(90deg, #ffd9f3 0%, #e8c9ff 44%, #b8ddff 100%));
border-top: 1px solid var(--shell-accent-line, #bf92e3);
box-shadow: 0 0 16px var(--shell-accent-shadow, rgba(191, 146, 227, 0.32));
pointer-events: none;
}
.app-shell-inner {
max-width: 1040px;
margin: 0 auto;
padding: 10px 16px;
padding: var(--shell-pad-y, 10px) 16px;
display: flex;
justify-content: space-between;
gap: 14px;
@@ -115,7 +129,7 @@ body {
margin: 0;
text-transform: uppercase;
letter-spacing: 0.10em;
color: #717986;
color: var(--shell-kicker, #717986);
font-size: 10px;
font-weight: 600;
}
@@ -124,15 +138,14 @@ body {
font-size: 16px;
line-height: 1.08;
font-weight: 700;
color: #2f343b;
color: var(--shell-title, #2f343b);
text-shadow: 0 1px 0 rgba(255,255,255,0.26);
}
.app-shell-subtitle {
margin: 1px 0 0;
color: var(--muted);
font-size: 11px;
line-height: 1.15;
color: #6b7480;
color: var(--shell-subtitle, #6b7480);
}
.app-shell-statuses {
display: flex;
@@ -3780,6 +3793,155 @@ code {
--vw-status-review-line: #c4afea;
--vw-status-failed-bg: #f8dbe6;
--vw-status-failed-line: #e2b4c6;
--shell-height: 64px;
--shell-pad-y: 10px;
--shell-bg-light:
linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0.08)),
linear-gradient(180deg, rgba(245,240,251,0.82), rgba(232,238,250,0.78));
--shell-bg-dark:
linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)),
linear-gradient(180deg, rgba(36,30,67,0.82), rgba(28,29,60,0.78));
--shell-border-light: #d7cee9;
--shell-border-dark: #534a8d;
--shell-kicker-light: #807691;
--shell-kicker-dark: #a79ec6;
--shell-title-light: #2f2843;
--shell-title-dark: #f0ebff;
--shell-subtitle-light: #6e6488;
--shell-subtitle-dark: #c4bbdf;
--shell-accent-light: linear-gradient(90deg, #ffd9f3 0%, #e8c9ff 44%, #b8ddff 100%);
--shell-accent-dark: linear-gradient(90deg, #ff96e3 0%, #ca88ff 44%, #79d0ff 100%);
--shell-accent-line-light: #bf92e3;
--shell-accent-line-dark: #cb84ff;
--shell-accent-shadow-light: rgba(191, 146, 227, 0.32);
--shell-accent-shadow-dark: rgba(203, 132, 255, 0.36);
--shell-bg: var(--shell-bg-light);
--shell-border: var(--shell-border-light);
--shell-kicker: var(--shell-kicker-light);
--shell-title: var(--shell-title-light);
--shell-subtitle: var(--shell-subtitle-light);
--shell-accent: var(--shell-accent-light);
--shell-accent-line: var(--shell-accent-line-light);
--shell-accent-shadow: var(--shell-accent-shadow-light);
}
/* Header color presets for host projects. Apply on html: data-vapor-shell="preset-id". */
html[data-vapor-shell="miami-sunset"] {
--shell-height: 66px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0.08)), linear-gradient(180deg, #fbe5f8 0%, #e4ecff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #3e2457 0%, #252c5c 100%);
--shell-border-light: #d8bae8;
--shell-border-dark: #7355b1;
--shell-accent-light: linear-gradient(90deg, #ff7ec7 0%, #cc8dff 52%, #6fd5ff 100%);
--shell-accent-dark: linear-gradient(90deg, #ff5bc8 0%, #b476ff 50%, #4dc8ff 100%);
--shell-accent-line-light: #be74da;
--shell-accent-line-dark: #d97aff;
--shell-accent-shadow-light: rgba(190, 116, 218, 0.35);
--shell-accent-shadow-dark: rgba(217, 122, 255, 0.40);
}
html[data-vapor-shell="neon-grid"] {
--shell-height: 64px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.40), rgba(255,255,255,0.08)), linear-gradient(180deg, #f5eeff 0%, #e7f5ff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #2f2352 0%, #1f3157 100%);
--shell-border-light: #cdbce7;
--shell-border-dark: #5b5bb0;
--shell-accent-light: linear-gradient(90deg, #ff4fd8 0%, #9e7dff 52%, #3cd6ff 100%);
--shell-accent-dark: linear-gradient(90deg, #ff39cc 0%, #8b68ff 50%, #2bc6ff 100%);
--shell-accent-line-light: #ab6fe7;
--shell-accent-line-dark: #c76fff;
--shell-accent-shadow-light: rgba(171, 111, 231, 0.34);
--shell-accent-shadow-dark: rgba(199, 111, 255, 0.38);
}
html[data-vapor-shell="laser-flamingo"] {
--shell-height: 70px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0.08)), linear-gradient(180deg, #ffe8f4 0%, #efe8ff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #472441 0%, #2d2a58 100%);
--shell-border-light: #dfb8cf;
--shell-border-dark: #8a4d8a;
--shell-accent-light: linear-gradient(90deg, #ff6fae 0%, #ff8adf 50%, #7cc8ff 100%);
--shell-accent-dark: linear-gradient(90deg, #ff4f99 0%, #eb73ff 50%, #5fb9ff 100%);
--shell-accent-line-light: #d16cae;
--shell-accent-line-dark: #e273e0;
--shell-accent-shadow-light: rgba(209, 108, 174, 0.36);
--shell-accent-shadow-dark: rgba(226, 115, 224, 0.40);
}
html[data-vapor-shell="synth-lagoon"] {
--shell-height: 62px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.40), rgba(255,255,255,0.08)), linear-gradient(180deg, #e8f6ff 0%, #e9ebff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #233856 0%, #212a53 100%);
--shell-border-light: #b7d5eb;
--shell-border-dark: #4f74b4;
--shell-accent-light: linear-gradient(90deg, #67d7ff 0%, #6ea9ff 50%, #b784ff 100%);
--shell-accent-dark: linear-gradient(90deg, #49c7ff 0%, #5b8fff 50%, #a86fff 100%);
--shell-accent-line-light: #6e9be8;
--shell-accent-line-dark: #8b7bff;
--shell-accent-shadow-light: rgba(110, 155, 232, 0.34);
--shell-accent-shadow-dark: rgba(139, 123, 255, 0.38);
}
html[data-vapor-shell="mall-soft"] {
--shell-height: 68px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0.08)), linear-gradient(180deg, #fff1f8 0%, #f4f5ff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #3f2f54 0%, #2c3459 100%);
--shell-border-light: #dfc9df;
--shell-border-dark: #73609d;
--shell-accent-light: linear-gradient(90deg, #ffb5d7 0%, #d6b0ff 50%, #9dd8ff 100%);
--shell-accent-dark: linear-gradient(90deg, #ff95ca 0%, #c397ff 50%, #81c8ff 100%);
--shell-accent-line-light: #c79ac8;
--shell-accent-line-dark: #b788ff;
--shell-accent-shadow-light: rgba(199, 154, 200, 0.33);
--shell-accent-shadow-dark: rgba(183, 136, 255, 0.38);
}
html[data-vapor-shell="hologram-sky"] {
--shell-height: 64px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.40), rgba(255,255,255,0.08)), linear-gradient(180deg, #edf9ff 0%, #ebf1ff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #233a4d 0%, #22325a 100%);
--shell-border-light: #bdd9e6;
--shell-border-dark: #4f78a9;
--shell-accent-light: linear-gradient(90deg, #5ce4ff 0%, #7bbfff 50%, #c28fff 100%);
--shell-accent-dark: linear-gradient(90deg, #3fd5ff 0%, #63a9ff 50%, #ab79ff 100%);
--shell-accent-line-light: #6bb8e1;
--shell-accent-line-dark: #9774ff;
--shell-accent-shadow-light: rgba(107, 184, 225, 0.34);
--shell-accent-shadow-dark: rgba(151, 116, 255, 0.38);
}
html[data-vapor-shell="peach-drive"] {
--shell-height: 72px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0.08)), linear-gradient(180deg, #fff0e6 0%, #ffe9f5 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #4e2f3f 0%, #383258 100%);
--shell-border-light: #e2c3b5;
--shell-border-dark: #8e5e7c;
--shell-accent-light: linear-gradient(90deg, #ff9a6a 0%, #ff78b2 52%, #8eb8ff 100%);
--shell-accent-dark: linear-gradient(90deg, #ff7e4f 0%, #f661a1 52%, #75a5ff 100%);
--shell-accent-line-light: #d67a7a;
--shell-accent-line-dark: #d56db5;
--shell-accent-shadow-light: rgba(214, 122, 122, 0.34);
--shell-accent-shadow-dark: rgba(213, 109, 181, 0.38);
}
html[data-vapor-shell="ultraviolet-plaza"] {
--shell-height: 66px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.40), rgba(255,255,255,0.08)), linear-gradient(180deg, #f0e8ff 0%, #e8edff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #2b1f4f 0%, #1f2756 100%);
--shell-border-light: #c9b8eb;
--shell-border-dark: #5d4eae;
--shell-accent-light: linear-gradient(90deg, #b26dff 0%, #ee68ff 52%, #6ec9ff 100%);
--shell-accent-dark: linear-gradient(90deg, #9e59ff 0%, #d853ff 52%, #55bbff 100%);
--shell-accent-line-light: #9f67e9;
--shell-accent-line-dark: #c962ff;
--shell-accent-shadow-light: rgba(159, 103, 233, 0.34);
--shell-accent-shadow-dark: rgba(201, 98, 255, 0.39);
}
html[data-vapor-shell="cyber-mint"] {
--shell-height: 62px;
--shell-bg-light: linear-gradient(180deg, rgba(255,255,255,0.40), rgba(255,255,255,0.08)), linear-gradient(180deg, #ebfff7 0%, #ebf9ff 100%);
--shell-bg-dark: linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)), linear-gradient(180deg, #1f3d3d 0%, #24345a 100%);
--shell-border-light: #b9e2d9;
--shell-border-dark: #4e8a9f;
--shell-accent-light: linear-gradient(90deg, #57f0c1 0%, #6fd8ff 52%, #9d9eff 100%);
--shell-accent-dark: linear-gradient(90deg, #3adcad 0%, #58c8ff 52%, #8e8dff 100%);
--shell-accent-line-light: #62c8b2;
--shell-accent-line-dark: #7fb3ff;
--shell-accent-shadow-light: rgba(98, 200, 178, 0.34);
--shell-accent-shadow-dark: rgba(127, 179, 255, 0.38);
}
body {
@@ -3862,14 +4024,13 @@ body::after {
}
.app-shell {
background:
linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0.08)),
linear-gradient(180deg, rgba(245,240,251,0.82), rgba(232,238,250,0.78));
border-bottom-color: var(--vw-line-soft);
min-height: var(--shell-height);
background: var(--shell-bg);
border-bottom-color: var(--shell-border);
}
.app-shell-kicker { color: #807691; }
.app-shell-title { color: #2f2843; }
.app-shell-subtitle { color: #6e6488; }
.app-shell-kicker { color: var(--shell-kicker); }
.app-shell-title { color: var(--shell-title); }
.app-shell-subtitle { color: var(--shell-subtitle); }
.shell-pill {
border-color: #cdbfe5;
background:
@@ -4121,6 +4282,14 @@ h1, h2, h3 { color: #2f2843; }
--vw-primary-bottom: #73cdff;
--vw-table-head-top: #473a74;
--vw-table-head-bottom: #2f2c5f;
--shell-bg: var(--shell-bg-dark);
--shell-border: var(--shell-border-dark);
--shell-kicker: var(--shell-kicker-dark);
--shell-title: var(--shell-title-dark);
--shell-subtitle: var(--shell-subtitle-dark);
--shell-accent: var(--shell-accent-dark);
--shell-accent-line: var(--shell-accent-line-dark);
--shell-accent-shadow: var(--shell-accent-shadow-dark);
}
body {
background:
@@ -4177,14 +4346,12 @@ h1, h2, h3 { color: #2f2843; }
linear-gradient(180deg, #ff96e3 0%, #ca88ff 44%, #79d0ff 100%);
}
.app-shell {
background:
linear-gradient(180deg, rgba(255,255,255,0.05), rgba(255,255,255,0.01)),
linear-gradient(180deg, rgba(36,30,67,0.82), rgba(28,29,60,0.78));
border-bottom-color: var(--vw-line-soft);
background: var(--shell-bg);
border-bottom-color: var(--shell-border);
}
.app-shell-kicker { color: #a79ec6; }
.app-shell-title { color: #f0ebff; }
.app-shell-subtitle { color: #c4bbdf; }
.app-shell-kicker { color: var(--shell-kicker); }
.app-shell-title { color: var(--shell-title); }
.app-shell-subtitle { color: var(--shell-subtitle); }
.lead, .meta, .panel .meta, .filters label, .text-link {
color: #d6ceef;
}
@@ -4344,6 +4511,16 @@ html[data-theme="dark"] .demo-topnav {
linear-gradient(180deg, rgba(36,30,66,0.86), rgba(28,27,57,0.84));
border-bottom-color: #534a8d;
}
html[data-theme="dark"] {
--shell-bg: var(--shell-bg-dark);
--shell-border: var(--shell-border-dark);
--shell-kicker: var(--shell-kicker-dark);
--shell-title: var(--shell-title-dark);
--shell-subtitle: var(--shell-subtitle-dark);
--shell-accent: var(--shell-accent-dark);
--shell-accent-line: var(--shell-accent-line-dark);
--shell-accent-shadow: var(--shell-accent-shadow-dark);
}
html[data-theme="dark"] .demo-topnav-brand,
html[data-theme="dark"] .demo-topnav-link,
html[data-theme="dark"] h1,
@@ -4356,7 +4533,7 @@ html[data-theme="dark"] .masthead .label,
html[data-theme="dark"] .app-shell-title,
html[data-theme="dark"] .ui-table th,
html[data-theme="dark"] .ui-table td {
color: #f0ebff;
color: var(--shell-title);
}
html[data-theme="dark"] .demo-topnav-brand,
html[data-theme="dark"] .demo-topnav-link {
@@ -4389,8 +4566,12 @@ html[data-theme="dark"] .selected-summary {
linear-gradient(180deg, rgba(255,255,255,0.10), rgba(255,255,255,0.02) 28%, rgba(255,255,255,0) 29%),
linear-gradient(180deg, var(--vw-card-top) 0%, var(--vw-card-bottom) 100%);
}
html[data-theme="dark"] .app-shell-kicker { color: #a79ec6; }
html[data-theme="dark"] .app-shell-subtitle,
html[data-theme="dark"] .app-shell {
background: var(--shell-bg);
border-bottom-color: var(--shell-border);
}
html[data-theme="dark"] .app-shell-kicker { color: var(--shell-kicker); }
html[data-theme="dark"] .app-shell-subtitle { color: var(--shell-subtitle); }
html[data-theme="dark"] .lead,
html[data-theme="dark"] .meta,
html[data-theme="dark"] .panel .meta,
@@ -4415,9 +4596,19 @@ html[data-theme="light"] .masthead .label,
html[data-theme="light"] .app-shell-title,
html[data-theme="light"] .ui-table th,
html[data-theme="light"] .ui-table td {
color: #2f2843;
color: var(--shell-title);
text-shadow: none;
}
html[data-theme="light"] {
--shell-bg: var(--shell-bg-light);
--shell-border: var(--shell-border-light);
--shell-kicker: var(--shell-kicker-light);
--shell-title: var(--shell-title-light);
--shell-subtitle: var(--shell-subtitle-light);
--shell-accent: var(--shell-accent-light);
--shell-accent-line: var(--shell-accent-line-light);
--shell-accent-shadow: var(--shell-accent-shadow-light);
}
html[data-theme="light"] body {
background:
radial-gradient(900px 280px at 10% 0%, rgba(255, 185, 236, 0.14), transparent 72%),
@@ -4475,14 +4666,12 @@ html[data-theme="light"] .demo-topnav-link.active {
linear-gradient(180deg, #ffd9f3 0%, #e8c9ff 44%, #b8ddff 100%);
}
html[data-theme="light"] .app-shell {
background:
linear-gradient(180deg, rgba(255,255,255,0.42), rgba(255,255,255,0.08)),
linear-gradient(180deg, rgba(245,240,251,0.82), rgba(232,238,250,0.78));
border-bottom-color: #d7cee9;
background: var(--shell-bg);
border-bottom-color: var(--shell-border);
}
html[data-theme="light"] .app-shell-kicker { color: #807691; }
html[data-theme="light"] .app-shell-title { color: #2f2843; }
html[data-theme="light"] .app-shell-subtitle { color: #6e6488; }
html[data-theme="light"] .app-shell-kicker { color: var(--shell-kicker); }
html[data-theme="light"] .app-shell-title { color: var(--shell-title); }
html[data-theme="light"] .app-shell-subtitle { color: var(--shell-subtitle); }
html[data-theme="light"] .shell-pill {
border-color: #cdbfe5;
color: #5d5573;
@@ -4635,7 +4824,6 @@ html[data-theme="light"] .demo-modal-titlebar {
linear-gradient(180deg, #efe8f9 0%, #dde4f5 100%);
}
html[data-theme="light"] .demo-modal-title { color: #31284b; text-shadow: none; }
html[data-theme="light"] .app-shell-subtitle,
html[data-theme="light"] .lead,
html[data-theme="light"] .meta,
html[data-theme="light"] .panel .meta,