/* global React */
// Shared icons + UI primitives for Content Radar
// All icons follow Lucide stroke conventions (2px stroke, currentColor)
const Icon = ({ d, size = 16, stroke = 2, fill = "none", children, style }) => (
React.createElement("svg", {
width: size, height: size, viewBox: "0 0 24 24",
fill, stroke: "currentColor", strokeWidth: stroke,
strokeLinecap: "round", strokeLinejoin: "round",
style,
}, children || (d && React.createElement("path", { d })))
);
const Icons = {
Inbox: (p) => ,
Doc: (p) => ,
Send: (p) => ,
Settings: (p) => ,
Plus: (p) => ,
Check: (p) => ,
X: (p) => ,
Sun: (p) => ,
Moon: (p) => ,
ChevronDown: (p) => ,
ChevronUp: (p) => ,
ChevronRight:(p) => ,
ChevronLeft: (p) => ,
Refresh: (p) => ,
Edit: (p) => ,
Sparkles: (p) => ,
Copy: (p) => ,
Trash: (p) => ,
AlertTriangle: (p) => ,
Info: (p) => ,
Search: (p) => ,
Link: (p) => ,
Stop: (p) => ,
Spinner: ({ size = 14 }) => (
),
Clipboard: (p) => ,
Branch: (p) => ,
Dot: ({ color = "currentColor", size = 6 }) => (
),
};
// Inject keyframes once
if (typeof document !== "undefined" && !document.getElementById("cr-keyframes")) {
const style = document.createElement("style");
style.id = "cr-keyframes";
style.textContent = `@keyframes cr-spin { to { transform: rotate(360deg); } }`;
document.head.appendChild(style);
}
// ---- Buttons ----
const Btn = ({ kind = "secondary", icon, children, onClick, disabled, size, type, title }) => {
const cls = ["btn"];
cls.push(`btn--${kind}`);
if (size) cls.push(`btn--${size}`);
if (!children && icon) cls.push("btn--icon");
return (
);
};
// ---- Tag / Badge ----
const Tag = ({ tone = "default", children, icon }) => {
const cls = ["tag"];
if (tone !== "default") cls.push(`tag--${tone}`);
return {icon}{children};
};
// ---- Empty state ----
const EmptyState = ({ icon, title, body, actions }) => (
{icon}
{title}
{body}
{actions ?
{actions}
: null}
);
// ---- Modal ----
const Modal = ({ title, onClose, children, footer, width }) => {
React.useEffect(() => {
const onKey = (e) => { if (e.key === "Escape") onClose(); };
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [onClose]);
return (
e.stopPropagation()}>
{title}
{children}
{footer ?
{footer}
: null}
);
};
// ---- Toast ----
const Toast = ({ message, hash }) => (
{message}
{hash ? {hash} : null}
);
// ---- Source favicon-style chip ----
const SourceChip = ({ domain }) => {
const letter = domain.replace(/^www\./, "")[0]?.toUpperCase() || "?";
return (
{letter}
{domain}
);
};
// ---- Time formatting ----
const formatRelative = (ts) => {
const diff = Date.now() - ts;
const m = Math.round(diff / 60_000);
if (m < 1) return "только что";
if (m < 60) return `${m} мин назад`;
const h = Math.round(m / 60);
if (h < 24) return `${h} ${h === 1 ? "час" : h < 5 ? "часа" : "часов"} назад`;
const d = Math.round(h / 24);
return `${d} ${d === 1 ? "день" : d < 5 ? "дня" : "дней"} назад`;
};
window.CR_UI = { Icons, Btn, Tag, EmptyState, Modal, Toast, SourceChip, formatRelative };