Feat v0.2.3 sdk tasks (#7)
Some checks failed
CI/CD / detect-changes (push) Successful in 23s
CI/CD / test-frontend (push) Successful in 5s
CI/CD / test-go-pg (push) Failing after 2m27s
CI/CD / test-sqlite (push) Successful in 2m34s
CI/CD / build-and-deploy (push) Has been skipped

Co-authored-by: Jeffrey Smith <jasafpro@gmail.com>
Co-committed-by: Jeffrey Smith <jasafpro@gmail.com>
This commit was merged in pull request #7.
This commit is contained in:
2026-03-27 11:06:40 +00:00
committed by xcaliber
parent 57ccf19efb
commit 239a5fb732
26 changed files with 2230 additions and 38 deletions

View File

@@ -20,7 +20,7 @@
* children — Surface content
*/
const { html } = window;
const { useState, useEffect, useRef } = hooks;
const { useState, useEffect, useRef, useReducer } = hooks;
function ShellBanner({ position, text, variant = 'info' }) {
const ref = useRef(null);
@@ -41,6 +41,28 @@ function ShellBanner({ position, text, variant = 'info' }) {
`;
}
/**
* Renders all components registered in a named slot.
* Re-renders when sw.slots changes (via 'slots.changed' event).
*/
function SlotRenderer({ name }) {
const [, tick] = useReducer(n => n + 1, 0);
useEffect(() => {
if (!window.sw) return;
const off = window.sw.on('slots.changed', (e) => {
if (e.slot === name) tick();
});
return () => { if (typeof off === 'function') off(); else window.sw.off('slots.changed', tick); };
}, [name]);
const items = window.sw?.slots?.get(name) || [];
if (!items.length) return null;
return html`<div class="sw-slot sw-slot--${name}">
${items.map(i => html`<${i.component} key=${i.id} />`)}
</div>`;
}
export function AppShell({ banner, message, footer, children }) {
const [msgDismissed, setMsgDismissed] = useState(false);
@@ -62,6 +84,9 @@ export function AppShell({ banner, message, footer, children }) {
</div>
`}
<${SlotRenderer} name="toolbar" />
<${SlotRenderer} name="surface.header" />
<main class="sw-shell__surface">
${children}
</main>
@@ -71,6 +96,8 @@ export function AppShell({ banner, message, footer, children }) {
${footer}
</footer>
`}
<${SlotRenderer} name="statusbar" />
</div>
${banner && html`