Files
website/src/components/BoardSelector.svelte
T
swaits 81130108b7 feat: add ELECROW ThinkNode-M2 board support
ESP32-S3 Meshtastic handset with SH1106 OLED. Flashes via the
CP2102 bridge, so this board is download-only like heltec_v3_uart —
Web Serial is unreliable through the bridge. The existing
`download-only` branch of EspFlashFlow surfaces the CP2102 warning
plus a .bin download and espflash CLI instructions, so no new
component code is needed.

ESP32-S3 grid in BoardSelector goes from sm:grid-cols-3 to
sm:grid-cols-2 lg:grid-cols-4 to accommodate the fourth ESP board.
Homepage Supported Boards grid drops from lg:grid-cols-5 to
lg:grid-cols-3 (3x2 layout) — six 200-px cards in one row was tight.
2026-04-11 22:51:45 -06:00

93 lines
3.3 KiB
Svelte

<script lang="ts">
import type { BoardDef } from "../lib/types";
import { boards } from "../lib/boards";
interface Props {
selected: BoardDef | null;
onselect: (board: BoardDef) => void;
}
let { selected, onselect }: Props = $props();
const espBoards = boards.filter((b) => b.family === "esp32s3");
const rpBoards = boards.filter((b) => b.family === "rp2040");
const nrfBoards = boards.filter((b) => b.family === "nrf52840");
function badgeText(board: BoardDef): string {
switch (board.flashMethod) {
case "web-serial":
return "Web Flash";
case "uf2":
return "UF2 Download";
case "download-only":
return "CLI Only";
}
}
function badgeColor(board: BoardDef): string {
switch (board.flashMethod) {
case "web-serial":
return "text-accent";
case "uf2":
return "text-info";
case "download-only":
return "text-warn";
}
}
</script>
<div>
<h3 class="font-mono text-sm text-text-muted mb-3 uppercase tracking-wider">Select Board</h3>
<p class="text-xs text-text-dim mb-2 font-mono">ESP32-S3</p>
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-3 mb-4">
{#each espBoards as board}
<button
class="text-left bg-bg-card border p-4 rounded transition-all cursor-pointer
{selected?.id === board.id
? 'border-accent shadow-[0_0_12px_oklch(from_var(--color-accent)_l_c_h_/_0.15)]'
: 'border-border hover:border-border-bright'}"
onclick={() => onselect(board)}
>
<div class="font-mono font-medium text-text text-sm">{board.name}</div>
<div class="text-xs text-text-muted mt-1">{board.mcu} &middot; {board.radio}</div>
<div class="text-xs {badgeColor(board)} mt-2 font-mono">{badgeText(board)}</div>
</button>
{/each}
</div>
<p class="text-xs text-text-dim mb-2 font-mono">nRF52840</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3 mb-4">
{#each nrfBoards as board}
<button
class="text-left bg-bg-card border p-4 rounded transition-all cursor-pointer
{selected?.id === board.id
? 'border-accent shadow-[0_0_12px_oklch(from_var(--color-accent)_l_c_h_/_0.15)]'
: 'border-border hover:border-border-bright'}"
onclick={() => onselect(board)}
>
<div class="font-mono font-medium text-text text-sm">{board.name}</div>
<div class="text-xs text-text-muted mt-1">{board.mcu} &middot; {board.radio}</div>
<div class="text-xs {badgeColor(board)} mt-2 font-mono">{badgeText(board)}</div>
</button>
{/each}
</div>
<p class="text-xs text-text-dim mb-2 font-mono">RP2040</p>
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
{#each rpBoards as board}
<button
class="text-left bg-bg-card border p-4 rounded transition-all cursor-pointer
{selected?.id === board.id
? 'border-accent shadow-[0_0_12px_oklch(from_var(--color-accent)_l_c_h_/_0.15)]'
: 'border-border hover:border-border-bright'}"
onclick={() => onselect(board)}
>
<div class="font-mono font-medium text-text text-sm">{board.name}</div>
<div class="text-xs text-text-muted mt-1">{board.mcu} &middot; {board.radio}</div>
<div class="text-xs {badgeColor(board)} mt-2 font-mono">{badgeText(board)}</div>
</button>
{/each}
</div>
</div>