// primitives.jsx — shared Chrono UI atoms
// ── Icons (custom-drawn, original) ────────────────────────────────────────
const Icon = {
cal: (p) => (
),
focus: (p) => (
),
ai: (p) => (
),
settings: (p) => (
),
user: (p) => (
),
plus: (p) => (
),
back: (p) => (
),
fwd: (p) => (
),
close: (p) => (
),
check: (p) => (
),
send: (p) => (
),
play: (p) => (
),
pause: (p) => (
),
stop: (p) => (
),
search: (p) => (
),
bell: (p) => (
),
pin: (p) => (
),
loop: (p) => (
),
pin2: (p) => (
),
tag: (p) => (
),
flame: (p) => (
),
sparkle: (p) => (
),
apple: (p) => (
),
google: (p) => (
),
mail: (p) => (
),
trash: (p) => (
),
edit: (p) => (
),
link: (p) => (
),
bolt: (p) => (
),
brain: (p) => (
),
arrowR: (p) => (
),
more: (p) => (
),
undo: (p) => (
),
redo: (p) => (
),
filter: (p) => (
),
text: (p) => (
),
clock: (p) => (
),
lock: (p) => (
),
};
// ── Gradient blob avatar (deterministic from string) ──────────────────────
function GradientBlob({ seed = 'C', size = 40, style }) {
// Deterministic hue from seed
const h = React.useMemo(() => {
let n = 0;
for (let i = 0; i < seed.length; i++) n = (n * 31 + seed.charCodeAt(i)) >>> 0;
return n % 360;
}, [seed]);
const h2 = (h + 60) % 360;
return (
);
}
// ── Glass surface ─────────────────────────────────────────────────────────
function Glass({ children, dark, style, intensity = 16, radius = 16 }) {
return (
{children}
);
}
// ── Subtle button ─────────────────────────────────────────────────────────
function Btn({ children, onClick, primary, ghost, accent, danger, style, theme, disabled }) {
const t = theme;
let bg, fg, border, shadow;
if (primary) {
bg = `linear-gradient(180deg, ${t.accentColor}, ${t.accentColor}DD)`;
fg = '#fff';
border = 'transparent';
shadow = t.accentGlow;
} else if (danger) {
bg = t.isDark ? 'rgba(255,92,122,0.12)' : 'rgba(255,92,122,0.08)';
fg = '#FF5C7A';
border = t.isDark ? 'rgba(255,92,122,0.25)' : 'rgba(255,92,122,0.18)';
shadow = 'none';
} else if (ghost) {
bg = 'transparent';
fg = t.text;
border = 'transparent';
shadow = 'none';
} else {
bg = t.isDark ? 'rgba(255,255,255,0.05)' : 'rgba(10,12,20,0.04)';
fg = t.text;
border = t.hairline;
shadow = 'none';
}
return (
);
}
// ── Hairline divider ──────────────────────────────────────────────────────
function Hair({ theme, style }) {
return ;
}
// ── Status bar (white text on dark) ───────────────────────────────────────
// Re-use IOSStatusBar from frame; it adapts via dark prop.
// ── Tab bar ───────────────────────────────────────────────────────────────
function TabBar({ active, onChange, theme }) {
const items = [
{ id: 'calendar', label: 'Calendar', icon: Icon.cal },
{ id: 'focus', label: 'Focus', icon: Icon.focus },
{ id: 'ai', label: 'Assistant', icon: Icon.ai },
{ id: 'settings', label: 'Settings', icon: Icon.settings },
{ id: 'profile', label: 'Profile', icon: Icon.user },
];
return (
{items.map(it => {
const isActive = active === it.id;
return (
);
})}
);
}
// ── Ambient glow background ───────────────────────────────────────────────
function AmbientBG({ theme, intensity = 1 }) {
if (theme.bg === 'true-black') return null;
return (
<>
>
);
}
// ── Logo ──────────────────────────────────────────────────────────────────
// Original mark: nested hex/rotor — six-petal aperture suggesting
// time segments + a futuristic chronograph rotor. Not a clock-with-hands
// trope; geometric, original, OK against trademark registries.
function ChronoLogo({ size = 48, color, glow }) {
const id = `cl-${size}-${Math.round((color||'#000').charCodeAt(1))}`;
return (
);
}
Object.assign(window, { Icon, GradientBlob, Glass, Btn, Hair, TabBar, AmbientBG, ChronoLogo });