@the-portland-company/shell 0.19.0 → 0.19.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app-chrome.cjs +3 -1
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +8 -2
- package/dist/app-chrome.d.ts +8 -2
- package/dist/app-chrome.js +3 -1
- package/dist/app-chrome.js.map +1 -1
- package/package.json +1 -1
package/dist/app-chrome.cjs
CHANGED
|
@@ -822,10 +822,11 @@ function AppDevNotes({
|
|
|
822
822
|
function PolitogyAppChrome({
|
|
823
823
|
storagePrefix,
|
|
824
824
|
proxyBasePath = "/api/chrome",
|
|
825
|
+
fetchJson: fetchJsonOverride,
|
|
825
826
|
identity,
|
|
826
827
|
children
|
|
827
828
|
}) {
|
|
828
|
-
const
|
|
829
|
+
const proxyFetchJson = react.useMemo(
|
|
829
830
|
() => async (path, init) => {
|
|
830
831
|
const res = await fetch(`${proxyBasePath}/${path}`, {
|
|
831
832
|
method: init?.method ?? "GET",
|
|
@@ -839,6 +840,7 @@ function PolitogyAppChrome({
|
|
|
839
840
|
},
|
|
840
841
|
[proxyBasePath]
|
|
841
842
|
);
|
|
843
|
+
const fetchJson = fetchJsonOverride ?? proxyFetchJson;
|
|
842
844
|
return /* @__PURE__ */ jsxRuntime.jsx(NavChromeProvider, { fetchJson, children: /* @__PURE__ */ jsxRuntime.jsx(ChromeStateProvider, { children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
843
845
|
AppDevNotes,
|
|
844
846
|
{
|
package/dist/app-chrome.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/topbarIconSlot.ts","../src/lib/brandGlyphs.tsx","../src/theme-preference.ts","../src/native/chromeActions.tsx","../src/app-chrome/index.tsx"],"names":["useState","useEffect","FiBatteryCharging","FiBattery","FiZap","FiGrid","FiBell","FiAlertTriangle","FiAlertCircle","FiLifeBuoy","FiHelpCircle","FiMoon","FiSun","FiInfo","FiMail","FiMessageSquare","FiSettings","FiUser","jsxs","jsx","createContext","useContext","useRef","useCallback","Fragment","createPortal","useMemo","createDevNotesClient","DevNotesProvider","DevNotesMenu"],"mappings":"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","file":"app-chrome.cjs","sourcesContent":["import { useEffect, useState } from 'react'\n\n/**\n * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar\n * icons). Each slot's GLYPH is unique and comes from the Brand API\n * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars\n * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,\n * hover, selected — is universal across all six slots.\n */\nexport type TopBarIconSlot =\n | 'comms-fuel'\n | 'apps'\n | 'notifications'\n | 'alerts'\n | 'support'\n | 'dark-mode'\n\n/**\n * Reads the glyph NAME for a slot from its `--topbar-icon-<slot>` CSS var.\n *\n * Runs in an effect because the Brand stylesheet is appended to <head> at\n * runtime (Global Rules forbids baking it into the build), so the var is not\n * resolvable during SSR or the first synchronous render. The MutationObserver\n * re-reads once the stylesheet lands so the glyph upgrades from the caller's\n * fallback without a reload.\n *\n * Returns null when the slot has no Brand glyph — callers render their own\n * fallback icon in that case.\n */\nexport function useTopBarIconSlotGlyph(slot: TopBarIconSlot): string | null {\n const [name, setName] = useState<string | null>(null)\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n const read = () => {\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(`--topbar-icon-${slot}`)\n .trim()\n // Brand may emit the name quoted (e.g. \"bell\"); strip the quotes.\n .replace(/^['\"]|['\"]$/g, '')\n setName(raw.length > 0 ? raw : null)\n }\n\n read()\n\n const observer = new MutationObserver(read)\n observer.observe(document.head, { childList: true, subtree: true })\n return () => observer.disconnect()\n }, [slot])\n\n return name\n}\n\n/** Path to a brand-icon SVG in the consuming app's public dir. */\nexport function brandIconSrc(name: string, basePath = '/brand/icons/') {\n return `${basePath}${name}.svg`\n}\n","import type { ComponentType } from 'react'\nimport {\n FiAlertCircle,\n FiBattery,\n FiBatteryCharging,\n FiAlertTriangle,\n FiBell,\n FiGrid,\n FiHelpCircle,\n FiInfo,\n FiLifeBuoy,\n FiMail,\n FiMessageSquare,\n FiMoon,\n FiSettings,\n FiSun,\n FiUser,\n FiZap,\n} from 'react-icons/fi'\n\nexport type GlyphComponent = ComponentType<{ size?: number | string; className?: string }>\n\n/**\n * Brand-glyph registry: maps the icon NAME the Brand API emits (e.g.\n * `--topbar-icon-comms-fuel: bolt`) to a component.\n *\n * These names are Feather/Lucide icon names, NOT asset filenames — there is no\n * `/brand/icons/<name>.svg` for them in any app, and treating them as URLs\n * renders a broken image. Resolving them against the icon library the shell\n * already depends on keeps every app consistent with zero vendored assets.\n *\n * Aliases are included where Brand and Feather disagree on a name (`bolt` vs\n * `zap`, `life-buoy` vs `life-ring`).\n */\nconst GLYPHS: Record<string, GlyphComponent> = {\n // Communications Fuel reads as a LEVEL, so its glyph is a battery. `bolt`/\n // `zap` stay mapped for older Brand values.\n 'battery-charging': FiBatteryCharging,\n battery: FiBattery,\n fuel: FiBatteryCharging,\n bolt: FiZap,\n zap: FiZap,\n grid: FiGrid,\n apps: FiGrid,\n bell: FiBell,\n notification: FiBell,\n 'alert-triangle': FiAlertTriangle,\n alert: FiAlertTriangle,\n 'alert-circle': FiAlertCircle,\n 'life-buoy': FiLifeBuoy,\n 'life-ring': FiLifeBuoy,\n support: FiLifeBuoy,\n 'help-circle': FiHelpCircle,\n moon: FiMoon,\n sun: FiSun,\n info: FiInfo,\n mail: FiMail,\n 'message-square': FiMessageSquare,\n settings: FiSettings,\n user: FiUser,\n}\n\n/**\n * Resolve a Brand glyph name to a component. Returns null for an unknown name\n * so the caller renders its own fallback — an unrecognized token must never\n * produce a broken or empty icon.\n */\nexport function resolveBrandGlyph(name: string | null | undefined): GlyphComponent | null {\n if (!name) return null\n return GLYPHS[name.trim().toLowerCase()] ?? null\n}\n\n/** Names the registry knows — exported for tests and tooling. */\nexport const KNOWN_BRAND_GLYPHS = Object.keys(GLYPHS)\n","// Universal theme preference — the ONE cross-app contract.\n//\n// One theme choice (Light / Dark / System) follows the authenticated user\n// across every Politogy app + subdomain. Three layers cooperate:\n// 1. VRM Core `profiles.theme_preference` — source of truth, persisted via\n// the chrome API (`PATCH me/preferences { themePreference }`) and read\n// back from `GET me` (`themePreference`).\n// 2. `.politogyvrm.com` cookie `politogy_theme` — zero-flash pre-paint\n// vehicle that crosses subdomains (auth session cookies are host-only).\n// 3. localStorage `politogy_theme` — offline fallback store.\n//\n// Ported verbatim from contacts/apps/web/src/lib/theme.ts (the origin of the\n// contract) so every app runs the identical behavior from npm. This module is\n// server-safe (no 'use client'): layouts import THEME_PREPAINT_SCRIPT for the\n// pre-paint inline script. The client-side hook lives in ./native\n// (useThemePreference).\n\nexport type ThemePreference = 'light' | 'dark' | 'system'\n\n// Single converged key for BOTH the localStorage store and the\n// cross-subdomain cookie, so a choice in one app is the same key in the next.\nexport const THEME_STORAGE_KEY = 'politogy_theme'\nexport const THEME_COOKIE = 'politogy_theme'\n\nconst VALID: readonly ThemePreference[] = ['light', 'dark', 'system']\n\nexport function isThemePreference(v: unknown): v is ThemePreference {\n return typeof v === 'string' && (VALID as readonly string[]).includes(v)\n}\n\n/** Read the shared cookie (browser only; null on the server or when unset). */\nexport function readThemeCookie(): ThemePreference | null {\n if (typeof document === 'undefined') return null\n try {\n const m = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${THEME_COOKIE}=([^;]+)`),\n )\n const v = m ? decodeURIComponent(m[1]) : null\n return isThemePreference(v) ? v : null\n } catch {\n return null\n }\n}\n\n// Set the cross-subdomain cookie. On a *.politogyvrm.com host we scope it to\n// the parent domain so every app subdomain reads it; on any other host\n// (localhost, *.pages.dev preview) we fall back to a host-only cookie so\n// local/preview theming still works without a mismatched Domain attribute\n// (which browsers silently drop). 1-year, SameSite=Lax, Secure on https.\nexport function writeThemeCookie(pref: ThemePreference): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') return\n const host = window.location.hostname\n const onParentDomain = /(^|\\.)politogyvrm\\.com$/i.test(host)\n const domainAttr = onParentDomain ? '; Domain=.politogyvrm.com' : ''\n const secure = window.location.protocol === 'https:' ? '; Secure' : ''\n document.cookie = `${THEME_COOKIE}=${encodeURIComponent(\n pref,\n )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`\n}\n\n/** Resolve a preference to the concrete light/dark it renders as right now. */\nexport function resolveTheme(pref: ThemePreference): 'light' | 'dark' {\n if (pref === 'system') {\n try {\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light'\n } catch {\n return 'light'\n }\n }\n return pref\n}\n\n/** Apply a preference to the document (`.dark` class + color-scheme). */\nexport function applyThemePreference(pref: ThemePreference): void {\n if (typeof document === 'undefined') return\n const resolved = resolveTheme(pref)\n const d = document.documentElement\n d.classList.toggle('dark', resolved === 'dark')\n try {\n d.style.colorScheme = resolved\n } catch {\n /* non-fatal */\n }\n}\n\n// Inline pre-paint script — render it in <head> (or as the first child of\n// <body>) so the theme applies before first paint. Resolves the preference\n// from cookie → localStorage → OS, applies the `.dark` class + `color-scheme`,\n// and seeds localStorage from the cookie so the app hydrates to the synced\n// value (the cross-subdomain flash fix). Self-contained, dependency-free, and\n// wrapped so any failure is silent (never blocks paint).\nexport const THEME_PREPAINT_SCRIPT = `(function(){try{\nvar KEY=${JSON.stringify(THEME_STORAGE_KEY)};\nvar VALID=[\"light\",\"dark\",\"system\"];\nfunction fromCookie(){try{var m=document.cookie.match(/(?:^|;\\\\s*)${THEME_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}\nvar cookie=fromCookie();\nvar ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}\nvar pref=cookie||ls||\"system\";\nif(VALID.indexOf(pref)===-1)pref=\"system\";\nif(cookie&&cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}\nvar resolved=pref;\nif(pref===\"system\"){try{resolved=window.matchMedia(\"(prefers-color-scheme: dark)\").matches?\"dark\":\"light\";}catch(e){resolved=\"light\";}}\nvar d=document.documentElement;\nif(resolved===\"dark\"){d.classList.add(\"dark\");}else{d.classList.remove(\"dark\");}\ntry{d.style.colorScheme=resolved;}catch(e){}\n}catch(e){}})();`\n","// ---------------------------------------------------------------------------\n// Native chrome actions — Tailwind-only top-bar widgets (Fuel, Notifications,\n// Support, Navigation-display) backed by the shared chrome API\n// (politogy-contacts-api on Railway). Zero Chakra, zero router, zero fetch\n// opinion: the consuming app injects ONE fetcher via <NavChromeProvider> —\n// typically a same-origin proxy route that attaches its own session's Bearer\n// token server-side — and every widget in every app runs this exact code.\n//\n// Data endpoints (paths are relative; the app's fetcher owns the base URL):\n// GET communications/fuel-status (header x-contacts-org: <core org id>)\n// GET notifications (header x-contacts-org: <core org id>)\n// GET orgs\n// POST support { message }\n//\n// Loading states follow Global-Rules \"Loading & Async States\": the chrome\n// (button, popover frame, labels) always renders; only the VALUE area shows a\n// skeleton shimmer — never a spinner, never a blank panel.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { useTopBarIconSlotGlyph, type TopBarIconSlot } from '../lib/topbarIconSlot'\nimport { resolveBrandGlyph } from '../lib/brandGlyphs'\nimport {\n applyThemePreference,\n isThemePreference,\n readThemeCookie,\n writeThemeCookie,\n THEME_STORAGE_KEY,\n type ThemePreference as SharedThemePreference,\n} from '../theme-preference'\n\ntype NavIconLike = ComponentType<{ size?: number; className?: string }>\n\n// ---------------------------------------------------------------------------\n// Shared 32×32 circular top-bar button chrome — the ONE definition of the\n// top-bar trigger (Global Rules: no slot hand-rolls its own trigger/badge).\n// NavTopBar's structured actionsList buttons use this same builder.\n// ---------------------------------------------------------------------------\n\nexport function topBarIconButtonClass(tone: 'default' | 'warning' | 'danger' = 'default'): string {\n const toneClass =\n tone === 'danger' || tone === 'warning'\n ? 'text-[color:var(--color-race-red)] hover:text-[color:var(--color-race-red)]'\n : 'text-[color:var(--topbar-icon-color,var(--muted))] hover:text-[color:var(--topbar-icon-hover-color,var(--foreground))] hover:bg-[color:var(--topbar-icon-hover-bg,transparent)]'\n return [\n // `group/tbtip` powers the shared <TopBarTooltip> rendered inside the trigger.\n 'group/tbtip relative flex items-center justify-center rounded-full border border-[color:var(--line)] transition',\n 'h-[var(--topbar-icon-button-size,32px)] w-[var(--topbar-icon-button-size,32px)]',\n toneClass,\n ].join(' ')\n}\n\n/** The shared count badge — one definition, used by every slot. */\nexport function TopBarCountBadge({ count }: { count: number }) {\n if (!(count > 0)) return null\n return (\n <span className=\"absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-[color:var(--color-race-red)] px-1 text-[10px] text-white\">\n {count > 99 ? '99+' : count}\n </span>\n )\n}\n\n/**\n * The shared hover tooltip every top-bar control renders BELOW itself: an\n * up-pointing arrow at the icon, a bold title line and a muted description.\n * Pure CSS (group-hover) so it works on <a>, <button> and <summary> triggers.\n * The trigger must carry `group/tbtip relative` (topBarIconButtonClass does).\n */\nexport function TopBarTooltip({\n title,\n description,\n}: {\n title: string\n description?: ReactNode\n}) {\n return (\n <span\n role=\"tooltip\"\n className=\"pointer-events-none absolute left-1/2 top-full z-50 mt-2 hidden w-max max-w-56 -translate-x-1/2 flex-col rounded-lg border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-3 py-2 text-left shadow-[var(--shadow-soft)] group-hover/tbtip:flex\"\n >\n {/* Arrow pointing up at the icon */}\n <span\n aria-hidden\n className=\"absolute -top-[5px] left-1/2 h-2.5 w-2.5 -translate-x-1/2 rotate-45 border-l border-t border-[color:var(--line)] bg-[color:var(--panel-elevated)]\"\n />\n <span className=\"text-xs font-semibold text-[color:var(--foreground)]\">{title}</span>\n {description ? (\n <span className=\"mt-0.5 text-[11px] leading-snug text-[color:var(--muted)]\">\n {description}\n </span>\n ) : null}\n </span>\n )\n}\n\n/**\n * The up-pointing arrow every top-bar panel renders, anchored under its\n * trigger icon (panels are right-aligned, so the arrow sits at the trigger's\n * center: 16px in from the panel's right edge). One definition — every menu\n * points at its own icon identically.\n */\nexport function TopBarPanelArrow() {\n return (\n <span\n aria-hidden\n className=\"absolute -top-[5px] right-[11px] h-2.5 w-2.5 rotate-45 border-l border-t border-[color:var(--line)] bg-[color:var(--panel-elevated)]\"\n />\n )\n}\n\n/**\n * Wrapper for third-party top-bar widgets that ship their own launcher button\n * (e.g. DevNotes). Normalizes the trigger to the universal 32px circular slot\n * (chrome.css `.topbar-widget-slot`) and adds the standard tooltip.\n */\nexport function TopBarWidgetSlot({\n title,\n description,\n children,\n}: {\n title: string\n description?: string\n children: ReactNode\n}) {\n return (\n <span className=\"topbar-widget-slot group/tbtip relative inline-flex\">\n {children}\n <TopBarTooltip title={title} description={description} />\n </span>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Theme control — Light / System / Dark, rendered inside the account menu.\n// Controlled: the app owns persistence (profile + cross-subdomain cookie).\n// ---------------------------------------------------------------------------\n\nexport type ThemePreference = SharedThemePreference\n\nconst THEME_OPTIONS: { value: ThemePreference; label: string }[] = [\n { value: 'light', label: 'Light' },\n { value: 'system', label: 'System' },\n { value: 'dark', label: 'Dark' },\n]\n\nexport function NavThemeControl({\n value,\n onChange,\n}: {\n value: ThemePreference\n onChange: (next: ThemePreference) => void\n}) {\n return (\n <div className=\"px-4 py-3\">\n <p className=\"mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Appearance\n </p>\n <div\n role=\"radiogroup\"\n aria-label=\"Appearance\"\n className=\"flex overflow-hidden rounded-full border border-[color:var(--line)]\"\n >\n {THEME_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === opt.value}\n onClick={() => onChange(opt.value)}\n className={[\n 'flex-1 px-3 py-1.5 text-xs font-semibold transition',\n value === opt.value\n ? 'bg-[color:var(--color-race-red)] text-white'\n : 'text-[color:var(--muted)] hover:bg-[color:var(--panel)] hover:text-[color:var(--foreground)]',\n ].join(' ')}\n >\n {opt.label}\n </button>\n ))}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Chrome data context — the injected fetcher.\n// ---------------------------------------------------------------------------\n\nexport type NavChromeFetcher = (\n path: string,\n init?: { method?: string; headers?: Record<string, string>; body?: string },\n) => Promise<unknown>\n\n/** GET me — the authenticated user's chrome identity from the shared API.\n * userName prefers the VRM-core profile full name over token claims. */\nexport type ChromeMe = {\n user: string | null\n userName: string | null\n avatarUrl: string | null\n themePreference: string | null\n account?: string | null\n accountName?: string | null\n role?: string | null\n}\n\ntype NavChromeContextValue = {\n fetchJson: NavChromeFetcher\n me: ChromeMe | null\n meLoaded: boolean\n}\n\nconst NavChromeContext = createContext<NavChromeContextValue | null>(null)\n\nexport function NavChromeProvider({\n fetchJson,\n children,\n}: {\n fetchJson: NavChromeFetcher\n children: ReactNode\n}) {\n // ONE `me` fetch per provider — identity (profile name/avatar) and the\n // theme reconciliation both hang off it.\n const [me, setMe] = useState<ChromeMe | null>(null)\n const [meLoaded, setMeLoaded] = useState(false)\n useEffect(() => {\n let cancelled = false\n fetchJson('me')\n .then((data) => {\n if (!cancelled) setMe(data as ChromeMe)\n })\n .catch(() => {\n /* degraded: session identity stands in */\n })\n .finally(() => {\n if (!cancelled) setMeLoaded(true)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson])\n\n return (\n <NavChromeContext.Provider value={{ fetchJson, me, meLoaded }}>\n {children}\n </NavChromeContext.Provider>\n )\n}\n\n/** The authenticated user's chrome identity (profile name / avatar / theme). */\nexport function useChromeMe(): { me: ChromeMe | null; loaded: boolean } {\n const ctx = useContext(NavChromeContext)\n return { me: ctx?.me ?? null, loaded: ctx?.meLoaded ?? false }\n}\n\nfunction useNavChrome(component: string): NavChromeContextValue {\n const ctx = useContext(NavChromeContext)\n if (!ctx) {\n throw new Error(\n `${component} must be rendered inside <NavChromeProvider> (inject the chrome API fetcher there).`,\n )\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// Data shapes (mirror of politogy-contacts-api responses).\n// ---------------------------------------------------------------------------\n\nexport type FuelChannelStatus = {\n remainingUnits: number\n rawBalanceUnits: number\n usedUnits: number\n lowFuel: boolean\n lowFuelThreshold: number\n}\n\nexport type CommunicationsFuelStatus = {\n organizationId: string\n signal: FuelChannelStatus\n broadcast: FuelChannelStatus\n combinedAvailableCredits: number\n}\n\nexport type ChromeNotificationAlert = {\n id: string\n title: string\n description: string\n href: string | null\n kind: string\n}\n\nexport type ChromeNotificationReply = {\n id: string\n contactId: string | null\n name: string\n preview: string\n}\n\nexport type ChromeNotificationsPayload = {\n organizationId: string\n alerts: ChromeNotificationAlert[]\n replies: ChromeNotificationReply[]\n}\n\nexport type ChromeOrgSummary = {\n id: string\n name: string | null\n logoUrl: string | null\n brandColor: string | null\n role: string | null\n /** Un-mapped VRM-core membership role (e.g. \"super_admin\"). */\n rawRole?: string | null\n}\n\n/**\n * Fetch the signed-in user's VRM-core organizations through the injected\n * fetcher. Exposed as a hook so the org switcher in the sidebar and the\n * org-scoped widgets share one request.\n */\nexport function useChromeOrgs(): {\n orgs: ChromeOrgSummary[] | null\n loading: boolean\n error: boolean\n} {\n const { fetchJson } = useNavChrome('useChromeOrgs')\n const [orgs, setOrgs] = useState<ChromeOrgSummary[] | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(false)\n fetchJson('orgs')\n .then((data) => {\n if (cancelled) return\n const list = (data as { orgs?: ChromeOrgSummary[] })?.orgs ?? []\n setOrgs(list)\n })\n .catch(() => {\n if (!cancelled) setError(true)\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson])\n\n return { orgs, loading, error }\n}\n\n// ---------------------------------------------------------------------------\n// Internal building blocks.\n// ---------------------------------------------------------------------------\n\n/** Value-area skeleton shimmer (chrome/labels stay static per Global Rules). */\nfunction ValueSkeleton({ className }: { className?: string }) {\n return (\n <span\n aria-hidden\n className={[\n 'inline-block animate-pulse rounded bg-[color:var(--panel-elevated)]',\n className ?? 'h-4 w-16',\n ].join(' ')}\n />\n )\n}\n\n/** Slot-driven glyph: Brand-token name when resolvable, fallback otherwise. */\nfunction SlotGlyph({\n slot,\n fallback: Fallback,\n size = 20,\n}: {\n slot?: TopBarIconSlot\n fallback: NavIconLike\n size?: number\n}) {\n const glyphName = useTopBarIconSlotGlyph(slot ?? 'apps')\n const BrandGlyph = slot ? resolveBrandGlyph(glyphName) : null\n const Glyph = BrandGlyph ?? Fallback\n return <Glyph size={size} className=\"text-current\" />\n}\n\n/**\n * A top-bar popover: the shared circular trigger + a right-aligned panel.\n * Closes on outside click / Escape. Purely presentational.\n */\nfunction TopBarPopover({\n label,\n description,\n slot,\n fallbackIcon,\n badge,\n tone,\n onOpen,\n children,\n panelClassName,\n}: {\n label: string\n description?: string\n slot?: TopBarIconSlot\n fallbackIcon: NavIconLike\n badge?: number\n tone?: 'default' | 'warning' | 'danger'\n onOpen?: () => void\n children: ReactNode\n panelClassName?: string\n}) {\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDocClick = (e: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(e.target as Node)) setOpen(false)\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false)\n }\n document.addEventListener('mousedown', onDocClick)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onDocClick)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n return (\n <div ref={rootRef} className=\"relative\">\n <button\n type=\"button\"\n aria-label={label}\n aria-expanded={open}\n className={topBarIconButtonClass(tone)}\n onClick={() => {\n setOpen((v) => {\n const next = !v\n if (next) onOpen?.()\n return next\n })\n }}\n >\n <SlotGlyph slot={slot} fallback={fallbackIcon} />\n {typeof badge === 'number' ? <TopBarCountBadge count={badge} /> : null}\n {!open ? <TopBarTooltip title={label} description={description} /> : null}\n </button>\n {open ? (\n <div\n className={[\n 'absolute right-0 z-40 mt-2 rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] shadow-[var(--shadow-soft)]',\n panelClassName ?? 'w-80',\n ].join(' ')}\n >\n <TopBarPanelArrow />\n <div className=\"overflow-hidden rounded-xl\">{children}</div>\n </div>\n ) : null}\n </div>\n )\n}\n\n// Inline fallback glyphs (Feather-style paths) so the package needs no icon dep.\nfunction BatteryGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <rect x=\"1\" y=\"6\" width=\"18\" height=\"12\" rx=\"2\" ry=\"2\" />\n <line x1=\"23\" y1=\"10\" x2=\"23\" y2=\"14\" />\n <line x1=\"5\" y1=\"10\" x2=\"5\" y2=\"14\" />\n <line x1=\"9\" y1=\"10\" x2=\"9\" y2=\"14\" />\n </svg>\n )\n}\n\nfunction BellGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\" />\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\" />\n </svg>\n )\n}\n\nfunction LifeBuoyGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"9.17\" y2=\"9.17\" />\n <line x1=\"14.83\" y1=\"14.83\" x2=\"19.07\" y2=\"19.07\" />\n <line x1=\"14.83\" y1=\"9.17\" x2=\"19.07\" y2=\"4.93\" />\n <line x1=\"4.93\" y1=\"19.07\" x2=\"9.17\" y2=\"14.83\" />\n </svg>\n )\n}\n\nfunction LayoutGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\" />\n <line x1=\"9\" y1=\"21\" x2=\"9\" y2=\"9\" />\n </svg>\n )\n}\n\n// ---------------------------------------------------------------------------\n// FuelAction — Communications Fuel balance (battery glyph + popover meters).\n// ---------------------------------------------------------------------------\n\nfunction FuelRow({\n label,\n channel,\n loading,\n}: {\n label: string\n channel: FuelChannelStatus | null\n loading: boolean\n}) {\n const remaining = channel?.remainingUnits ?? 0\n const total = channel ? Math.max(channel.rawBalanceUnits, channel.remainingUnits) : 0\n const ratio = total > 0 ? Math.min(100, Math.max(0, (remaining / total) * 100)) : 0\n const low = channel?.lowFuel ?? false\n\n return (\n <div className=\"w-full\">\n <div className=\"mb-1 flex items-center justify-between\">\n <span className=\"text-xs font-semibold text-[color:var(--foreground)]\">{label}</span>\n {loading ? (\n <ValueSkeleton className=\"h-3.5 w-14\" />\n ) : (\n <span\n className={[\n 'text-xs font-semibold tabular-nums',\n low ? 'text-[color:var(--color-race-red)]' : 'text-[color:var(--muted)]',\n ].join(' ')}\n >\n {remaining.toLocaleString()} left\n </span>\n )}\n </div>\n <div className=\"h-1.5 w-full overflow-hidden rounded-full bg-[color:var(--panel)]\">\n {loading ? (\n <div className=\"h-full w-full animate-pulse bg-[color:var(--line)]\" />\n ) : (\n <div\n className={[\n 'h-full rounded-full transition-[width]',\n low ? 'bg-[color:var(--color-race-red)]' : 'bg-[color:var(--color-ok,#00A651)]',\n ].join(' ')}\n style={{ width: `${ratio}%` }}\n />\n )}\n </div>\n </div>\n )\n}\n\nexport function FuelAction({ orgId }: { orgId: string | null }) {\n const { fetchJson } = useNavChrome('FuelAction')\n const [fuel, setFuel] = useState<CommunicationsFuelStatus | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(false)\n setFuel(null)\n fetchJson('communications/fuel-status', {\n headers: orgId ? { 'x-contacts-org': orgId } : undefined,\n })\n .then((data) => {\n if (cancelled) return\n setFuel((data as { fuel?: CommunicationsFuelStatus | null })?.fuel ?? null)\n })\n .catch(() => {\n if (!cancelled) setError(true)\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson, orgId])\n\n const low = !!fuel && (fuel.signal.lowFuel || fuel.broadcast.lowFuel)\n\n return (\n <TopBarPopover\n label=\"Communications Fuel\"\n description=\"Remaining SMS and email sending balance for the active organization.\"\n slot=\"comms-fuel\"\n fallbackIcon={BatteryGlyph}\n tone={low ? 'warning' : 'default'}\n >\n <div className=\"px-4 py-3\">\n <p className=\"mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Communications Fuel\n </p>\n {error || (!loading && !fuel) ? (\n <p className=\"text-sm text-[color:var(--muted)]\">\n Fuel balance is unavailable right now.\n </p>\n ) : (\n <div className=\"flex flex-col gap-3\">\n <FuelRow label=\"SMS Signal\" channel={fuel?.signal ?? null} loading={loading} />\n <FuelRow label=\"Email Broadcast\" channel={fuel?.broadcast ?? null} loading={loading} />\n </div>\n )}\n </div>\n </TopBarPopover>\n )\n}\n\n// ---------------------------------------------------------------------------\n// NotificationsAction — bell + count badge + alerts/replies popover.\n// ---------------------------------------------------------------------------\n\nexport function NotificationsAction({ orgId }: { orgId: string | null }) {\n const { fetchJson } = useNavChrome('NotificationsAction')\n const [payload, setPayload] = useState<ChromeNotificationsPayload | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(false)\n setPayload(null)\n fetchJson('notifications', {\n headers: orgId ? { 'x-contacts-org': orgId } : undefined,\n })\n .then((data) => {\n if (!cancelled) setPayload(data as ChromeNotificationsPayload)\n })\n .catch(() => {\n if (!cancelled) setError(true)\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson, orgId])\n\n const count = (payload?.alerts.length ?? 0) + (payload?.replies.length ?? 0)\n\n return (\n <TopBarPopover\n label=\"Alerts & Notifications\"\n description=\"System alerts and recent activity for the active organization.\"\n slot=\"notifications\"\n fallbackIcon={BellGlyph}\n badge={loading ? 0 : count}\n >\n <div className=\"px-4 py-3\">\n <p className=\"mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Notifications\n </p>\n {loading ? (\n <div className=\"flex flex-col gap-2 py-1\">\n <ValueSkeleton className=\"h-4 w-full\" />\n <ValueSkeleton className=\"h-4 w-3/4\" />\n </div>\n ) : error ? (\n <p className=\"text-sm text-[color:var(--muted)]\">\n Notifications are unavailable right now.\n </p>\n ) : count === 0 ? (\n <p className=\"py-1 text-sm text-[color:var(--muted)]\">You’re all caught up.</p>\n ) : (\n <ul className=\"flex max-h-80 flex-col gap-1 overflow-y-auto\">\n {payload?.alerts.map((a) => (\n <li key={a.id}>\n <a\n href={a.href ?? '#'}\n className=\"block rounded-lg px-2 py-2 hover:bg-[color:var(--panel)]\"\n >\n <p className=\"text-sm font-semibold text-[color:var(--foreground)]\">{a.title}</p>\n <p className=\"text-xs text-[color:var(--muted)]\">{a.description}</p>\n </a>\n </li>\n ))}\n {payload?.replies.map((r) => (\n <li key={r.id} className=\"rounded-lg px-2 py-2 hover:bg-[color:var(--panel)]\">\n <p className=\"text-sm font-semibold text-[color:var(--foreground)]\">{r.name}</p>\n <p className=\"truncate text-xs text-[color:var(--muted)]\">{r.preview}</p>\n </li>\n ))}\n </ul>\n )}\n </div>\n </TopBarPopover>\n )\n}\n\n// ---------------------------------------------------------------------------\n// SupportAction — life-buoy trigger + the shared support-request modal\n// (never a mailto:, never an app-local form — Reference/UI-Platform).\n// ---------------------------------------------------------------------------\n\nexport function SupportAction() {\n const { fetchJson } = useNavChrome('SupportAction')\n const [open, setOpen] = useState(false)\n const [message, setMessage] = useState('')\n const [state, setState] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle')\n\n const close = useCallback(() => {\n setOpen(false)\n setState('idle')\n setMessage('')\n }, [])\n\n useEffect(() => {\n if (!open) return\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') close()\n }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [open, close])\n\n const submit = async () => {\n if (!message.trim() || state === 'sending') return\n setState('sending')\n try {\n await fetchJson('support', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ message: message.trim() }),\n })\n setState('sent')\n } catch {\n setState('error')\n }\n }\n\n return (\n <>\n <button\n type=\"button\"\n aria-label=\"Support\"\n className={topBarIconButtonClass()}\n onClick={() => setOpen(true)}\n >\n <SlotGlyph slot=\"support\" fallback={LifeBuoyGlyph} />\n <TopBarTooltip\n title=\"Support\"\n description=\"Send a support request to the Politogy team.\"\n />\n </button>\n {open && typeof document !== 'undefined'\n ? createPortal(\n <div\n // Portaled to <body>: the top bar's backdrop-blur creates a CSS\n // containing block, so a fixed-position descendant would center on\n // the HEADER (rendering off-screen) instead of the viewport.\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Support request\"\n onMouseDown={(e) => {\n if (e.target === e.currentTarget) close()\n }}\n >\n <div className=\"w-full max-w-md rounded-2xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] p-6 shadow-[var(--shadow-soft)]\">\n <h2 className=\"text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]\">\n Contact Support\n </h2>\n {state === 'sent' ? (\n <>\n <p className=\"mt-3 text-sm text-[color:var(--muted)]\">\n Your request was sent. The team will reply by email.\n </p>\n <div className=\"mt-5 flex justify-end\">\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-full bg-[color:var(--color-race-red)] px-4 py-2 text-sm font-semibold text-white hover:opacity-90\"\n >\n Done\n </button>\n </div>\n </>\n ) : (\n <>\n <p className=\"mt-1 text-sm text-[color:var(--muted)]\">\n Describe the problem or question. Your account details ride along\n automatically.\n </p>\n <textarea\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n rows={5}\n placeholder=\"How can we help?\"\n className=\"mt-4 w-full resize-y rounded-lg border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2 text-sm text-[color:var(--foreground)] placeholder:text-[color:var(--muted)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-race-red)]\"\n />\n {state === 'error' ? (\n <p className=\"mt-2 text-sm text-[color:var(--color-race-red)]\">\n Sending failed — try again.\n </p>\n ) : null}\n <div className=\"mt-4 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-full border border-[color:var(--line)] px-4 py-2 text-sm font-semibold text-[color:var(--foreground)] hover:bg-[color:var(--panel)]\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={submit}\n disabled={!message.trim() || state === 'sending'}\n className=\"rounded-full bg-[color:var(--color-race-red)] px-4 py-2 text-sm font-semibold text-white transition hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {state === 'sending' ? 'Sending…' : 'Send request'}\n </button>\n </div>\n </>\n )}\n </div>\n </div>,\n document.body,\n )\n : null}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// NavDisplayAction — the Menu / Tabs / Both navigation-display switcher.\n// Controlled: the app owns persistence (localStorage/profile) and layout\n// consequences (sub-menu visibility, tab strip visibility).\n// ---------------------------------------------------------------------------\n\nexport type NavDisplayMode = 'menu' | 'tabs' | 'both'\n\nconst NAV_DISPLAY_OPTIONS: { value: NavDisplayMode; label: string }[] = [\n { value: 'menu', label: 'Sub Menu' },\n { value: 'tabs', label: 'Tabs Only' },\n { value: 'both', label: 'Both' },\n]\n\nexport function NavDisplayAction({\n value,\n onChange,\n}: {\n value: NavDisplayMode\n onChange: (next: NavDisplayMode) => void\n}) {\n return (\n <TopBarPopover\n label=\"Navigation Display\"\n description=\"Show navigation as a sub-menu, tabs, or both.\"\n fallbackIcon={LayoutGlyph}\n panelClassName=\"w-44\"\n >\n <div className=\"py-1\" role=\"radiogroup\" aria-label=\"Navigation display\">\n {NAV_DISPLAY_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === opt.value}\n onClick={() => onChange(opt.value)}\n className={[\n 'flex w-full items-center justify-between px-4 py-2 text-left text-sm font-medium',\n value === opt.value\n ? 'text-[color:var(--color-race-red)]'\n : 'text-[color:var(--foreground)] hover:bg-[color:var(--panel)]',\n ].join(' ')}\n >\n {opt.label}\n {value === opt.value ? <span aria-hidden>✓</span> : null}\n </button>\n ))}\n </div>\n </TopBarPopover>\n )\n}\n\n// ---------------------------------------------------------------------------\n// useThemePreference — the cross-app theme state machine (Task: theme derived\n// from the Auth system, live across tabs and apps).\n//\n// boot : cookie → localStorage → \"system\" (the pre-paint script already\n// painted this), then ONCE per session reconcile against the\n// profile value from `GET me` (authoritative) when a fetcher is\n// available.\n// change : apply + localStorage + cross-subdomain cookie + best-effort\n// `PATCH me/preferences { themePreference }`.\n// sync : same-app tabs via the `storage` event; other-app tabs re-read the\n// shared cookie on focus/visibility; `system` follows live OS\n// changes via matchMedia.\n// ---------------------------------------------------------------------------\n\nexport function useThemePreference(): {\n value: ThemePreference\n setValue: (next: ThemePreference) => void\n} {\n const ctx = useContext(NavChromeContext)\n const fetchJson = ctx?.fetchJson ?? null\n const [value, setValueState] = useState<ThemePreference>('system')\n const reconciled = useRef(false)\n\n // Boot: cookie → localStorage → system.\n useEffect(() => {\n const cookie = readThemeCookie()\n let ls: string | null = null\n try {\n ls = localStorage.getItem(THEME_STORAGE_KEY)\n } catch {\n /* unavailable */\n }\n const pref = cookie ?? (isThemePreference(ls) ? ls : null) ?? 'system'\n setValueState(pref)\n applyThemePreference(pref)\n }, [])\n\n // Once per session: converge on the profile's saved choice (authoritative),\n // reusing the provider's single `me` fetch.\n const meCtx = useContext(NavChromeContext)\n useEffect(() => {\n if (reconciled.current) return\n const pref = meCtx?.me?.themePreference\n if (isThemePreference(pref)) {\n reconciled.current = true\n setValueState(pref)\n applyThemePreference(pref)\n writeThemeCookie(pref)\n try {\n localStorage.setItem(THEME_STORAGE_KEY, pref)\n } catch {\n /* unavailable */\n }\n }\n }, [meCtx?.me])\n\n // Live sync: storage events (same-app tabs), focus/visibility cookie\n // re-reads (other-app tabs), and OS changes while on \"system\".\n useEffect(() => {\n const onStorage = (e: StorageEvent) => {\n if (e.key === THEME_STORAGE_KEY && isThemePreference(e.newValue)) {\n setValueState(e.newValue)\n applyThemePreference(e.newValue)\n }\n }\n const onWake = () => {\n const cookie = readThemeCookie()\n if (cookie) {\n setValueState((prev) => {\n if (cookie !== prev) applyThemePreference(cookie)\n return cookie\n })\n }\n }\n window.addEventListener('storage', onStorage)\n window.addEventListener('focus', onWake)\n document.addEventListener('visibilitychange', onWake)\n return () => {\n window.removeEventListener('storage', onStorage)\n window.removeEventListener('focus', onWake)\n document.removeEventListener('visibilitychange', onWake)\n }\n }, [])\n\n // Follow the OS while set to \"system\".\n useEffect(() => {\n if (value !== 'system') return\n let mq: MediaQueryList\n try {\n mq = window.matchMedia('(prefers-color-scheme: dark)')\n } catch {\n return\n }\n const onChange = () => applyThemePreference('system')\n mq.addEventListener('change', onChange)\n return () => mq.removeEventListener('change', onChange)\n }, [value])\n\n const setValue = useCallback(\n (next: ThemePreference) => {\n setValueState(next)\n applyThemePreference(next)\n writeThemeCookie(next)\n try {\n localStorage.setItem(THEME_STORAGE_KEY, next)\n } catch {\n /* unavailable */\n }\n // Best-effort profile persistence — a theme toggle never errors.\n fetchJson?.('me/preferences', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ themePreference: next }),\n }).catch(() => {})\n },\n [fetchJson],\n )\n\n return { value, setValue }\n}\n","// ---------------------------------------------------------------------------\n// App chrome wiring — the ONE shared implementation of the per-app glue that\n// previously lived as a copied ChromeWidgets.tsx in every Next.js feature app\n// (forms / surveys / polls / contacts). Copies drifted (org dropdown, badges);\n// this module makes that class of drift impossible: apps configure, never\n// re-implement (Reference/UI-Platform: consume via npm, never vendored).\n//\n// Provides:\n// <PolitogyAppChrome> — NavChromeProvider (same-origin proxy fetcher) +\n// chrome state (active core org, nav display) +\n// DevNotes provider, in one wrapper.\n// <ChromeTopBarActions> — the canonical top-bar cluster, in canonical order\n// (Fuel · Nav display · DevNotes · Support · Alerts\n// LAST, immediately left of My Account).\n// useChromeState / useChromeUserMenu / useIsSuperAdmin / useChromeFooter.\n//\n// The app still owns: its session (the /api/chrome proxy), page frames, build\n// metadata (env/commit/version), tab strips, and its own icons.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n NavChromeProvider,\n FuelAction,\n NotificationsAction,\n SupportAction,\n NavDisplayAction,\n TopBarWidgetSlot,\n useChromeOrgs,\n useThemePreference,\n type NavChromeFetcher,\n type NavDisplayMode,\n type NavOrgOption,\n type NavUserMenu,\n type NavFooter,\n type NavFooterLink,\n} from '../native/index'\nimport {\n DevNotesProvider,\n DevNotesMenu,\n createDevNotesClient,\n type DevNotesConfig,\n} from '@the-portland-company/devnotes'\n\nconst ORG_STORAGE_KEY = 'vrm.activeOrg'\nconst NAV_DISPLAY_KEY = 'vrm.navDisplay'\nconst CORE_BASE_URL = 'https://app.politogyvrm.com'\n\nexport type ChromeIdentity = {\n userId: string\n userName: string | null\n email: string | null\n /** The APP's own role string (any casing) — feeds DevNotes admin gating. */\n role: string\n}\n\ntype ChromeState = {\n orgId: string | null\n setOrgId: (id: string) => void\n orgs: (NavOrgOption & { rawRole?: string | null })[]\n navDisplay: NavDisplayMode\n setNavDisplay: (m: NavDisplayMode) => void\n}\n\nconst ChromeStateContext = createContext<ChromeState | null>(null)\n\nexport function useChromeState(): ChromeState | null {\n return useContext(ChromeStateContext)\n}\n\nfunction ChromeStateProvider({ children }: { children: ReactNode }) {\n const { orgs } = useChromeOrgs()\n const [orgId, setOrgIdState] = useState<string | null>(null)\n const [navDisplay, setNavDisplayState] = useState<NavDisplayMode>('both')\n\n // Boot: restore persisted choices.\n useEffect(() => {\n try {\n const storedOrg = localStorage.getItem(ORG_STORAGE_KEY)\n if (storedOrg) setOrgIdState(storedOrg)\n const storedNav = localStorage.getItem(NAV_DISPLAY_KEY)\n if (storedNav === 'menu' || storedNav === 'tabs' || storedNav === 'both') {\n setNavDisplayState(storedNav)\n }\n } catch {\n /* storage unavailable */\n }\n }, [])\n\n // Once orgs resolve: validate the stored org, default to the first.\n useEffect(() => {\n if (!orgs || orgs.length === 0) return\n setOrgIdState((prev) => (prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id))\n }, [orgs])\n\n const setOrgId = useCallback((id: string) => {\n setOrgIdState(id)\n try {\n localStorage.setItem(ORG_STORAGE_KEY, id)\n } catch {\n /* best effort */\n }\n }, [])\n\n const setNavDisplay = useCallback((m: NavDisplayMode) => {\n setNavDisplayState(m)\n try {\n localStorage.setItem(NAV_DISPLAY_KEY, m)\n } catch {\n /* best effort */\n }\n }, [])\n\n const value = useMemo<ChromeState>(\n () => ({\n orgId,\n setOrgId,\n orgs: (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n navDisplay,\n setNavDisplay,\n }),\n [orgId, setOrgId, orgs, navDisplay, setNavDisplay],\n )\n\n return <ChromeStateContext.Provider value={value}>{children}</ChromeStateContext.Provider>\n}\n\nfunction AppDevNotes({\n storagePrefix,\n proxyBasePath,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath: string\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const adapter = useMemo(\n () =>\n createDevNotesClient({\n basePath: `${proxyBasePath}/devnotes`,\n // The proxy attaches the session's Bearer server-side.\n getAuthToken: async () => '',\n }),\n [proxyBasePath],\n )\n\n const user = useMemo(\n () => ({\n id: identity.userId,\n email: identity.email ?? '',\n fullName: identity.userName ?? undefined,\n }),\n [identity.userId, identity.email, identity.userName],\n )\n\n const config = useMemo<DevNotesConfig>(\n () => ({\n storagePrefix,\n role: identity.role.toLowerCase() === 'admin' ? 'admin' : 'reporter',\n disableAi: true,\n getPagePath: () => window.location.pathname,\n }),\n [storagePrefix, identity.role],\n )\n\n return (\n <DevNotesProvider adapter={adapter} user={user} config={config}>\n {children}\n </DevNotesProvider>\n )\n}\n\n/**\n * The app-chrome root. Wrap the authenticated frame once:\n *\n * <PolitogyAppChrome storagePrefix=\"forms\" identity={{userId, userName, email, role}}>\n * <ShellFrame …/>\n * </PolitogyAppChrome>\n */\nexport function PolitogyAppChrome({\n storagePrefix,\n proxyBasePath = '/api/chrome',\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath?: string\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const fetchJson = useMemo<NavChromeFetcher>(\n () =>\n async (path, init) => {\n const res = await fetch(`${proxyBasePath}/${path}`, {\n method: init?.method ?? 'GET',\n headers: init?.headers,\n body: init?.body,\n })\n if (!res.ok) throw new Error(`chrome ${path}: ${res.status}`)\n if (res.status === 204) return null\n const text = await res.text()\n return text ? JSON.parse(text) : null\n },\n [proxyBasePath],\n )\n\n return (\n <NavChromeProvider fetchJson={fetchJson}>\n <ChromeStateProvider>\n <AppDevNotes\n storagePrefix={storagePrefix}\n proxyBasePath={proxyBasePath}\n identity={identity}\n >\n {children}\n </AppDevNotes>\n </ChromeStateProvider>\n </NavChromeProvider>\n )\n}\n\n/** The standard top-bar action cluster. The Alerts bell renders LAST so it\n * sits farthest right, immediately left of the My Account badge. */\nexport function ChromeTopBarActions() {\n const state = useChromeState()\n if (!state) return null\n return (\n <>\n <FuelAction orgId={state.orgId} />\n <NavDisplayAction value={state.navDisplay} onChange={state.setNavDisplay} />\n <TopBarWidgetSlot\n title=\"DevNotes\"\n description=\"Capture bugs and notes, filed straight to Forge.\"\n >\n <DevNotesMenu />\n </TopBarWidgetSlot>\n <SupportAction />\n <NotificationsAction orgId={state.orgId} />\n </>\n )\n}\n\n/** True when any core-org membership carries a super-admin tier. */\nexport function useIsSuperAdmin(): boolean {\n const state = useChromeState()\n return (state?.orgs ?? []).some((o) => /super/i.test(o.rawRole ?? ''))\n}\n\nconst FOOTER_LINKS: NavFooterLink[] = [\n { label: 'Privacy', href: `${CORE_BASE_URL}/privacy-policy`, external: true },\n { label: 'Terms', href: `${CORE_BASE_URL}/terms-and-conditions`, external: true },\n {\n label: 'Subscriptions',\n href: 'https://politogyvrm.com/subscription-cancellation-policy',\n external: true,\n },\n]\n\n/**\n * Sidebar footer: legal links for everyone; build metadata (env / commit /\n * version / date / author) ONLY for Super Administrators\n * (Reference/UI-Platform). Pass the app's build-time metadata in.\n */\nexport function useChromeFooter(meta: {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}): NavFooter {\n const isSuperAdmin = useIsSuperAdmin()\n return useMemo<NavFooter>(\n () => (isSuperAdmin ? { links: FOOTER_LINKS, ...meta } : { links: FOOTER_LINKS }),\n [isSuperAdmin, meta.envLabel, meta.version, meta.commit, meta.commitDate, meta.commitAuthor],\n )\n}\n\n/**\n * The My Account menu config — profile/org links into VRM core, real roles\n * from the user's core organizations, the signed-in account, and the shared\n * Light/System/Dark theme control (auth-derived, cross-app).\n */\nexport function useChromeUserMenu({\n userId,\n userName,\n email,\n}: {\n userId: string\n userName: string | null\n email: string | null\n}): NavUserMenu {\n const state = useChromeState()\n const theme = useThemePreference()\n const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null\n const orgSuffix = activeOrg ? `?org=${activeOrg.id.slice(-6)}` : ''\n return {\n // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).\n myProfileHref: `${CORE_BASE_URL}/my-profile`,\n organizationSettingsHref: `${CORE_BASE_URL}/organization-settings${orgSuffix}`,\n roles: (state?.orgs ?? [])\n .filter((o) => o.rawRole || o.role)\n .map((o) => ({ role: (o.rawRole ?? o.role) as string, orgName: o.name })),\n accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],\n addAccountHref: `${CORE_BASE_URL}/my-profile#accounts`,\n theme: { value: theme.value, onChange: theme.setValue },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/topbarIconSlot.ts","../src/lib/brandGlyphs.tsx","../src/theme-preference.ts","../src/native/chromeActions.tsx","../src/app-chrome/index.tsx"],"names":["useState","useEffect","FiBatteryCharging","FiBattery","FiZap","FiGrid","FiBell","FiAlertTriangle","FiAlertCircle","FiLifeBuoy","FiHelpCircle","FiMoon","FiSun","FiInfo","FiMail","FiMessageSquare","FiSettings","FiUser","jsxs","jsx","createContext","useContext","useRef","useCallback","Fragment","createPortal","useMemo","createDevNotesClient","DevNotesProvider","DevNotesMenu"],"mappings":"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","file":"app-chrome.cjs","sourcesContent":["import { useEffect, useState } from 'react'\n\n/**\n * The six canonical top-bar action slots (Reference/Global-Rules v9 → top-bar\n * icons). Each slot's GLYPH is unique and comes from the Brand API\n * `topbarIcons.items.*` tokens, exposed as `--topbar-icon-<slot>` CSS vars\n * whose value is the brand-icon NAME. Every OTHER property — size, gap, color,\n * hover, selected — is universal across all six slots.\n */\nexport type TopBarIconSlot =\n | 'comms-fuel'\n | 'apps'\n | 'notifications'\n | 'alerts'\n | 'support'\n | 'dark-mode'\n\n/**\n * Reads the glyph NAME for a slot from its `--topbar-icon-<slot>` CSS var.\n *\n * Runs in an effect because the Brand stylesheet is appended to <head> at\n * runtime (Global Rules forbids baking it into the build), so the var is not\n * resolvable during SSR or the first synchronous render. The MutationObserver\n * re-reads once the stylesheet lands so the glyph upgrades from the caller's\n * fallback without a reload.\n *\n * Returns null when the slot has no Brand glyph — callers render their own\n * fallback icon in that case.\n */\nexport function useTopBarIconSlotGlyph(slot: TopBarIconSlot): string | null {\n const [name, setName] = useState<string | null>(null)\n\n useEffect(() => {\n if (typeof window === 'undefined') return\n\n const read = () => {\n const raw = window\n .getComputedStyle(document.documentElement)\n .getPropertyValue(`--topbar-icon-${slot}`)\n .trim()\n // Brand may emit the name quoted (e.g. \"bell\"); strip the quotes.\n .replace(/^['\"]|['\"]$/g, '')\n setName(raw.length > 0 ? raw : null)\n }\n\n read()\n\n const observer = new MutationObserver(read)\n observer.observe(document.head, { childList: true, subtree: true })\n return () => observer.disconnect()\n }, [slot])\n\n return name\n}\n\n/** Path to a brand-icon SVG in the consuming app's public dir. */\nexport function brandIconSrc(name: string, basePath = '/brand/icons/') {\n return `${basePath}${name}.svg`\n}\n","import type { ComponentType } from 'react'\nimport {\n FiAlertCircle,\n FiBattery,\n FiBatteryCharging,\n FiAlertTriangle,\n FiBell,\n FiGrid,\n FiHelpCircle,\n FiInfo,\n FiLifeBuoy,\n FiMail,\n FiMessageSquare,\n FiMoon,\n FiSettings,\n FiSun,\n FiUser,\n FiZap,\n} from 'react-icons/fi'\n\nexport type GlyphComponent = ComponentType<{ size?: number | string; className?: string }>\n\n/**\n * Brand-glyph registry: maps the icon NAME the Brand API emits (e.g.\n * `--topbar-icon-comms-fuel: bolt`) to a component.\n *\n * These names are Feather/Lucide icon names, NOT asset filenames — there is no\n * `/brand/icons/<name>.svg` for them in any app, and treating them as URLs\n * renders a broken image. Resolving them against the icon library the shell\n * already depends on keeps every app consistent with zero vendored assets.\n *\n * Aliases are included where Brand and Feather disagree on a name (`bolt` vs\n * `zap`, `life-buoy` vs `life-ring`).\n */\nconst GLYPHS: Record<string, GlyphComponent> = {\n // Communications Fuel reads as a LEVEL, so its glyph is a battery. `bolt`/\n // `zap` stay mapped for older Brand values.\n 'battery-charging': FiBatteryCharging,\n battery: FiBattery,\n fuel: FiBatteryCharging,\n bolt: FiZap,\n zap: FiZap,\n grid: FiGrid,\n apps: FiGrid,\n bell: FiBell,\n notification: FiBell,\n 'alert-triangle': FiAlertTriangle,\n alert: FiAlertTriangle,\n 'alert-circle': FiAlertCircle,\n 'life-buoy': FiLifeBuoy,\n 'life-ring': FiLifeBuoy,\n support: FiLifeBuoy,\n 'help-circle': FiHelpCircle,\n moon: FiMoon,\n sun: FiSun,\n info: FiInfo,\n mail: FiMail,\n 'message-square': FiMessageSquare,\n settings: FiSettings,\n user: FiUser,\n}\n\n/**\n * Resolve a Brand glyph name to a component. Returns null for an unknown name\n * so the caller renders its own fallback — an unrecognized token must never\n * produce a broken or empty icon.\n */\nexport function resolveBrandGlyph(name: string | null | undefined): GlyphComponent | null {\n if (!name) return null\n return GLYPHS[name.trim().toLowerCase()] ?? null\n}\n\n/** Names the registry knows — exported for tests and tooling. */\nexport const KNOWN_BRAND_GLYPHS = Object.keys(GLYPHS)\n","// Universal theme preference — the ONE cross-app contract.\n//\n// One theme choice (Light / Dark / System) follows the authenticated user\n// across every Politogy app + subdomain. Three layers cooperate:\n// 1. VRM Core `profiles.theme_preference` — source of truth, persisted via\n// the chrome API (`PATCH me/preferences { themePreference }`) and read\n// back from `GET me` (`themePreference`).\n// 2. `.politogyvrm.com` cookie `politogy_theme` — zero-flash pre-paint\n// vehicle that crosses subdomains (auth session cookies are host-only).\n// 3. localStorage `politogy_theme` — offline fallback store.\n//\n// Ported verbatim from contacts/apps/web/src/lib/theme.ts (the origin of the\n// contract) so every app runs the identical behavior from npm. This module is\n// server-safe (no 'use client'): layouts import THEME_PREPAINT_SCRIPT for the\n// pre-paint inline script. The client-side hook lives in ./native\n// (useThemePreference).\n\nexport type ThemePreference = 'light' | 'dark' | 'system'\n\n// Single converged key for BOTH the localStorage store and the\n// cross-subdomain cookie, so a choice in one app is the same key in the next.\nexport const THEME_STORAGE_KEY = 'politogy_theme'\nexport const THEME_COOKIE = 'politogy_theme'\n\nconst VALID: readonly ThemePreference[] = ['light', 'dark', 'system']\n\nexport function isThemePreference(v: unknown): v is ThemePreference {\n return typeof v === 'string' && (VALID as readonly string[]).includes(v)\n}\n\n/** Read the shared cookie (browser only; null on the server or when unset). */\nexport function readThemeCookie(): ThemePreference | null {\n if (typeof document === 'undefined') return null\n try {\n const m = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${THEME_COOKIE}=([^;]+)`),\n )\n const v = m ? decodeURIComponent(m[1]) : null\n return isThemePreference(v) ? v : null\n } catch {\n return null\n }\n}\n\n// Set the cross-subdomain cookie. On a *.politogyvrm.com host we scope it to\n// the parent domain so every app subdomain reads it; on any other host\n// (localhost, *.pages.dev preview) we fall back to a host-only cookie so\n// local/preview theming still works without a mismatched Domain attribute\n// (which browsers silently drop). 1-year, SameSite=Lax, Secure on https.\nexport function writeThemeCookie(pref: ThemePreference): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') return\n const host = window.location.hostname\n const onParentDomain = /(^|\\.)politogyvrm\\.com$/i.test(host)\n const domainAttr = onParentDomain ? '; Domain=.politogyvrm.com' : ''\n const secure = window.location.protocol === 'https:' ? '; Secure' : ''\n document.cookie = `${THEME_COOKIE}=${encodeURIComponent(\n pref,\n )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`\n}\n\n/** Resolve a preference to the concrete light/dark it renders as right now. */\nexport function resolveTheme(pref: ThemePreference): 'light' | 'dark' {\n if (pref === 'system') {\n try {\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light'\n } catch {\n return 'light'\n }\n }\n return pref\n}\n\n/** Apply a preference to the document (`.dark` class + color-scheme). */\nexport function applyThemePreference(pref: ThemePreference): void {\n if (typeof document === 'undefined') return\n const resolved = resolveTheme(pref)\n const d = document.documentElement\n d.classList.toggle('dark', resolved === 'dark')\n try {\n d.style.colorScheme = resolved\n } catch {\n /* non-fatal */\n }\n}\n\n// Inline pre-paint script — render it in <head> (or as the first child of\n// <body>) so the theme applies before first paint. Resolves the preference\n// from cookie → localStorage → OS, applies the `.dark` class + `color-scheme`,\n// and seeds localStorage from the cookie so the app hydrates to the synced\n// value (the cross-subdomain flash fix). Self-contained, dependency-free, and\n// wrapped so any failure is silent (never blocks paint).\nexport const THEME_PREPAINT_SCRIPT = `(function(){try{\nvar KEY=${JSON.stringify(THEME_STORAGE_KEY)};\nvar VALID=[\"light\",\"dark\",\"system\"];\nfunction fromCookie(){try{var m=document.cookie.match(/(?:^|;\\\\s*)${THEME_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}\nvar cookie=fromCookie();\nvar ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}\nvar pref=cookie||ls||\"system\";\nif(VALID.indexOf(pref)===-1)pref=\"system\";\nif(cookie&&cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}\nvar resolved=pref;\nif(pref===\"system\"){try{resolved=window.matchMedia(\"(prefers-color-scheme: dark)\").matches?\"dark\":\"light\";}catch(e){resolved=\"light\";}}\nvar d=document.documentElement;\nif(resolved===\"dark\"){d.classList.add(\"dark\");}else{d.classList.remove(\"dark\");}\ntry{d.style.colorScheme=resolved;}catch(e){}\n}catch(e){}})();`\n","// ---------------------------------------------------------------------------\n// Native chrome actions — Tailwind-only top-bar widgets (Fuel, Notifications,\n// Support, Navigation-display) backed by the shared chrome API\n// (politogy-contacts-api on Railway). Zero Chakra, zero router, zero fetch\n// opinion: the consuming app injects ONE fetcher via <NavChromeProvider> —\n// typically a same-origin proxy route that attaches its own session's Bearer\n// token server-side — and every widget in every app runs this exact code.\n//\n// Data endpoints (paths are relative; the app's fetcher owns the base URL):\n// GET communications/fuel-status (header x-contacts-org: <core org id>)\n// GET notifications (header x-contacts-org: <core org id>)\n// GET orgs\n// POST support { message }\n//\n// Loading states follow Global-Rules \"Loading & Async States\": the chrome\n// (button, popover frame, labels) always renders; only the VALUE area shows a\n// skeleton shimmer — never a spinner, never a blank panel.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useRef,\n useState,\n type ComponentType,\n type ReactNode,\n} from 'react'\nimport { createPortal } from 'react-dom'\n\nimport { useTopBarIconSlotGlyph, type TopBarIconSlot } from '../lib/topbarIconSlot'\nimport { resolveBrandGlyph } from '../lib/brandGlyphs'\nimport {\n applyThemePreference,\n isThemePreference,\n readThemeCookie,\n writeThemeCookie,\n THEME_STORAGE_KEY,\n type ThemePreference as SharedThemePreference,\n} from '../theme-preference'\n\ntype NavIconLike = ComponentType<{ size?: number; className?: string }>\n\n// ---------------------------------------------------------------------------\n// Shared 32×32 circular top-bar button chrome — the ONE definition of the\n// top-bar trigger (Global Rules: no slot hand-rolls its own trigger/badge).\n// NavTopBar's structured actionsList buttons use this same builder.\n// ---------------------------------------------------------------------------\n\nexport function topBarIconButtonClass(tone: 'default' | 'warning' | 'danger' = 'default'): string {\n const toneClass =\n tone === 'danger' || tone === 'warning'\n ? 'text-[color:var(--color-race-red)] hover:text-[color:var(--color-race-red)]'\n : 'text-[color:var(--topbar-icon-color,var(--muted))] hover:text-[color:var(--topbar-icon-hover-color,var(--foreground))] hover:bg-[color:var(--topbar-icon-hover-bg,transparent)]'\n return [\n // `group/tbtip` powers the shared <TopBarTooltip> rendered inside the trigger.\n 'group/tbtip relative flex items-center justify-center rounded-full border border-[color:var(--line)] transition',\n 'h-[var(--topbar-icon-button-size,32px)] w-[var(--topbar-icon-button-size,32px)]',\n toneClass,\n ].join(' ')\n}\n\n/** The shared count badge — one definition, used by every slot. */\nexport function TopBarCountBadge({ count }: { count: number }) {\n if (!(count > 0)) return null\n return (\n <span className=\"absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full bg-[color:var(--color-race-red)] px-1 text-[10px] text-white\">\n {count > 99 ? '99+' : count}\n </span>\n )\n}\n\n/**\n * The shared hover tooltip every top-bar control renders BELOW itself: an\n * up-pointing arrow at the icon, a bold title line and a muted description.\n * Pure CSS (group-hover) so it works on <a>, <button> and <summary> triggers.\n * The trigger must carry `group/tbtip relative` (topBarIconButtonClass does).\n */\nexport function TopBarTooltip({\n title,\n description,\n}: {\n title: string\n description?: ReactNode\n}) {\n return (\n <span\n role=\"tooltip\"\n className=\"pointer-events-none absolute left-1/2 top-full z-50 mt-2 hidden w-max max-w-56 -translate-x-1/2 flex-col rounded-lg border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-3 py-2 text-left shadow-[var(--shadow-soft)] group-hover/tbtip:flex\"\n >\n {/* Arrow pointing up at the icon */}\n <span\n aria-hidden\n className=\"absolute -top-[5px] left-1/2 h-2.5 w-2.5 -translate-x-1/2 rotate-45 border-l border-t border-[color:var(--line)] bg-[color:var(--panel-elevated)]\"\n />\n <span className=\"text-xs font-semibold text-[color:var(--foreground)]\">{title}</span>\n {description ? (\n <span className=\"mt-0.5 text-[11px] leading-snug text-[color:var(--muted)]\">\n {description}\n </span>\n ) : null}\n </span>\n )\n}\n\n/**\n * The up-pointing arrow every top-bar panel renders, anchored under its\n * trigger icon (panels are right-aligned, so the arrow sits at the trigger's\n * center: 16px in from the panel's right edge). One definition — every menu\n * points at its own icon identically.\n */\nexport function TopBarPanelArrow() {\n return (\n <span\n aria-hidden\n className=\"absolute -top-[5px] right-[11px] h-2.5 w-2.5 rotate-45 border-l border-t border-[color:var(--line)] bg-[color:var(--panel-elevated)]\"\n />\n )\n}\n\n/**\n * Wrapper for third-party top-bar widgets that ship their own launcher button\n * (e.g. DevNotes). Normalizes the trigger to the universal 32px circular slot\n * (chrome.css `.topbar-widget-slot`) and adds the standard tooltip.\n */\nexport function TopBarWidgetSlot({\n title,\n description,\n children,\n}: {\n title: string\n description?: string\n children: ReactNode\n}) {\n return (\n <span className=\"topbar-widget-slot group/tbtip relative inline-flex\">\n {children}\n <TopBarTooltip title={title} description={description} />\n </span>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Theme control — Light / System / Dark, rendered inside the account menu.\n// Controlled: the app owns persistence (profile + cross-subdomain cookie).\n// ---------------------------------------------------------------------------\n\nexport type ThemePreference = SharedThemePreference\n\nconst THEME_OPTIONS: { value: ThemePreference; label: string }[] = [\n { value: 'light', label: 'Light' },\n { value: 'system', label: 'System' },\n { value: 'dark', label: 'Dark' },\n]\n\nexport function NavThemeControl({\n value,\n onChange,\n}: {\n value: ThemePreference\n onChange: (next: ThemePreference) => void\n}) {\n return (\n <div className=\"px-4 py-3\">\n <p className=\"mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Appearance\n </p>\n <div\n role=\"radiogroup\"\n aria-label=\"Appearance\"\n className=\"flex overflow-hidden rounded-full border border-[color:var(--line)]\"\n >\n {THEME_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === opt.value}\n onClick={() => onChange(opt.value)}\n className={[\n 'flex-1 px-3 py-1.5 text-xs font-semibold transition',\n value === opt.value\n ? 'bg-[color:var(--color-race-red)] text-white'\n : 'text-[color:var(--muted)] hover:bg-[color:var(--panel)] hover:text-[color:var(--foreground)]',\n ].join(' ')}\n >\n {opt.label}\n </button>\n ))}\n </div>\n </div>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Chrome data context — the injected fetcher.\n// ---------------------------------------------------------------------------\n\nexport type NavChromeFetcher = (\n path: string,\n init?: { method?: string; headers?: Record<string, string>; body?: string },\n) => Promise<unknown>\n\n/** GET me — the authenticated user's chrome identity from the shared API.\n * userName prefers the VRM-core profile full name over token claims. */\nexport type ChromeMe = {\n user: string | null\n userName: string | null\n avatarUrl: string | null\n themePreference: string | null\n account?: string | null\n accountName?: string | null\n role?: string | null\n}\n\ntype NavChromeContextValue = {\n fetchJson: NavChromeFetcher\n me: ChromeMe | null\n meLoaded: boolean\n}\n\nconst NavChromeContext = createContext<NavChromeContextValue | null>(null)\n\nexport function NavChromeProvider({\n fetchJson,\n children,\n}: {\n fetchJson: NavChromeFetcher\n children: ReactNode\n}) {\n // ONE `me` fetch per provider — identity (profile name/avatar) and the\n // theme reconciliation both hang off it.\n const [me, setMe] = useState<ChromeMe | null>(null)\n const [meLoaded, setMeLoaded] = useState(false)\n useEffect(() => {\n let cancelled = false\n fetchJson('me')\n .then((data) => {\n if (!cancelled) setMe(data as ChromeMe)\n })\n .catch(() => {\n /* degraded: session identity stands in */\n })\n .finally(() => {\n if (!cancelled) setMeLoaded(true)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson])\n\n return (\n <NavChromeContext.Provider value={{ fetchJson, me, meLoaded }}>\n {children}\n </NavChromeContext.Provider>\n )\n}\n\n/** The authenticated user's chrome identity (profile name / avatar / theme). */\nexport function useChromeMe(): { me: ChromeMe | null; loaded: boolean } {\n const ctx = useContext(NavChromeContext)\n return { me: ctx?.me ?? null, loaded: ctx?.meLoaded ?? false }\n}\n\nfunction useNavChrome(component: string): NavChromeContextValue {\n const ctx = useContext(NavChromeContext)\n if (!ctx) {\n throw new Error(\n `${component} must be rendered inside <NavChromeProvider> (inject the chrome API fetcher there).`,\n )\n }\n return ctx\n}\n\n// ---------------------------------------------------------------------------\n// Data shapes (mirror of politogy-contacts-api responses).\n// ---------------------------------------------------------------------------\n\nexport type FuelChannelStatus = {\n remainingUnits: number\n rawBalanceUnits: number\n usedUnits: number\n lowFuel: boolean\n lowFuelThreshold: number\n}\n\nexport type CommunicationsFuelStatus = {\n organizationId: string\n signal: FuelChannelStatus\n broadcast: FuelChannelStatus\n combinedAvailableCredits: number\n}\n\nexport type ChromeNotificationAlert = {\n id: string\n title: string\n description: string\n href: string | null\n kind: string\n}\n\nexport type ChromeNotificationReply = {\n id: string\n contactId: string | null\n name: string\n preview: string\n}\n\nexport type ChromeNotificationsPayload = {\n organizationId: string\n alerts: ChromeNotificationAlert[]\n replies: ChromeNotificationReply[]\n}\n\nexport type ChromeOrgSummary = {\n id: string\n name: string | null\n logoUrl: string | null\n brandColor: string | null\n role: string | null\n /** Un-mapped VRM-core membership role (e.g. \"super_admin\"). */\n rawRole?: string | null\n}\n\n/**\n * Fetch the signed-in user's VRM-core organizations through the injected\n * fetcher. Exposed as a hook so the org switcher in the sidebar and the\n * org-scoped widgets share one request.\n */\nexport function useChromeOrgs(): {\n orgs: ChromeOrgSummary[] | null\n loading: boolean\n error: boolean\n} {\n const { fetchJson } = useNavChrome('useChromeOrgs')\n const [orgs, setOrgs] = useState<ChromeOrgSummary[] | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(false)\n fetchJson('orgs')\n .then((data) => {\n if (cancelled) return\n const list = (data as { orgs?: ChromeOrgSummary[] })?.orgs ?? []\n setOrgs(list)\n })\n .catch(() => {\n if (!cancelled) setError(true)\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson])\n\n return { orgs, loading, error }\n}\n\n// ---------------------------------------------------------------------------\n// Internal building blocks.\n// ---------------------------------------------------------------------------\n\n/** Value-area skeleton shimmer (chrome/labels stay static per Global Rules). */\nfunction ValueSkeleton({ className }: { className?: string }) {\n return (\n <span\n aria-hidden\n className={[\n 'inline-block animate-pulse rounded bg-[color:var(--panel-elevated)]',\n className ?? 'h-4 w-16',\n ].join(' ')}\n />\n )\n}\n\n/** Slot-driven glyph: Brand-token name when resolvable, fallback otherwise. */\nfunction SlotGlyph({\n slot,\n fallback: Fallback,\n size = 20,\n}: {\n slot?: TopBarIconSlot\n fallback: NavIconLike\n size?: number\n}) {\n const glyphName = useTopBarIconSlotGlyph(slot ?? 'apps')\n const BrandGlyph = slot ? resolveBrandGlyph(glyphName) : null\n const Glyph = BrandGlyph ?? Fallback\n return <Glyph size={size} className=\"text-current\" />\n}\n\n/**\n * A top-bar popover: the shared circular trigger + a right-aligned panel.\n * Closes on outside click / Escape. Purely presentational.\n */\nfunction TopBarPopover({\n label,\n description,\n slot,\n fallbackIcon,\n badge,\n tone,\n onOpen,\n children,\n panelClassName,\n}: {\n label: string\n description?: string\n slot?: TopBarIconSlot\n fallbackIcon: NavIconLike\n badge?: number\n tone?: 'default' | 'warning' | 'danger'\n onOpen?: () => void\n children: ReactNode\n panelClassName?: string\n}) {\n const [open, setOpen] = useState(false)\n const rootRef = useRef<HTMLDivElement | null>(null)\n\n useEffect(() => {\n if (!open) return\n const onDocClick = (e: MouseEvent) => {\n if (rootRef.current && !rootRef.current.contains(e.target as Node)) setOpen(false)\n }\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') setOpen(false)\n }\n document.addEventListener('mousedown', onDocClick)\n document.addEventListener('keydown', onKey)\n return () => {\n document.removeEventListener('mousedown', onDocClick)\n document.removeEventListener('keydown', onKey)\n }\n }, [open])\n\n return (\n <div ref={rootRef} className=\"relative\">\n <button\n type=\"button\"\n aria-label={label}\n aria-expanded={open}\n className={topBarIconButtonClass(tone)}\n onClick={() => {\n setOpen((v) => {\n const next = !v\n if (next) onOpen?.()\n return next\n })\n }}\n >\n <SlotGlyph slot={slot} fallback={fallbackIcon} />\n {typeof badge === 'number' ? <TopBarCountBadge count={badge} /> : null}\n {!open ? <TopBarTooltip title={label} description={description} /> : null}\n </button>\n {open ? (\n <div\n className={[\n 'absolute right-0 z-40 mt-2 rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] shadow-[var(--shadow-soft)]',\n panelClassName ?? 'w-80',\n ].join(' ')}\n >\n <TopBarPanelArrow />\n <div className=\"overflow-hidden rounded-xl\">{children}</div>\n </div>\n ) : null}\n </div>\n )\n}\n\n// Inline fallback glyphs (Feather-style paths) so the package needs no icon dep.\nfunction BatteryGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <rect x=\"1\" y=\"6\" width=\"18\" height=\"12\" rx=\"2\" ry=\"2\" />\n <line x1=\"23\" y1=\"10\" x2=\"23\" y2=\"14\" />\n <line x1=\"5\" y1=\"10\" x2=\"5\" y2=\"14\" />\n <line x1=\"9\" y1=\"10\" x2=\"9\" y2=\"14\" />\n </svg>\n )\n}\n\nfunction BellGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <path d=\"M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9\" />\n <path d=\"M13.73 21a2 2 0 0 1-3.46 0\" />\n </svg>\n )\n}\n\nfunction LifeBuoyGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <circle cx=\"12\" cy=\"12\" r=\"10\" />\n <circle cx=\"12\" cy=\"12\" r=\"4\" />\n <line x1=\"4.93\" y1=\"4.93\" x2=\"9.17\" y2=\"9.17\" />\n <line x1=\"14.83\" y1=\"14.83\" x2=\"19.07\" y2=\"19.07\" />\n <line x1=\"14.83\" y1=\"9.17\" x2=\"19.07\" y2=\"4.93\" />\n <line x1=\"4.93\" y1=\"19.07\" x2=\"9.17\" y2=\"14.83\" />\n </svg>\n )\n}\n\nfunction LayoutGlyph({ size = 20, className }: { size?: number; className?: string }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={2} strokeLinecap=\"round\" strokeLinejoin=\"round\" className={className} aria-hidden>\n <rect x=\"3\" y=\"3\" width=\"18\" height=\"18\" rx=\"2\" ry=\"2\" />\n <line x1=\"3\" y1=\"9\" x2=\"21\" y2=\"9\" />\n <line x1=\"9\" y1=\"21\" x2=\"9\" y2=\"9\" />\n </svg>\n )\n}\n\n// ---------------------------------------------------------------------------\n// FuelAction — Communications Fuel balance (battery glyph + popover meters).\n// ---------------------------------------------------------------------------\n\nfunction FuelRow({\n label,\n channel,\n loading,\n}: {\n label: string\n channel: FuelChannelStatus | null\n loading: boolean\n}) {\n const remaining = channel?.remainingUnits ?? 0\n const total = channel ? Math.max(channel.rawBalanceUnits, channel.remainingUnits) : 0\n const ratio = total > 0 ? Math.min(100, Math.max(0, (remaining / total) * 100)) : 0\n const low = channel?.lowFuel ?? false\n\n return (\n <div className=\"w-full\">\n <div className=\"mb-1 flex items-center justify-between\">\n <span className=\"text-xs font-semibold text-[color:var(--foreground)]\">{label}</span>\n {loading ? (\n <ValueSkeleton className=\"h-3.5 w-14\" />\n ) : (\n <span\n className={[\n 'text-xs font-semibold tabular-nums',\n low ? 'text-[color:var(--color-race-red)]' : 'text-[color:var(--muted)]',\n ].join(' ')}\n >\n {remaining.toLocaleString()} left\n </span>\n )}\n </div>\n <div className=\"h-1.5 w-full overflow-hidden rounded-full bg-[color:var(--panel)]\">\n {loading ? (\n <div className=\"h-full w-full animate-pulse bg-[color:var(--line)]\" />\n ) : (\n <div\n className={[\n 'h-full rounded-full transition-[width]',\n low ? 'bg-[color:var(--color-race-red)]' : 'bg-[color:var(--color-ok,#00A651)]',\n ].join(' ')}\n style={{ width: `${ratio}%` }}\n />\n )}\n </div>\n </div>\n )\n}\n\nexport function FuelAction({ orgId }: { orgId: string | null }) {\n const { fetchJson } = useNavChrome('FuelAction')\n const [fuel, setFuel] = useState<CommunicationsFuelStatus | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(false)\n setFuel(null)\n fetchJson('communications/fuel-status', {\n headers: orgId ? { 'x-contacts-org': orgId } : undefined,\n })\n .then((data) => {\n if (cancelled) return\n setFuel((data as { fuel?: CommunicationsFuelStatus | null })?.fuel ?? null)\n })\n .catch(() => {\n if (!cancelled) setError(true)\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson, orgId])\n\n const low = !!fuel && (fuel.signal.lowFuel || fuel.broadcast.lowFuel)\n\n return (\n <TopBarPopover\n label=\"Communications Fuel\"\n description=\"Remaining SMS and email sending balance for the active organization.\"\n slot=\"comms-fuel\"\n fallbackIcon={BatteryGlyph}\n tone={low ? 'warning' : 'default'}\n >\n <div className=\"px-4 py-3\">\n <p className=\"mb-3 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Communications Fuel\n </p>\n {error || (!loading && !fuel) ? (\n <p className=\"text-sm text-[color:var(--muted)]\">\n Fuel balance is unavailable right now.\n </p>\n ) : (\n <div className=\"flex flex-col gap-3\">\n <FuelRow label=\"SMS Signal\" channel={fuel?.signal ?? null} loading={loading} />\n <FuelRow label=\"Email Broadcast\" channel={fuel?.broadcast ?? null} loading={loading} />\n </div>\n )}\n </div>\n </TopBarPopover>\n )\n}\n\n// ---------------------------------------------------------------------------\n// NotificationsAction — bell + count badge + alerts/replies popover.\n// ---------------------------------------------------------------------------\n\nexport function NotificationsAction({ orgId }: { orgId: string | null }) {\n const { fetchJson } = useNavChrome('NotificationsAction')\n const [payload, setPayload] = useState<ChromeNotificationsPayload | null>(null)\n const [loading, setLoading] = useState(true)\n const [error, setError] = useState(false)\n\n useEffect(() => {\n let cancelled = false\n setLoading(true)\n setError(false)\n setPayload(null)\n fetchJson('notifications', {\n headers: orgId ? { 'x-contacts-org': orgId } : undefined,\n })\n .then((data) => {\n if (!cancelled) setPayload(data as ChromeNotificationsPayload)\n })\n .catch(() => {\n if (!cancelled) setError(true)\n })\n .finally(() => {\n if (!cancelled) setLoading(false)\n })\n return () => {\n cancelled = true\n }\n }, [fetchJson, orgId])\n\n const count = (payload?.alerts.length ?? 0) + (payload?.replies.length ?? 0)\n\n return (\n <TopBarPopover\n label=\"Alerts & Notifications\"\n description=\"System alerts and recent activity for the active organization.\"\n slot=\"notifications\"\n fallbackIcon={BellGlyph}\n badge={loading ? 0 : count}\n >\n <div className=\"px-4 py-3\">\n <p className=\"mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Notifications\n </p>\n {loading ? (\n <div className=\"flex flex-col gap-2 py-1\">\n <ValueSkeleton className=\"h-4 w-full\" />\n <ValueSkeleton className=\"h-4 w-3/4\" />\n </div>\n ) : error ? (\n <p className=\"text-sm text-[color:var(--muted)]\">\n Notifications are unavailable right now.\n </p>\n ) : count === 0 ? (\n <p className=\"py-1 text-sm text-[color:var(--muted)]\">You’re all caught up.</p>\n ) : (\n <ul className=\"flex max-h-80 flex-col gap-1 overflow-y-auto\">\n {payload?.alerts.map((a) => (\n <li key={a.id}>\n <a\n href={a.href ?? '#'}\n className=\"block rounded-lg px-2 py-2 hover:bg-[color:var(--panel)]\"\n >\n <p className=\"text-sm font-semibold text-[color:var(--foreground)]\">{a.title}</p>\n <p className=\"text-xs text-[color:var(--muted)]\">{a.description}</p>\n </a>\n </li>\n ))}\n {payload?.replies.map((r) => (\n <li key={r.id} className=\"rounded-lg px-2 py-2 hover:bg-[color:var(--panel)]\">\n <p className=\"text-sm font-semibold text-[color:var(--foreground)]\">{r.name}</p>\n <p className=\"truncate text-xs text-[color:var(--muted)]\">{r.preview}</p>\n </li>\n ))}\n </ul>\n )}\n </div>\n </TopBarPopover>\n )\n}\n\n// ---------------------------------------------------------------------------\n// SupportAction — life-buoy trigger + the shared support-request modal\n// (never a mailto:, never an app-local form — Reference/UI-Platform).\n// ---------------------------------------------------------------------------\n\nexport function SupportAction() {\n const { fetchJson } = useNavChrome('SupportAction')\n const [open, setOpen] = useState(false)\n const [message, setMessage] = useState('')\n const [state, setState] = useState<'idle' | 'sending' | 'sent' | 'error'>('idle')\n\n const close = useCallback(() => {\n setOpen(false)\n setState('idle')\n setMessage('')\n }, [])\n\n useEffect(() => {\n if (!open) return\n const onKey = (e: KeyboardEvent) => {\n if (e.key === 'Escape') close()\n }\n document.addEventListener('keydown', onKey)\n return () => document.removeEventListener('keydown', onKey)\n }, [open, close])\n\n const submit = async () => {\n if (!message.trim() || state === 'sending') return\n setState('sending')\n try {\n await fetchJson('support', {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ message: message.trim() }),\n })\n setState('sent')\n } catch {\n setState('error')\n }\n }\n\n return (\n <>\n <button\n type=\"button\"\n aria-label=\"Support\"\n className={topBarIconButtonClass()}\n onClick={() => setOpen(true)}\n >\n <SlotGlyph slot=\"support\" fallback={LifeBuoyGlyph} />\n <TopBarTooltip\n title=\"Support\"\n description=\"Send a support request to the Politogy team.\"\n />\n </button>\n {open && typeof document !== 'undefined'\n ? createPortal(\n <div\n // Portaled to <body>: the top bar's backdrop-blur creates a CSS\n // containing block, so a fixed-position descendant would center on\n // the HEADER (rendering off-screen) instead of the viewport.\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Support request\"\n onMouseDown={(e) => {\n if (e.target === e.currentTarget) close()\n }}\n >\n <div className=\"w-full max-w-md rounded-2xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] p-6 shadow-[var(--shadow-soft)]\">\n <h2 className=\"text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]\">\n Contact Support\n </h2>\n {state === 'sent' ? (\n <>\n <p className=\"mt-3 text-sm text-[color:var(--muted)]\">\n Your request was sent. The team will reply by email.\n </p>\n <div className=\"mt-5 flex justify-end\">\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-full bg-[color:var(--color-race-red)] px-4 py-2 text-sm font-semibold text-white hover:opacity-90\"\n >\n Done\n </button>\n </div>\n </>\n ) : (\n <>\n <p className=\"mt-1 text-sm text-[color:var(--muted)]\">\n Describe the problem or question. Your account details ride along\n automatically.\n </p>\n <textarea\n value={message}\n onChange={(e) => setMessage(e.target.value)}\n rows={5}\n placeholder=\"How can we help?\"\n className=\"mt-4 w-full resize-y rounded-lg border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2 text-sm text-[color:var(--foreground)] placeholder:text-[color:var(--muted)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-race-red)]\"\n />\n {state === 'error' ? (\n <p className=\"mt-2 text-sm text-[color:var(--color-race-red)]\">\n Sending failed — try again.\n </p>\n ) : null}\n <div className=\"mt-4 flex justify-end gap-2\">\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded-full border border-[color:var(--line)] px-4 py-2 text-sm font-semibold text-[color:var(--foreground)] hover:bg-[color:var(--panel)]\"\n >\n Cancel\n </button>\n <button\n type=\"button\"\n onClick={submit}\n disabled={!message.trim() || state === 'sending'}\n className=\"rounded-full bg-[color:var(--color-race-red)] px-4 py-2 text-sm font-semibold text-white transition hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50\"\n >\n {state === 'sending' ? 'Sending…' : 'Send request'}\n </button>\n </div>\n </>\n )}\n </div>\n </div>,\n document.body,\n )\n : null}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n// NavDisplayAction — the Menu / Tabs / Both navigation-display switcher.\n// Controlled: the app owns persistence (localStorage/profile) and layout\n// consequences (sub-menu visibility, tab strip visibility).\n// ---------------------------------------------------------------------------\n\nexport type NavDisplayMode = 'menu' | 'tabs' | 'both'\n\nconst NAV_DISPLAY_OPTIONS: { value: NavDisplayMode; label: string }[] = [\n { value: 'menu', label: 'Sub Menu' },\n { value: 'tabs', label: 'Tabs Only' },\n { value: 'both', label: 'Both' },\n]\n\nexport function NavDisplayAction({\n value,\n onChange,\n}: {\n value: NavDisplayMode\n onChange: (next: NavDisplayMode) => void\n}) {\n return (\n <TopBarPopover\n label=\"Navigation Display\"\n description=\"Show navigation as a sub-menu, tabs, or both.\"\n fallbackIcon={LayoutGlyph}\n panelClassName=\"w-44\"\n >\n <div className=\"py-1\" role=\"radiogroup\" aria-label=\"Navigation display\">\n {NAV_DISPLAY_OPTIONS.map((opt) => (\n <button\n key={opt.value}\n type=\"button\"\n role=\"radio\"\n aria-checked={value === opt.value}\n onClick={() => onChange(opt.value)}\n className={[\n 'flex w-full items-center justify-between px-4 py-2 text-left text-sm font-medium',\n value === opt.value\n ? 'text-[color:var(--color-race-red)]'\n : 'text-[color:var(--foreground)] hover:bg-[color:var(--panel)]',\n ].join(' ')}\n >\n {opt.label}\n {value === opt.value ? <span aria-hidden>✓</span> : null}\n </button>\n ))}\n </div>\n </TopBarPopover>\n )\n}\n\n// ---------------------------------------------------------------------------\n// useThemePreference — the cross-app theme state machine (Task: theme derived\n// from the Auth system, live across tabs and apps).\n//\n// boot : cookie → localStorage → \"system\" (the pre-paint script already\n// painted this), then ONCE per session reconcile against the\n// profile value from `GET me` (authoritative) when a fetcher is\n// available.\n// change : apply + localStorage + cross-subdomain cookie + best-effort\n// `PATCH me/preferences { themePreference }`.\n// sync : same-app tabs via the `storage` event; other-app tabs re-read the\n// shared cookie on focus/visibility; `system` follows live OS\n// changes via matchMedia.\n// ---------------------------------------------------------------------------\n\nexport function useThemePreference(): {\n value: ThemePreference\n setValue: (next: ThemePreference) => void\n} {\n const ctx = useContext(NavChromeContext)\n const fetchJson = ctx?.fetchJson ?? null\n const [value, setValueState] = useState<ThemePreference>('system')\n const reconciled = useRef(false)\n\n // Boot: cookie → localStorage → system.\n useEffect(() => {\n const cookie = readThemeCookie()\n let ls: string | null = null\n try {\n ls = localStorage.getItem(THEME_STORAGE_KEY)\n } catch {\n /* unavailable */\n }\n const pref = cookie ?? (isThemePreference(ls) ? ls : null) ?? 'system'\n setValueState(pref)\n applyThemePreference(pref)\n }, [])\n\n // Once per session: converge on the profile's saved choice (authoritative),\n // reusing the provider's single `me` fetch.\n const meCtx = useContext(NavChromeContext)\n useEffect(() => {\n if (reconciled.current) return\n const pref = meCtx?.me?.themePreference\n if (isThemePreference(pref)) {\n reconciled.current = true\n setValueState(pref)\n applyThemePreference(pref)\n writeThemeCookie(pref)\n try {\n localStorage.setItem(THEME_STORAGE_KEY, pref)\n } catch {\n /* unavailable */\n }\n }\n }, [meCtx?.me])\n\n // Live sync: storage events (same-app tabs), focus/visibility cookie\n // re-reads (other-app tabs), and OS changes while on \"system\".\n useEffect(() => {\n const onStorage = (e: StorageEvent) => {\n if (e.key === THEME_STORAGE_KEY && isThemePreference(e.newValue)) {\n setValueState(e.newValue)\n applyThemePreference(e.newValue)\n }\n }\n const onWake = () => {\n const cookie = readThemeCookie()\n if (cookie) {\n setValueState((prev) => {\n if (cookie !== prev) applyThemePreference(cookie)\n return cookie\n })\n }\n }\n window.addEventListener('storage', onStorage)\n window.addEventListener('focus', onWake)\n document.addEventListener('visibilitychange', onWake)\n return () => {\n window.removeEventListener('storage', onStorage)\n window.removeEventListener('focus', onWake)\n document.removeEventListener('visibilitychange', onWake)\n }\n }, [])\n\n // Follow the OS while set to \"system\".\n useEffect(() => {\n if (value !== 'system') return\n let mq: MediaQueryList\n try {\n mq = window.matchMedia('(prefers-color-scheme: dark)')\n } catch {\n return\n }\n const onChange = () => applyThemePreference('system')\n mq.addEventListener('change', onChange)\n return () => mq.removeEventListener('change', onChange)\n }, [value])\n\n const setValue = useCallback(\n (next: ThemePreference) => {\n setValueState(next)\n applyThemePreference(next)\n writeThemeCookie(next)\n try {\n localStorage.setItem(THEME_STORAGE_KEY, next)\n } catch {\n /* unavailable */\n }\n // Best-effort profile persistence — a theme toggle never errors.\n fetchJson?.('me/preferences', {\n method: 'PATCH',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ themePreference: next }),\n }).catch(() => {})\n },\n [fetchJson],\n )\n\n return { value, setValue }\n}\n","// ---------------------------------------------------------------------------\n// App chrome wiring — the ONE shared implementation of the per-app glue that\n// previously lived as a copied ChromeWidgets.tsx in every Next.js feature app\n// (forms / surveys / polls / contacts). Copies drifted (org dropdown, badges);\n// this module makes that class of drift impossible: apps configure, never\n// re-implement (Reference/UI-Platform: consume via npm, never vendored).\n//\n// Provides:\n// <PolitogyAppChrome> — NavChromeProvider (same-origin proxy fetcher) +\n// chrome state (active core org, nav display) +\n// DevNotes provider, in one wrapper.\n// <ChromeTopBarActions> — the canonical top-bar cluster, in canonical order\n// (Fuel · Nav display · DevNotes · Support · Alerts\n// LAST, immediately left of My Account).\n// useChromeState / useChromeUserMenu / useIsSuperAdmin / useChromeFooter.\n//\n// The app still owns: its session (the /api/chrome proxy), page frames, build\n// metadata (env/commit/version), tab strips, and its own icons.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n NavChromeProvider,\n FuelAction,\n NotificationsAction,\n SupportAction,\n NavDisplayAction,\n TopBarWidgetSlot,\n useChromeOrgs,\n useThemePreference,\n type NavChromeFetcher,\n type NavDisplayMode,\n type NavOrgOption,\n type NavUserMenu,\n type NavFooter,\n type NavFooterLink,\n} from '../native/index'\nimport {\n DevNotesProvider,\n DevNotesMenu,\n createDevNotesClient,\n type DevNotesConfig,\n} from '@the-portland-company/devnotes'\n\nconst ORG_STORAGE_KEY = 'vrm.activeOrg'\nconst NAV_DISPLAY_KEY = 'vrm.navDisplay'\nconst CORE_BASE_URL = 'https://app.politogyvrm.com'\n\nexport type ChromeIdentity = {\n userId: string\n userName: string | null\n email: string | null\n /** The APP's own role string (any casing) — feeds DevNotes admin gating. */\n role: string\n}\n\ntype ChromeState = {\n orgId: string | null\n setOrgId: (id: string) => void\n orgs: (NavOrgOption & { rawRole?: string | null })[]\n navDisplay: NavDisplayMode\n setNavDisplay: (m: NavDisplayMode) => void\n}\n\nconst ChromeStateContext = createContext<ChromeState | null>(null)\n\nexport function useChromeState(): ChromeState | null {\n return useContext(ChromeStateContext)\n}\n\nfunction ChromeStateProvider({ children }: { children: ReactNode }) {\n const { orgs } = useChromeOrgs()\n const [orgId, setOrgIdState] = useState<string | null>(null)\n const [navDisplay, setNavDisplayState] = useState<NavDisplayMode>('both')\n\n // Boot: restore persisted choices.\n useEffect(() => {\n try {\n const storedOrg = localStorage.getItem(ORG_STORAGE_KEY)\n if (storedOrg) setOrgIdState(storedOrg)\n const storedNav = localStorage.getItem(NAV_DISPLAY_KEY)\n if (storedNav === 'menu' || storedNav === 'tabs' || storedNav === 'both') {\n setNavDisplayState(storedNav)\n }\n } catch {\n /* storage unavailable */\n }\n }, [])\n\n // Once orgs resolve: validate the stored org, default to the first.\n useEffect(() => {\n if (!orgs || orgs.length === 0) return\n setOrgIdState((prev) => (prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id))\n }, [orgs])\n\n const setOrgId = useCallback((id: string) => {\n setOrgIdState(id)\n try {\n localStorage.setItem(ORG_STORAGE_KEY, id)\n } catch {\n /* best effort */\n }\n }, [])\n\n const setNavDisplay = useCallback((m: NavDisplayMode) => {\n setNavDisplayState(m)\n try {\n localStorage.setItem(NAV_DISPLAY_KEY, m)\n } catch {\n /* best effort */\n }\n }, [])\n\n const value = useMemo<ChromeState>(\n () => ({\n orgId,\n setOrgId,\n orgs: (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n navDisplay,\n setNavDisplay,\n }),\n [orgId, setOrgId, orgs, navDisplay, setNavDisplay],\n )\n\n return <ChromeStateContext.Provider value={value}>{children}</ChromeStateContext.Provider>\n}\n\nfunction AppDevNotes({\n storagePrefix,\n proxyBasePath,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath: string\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const adapter = useMemo(\n () =>\n createDevNotesClient({\n basePath: `${proxyBasePath}/devnotes`,\n // The proxy attaches the session's Bearer server-side.\n getAuthToken: async () => '',\n }),\n [proxyBasePath],\n )\n\n const user = useMemo(\n () => ({\n id: identity.userId,\n email: identity.email ?? '',\n fullName: identity.userName ?? undefined,\n }),\n [identity.userId, identity.email, identity.userName],\n )\n\n const config = useMemo<DevNotesConfig>(\n () => ({\n storagePrefix,\n role: identity.role.toLowerCase() === 'admin' ? 'admin' : 'reporter',\n disableAi: true,\n getPagePath: () => window.location.pathname,\n }),\n [storagePrefix, identity.role],\n )\n\n return (\n <DevNotesProvider adapter={adapter} user={user} config={config}>\n {children}\n </DevNotesProvider>\n )\n}\n\n/**\n * The app-chrome root. Wrap the authenticated frame once:\n *\n * <PolitogyAppChrome storagePrefix=\"forms\" identity={{userId, userName, email, role}}>\n * <ShellFrame …/>\n * </PolitogyAppChrome>\n */\nexport function PolitogyAppChrome({\n storagePrefix,\n proxyBasePath = '/api/chrome',\n fetchJson: fetchJsonOverride,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath?: string\n /**\n * Override the same-origin proxy fetcher for apps that talk to the chrome\n * API directly with their own auth (Contacts sends a client-side Bearer).\n * Paths stay relative ('orgs', 'me', …) — the override owns base + auth.\n */\n fetchJson?: NavChromeFetcher\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const proxyFetchJson = useMemo<NavChromeFetcher>(\n () =>\n async (path, init) => {\n const res = await fetch(`${proxyBasePath}/${path}`, {\n method: init?.method ?? 'GET',\n headers: init?.headers,\n body: init?.body,\n })\n if (!res.ok) throw new Error(`chrome ${path}: ${res.status}`)\n if (res.status === 204) return null\n const text = await res.text()\n return text ? JSON.parse(text) : null\n },\n [proxyBasePath],\n )\n const fetchJson = fetchJsonOverride ?? proxyFetchJson\n\n return (\n <NavChromeProvider fetchJson={fetchJson}>\n <ChromeStateProvider>\n <AppDevNotes\n storagePrefix={storagePrefix}\n proxyBasePath={proxyBasePath}\n identity={identity}\n >\n {children}\n </AppDevNotes>\n </ChromeStateProvider>\n </NavChromeProvider>\n )\n}\n\n/** The standard top-bar action cluster. The Alerts bell renders LAST so it\n * sits farthest right, immediately left of the My Account badge. */\nexport function ChromeTopBarActions() {\n const state = useChromeState()\n if (!state) return null\n return (\n <>\n <FuelAction orgId={state.orgId} />\n <NavDisplayAction value={state.navDisplay} onChange={state.setNavDisplay} />\n <TopBarWidgetSlot\n title=\"DevNotes\"\n description=\"Capture bugs and notes, filed straight to Forge.\"\n >\n <DevNotesMenu />\n </TopBarWidgetSlot>\n <SupportAction />\n <NotificationsAction orgId={state.orgId} />\n </>\n )\n}\n\n/** True when any core-org membership carries a super-admin tier. */\nexport function useIsSuperAdmin(): boolean {\n const state = useChromeState()\n return (state?.orgs ?? []).some((o) => /super/i.test(o.rawRole ?? ''))\n}\n\nconst FOOTER_LINKS: NavFooterLink[] = [\n { label: 'Privacy', href: `${CORE_BASE_URL}/privacy-policy`, external: true },\n { label: 'Terms', href: `${CORE_BASE_URL}/terms-and-conditions`, external: true },\n {\n label: 'Subscriptions',\n href: 'https://politogyvrm.com/subscription-cancellation-policy',\n external: true,\n },\n]\n\n/**\n * Sidebar footer: legal links for everyone; build metadata (env / commit /\n * version / date / author) ONLY for Super Administrators\n * (Reference/UI-Platform). Pass the app's build-time metadata in.\n */\nexport function useChromeFooter(meta: {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}): NavFooter {\n const isSuperAdmin = useIsSuperAdmin()\n return useMemo<NavFooter>(\n () => (isSuperAdmin ? { links: FOOTER_LINKS, ...meta } : { links: FOOTER_LINKS }),\n [isSuperAdmin, meta.envLabel, meta.version, meta.commit, meta.commitDate, meta.commitAuthor],\n )\n}\n\n/**\n * The My Account menu config — profile/org links into VRM core, real roles\n * from the user's core organizations, the signed-in account, and the shared\n * Light/System/Dark theme control (auth-derived, cross-app).\n */\nexport function useChromeUserMenu({\n userId,\n userName,\n email,\n}: {\n userId: string\n userName: string | null\n email: string | null\n}): NavUserMenu {\n const state = useChromeState()\n const theme = useThemePreference()\n const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null\n const orgSuffix = activeOrg ? `?org=${activeOrg.id.slice(-6)}` : ''\n return {\n // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).\n myProfileHref: `${CORE_BASE_URL}/my-profile`,\n organizationSettingsHref: `${CORE_BASE_URL}/organization-settings${orgSuffix}`,\n roles: (state?.orgs ?? [])\n .filter((o) => o.rawRole || o.role)\n .map((o) => ({ role: (o.rawRole ?? o.role) as string, orgName: o.name })),\n accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],\n addAccountHref: `${CORE_BASE_URL}/my-profile#accounts`,\n theme: { value: theme.value, onChange: theme.setValue },\n }\n}\n"]}
|
package/dist/app-chrome.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { NavFooter, NavOrgOption, NavDisplayMode, NavUserMenu } from './native.cjs';
|
|
3
|
+
import { NavChromeFetcher, NavFooter, NavOrgOption, NavDisplayMode, NavUserMenu } from './native.cjs';
|
|
4
4
|
import './topbarIconSlot-FunwEKO9.cjs';
|
|
5
5
|
import './theme-preference.cjs';
|
|
6
6
|
|
|
@@ -28,9 +28,15 @@ declare function useChromeState(): ChromeState | null;
|
|
|
28
28
|
* <ShellFrame …/>
|
|
29
29
|
* </PolitogyAppChrome>
|
|
30
30
|
*/
|
|
31
|
-
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, identity, children, }: {
|
|
31
|
+
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fetchJsonOverride, identity, children, }: {
|
|
32
32
|
storagePrefix: string;
|
|
33
33
|
proxyBasePath?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Override the same-origin proxy fetcher for apps that talk to the chrome
|
|
36
|
+
* API directly with their own auth (Contacts sends a client-side Bearer).
|
|
37
|
+
* Paths stay relative ('orgs', 'me', …) — the override owns base + auth.
|
|
38
|
+
*/
|
|
39
|
+
fetchJson?: NavChromeFetcher;
|
|
34
40
|
identity: ChromeIdentity;
|
|
35
41
|
children: ReactNode;
|
|
36
42
|
}): react_jsx_runtime.JSX.Element;
|
package/dist/app-chrome.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import { ReactNode } from 'react';
|
|
3
|
-
import { NavFooter, NavOrgOption, NavDisplayMode, NavUserMenu } from './native.js';
|
|
3
|
+
import { NavChromeFetcher, NavFooter, NavOrgOption, NavDisplayMode, NavUserMenu } from './native.js';
|
|
4
4
|
import './topbarIconSlot-FunwEKO9.js';
|
|
5
5
|
import './theme-preference.js';
|
|
6
6
|
|
|
@@ -28,9 +28,15 @@ declare function useChromeState(): ChromeState | null;
|
|
|
28
28
|
* <ShellFrame …/>
|
|
29
29
|
* </PolitogyAppChrome>
|
|
30
30
|
*/
|
|
31
|
-
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, identity, children, }: {
|
|
31
|
+
declare function PolitogyAppChrome({ storagePrefix, proxyBasePath, fetchJson: fetchJsonOverride, identity, children, }: {
|
|
32
32
|
storagePrefix: string;
|
|
33
33
|
proxyBasePath?: string;
|
|
34
|
+
/**
|
|
35
|
+
* Override the same-origin proxy fetcher for apps that talk to the chrome
|
|
36
|
+
* API directly with their own auth (Contacts sends a client-side Bearer).
|
|
37
|
+
* Paths stay relative ('orgs', 'me', …) — the override owns base + auth.
|
|
38
|
+
*/
|
|
39
|
+
fetchJson?: NavChromeFetcher;
|
|
34
40
|
identity: ChromeIdentity;
|
|
35
41
|
children: ReactNode;
|
|
36
42
|
}): react_jsx_runtime.JSX.Element;
|
package/dist/app-chrome.js
CHANGED
|
@@ -101,10 +101,11 @@ function AppDevNotes({
|
|
|
101
101
|
function PolitogyAppChrome({
|
|
102
102
|
storagePrefix,
|
|
103
103
|
proxyBasePath = "/api/chrome",
|
|
104
|
+
fetchJson: fetchJsonOverride,
|
|
104
105
|
identity,
|
|
105
106
|
children
|
|
106
107
|
}) {
|
|
107
|
-
const
|
|
108
|
+
const proxyFetchJson = useMemo(
|
|
108
109
|
() => async (path, init) => {
|
|
109
110
|
const res = await fetch(`${proxyBasePath}/${path}`, {
|
|
110
111
|
method: init?.method ?? "GET",
|
|
@@ -118,6 +119,7 @@ function PolitogyAppChrome({
|
|
|
118
119
|
},
|
|
119
120
|
[proxyBasePath]
|
|
120
121
|
);
|
|
122
|
+
const fetchJson = fetchJsonOverride ?? proxyFetchJson;
|
|
121
123
|
return /* @__PURE__ */ jsx(NavChromeProvider, { fetchJson, children: /* @__PURE__ */ jsx(ChromeStateProvider, { children: /* @__PURE__ */ jsx(
|
|
122
124
|
AppDevNotes,
|
|
123
125
|
{
|
package/dist/app-chrome.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/app-chrome/index.tsx"],"names":[],"mappings":"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","file":"app-chrome.js","sourcesContent":["// ---------------------------------------------------------------------------\n// App chrome wiring — the ONE shared implementation of the per-app glue that\n// previously lived as a copied ChromeWidgets.tsx in every Next.js feature app\n// (forms / surveys / polls / contacts). Copies drifted (org dropdown, badges);\n// this module makes that class of drift impossible: apps configure, never\n// re-implement (Reference/UI-Platform: consume via npm, never vendored).\n//\n// Provides:\n// <PolitogyAppChrome> — NavChromeProvider (same-origin proxy fetcher) +\n// chrome state (active core org, nav display) +\n// DevNotes provider, in one wrapper.\n// <ChromeTopBarActions> — the canonical top-bar cluster, in canonical order\n// (Fuel · Nav display · DevNotes · Support · Alerts\n// LAST, immediately left of My Account).\n// useChromeState / useChromeUserMenu / useIsSuperAdmin / useChromeFooter.\n//\n// The app still owns: its session (the /api/chrome proxy), page frames, build\n// metadata (env/commit/version), tab strips, and its own icons.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n NavChromeProvider,\n FuelAction,\n NotificationsAction,\n SupportAction,\n NavDisplayAction,\n TopBarWidgetSlot,\n useChromeOrgs,\n useThemePreference,\n type NavChromeFetcher,\n type NavDisplayMode,\n type NavOrgOption,\n type NavUserMenu,\n type NavFooter,\n type NavFooterLink,\n} from '../native/index'\nimport {\n DevNotesProvider,\n DevNotesMenu,\n createDevNotesClient,\n type DevNotesConfig,\n} from '@the-portland-company/devnotes'\n\nconst ORG_STORAGE_KEY = 'vrm.activeOrg'\nconst NAV_DISPLAY_KEY = 'vrm.navDisplay'\nconst CORE_BASE_URL = 'https://app.politogyvrm.com'\n\nexport type ChromeIdentity = {\n userId: string\n userName: string | null\n email: string | null\n /** The APP's own role string (any casing) — feeds DevNotes admin gating. */\n role: string\n}\n\ntype ChromeState = {\n orgId: string | null\n setOrgId: (id: string) => void\n orgs: (NavOrgOption & { rawRole?: string | null })[]\n navDisplay: NavDisplayMode\n setNavDisplay: (m: NavDisplayMode) => void\n}\n\nconst ChromeStateContext = createContext<ChromeState | null>(null)\n\nexport function useChromeState(): ChromeState | null {\n return useContext(ChromeStateContext)\n}\n\nfunction ChromeStateProvider({ children }: { children: ReactNode }) {\n const { orgs } = useChromeOrgs()\n const [orgId, setOrgIdState] = useState<string | null>(null)\n const [navDisplay, setNavDisplayState] = useState<NavDisplayMode>('both')\n\n // Boot: restore persisted choices.\n useEffect(() => {\n try {\n const storedOrg = localStorage.getItem(ORG_STORAGE_KEY)\n if (storedOrg) setOrgIdState(storedOrg)\n const storedNav = localStorage.getItem(NAV_DISPLAY_KEY)\n if (storedNav === 'menu' || storedNav === 'tabs' || storedNav === 'both') {\n setNavDisplayState(storedNav)\n }\n } catch {\n /* storage unavailable */\n }\n }, [])\n\n // Once orgs resolve: validate the stored org, default to the first.\n useEffect(() => {\n if (!orgs || orgs.length === 0) return\n setOrgIdState((prev) => (prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id))\n }, [orgs])\n\n const setOrgId = useCallback((id: string) => {\n setOrgIdState(id)\n try {\n localStorage.setItem(ORG_STORAGE_KEY, id)\n } catch {\n /* best effort */\n }\n }, [])\n\n const setNavDisplay = useCallback((m: NavDisplayMode) => {\n setNavDisplayState(m)\n try {\n localStorage.setItem(NAV_DISPLAY_KEY, m)\n } catch {\n /* best effort */\n }\n }, [])\n\n const value = useMemo<ChromeState>(\n () => ({\n orgId,\n setOrgId,\n orgs: (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n navDisplay,\n setNavDisplay,\n }),\n [orgId, setOrgId, orgs, navDisplay, setNavDisplay],\n )\n\n return <ChromeStateContext.Provider value={value}>{children}</ChromeStateContext.Provider>\n}\n\nfunction AppDevNotes({\n storagePrefix,\n proxyBasePath,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath: string\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const adapter = useMemo(\n () =>\n createDevNotesClient({\n basePath: `${proxyBasePath}/devnotes`,\n // The proxy attaches the session's Bearer server-side.\n getAuthToken: async () => '',\n }),\n [proxyBasePath],\n )\n\n const user = useMemo(\n () => ({\n id: identity.userId,\n email: identity.email ?? '',\n fullName: identity.userName ?? undefined,\n }),\n [identity.userId, identity.email, identity.userName],\n )\n\n const config = useMemo<DevNotesConfig>(\n () => ({\n storagePrefix,\n role: identity.role.toLowerCase() === 'admin' ? 'admin' : 'reporter',\n disableAi: true,\n getPagePath: () => window.location.pathname,\n }),\n [storagePrefix, identity.role],\n )\n\n return (\n <DevNotesProvider adapter={adapter} user={user} config={config}>\n {children}\n </DevNotesProvider>\n )\n}\n\n/**\n * The app-chrome root. Wrap the authenticated frame once:\n *\n * <PolitogyAppChrome storagePrefix=\"forms\" identity={{userId, userName, email, role}}>\n * <ShellFrame …/>\n * </PolitogyAppChrome>\n */\nexport function PolitogyAppChrome({\n storagePrefix,\n proxyBasePath = '/api/chrome',\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath?: string\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const fetchJson = useMemo<NavChromeFetcher>(\n () =>\n async (path, init) => {\n const res = await fetch(`${proxyBasePath}/${path}`, {\n method: init?.method ?? 'GET',\n headers: init?.headers,\n body: init?.body,\n })\n if (!res.ok) throw new Error(`chrome ${path}: ${res.status}`)\n if (res.status === 204) return null\n const text = await res.text()\n return text ? JSON.parse(text) : null\n },\n [proxyBasePath],\n )\n\n return (\n <NavChromeProvider fetchJson={fetchJson}>\n <ChromeStateProvider>\n <AppDevNotes\n storagePrefix={storagePrefix}\n proxyBasePath={proxyBasePath}\n identity={identity}\n >\n {children}\n </AppDevNotes>\n </ChromeStateProvider>\n </NavChromeProvider>\n )\n}\n\n/** The standard top-bar action cluster. The Alerts bell renders LAST so it\n * sits farthest right, immediately left of the My Account badge. */\nexport function ChromeTopBarActions() {\n const state = useChromeState()\n if (!state) return null\n return (\n <>\n <FuelAction orgId={state.orgId} />\n <NavDisplayAction value={state.navDisplay} onChange={state.setNavDisplay} />\n <TopBarWidgetSlot\n title=\"DevNotes\"\n description=\"Capture bugs and notes, filed straight to Forge.\"\n >\n <DevNotesMenu />\n </TopBarWidgetSlot>\n <SupportAction />\n <NotificationsAction orgId={state.orgId} />\n </>\n )\n}\n\n/** True when any core-org membership carries a super-admin tier. */\nexport function useIsSuperAdmin(): boolean {\n const state = useChromeState()\n return (state?.orgs ?? []).some((o) => /super/i.test(o.rawRole ?? ''))\n}\n\nconst FOOTER_LINKS: NavFooterLink[] = [\n { label: 'Privacy', href: `${CORE_BASE_URL}/privacy-policy`, external: true },\n { label: 'Terms', href: `${CORE_BASE_URL}/terms-and-conditions`, external: true },\n {\n label: 'Subscriptions',\n href: 'https://politogyvrm.com/subscription-cancellation-policy',\n external: true,\n },\n]\n\n/**\n * Sidebar footer: legal links for everyone; build metadata (env / commit /\n * version / date / author) ONLY for Super Administrators\n * (Reference/UI-Platform). Pass the app's build-time metadata in.\n */\nexport function useChromeFooter(meta: {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}): NavFooter {\n const isSuperAdmin = useIsSuperAdmin()\n return useMemo<NavFooter>(\n () => (isSuperAdmin ? { links: FOOTER_LINKS, ...meta } : { links: FOOTER_LINKS }),\n [isSuperAdmin, meta.envLabel, meta.version, meta.commit, meta.commitDate, meta.commitAuthor],\n )\n}\n\n/**\n * The My Account menu config — profile/org links into VRM core, real roles\n * from the user's core organizations, the signed-in account, and the shared\n * Light/System/Dark theme control (auth-derived, cross-app).\n */\nexport function useChromeUserMenu({\n userId,\n userName,\n email,\n}: {\n userId: string\n userName: string | null\n email: string | null\n}): NavUserMenu {\n const state = useChromeState()\n const theme = useThemePreference()\n const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null\n const orgSuffix = activeOrg ? `?org=${activeOrg.id.slice(-6)}` : ''\n return {\n // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).\n myProfileHref: `${CORE_BASE_URL}/my-profile`,\n organizationSettingsHref: `${CORE_BASE_URL}/organization-settings${orgSuffix}`,\n roles: (state?.orgs ?? [])\n .filter((o) => o.rawRole || o.role)\n .map((o) => ({ role: (o.rawRole ?? o.role) as string, orgName: o.name })),\n accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],\n addAccountHref: `${CORE_BASE_URL}/my-profile#accounts`,\n theme: { value: theme.value, onChange: theme.setValue },\n }\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/app-chrome/index.tsx"],"names":[],"mappings":"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","file":"app-chrome.js","sourcesContent":["// ---------------------------------------------------------------------------\n// App chrome wiring — the ONE shared implementation of the per-app glue that\n// previously lived as a copied ChromeWidgets.tsx in every Next.js feature app\n// (forms / surveys / polls / contacts). Copies drifted (org dropdown, badges);\n// this module makes that class of drift impossible: apps configure, never\n// re-implement (Reference/UI-Platform: consume via npm, never vendored).\n//\n// Provides:\n// <PolitogyAppChrome> — NavChromeProvider (same-origin proxy fetcher) +\n// chrome state (active core org, nav display) +\n// DevNotes provider, in one wrapper.\n// <ChromeTopBarActions> — the canonical top-bar cluster, in canonical order\n// (Fuel · Nav display · DevNotes · Support · Alerts\n// LAST, immediately left of My Account).\n// useChromeState / useChromeUserMenu / useIsSuperAdmin / useChromeFooter.\n//\n// The app still owns: its session (the /api/chrome proxy), page frames, build\n// metadata (env/commit/version), tab strips, and its own icons.\n// ---------------------------------------------------------------------------\n\n'use client'\n\nimport {\n createContext,\n useCallback,\n useContext,\n useEffect,\n useMemo,\n useState,\n type ReactNode,\n} from 'react'\nimport {\n NavChromeProvider,\n FuelAction,\n NotificationsAction,\n SupportAction,\n NavDisplayAction,\n TopBarWidgetSlot,\n useChromeOrgs,\n useThemePreference,\n type NavChromeFetcher,\n type NavDisplayMode,\n type NavOrgOption,\n type NavUserMenu,\n type NavFooter,\n type NavFooterLink,\n} from '../native/index'\nimport {\n DevNotesProvider,\n DevNotesMenu,\n createDevNotesClient,\n type DevNotesConfig,\n} from '@the-portland-company/devnotes'\n\nconst ORG_STORAGE_KEY = 'vrm.activeOrg'\nconst NAV_DISPLAY_KEY = 'vrm.navDisplay'\nconst CORE_BASE_URL = 'https://app.politogyvrm.com'\n\nexport type ChromeIdentity = {\n userId: string\n userName: string | null\n email: string | null\n /** The APP's own role string (any casing) — feeds DevNotes admin gating. */\n role: string\n}\n\ntype ChromeState = {\n orgId: string | null\n setOrgId: (id: string) => void\n orgs: (NavOrgOption & { rawRole?: string | null })[]\n navDisplay: NavDisplayMode\n setNavDisplay: (m: NavDisplayMode) => void\n}\n\nconst ChromeStateContext = createContext<ChromeState | null>(null)\n\nexport function useChromeState(): ChromeState | null {\n return useContext(ChromeStateContext)\n}\n\nfunction ChromeStateProvider({ children }: { children: ReactNode }) {\n const { orgs } = useChromeOrgs()\n const [orgId, setOrgIdState] = useState<string | null>(null)\n const [navDisplay, setNavDisplayState] = useState<NavDisplayMode>('both')\n\n // Boot: restore persisted choices.\n useEffect(() => {\n try {\n const storedOrg = localStorage.getItem(ORG_STORAGE_KEY)\n if (storedOrg) setOrgIdState(storedOrg)\n const storedNav = localStorage.getItem(NAV_DISPLAY_KEY)\n if (storedNav === 'menu' || storedNav === 'tabs' || storedNav === 'both') {\n setNavDisplayState(storedNav)\n }\n } catch {\n /* storage unavailable */\n }\n }, [])\n\n // Once orgs resolve: validate the stored org, default to the first.\n useEffect(() => {\n if (!orgs || orgs.length === 0) return\n setOrgIdState((prev) => (prev && orgs.some((o) => o.id === prev) ? prev : orgs[0].id))\n }, [orgs])\n\n const setOrgId = useCallback((id: string) => {\n setOrgIdState(id)\n try {\n localStorage.setItem(ORG_STORAGE_KEY, id)\n } catch {\n /* best effort */\n }\n }, [])\n\n const setNavDisplay = useCallback((m: NavDisplayMode) => {\n setNavDisplayState(m)\n try {\n localStorage.setItem(NAV_DISPLAY_KEY, m)\n } catch {\n /* best effort */\n }\n }, [])\n\n const value = useMemo<ChromeState>(\n () => ({\n orgId,\n setOrgId,\n orgs: (orgs ?? []).map((o) => ({\n id: o.id,\n name: o.name,\n logoUrl: o.logoUrl,\n brandColor: o.brandColor,\n role: o.role,\n rawRole: o.rawRole ?? null,\n })),\n navDisplay,\n setNavDisplay,\n }),\n [orgId, setOrgId, orgs, navDisplay, setNavDisplay],\n )\n\n return <ChromeStateContext.Provider value={value}>{children}</ChromeStateContext.Provider>\n}\n\nfunction AppDevNotes({\n storagePrefix,\n proxyBasePath,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath: string\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const adapter = useMemo(\n () =>\n createDevNotesClient({\n basePath: `${proxyBasePath}/devnotes`,\n // The proxy attaches the session's Bearer server-side.\n getAuthToken: async () => '',\n }),\n [proxyBasePath],\n )\n\n const user = useMemo(\n () => ({\n id: identity.userId,\n email: identity.email ?? '',\n fullName: identity.userName ?? undefined,\n }),\n [identity.userId, identity.email, identity.userName],\n )\n\n const config = useMemo<DevNotesConfig>(\n () => ({\n storagePrefix,\n role: identity.role.toLowerCase() === 'admin' ? 'admin' : 'reporter',\n disableAi: true,\n getPagePath: () => window.location.pathname,\n }),\n [storagePrefix, identity.role],\n )\n\n return (\n <DevNotesProvider adapter={adapter} user={user} config={config}>\n {children}\n </DevNotesProvider>\n )\n}\n\n/**\n * The app-chrome root. Wrap the authenticated frame once:\n *\n * <PolitogyAppChrome storagePrefix=\"forms\" identity={{userId, userName, email, role}}>\n * <ShellFrame …/>\n * </PolitogyAppChrome>\n */\nexport function PolitogyAppChrome({\n storagePrefix,\n proxyBasePath = '/api/chrome',\n fetchJson: fetchJsonOverride,\n identity,\n children,\n}: {\n storagePrefix: string\n proxyBasePath?: string\n /**\n * Override the same-origin proxy fetcher for apps that talk to the chrome\n * API directly with their own auth (Contacts sends a client-side Bearer).\n * Paths stay relative ('orgs', 'me', …) — the override owns base + auth.\n */\n fetchJson?: NavChromeFetcher\n identity: ChromeIdentity\n children: ReactNode\n}) {\n const proxyFetchJson = useMemo<NavChromeFetcher>(\n () =>\n async (path, init) => {\n const res = await fetch(`${proxyBasePath}/${path}`, {\n method: init?.method ?? 'GET',\n headers: init?.headers,\n body: init?.body,\n })\n if (!res.ok) throw new Error(`chrome ${path}: ${res.status}`)\n if (res.status === 204) return null\n const text = await res.text()\n return text ? JSON.parse(text) : null\n },\n [proxyBasePath],\n )\n const fetchJson = fetchJsonOverride ?? proxyFetchJson\n\n return (\n <NavChromeProvider fetchJson={fetchJson}>\n <ChromeStateProvider>\n <AppDevNotes\n storagePrefix={storagePrefix}\n proxyBasePath={proxyBasePath}\n identity={identity}\n >\n {children}\n </AppDevNotes>\n </ChromeStateProvider>\n </NavChromeProvider>\n )\n}\n\n/** The standard top-bar action cluster. The Alerts bell renders LAST so it\n * sits farthest right, immediately left of the My Account badge. */\nexport function ChromeTopBarActions() {\n const state = useChromeState()\n if (!state) return null\n return (\n <>\n <FuelAction orgId={state.orgId} />\n <NavDisplayAction value={state.navDisplay} onChange={state.setNavDisplay} />\n <TopBarWidgetSlot\n title=\"DevNotes\"\n description=\"Capture bugs and notes, filed straight to Forge.\"\n >\n <DevNotesMenu />\n </TopBarWidgetSlot>\n <SupportAction />\n <NotificationsAction orgId={state.orgId} />\n </>\n )\n}\n\n/** True when any core-org membership carries a super-admin tier. */\nexport function useIsSuperAdmin(): boolean {\n const state = useChromeState()\n return (state?.orgs ?? []).some((o) => /super/i.test(o.rawRole ?? ''))\n}\n\nconst FOOTER_LINKS: NavFooterLink[] = [\n { label: 'Privacy', href: `${CORE_BASE_URL}/privacy-policy`, external: true },\n { label: 'Terms', href: `${CORE_BASE_URL}/terms-and-conditions`, external: true },\n {\n label: 'Subscriptions',\n href: 'https://politogyvrm.com/subscription-cancellation-policy',\n external: true,\n },\n]\n\n/**\n * Sidebar footer: legal links for everyone; build metadata (env / commit /\n * version / date / author) ONLY for Super Administrators\n * (Reference/UI-Platform). Pass the app's build-time metadata in.\n */\nexport function useChromeFooter(meta: {\n envLabel?: string\n version?: string\n commit?: string\n commitDate?: string\n commitAuthor?: string\n}): NavFooter {\n const isSuperAdmin = useIsSuperAdmin()\n return useMemo<NavFooter>(\n () => (isSuperAdmin ? { links: FOOTER_LINKS, ...meta } : { links: FOOTER_LINKS }),\n [isSuperAdmin, meta.envLabel, meta.version, meta.commit, meta.commitDate, meta.commitAuthor],\n )\n}\n\n/**\n * The My Account menu config — profile/org links into VRM core, real roles\n * from the user's core organizations, the signed-in account, and the shared\n * Light/System/Dark theme control (auth-derived, cross-app).\n */\nexport function useChromeUserMenu({\n userId,\n userName,\n email,\n}: {\n userId: string\n userName: string | null\n email: string | null\n}): NavUserMenu {\n const state = useChromeState()\n const theme = useThemePreference()\n const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null\n const orgSuffix = activeOrg ? `?org=${activeOrg.id.slice(-6)}` : ''\n return {\n // My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).\n myProfileHref: `${CORE_BASE_URL}/my-profile`,\n organizationSettingsHref: `${CORE_BASE_URL}/organization-settings${orgSuffix}`,\n roles: (state?.orgs ?? [])\n .filter((o) => o.rawRole || o.role)\n .map((o) => ({ role: (o.rawRole ?? o.role) as string, orgName: o.name })),\n accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],\n addAccountHref: `${CORE_BASE_URL}/my-profile#accounts`,\n theme: { value: theme.value, onChange: theme.setValue },\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-portland-company/shell",
|
|
3
|
-
"version": "0.19.
|
|
3
|
+
"version": "0.19.1",
|
|
4
4
|
"description": "Shared chrome (header, sidebar, footer, theme, auth) for politogy apps. Drop into any Vite SPA to inherit the politogy look and signed-in user.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"private": false,
|