const { useState: v7us, useEffect: v7ue, useRef: v7ur } = React; const ICONS = { ArrowRight:'M5 12h14M12 5l7 7-7 7', ArrowUpRight:'M7 17L17 7M7 7h10v10', Check:'M20 6L9 17l-5-5', X:'M18 6L6 18M6 6l12 12', Plus:'M12 5v14M5 12h14', Play:'M8 5v14l11-7L8 5z', Minus:'M5 12h14', Shield:'M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z', Lock:'M19 11H5a2 2 0 0 0-2 2v7a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7a2 2 0 0 0-2-2zM7 11V7a5 5 0 0 1 10 0v4', Eye:'M1 12s4-8 11-8 11 8 11 8-4 8-11 8-11-8-11-8z M12 12m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0', ChevronRight:'M9 18l6-6-6-6', Sparkle:'M12 3l1.6 4.4L18 9l-4.4 1.6L12 15l-1.6-4.4L6 9l4.4-1.6L12 3z', Bell:'M18 8a6 6 0 1 0-12 0c0 7-3 9-3 9h18s-3-2-3-9 M13.7 21a2 2 0 0 1-3.4 0', AlertTriangle:'M10.3 3.9L1.8 18a2 2 0 0 0 1.7 3h17a2 2 0 0 0 1.7-3L13.7 3.9a2 2 0 0 0-3.4 0z M12 9v4 M12 17h.01', }; function Icon({ name, size=16, stroke=1.7, color='currentColor', className='' }) { const d = ICONS[name]; if (!d) return ; const filled = name === 'Play'; return ( {d.split(' M').map((s,i)=>())} ); } function Btn({ variant='primary', size='md', children, icon, onClick, className='', as:As='button', ...rest }) { const C = window.DT.color; const sizes = { sm:'h-10 px-4 text-[13px]', md:'h-12 px-6 text-[14px]', lg:'h-14 px-8 text-[15px]' }; const styles = { primary: { background:C.ink, color:C.cream, border:'1px solid '+C.ink }, grass: { background:C.grass, color:'#FFFFFF', border:'1px solid '+C.grass }, accent: { background:C.accent, color:C.cream, border:'1px solid '+C.accent }, ghost: { background:'transparent', color:C.ink, border:'1.5px solid rgba(19,17,14,0.18)' }, ghostInv: { background:'transparent', color:C.cream, border:'1.5px solid rgba(247,244,236,0.30)' }, light: { background:'#FFFFFF', color:C.ink, border:'1px solid rgba(19,17,14,0.12)' }, }; return ( {children} {icon && } ); } function Eyebrow({ children, dark=false, color, className='' }) { const C = window.DT.color; const fg = color || (dark?'rgba(247,244,236,0.7)':C.inkMute); return (
{children}
); } function Reveal({ children, delay=0, y=20, className='' }) { const ref = v7ur(null); const [shown,setShown] = v7us(false); v7ue(()=>{ const el = ref.current; if (!el) return; const io = new IntersectionObserver(([e])=>{ if(e.isIntersecting){ setShown(true); io.disconnect(); }}, { threshold:0.12 }); io.observe(el); return ()=>io.disconnect(); },[]); return (
{children}
); } // status pill used across portal UI function StatusPill({ kind, dark=false }) { const C = window.DT.color; const map = { in_progress: { label:'В работе', bg:'#3970C2', fg:'#FFFFFF' }, done: { label:'Выполнено', bg:C.grass, fg:'#FFFFFF' }, approval: { label:'Нужно подтверждение',bg:C.accent, fg:'#FFFFFF' }, attention: { label:'Внимание', bg:C.warn, fg:'#FFFFFF' }, error: { label:'Ошибка', bg:'#B23A3A', fg:'#FFFFFF' }, waiting: { label:'Ожидает ответа', bg:'rgba(19,17,14,0.10)', fg:C.inkMute }, }; const s = map[kind] || map.done; return ( {s.label} ); } // Portal logo mark — abstract: nested squares (offset), grass status dot. Less "microwave", more "doorway". function PortalLogoMark({ size=28, fg, accent, inverse=false }) { const C = window.DT.color; const stroke = inverse ? C.cream : (fg || C.ink); const dotFg = accent || C.grass; return ( {/* outer frame */} {/* inner offset square — like a doorway/inset, not a window with shelf */} {/* status dot — top-right corner of outer frame */} ); } Object.assign(window, { Icon, Btn, Eyebrow, Reveal, StatusPill, PortalLogoMark });