/* global React */
const { useState, useEffect, useRef, useMemo } = React;
// ============================================================
// LOGO — 3 rotated nested squares = vibration wave + precision
// ============================================================
function Logo({ size = 20, color = "currentColor" }) {
return (
);
}
function Wordmark({ showTagline = true }) {
return (
Vibranium
{showTagline && (
Obserwator wibracji
)}
);
}
// ============================================================
// STATUS — colorblind-safe via SHAPE (● = ok, ▲ = warn, ■ = alarm)
// ============================================================
const STATUS_META = {
ok: { color: "var(--ok)", weak: "var(--ok-weak)", border: "var(--ok-border)", label: "OK", shape: "circle" },
warn: { color: "var(--warn)", weak: "var(--warn-weak)", border: "var(--warn-border)", label: "Ostrzeżenie", shape: "triangle" },
alarm: { color: "var(--alarm)", weak: "var(--alarm-weak)", border: "var(--alarm-border)", label: "Alarm", shape: "square" },
idle: { color: "var(--fg-subtle)", weak: "var(--bg-sunken)", border: "var(--border)", label: "Brak", shape: "dash" },
};
function StatusGlyph({ status, size = 10 }) {
const meta = STATUS_META[status] || STATUS_META.idle;
const s = size;
if (meta.shape === "circle") {
return ;
}
if (meta.shape === "triangle") {
return ;
}
if (meta.shape === "square") {
return ;
}
return ;
}
function StatusBadge({ status, label, size = "md" }) {
const meta = STATUS_META[status] || STATUS_META.idle;
const pad = size === "sm" ? "2px 6px" : "3px 8px";
const fs = size === "sm" ? 10 : 11;
return (
{label ?? meta.label}
);
}
// ============================================================
// BUTTON
// ============================================================
function Button({ variant = "default", size = "md", children, icon, onClick, style, disabled }) {
const sizes = {
sm: { padding: "4px 10px", fontSize: 11, height: 24 },
md: { padding: "6px 12px", fontSize: 12, height: 28 },
lg: { padding: "8px 16px", fontSize: 13, height: 34 },
};
const variants = {
default: { background: "var(--surface)", color: "var(--fg)", border: "1px solid var(--border-strong)" },
primary: { background: "var(--fg)", color: "var(--bg)", border: "1px solid var(--fg)" },
ghost: { background: "transparent", color: "var(--fg)", border: "1px solid transparent" },
accent: { background: "var(--accent)", color: "var(--accent-fg)", border: "1px solid var(--accent)" },
danger: { background: "var(--alarm-weak)", color: "var(--alarm)", border: "1px solid var(--alarm-border)" },
};
return (
);
}
// ============================================================
// ICONS — thin, monoline, lucide-inspired but minimal
// ============================================================
const Ic = {
search: (p) => ,
refresh: (p) => ,
download: (p) => ,
upload: (p) => ,
mail: (p) => ,
edit: (p) => ,
eye: (p) => ,
plus: (p) => ,
chevronRight: (p) => ,
chevronDown: (p) => ,
chevronLeft: (p) => ,
arrowUp: (p) => ,
arrowDown: (p) => ,
dashboard: (p) => ,
measure: (p) => ,
chart: (p) => ,
config: (p) => ,
computer: (p) => ,
moon: (p) => ,
sun: (p) => ,
file: (p) => ,
wrench: (p) => ,
};
// ============================================================
// INPUT
// ============================================================
function Input({ icon, placeholder, value, onChange, style }) {
return (
);
}
// ============================================================
// CARD
// ============================================================
function Card({ children, style, pad = true, elev = false }) {
return (
{children}
);
}
// ============================================================
// STAT CARD
// ============================================================
function StatCard({ label, value, unit, trend, trendValue, status, note, style }) {
const trendColor = trend === "up" ? "var(--alarm)" : trend === "down" ? "var(--ok)" : "var(--fg-muted)";
return (
{(trend || note) && (
{trend === "up" && }
{trend === "down" && }
{trendValue}
{note && {note}}
)}
);
}
// ============================================================
// BREADCRUMB
// ============================================================
function Breadcrumb({ items }) {
return (
{items.map((it, i) => (
{i > 0 && }
{it.label}
))}
);
}
Object.assign(window, {
Logo, Wordmark, StatusGlyph, StatusBadge, STATUS_META,
Button, Input, Card, StatCard, Breadcrumb, Ic,
});