diff options
Diffstat (limited to 'src/features/surface-host/ui')
| -rw-r--r-- | src/features/surface-host/ui/Stat.svelte | 10 | ||||
| -rw-r--r-- | src/features/surface-host/ui/StatTable.svelte | 21 | ||||
| -rw-r--r-- | src/features/surface-host/ui/SurfaceTable.svelte | 14 | ||||
| -rw-r--r-- | src/features/surface-host/ui/SurfaceView.svelte | 36 |
4 files changed, 58 insertions, 23 deletions
diff --git a/src/features/surface-host/ui/Stat.svelte b/src/features/surface-host/ui/Stat.svelte deleted file mode 100644 index e184dab..0000000 --- a/src/features/surface-host/ui/Stat.svelte +++ /dev/null @@ -1,10 +0,0 @@ -<script lang="ts"> - import type { StatFieldView } from "../logic/types"; - - let { field }: { field: StatFieldView } = $props(); -</script> - -<dl> - <dt>{field.label}</dt> - <dd>{field.value}</dd> -</dl> diff --git a/src/features/surface-host/ui/StatTable.svelte b/src/features/surface-host/ui/StatTable.svelte new file mode 100644 index 0000000..415423f --- /dev/null +++ b/src/features/surface-host/ui/StatTable.svelte @@ -0,0 +1,21 @@ +<script lang="ts"> + import type { StatFieldView } from "../logic/types"; + + // Renders a run of stat fields as one aligned label/value table. Headerless: + // the column semantics aren't known generically, but the two-column layout + // gives the tidy, aligned readout the stats deserve (e.g. extension → version). + let { stats }: { readonly stats: readonly StatFieldView[] } = $props(); +</script> + +<div class="overflow-x-auto"> + <table class="table table-sm"> + <tbody> + {#each stats as stat, i (i)} + <tr> + <th class="font-medium">{stat.label}</th> + <td class="text-right tabular-nums">{stat.value}</td> + </tr> + {/each} + </tbody> + </table> +</div> diff --git a/src/features/surface-host/ui/SurfaceTable.svelte b/src/features/surface-host/ui/SurfaceTable.svelte new file mode 100644 index 0000000..764cc36 --- /dev/null +++ b/src/features/surface-host/ui/SurfaceTable.svelte @@ -0,0 +1,14 @@ +<script lang="ts"> + import Table from "../../../components/Table.svelte"; + import { parseTablePayload } from "../logic/table"; + + let { payload }: { readonly payload: unknown } = $props(); + + // Parse defensively; an unparseable payload yields null → render nothing + // (graceful skip, per the custom-field contract). + const data = $derived(parseTablePayload(payload)); +</script> + +{#if data !== null} + <Table columns={data.columns} rows={data.rows} /> +{/if} diff --git a/src/features/surface-host/ui/SurfaceView.svelte b/src/features/surface-host/ui/SurfaceView.svelte index 4207913..5210e8c 100644 --- a/src/features/surface-host/ui/SurfaceView.svelte +++ b/src/features/surface-host/ui/SurfaceView.svelte @@ -1,10 +1,11 @@ <script lang="ts"> import type { InvokeMessage, SurfaceSpec } from "@dispatch/ui-contract"; - import { planSurface } from "../logic/plan"; + import { groupRenderFields, planSurface } from "../logic/plan"; import Button from "./Button.svelte"; import Progress from "./Progress.svelte"; import Selector from "./Selector.svelte"; - import Stat from "./Stat.svelte"; + import StatTable from "./StatTable.svelte"; + import SurfaceTable from "./SurfaceTable.svelte"; import Toggle from "./Toggle.svelte"; let { @@ -13,21 +14,30 @@ }: { spec: SurfaceSpec; onInvoke: (msg: InvokeMessage) => void } = $props(); const plan = $derived(planSurface(spec)); + // Consecutive stats render together as one aligned table; everything else is + // a standalone widget. Grouping keys on field KIND only — never the surface id. + const groups = $derived(groupRenderFields(plan.fields)); </script> <article> <h2>{spec.title}</h2> - {#each plan.fields as field (field)} - {#if field.kind === "toggle"} - <Toggle {field} surfaceId={spec.id} {onInvoke} /> - {:else if field.kind === "progress"} - <Progress {field} /> - {:else if field.kind === "selector"} - <Selector {field} surfaceId={spec.id} {onInvoke} /> - {:else if field.kind === "stat"} - <Stat {field} /> - {:else if field.kind === "button"} - <Button {field} surfaceId={spec.id} {onInvoke} /> + {#each groups as group, i (i)} + {#if group.type === "stats"} + <StatTable stats={group.stats} /> + {:else if group.field.kind === "toggle"} + <Toggle field={group.field} surfaceId={spec.id} {onInvoke} /> + {:else if group.field.kind === "progress"} + <Progress field={group.field} /> + {:else if group.field.kind === "selector"} + <Selector field={group.field} surfaceId={spec.id} {onInvoke} /> + {:else if group.field.kind === "button"} + <Button field={group.field} surfaceId={spec.id} {onInvoke} /> + {:else if group.field.kind === "custom"} + <!-- Dispatch on rendererId (a renderer KIND, never a surface id); + unknown ids gracefully render nothing. --> + {#if group.field.rendererId === "table"} + <SurfaceTable payload={group.field.payload} /> + {/if} {/if} {/each} </article> |
