Embed widget: Image option scales a camera stream to the tile
Docs / docs (push) Successful in 19s
Playwright Tests / test-playwright (1, 2) (push) Failing after 3m41s
Playwright Tests / test-playwright (2, 2) (push) Failing after 2m21s
pre-commit / pre-commit (push) Failing after 2m36s
Test Backend / test-backend (push) Failing after 2m58s
Compose Smoke Test / test-compose (push) Successful in 31s
Playwright Tests / merge-reports (push) Successful in 1m36s

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
2026-10-11 20:23:37 +02:00
co-authored by Claude Opus 5.5
parent 022079728c
commit 9a84d27347
3 changed files with 28 additions and 0 deletions
+4
View File
@@ -161,6 +161,10 @@ this app's own address, or the hub's when the app is reached through one, shows
a notice instead: on that origin the page could reach into the app and read
your session.
**Image** draws the address as a picture scaled to fit the tile, rather than
as a page. Use it for a camera's MJPEG stream (`http://<camera>/stream`) or a
snapshot URL, which a page frame would show at the camera's native size.
## Dashboard settings
Most of what a dashboard carries is a widget: a tile bound to a message. A
@@ -582,6 +582,16 @@ export function WidgetPanel({
onCheckedChange={(trusted) => set({ trusted })}
/>
</div>
<div className="flex items-center justify-between gap-2 text-sm">
<FieldLabel help="Draws the address as a picture scaled to the tile, for a camera stream or snapshot rather than a page.">
Image
</FieldLabel>
<Switch
checked={cfg.image === true}
aria-label="Image"
onCheckedChange={(image) => set({ image })}
/>
</div>
</>
) : widget.type === "markdown" ? (
<div className="grid gap-1.5">
@@ -488,11 +488,25 @@ export function onOrigin(url: string, origin: string): boolean {
* its own. **Trusted** keeps it in its own origin, which most interactive
* sites need to start (the demo's weather map renders an unstyled list
* without it), and is refused for this app's own origin.
*
* **Image** draws the address as a picture scaled to the tile instead: a
* camera's MJPEG stream or snapshot, which a frame would show at its native
* size. An image runs nothing, so it needs no sandbox.
*/
function EmbedWidget({ widget }: WidgetProps) {
const url = embedUrl(widget)
const trusted = config(widget).trusted === true
if (!url) return <p className="text-muted-foreground">Give it an address.</p>
if (config(widget).image === true) {
return (
<img
src={url}
alt={widget.title || url}
referrerPolicy="no-referrer"
className="h-full w-full rounded-md object-contain"
/>
)
}
if (trusted && onOrigin(url, window.location.origin)) {
return (
<p className="text-muted-foreground" data-testid="embed-refused">