返回 CodeWhale
status-badge.tsx
根目录 / web / components / status-badge.tsx
1 /**
2 * State is a mark and a word, never colour alone.
3 *
4 * <Status> is the general form: a dot in the tone's colour and the word in
5 * text. `live` lights its dot (bioluminescence) and is only for something
6 * the site actually observes; nothing static qualifies.
7 *
8 * <StatusBadge> keeps the older availability vocabulary (experimental,
9 * preview, pending, unavailable) for the pages that still use it.
10 */
11
12 import type { ReactNode } from "react";
13 import type { LocalizedText } from "@/lib/content/vocabulary";
14 import { pickText } from "@/lib/i18n/dictionaries";
15
16 export type StatusTone = "ready" | "attention" | "idle" | "live" | "danger" | "accent";
17
18 export function Status({ tone, children }: { tone: StatusTone; children: ReactNode }) {
19 return (
20 <span className={`status status-${tone}`}>
21 <span className="status-dot" aria-hidden="true" />
22 {children}
23 </span>
24 );
25 }
26
27 export type StatusKind = "experimental" | "preview" | "pending" | "unavailable";
28
29 const DEFAULT_LABELS: Record<StatusKind, LocalizedText> = {
30 experimental: { en: "Experimental", zh: "实验性" },
31 preview: { en: "Preview", zh: "预览" },
32 pending: { en: "Pending", zh: "待就绪" },
33 unavailable: { en: "Unavailable", zh: "暂不可用" },
34 };
35
36 export function StatusBadge({
37 kind,
38 locale = "en",
39 label,
40 }: {
41 kind: StatusKind;
42 locale?: string;
43 /** Overrides the default per-kind label (e.g. a media entry's pendingLabel). */
44 label?: LocalizedText;
45 }) {
46 const text = pickText(label ?? DEFAULT_LABELS[kind], locale);
47
48 return (
49 <span className={`status-badge status-badge-${kind}`}>
50 <span className="status-badge-dot" aria-hidden="true" />
51 {text}
52 </span>
53 );
54 }
55
55 lines Plain Text