Mark beta firmware versions with an amber Beta badge

Pre-release builds now carry a `beta` flag in each group's list.json.
Surface it in the UI: a small amber Beta pill (and amber card border)
next to the version on the landing list, in the version switcher, and
in the diff version-history panel, so betas are visually distinct from
stable releases while remaining fully diffable against historical builds.
This commit is contained in:
cc
2026-06-10 13:19:41 +02:00
parent 0d58645da3
commit 9846dacbfc
5 changed files with 51 additions and 9 deletions
+3 -1
View File
@@ -29,6 +29,7 @@ import { createEngine } from "@/lib/engine";
import { getTopTokens, tokenizeKeys } from "@/lib/tokenizer";
import type { OS } from "@/lib/types";
import { cn } from "@/lib/utils";
import { BetaBadge } from "@/components/beta-badge";
function versionTag(os: OS) {
return `${os.version}_${os.build}`;
@@ -198,8 +199,9 @@ function VersionHistoryPanel({
: "text-muted-foreground hover:text-foreground",
)}
>
<span className="block truncate font-mono">
<span className="flex items-center gap-1.5 truncate font-mono">
{version.version}
{version.beta && <BetaBadge />}
</span>
<span
className={cn(
+20
View File
@@ -0,0 +1,20 @@
import { cn } from "@/lib/utils";
/**
* Small amber "Beta" pill shown next to pre-release firmware versions.
* Beta builds are surfaced by the `beta` flag in each group's list.json.
*/
export function BetaBadge({ className }: { className?: string }) {
return (
<span
className={cn(
"inline-flex items-center rounded-md border px-1.5 py-0.5 text-[10px] font-semibold uppercase leading-none tracking-wide",
"border-amber-400/50 bg-amber-50 text-amber-700",
"dark:border-amber-500/40 dark:bg-amber-950/40 dark:text-amber-300",
className,
)}
>
Beta
</span>
);
}
+22 -6
View File
@@ -8,6 +8,8 @@ import { useEffect, useMemo, useState } from "react";
import { useQueryFilter } from "@/hooks/use-query-filter";
import { dataURL } from "@/lib/env";
import type { Group, OS } from "@/lib/types";
import { cn } from "@/lib/utils";
import { BetaBadge } from "./beta-badge";
import { HeaderPortal } from "./header-portal";
import { Button } from "./ui/button";
import { Input } from "./ui/input";
@@ -309,13 +311,21 @@ export default function OSList() {
>
<Link
href={`/os/keys?os=${group.name}/${os.version}_${os.build}`}
className="block p-3 border border-border rounded-lg hover:border-foreground/20 transition-colors hover:bg-accent/50"
className={cn(
"block p-3 border rounded-lg transition-colors hover:bg-accent/50",
os.beta
? "border-amber-400/50 hover:border-amber-500/70 dark:border-amber-500/40"
: "border-border hover:border-foreground/20",
)}
>
<div className="text-xs text-muted-foreground mb-1 truncate">
{os.name}
</div>
<div className="flex justify-between items-center">
<span className="font-medium">{os.version}</span>
<div className="flex justify-between items-center gap-2">
<span className="font-medium flex items-center gap-1.5">
{os.version}
{os.beta && <BetaBadge />}
</span>
<span className="text-xs text-muted-foreground font-mono">
{os.build}
</span>
@@ -339,14 +349,20 @@ export default function OSList() {
>
<Link
href={`/os/keys?os=${group.name}/${os.version}_${os.build}`}
className="block p-3 border border-border rounded-lg hover:border-foreground/20 transition-colors hover:bg-accent/50"
className={cn(
"block p-3 border rounded-lg transition-colors hover:bg-accent/50",
os.beta
? "border-amber-400/50 hover:border-amber-500/70 dark:border-amber-500/40"
: "border-border hover:border-foreground/20",
)}
>
<div className="text-xs text-muted-foreground mb-1 truncate">
{os.name}
</div>
<div className="flex justify-between items-center">
<span className="font-medium">
<div className="flex justify-between items-center gap-2">
<span className="font-medium flex items-center gap-1.5">
{os.version}
{os.beta && <BetaBadge />}
</span>
<span className="text-xs text-muted-foreground font-mono">
{os.build}
+5 -2
View File
@@ -13,6 +13,7 @@ import { ChevronDown, Check } from "lucide-react";
import type { OS } from "@/lib/types";
import { withBase, basePath, dataURL } from "@/lib/env";
import { BetaBadge } from "@/components/beta-badge";
function compareVersion(a: string, b: string) {
const l1 = a.split(".").map(Number);
@@ -83,11 +84,12 @@ export function VersionSwitcher({ currentOs }: { currentOs: string }) {
{loading ? (
"Loading..."
) : currentVersion ? (
<span>
<span className="flex items-center gap-1.5">
{currentVersion.version}{" "}
<span className="text-muted-foreground text-xs">
({currentVersion.build})
</span>
{currentVersion.beta && <BetaBadge />}
</span>
) : (
currentBuild
@@ -123,11 +125,12 @@ export function VersionSwitcher({ currentOs }: { currentOs: string }) {
isSelected ? "bg-accent" : ""
}`}
>
<span className="font-mono">
<span className="font-mono flex items-center gap-1.5">
{os.version}{" "}
<span className="text-muted-foreground text-xs">
({os.build})
</span>
{os.beta && <BetaBadge />}
</span>
{isSelected && <Check className="h-4 w-4" />}
</button>
+1
View File
@@ -3,6 +3,7 @@ export interface OS {
build: string;
version: string;
devices: string[];
beta?: boolean;
}
export interface Group {