Size HTML firmware previews by board (480x320 for 3.5).
EOF Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -31,7 +31,13 @@ export function FirmwareCard({
|
|||||||
: "border-[var(--line)] bg-[rgba(0,0,0,0.22)] hover:-translate-y-0.5 hover:border-[rgba(240,197,10,0.35)] hover:bg-[rgba(240,197,10,0.04)]"
|
: "border-[var(--line)] bg-[rgba(0,0,0,0.22)] hover:-translate-y-0.5 hover:border-[rgba(240,197,10,0.35)] hover:bg-[rgba(240,197,10,0.04)]"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="relative aspect-[4/3] w-full overflow-hidden border-b border-[var(--line)]">
|
<div
|
||||||
|
className={
|
||||||
|
fw.boardId === "esp32-3248s035"
|
||||||
|
? "relative aspect-[3/2] w-full overflow-hidden border-b border-[var(--line)]"
|
||||||
|
: "relative aspect-[4/3] w-full overflow-hidden border-b border-[var(--line)]"
|
||||||
|
}
|
||||||
|
>
|
||||||
<FirmwarePreview fw={fw} />
|
<FirmwarePreview fw={fw} />
|
||||||
<div className="pointer-events-none absolute bottom-2 left-2 flex gap-1">
|
<div className="pointer-events-none absolute bottom-2 left-2 flex gap-1">
|
||||||
{hasPreview && (
|
{hasPreview && (
|
||||||
|
|||||||
@@ -36,7 +36,13 @@ export function FirmwareDetail({
|
|||||||
</h3>
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="aspect-[4/3] w-full border-b border-[var(--line)] bg-black/40">
|
<div
|
||||||
|
className={
|
||||||
|
fw.boardId === "esp32-3248s035"
|
||||||
|
? "aspect-[3/2] w-full border-b border-[var(--line)] bg-black/40"
|
||||||
|
: "aspect-[4/3] w-full border-b border-[var(--line)] bg-black/40"
|
||||||
|
}
|
||||||
|
>
|
||||||
{fw.media.preview ? (
|
{fw.media.preview ? (
|
||||||
<FirmwarePreview fw={fw} />
|
<FirmwarePreview fw={fw} />
|
||||||
) : fw.media.video ? (
|
) : fw.media.video ? (
|
||||||
|
|||||||
@@ -3,12 +3,10 @@
|
|||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { useTranslations } from "next-intl";
|
import { useTranslations } from "next-intl";
|
||||||
import type { FirmwareInfo } from "@/lib/firmware";
|
import type { FirmwareInfo } from "@/lib/firmware";
|
||||||
|
import { boardPreviewSize } from "@/lib/boards";
|
||||||
import { sensorMediaForProject } from "@/lib/sensor-media";
|
import { sensorMediaForProject } from "@/lib/sensor-media";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const SCREEN_W = 320;
|
|
||||||
const SCREEN_H = 240;
|
|
||||||
|
|
||||||
type Tab = "ui" | "sensor";
|
type Tab = "ui" | "sensor";
|
||||||
|
|
||||||
/** On-device HTML UI mock + optional hardware still, switchable via tabs. */
|
/** On-device HTML UI mock + optional hardware still, switchable via tabs. */
|
||||||
@@ -24,6 +22,7 @@ export function FirmwarePreview({
|
|||||||
const t = useTranslations("firmware");
|
const t = useTranslations("firmware");
|
||||||
const hostRef = useRef<HTMLDivElement>(null);
|
const hostRef = useRef<HTMLDivElement>(null);
|
||||||
const [scale, setScale] = useState(1);
|
const [scale, setScale] = useState(1);
|
||||||
|
const { w: screenW, h: screenH } = boardPreviewSize(fw.boardId);
|
||||||
const sensor = sensorMediaForProject(fw.project);
|
const sensor = sensorMediaForProject(fw.project);
|
||||||
const hasUi = Boolean(fw.media.preview);
|
const hasUi = Boolean(fw.media.preview);
|
||||||
const [tab, setTab] = useState<Tab>(hasUi ? "ui" : "sensor");
|
const [tab, setTab] = useState<Tab>(hasUi ? "ui" : "sensor");
|
||||||
@@ -39,14 +38,14 @@ export function FirmwarePreview({
|
|||||||
const update = () => {
|
const update = () => {
|
||||||
const { width, height } = el.getBoundingClientRect();
|
const { width, height } = el.getBoundingClientRect();
|
||||||
if (width <= 0 || height <= 0) return;
|
if (width <= 0 || height <= 0) return;
|
||||||
setScale(Math.min(width / SCREEN_W, height / SCREEN_H));
|
setScale(Math.min(width / screenW, height / screenH));
|
||||||
};
|
};
|
||||||
|
|
||||||
update();
|
update();
|
||||||
const ro = new ResizeObserver(update);
|
const ro = new ResizeObserver(update);
|
||||||
ro.observe(el);
|
ro.observe(el);
|
||||||
return () => ro.disconnect();
|
return () => ro.disconnect();
|
||||||
}, [fw.media.preview, tab]);
|
}, [fw.media.preview, tab, screenW, screenH]);
|
||||||
|
|
||||||
const showTabs = hasUi && Boolean(sensor);
|
const showTabs = hasUi && Boolean(sensor);
|
||||||
|
|
||||||
@@ -113,8 +112,8 @@ export function FirmwarePreview({
|
|||||||
<iframe
|
<iframe
|
||||||
title={title || `${fw.name} UI preview`}
|
title={title || `${fw.name} UI preview`}
|
||||||
src={fw.media.preview!}
|
src={fw.media.preview!}
|
||||||
width={SCREEN_W}
|
width={screenW}
|
||||||
height={SCREEN_H}
|
height={screenH}
|
||||||
loading="lazy"
|
loading="lazy"
|
||||||
sandbox="allow-scripts"
|
sandbox="allow-scripts"
|
||||||
tabIndex={-1}
|
tabIndex={-1}
|
||||||
|
|||||||
@@ -60,3 +60,9 @@ export function resolveBoardId(boardField: string | null | undefined): string {
|
|||||||
export function getBoard(id: string): BoardDefinition | undefined {
|
export function getBoard(id: string): BoardDefinition | undefined {
|
||||||
return BOARDS.find((b) => b.id === id);
|
return BOARDS.find((b) => b.id === id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Logical UI resolution used by HTML firmware previews (matches UX/UY). */
|
||||||
|
export function boardPreviewSize(boardId: string): { w: number; h: number } {
|
||||||
|
if (boardId === "esp32-3248s035") return { w: 480, h: 320 };
|
||||||
|
return { w: 320, h: 240 };
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user