summaryrefslogtreecommitdiffhomepage
path: root/src/features/surface-host/ui
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/surface-host/ui')
-rw-r--r--src/features/surface-host/ui/Button.svelte21
-rw-r--r--src/features/surface-host/ui/Progress.svelte13
-rw-r--r--src/features/surface-host/ui/Selector.svelte32
-rw-r--r--src/features/surface-host/ui/Stat.svelte10
-rw-r--r--src/features/surface-host/ui/SurfaceView.svelte33
-rw-r--r--src/features/surface-host/ui/Toggle.svelte25
6 files changed, 134 insertions, 0 deletions
diff --git a/src/features/surface-host/ui/Button.svelte b/src/features/surface-host/ui/Button.svelte
new file mode 100644
index 0000000..62d7acf
--- /dev/null
+++ b/src/features/surface-host/ui/Button.svelte
@@ -0,0 +1,21 @@
+<script lang="ts">
+ import type { InvokeMessage } from "@dispatch/ui-contract";
+ import type { ButtonFieldView } from "../logic/types";
+
+ let {
+ field,
+ surfaceId,
+ onInvoke,
+ }: { field: ButtonFieldView; surfaceId: string; onInvoke: (msg: InvokeMessage) => void } =
+ $props();
+
+ function handleClick() {
+ onInvoke({
+ type: "invoke",
+ surfaceId,
+ actionId: field.action.actionId,
+ });
+ }
+</script>
+
+<button onclick={handleClick}>{field.label}</button>
diff --git a/src/features/surface-host/ui/Progress.svelte b/src/features/surface-host/ui/Progress.svelte
new file mode 100644
index 0000000..cba9e0f
--- /dev/null
+++ b/src/features/surface-host/ui/Progress.svelte
@@ -0,0 +1,13 @@
+<script lang="ts">
+ import type { ProgressFieldView } from "../logic/types";
+
+ let { field }: { field: ProgressFieldView } = $props();
+
+ const percent = $derived(Math.round(field.value * 100));
+</script>
+
+<div>
+ <span>{field.label}</span>
+ <progress max="100" value={percent}>{percent}%</progress>
+ <span>{percent}%</span>
+</div>
diff --git a/src/features/surface-host/ui/Selector.svelte b/src/features/surface-host/ui/Selector.svelte
new file mode 100644
index 0000000..2da104f
--- /dev/null
+++ b/src/features/surface-host/ui/Selector.svelte
@@ -0,0 +1,32 @@
+<script lang="ts">
+ import type { InvokeMessage } from "@dispatch/ui-contract";
+ import type { SelectorFieldView } from "../logic/types";
+
+ let {
+ field,
+ surfaceId,
+ onInvoke,
+ }: { field: SelectorFieldView; surfaceId: string; onInvoke: (msg: InvokeMessage) => void } =
+ $props();
+
+ function handleChange(event: Event) {
+ const target = event.target as HTMLSelectElement;
+ onInvoke({
+ type: "invoke",
+ surfaceId,
+ actionId: field.action.actionId,
+ payload: target.value,
+ });
+ }
+</script>
+
+<label>
+ {field.label}
+ <select onchange={handleChange}>
+ {#each field.options as option (option.value)}
+ <option value={option.value} selected={option.value === field.value}>
+ {option.label}
+ </option>
+ {/each}
+ </select>
+</label>
diff --git a/src/features/surface-host/ui/Stat.svelte b/src/features/surface-host/ui/Stat.svelte
new file mode 100644
index 0000000..e184dab
--- /dev/null
+++ b/src/features/surface-host/ui/Stat.svelte
@@ -0,0 +1,10 @@
+<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/SurfaceView.svelte b/src/features/surface-host/ui/SurfaceView.svelte
new file mode 100644
index 0000000..4207913
--- /dev/null
+++ b/src/features/surface-host/ui/SurfaceView.svelte
@@ -0,0 +1,33 @@
+<script lang="ts">
+ import type { InvokeMessage, SurfaceSpec } from "@dispatch/ui-contract";
+ import { 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 Toggle from "./Toggle.svelte";
+
+ let {
+ spec,
+ onInvoke,
+ }: { spec: SurfaceSpec; onInvoke: (msg: InvokeMessage) => void } = $props();
+
+ const plan = $derived(planSurface(spec));
+</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} />
+ {/if}
+ {/each}
+</article>
diff --git a/src/features/surface-host/ui/Toggle.svelte b/src/features/surface-host/ui/Toggle.svelte
new file mode 100644
index 0000000..aec8f4e
--- /dev/null
+++ b/src/features/surface-host/ui/Toggle.svelte
@@ -0,0 +1,25 @@
+<script lang="ts">
+ import type { InvokeMessage } from "@dispatch/ui-contract";
+ import type { ToggleFieldView } from "../logic/types";
+
+ let {
+ field,
+ surfaceId,
+ onInvoke,
+ }: { field: ToggleFieldView; surfaceId: string; onInvoke: (msg: InvokeMessage) => void } =
+ $props();
+
+ function handleChange() {
+ onInvoke({
+ type: "invoke",
+ surfaceId,
+ actionId: field.action.actionId,
+ payload: !field.value,
+ });
+ }
+</script>
+
+<label>
+ <input type="checkbox" checked={field.value} onchange={handleChange} />
+ {field.label}
+</label>