// ui.jsx — shared atoms: Logo, Avatar, Stars, Chip, primary button etc. const COLORS = { bg: '#0B0B0B', bg2: '#141414', card: '#1A1A1A', card2: '#222222', border: 'rgba(212,175,55,0.14)', borderSoft: 'rgba(255,255,255,0.06)', text: '#FFFFFF', text2: 'rgba(255,255,255,0.65)', text3: 'rgba(255,255,255,0.4)', gold: '#D4AF37', goldDark: '#B6932B', goldSoft: 'rgba(212,175,55,0.14)', green: '#34D399', red: '#F87171', }; // Logo: T inside shield, gold gradient function TrustaLogo({ size = 64, mark = true }) { const id = React.useId(); return ( {/* shield outline */} {/* T mark */} {mark && ( {/* serif feet */} )} ); } function Wordmark({ size = 28, color = '#D4AF37', tracking = 0.32 }) { return ( TRUSTA ); } function Avatar({ src, size = 40, ring = false, verified = false }) { return (
{verified && (
)}
); } function Stars({ value = 5, size = 12, count = true }) { return (
{[1, 2, 3, 4, 5].map(i => ( ))}
); } function GoldButton({ children, onClick, disabled, full = true, style = {} }) { return ( ); } function GhostButton({ children, onClick, full = true, style = {} }) { return ( ); } // Bottom tab bar (5 tabs, center is FAB-style "+") function TabBar({ active, onChange, t }) { // Badge unread sur l'onglet Alerts const [unread, setUnread] = React.useState(() => (window.TrustaNotifStore && window.TrustaNotifStore.getUnread()) || 0 ); React.useEffect(() => { if (!window.TrustaNotifStore) return; setUnread(window.TrustaNotifStore.getUnread()); return window.TrustaNotifStore.subscribe(setUnread); }, []); const Icon = ({ name, fill }) => { const c = fill; switch (name) { case 'home': return ; case 'chat': return ; case 'alert': return ; case 'profile': return ; } }; const tabs = [ { id: 'home', label: t('nav_home') }, { id: 'chat', label: t('nav_chat') }, { id: 'post', label: '' }, // FAB { id: 'alert', label: t('nav_alerts') }, { id: 'profile', label: t('nav_profile') }, ]; return (
{tabs.map(tab => { if (tab.id === 'post') { return ( ); } const isActive = active === tab.id; const c = isActive ? COLORS.gold : COLORS.text3; const showBadge = tab.id === 'alert' && unread > 0; return ( ); })}
); } // Top header (custom, replaces IOSNavBar) function Header({ left, right, title, sub, dark = true, onBack, big = false }) { return (
{onBack ? ( ) : left}
{sub &&
{sub}
}
{title}
{right}
); } // === HeartButton — favoris (cœur, état synchronisé via TrustaFavStore) === function HeartButton({ kind, id, size = 22, style = {}, onChange }) { const numId = Number(id || 0); const [fav, setFav] = React.useState(() => !!(window.TrustaFavStore && window.TrustaFavStore.isFav(kind, numId)) ); const [busy, setBusy] = React.useState(false); React.useEffect(() => { if (!window.TrustaFavStore) return; const update = () => setFav(window.TrustaFavStore.isFav(kind, numId)); update(); return window.TrustaFavStore.subscribe(update); }, [kind, numId]); const handleClick = async (e) => { if (e) { e.stopPropagation(); e.preventDefault(); } if (busy || !numId || !window.TrustaFavStore) return; setBusy(true); try { const newVal = await window.TrustaFavStore.toggle(kind, numId); if (onChange) onChange(newVal); } catch (err) { console.error('toggle fav failed', err); } finally { setBusy(false); } }; const fillColor = fav ? COLORS.gold : 'transparent'; const strokeColor = fav ? COLORS.gold : 'rgba(255,255,255,0.85)'; return ( ); } window.HeartButton = HeartButton; window.COLORS = COLORS; window.TrustaLogo = TrustaLogo; window.Wordmark = Wordmark; window.Avatar = Avatar; window.Stars = Stars; window.GoldButton = GoldButton; window.GhostButton = GhostButton; window.TabBar = TabBar; window.Header = Header;