Add vapor shell preset selection flow for host apps

This commit is contained in:
2026-02-28 18:55:43 +03:00
parent 0e710ec4ce
commit 7ee984a225
9 changed files with 153 additions and 7 deletions

View File

@@ -17,6 +17,7 @@ This module is the active reusable theme source for design-code consumers.
- 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>`.
- For runtime switching, the recommended query key is `vapor_shell` (same IDs as the catalog).
- Keep host-specific brand overrides outside this module unless they are reusable presets.
## Boundary

View File

@@ -14,6 +14,17 @@ Optional: host project can override shell height without changing preset IDs:
:root { --shell-height: 72px; }
```
## Selection Approach
Recommended precedence for host integration:
1. `?vapor_shell=<preset-id>` query parameter (preview/share links)
2. `localStorage["vapor_shell"]` (remembered user choice)
3. `<html data-vapor-shell="...">` static default from server/templates
4. fallback preset: `miami-sunset`
The scaffold and demo JavaScript implement this precedence.
## Presets (Header + Accent)
| Preset ID | Header core | Accent core | Default shell height |

View File

@@ -8,3 +8,8 @@ Minimal starter skeleton for a Go web app using:
This scaffold is intended as a starting point that host repositories can adapt.
Vapor shell preset integration is included:
- default preset via `<html data-vapor-shell="miami-sunset">`
- runtime override via `?vapor_shell=<preset-id>`
- persisted selection via `localStorage["vapor_shell"]`

View File

@@ -1,2 +1,65 @@
document.documentElement.classList.add("js");
(() => {
const root = document.documentElement;
const storageKey = "vapor_shell";
const queryKey = "vapor_shell";
const fallbackPreset = "miami-sunset";
const allowed = new Set([
"miami-sunset",
"neon-grid",
"laser-flamingo",
"synth-lagoon",
"mall-soft",
"hologram-sky",
"peach-drive",
"ultraviolet-plaza",
"cyber-mint",
]);
const normalizePreset = (value) => {
const trimmed = (value || "").trim().toLowerCase();
if (!trimmed || !allowed.has(trimmed)) {
return "";
}
return trimmed;
};
const setPreset = (value) => {
const preset = normalizePreset(value);
if (!preset) {
return false;
}
root.setAttribute("data-vapor-shell", preset);
return true;
};
root.classList.add("js");
const url = new URL(window.location.href);
const fromQuery = normalizePreset(url.searchParams.get(queryKey));
if (fromQuery) {
setPreset(fromQuery);
try {
window.localStorage.setItem(storageKey, fromQuery);
} catch (_err) {
// Keep behavior deterministic even when storage is blocked.
}
return;
}
const fromMarkup = normalizePreset(root.getAttribute("data-vapor-shell"));
if (fromMarkup) {
return;
}
try {
const fromStorage = normalizePreset(window.localStorage.getItem(storageKey));
if (fromStorage) {
setPreset(fromStorage);
return;
}
} catch (_err) {
// Fallback handled below.
}
setPreset(fallbackPreset);
})();

View File

@@ -1,6 +1,6 @@
{{ define "base.html" }}
<!doctype html>
<html lang="en">
<html lang="en" data-vapor-shell="miami-sunset">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
@@ -19,4 +19,3 @@
</body>
</html>
{{ end }}