/* chrome.jsx — Sidebar, XP widget, Streak, Stats, Topbar, Filters, Toasts. Exported to window. */ function XPWidget({ xp, justLeveled }) { const { Ic, Store } = window; const info = Store.levelInfo(xp); return (
{info.level}
Nível {info.level} Dev {info.level < 3 ? "Aprendiz" : info.level < 6 ? "Pleno" : info.level < 10 ? "Sênior" : "Lenda"}
{info.into}/{info.need} XP
); } function StreakPill({ streak }) { return (
🔥
{streak} {streak === 1 ? "dia" : "dias"} sequência
); } const NAV = [ { id: "tarefas", label: "Tarefas", icon: "Tasks" }, ]; function Sidebar({ game, justLeveled, user, onOpenSettings, onLogout, canAdmin, onOpenAdmin, canApprove, pendingCount, onOpenApprovals }) { const { Ic } = window; const [active, setActive] = React.useState("tarefas"); const [menu, setMenu] = React.useState(false); const ref = React.useRef(null); React.useEffect(() => { const h = (e) => { if (ref.current && !ref.current.contains(e.target)) setMenu(false); }; document.addEventListener("mousedown", h); return () => document.removeEventListener("mousedown", h); }, []); const initials = (user.name || "U").trim().split(/\s+/).map(w => w[0]).slice(0, 2).join("").toUpperCase(); return ( ); } function Topbar({ query, setQuery, onNew, muted, toggleMute }) { const { Ic } = window; return (

Minhas Tarefas

setQuery(e.target.value)} aria-label="Buscar tarefa" /> {query && }
); } function StatBar({ game, totalTasks }) { const { Ic, Store } = window; const rate = totalTasks ? Math.round((game.totalDone / (totalTasks + game.totalDone)) * 100) : 0; const stats = [ { ico: "Check", c: "var(--c-melhoria)", bg: "var(--c-melhoria-bg)", num: game.todayCount, lbl: "concluídas hoje" }, { ico: "Calendar", c: "var(--accent)", bg: "rgba(var(--accent-rgb),0.14)", num: game.weekCount, lbl: "essa semana" }, { ico: "Target", c: "var(--gold)", bg: "rgba(245,185,66,0.14)", num: rate + "%", lbl: "taxa de conclusão" }, { ico: "Trophy", c: "var(--c-feature)", bg: "var(--c-feature-bg)", num: game.totalDone, lbl: "total concluídas" }, ]; return (
{stats.map((s, i) => { const I = Ic[s.ico]; return (
{s.num}
{s.lbl}
); })}
); } function Filters({ catFilter, setCatFilter, prioFilter, setPrioFilter }) { const { Store } = window; const cats = Object.entries(Store.CATEGORIES); const prios = Object.entries(Store.PRIORITIES); const toggle = (val, cur, set) => set(cur === val ? null : val); const any = catFilter || prioFilter; return (
{cats.map(([k, m]) => ( ))} {prios.map(([k, m]) => ( ))} {any && }
); } function ToastHost({ toasts }) { return (
{toasts.map(t => (
{t.e} {t.t}
))}
); } /* MobileHero — logo grande de marca no topo do conteúdo (só no celular). Fica dentro da .main (rola com a página); o CSS a esconde no desktop. */ function MobileHero() { return (
Mil Grau RP
MIL GRAU RP
TAREFAS
); } /* MobileChrome — barra superior, FAB e barra inferior do celular. Renderizada sempre; o CSS a esconde no desktop (≥821px). */ function MobileChrome({ game, justLeveled, user, muted, toggleMute, onNew, onOpenSettings, onLogout, canAdmin, onOpenAdmin, canApprove, pendingCount, onOpenApprovals }) { const { Ic, FX } = window; const [drawer, setDrawer] = React.useState(false); const [sheet, setSheet] = React.useState(null); // "nivel" | "sequencia" | null const initials = (user.name || "U").trim().split(/\s+/).map(w => w[0]).slice(0, 2).join("").toUpperCase(); return ( <>
{drawer && (
setDrawer(false)}>
)} {sheet && (
setSheet(null)}>
e.stopPropagation()}>
{sheet === "nivel" && (<>

Seu nível

Conclua tarefas para ganhar XP e subir de nível.

)} {sheet === "sequencia" && (<>

Sua sequência

Volte todos os dias e conclua tarefas para manter sua ofensiva acesa.

)}
)} ); } Object.assign(window, { Sidebar, Topbar, StatBar, Filters, ToastHost, XPWidget, StreakPill, MobileChrome, MobileHero });