Changeset 0.37.2 (#214)

Co-authored-by: gobha <jasafpro@gmail.com>
Co-committed-by: gobha <jasafpro@gmail.com>
This commit is contained in:
2026-03-20 23:52:55 +00:00
committed by xcaliber
parent 8c53f61b71
commit 4f1abc6321
24 changed files with 1775 additions and 25 deletions

View File

@@ -0,0 +1,81 @@
/**
* AppShell — Layer 1 layout scaffold
*
* ┌─────────────────────────────────┐ ← fixed banner (top, optional)
* ├─────────────────────────────────┤
* │ message (optional, dismissible)│
* ├─────────────────────────────────┤
* │ │
* │ surface (fills remaining) │
* │ │
* ├─────────────────────────────────┤
* │ footer (optional) │
* ├─────────────────────────────────┤
* └─────────────────────────────────┘ ← fixed banner (bottom, same as top)
*
* Props:
* banner — { text, variant } or null (one config → top AND bottom)
* message — { text, variant } or null (dismissible)
* footer — VNode children or null
* children — Surface content
*/
const { html } = window;
const { useState, useEffect, useRef } = hooks;
function ShellBanner({ position, text, variant = 'info' }) {
const ref = useRef(null);
const prop = position === 'top' ? '--banner-top-height' : '--banner-bottom-height';
useEffect(() => {
if (ref.current) {
const h = ref.current.offsetHeight + 'px';
document.documentElement.style.setProperty(prop, h);
}
return () => document.documentElement.style.setProperty(prop, '0px');
}, [text, prop]);
return html`
<div class="sw-shell__banner sw-shell__banner--${position} sw-shell__banner--${variant}" ref=${ref}>
<span class="sw-shell__banner-text">${text}</span>
</div>
`;
}
export function AppShell({ banner, message, footer, children }) {
const [msgDismissed, setMsgDismissed] = useState(false);
const showMsg = message && !msgDismissed;
return html`
<div class="sw-shell">
${banner && html`
<${ShellBanner} position="top" text=${banner.text} variant=${banner.variant} />
`}
<div class="sw-shell__body">
${showMsg && html`
<div class="sw-shell__announcement">
<div class="sw-shell__announcement-inner sw-shell__announcement--${message.variant || 'info'}">
<span class="sw-shell__announcement-text">${message.text}</span>
<button class="sw-shell__banner-close" onClick=${() => setMsgDismissed(true)} aria-label="Dismiss">×</button>
</div>
</div>
`}
<main class="sw-shell__surface">
${children}
</main>
${footer && html`
<footer class="sw-shell__footer">
${footer}
</footer>
`}
</div>
${banner && html`
<${ShellBanner} position="bottom" text=${banner.text} variant=${banner.variant} />
`}
</div>
`;
}