// SONARA — Manager Nav (sidebar + topbar + bottom nav) // Persona: Andrea Conti / @andreaconti — Milano, manager indipendente // Roster: 5 artisti (indie, alt-pop, cantautorato, trap) const MIcons = window.SonaraIcons; function Sidebar({ active = "home" }) { const marketplace = { key: "esplora", label: "Esplora talenti", icon: , href: "Esplora.html", sub: "Artisti, producer, manager" }; const work = [ { key: "home", label: "Home", icon: , href: "Dashboard.html" }, { key: "roster", label: "Roster", icon: , badge: 5, href: "Roster.html" }, { key: "messaggi", label: "Messaggi", icon: , badge: 3, href: "Messaggi.html" }, { key: "preferiti", label: "Preferiti", icon: , href: "Preferiti.html" }, ]; const biz = [ { key: "profilo", label: "Profilo pubblico", icon: , href: "Profilo.html" }, ]; return ( ); } function Topbar({ theme = "dark", onToggleTheme }) { const [notifOpen, setNotifOpen] = React.useState(false); const notifRef = React.useRef(null); React.useEffect(() => { const onDown = (e) => { if (notifOpen && notifRef.current && !notifRef.current.contains(e.target)) setNotifOpen(false); }; document.addEventListener("mousedown", onDown); return () => document.removeEventListener("mousedown", onDown); }, [notifOpen]); const SunIcon = ({ size = 16 }) => ( ); const MoonIcon = ({ size = 16 }) => ( ); return (
⌘ K
Talenti 12 nuovi Feed 3
{notifOpen && setNotifOpen(false)}/>}
); } function Greet({ name = "Andrea", sub = "Hai 2 nuove offerte sui tuoi artisti, 1 invito al roster accettato e 3 messaggi non letti.", }) { return (

Bentornato, {name} 👋

{sub}
); } function BottomNav({ active = "home" }) { const items = [ { key: "home", label: "Home", icon: , href: "Dashboard.html" }, { key: "esplora", label: "Esplora", icon: , href: "Esplora.html", primary: true }, { key: "roster", label: "Roster", icon: , badge: 5, href: "Roster.html" }, { key: "chat", label: "Chat", icon: , badge: 3, href: "Messaggi.html" }, { key: "profilo", label: "Profilo", icon: , href: "Profilo.html" }, ]; return ( ); } /* ─────────────────────────────────────────────────── */ /* Notifications panel (manager-specific) */ /* ─────────────────────────────────────────────────── */ const MGR_NOTIFICATIONS = [ { id: "mn1", unread: true, time: "12m fa", title: "Invito al roster accettato", body: "@martinarey ha accettato il tuo invito. Ora fa parte ufficialmente del roster.", href: "Roster.html", icon: "users", accent: "success", }, { id: "mn2", unread: true, time: "47m fa", title: "Offerta su @lucabianchi", body: "Studio Riva ha mandato un'offerta da €420 sulla richiesta Mix EP \"Restami\".", href: "Roster.html", icon: "target", accent: "violet", }, { id: "mn3", unread: true, time: "2h fa", title: "Nuovo messaggio da @giuliawave", body: "\"Ciao Andrea, ti scrivo perché ho visto il tuo profilo e sono interessata…\"", href: "Messaggi.html", icon: "connect", accent: "violet", }, { id: "mn4", unread: false, time: "Ieri", title: "@martinarey ha pubblicato una richiesta", body: "Cerca producer R&B/soul a Bologna. Budget €300-500.", href: "Roster.html", icon: "target", accent: "neutral", }, { id: "mn5", unread: false, time: "Ieri", title: "Invito al roster scaduto", body: "@kayalow non ha risposto entro 30 giorni. L'invito è stato auto-decline.", href: "Roster.html", icon: "clock", accent: "warning", }, { id: "mn6", unread: false, time: "12 mag", title: "@lucabianchi ha completato un progetto", body: "Mix \"Senza Te\" approvato. 5★ rilasciate a Marco Vitale.", href: "Roster.html", icon: "audioFile", accent: "success", }, { id: "mn7", unread: false, time: "10 mag", title: "Artista suggerito per te", body: "@simonecaruso (alt-pop · Torino) corrisponde al 92% ai tuoi generi gestiti.", href: "Esplora.html", icon: "user", accent: "violet", }, ]; function ManagerNotificationsPanel({ onClose }) { const [filter, setFilter] = React.useState("all"); const unreadCount = MGR_NOTIFICATIONS.filter(n => n.unread).length; const items = filter === "unread" ? MGR_NOTIFICATIONS.filter(n => n.unread) : MGR_NOTIFICATIONS; return (
Notifiche {unreadCount > 0 && {unreadCount} nuove}
{items.map(n => { const Ic = MIcons[n.icon] || MIcons.bell; return (
{n.title} {n.time}
{n.body}
{n.unread && }
); })} {items.length === 0 && (
Nessuna notifica non letta
Sei in pari 🎉
)}
); } Object.assign(window, { Sidebar, Topbar, Greet, BottomNav, ManagerNotificationsPanel });