diff --git a/README.md b/README.md index 7dec6c9..2d794fa 100644 --- a/README.md +++ b/README.md @@ -51,6 +51,8 @@ After rebuilding a project, run its `firmware\export_from_build.ps1`, then click Preferred card preview: **`media/preview.html`** — HTML recreation of the on-device LVGL UI (320×240). Auto-detected if present. +Cards also offer a **Hardware** tab (sensor / module still). Mapping lives in `lib/sensor-media.ts`; images under `public/sensors/` (see `ATTRIBUTION.md`). + Optional `meta.json` beside the `.bin` files: ```json diff --git a/components/firmware-preview.tsx b/components/firmware-preview.tsx index c27339c..4ac2774 100644 --- a/components/firmware-preview.tsx +++ b/components/firmware-preview.tsx @@ -1,13 +1,17 @@ "use client"; import { useEffect, useRef, useState } from "react"; +import { useTranslations } from "next-intl"; import type { FirmwareInfo } from "@/lib/firmware"; +import { sensorMediaForProject } from "@/lib/sensor-media"; import { cn } from "@/lib/utils"; const SCREEN_W = 320; const SCREEN_H = 240; -/** Renders HTML on-device UI mock (preferred) — never uses raster covers. */ +type Tab = "ui" | "sensor"; + +/** On-device HTML UI mock + optional hardware still, switchable via tabs. */ export function FirmwarePreview({ fw, className, @@ -17,12 +21,20 @@ export function FirmwarePreview({ className?: string; title?: string; }) { + const t = useTranslations("firmware"); const hostRef = useRef(null); const [scale, setScale] = useState(1); + const sensor = sensorMediaForProject(fw.project); + const hasUi = Boolean(fw.media.preview); + const [tab, setTab] = useState(hasUi ? "ui" : "sensor"); + + useEffect(() => { + setTab(hasUi ? "ui" : sensor ? "sensor" : "ui"); + }, [fw.id, hasUi, sensor]); useEffect(() => { const el = hostRef.current; - if (!el) return; + if (!el || tab !== "ui") return; const update = () => { const { width, height } = el.getBoundingClientRect(); @@ -34,34 +46,9 @@ export function FirmwarePreview({ const ro = new ResizeObserver(update); ro.observe(el); return () => ro.disconnect(); - }, [fw.media.preview]); + }, [fw.media.preview, tab]); - if (fw.media.preview) { - return ( -
-