/* global React */ // ============================================================ // Shared components — icons, badges, meters, chips, shell // ============================================================ const { useState, useEffect, useMemo, useRef, createContext, useContext } = React; // ============== ICONS — original, neutral, geometric ============== const Icon = { // app mark (faceted gem — original, not SE assets) Mark: () => ( ), // nav Dashboard: () => , Collections: () => , Relic: () => , Static: () => , FC: () => , Settings: () => , // utility Search: () => , Refresh: () => , Check: () => , X: () => , Plus: () => , ChevR: () => , ChevL: () => , ChevD: () => , ChevUD: () => , More: () => , Copy: () => , Edit: () => , Discord: () => , Sun: () => , Moon: () => , External: () => , Sidebar: () => , Warning: () => , Info: () => , Lock: () => , Link: () => , Bot: () => , Loot: () => , Clock: () => , Filter: () => , Spinner: () => , }; // ============== role / job helpers ============== const ROLES = { PLD: { role: 'tank', glyph: 'P' }, WAR: { role: 'tank', glyph: 'W' }, DRK: { role: 'tank', glyph: 'D' }, GNB: { role: 'tank', glyph: 'G' }, WHM: { role: 'heal', glyph: 'W' }, SCH: { role: 'heal', glyph: 'S' }, AST: { role: 'heal', glyph: 'A' }, SGE: { role: 'heal', glyph: 'S' }, MNK: { role: 'dps', glyph: 'M' }, DRG: { role: 'dps', glyph: 'D' }, NIN: { role: 'dps', glyph: 'N' }, SAM: { role: 'dps', glyph: 'S' }, RPR: { role: 'dps', glyph: 'R' }, VPR: { role: 'dps', glyph: 'V' }, BRD: { role: 'dps', glyph: 'B' }, MCH: { role: 'dps', glyph: 'M' }, DNC: { role: 'dps', glyph: 'D' }, BLM: { role: 'dps', glyph: 'B' }, SMN: { role: 'dps', glyph: 'S' }, RDM: { role: 'dps', glyph: 'R' }, PCT: { role: 'dps', glyph: 'P' }, }; function roleOf(job) { return ROLES[job]?.role || 'dps'; } function glyphOf(job) { return ROLES[job]?.glyph || job[0]; } function RoleChip({ job }) { const r = roleOf(job); return ( {glyphOf(job)} {job} ); } function JobChip({ job, lvl, cap }) { const r = roleOf(job); return ( {glyphOf(job)} {job} {lvl} ); } // ============== Origin badge ============== function Origin({ kind, label }) { const labels = { auto: 'auto', manual: 'manual', diffed: 'diffed' }; return ( {label || labels[kind]} ); } // ============== Sync chip ============== function SyncChip({ state = 'ok', label }) { const labels = { ok: label || 'Synced 2h ago', syncing: 'Syncing…', failed: 'Sync failed', }; return ( ); } // ============== Progress meter ============== function Meter({ value, total, label, size = 'md', tone, showPct = true, suffix }) { const pct = total ? Math.round((value / total) * 100) : value; // tone scaling: red -> amber -> green let color = 'var(--primary)'; if (tone === 'status') { if (pct < 35) color = 'var(--danger)'; else if (pct < 75) color = 'var(--warning)'; else color = 'var(--success)'; } else if (tone) { color = `var(--${tone})`; } return (
{sub}
} {action}