feat: P5 — first widget on screen (clock via SDK)
The dashboard finally has live content. `runtime.ts` now imports
`defineWidget` from `@dashward/widget-sdk` (added as a workspace
dependency of the container), defines a tabular-numerals clock widget
inline, and mounts it onto the 12-column grid via a generic
`mountWidget` + `createContext` pair that produces the SDK's
config/system/lifecycle/shell APIs.
container/runtime/runtime.ts
- mountWidget(def, parent, instanceId, size): creates a grid card,
applies grid-column/row span, builds the widget context, calls
def.mount; wraps in try/catch so a mount failure visibly degrades
the card (red border + error label) instead of breaking the page.
- createContext: localStorage-backed config (persists per
instanceId), theme reads dataset.theme and subscribes to the
dashward:ThemeChanged CustomEvent (DBus signal forwarded from
shell), shell.call delegates to window.__dashShell__. onMount
fires via microtask; onUnmount handlers stored; visibility is a
no-op until P7 (edit mode / workspace tracking).
- clockDef: defineWidget<ClockConfig>; shadow DOM root, large
tabular-numerals time string, re-renders on tick + config.onChange.
container/runtime/styles.css
- Real card style: half-transparent backdrop-filter blur with a
light/dark variant, rounded 18px corners, subtle border and shadow.
- .widget-error fallback for failed mount.
- grid-auto-rows: minmax(120px, auto) so widgets have a sensible
minimum row height.
container/package.json
- `@dashward/widget-sdk` is now a runtime dependency. esbuild
bundles it into runtime.js.
Verified on ubuntu2504-test VM: clock card renders top-left at 4-wide
× 2-tall, ticks every second, follows system theme live via the P4
bridge (light → glass-white card, dark → glass-black card).
Layout persistence, edit mode, dynamic disk loading of widget bundles,
and iframe crash isolation per design §11 / §14 land in P6+.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -2,6 +2,9 @@
|
||||
--bg: #f5f5f7;
|
||||
--fg: #1c1c1e;
|
||||
--fg-muted: rgba(28, 28, 30, 0.55);
|
||||
--card: rgba(255, 255, 255, 0.7);
|
||||
--card-border: rgba(0, 0, 0, 0.08);
|
||||
--card-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
|
||||
--grid-gap: 16px;
|
||||
}
|
||||
|
||||
@@ -9,9 +12,13 @@
|
||||
--bg: #0f0f12;
|
||||
--fg: #f0f0f5;
|
||||
--fg-muted: rgba(240, 240, 245, 0.55);
|
||||
--card: rgba(255, 255, 255, 0.06);
|
||||
--card-border: rgba(255, 255, 255, 0.08);
|
||||
--card-shadow: 0 8px 24px rgba(0, 0, 0, 0.4);
|
||||
}
|
||||
|
||||
html, body {
|
||||
html,
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
height: 100%;
|
||||
@@ -24,15 +31,6 @@ body {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
}
|
||||
|
||||
#grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
gap: var(--grid-gap);
|
||||
padding: var(--grid-gap);
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#boot {
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
@@ -46,31 +44,34 @@ body {
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.placeholder {
|
||||
grid-column: 1 / -1;
|
||||
#grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(12, 1fr);
|
||||
grid-auto-rows: minmax(120px, auto);
|
||||
gap: var(--grid-gap);
|
||||
padding: var(--grid-gap);
|
||||
min-height: 100%;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.widget {
|
||||
background: var(--card);
|
||||
border: 1px solid var(--card-border);
|
||||
border-radius: 18px;
|
||||
padding: 20px;
|
||||
box-shadow: var(--card-shadow);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
transition: transform 120ms ease, box-shadow 120ms ease;
|
||||
}
|
||||
|
||||
.widget-error {
|
||||
border-color: rgba(255, 80, 80, 0.6);
|
||||
color: rgba(255, 80, 80, 0.95);
|
||||
display: grid;
|
||||
place-items: center;
|
||||
align-content: center;
|
||||
gap: 12px;
|
||||
min-height: 80vh;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.placeholder h1 {
|
||||
font-size: clamp(3rem, 8vw, 6rem);
|
||||
font-weight: 200;
|
||||
letter-spacing: -0.02em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.placeholder .hint {
|
||||
font-size: 1.25rem;
|
||||
margin: 0;
|
||||
opacity: 0.7;
|
||||
}
|
||||
|
||||
.placeholder .meta {
|
||||
font-size: 0.9rem;
|
||||
margin: 0;
|
||||
color: var(--fg-muted);
|
||||
font-family: ui-monospace, monospace;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user