@the-portland-company/shell 0.14.2 → 0.14.3
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/chrome.css +20 -6
- package/dist/native.cjs +1 -1
- package/dist/native.cjs.map +1 -1
- package/dist/native.js +1 -1
- package/dist/native.js.map +1 -1
- package/package.json +1 -1
package/dist/chrome.css
CHANGED
|
@@ -251,6 +251,10 @@
|
|
|
251
251
|
--muted: var(--topbar-breadcrumb-color);
|
|
252
252
|
--panel: var(--topbar-bg);
|
|
253
253
|
--panel-elevated: var(--surface-1);
|
|
254
|
+
/* The left bar's own surface. Separate from --panel-elevated (which also
|
|
255
|
+
backs hover states and dropdowns) so dark can put the bars and the raised
|
|
256
|
+
surfaces on different steps of the neutral ramp. */
|
|
257
|
+
--nav-surface: var(--surface-1);
|
|
254
258
|
--line: var(--sidebar-border);
|
|
255
259
|
--shadow-soft: var(--shadow-lg);
|
|
256
260
|
}
|
|
@@ -274,11 +278,21 @@
|
|
|
274
278
|
--border: 217.2 32.6% 17.5%;
|
|
275
279
|
--input: 217.2 32.6% 17.5%;
|
|
276
280
|
--ring: 212.7 26.8% 83.9%;
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
281
|
+
/* Native chrome semantic layer — dark values.
|
|
282
|
+
Global Rules: dark chrome is NEUTRAL BLACK, never blue/navy/slate. These
|
|
283
|
+
were ShadCN slate (hsl(222.2 84% 4.9%) = #020817, hsl(217.2 32.6% 17.5%)
|
|
284
|
+
= #1E293B) — the exact palette the rule names as forbidden — which made
|
|
285
|
+
the top bar and left bar read as navy. The ramp below is the hue-free one
|
|
286
|
+
from Reference/Global-Rules: page #0A0A0A → bars #161616 → raised #1F1F1F
|
|
287
|
+
→ hover #2B2B2B → borders #333333, with #A3A3A3 muted / #E8E8E8 body text.
|
|
288
|
+
The ShadCN HSL channel tokens above stay as-is — they are the separate
|
|
289
|
+
darkMode group and are Brand-API-controlled. */
|
|
290
|
+
--background: #0A0A0A;
|
|
291
|
+
--foreground: #E8E8E8;
|
|
292
|
+
--muted: #A3A3A3;
|
|
293
|
+
--panel: #161616;
|
|
294
|
+
--nav-surface: #161616;
|
|
295
|
+
--panel-elevated: #1F1F1F;
|
|
296
|
+
--line: #333333;
|
|
283
297
|
--shadow-soft: 0 4px 16px rgba(0, 0, 0, 0.5);
|
|
284
298
|
}
|
package/dist/native.cjs
CHANGED
|
@@ -182,7 +182,7 @@ function NavSidebar({
|
|
|
182
182
|
setOpenGroup(activeGroupKey);
|
|
183
183
|
}, [activeGroupKey]);
|
|
184
184
|
const toggleGroup = (key) => setOpenGroup((prev) => prev === key ? null : key);
|
|
185
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--
|
|
185
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("aside", { className: "fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--nav-surface)] lg:flex", children: [
|
|
186
186
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
187
187
|
Link,
|
|
188
188
|
{
|
package/dist/native.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/lib/topbarIconSlot.ts","../src/lib/brandGlyphs.tsx","../src/native/standardNav.ts","../src/native/index.tsx"],"names":["useState","useEffect","FiBatteryCharging","FiBattery","FiZap","FiGrid","FiBell","FiAlertTriangle","FiAlertCircle","FiLifeBuoy","FiHelpCircle","FiMoon","FiSun","FiInfo","FiMail","FiMessageSquare","FiSettings","FiUser","jsx","useMemo","jsxs","Fragment"],"mappings":";;;;;;;AA6BO,SAAS,uBAAuB,IAAA,EAAqC;AAC1E,EAAA,MAAM,CAAC,IAAA,EAAM,OAAO,CAAA,GAAIA,eAAwB,IAAI,CAAA;AAEpD,EAAAC,eAAA,CAAU,MAAM;AACd,IAAA,IAAI,OAAO,WAAW,WAAA,EAAa;AAEnC,IAAA,MAAM,OAAO,MAAM;AACjB,MAAA,MAAM,GAAA,GAAM,MAAA,CACT,gBAAA,CAAiB,QAAA,CAAS,eAAe,CAAA,CACzC,gBAAA,CAAiB,CAAA,cAAA,EAAiB,IAAI,EAAE,CAAA,CACxC,IAAA,EAAK,CAEL,OAAA,CAAQ,gBAAgB,EAAE,CAAA;AAC7B,MAAA,OAAA,CAAQ,GAAA,CAAI,MAAA,GAAS,CAAA,GAAI,GAAA,GAAM,IAAI,CAAA;AAAA,IACrC,CAAA;AAEA,IAAA,IAAA,EAAK;AAEL,IAAA,MAAM,QAAA,GAAW,IAAI,gBAAA,CAAiB,IAAI,CAAA;AAC1C,IAAA,QAAA,CAAS,OAAA,CAAQ,SAAS,IAAA,EAAM,EAAE,WAAW,IAAA,EAAM,OAAA,EAAS,MAAM,CAAA;AAClE,IAAA,OAAO,MAAM,SAAS,UAAA,EAAW;AAAA,EACnC,CAAA,EAAG,CAAC,IAAI,CAAC,CAAA;AAET,EAAA,OAAO,IAAA;AACT;ACnBA,IAAM,MAAA,GAAyC;AAAA;AAAA;AAAA,EAG7C,kBAAA,EAAoBC,oBAAA;AAAA,EACpB,OAAA,EAASC,YAAA;AAAA,EACT,IAAA,EAAMD,oBAAA;AAAA,EACN,IAAA,EAAME,QAAA;AAAA,EACN,GAAA,EAAKA,QAAA;AAAA,EACL,IAAA,EAAMC,SAAA;AAAA,EACN,IAAA,EAAMA,SAAA;AAAA,EACN,IAAA,EAAMC,SAAA;AAAA,EACN,YAAA,EAAcA,SAAA;AAAA,EACd,gBAAA,EAAkBC,kBAAA;AAAA,EAClB,KAAA,EAAOA,kBAAA;AAAA,EACP,cAAA,EAAgBC,gBAAA;AAAA,EAChB,WAAA,EAAaC,aAAA;AAAA,EACb,WAAA,EAAaA,aAAA;AAAA,EACb,OAAA,EAASA,aAAA;AAAA,EACT,aAAA,EAAeC,eAAA;AAAA,EACf,IAAA,EAAMC,SAAA;AAAA,EACN,GAAA,EAAKC,QAAA;AAAA,EACL,IAAA,EAAMC,SAAA;AAAA,EACN,IAAA,EAAMC,SAAA;AAAA,EACN,gBAAA,EAAkBC,kBAAA;AAAA,EAClB,QAAA,EAAUC,aAAA;AAAA,EACV,IAAA,EAAMC;AACR,CAAA;AAOO,SAAS,kBAAkB,IAAA,EAAwD;AACxF,EAAA,IAAI,CAAC,MAAM,OAAO,IAAA;AAClB,EAAA,OAAO,OAAO,IAAA,CAAK,IAAA,EAAK,CAAE,WAAA,EAAa,CAAA,IAAK,IAAA;AAC9C;;;ACVA,IAAM,yBAAA,GAAwC;AAAA,EAC5C,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,MAAA,EAAQ,MAAM,kCAAA,EAAmC;AAAA,EAC7E,EAAE,KAAA,EAAO,cAAA,EAAgB,IAAA,EAAM,MAAA,EAAQ,MAAM,4BAAA,EAA6B;AAAA,EAC1E,EAAE,KAAA,EAAO,QAAA,EAAU,IAAA,EAAM,OAAA,EAAS,MAAM,+BAAA,EAAgC;AAAA,EACxE,EAAE,KAAA,EAAO,QAAA,EAAU,IAAA,EAAM,QAAA,EAAU,MAAM,+BAAA,EAAgC;AAAA,EACzE,EAAE,KAAA,EAAO,gBAAA,EAAkB,IAAA,EAAM,UAAA,EAAY,MAAM,uCAAA,EAAwC;AAAA,EAC3F,EAAE,KAAA,EAAO,aAAA,EAAe,IAAA,EAAM,QAAA,EAAU,MAAM,oCAAA;AAChD,CAAA;AAEA,IAAM,cAAA,GAA6B;AAAA,EACjC,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,MAAA,EAAQ,MAAM,+BAAA,EAAgC;AAAA,EAC1E,EAAE,KAAA,EAAO,eAAA,EAAiB,IAAA,EAAM,MAAA,EAAQ,MAAM,qCAAA,EAAsC;AAAA,EACpF,EAAE,KAAA,EAAO,oBAAA,EAAsB,IAAA,EAAM,MAAA,EAAQ,MAAM,2BAAA,EAA4B;AAAA,EAC/E,EAAE,KAAA,EAAO,YAAA,EAAc,IAAA,EAAM,MAAA,EAAQ,MAAM,6BAAA,EAA8B;AAAA,EACzE,EAAE,KAAA,EAAO,iBAAA,EAAmB,IAAA,EAAM,OAAA,EAAS,MAAM,uCAAA,EAAwC;AAAA,EACzF,EAAE,KAAA,EAAO,YAAA,EAAc,IAAA,EAAM,UAAA,EAAY,MAAM,gCAAA;AACjD,CAAA;AAEA,IAAM,YAAA,GAA2B;AAAA,EAC/B,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,MAAA,EAAQ,MAAM,uCAAA,EAAwC;AAAA,EAClF,EAAE,KAAA,EAAO,gBAAA,EAAkB,IAAA,EAAM,MAAA,EAAQ,MAAM,8CAAA,EAA+C;AAAA,EAC9F,EAAE,KAAA,EAAO,eAAA,EAAiB,IAAA,EAAM,eAAA,EAAiB,MAAM,2CAAA;AACzD,CAAA;AAEA,IAAM,YAAA,GAA2B;AAAA,EAC/B,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,MAAA,EAAQ,MAAM,sCAAA,EAAuC;AAAA,EACjF,EAAE,KAAA,EAAO,eAAA,EAAiB,IAAA,EAAM,MAAA,EAAQ,MAAM,2CAAA,EAA4C;AAAA,EAC1F,EAAE,KAAA,EAAO,aAAA,EAAe,IAAA,EAAM,UAAA,EAAY,MAAM,2CAAA;AAClD,CAAA;AAEA,IAAM,cAAA,GAA6B;AAAA,EACjC,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,MAAA,EAAQ,MAAM,qBAAA,EAAsB;AAAA,EAChE,EAAE,KAAA,EAAO,eAAA,EAAiB,IAAA,EAAM,MAAA,EAAQ,MAAM,qCAAA,EAAsC;AAAA,EACpF,EAAE,KAAA,EAAO,aAAA,EAAe,IAAA,EAAM,UAAA,EAAY,MAAM,iCAAA;AAClD,CAAA;AAOO,SAAS,oBAAoB,IAAA,EAAqC;AACvE,EAAA,MAAM,IAAA,GAAO,IAAA,CAAK,WAAA,CAAY,OAAA,CAAQ,QAAQ,EAAE,CAAA;AAChD,EAAA,MAAM,GAAA,GAAM,CAAC,IAAA,KAAyB,CAAA,EAAG,IAAI,CAAA,EAAG,IAAA,CAAK,UAAA,CAAW,GAAG,CAAA,GAAI,IAAA,GAAO,CAAA,CAAA,EAAI,IAAI,CAAA,CAAE,CAAA,CAAA;AACxF,EAAA,MAAM,IAAA,GAAO,CAAC,GAAA,KAAiD,IAAA,CAAK,QAAQ,GAAG,CAAA;AAC/E,EAAA,MAAM,MAAA,GAAS,CAAC,QAAA,KACd,QAAA,CAAS,IAAI,CAAC,CAAA,MAAO,EAAE,KAAA,EAAO,CAAA,CAAE,OAAO,IAAA,EAAM,IAAA,CAAK,EAAE,IAAI,CAAA,EAAG,MAAM,GAAA,CAAI,CAAA,CAAE,IAAI,CAAA,EAAE,CAAE,CAAA;AAEjF,EAAA,MAAM,QAAA,GAAoB,KAAK,YAAA,GAC3B;AAAA,IACE,KAAA,EAAO,UAAA;AAAA,IACP,IAAA,EAAM,KAAK,OAAO,CAAA;AAAA,IAClB,IAAA,EAAM,KAAK,YAAA,CAAa,IAAA;AAAA,IACxB,QAAA,EAAU,KAAK,YAAA,CAAa;AAAA,GAC9B,GACA;AAAA,IACE,KAAA,EAAO,UAAA;AAAA,IACP,IAAA,EAAM,KAAK,OAAO,CAAA;AAAA,IAClB,IAAA,EAAM,IAAI,kCAAkC,CAAA;AAAA,IAC5C,QAAA,EAAU,OAAO,yBAAyB;AAAA,GAC5C;AAEJ,EAAA,MAAM,KAAA,GAAmB;AAAA,IACvB,EAAE,KAAA,EAAO,WAAA,EAAa,IAAA,EAAM,IAAA,CAAK,MAAM,CAAA,EAAG,IAAA,EAAM,GAAA,CAAI,yBAAyB,CAAA,EAAE;AAAA,IAC/E,QAAA;AAAA,IACA;AAAA,MACE,KAAA,EAAO,iBAAA;AAAA,MACP,IAAA,EAAM,KAAK,MAAM,CAAA;AAAA,MACjB,IAAA,EAAM,IAAI,+BAA+B,CAAA;AAAA,MACzC,QAAA,EAAU,OAAO,cAAc;AAAA,KACjC;AAAA,IACA;AAAA,MACE,KAAA,EAAO,eAAA;AAAA,MACP,IAAA,EAAM,KAAK,eAAe,CAAA;AAAA,MAC1B,IAAA,EAAM,IAAI,uCAAuC,CAAA;AAAA,MACjD,QAAA,EAAU,OAAO,YAAY;AAAA,KAC/B;AAAA;AAAA,IAEA,EAAE,KAAA,EAAO,iBAAA,EAAmB,IAAA,EAAM,IAAA,CAAK,QAAQ,CAAA,EAAG,QAAA,EAAU,MAAA,CAAO,YAAY,CAAA,EAAE;AAAA,IACjF,EAAE,KAAA,EAAO,iBAAA,EAAmB,IAAA,EAAM,IAAA,CAAK,UAAU,CAAA,EAAG,QAAA,EAAU,MAAA,CAAO,cAAc,CAAA;AAAE,GACvF;AAEA,EAAA,IAAI,KAAK,WAAA,EAAa;AACpB,IAAA,KAAA,CAAM,IAAA,CAAK;AAAA,MACT,KAAA,EAAO,SAAA;AAAA,MACP,IAAA,EAAM,KAAK,UAAU,CAAA;AAAA,MACrB,IAAA,EAAM,KAAK,WAAA,CAAY,IAAA;AAAA,MACvB,OAAA,EAAS,KAAK,WAAA,CAAY;AAAA,KAC3B,CAAA;AAAA,EACH;AAEA,EAAA,OAAO,KAAA;AACT;AC1EA,IAAM,QAAA,GAAW,CAAC,CAAA,KAChB,CAAA,IAAK,kCAAA,CAAmC,KAAK,CAAA,CAAE,IAAA,EAAM,CAAA,GAAI,CAAA,GAAI,GAAA;AAE/D,IAAM,cAAgC,CAAC,EAAE,IAAA,EAAM,QAAA,EAAU,GAAG,IAAA,EAAK,qBAC/DC,cAAA,CAAC,GAAA,EAAA,EAAE,MAAM,QAAA,CAAS,IAAI,CAAA,EAAI,GAAG,MAC1B,QAAA,EACH,CAAA;AAIK,SAAS,eAAA,CAAgB,UAAkB,IAAA,EAAuB;AACvE,EAAA,IAAI,IAAA,KAAS,GAAA,EAAK,OAAO,QAAA,KAAa,GAAA;AACtC,EAAA,OAAO,aAAa,IAAA,IAAQ,QAAA,CAAS,UAAA,CAAW,CAAA,EAAG,IAAI,CAAA,CAAA,CAAG,CAAA;AAC5D;AAOA,SAAS,UAAA,CAAW,MAAe,KAAA,EAAuB;AACxD,EAAA,OAAO,KAAK,IAAA,IAAQ,CAAA,UAAA,EAAa,KAAK,CAAA,CAAA,EAAI,KAAK,KAAK,CAAA,CAAA;AACtD;AAGA,SAAS,cAAA,CACP,IAAA,EACA,QAAA,EACA,QAAA,EACS;AACT,EAAA,OAAA,CAAQ,IAAA,CAAK,QAAA,IAAY,EAAC,EAAG,IAAA;AAAA,IAAK,CAAC,UACjC,KAAA,CAAM,IAAA,GAAO,SAAS,QAAA,EAAU,KAAA,CAAM,IAAI,CAAA,GAAI;AAAA,GAChD;AACF;AAMO,SAAS,eAAe,KAAA,EAAuB;AACpD,EAAA,MAAM,CAAA,GAAI,MAAM,WAAA,EAAY;AAC5B,EAAA,IAAI,CAAA,KAAM,gBAAgB,CAAA,KAAM,MAAA;AAC9B,IAAA,OAAO,6BAAA;AACT,EAAA,IAAI,CAAA,KAAM,aAAa,CAAA,KAAM,OAAA;AAC3B,IAAA,OAAO,6BAAA;AACT,EAAA,IAAI,CAAA,KAAM,OAAA,IAAW,CAAA,KAAM,aAAA,IAAiB,CAAA,KAAM,KAAA;AAChD,IAAA,OAAO,6BAAA;AACT,EAAA,OAAO,4CAAA;AACT;AAiEA,IAAM,gBAAA,GAAmB,uBAAA;AAElB,SAAS,UAAA,CAAW;AAAA,EACzB,QAAA;AAAA,EACA,KAAA;AAAA,EACA,GAAA;AAAA,EACA,GAAA;AAAA,EACA,IAAA;AAAA,EACA,MAAA;AAAA,EACA;AACF,CAAA,EAAoB;AAClB,EAAA,MAAM,OAAO,aAAA,IAAiB,WAAA;AAC9B,EAAA,MAAM,QAAA,GAAW,IAAI,QAAA,IAAY,eAAA;AACjC,EAAA,MAAM,WAAW,IAAA,EAAM,IAAA;AACvB,EAAA,MAAM,KAAA,GAAQ,KAAK,UAAA,IAAc,gBAAA;AAOjC,EAAA,MAAM,cAAA,GAAiBC,cAAQ,MAAM;AACnC,IAAA,KAAA,IAAS,IAAI,CAAA,EAAG,CAAA,GAAI,GAAA,CAAI,KAAA,CAAM,QAAQ,CAAA,EAAA,EAAK;AACzC,MAAA,MAAM,IAAA,GAAO,GAAA,CAAI,KAAA,CAAM,CAAC,CAAA;AACxB,MAAA,IAAI,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,QAAA,CAAS,MAAA,GAAS,KAAK,cAAA,CAAe,IAAA,EAAM,QAAA,EAAU,QAAQ,CAAA,EAAG;AACzF,QAAA,OAAO,UAAA,CAAW,MAAM,CAAC,CAAA;AAAA,MAC3B;AAAA,IACF;AACA,IAAA,OAAO,IAAA;AAAA,EACT,GAAG,CAAC,GAAA,CAAI,KAAA,EAAO,QAAA,EAAU,QAAQ,CAAC,CAAA;AAMlC,EAAA,MAAM,CAAC,SAAA,EAAW,YAAY,CAAA,GAAInB,eAAwB,cAAc,CAAA;AACxE,EAAAC,gBAAU,MAAM;AACd,IAAA,YAAA,CAAa,cAAc,CAAA;AAAA,EAC7B,CAAA,EAAG,CAAC,cAAc,CAAC,CAAA;AACnB,EAAA,MAAM,WAAA,GAAc,CAAC,GAAA,KACnB,YAAA,CAAa,CAAC,IAAA,KAAU,IAAA,KAAS,GAAA,GAAM,IAAA,GAAO,GAAI,CAAA;AAEpD,EAAA,uBACEmB,eAAA,CAAC,OAAA,EAAA,EAAM,SAAA,EAAU,oIAAA,EAEf,QAAA,EAAA;AAAA,oBAAAF,cAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,MAAM,QAAA,IAAY,GAAA;AAAA,QACxB,SAAA,EAAU,uDAAA;AAAA,QAET,gBAAM,OAAA,mBACLA,cAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,KAAK,KAAA,CAAM,OAAA;AAAA,YACX,GAAA,EAAK,KAAA,CAAM,OAAA,IAAW,KAAA,CAAM,KAAA;AAAA,YAC5B,SAAA,EAAW,KAAA;AAAA,YACX,SAAA,EAAU;AAAA;AAAA,4BAGZE,eAAA,CAAAC,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,0BAAAH,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gIAAA,EACb,QAAA,EAAA,KAAA,CAAM,UAAA,EACT,CAAA;AAAA,0BACAE,eAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,6BAAA,EACd,QAAA,EAAA;AAAA,4BAAAF,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,gFAAA,EACb,QAAA,EAAA,KAAA,CAAM,KAAA,EACT,CAAA;AAAA,YACC,KAAA,CAAM,2BACLA,cAAA,CAAC,MAAA,EAAA,EAAK,WAAU,iFAAA,EACb,QAAA,EAAA,KAAA,CAAM,UACT,CAAA,GACE;AAAA,WAAA,EACN;AAAA,SAAA,EACF;AAAA;AAAA,KAEJ;AAAA,oBAGAE,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gDAAA,EAEZ,QAAA,EAAA;AAAA,MAAA,GAAA,mBACCA,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EACb,QAAA,EAAA;AAAA,wBAAAA,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,6CAAA,EACb,QAAA,EAAA;AAAA,0BAAAF,cAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,iFAAA,EAAkF,QAAA,EAAA,cAAA,EAE/F,CAAA;AAAA,UACC,IAAI,EAAA,mBAAKA,cAAA,CAAC,mBAAgB,EAAA,EAAI,GAAA,CAAI,IAAI,CAAA,GAAK;AAAA,SAAA,EAC9C,CAAA;AAAA,wBACAE,eAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,SAAS,GAAA,CAAI,OAAA;AAAA,YACb,KAAA,EAAO,EAAE,eAAA,EAAiB,KAAA,EAAM;AAAA,YAChC,SAAA,EAAU,kIAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAAA,eAAA,CAAC,MAAA,EAAA,EAAK,WAAU,mCAAA,EACd,QAAA,EAAA;AAAA,gCAAAF,cAAA,CAAC,MAAA,EAAA,EAAK,WAAU,6HAAA,EACb,QAAA,EAAA,GAAA,CAAI,0BACHA,cAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,GAAA,CAAI,OAAA,EAAS,GAAA,EAAI,IAAG,SAAA,EAAU,4BAAA,EAA6B,CAAA,GAAA,CAEpE,GAAA,CAAI,IAAA,IAAQ,KAAA,EAAO,MAAM,CAAA,EAAG,CAAC,CAAA,CAAE,WAAA,EAAY,EAEhD,CAAA;AAAA,+CACC,MAAA,EAAA,EAAK,SAAA,EAAU,gCAAA,EACb,QAAA,EAAA,GAAA,CAAI,QAAQ,kBAAA,EACf;AAAA,eAAA,EACF,CAAA;AAAA,6CACC,WAAA,EAAA,EAAY;AAAA;AAAA;AAAA;AACf,OAAA,EACF,CAAA,GACE,IAAA;AAAA,MAGH,IAAA,mBACCA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,MAAA,EACb,QAAA,kBAAAE,eAAA;AAAA,QAAC,QAAA;AAAA,QAAA;AAAA,UACC,IAAA,EAAK,QAAA;AAAA,UACL,SAAA,EAAU,6HAAA;AAAA,UAEV,QAAA,EAAA;AAAA,4BAAAA,eAAA,CAAC,MAAA,EAAA,EAAK,WAAU,2BAAA,EACb,QAAA,EAAA;AAAA,cAAA,QAAA,kCAAY,QAAA,EAAA,EAAS,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,YAAW,CAAA,GAAK,IAAA;AAAA,8BAC1DF,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,0CAAA,EAA4C,eAAK,KAAA,EAAM;AAAA,aAAA,EACzE,CAAA;AAAA,2CACC,WAAA,EAAA,EAAY;AAAA;AAAA;AAAA,SAEjB,CAAA,GACE,IAAA;AAAA,sBAGJE,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,qBAAA,EACZ,QAAA,EAAA;AAAA,QAAA,GAAA,CAAI,6BACHF,cAAA,CAAC,GAAA,EAAA,EAAE,WAAU,2FAAA,EACV,QAAA,EAAA,GAAA,CAAI,YACP,CAAA,GACE,IAAA;AAAA,QACH,GAAA,CAAI,KAAA,CAAM,GAAA,CAAI,CAAC,MAAM,GAAA,KAAQ;AAE5B,UAAA,IAAI,IAAA,CAAK,QAAA,IAAY,IAAA,CAAK,QAAA,CAAS,SAAS,CAAA,EAAG;AAC7C,YAAA,MAAM,GAAA,GAAM,UAAA,CAAW,IAAA,EAAM,GAAG,CAAA;AAChC,YAAA,MAAM,aAAa,IAAA,CAAK,IAAA,GAAO,SAAS,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA,GAAI,KAAA;AAC/D,YAAA,MAAM,YAAA,GAAe,UAAA,IAAc,cAAA,CAAe,IAAA,EAAM,UAAU,QAAQ,CAAA;AAC1E,YAAA,uBACEA,cAAA;AAAA,cAAC,QAAA;AAAA,cAAA;AAAA,gBAEC,IAAA;AAAA,gBACA,MAAA,EAAQ,YAAA;AAAA,gBACR,MAAM,SAAA,KAAc,GAAA;AAAA,gBACpB,QAAA,EAAU,MAAM,WAAA,CAAY,GAAG,CAAA;AAAA,gBAC/B,QAAA;AAAA,gBACA,QAAA;AAAA,gBACA;AAAA,eAAA;AAAA,cAPK;AAAA,aAQP;AAAA,UAEJ;AACA,UAAA,MAAM,SAAS,IAAA,CAAK,IAAA,GAAO,SAAS,QAAA,EAAU,IAAA,CAAK,IAAI,CAAA,GAAI,KAAA;AAC3D,UAAA,uBACEA,cAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cAEC,IAAA;AAAA,cACA,MAAA;AAAA,cACA;AAAA,aAAA;AAAA,YAHK,KAAK,IAAA,IAAQ,CAAA,IAAA,EAAO,GAAG,CAAA,CAAA,EAAI,KAAK,KAAK,CAAA;AAAA,WAI5C;AAAA,QAEJ,CAAC;AAAA,OAAA,EACH;AAAA,KAAA,EACF,CAAA;AAAA,IAGC,MAAA,mBACCE,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6DAAA,EACZ,QAAA,EAAA;AAAA,MAAA,MAAA,CAAO,SAAS,MAAA,CAAO,KAAA,CAAM,SAAS,CAAA,mBACrCF,cAAA,CAAC,SAAI,SAAA,EAAU,6CAAA,EACZ,QAAA,EAAA,MAAA,CAAO,KAAA,CAAM,IAAI,CAAC,CAAA,EAAG,wBACpBE,eAAA,CAAC,MAAA,EAAA,EAAmB,WAAU,kCAAA,EAC3B,QAAA,EAAA;AAAA,QAAA,GAAA,GAAM,oBAAIF,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,eAAC,CAAA,GAAU,IAAA;AAAA,wBAClEA,cAAA;AAAA,UAAC,GAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAM,QAAA,CAAS,CAAA,CAAE,IAAI,CAAA;AAAA,YACrB,SAAA,EAAU,gEAAA;AAAA,YAET,QAAA,EAAA,CAAA,CAAE;AAAA;AAAA;AACL,OAAA,EAAA,EAPS,CAAA,CAAE,KAQb,CACD,CAAA,EACH,CAAA,GACE,IAAA;AAAA,sBACJE,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0HAAA,EAEb,QAAA,EAAA;AAAA,wBAAAA,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,2BAAA,EACb,QAAA,EAAA;AAAA,0BAAAF,cAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,SAAA,EAAW;AAAA,gBACT,oDAAA;AAAA,gBACA,cAAA,CAAe,OAAO,QAAQ;AAAA,eAChC,CAAE,KAAK,GAAG,CAAA;AAAA,cAET,QAAA,EAAA,MAAA,CAAO;AAAA;AAAA,WACV;AAAA,0BACAA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,yCAC5C,MAAA,EAAA,EAAM,QAAA,EAAA,MAAA,CAAO,MAAA,CAAO,KAAA,CAAM,EAAE,CAAA,EAAE,CAAA;AAAA,0BAC/BA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,0CAC5C,MAAA,EAAA,EAAK,QAAA,EAAA;AAAA,YAAA,GAAA;AAAA,YAAE,MAAA,CAAO;AAAA,WAAA,EAAQ;AAAA,SAAA,EACzB,CAAA;AAAA,QAEC,OAAO,UAAA,IAAc,MAAA,CAAO,+BAC3BE,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,2BAAA,EACb,QAAA,EAAA;AAAA,0BAAAF,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,UAC5C,MAAA,CAAO,UAAA,mBACNA,cAAA,CAAC,MAAA,EAAA,EACE,QAAA,EAAA,IAAI,KAAK,MAAA,CAAO,UAAU,CAAA,CAAE,kBAAA,CAAmB,MAAA,EAAW;AAAA,YACzD,KAAA,EAAO,OAAA;AAAA,YACP,GAAA,EAAK;AAAA,WACN,GACH,CAAA,GACE,IAAA;AAAA,0BACJA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,QAAA,EAAA,GAAA,EAAC,CAAA;AAAA,UAC5C,MAAA,CAAO,YAAA,mBACNA,cAAA,CAAC,MAAA,EAAA,EAAM,QAAA,EAAA,MAAA,CAAO,YAAA,CAAa,KAAA,CAAM,KAAK,CAAA,CAAE,CAAC,CAAA,EAAE,CAAA,GACzC,IAAA;AAAA,0BACJA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,2BAAA,EAA4B,QAAA,EAAA,GAAA,EAAC;AAAA,SAAA,EAC/C,CAAA,GACE;AAAA,OAAA,EACN;AAAA,KAAA,EACF,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;AAIA,SAAS,WAAA,CAAY,EAAE,SAAA,EAAU,GAA4B,EAAC,EAAG;AAC/D,EAAA,uBACEA,cAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAA;AAAA,MACP,MAAA,EAAQ,EAAA;AAAA,MACR,OAAA,EAAQ,WAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,MAAA,EAAO,cAAA;AAAA,MACP,WAAA,EAAa,CAAA;AAAA,MACb,aAAA,EAAc,OAAA;AAAA,MACd,cAAA,EAAe,OAAA;AAAA,MACf,WAAW,SAAA,IAAa,qBAAA;AAAA,MACxB,aAAA,EAAY,MAAA;AAAA,MAEZ,QAAA,kBAAAA,cAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAE,cAAA,EAAe;AAAA;AAAA,GACzB;AAEJ;AAWA,IAAM,kBAAA,GAAqB,gDAAA;AAE3B,SAAS,MAAA,CAAO;AAAA,EACd,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,OAAA,GAAU;AACZ,CAAA,EAKG;AACD,EAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,EAAA,MAAM,QAAQ,OAAA,KAAY,KAAA;AAC1B,EAAA,MAAM,aAAA,GAAgB,QAClB,+EAAA,GACA,uDAAA;AACJ,EAAA,MAAM,cAAA,GAAiB;AAAA,IACrB,4DAAA;AAAA,IACA,SAAS,aAAA,GAAgB;AAAA,GAC3B,CAAE,KAAK,GAAG,CAAA;AAEV,EAAA,MAAM,UAAA,GAAa,QAAQ,yBAAA,GAA4B,mBAAA;AACvD,EAAA,MAAM,QAAA,GAAW,QAAQ,EAAA,GAAK,EAAA;AAG9B,EAAA,MAAM,SAAA,GAAY,MAAA,IAAU,CAAC,KAAA,GAAQ,YAAA,GAAe,cAAA;AAEpD,EAAA,MAAM,wBACJE,eAAA,CAAAC,mBAAA,EAAA,EACG,QAAA,EAAA;AAAA,IAAA,CAAC,MAAA,mBACAH,cAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,aAAA,EAAY,MAAA;AAAA,QACZ,SAAA,EAAU,sGAAA;AAAA,QACV,KAAA,EAAO,EAAE,UAAA,EAAY,kBAAA;AAAmB;AAAA,KAC1C,GACE,IAAA;AAAA,oBACJE,eAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAW,CAAA,oDAAA,EAAuD,UAAU,CAAA,CAAA,EAC/E,QAAA,EAAA;AAAA,MAAA,IAAA,kCAAQ,IAAA,EAAA,EAAK,IAAA,EAAM,QAAA,EAAU,SAAA,EAAW,WAAW,CAAA,GAAK,IAAA;AAAA,MACxD,IAAA,CAAK;AAAA,KAAA,EACR;AAAA,GAAA,EACF,CAAA;AAGF,EAAA,IAAI,IAAA,CAAK,OAAA,IAAW,CAAC,IAAA,CAAK,IAAA,EAAM;AAC9B,IAAA,uBACEF,cAAA,CAAC,QAAA,EAAA,EAAO,IAAA,EAAK,QAAA,EAAS,OAAA,EAAS,IAAA,CAAK,OAAA,EAAS,SAAA,EAAW,CAAA,iBAAA,EAAoB,cAAc,CAAA,CAAA,EACvF,QAAA,EAAA,KAAA,EACH,CAAA;AAAA,EAEJ;AAEA,EAAA,uBACEA,cAAA;AAAA,IAAC,IAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAM,KAAK,IAAA,IAAQ,GAAA;AAAA,MACnB,cAAA,EAAc,SAAS,MAAA,GAAS,MAAA;AAAA,MAChC,SAAA,EAAW,cAAA;AAAA,MAEV,QAAA,EAAA;AAAA;AAAA,GACH;AAEJ;AAeA,SAAS,QAAA,CAAS;AAAA,EAChB,IAAA;AAAA,EACA,MAAA;AAAA,EACA,IAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA,QAAA;AAAA,EACA;AACF,CAAA,EAQG;AACD,EAAA,MAAM,OAAO,IAAA,CAAK,IAAA;AAClB,EAAA,MAAM,aAAA,GAAgB;AAAA,IACpB,kEAAA;AAAA,IACA,OAAO,cAAA,GAAiB,YAAA;AAAA,IACxB,MAAA,GACI,uDAAA,GACA,IAAA,GACE,wDAAA,GACA;AAAA,GACR,CAAE,KAAK,GAAG,CAAA;AAEV,EAAA,uCACG,KAAA,EAAA,EACC,QAAA,EAAA;AAAA,oBAAAE,eAAA;AAAA,MAAC,QAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,QAAA;AAAA,QACL,OAAA,EAAS,QAAA;AAAA,QACT,eAAA,EAAe,IAAA;AAAA,QACf,SAAA,EAAW,aAAA;AAAA,QAEV,QAAA,EAAA;AAAA,UAAA,CAAC,MAAA,mBACAF,cAAA;AAAA,YAAC,MAAA;AAAA,YAAA;AAAA,cACC,aAAA,EAAY,MAAA;AAAA,cACZ,SAAA,EAAU,sGAAA;AAAA,cACV,KAAA,EAAO,EAAE,UAAA,EAAY,kBAAA;AAAmB;AAAA,WAC1C,GACE,IAAA;AAAA,0BACJE,eAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uEAAA,EACb,QAAA,EAAA;AAAA,YAAA,IAAA,mBACCF,cAAA,CAAC,QAAK,IAAA,EAAM,EAAA,EAAI,WAAW,MAAA,GAAS,YAAA,GAAe,gBAAgB,CAAA,GACjE,IAAA;AAAA,4BACJA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,QAAA,EAAU,eAAK,KAAA,EAAM,CAAA;AAAA,4BACrCA,cAAA;AAAA,cAAC,WAAA;AAAA,cAAA;AAAA,gBACC,SAAA,EAAW;AAAA,kBACT,uDAAA;AAAA,kBACA,OAAO,YAAA,GAAe;AAAA,iBACxB,CAAE,KAAK,GAAG;AAAA;AAAA;AACZ,WAAA,EACF;AAAA;AAAA;AAAA,KACF;AAAA,IAEC,IAAA,mBACCA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,4DACb,QAAA,kBAAAA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,uBAAA,EACZ,QAAA,EAAA,IAAA,CAAK,QAAA,CAAU,GAAA,CAAI,CAAC,OAAO,CAAA,KAAM;AAChC,MAAA,MAAM,cAAc,KAAA,CAAM,IAAA,GAAO,SAAS,QAAA,EAAU,KAAA,CAAM,IAAI,CAAA,GAAI,KAAA;AAClE,MAAA,uBACEA,cAAA;AAAA,QAAC,MAAA;AAAA,QAAA;AAAA,UAEC,IAAA,EAAM,KAAA;AAAA,UACN,MAAA,EAAQ,WAAA;AAAA,UACR,IAAA;AAAA,UACA,OAAA,EAAQ;AAAA,SAAA;AAAA,QAJH,MAAM,IAAA,IAAQ,CAAA,IAAA,EAAO,CAAC,CAAA,CAAA,EAAI,MAAM,KAAK,CAAA;AAAA,OAK5C;AAAA,IAEJ,CAAC,CAAA,EACH,CAAA,EACF,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;AAIA,SAAS,eAAA,CAAgB,EAAE,EAAA,EAAG,EAAmB;AAC/C,EAAA,MAAM,CAAC,MAAA,EAAQ,SAAS,CAAA,GAAIlB,eAAS,KAAK,CAAA;AAC1C,EAAA,uBACEkB,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,SAAS,MAAM;AACb,QAAA,IAAI;AACF,UAAA,KAAK,SAAA,CAAU,SAAA,EAAW,SAAA,CAAU,EAAE,CAAA;AAAA,QACxC,CAAA,CAAA,MAAQ;AAAA,QAER;AACA,QAAA,SAAA,CAAU,IAAI,CAAA;AACd,QAAA,UAAA,CAAW,MAAM,SAAA,CAAU,KAAK,CAAA,EAAG,IAAI,CAAA;AAAA,MACzC,CAAA;AAAA,MACA,KAAA,EAAM,sBAAA;AAAA,MACN,SAAA,EAAU,kFAAA;AAAA,MAET,mBAAS,QAAA,GAAW,CAAA,GAAA,EAAM,EAAA,CAAG,KAAA,CAAM,EAAE,CAAC,CAAA;AAAA;AAAA,GACzC;AAEJ;AA8CO,SAAS,SAAA,CAAU;AAAA,EACxB,KAAA;AAAA,EACA,QAAA;AAAA,EACA,IAAA;AAAA,EACA,SAAA;AAAA,EACA,WAAA;AAAA,EACA,OAAA;AAAA,EACA;AACF,CAAA,EAAmB;AACjB,EAAA,MAAM,QAAA,GAAA,CAAY,MAAM,IAAA,IAAQ,UAAA,EAAY,MAAM,CAAA,EAAG,CAAC,EAAE,WAAA,EAAY;AACpE,EAAA,MAAM,SAAA,GAAY,IAAA,EAAM,KAAA,IAAS,CAAC,MAAM,IAAA,EAAM,IAAA,EAAM,IAAI,CAAA,CAAE,MAAA,CAAO,OAAO,CAAA,CAAE,IAAA,CAAK,QAAK,CAAA,IAAK,QAAA;AACzF,EAAA,uBACEE,eAAA,CAAC,QAAA,EAAA,EAAO,SAAA,EAAU,kJAAA,EAChB,QAAA,EAAA;AAAA,oBAAAA,eAAA,CAAC,KAAA,EAAA,EAAI,WAAU,SAAA,EACb,QAAA,EAAA;AAAA,sBAAAF,cAAA;AAAA,QAAC,IAAA;AAAA,QAAA;AAAA,UACC,SAAA,EAAU,8EAAA;AAAA,UACV,cAAA,EAAa,MAAA;AAAA,UAEZ,QAAA,EAAA;AAAA;AAAA,OACH;AAAA,MACC,2BACCA,cAAA,CAAC,GAAA,EAAA,EAAE,SAAA,EAAU,4CAAA,EAA8C,oBAAS,CAAA,GAClE;AAAA,KAAA,EACN,CAAA;AAAA,oBAEAE,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,6DAAA,EACZ,QAAA,EAAA;AAAA,MAAA,WAAA,IAAe,WAAA,CAAY,MAAA,GAAS,CAAA,GACjC,WAAA,CAAY,GAAA,CAAI,CAAC,MAAA,qBACfF,cAAA,CAAC,qBAAA,EAAA,EAAuC,MAAA,EAAA,EAAZ,MAAA,CAAO,GAAqB,CACzD,CAAA,GACD,IAAA;AAAA,MACH,OAAA;AAAA,MACA,WAAA;AAAA,sBAIDE,eAAA,CAAC,SAAA,EAAA,EAAQ,SAAA,EAAU,gBAAA,EACjB,QAAA,EAAA;AAAA,wBAAAA,eAAA,CAAC,SAAA,EAAA,EAAQ,WAAU,qKAAA,EACjB,QAAA,EAAA;AAAA,0BAAAF,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,qIAAA,EACb,QAAA,EAAA,IAAA,EAAM,4BACLA,cAAA,CAAC,KAAA,EAAA,EAAI,GAAA,EAAK,IAAA,CAAK,WAAW,GAAA,EAAI,EAAA,EAAG,SAAA,EAAU,4BAAA,EAA6B,IAExE,QAAA,EAEJ,CAAA;AAAA,0BACAE,eAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,uCAAA,EACd,QAAA,EAAA;AAAA,4BAAAF,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,sDAAA,EACb,QAAA,EAAA,IAAA,EAAM,QAAQ,WAAA,EACjB,CAAA;AAAA,4BACAA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,mCAAA,EAAqC,QAAA,EAAA,SAAA,EAAU;AAAA,WAAA,EACjE,CAAA;AAAA,yCACC,WAAA,EAAA,EAAY;AAAA,SAAA,EACf,CAAA;AAAA,QACC,SAAA,mBACCA,cAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,gKAAA,EACb,QAAA,kBAAAE,eAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,OAAA,EAAS,SAAA;AAAA,YACT,SAAA,EAAU,gLAAA;AAAA,YAEV,QAAA,EAAA;AAAA,8BAAAF,cAAA,CAAC,WAAA,EAAA,EAAY,CAAA;AAAA,cAAE;AAAA;AAAA;AAAA,WAGnB,CAAA,GACE;AAAA,OAAA,EACN;AAAA,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ;AAGA,SAAS,WAAA,GAAc;AACrB,EAAA,uBACEE,eAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,KAAA,EAAO,EAAA;AAAA,MACP,MAAA,EAAQ,EAAA;AAAA,MACR,OAAA,EAAQ,WAAA;AAAA,MACR,IAAA,EAAK,MAAA;AAAA,MACL,MAAA,EAAO,cAAA;AAAA,MACP,WAAA,EAAa,CAAA;AAAA,MACb,aAAA,EAAc,OAAA;AAAA,MACd,cAAA,EAAe,OAAA;AAAA,MACf,aAAA,EAAY,MAAA;AAAA,MAEZ,QAAA,EAAA;AAAA,wBAAAF,cAAA,CAAC,MAAA,EAAA,EAAK,GAAE,yCAAA,EAA0C,CAAA;AAAA,wBAClDA,cAAA,CAAC,UAAA,EAAA,EAAS,MAAA,EAAO,kBAAA,EAAmB,CAAA;AAAA,wBACpCA,cAAA,CAAC,UAAK,EAAA,EAAG,IAAA,EAAK,IAAG,GAAA,EAAI,EAAA,EAAG,IAAA,EAAK,EAAA,EAAG,IAAA,EAAK;AAAA;AAAA;AAAA,GACvC;AAEJ;AAKA,SAAS,qBAAA,CAAsB,EAAE,MAAA,EAAO,EAAgC;AACtE,EAAA,MAAM,OAAO,MAAA,CAAO,IAAA;AACpB,EAAA,MAAM,IAAA,GAAO,OAAO,IAAA,IAAQ,SAAA;AAI5B,EAAA,MAAM,SAAA,GACJ,IAAA,KAAS,QAAA,IAAY,IAAA,KAAS,YAC1B,6EAAA,GACA,iLAAA;AACN,EAAA,MAAM,SAAA,GAAY;AAAA,IAChB,qGAAA;AAAA,IACA,iFAAA;AAAA,IACA;AAAA,GACF,CAAE,KAAK,GAAG,CAAA;AAIV,EAAA,MAAM,SAAA,GAAY,sBAAA,CAAuB,MAAA,CAAO,IAAA,IAAQ,MAAM,CAAA;AAC9D,EAAA,MAAM,UAAA,GAAa,MAAA,CAAO,IAAA,GAAO,iBAAA,CAAkB,SAAS,CAAA,GAAI,IAAA;AAChE,EAAA,MAAM,QAAQ,UAAA,IAAc,IAAA;AAE5B,EAAA,MAAM,0BACJE,eAAA,CAAAC,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAH,cAAA,CAAC,KAAA,EAAA,EAAM,IAAA,EAAM,EAAA,EAAI,SAAA,EAAU,cAAA,EAAe,CAAA;AAAA,IACzC,OAAO,MAAA,CAAO,KAAA,KAAU,QAAA,IAAY,MAAA,CAAO,KAAA,GAAQ,CAAA,mBAClDA,cAAA,CAAC,MAAA,EAAA,EAAK,SAAA,EAAU,iJAAA,EACb,QAAA,EAAA,MAAA,CAAO,OACV,CAAA,GACE;AAAA,GAAA,EACN,CAAA;AAGF,EAAA,MAAM,aAAa,MAAA,CAAO,IAAA,GAAO,eAAe,IAAA,CAAK,MAAA,CAAO,IAAI,CAAA,GAAI,KAAA;AAEpE,EAAA,IAAI,OAAO,IAAA,EAAM;AACf,IAAA,uBACEA,cAAA;AAAA,MAAC,GAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAM,QAAA,CAAS,MAAA,CAAO,IAAI,CAAA;AAAA,QAC1B,cAAY,MAAA,CAAO,KAAA;AAAA,QACnB,OAAO,MAAA,CAAO,KAAA;AAAA,QACd,SAAA;AAAA,QACC,GAAI,aAAa,EAAE,MAAA,EAAQ,UAAU,GAAA,EAAK,YAAA,KAAiB,EAAC;AAAA,QAE5D,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,uBACEA,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,SAAS,MAAA,CAAO,OAAA;AAAA,MAChB,cAAY,MAAA,CAAO,KAAA;AAAA,MACnB,OAAO,MAAA,CAAO,KAAA;AAAA,MACd,SAAA;AAAA,MAEC,QAAA,EAAA;AAAA;AAAA,GACH;AAEJ;AAyDA,IAAM,aAAA,GAAgB,EAAA;AAEtB,SAAS,YAAA,CAAa;AAAA,EACpB,GAAA;AAAA,EACA;AACF,CAAA,EAGG;AACD,EAAA,MAAM,EAAE,OAAO,IAAA,EAAM,IAAA,EAAM,MAAM,QAAA,EAAU,QAAA,EAAU,QAAA,EAAU,aAAA,EAAc,GAAI,GAAA;AACjF,EAAA,MAAM,KAAA,GAAQ,QAAA,GAAW,aAAA,IAAiB,KAAA,GAAQ,KAAA;AAIlD,EAAA,MAAM,IAAA,GACJ,uFAAA;AACF,EAAA,MAAM,UAAA,GAAa,QAAA,GACf,kDAAA,GACA,QAAA,GACE,sDAAA,GACA,iFAAA;AACN,EAAA,MAAM,SAAA,GAAY,CAAA,EAAG,IAAI,CAAA,CAAA,EAAI,UAAU,CAAA,CAAA;AAEvC,EAAA,MAAM,KAAA,GAAuB;AAAA,IAC3B,MAAA,EAAQ,yBAAA;AAAA,IACR,KAAA,EAAO,wBAAA;AAAA,IACP,KAAA,EAAO,mBAAA;AAAA,IACP,mBAAA,EAAqB,yBAAA;AAAA,IACrB,oBAAA,EAAsB,yBAAA;AAAA,IACtB,GAAI,QAAA,GAAW,EAAE,UAAA,EAAY,yBAAwB,GAAI;AAAA,GAC3D;AAEA,EAAA,MAAM,wBAAQA,cAAA,CAAC,IAAA,EAAA,EAAK,IAAA,EAAM,aAAA,EAAe,WAAU,cAAA,EAAe,CAAA;AAGlE,EAAA,IAAI,QAAA,EAAU;AACZ,IAAA,uBACEA,cAAA;AAAA,MAAC,MAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,KAAA;AAAA,QACL,eAAA,EAAe,KAAA;AAAA,QACf,eAAA,EAAc,MAAA;AAAA,QACd,YAAA,EAAY,KAAA;AAAA,QACZ,KAAA;AAAA,QACA,SAAA;AAAA,QACA,KAAA;AAAA,QAEC,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,uBACEA,cAAA;AAAA,MAAC,IAAA;AAAA,MAAA;AAAA,QACC,IAAA;AAAA,QACA,IAAA,EAAK,KAAA;AAAA,QACL,eAAA,EAAe,WAAW,IAAA,GAAO,KAAA;AAAA,QACjC,YAAA,EAAY,KAAA;AAAA,QACZ,KAAA;AAAA,QACA,SAAA;AAAA,QACA,KAAA;AAAA,QAEC,QAAA,EAAA;AAAA;AAAA,KACH;AAAA,EAEJ;AAEA,EAAA,uBACEA,cAAA;AAAA,IAAC,QAAA;AAAA,IAAA;AAAA,MACC,IAAA,EAAK,QAAA;AAAA,MACL,IAAA,EAAK,KAAA;AAAA,MACL,eAAA,EAAe,WAAW,IAAA,GAAO,KAAA;AAAA,MACjC,YAAA,EAAY,KAAA;AAAA,MACZ,KAAA;AAAA,MACA,OAAA,EAAS,QAAA;AAAA,MACT,SAAA;AAAA,MACA,KAAA;AAAA,MAEC,QAAA,EAAA;AAAA;AAAA,GACH;AAEJ;AAQO,SAAS,WAAA,CAAY;AAAA,EAC1B,IAAA;AAAA,EACA,YAAA,EAAc,SAAA;AAAA,EACd,aAAA;AAAA,EACA,SAAA;AAAA,EACA;AACF,CAAA,EAAqB;AACnB,EAAA,MAAM,OAAO,aAAA,IAAiB,WAAA;AAC9B,EAAA,uBACEE,eAAA,CAAAC,mBAAA,EAAA,EACE,QAAA,EAAA;AAAA,oBAAAH,cAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,IAAA,EAAK,SAAA;AAAA,QACL,YAAA,EAAY,SAAA;AAAA,QACZ,SAAA,EAAW,CAAC,yCAAA,EAA2C,SAAS,EAC7D,MAAA,CAAO,OAAO,CAAA,CACd,IAAA,CAAK,GAAG,CAAA;AAAA,QAEV,QAAA,EAAA,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,qBACTA,cAAA,CAAC,gBAA2B,GAAA,EAAU,IAAA,EAAA,EAAnB,GAAA,CAAI,GAA2B,CACnD;AAAA;AAAA,KACH;AAAA,IACC,aAAa,MAAA,mBACZA,cAAA;AAAA,MAAC,KAAA;AAAA,MAAA;AAAA,QACC,SAAA,EAAU,uDAAA;AAAA,QACV,KAAA,EAAO;AAAA,UACL,UAAA,EAAY,uBAAA;AAAA,UACZ,mBAAA,EAAqB,CAAA;AAAA,UACrB,oBAAA,EAAsB,yBAAA;AAAA,UACtB,sBAAA,EAAwB,yBAAA;AAAA,UACxB,uBAAA,EAAyB;AAAA,SAC3B;AAAA,QAEC;AAAA;AAAA,KACH,GACE;AAAA,GAAA,EACN,CAAA;AAEJ;AAcO,SAAS,WAAA,CAAY,EAAE,OAAA,EAAS,MAAA,EAAQ,UAAS,EAAqB;AAC3E,EAAA,uBACEE,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,0EAAA,EACb,QAAA,EAAA;AAAA,oBAAAF,cAAA,CAAC,UAAA,EAAA,EAAY,GAAG,OAAA,EAAS,CAAA;AAAA,oBACzBE,eAAA,CAAC,KAAA,EAAA,EAAI,SAAA,EAAU,eAAA,EACb,QAAA,EAAA;AAAA,sBAAAF,cAAA,CAAC,SAAA,EAAA,EAAW,GAAG,MAAA,EAAQ,CAAA;AAAA,sBACvBA,cAAA,CAAC,UAAK,SAAA,EAAU,WAAA,EACd,yCAAC,KAAA,EAAA,EAAI,SAAA,EAAU,mBAAA,EAAqB,QAAA,EAAS,CAAA,EAC/C;AAAA,KAAA,EACF;AAAA,GAAA,EACF,CAAA;AAEJ","file":"native.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","import type { NavIcon, NavItem } from './index'\n\n// ---------------------------------------------------------------------------\n// standardPolitogyNav — the canonical Politogy VRM menu.\n//\n// This is the single source of truth for the navigation every politogy app\n// renders (extracted verbatim from VRM core's relationship-mode sidebar,\n// `getRelationshipLinkItems`). Apps consume the same menu everywhere; an app\n// that owns one of the items (e.g. the standalone Contacts app) nests its own\n// pages as that item's children while every other entry links out to VRM core\n// as an absolute URL — full-page navigation with SSO shared across\n// *.politogyvrm.com.\n// ---------------------------------------------------------------------------\n\n/**\n * Icon slots used by the standard menu. The shell stays icon-library-agnostic:\n * callers map each key to their own icon components (lucide, react-icons, …).\n * A missing key simply renders that row without an icon.\n */\nexport type StandardNavIconKey =\n | 'home'\n | 'users'\n | 'mail'\n | 'messageSquare'\n | 'layout'\n | 'activity'\n | 'lifeBuoy'\n | 'grid'\n | 'list'\n | 'upload'\n | 'edit'\n | 'fileText'\n | 'send'\n | 'clock'\n | 'user'\n | 'barChart'\n\nexport interface StandardNavOptions {\n /** VRM core origin, e.g. \"https://app.politogyvrm.com\". Trailing slash OK. */\n coreBaseUrl: string\n /** Icon component per slot; omitted slots render icon-less rows. */\n icons?: Partial<Record<StandardNavIconKey, NavIcon>>\n /**\n * App-local override for the \"Contacts\" item. `children` are used verbatim\n * (NOT absolutized) so the owning app nests its own routes; `href` (also\n * verbatim) feeds active-detection for the group header. When omitted, the\n * item carries VRM core's own contacts sub-pages as absolute links.\n */\n contactsItem?: { href?: string; children?: NavItem[] }\n /**\n * The trailing \"Support\" row. VRM core opens its SupportRequestModal here;\n * other apps supply their own handler (`onClick`) or a link (`href`).\n * Omitted or `false` → no Support row.\n */\n supportItem?: { onClick?: () => void; href?: string } | false\n}\n\n/** Core-relative route + icon slot for one standard entry. */\ntype CoreLeaf = { label: string; icon: StandardNavIconKey; path: string }\n\nconst CONTACTS_DEFAULT_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/contacts/dashboard' },\n { label: 'All Contacts', icon: 'list', path: '/relationship/contacts/all' },\n { label: 'Tribes', icon: 'users', path: '/relationship/contacts/groups' },\n { label: 'Import', icon: 'upload', path: '/relationship/contacts/import' },\n { label: 'Import History', icon: 'fileText', path: '/relationship/contacts/import-history' },\n { label: 'Merge Rules', icon: 'layout', path: '/relationship/contacts/merge-rules' },\n]\n\nconst EMAIL_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/email/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/email/create-and-edit' },\n { label: 'Sender Information', icon: 'mail', path: '/relationship/email/inbox' },\n { label: 'Recipients', icon: 'user', path: '/relationship/email/send-to' },\n { label: 'Send & Automate', icon: 'clock', path: '/relationship/email/send-and-automate' },\n { label: 'Statistics', icon: 'barChart', path: '/relationship/email/statistics' },\n]\n\nconst SMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/sms-mms-blast/dashboard' },\n { label: 'Compose & Send', icon: 'send', path: '/relationship/sms-mms-blast/compose-and-send' },\n { label: 'Conversations', icon: 'messageSquare', path: '/relationship/sms-mms-blast/conversations' },\n]\n\nconst CTA_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/cta-database/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/cta-creator/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/cta-submissions/submissions' },\n]\n\nconst FORMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/forms' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/forms/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/forms/submissions' },\n]\n\n/**\n * Build the standard Politogy VRM menu (relationship mode), in the exact order\n * and wording the main app renders it. See `StandardNavOptions` for the two\n * app-specific hooks (`contactsItem`, `supportItem`).\n */\nexport function standardPolitogyNav(opts: StandardNavOptions): NavItem[] {\n const base = opts.coreBaseUrl.replace(/\\/+$/, '')\n const abs = (path: string): string => `${base}${path.startsWith('/') ? path : `/${path}`}`\n const icon = (key: StandardNavIconKey): NavIcon | undefined => opts.icons?.[key]\n const leaves = (children: CoreLeaf[]): NavItem[] =>\n children.map((c) => ({ label: c.label, icon: icon(c.icon), href: abs(c.path) }))\n\n const contacts: NavItem = opts.contactsItem\n ? {\n label: 'Contacts',\n icon: icon('users'),\n href: opts.contactsItem.href,\n children: opts.contactsItem.children,\n }\n : {\n label: 'Contacts',\n icon: icon('users'),\n href: abs('/relationship/contacts/dashboard'),\n children: leaves(CONTACTS_DEFAULT_CHILDREN),\n }\n\n const items: NavItem[] = [\n { label: 'Dashboard', icon: icon('home'), href: abs('/relationship/dashboard') },\n contacts,\n {\n label: 'Email Broadcast',\n icon: icon('mail'),\n href: abs('/relationship/email/dashboard'),\n children: leaves(EMAIL_CHILDREN),\n },\n {\n label: 'SMS/MMS Blast',\n icon: icon('messageSquare'),\n href: abs('/relationship/sms-mms-blast/dashboard'),\n children: leaves(SMS_CHILDREN),\n },\n // These two carry no top-level href in VRM core (parent row only toggles).\n { label: 'Calls to Action', icon: icon('layout'), children: leaves(CTA_CHILDREN) },\n { label: 'Forms & Surveys', icon: icon('activity'), children: leaves(FORMS_CHILDREN) },\n ]\n\n if (opts.supportItem) {\n items.push({\n label: 'Support',\n icon: icon('lifeBuoy'),\n href: opts.supportItem.href,\n onClick: opts.supportItem.onClick,\n })\n }\n\n return items\n}\n","// ---------------------------------------------------------------------------\n// Framework-agnostic chrome (sidebar + top navbar) for @the-portland-company/shell.\n//\n// The other chrome in this package (ShellChrome, Sidebar, Header, …) is built\n// on Chakra UI v2 + react-router and targets Vite SPAs. That stack cannot be\n// imported into a Next.js / React 19 / Tailwind app. This \"native\" module is a\n// dependency-light alternative: pure React (no Chakra, no emotion, no\n// react-router, no icon library) whose styling is driven entirely by the CSS\n// design tokens shipped in `@the-portland-company/shell/chrome.css`.\n//\n// It is a FAITHFUL VISUAL TWIN of the Chakra chrome (Sidebar.tsx / Header.tsx /\n// OrgPill / ModePill / NavItem / UserMenu): same 240px sidebar, brand-logo\n// slot, \"ORGANIZATION\" org pill, mode pill, solid active nav rows, pipe-\n// separated footer links + commit string, and an avatar+name+email+chevron user\n// menu — so an app rendering this looks identical to the main VRM app.\n//\n// Every app concern (nav items, org, mode, user, links, icons, the routing\n// Link component, the theme toggle) is injected via props, so both the Contacts\n// app (Next.js) and the VRM app could consume the same components.\n// ---------------------------------------------------------------------------\n\nimport type { ComponentType, CSSProperties, ReactNode } from 'react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTopBarIconSlotGlyph, type TopBarIconSlot } from '../lib/topbarIconSlot'\nimport { resolveBrandGlyph } from '../lib/brandGlyphs'\n\n// An icon is any component that accepts an optional size + className. This\n// matches both `lucide-react` and `react-icons` icon signatures, so consuming\n// apps pass their own icon set without this package depending on one.\nexport type NavIcon = ComponentType<{ size?: number; className?: string }>\n\nexport type NavItem = {\n /** Route to link to. Optional when `onClick` is supplied (renders a button). */\n href?: string\n label: string\n icon?: NavIcon\n /**\n * When supplied the row renders as a `<button>` (styled identically to the\n * link rows) instead of a routed link — used for actions like \"Support\".\n */\n onClick?: () => void\n /**\n * Nested sub-items. When present, the row becomes an expandable GROUP header:\n * clicking it toggles the children open/closed (it never navigates, even if\n * `href` is set) and renders a right-aligned chevron that rotates 180° when\n * open. The sidebar runs a single-open accordion (opening one group closes\n * the others) and auto-expands whichever group contains the active route —\n * mirroring the main VRM app's Chakra sidebar. Children render as smaller nav\n * rows on a lighter panel and support both `href` links and `onClick` actions.\n */\n children?: NavItem[]\n}\n\n// The routing primitive is injected so each app supplies its own (Next.js\n// `<Link>`, react-router `<Link>`, or a plain `<a>`). Defaults to an anchor.\nexport type NavLinkProps = {\n href: string\n className?: string\n 'aria-current'?: 'page' | undefined\n children: ReactNode\n // Optional passthrough attributes so the same injected link can back a\n // routed nav row OR a routed tab (which needs ARIA tab semantics + inline\n // token geometry). Next.js `<Link>`, react-router `<Link>` and a plain <a>\n // all accept these DOM props, and DefaultLink spreads them onto its anchor.\n role?: string\n 'aria-selected'?: boolean\n 'aria-label'?: string\n title?: string\n style?: CSSProperties\n}\nexport type NavLinkComponent = ComponentType<NavLinkProps>\n\n/**\n * URL-scheme allow-list for host-supplied hrefs. React does not neutralize\n * `javascript:`/`data:` schemes on anchor href, so any app-supplied nav/footer/\n * action href must be validated before it reaches the DOM. Permits absolute\n * http(s), mailto/tel, and in-app relative targets; everything else → '#'.\n */\nconst safeHref = (h?: string) =>\n h && /^(https?:|mailto:|tel:|\\/|#|\\.)/i.test(h.trim()) ? h : '#'\n\nconst DefaultLink: NavLinkComponent = ({ href, children, ...rest }) => (\n <a href={safeHref(href)} {...rest}>\n {children}\n </a>\n)\n\n/** Default active-route test: exact match for \"/\", prefix match otherwise. */\nexport function isNavItemActive(pathname: string, href: string): boolean {\n if (href === '/') return pathname === '/'\n return pathname === href || pathname.startsWith(`${href}/`)\n}\n\n/**\n * Stable identity for an expandable nav group's accordion state. Prefers the\n * item's href; falls back to an index-scoped label so two groups can never\n * collide even when they share a label and have no href.\n */\nfunction groupKeyOf(item: NavItem, index: number): string {\n return item.href ?? `nav-group-${index}-${item.label}`\n}\n\n/** True when any of a group's children links to the active route. */\nfunction hasActiveChild(\n item: NavItem,\n pathname: string,\n activeFn: (pathname: string, href: string) => boolean,\n): boolean {\n return (item.children ?? []).some((child) =>\n child.href ? activeFn(pathname, child.href) : false,\n )\n}\n\n/**\n * Color-coded tone classes for the sidebar environment chip, matching the main\n * VRM app: prod red, staging orange, local/dev green, unknown gray.\n */\nexport function envChipClasses(label: string): string {\n const l = label.toLowerCase()\n if (l === 'production' || l === 'prod')\n return 'bg-[#fee2e2] text-[#ef4444]'\n if (l === 'staging' || l === 'stage')\n return 'bg-[#ffedd5] text-[#f97316]'\n if (l === 'local' || l === 'development' || l === 'dev')\n return 'bg-[#dcfce7] text-[#22c55e]'\n return 'bg-[rgba(107,114,128,0.16)] text-[#6b7280]'\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavBrand = {\n /** Where the logo links to. Defaults to \"/\". */\n homeHref?: string\n /**\n * Brand logo image src. When supplied this renders as the wordmark logo\n * (matching the main app's BrandLogo), and `badgeLabel`/`title`/`subtitle`\n * are used only as the no-image fallback.\n */\n logoSrc?: string\n logoAlt?: string\n /** Short label shown inside the brand badge fallback (e.g. \"P\"). */\n badgeLabel: string\n title: string\n subtitle?: string\n}\n\nexport type NavOrg = {\n name: string | null\n /** Full org id. When present, a copy affordance is shown by the label. */\n id?: string | null\n /** Optional org logo for the pill badge; falls back to initials. */\n logoUrl?: string | null\n /** Solid pill background (the org's brand color). Defaults to race red. */\n brandColor?: string | null\n onClick?: () => void\n}\n\nexport type NavMode = {\n label: string\n icon?: NavIcon\n}\n\nexport type NavFooterLink = { label: string; href: string; external?: boolean }\n\nexport type NavFooter = {\n envLabel: string\n version: string\n commit: string\n links?: NavFooterLink[]\n /** ISO date (or any Date-parseable string) of the deployed commit. */\n commitDate?: string\n /** Full name of the commit author (only the first name is shown). */\n commitAuthor?: string\n}\n\nexport type NavSidebarProps = {\n pathname: string\n brand: NavBrand\n nav: {\n groupLabel?: string\n items: NavItem[]\n isActive?: (pathname: string, href: string) => boolean\n }\n org?: NavOrg | null\n mode?: NavMode | null\n footer?: NavFooter | null\n linkComponent?: NavLinkComponent\n}\n\n// Default org-pill background — race red, matching the main app's fallback\n// (mode primary) when an org has no explicit brand color.\nconst ORG_PILL_DEFAULT = 'var(--color-race-red)'\n\nexport function NavSidebar({\n pathname,\n brand,\n nav,\n org,\n mode,\n footer,\n linkComponent,\n}: NavSidebarProps) {\n const Link = linkComponent ?? DefaultLink\n const activeFn = nav.isActive ?? isNavItemActive\n const ModeIcon = mode?.icon\n const orgBg = org?.brandColor || ORG_PILL_DEFAULT\n\n // Single-open accordion for expandable nav groups, mirroring the main VRM\n // app's Chakra sidebar. `activeGroupKey` is the group (if any) that owns the\n // current route; deriving it as a primitive string keeps the auto-expand\n // effect from firing when `nav.items` is a fresh array reference each render\n // (which would otherwise clobber a manual toggle).\n const activeGroupKey = useMemo(() => {\n for (let i = 0; i < nav.items.length; i++) {\n const item = nav.items[i]\n if (item.children && item.children.length > 0 && hasActiveChild(item, pathname, activeFn)) {\n return groupKeyOf(item, i)\n }\n }\n return null\n }, [nav.items, pathname, activeFn])\n\n // Seed the open group from the active route on first paint (no expand flash),\n // then keep it synced as the route changes. Manual toggles between route\n // changes are preserved because the effect only reruns when the *derived*\n // active group actually changes.\n const [openGroup, setOpenGroup] = useState<string | null>(activeGroupKey)\n useEffect(() => {\n setOpenGroup(activeGroupKey)\n }, [activeGroupKey])\n const toggleGroup = (key: string) =>\n setOpenGroup((prev) => (prev === key ? null : key))\n\n return (\n <aside className=\"fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--panel-elevated)] lg:flex\">\n {/* Brand — logo image (preferred) or badge fallback */}\n <Link\n href={brand.homeHref ?? '/'}\n className=\"flex h-[64px] flex-shrink-0 items-center gap-2.5 px-6\"\n >\n {brand.logoSrc ? (\n <img\n src={brand.logoSrc}\n alt={brand.logoAlt ?? brand.title}\n draggable={false}\n className=\"h-10 w-auto object-contain\"\n />\n ) : (\n <>\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-[color:var(--color-race-red)] text-base font-black text-white shadow-sm\">\n {brand.badgeLabel}\n </span>\n <span className=\"flex flex-col leading-tight\">\n <span className=\"text-base font-extrabold tracking-[-0.01em] text-[color:var(--color-race-red)]\">\n {brand.title}\n </span>\n {brand.subtitle ? (\n <span className=\"text-[11px] font-semibold uppercase tracking-[0.16em] text-[color:var(--muted)]\">\n {brand.subtitle}\n </span>\n ) : null}\n </span>\n </>\n )}\n </Link>\n\n {/* Scroll region: org pill, mode pill, nav */}\n <div className=\"flex flex-1 flex-col overflow-y-auto px-4 pb-2\">\n {/* Organization switcher */}\n {org ? (\n <div className=\"mb-3\">\n <div className=\"mb-2 flex items-center justify-between px-1\">\n <p className=\"text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Organization\n </p>\n {org.id ? <OrgIdCopyButton id={org.id} /> : null}\n </div>\n <button\n type=\"button\"\n onClick={org.onClick}\n style={{ backgroundColor: orgBg }}\n className=\"flex w-full items-center justify-between gap-2 rounded-md px-2.5 py-2 text-left text-white shadow-sm transition hover:opacity-95\"\n >\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-white/20 text-[11px] font-bold text-white\">\n {org.logoUrl ? (\n <img src={org.logoUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n (org.name ?? 'Org').slice(0, 2).toUpperCase()\n )}\n </span>\n <span className=\"truncate text-sm font-semibold\">\n {org.name ?? 'No organizations'}\n </span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Mode pill */}\n {mode ? (\n <div className=\"mb-4\">\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 rounded-md bg-[color:var(--color-race-red)] px-2.5 py-2 text-white shadow-sm\"\n >\n <span className=\"flex items-center gap-2.5\">\n {ModeIcon ? <ModeIcon size={16} className=\"shrink-0\" /> : null}\n <span className=\"text-sm font-semibold tracking-[-0.01em]\">{mode.label}</span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Nav list */}\n <nav className=\"flex flex-col gap-1\">\n {nav.groupLabel ? (\n <p className=\"px-2 pb-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n {nav.groupLabel}\n </p>\n ) : null}\n {nav.items.map((item, idx) => {\n // Expandable group: renders a toggle header + collapsible children.\n if (item.children && item.children.length > 0) {\n const key = groupKeyOf(item, idx)\n const selfActive = item.href ? activeFn(pathname, item.href) : false\n const parentActive = selfActive || hasActiveChild(item, pathname, activeFn)\n return (\n <NavGroup\n key={key}\n item={item}\n active={parentActive}\n open={openGroup === key}\n onToggle={() => toggleGroup(key)}\n pathname={pathname}\n activeFn={activeFn}\n Link={Link}\n />\n )\n }\n const active = item.href ? activeFn(pathname, item.href) : false\n return (\n <NavRow\n key={item.href ?? `nav-${idx}-${item.label}`}\n item={item}\n active={active}\n Link={Link}\n />\n )\n })}\n </nav>\n </div>\n\n {/* Footer — pipe-separated links + commit/version string */}\n {footer ? (\n <div className=\"flex-shrink-0 border-t border-[color:var(--line)] px-4 py-3\">\n {footer.links && footer.links.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-1.5 text-xs\">\n {footer.links.map((l, idx) => (\n <span key={l.label} className=\"inline-flex items-center gap-1.5\">\n {idx > 0 ? <span className=\"text-[color:var(--muted)]\">|</span> : null}\n <a\n href={safeHref(l.href)}\n className=\"font-medium text-[color:var(--color-race-red)] hover:underline\"\n >\n {l.label}\n </a>\n </span>\n ))}\n </div>\n ) : null}\n <div className=\"mt-1.5 flex flex-col items-center gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--muted)]\">\n {/* Row 1: env chip | commit | version */}\n <div className=\"flex items-center gap-1.5\">\n <span\n className={[\n 'rounded-md px-1.5 py-0.5 text-[10px] font-semibold',\n envChipClasses(footer.envLabel),\n ].join(' ')}\n >\n {footer.envLabel}\n </span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>{footer.commit.slice(-4)}</span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>v{footer.version}</span>\n </div>\n {/* Row 2: date | author (only when supplied) */}\n {footer.commitDate || footer.commitAuthor ? (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitDate ? (\n <span>\n {new Date(footer.commitDate).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitAuthor ? (\n <span>{footer.commitAuthor.split(/\\s+/)[0]}</span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n </div>\n ) : null}\n </div>\n </div>\n ) : null}\n </aside>\n )\n}\n\n// Inline chevron-down (mirrors lucide `ChevronDown`) — no icon dependency.\n// Callers may override `className` to add a rotation (used by expandable groups).\nfunction ChevronDown({ className }: { className?: string } = {}) {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className ?? 'shrink-0 opacity-80'}\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\n// A single sidebar nav row. Renders as a routed <Link> (href) or a <button>\n// (onClick), styled identically. Inactive rows animate a left→right gradient\n// sweep on hover (matching the main app); active rows keep solid race-red.\n//\n// `variant=\"sub\"` renders the smaller child rows inside an expanded group: a\n// tighter row whose ACTIVE state is a lighter elevated surface with race-red\n// text (not a solid-red fill — that stays reserved for top-level/parent rows,\n// exactly as the main VRM app's Chakra sidebar treats active sub-items).\n// Specs race-red ramp (hover → active primary).\nconst NAV_HOVER_GRADIENT = 'linear-gradient(90deg,#EA4751 0%,#E63946 100%)'\n\nfunction NavRow({\n item,\n active,\n Link,\n variant = 'top',\n}: {\n item: NavItem\n active: boolean\n Link: NavLinkComponent\n variant?: 'top' | 'sub'\n}) {\n const Icon = item.icon\n const isSub = variant === 'sub'\n const activeClasses = isSub\n ? 'bg-[color:var(--panel-elevated)] text-[color:var(--color-race-red)] shadow-sm'\n : 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n const wrapperClasses = [\n 'group relative block overflow-hidden rounded-md transition',\n active ? activeClasses : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n const rowPadding = isSub ? 'px-3 py-1.5 text-[13px]' : 'px-3 py-2 text-sm'\n const iconSize = isSub ? 16 : 18\n // Top-level active rows use white glyphs on the red fill; sub-item active\n // rows inherit the race-red text color via `text-current`.\n const iconClass = active && !isSub ? 'text-white' : 'text-current'\n\n const inner = (\n <>\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className={`relative z-10 flex items-center gap-3 font-semibold ${rowPadding}`}>\n {Icon ? <Icon size={iconSize} className={iconClass} /> : null}\n {item.label}\n </span>\n </>\n )\n\n if (item.onClick && !item.href) {\n return (\n <button type=\"button\" onClick={item.onClick} className={`w-full text-left ${wrapperClasses}`}>\n {inner}\n </button>\n )\n }\n\n return (\n <Link\n href={item.href ?? '#'}\n aria-current={active ? 'page' : undefined}\n className={wrapperClasses}\n >\n {inner}\n </Link>\n )\n}\n\n// An expandable nav GROUP: a toggle header + a collapsible list of child rows.\n// Faithful twin of the main VRM app's Chakra accordion (Sidebar.tsx /\n// NavItem.tsx):\n// - Clicking the header toggles the children — it never navigates, even when\n// the group carries an `href`.\n// - A right-aligned chevron rotates 180° when open.\n// - The header goes solid race-red (white text) when the group owns the active\n// route (its own href OR any child), matching top-level active rows; when\n// merely open it lifts onto the `--panel` surface; otherwise it's a muted row\n// with the same left→right gradient hover sweep as every other nav row.\n// - Children sit on the lighter `--panel` surface, indented and rounded, each\n// rendered through the SAME injected LinkComponent (or as a button for\n// `onClick` children) via <NavRow variant=\"sub\" />.\nfunction NavGroup({\n item,\n active,\n open,\n onToggle,\n pathname,\n activeFn,\n Link,\n}: {\n item: NavItem\n active: boolean\n open: boolean\n onToggle: () => void\n pathname: string\n activeFn: (pathname: string, href: string) => boolean\n Link: NavLinkComponent\n}) {\n const Icon = item.icon\n const headerClasses = [\n 'group relative block w-full overflow-hidden text-left transition',\n open ? 'rounded-t-md' : 'rounded-md',\n active\n ? 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n : open\n ? 'bg-[color:var(--panel)] text-[color:var(--foreground)]'\n : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n return (\n <div>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n className={headerClasses}\n >\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className=\"relative z-10 flex items-center gap-3 px-3 py-2 text-sm font-semibold\">\n {Icon ? (\n <Icon size={18} className={active ? 'text-white' : 'text-current'} />\n ) : null}\n <span className=\"flex-1\">{item.label}</span>\n <ChevronDown\n className={[\n 'shrink-0 opacity-80 transition-transform duration-200',\n open ? 'rotate-180' : '',\n ].join(' ')}\n />\n </span>\n </button>\n\n {open ? (\n <div className=\"overflow-hidden rounded-b-md bg-[color:var(--panel)] p-1\">\n <div className=\"flex flex-col gap-0.5\">\n {item.children!.map((child, i) => {\n const childActive = child.href ? activeFn(pathname, child.href) : false\n return (\n <NavRow\n key={child.href ?? `sub-${i}-${child.label}`}\n item={child}\n active={childActive}\n Link={Link}\n variant=\"sub\"\n />\n )\n })}\n </div>\n </div>\n ) : null}\n </div>\n )\n}\n\n// Right-aligned copy affordance for the org id, shown beside the \"Organization\"\n// label. Copies the full id and briefly swaps its text to \"Copied\".\nfunction OrgIdCopyButton({ id }: { id: string }) {\n const [copied, setCopied] = useState(false)\n return (\n <button\n type=\"button\"\n onClick={() => {\n try {\n void navigator.clipboard?.writeText(id)\n } catch {\n /* clipboard unavailable — ignore */\n }\n setCopied(true)\n setTimeout(() => setCopied(false), 1500)\n }}\n title=\"Copy organization id\"\n className=\"rounded px-1 text-[11px] text-[color:var(--muted)] hover:bg-[color:var(--panel)]\"\n >\n {copied ? 'Copied' : `...${id.slice(-8)}`}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavUser = {\n name: string | null\n email?: string | null\n /** Avatar image URL; falls back to initials on the brand color. */\n avatarUrl?: string | null\n tier?: string | null\n role?: string | null\n}\n\nexport type NavTopBarAction = {\n key: string\n /**\n * Canonical top-bar slot. When set, the glyph is sourced by NAME from the\n * Brand API via `--topbar-icon-<slot>`; `icon` becomes the fallback used\n * until the runtime Brand stylesheet lands (or when the token is unset).\n */\n slot?: TopBarIconSlot\n icon: NavIcon\n label: string\n onClick?: () => void\n href?: string\n badge?: number | null\n tone?: 'default' | 'warning' | 'danger'\n}\n\nexport type NavTopBarProps = {\n title: string\n subtitle?: string\n user?: NavUser | null\n onSignOut?: () => void\n /**\n * Structured icon-button action cluster (32×32 circular buttons with optional\n * count badges), rendered before the `actions` slot. Matches the main app's\n * topbar action icons.\n */\n actionsList?: NavTopBarAction[]\n /** App-specific action cluster rendered left of the theme toggle. */\n actions?: ReactNode\n /** Theme toggle slot (injected so this package needs no theme dependency). */\n themeToggle?: ReactNode\n}\n\nexport function NavTopBar({\n title,\n subtitle,\n user,\n onSignOut,\n actionsList,\n actions,\n themeToggle,\n}: NavTopBarProps) {\n const initials = (user?.name ?? 'Politogy').slice(0, 2).toUpperCase()\n const secondary = user?.email || [user?.tier, user?.role].filter(Boolean).join(' · ') || 'member'\n return (\n <header className=\"sticky top-0 z-20 flex h-20 items-center justify-between gap-4 border-b border-[color:var(--line)] bg-[color:var(--panel)] px-4 backdrop-blur-xl\">\n <div className=\"min-w-0\">\n <h1\n className=\"truncate text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]\"\n data-display=\"true\"\n >\n {title}\n </h1>\n {subtitle ? (\n <p className=\"truncate text-sm text-[color:var(--muted)]\">{subtitle}</p>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]\">\n {actionsList && actionsList.length > 0\n ? actionsList.map((action) => (\n <NavTopBarActionButton key={action.key} action={action} />\n ))\n : null}\n {actions}\n {themeToggle}\n\n {/* User menu — avatar + name/email + chevron; sign-out in a native\n <details> popover so the package needs no JS state. */}\n <details className=\"group relative\">\n <summary className=\"flex cursor-pointer list-none items-center gap-2.5 rounded-full py-1 pl-1 pr-2 transition hover:bg-[color:var(--panel-elevated)] [&::-webkit-details-marker]:hidden\">\n <span className=\"flex h-9 w-9 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-race-red)] text-xs font-bold text-white\">\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n initials\n )}\n </span>\n <span className=\"hidden flex-col leading-tight md:flex\">\n <span className=\"text-sm font-semibold text-[color:var(--foreground)]\">\n {user?.name ?? 'Signed in'}\n </span>\n <span className=\"text-xs text-[color:var(--muted)]\">{secondary}</span>\n </span>\n <ChevronDown />\n </summary>\n {onSignOut ? (\n <div className=\"absolute right-0 z-30 mt-2 w-44 overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]\">\n <button\n type=\"button\"\n onClick={onSignOut}\n className=\"flex w-full items-center gap-2.5 px-4 py-2 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-race-red)]\"\n >\n <SignOutIcon />\n Sign out\n </button>\n </div>\n ) : null}\n </details>\n </div>\n </header>\n )\n}\n\n// Inline log-out glyph (mirrors lucide `LogOut`) to avoid an icon dependency.\nfunction SignOutIcon() {\n return (\n <svg\n width={15}\n height={15}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n\n// A single 32×32 circular icon button for the top bar's structured action list.\n// Renders an <a> when `href` is present (external links open in a new tab),\n// otherwise a <button>. Shows a red count badge when `badge > 0`.\nfunction NavTopBarActionButton({ action }: { action: NavTopBarAction }) {\n const Icon = action.icon\n const tone = action.tone ?? 'default'\n // Universal treatment (Global Rules v9): size, color and hover are a single\n // shared value across every top-bar slot — only the glyph varies per slot.\n // Tone is a semantic state, not a bespoke per-slot style.\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 const className = [\n '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 // Per-slot glyph from Brand; `icon` is the fallback until the token resolves.\n // Brand emits Feather/Lucide glyph NAMES, not asset paths.\n const glyphName = useTopBarIconSlotGlyph(action.slot ?? 'apps')\n const BrandGlyph = action.slot ? resolveBrandGlyph(glyphName) : null\n const Glyph = BrandGlyph ?? Icon\n\n const content = (\n <>\n <Glyph size={20} className=\"text-current\" />\n {typeof action.badge === 'number' && action.badge > 0 ? (\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 {action.badge}\n </span>\n ) : null}\n </>\n )\n\n const isExternal = action.href ? /^https?:\\/\\//.test(action.href) : false\n\n if (action.href) {\n return (\n <a\n href={safeHref(action.href)}\n aria-label={action.label}\n title={action.label}\n className={className}\n {...(isExternal ? { target: '_blank', rel: 'noreferrer' } : {})}\n >\n {content}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={action.onClick}\n aria-label={action.label}\n title={action.label}\n className={className}\n >\n {content}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Icon-only tab strip — the standard secondary navigation the three Next.js\n// worker apps (Forms / Surveys / Polls) render below the top bar: a horizontal\n// row of icon-only tabs where the SELECTED tab merges into the content panel\n// below it (top/left/right border, no bottom border, sharing --tab-content-bg).\n//\n// A faithful twin of the hand-rolled `.tabstrip`/`.tab-strip` markup those apps\n// carried, promoted into the shell so every app renders the same accessible,\n// token-driven strip. All geometry is driven by the Brand `--tab-*` CSS vars\n// shipped in chrome.css (with literal fallbacks so the strip still renders in\n// an app that hasn't loaded the runtime tokens link yet):\n// --tab-height (row height) · --tab-icon-size (glyph) · --tab-radius (top\n// corners) · --tab-gap (between tabs) · --tab-content-bg (selected + panel\n// surface) · --tab-unselected-opacity (dimmed inactive tabs, default 0.6).\n// ---------------------------------------------------------------------------\n\nexport type NavTab = {\n /** Stable identity (used as the React key). */\n key: string\n /** Accessible name — becomes both the `title` tooltip and `aria-label`. */\n label: string\n icon: NavIcon\n /** Route to link to (rendered through `linkComponent`). */\n href?: string\n /** Click handler — rendered as a `<button>` when there's no `href`. */\n onSelect?: () => void\n /** Whether this tab is the active one (drives the merged-panel geometry). */\n selected?: boolean\n /**\n * Non-interactive, dimmed tab (e.g. Surveys' Canvas/Results before a survey\n * is chosen). Renders a non-navigating span; `disabledTitle` overrides the\n * tooltip to explain why (falls back to `label`).\n */\n disabled?: boolean\n disabledTitle?: string\n}\n\nexport type NavTabStripProps = {\n tabs: NavTab[]\n /** Accessible name for the tablist. */\n 'aria-label'?: string\n /** Routing primitive for `href` tabs (Next `<Link>`, etc). Defaults to <a>. */\n linkComponent?: NavLinkComponent\n /** Extra classes on the tablist container. */\n className?: string\n /**\n * Optional content panel rendered directly below the strip. When supplied it\n * renders on the shared `--tab-content-bg` surface with a square top-left\n * corner so the selected tab visually merges into it. Omit to render only the\n * strip and compose the panel yourself.\n */\n children?: ReactNode\n}\n\n/** Default icon glyph size — mirrors the `--tab-icon-size` token default. */\nconst TAB_ICON_SIZE = 18\n\nfunction NavTabButton({\n tab,\n Link,\n}: {\n tab: NavTab\n Link: NavLinkComponent\n}) {\n const { label, icon: Icon, href, onSelect, selected, disabled, disabledTitle } = tab\n const title = disabled ? disabledTitle ?? label : label\n\n // Base geometry shared by every state. Selected tabs sit above the content\n // panel (`z-10`) so their missing bottom border merges cleanly into it.\n const base =\n 'inline-flex shrink-0 items-center justify-center border border-b-0 transition-opacity'\n const stateClass = disabled\n ? 'cursor-not-allowed border-transparent opacity-40'\n : selected\n ? 'relative z-10 opacity-100 border-[color:var(--line)]'\n : 'border-transparent opacity-[var(--tab-unselected-opacity,0.6)] hover:opacity-90'\n const className = `${base} ${stateClass}`\n\n const style: CSSProperties = {\n height: 'var(--tab-height, 44px)',\n width: 'var(--tab-width, 3rem)',\n color: 'var(--foreground)',\n borderTopLeftRadius: 'var(--tab-radius, 12px)',\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n ...(selected ? { background: 'var(--tab-content-bg)' } : null),\n }\n\n const glyph = <Icon size={TAB_ICON_SIZE} className=\"text-current\" />\n\n // Disabled: non-navigating span, still exposed as a tab for AT.\n if (disabled) {\n return (\n <span\n role=\"tab\"\n aria-selected={false}\n aria-disabled=\"true\"\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </span>\n )\n }\n\n if (href) {\n return (\n <Link\n href={href}\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </Link>\n )\n }\n\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n onClick={onSelect}\n className={className}\n style={style}\n >\n {glyph}\n </button>\n )\n}\n\n/**\n * Icon-only, token-driven tab strip. Render it below `NavTopBar`; pass the\n * app's `Link` as `linkComponent` for `href` tabs. Supply `children` to get the\n * merged content panel, or omit it and compose your own panel on\n * `var(--tab-content-bg)`.\n */\nexport function NavTabStrip({\n tabs,\n 'aria-label': ariaLabel,\n linkComponent,\n className,\n children,\n}: NavTabStripProps) {\n const Link = linkComponent ?? DefaultLink\n return (\n <>\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n className={['flex items-end gap-[var(--tab-gap,8px)]', className]\n .filter(Boolean)\n .join(' ')}\n >\n {tabs.map((tab) => (\n <NavTabButton key={tab.key} tab={tab} Link={Link} />\n ))}\n </div>\n {children !== undefined ? (\n <div\n className=\"relative -mt-px border border-[color:var(--line)] p-5\"\n style={{\n background: 'var(--tab-content-bg)',\n borderTopLeftRadius: 0,\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n borderBottomLeftRadius: 'var(--tab-radius, 12px)',\n borderBottomRightRadius: 'var(--tab-radius, 12px)',\n }}\n >\n {children}\n </div>\n ) : null}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavAppShellProps = {\n sidebar: NavSidebarProps\n topBar: NavTopBarProps\n children: ReactNode\n}\n\n/**\n * Full chrome: branded left sidebar + sticky top navbar + scrollable content\n * region. Presentational only — wrap it in app-level auth/gating as needed.\n */\nexport function NavAppShell({ sidebar, topBar, children }: NavAppShellProps) {\n return (\n <div className=\"min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]\">\n <NavSidebar {...sidebar} />\n <div className=\"lg:pl-[240px]\">\n <NavTopBar {...topBar} />\n <main className=\"px-6 py-7\">\n <div className=\"mx-auto max-w-7xl\">{children}</div>\n </main>\n </div>\n </div>\n )\n}\n\n// Canonical Politogy VRM menu — the standard nav structure every politogy app\n// renders, with hooks for the app-owned \"Contacts\" item and Support handler.\nexport {\n standardPolitogyNav,\n type StandardNavIconKey,\n type StandardNavOptions,\n} from './standardNav'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/lib/topbarIconSlot.ts","../src/lib/brandGlyphs.tsx","../src/native/standardNav.ts","../src/native/index.tsx"],"names":["useState","useEffect","FiBatteryCharging","FiBattery","FiZap","FiGrid","FiBell","FiAlertTriangle","FiAlertCircle","FiLifeBuoy","FiHelpCircle","FiMoon","FiSun","FiInfo","FiMail","FiMessageSquare","FiSettings","FiUser","jsx","useMemo","jsxs","Fragment"],"mappings":"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","file":"native.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","import type { NavIcon, NavItem } from './index'\n\n// ---------------------------------------------------------------------------\n// standardPolitogyNav — the canonical Politogy VRM menu.\n//\n// This is the single source of truth for the navigation every politogy app\n// renders (extracted verbatim from VRM core's relationship-mode sidebar,\n// `getRelationshipLinkItems`). Apps consume the same menu everywhere; an app\n// that owns one of the items (e.g. the standalone Contacts app) nests its own\n// pages as that item's children while every other entry links out to VRM core\n// as an absolute URL — full-page navigation with SSO shared across\n// *.politogyvrm.com.\n// ---------------------------------------------------------------------------\n\n/**\n * Icon slots used by the standard menu. The shell stays icon-library-agnostic:\n * callers map each key to their own icon components (lucide, react-icons, …).\n * A missing key simply renders that row without an icon.\n */\nexport type StandardNavIconKey =\n | 'home'\n | 'users'\n | 'mail'\n | 'messageSquare'\n | 'layout'\n | 'activity'\n | 'lifeBuoy'\n | 'grid'\n | 'list'\n | 'upload'\n | 'edit'\n | 'fileText'\n | 'send'\n | 'clock'\n | 'user'\n | 'barChart'\n\nexport interface StandardNavOptions {\n /** VRM core origin, e.g. \"https://app.politogyvrm.com\". Trailing slash OK. */\n coreBaseUrl: string\n /** Icon component per slot; omitted slots render icon-less rows. */\n icons?: Partial<Record<StandardNavIconKey, NavIcon>>\n /**\n * App-local override for the \"Contacts\" item. `children` are used verbatim\n * (NOT absolutized) so the owning app nests its own routes; `href` (also\n * verbatim) feeds active-detection for the group header. When omitted, the\n * item carries VRM core's own contacts sub-pages as absolute links.\n */\n contactsItem?: { href?: string; children?: NavItem[] }\n /**\n * The trailing \"Support\" row. VRM core opens its SupportRequestModal here;\n * other apps supply their own handler (`onClick`) or a link (`href`).\n * Omitted or `false` → no Support row.\n */\n supportItem?: { onClick?: () => void; href?: string } | false\n}\n\n/** Core-relative route + icon slot for one standard entry. */\ntype CoreLeaf = { label: string; icon: StandardNavIconKey; path: string }\n\nconst CONTACTS_DEFAULT_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/contacts/dashboard' },\n { label: 'All Contacts', icon: 'list', path: '/relationship/contacts/all' },\n { label: 'Tribes', icon: 'users', path: '/relationship/contacts/groups' },\n { label: 'Import', icon: 'upload', path: '/relationship/contacts/import' },\n { label: 'Import History', icon: 'fileText', path: '/relationship/contacts/import-history' },\n { label: 'Merge Rules', icon: 'layout', path: '/relationship/contacts/merge-rules' },\n]\n\nconst EMAIL_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/email/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/email/create-and-edit' },\n { label: 'Sender Information', icon: 'mail', path: '/relationship/email/inbox' },\n { label: 'Recipients', icon: 'user', path: '/relationship/email/send-to' },\n { label: 'Send & Automate', icon: 'clock', path: '/relationship/email/send-and-automate' },\n { label: 'Statistics', icon: 'barChart', path: '/relationship/email/statistics' },\n]\n\nconst SMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/sms-mms-blast/dashboard' },\n { label: 'Compose & Send', icon: 'send', path: '/relationship/sms-mms-blast/compose-and-send' },\n { label: 'Conversations', icon: 'messageSquare', path: '/relationship/sms-mms-blast/conversations' },\n]\n\nconst CTA_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/cta-database/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/cta-creator/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/cta-submissions/submissions' },\n]\n\nconst FORMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/forms' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/forms/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/forms/submissions' },\n]\n\n/**\n * Build the standard Politogy VRM menu (relationship mode), in the exact order\n * and wording the main app renders it. See `StandardNavOptions` for the two\n * app-specific hooks (`contactsItem`, `supportItem`).\n */\nexport function standardPolitogyNav(opts: StandardNavOptions): NavItem[] {\n const base = opts.coreBaseUrl.replace(/\\/+$/, '')\n const abs = (path: string): string => `${base}${path.startsWith('/') ? path : `/${path}`}`\n const icon = (key: StandardNavIconKey): NavIcon | undefined => opts.icons?.[key]\n const leaves = (children: CoreLeaf[]): NavItem[] =>\n children.map((c) => ({ label: c.label, icon: icon(c.icon), href: abs(c.path) }))\n\n const contacts: NavItem = opts.contactsItem\n ? {\n label: 'Contacts',\n icon: icon('users'),\n href: opts.contactsItem.href,\n children: opts.contactsItem.children,\n }\n : {\n label: 'Contacts',\n icon: icon('users'),\n href: abs('/relationship/contacts/dashboard'),\n children: leaves(CONTACTS_DEFAULT_CHILDREN),\n }\n\n const items: NavItem[] = [\n { label: 'Dashboard', icon: icon('home'), href: abs('/relationship/dashboard') },\n contacts,\n {\n label: 'Email Broadcast',\n icon: icon('mail'),\n href: abs('/relationship/email/dashboard'),\n children: leaves(EMAIL_CHILDREN),\n },\n {\n label: 'SMS/MMS Blast',\n icon: icon('messageSquare'),\n href: abs('/relationship/sms-mms-blast/dashboard'),\n children: leaves(SMS_CHILDREN),\n },\n // These two carry no top-level href in VRM core (parent row only toggles).\n { label: 'Calls to Action', icon: icon('layout'), children: leaves(CTA_CHILDREN) },\n { label: 'Forms & Surveys', icon: icon('activity'), children: leaves(FORMS_CHILDREN) },\n ]\n\n if (opts.supportItem) {\n items.push({\n label: 'Support',\n icon: icon('lifeBuoy'),\n href: opts.supportItem.href,\n onClick: opts.supportItem.onClick,\n })\n }\n\n return items\n}\n","// ---------------------------------------------------------------------------\n// Framework-agnostic chrome (sidebar + top navbar) for @the-portland-company/shell.\n//\n// The other chrome in this package (ShellChrome, Sidebar, Header, …) is built\n// on Chakra UI v2 + react-router and targets Vite SPAs. That stack cannot be\n// imported into a Next.js / React 19 / Tailwind app. This \"native\" module is a\n// dependency-light alternative: pure React (no Chakra, no emotion, no\n// react-router, no icon library) whose styling is driven entirely by the CSS\n// design tokens shipped in `@the-portland-company/shell/chrome.css`.\n//\n// It is a FAITHFUL VISUAL TWIN of the Chakra chrome (Sidebar.tsx / Header.tsx /\n// OrgPill / ModePill / NavItem / UserMenu): same 240px sidebar, brand-logo\n// slot, \"ORGANIZATION\" org pill, mode pill, solid active nav rows, pipe-\n// separated footer links + commit string, and an avatar+name+email+chevron user\n// menu — so an app rendering this looks identical to the main VRM app.\n//\n// Every app concern (nav items, org, mode, user, links, icons, the routing\n// Link component, the theme toggle) is injected via props, so both the Contacts\n// app (Next.js) and the VRM app could consume the same components.\n// ---------------------------------------------------------------------------\n\nimport type { ComponentType, CSSProperties, ReactNode } from 'react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTopBarIconSlotGlyph, type TopBarIconSlot } from '../lib/topbarIconSlot'\nimport { resolveBrandGlyph } from '../lib/brandGlyphs'\n\n// An icon is any component that accepts an optional size + className. This\n// matches both `lucide-react` and `react-icons` icon signatures, so consuming\n// apps pass their own icon set without this package depending on one.\nexport type NavIcon = ComponentType<{ size?: number; className?: string }>\n\nexport type NavItem = {\n /** Route to link to. Optional when `onClick` is supplied (renders a button). */\n href?: string\n label: string\n icon?: NavIcon\n /**\n * When supplied the row renders as a `<button>` (styled identically to the\n * link rows) instead of a routed link — used for actions like \"Support\".\n */\n onClick?: () => void\n /**\n * Nested sub-items. When present, the row becomes an expandable GROUP header:\n * clicking it toggles the children open/closed (it never navigates, even if\n * `href` is set) and renders a right-aligned chevron that rotates 180° when\n * open. The sidebar runs a single-open accordion (opening one group closes\n * the others) and auto-expands whichever group contains the active route —\n * mirroring the main VRM app's Chakra sidebar. Children render as smaller nav\n * rows on a lighter panel and support both `href` links and `onClick` actions.\n */\n children?: NavItem[]\n}\n\n// The routing primitive is injected so each app supplies its own (Next.js\n// `<Link>`, react-router `<Link>`, or a plain `<a>`). Defaults to an anchor.\nexport type NavLinkProps = {\n href: string\n className?: string\n 'aria-current'?: 'page' | undefined\n children: ReactNode\n // Optional passthrough attributes so the same injected link can back a\n // routed nav row OR a routed tab (which needs ARIA tab semantics + inline\n // token geometry). Next.js `<Link>`, react-router `<Link>` and a plain <a>\n // all accept these DOM props, and DefaultLink spreads them onto its anchor.\n role?: string\n 'aria-selected'?: boolean\n 'aria-label'?: string\n title?: string\n style?: CSSProperties\n}\nexport type NavLinkComponent = ComponentType<NavLinkProps>\n\n/**\n * URL-scheme allow-list for host-supplied hrefs. React does not neutralize\n * `javascript:`/`data:` schemes on anchor href, so any app-supplied nav/footer/\n * action href must be validated before it reaches the DOM. Permits absolute\n * http(s), mailto/tel, and in-app relative targets; everything else → '#'.\n */\nconst safeHref = (h?: string) =>\n h && /^(https?:|mailto:|tel:|\\/|#|\\.)/i.test(h.trim()) ? h : '#'\n\nconst DefaultLink: NavLinkComponent = ({ href, children, ...rest }) => (\n <a href={safeHref(href)} {...rest}>\n {children}\n </a>\n)\n\n/** Default active-route test: exact match for \"/\", prefix match otherwise. */\nexport function isNavItemActive(pathname: string, href: string): boolean {\n if (href === '/') return pathname === '/'\n return pathname === href || pathname.startsWith(`${href}/`)\n}\n\n/**\n * Stable identity for an expandable nav group's accordion state. Prefers the\n * item's href; falls back to an index-scoped label so two groups can never\n * collide even when they share a label and have no href.\n */\nfunction groupKeyOf(item: NavItem, index: number): string {\n return item.href ?? `nav-group-${index}-${item.label}`\n}\n\n/** True when any of a group's children links to the active route. */\nfunction hasActiveChild(\n item: NavItem,\n pathname: string,\n activeFn: (pathname: string, href: string) => boolean,\n): boolean {\n return (item.children ?? []).some((child) =>\n child.href ? activeFn(pathname, child.href) : false,\n )\n}\n\n/**\n * Color-coded tone classes for the sidebar environment chip, matching the main\n * VRM app: prod red, staging orange, local/dev green, unknown gray.\n */\nexport function envChipClasses(label: string): string {\n const l = label.toLowerCase()\n if (l === 'production' || l === 'prod')\n return 'bg-[#fee2e2] text-[#ef4444]'\n if (l === 'staging' || l === 'stage')\n return 'bg-[#ffedd5] text-[#f97316]'\n if (l === 'local' || l === 'development' || l === 'dev')\n return 'bg-[#dcfce7] text-[#22c55e]'\n return 'bg-[rgba(107,114,128,0.16)] text-[#6b7280]'\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavBrand = {\n /** Where the logo links to. Defaults to \"/\". */\n homeHref?: string\n /**\n * Brand logo image src. When supplied this renders as the wordmark logo\n * (matching the main app's BrandLogo), and `badgeLabel`/`title`/`subtitle`\n * are used only as the no-image fallback.\n */\n logoSrc?: string\n logoAlt?: string\n /** Short label shown inside the brand badge fallback (e.g. \"P\"). */\n badgeLabel: string\n title: string\n subtitle?: string\n}\n\nexport type NavOrg = {\n name: string | null\n /** Full org id. When present, a copy affordance is shown by the label. */\n id?: string | null\n /** Optional org logo for the pill badge; falls back to initials. */\n logoUrl?: string | null\n /** Solid pill background (the org's brand color). Defaults to race red. */\n brandColor?: string | null\n onClick?: () => void\n}\n\nexport type NavMode = {\n label: string\n icon?: NavIcon\n}\n\nexport type NavFooterLink = { label: string; href: string; external?: boolean }\n\nexport type NavFooter = {\n envLabel: string\n version: string\n commit: string\n links?: NavFooterLink[]\n /** ISO date (or any Date-parseable string) of the deployed commit. */\n commitDate?: string\n /** Full name of the commit author (only the first name is shown). */\n commitAuthor?: string\n}\n\nexport type NavSidebarProps = {\n pathname: string\n brand: NavBrand\n nav: {\n groupLabel?: string\n items: NavItem[]\n isActive?: (pathname: string, href: string) => boolean\n }\n org?: NavOrg | null\n mode?: NavMode | null\n footer?: NavFooter | null\n linkComponent?: NavLinkComponent\n}\n\n// Default org-pill background — race red, matching the main app's fallback\n// (mode primary) when an org has no explicit brand color.\nconst ORG_PILL_DEFAULT = 'var(--color-race-red)'\n\nexport function NavSidebar({\n pathname,\n brand,\n nav,\n org,\n mode,\n footer,\n linkComponent,\n}: NavSidebarProps) {\n const Link = linkComponent ?? DefaultLink\n const activeFn = nav.isActive ?? isNavItemActive\n const ModeIcon = mode?.icon\n const orgBg = org?.brandColor || ORG_PILL_DEFAULT\n\n // Single-open accordion for expandable nav groups, mirroring the main VRM\n // app's Chakra sidebar. `activeGroupKey` is the group (if any) that owns the\n // current route; deriving it as a primitive string keeps the auto-expand\n // effect from firing when `nav.items` is a fresh array reference each render\n // (which would otherwise clobber a manual toggle).\n const activeGroupKey = useMemo(() => {\n for (let i = 0; i < nav.items.length; i++) {\n const item = nav.items[i]\n if (item.children && item.children.length > 0 && hasActiveChild(item, pathname, activeFn)) {\n return groupKeyOf(item, i)\n }\n }\n return null\n }, [nav.items, pathname, activeFn])\n\n // Seed the open group from the active route on first paint (no expand flash),\n // then keep it synced as the route changes. Manual toggles between route\n // changes are preserved because the effect only reruns when the *derived*\n // active group actually changes.\n const [openGroup, setOpenGroup] = useState<string | null>(activeGroupKey)\n useEffect(() => {\n setOpenGroup(activeGroupKey)\n }, [activeGroupKey])\n const toggleGroup = (key: string) =>\n setOpenGroup((prev) => (prev === key ? null : key))\n\n return (\n <aside className=\"fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--nav-surface)] lg:flex\">\n {/* Brand — logo image (preferred) or badge fallback */}\n <Link\n href={brand.homeHref ?? '/'}\n className=\"flex h-[64px] flex-shrink-0 items-center gap-2.5 px-6\"\n >\n {brand.logoSrc ? (\n <img\n src={brand.logoSrc}\n alt={brand.logoAlt ?? brand.title}\n draggable={false}\n className=\"h-10 w-auto object-contain\"\n />\n ) : (\n <>\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-[color:var(--color-race-red)] text-base font-black text-white shadow-sm\">\n {brand.badgeLabel}\n </span>\n <span className=\"flex flex-col leading-tight\">\n <span className=\"text-base font-extrabold tracking-[-0.01em] text-[color:var(--color-race-red)]\">\n {brand.title}\n </span>\n {brand.subtitle ? (\n <span className=\"text-[11px] font-semibold uppercase tracking-[0.16em] text-[color:var(--muted)]\">\n {brand.subtitle}\n </span>\n ) : null}\n </span>\n </>\n )}\n </Link>\n\n {/* Scroll region: org pill, mode pill, nav */}\n <div className=\"flex flex-1 flex-col overflow-y-auto px-4 pb-2\">\n {/* Organization switcher */}\n {org ? (\n <div className=\"mb-3\">\n <div className=\"mb-2 flex items-center justify-between px-1\">\n <p className=\"text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Organization\n </p>\n {org.id ? <OrgIdCopyButton id={org.id} /> : null}\n </div>\n <button\n type=\"button\"\n onClick={org.onClick}\n style={{ backgroundColor: orgBg }}\n className=\"flex w-full items-center justify-between gap-2 rounded-md px-2.5 py-2 text-left text-white shadow-sm transition hover:opacity-95\"\n >\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-white/20 text-[11px] font-bold text-white\">\n {org.logoUrl ? (\n <img src={org.logoUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n (org.name ?? 'Org').slice(0, 2).toUpperCase()\n )}\n </span>\n <span className=\"truncate text-sm font-semibold\">\n {org.name ?? 'No organizations'}\n </span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Mode pill */}\n {mode ? (\n <div className=\"mb-4\">\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 rounded-md bg-[color:var(--color-race-red)] px-2.5 py-2 text-white shadow-sm\"\n >\n <span className=\"flex items-center gap-2.5\">\n {ModeIcon ? <ModeIcon size={16} className=\"shrink-0\" /> : null}\n <span className=\"text-sm font-semibold tracking-[-0.01em]\">{mode.label}</span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Nav list */}\n <nav className=\"flex flex-col gap-1\">\n {nav.groupLabel ? (\n <p className=\"px-2 pb-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n {nav.groupLabel}\n </p>\n ) : null}\n {nav.items.map((item, idx) => {\n // Expandable group: renders a toggle header + collapsible children.\n if (item.children && item.children.length > 0) {\n const key = groupKeyOf(item, idx)\n const selfActive = item.href ? activeFn(pathname, item.href) : false\n const parentActive = selfActive || hasActiveChild(item, pathname, activeFn)\n return (\n <NavGroup\n key={key}\n item={item}\n active={parentActive}\n open={openGroup === key}\n onToggle={() => toggleGroup(key)}\n pathname={pathname}\n activeFn={activeFn}\n Link={Link}\n />\n )\n }\n const active = item.href ? activeFn(pathname, item.href) : false\n return (\n <NavRow\n key={item.href ?? `nav-${idx}-${item.label}`}\n item={item}\n active={active}\n Link={Link}\n />\n )\n })}\n </nav>\n </div>\n\n {/* Footer — pipe-separated links + commit/version string */}\n {footer ? (\n <div className=\"flex-shrink-0 border-t border-[color:var(--line)] px-4 py-3\">\n {footer.links && footer.links.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-1.5 text-xs\">\n {footer.links.map((l, idx) => (\n <span key={l.label} className=\"inline-flex items-center gap-1.5\">\n {idx > 0 ? <span className=\"text-[color:var(--muted)]\">|</span> : null}\n <a\n href={safeHref(l.href)}\n className=\"font-medium text-[color:var(--color-race-red)] hover:underline\"\n >\n {l.label}\n </a>\n </span>\n ))}\n </div>\n ) : null}\n <div className=\"mt-1.5 flex flex-col items-center gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--muted)]\">\n {/* Row 1: env chip | commit | version */}\n <div className=\"flex items-center gap-1.5\">\n <span\n className={[\n 'rounded-md px-1.5 py-0.5 text-[10px] font-semibold',\n envChipClasses(footer.envLabel),\n ].join(' ')}\n >\n {footer.envLabel}\n </span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>{footer.commit.slice(-4)}</span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>v{footer.version}</span>\n </div>\n {/* Row 2: date | author (only when supplied) */}\n {footer.commitDate || footer.commitAuthor ? (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitDate ? (\n <span>\n {new Date(footer.commitDate).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitAuthor ? (\n <span>{footer.commitAuthor.split(/\\s+/)[0]}</span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n </div>\n ) : null}\n </div>\n </div>\n ) : null}\n </aside>\n )\n}\n\n// Inline chevron-down (mirrors lucide `ChevronDown`) — no icon dependency.\n// Callers may override `className` to add a rotation (used by expandable groups).\nfunction ChevronDown({ className }: { className?: string } = {}) {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className ?? 'shrink-0 opacity-80'}\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\n// A single sidebar nav row. Renders as a routed <Link> (href) or a <button>\n// (onClick), styled identically. Inactive rows animate a left→right gradient\n// sweep on hover (matching the main app); active rows keep solid race-red.\n//\n// `variant=\"sub\"` renders the smaller child rows inside an expanded group: a\n// tighter row whose ACTIVE state is a lighter elevated surface with race-red\n// text (not a solid-red fill — that stays reserved for top-level/parent rows,\n// exactly as the main VRM app's Chakra sidebar treats active sub-items).\n// Specs race-red ramp (hover → active primary).\nconst NAV_HOVER_GRADIENT = 'linear-gradient(90deg,#EA4751 0%,#E63946 100%)'\n\nfunction NavRow({\n item,\n active,\n Link,\n variant = 'top',\n}: {\n item: NavItem\n active: boolean\n Link: NavLinkComponent\n variant?: 'top' | 'sub'\n}) {\n const Icon = item.icon\n const isSub = variant === 'sub'\n const activeClasses = isSub\n ? 'bg-[color:var(--panel-elevated)] text-[color:var(--color-race-red)] shadow-sm'\n : 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n const wrapperClasses = [\n 'group relative block overflow-hidden rounded-md transition',\n active ? activeClasses : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n const rowPadding = isSub ? 'px-3 py-1.5 text-[13px]' : 'px-3 py-2 text-sm'\n const iconSize = isSub ? 16 : 18\n // Top-level active rows use white glyphs on the red fill; sub-item active\n // rows inherit the race-red text color via `text-current`.\n const iconClass = active && !isSub ? 'text-white' : 'text-current'\n\n const inner = (\n <>\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className={`relative z-10 flex items-center gap-3 font-semibold ${rowPadding}`}>\n {Icon ? <Icon size={iconSize} className={iconClass} /> : null}\n {item.label}\n </span>\n </>\n )\n\n if (item.onClick && !item.href) {\n return (\n <button type=\"button\" onClick={item.onClick} className={`w-full text-left ${wrapperClasses}`}>\n {inner}\n </button>\n )\n }\n\n return (\n <Link\n href={item.href ?? '#'}\n aria-current={active ? 'page' : undefined}\n className={wrapperClasses}\n >\n {inner}\n </Link>\n )\n}\n\n// An expandable nav GROUP: a toggle header + a collapsible list of child rows.\n// Faithful twin of the main VRM app's Chakra accordion (Sidebar.tsx /\n// NavItem.tsx):\n// - Clicking the header toggles the children — it never navigates, even when\n// the group carries an `href`.\n// - A right-aligned chevron rotates 180° when open.\n// - The header goes solid race-red (white text) when the group owns the active\n// route (its own href OR any child), matching top-level active rows; when\n// merely open it lifts onto the `--panel` surface; otherwise it's a muted row\n// with the same left→right gradient hover sweep as every other nav row.\n// - Children sit on the lighter `--panel` surface, indented and rounded, each\n// rendered through the SAME injected LinkComponent (or as a button for\n// `onClick` children) via <NavRow variant=\"sub\" />.\nfunction NavGroup({\n item,\n active,\n open,\n onToggle,\n pathname,\n activeFn,\n Link,\n}: {\n item: NavItem\n active: boolean\n open: boolean\n onToggle: () => void\n pathname: string\n activeFn: (pathname: string, href: string) => boolean\n Link: NavLinkComponent\n}) {\n const Icon = item.icon\n const headerClasses = [\n 'group relative block w-full overflow-hidden text-left transition',\n open ? 'rounded-t-md' : 'rounded-md',\n active\n ? 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n : open\n ? 'bg-[color:var(--panel)] text-[color:var(--foreground)]'\n : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n return (\n <div>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n className={headerClasses}\n >\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className=\"relative z-10 flex items-center gap-3 px-3 py-2 text-sm font-semibold\">\n {Icon ? (\n <Icon size={18} className={active ? 'text-white' : 'text-current'} />\n ) : null}\n <span className=\"flex-1\">{item.label}</span>\n <ChevronDown\n className={[\n 'shrink-0 opacity-80 transition-transform duration-200',\n open ? 'rotate-180' : '',\n ].join(' ')}\n />\n </span>\n </button>\n\n {open ? (\n <div className=\"overflow-hidden rounded-b-md bg-[color:var(--panel)] p-1\">\n <div className=\"flex flex-col gap-0.5\">\n {item.children!.map((child, i) => {\n const childActive = child.href ? activeFn(pathname, child.href) : false\n return (\n <NavRow\n key={child.href ?? `sub-${i}-${child.label}`}\n item={child}\n active={childActive}\n Link={Link}\n variant=\"sub\"\n />\n )\n })}\n </div>\n </div>\n ) : null}\n </div>\n )\n}\n\n// Right-aligned copy affordance for the org id, shown beside the \"Organization\"\n// label. Copies the full id and briefly swaps its text to \"Copied\".\nfunction OrgIdCopyButton({ id }: { id: string }) {\n const [copied, setCopied] = useState(false)\n return (\n <button\n type=\"button\"\n onClick={() => {\n try {\n void navigator.clipboard?.writeText(id)\n } catch {\n /* clipboard unavailable — ignore */\n }\n setCopied(true)\n setTimeout(() => setCopied(false), 1500)\n }}\n title=\"Copy organization id\"\n className=\"rounded px-1 text-[11px] text-[color:var(--muted)] hover:bg-[color:var(--panel)]\"\n >\n {copied ? 'Copied' : `...${id.slice(-8)}`}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavUser = {\n name: string | null\n email?: string | null\n /** Avatar image URL; falls back to initials on the brand color. */\n avatarUrl?: string | null\n tier?: string | null\n role?: string | null\n}\n\nexport type NavTopBarAction = {\n key: string\n /**\n * Canonical top-bar slot. When set, the glyph is sourced by NAME from the\n * Brand API via `--topbar-icon-<slot>`; `icon` becomes the fallback used\n * until the runtime Brand stylesheet lands (or when the token is unset).\n */\n slot?: TopBarIconSlot\n icon: NavIcon\n label: string\n onClick?: () => void\n href?: string\n badge?: number | null\n tone?: 'default' | 'warning' | 'danger'\n}\n\nexport type NavTopBarProps = {\n title: string\n subtitle?: string\n user?: NavUser | null\n onSignOut?: () => void\n /**\n * Structured icon-button action cluster (32×32 circular buttons with optional\n * count badges), rendered before the `actions` slot. Matches the main app's\n * topbar action icons.\n */\n actionsList?: NavTopBarAction[]\n /** App-specific action cluster rendered left of the theme toggle. */\n actions?: ReactNode\n /** Theme toggle slot (injected so this package needs no theme dependency). */\n themeToggle?: ReactNode\n}\n\nexport function NavTopBar({\n title,\n subtitle,\n user,\n onSignOut,\n actionsList,\n actions,\n themeToggle,\n}: NavTopBarProps) {\n const initials = (user?.name ?? 'Politogy').slice(0, 2).toUpperCase()\n const secondary = user?.email || [user?.tier, user?.role].filter(Boolean).join(' · ') || 'member'\n return (\n <header className=\"sticky top-0 z-20 flex h-20 items-center justify-between gap-4 border-b border-[color:var(--line)] bg-[color:var(--panel)] px-4 backdrop-blur-xl\">\n <div className=\"min-w-0\">\n <h1\n className=\"truncate text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]\"\n data-display=\"true\"\n >\n {title}\n </h1>\n {subtitle ? (\n <p className=\"truncate text-sm text-[color:var(--muted)]\">{subtitle}</p>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]\">\n {actionsList && actionsList.length > 0\n ? actionsList.map((action) => (\n <NavTopBarActionButton key={action.key} action={action} />\n ))\n : null}\n {actions}\n {themeToggle}\n\n {/* User menu — avatar + name/email + chevron; sign-out in a native\n <details> popover so the package needs no JS state. */}\n <details className=\"group relative\">\n <summary className=\"flex cursor-pointer list-none items-center gap-2.5 rounded-full py-1 pl-1 pr-2 transition hover:bg-[color:var(--panel-elevated)] [&::-webkit-details-marker]:hidden\">\n <span className=\"flex h-9 w-9 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-race-red)] text-xs font-bold text-white\">\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n initials\n )}\n </span>\n <span className=\"hidden flex-col leading-tight md:flex\">\n <span className=\"text-sm font-semibold text-[color:var(--foreground)]\">\n {user?.name ?? 'Signed in'}\n </span>\n <span className=\"text-xs text-[color:var(--muted)]\">{secondary}</span>\n </span>\n <ChevronDown />\n </summary>\n {onSignOut ? (\n <div className=\"absolute right-0 z-30 mt-2 w-44 overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]\">\n <button\n type=\"button\"\n onClick={onSignOut}\n className=\"flex w-full items-center gap-2.5 px-4 py-2 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-race-red)]\"\n >\n <SignOutIcon />\n Sign out\n </button>\n </div>\n ) : null}\n </details>\n </div>\n </header>\n )\n}\n\n// Inline log-out glyph (mirrors lucide `LogOut`) to avoid an icon dependency.\nfunction SignOutIcon() {\n return (\n <svg\n width={15}\n height={15}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n\n// A single 32×32 circular icon button for the top bar's structured action list.\n// Renders an <a> when `href` is present (external links open in a new tab),\n// otherwise a <button>. Shows a red count badge when `badge > 0`.\nfunction NavTopBarActionButton({ action }: { action: NavTopBarAction }) {\n const Icon = action.icon\n const tone = action.tone ?? 'default'\n // Universal treatment (Global Rules v9): size, color and hover are a single\n // shared value across every top-bar slot — only the glyph varies per slot.\n // Tone is a semantic state, not a bespoke per-slot style.\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 const className = [\n '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 // Per-slot glyph from Brand; `icon` is the fallback until the token resolves.\n // Brand emits Feather/Lucide glyph NAMES, not asset paths.\n const glyphName = useTopBarIconSlotGlyph(action.slot ?? 'apps')\n const BrandGlyph = action.slot ? resolveBrandGlyph(glyphName) : null\n const Glyph = BrandGlyph ?? Icon\n\n const content = (\n <>\n <Glyph size={20} className=\"text-current\" />\n {typeof action.badge === 'number' && action.badge > 0 ? (\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 {action.badge}\n </span>\n ) : null}\n </>\n )\n\n const isExternal = action.href ? /^https?:\\/\\//.test(action.href) : false\n\n if (action.href) {\n return (\n <a\n href={safeHref(action.href)}\n aria-label={action.label}\n title={action.label}\n className={className}\n {...(isExternal ? { target: '_blank', rel: 'noreferrer' } : {})}\n >\n {content}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={action.onClick}\n aria-label={action.label}\n title={action.label}\n className={className}\n >\n {content}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Icon-only tab strip — the standard secondary navigation the three Next.js\n// worker apps (Forms / Surveys / Polls) render below the top bar: a horizontal\n// row of icon-only tabs where the SELECTED tab merges into the content panel\n// below it (top/left/right border, no bottom border, sharing --tab-content-bg).\n//\n// A faithful twin of the hand-rolled `.tabstrip`/`.tab-strip` markup those apps\n// carried, promoted into the shell so every app renders the same accessible,\n// token-driven strip. All geometry is driven by the Brand `--tab-*` CSS vars\n// shipped in chrome.css (with literal fallbacks so the strip still renders in\n// an app that hasn't loaded the runtime tokens link yet):\n// --tab-height (row height) · --tab-icon-size (glyph) · --tab-radius (top\n// corners) · --tab-gap (between tabs) · --tab-content-bg (selected + panel\n// surface) · --tab-unselected-opacity (dimmed inactive tabs, default 0.6).\n// ---------------------------------------------------------------------------\n\nexport type NavTab = {\n /** Stable identity (used as the React key). */\n key: string\n /** Accessible name — becomes both the `title` tooltip and `aria-label`. */\n label: string\n icon: NavIcon\n /** Route to link to (rendered through `linkComponent`). */\n href?: string\n /** Click handler — rendered as a `<button>` when there's no `href`. */\n onSelect?: () => void\n /** Whether this tab is the active one (drives the merged-panel geometry). */\n selected?: boolean\n /**\n * Non-interactive, dimmed tab (e.g. Surveys' Canvas/Results before a survey\n * is chosen). Renders a non-navigating span; `disabledTitle` overrides the\n * tooltip to explain why (falls back to `label`).\n */\n disabled?: boolean\n disabledTitle?: string\n}\n\nexport type NavTabStripProps = {\n tabs: NavTab[]\n /** Accessible name for the tablist. */\n 'aria-label'?: string\n /** Routing primitive for `href` tabs (Next `<Link>`, etc). Defaults to <a>. */\n linkComponent?: NavLinkComponent\n /** Extra classes on the tablist container. */\n className?: string\n /**\n * Optional content panel rendered directly below the strip. When supplied it\n * renders on the shared `--tab-content-bg` surface with a square top-left\n * corner so the selected tab visually merges into it. Omit to render only the\n * strip and compose the panel yourself.\n */\n children?: ReactNode\n}\n\n/** Default icon glyph size — mirrors the `--tab-icon-size` token default. */\nconst TAB_ICON_SIZE = 18\n\nfunction NavTabButton({\n tab,\n Link,\n}: {\n tab: NavTab\n Link: NavLinkComponent\n}) {\n const { label, icon: Icon, href, onSelect, selected, disabled, disabledTitle } = tab\n const title = disabled ? disabledTitle ?? label : label\n\n // Base geometry shared by every state. Selected tabs sit above the content\n // panel (`z-10`) so their missing bottom border merges cleanly into it.\n const base =\n 'inline-flex shrink-0 items-center justify-center border border-b-0 transition-opacity'\n const stateClass = disabled\n ? 'cursor-not-allowed border-transparent opacity-40'\n : selected\n ? 'relative z-10 opacity-100 border-[color:var(--line)]'\n : 'border-transparent opacity-[var(--tab-unselected-opacity,0.6)] hover:opacity-90'\n const className = `${base} ${stateClass}`\n\n const style: CSSProperties = {\n height: 'var(--tab-height, 44px)',\n width: 'var(--tab-width, 3rem)',\n color: 'var(--foreground)',\n borderTopLeftRadius: 'var(--tab-radius, 12px)',\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n ...(selected ? { background: 'var(--tab-content-bg)' } : null),\n }\n\n const glyph = <Icon size={TAB_ICON_SIZE} className=\"text-current\" />\n\n // Disabled: non-navigating span, still exposed as a tab for AT.\n if (disabled) {\n return (\n <span\n role=\"tab\"\n aria-selected={false}\n aria-disabled=\"true\"\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </span>\n )\n }\n\n if (href) {\n return (\n <Link\n href={href}\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </Link>\n )\n }\n\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n onClick={onSelect}\n className={className}\n style={style}\n >\n {glyph}\n </button>\n )\n}\n\n/**\n * Icon-only, token-driven tab strip. Render it below `NavTopBar`; pass the\n * app's `Link` as `linkComponent` for `href` tabs. Supply `children` to get the\n * merged content panel, or omit it and compose your own panel on\n * `var(--tab-content-bg)`.\n */\nexport function NavTabStrip({\n tabs,\n 'aria-label': ariaLabel,\n linkComponent,\n className,\n children,\n}: NavTabStripProps) {\n const Link = linkComponent ?? DefaultLink\n return (\n <>\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n className={['flex items-end gap-[var(--tab-gap,8px)]', className]\n .filter(Boolean)\n .join(' ')}\n >\n {tabs.map((tab) => (\n <NavTabButton key={tab.key} tab={tab} Link={Link} />\n ))}\n </div>\n {children !== undefined ? (\n <div\n className=\"relative -mt-px border border-[color:var(--line)] p-5\"\n style={{\n background: 'var(--tab-content-bg)',\n borderTopLeftRadius: 0,\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n borderBottomLeftRadius: 'var(--tab-radius, 12px)',\n borderBottomRightRadius: 'var(--tab-radius, 12px)',\n }}\n >\n {children}\n </div>\n ) : null}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavAppShellProps = {\n sidebar: NavSidebarProps\n topBar: NavTopBarProps\n children: ReactNode\n}\n\n/**\n * Full chrome: branded left sidebar + sticky top navbar + scrollable content\n * region. Presentational only — wrap it in app-level auth/gating as needed.\n */\nexport function NavAppShell({ sidebar, topBar, children }: NavAppShellProps) {\n return (\n <div className=\"min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]\">\n <NavSidebar {...sidebar} />\n <div className=\"lg:pl-[240px]\">\n <NavTopBar {...topBar} />\n <main className=\"px-6 py-7\">\n <div className=\"mx-auto max-w-7xl\">{children}</div>\n </main>\n </div>\n </div>\n )\n}\n\n// Canonical Politogy VRM menu — the standard nav structure every politogy app\n// renders, with hooks for the app-owned \"Contacts\" item and Support handler.\nexport {\n standardPolitogyNav,\n type StandardNavIconKey,\n type StandardNavOptions,\n} from './standardNav'\n"]}
|
package/dist/native.js
CHANGED
|
@@ -132,7 +132,7 @@ function NavSidebar({
|
|
|
132
132
|
setOpenGroup(activeGroupKey);
|
|
133
133
|
}, [activeGroupKey]);
|
|
134
134
|
const toggleGroup = (key) => setOpenGroup((prev) => prev === key ? null : key);
|
|
135
|
-
return /* @__PURE__ */ jsxs("aside", { className: "fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--
|
|
135
|
+
return /* @__PURE__ */ jsxs("aside", { className: "fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--nav-surface)] lg:flex", children: [
|
|
136
136
|
/* @__PURE__ */ jsx(
|
|
137
137
|
Link,
|
|
138
138
|
{
|
package/dist/native.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/native/standardNav.ts","../src/native/index.tsx"],"names":[],"mappings":"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","file":"native.js","sourcesContent":["import type { NavIcon, NavItem } from './index'\n\n// ---------------------------------------------------------------------------\n// standardPolitogyNav — the canonical Politogy VRM menu.\n//\n// This is the single source of truth for the navigation every politogy app\n// renders (extracted verbatim from VRM core's relationship-mode sidebar,\n// `getRelationshipLinkItems`). Apps consume the same menu everywhere; an app\n// that owns one of the items (e.g. the standalone Contacts app) nests its own\n// pages as that item's children while every other entry links out to VRM core\n// as an absolute URL — full-page navigation with SSO shared across\n// *.politogyvrm.com.\n// ---------------------------------------------------------------------------\n\n/**\n * Icon slots used by the standard menu. The shell stays icon-library-agnostic:\n * callers map each key to their own icon components (lucide, react-icons, …).\n * A missing key simply renders that row without an icon.\n */\nexport type StandardNavIconKey =\n | 'home'\n | 'users'\n | 'mail'\n | 'messageSquare'\n | 'layout'\n | 'activity'\n | 'lifeBuoy'\n | 'grid'\n | 'list'\n | 'upload'\n | 'edit'\n | 'fileText'\n | 'send'\n | 'clock'\n | 'user'\n | 'barChart'\n\nexport interface StandardNavOptions {\n /** VRM core origin, e.g. \"https://app.politogyvrm.com\". Trailing slash OK. */\n coreBaseUrl: string\n /** Icon component per slot; omitted slots render icon-less rows. */\n icons?: Partial<Record<StandardNavIconKey, NavIcon>>\n /**\n * App-local override for the \"Contacts\" item. `children` are used verbatim\n * (NOT absolutized) so the owning app nests its own routes; `href` (also\n * verbatim) feeds active-detection for the group header. When omitted, the\n * item carries VRM core's own contacts sub-pages as absolute links.\n */\n contactsItem?: { href?: string; children?: NavItem[] }\n /**\n * The trailing \"Support\" row. VRM core opens its SupportRequestModal here;\n * other apps supply their own handler (`onClick`) or a link (`href`).\n * Omitted or `false` → no Support row.\n */\n supportItem?: { onClick?: () => void; href?: string } | false\n}\n\n/** Core-relative route + icon slot for one standard entry. */\ntype CoreLeaf = { label: string; icon: StandardNavIconKey; path: string }\n\nconst CONTACTS_DEFAULT_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/contacts/dashboard' },\n { label: 'All Contacts', icon: 'list', path: '/relationship/contacts/all' },\n { label: 'Tribes', icon: 'users', path: '/relationship/contacts/groups' },\n { label: 'Import', icon: 'upload', path: '/relationship/contacts/import' },\n { label: 'Import History', icon: 'fileText', path: '/relationship/contacts/import-history' },\n { label: 'Merge Rules', icon: 'layout', path: '/relationship/contacts/merge-rules' },\n]\n\nconst EMAIL_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/email/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/email/create-and-edit' },\n { label: 'Sender Information', icon: 'mail', path: '/relationship/email/inbox' },\n { label: 'Recipients', icon: 'user', path: '/relationship/email/send-to' },\n { label: 'Send & Automate', icon: 'clock', path: '/relationship/email/send-and-automate' },\n { label: 'Statistics', icon: 'barChart', path: '/relationship/email/statistics' },\n]\n\nconst SMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/sms-mms-blast/dashboard' },\n { label: 'Compose & Send', icon: 'send', path: '/relationship/sms-mms-blast/compose-and-send' },\n { label: 'Conversations', icon: 'messageSquare', path: '/relationship/sms-mms-blast/conversations' },\n]\n\nconst CTA_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/cta-database/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/cta-creator/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/cta-submissions/submissions' },\n]\n\nconst FORMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/forms' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/forms/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/forms/submissions' },\n]\n\n/**\n * Build the standard Politogy VRM menu (relationship mode), in the exact order\n * and wording the main app renders it. See `StandardNavOptions` for the two\n * app-specific hooks (`contactsItem`, `supportItem`).\n */\nexport function standardPolitogyNav(opts: StandardNavOptions): NavItem[] {\n const base = opts.coreBaseUrl.replace(/\\/+$/, '')\n const abs = (path: string): string => `${base}${path.startsWith('/') ? path : `/${path}`}`\n const icon = (key: StandardNavIconKey): NavIcon | undefined => opts.icons?.[key]\n const leaves = (children: CoreLeaf[]): NavItem[] =>\n children.map((c) => ({ label: c.label, icon: icon(c.icon), href: abs(c.path) }))\n\n const contacts: NavItem = opts.contactsItem\n ? {\n label: 'Contacts',\n icon: icon('users'),\n href: opts.contactsItem.href,\n children: opts.contactsItem.children,\n }\n : {\n label: 'Contacts',\n icon: icon('users'),\n href: abs('/relationship/contacts/dashboard'),\n children: leaves(CONTACTS_DEFAULT_CHILDREN),\n }\n\n const items: NavItem[] = [\n { label: 'Dashboard', icon: icon('home'), href: abs('/relationship/dashboard') },\n contacts,\n {\n label: 'Email Broadcast',\n icon: icon('mail'),\n href: abs('/relationship/email/dashboard'),\n children: leaves(EMAIL_CHILDREN),\n },\n {\n label: 'SMS/MMS Blast',\n icon: icon('messageSquare'),\n href: abs('/relationship/sms-mms-blast/dashboard'),\n children: leaves(SMS_CHILDREN),\n },\n // These two carry no top-level href in VRM core (parent row only toggles).\n { label: 'Calls to Action', icon: icon('layout'), children: leaves(CTA_CHILDREN) },\n { label: 'Forms & Surveys', icon: icon('activity'), children: leaves(FORMS_CHILDREN) },\n ]\n\n if (opts.supportItem) {\n items.push({\n label: 'Support',\n icon: icon('lifeBuoy'),\n href: opts.supportItem.href,\n onClick: opts.supportItem.onClick,\n })\n }\n\n return items\n}\n","// ---------------------------------------------------------------------------\n// Framework-agnostic chrome (sidebar + top navbar) for @the-portland-company/shell.\n//\n// The other chrome in this package (ShellChrome, Sidebar, Header, …) is built\n// on Chakra UI v2 + react-router and targets Vite SPAs. That stack cannot be\n// imported into a Next.js / React 19 / Tailwind app. This \"native\" module is a\n// dependency-light alternative: pure React (no Chakra, no emotion, no\n// react-router, no icon library) whose styling is driven entirely by the CSS\n// design tokens shipped in `@the-portland-company/shell/chrome.css`.\n//\n// It is a FAITHFUL VISUAL TWIN of the Chakra chrome (Sidebar.tsx / Header.tsx /\n// OrgPill / ModePill / NavItem / UserMenu): same 240px sidebar, brand-logo\n// slot, \"ORGANIZATION\" org pill, mode pill, solid active nav rows, pipe-\n// separated footer links + commit string, and an avatar+name+email+chevron user\n// menu — so an app rendering this looks identical to the main VRM app.\n//\n// Every app concern (nav items, org, mode, user, links, icons, the routing\n// Link component, the theme toggle) is injected via props, so both the Contacts\n// app (Next.js) and the VRM app could consume the same components.\n// ---------------------------------------------------------------------------\n\nimport type { ComponentType, CSSProperties, ReactNode } from 'react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTopBarIconSlotGlyph, type TopBarIconSlot } from '../lib/topbarIconSlot'\nimport { resolveBrandGlyph } from '../lib/brandGlyphs'\n\n// An icon is any component that accepts an optional size + className. This\n// matches both `lucide-react` and `react-icons` icon signatures, so consuming\n// apps pass their own icon set without this package depending on one.\nexport type NavIcon = ComponentType<{ size?: number; className?: string }>\n\nexport type NavItem = {\n /** Route to link to. Optional when `onClick` is supplied (renders a button). */\n href?: string\n label: string\n icon?: NavIcon\n /**\n * When supplied the row renders as a `<button>` (styled identically to the\n * link rows) instead of a routed link — used for actions like \"Support\".\n */\n onClick?: () => void\n /**\n * Nested sub-items. When present, the row becomes an expandable GROUP header:\n * clicking it toggles the children open/closed (it never navigates, even if\n * `href` is set) and renders a right-aligned chevron that rotates 180° when\n * open. The sidebar runs a single-open accordion (opening one group closes\n * the others) and auto-expands whichever group contains the active route —\n * mirroring the main VRM app's Chakra sidebar. Children render as smaller nav\n * rows on a lighter panel and support both `href` links and `onClick` actions.\n */\n children?: NavItem[]\n}\n\n// The routing primitive is injected so each app supplies its own (Next.js\n// `<Link>`, react-router `<Link>`, or a plain `<a>`). Defaults to an anchor.\nexport type NavLinkProps = {\n href: string\n className?: string\n 'aria-current'?: 'page' | undefined\n children: ReactNode\n // Optional passthrough attributes so the same injected link can back a\n // routed nav row OR a routed tab (which needs ARIA tab semantics + inline\n // token geometry). Next.js `<Link>`, react-router `<Link>` and a plain <a>\n // all accept these DOM props, and DefaultLink spreads them onto its anchor.\n role?: string\n 'aria-selected'?: boolean\n 'aria-label'?: string\n title?: string\n style?: CSSProperties\n}\nexport type NavLinkComponent = ComponentType<NavLinkProps>\n\n/**\n * URL-scheme allow-list for host-supplied hrefs. React does not neutralize\n * `javascript:`/`data:` schemes on anchor href, so any app-supplied nav/footer/\n * action href must be validated before it reaches the DOM. Permits absolute\n * http(s), mailto/tel, and in-app relative targets; everything else → '#'.\n */\nconst safeHref = (h?: string) =>\n h && /^(https?:|mailto:|tel:|\\/|#|\\.)/i.test(h.trim()) ? h : '#'\n\nconst DefaultLink: NavLinkComponent = ({ href, children, ...rest }) => (\n <a href={safeHref(href)} {...rest}>\n {children}\n </a>\n)\n\n/** Default active-route test: exact match for \"/\", prefix match otherwise. */\nexport function isNavItemActive(pathname: string, href: string): boolean {\n if (href === '/') return pathname === '/'\n return pathname === href || pathname.startsWith(`${href}/`)\n}\n\n/**\n * Stable identity for an expandable nav group's accordion state. Prefers the\n * item's href; falls back to an index-scoped label so two groups can never\n * collide even when they share a label and have no href.\n */\nfunction groupKeyOf(item: NavItem, index: number): string {\n return item.href ?? `nav-group-${index}-${item.label}`\n}\n\n/** True when any of a group's children links to the active route. */\nfunction hasActiveChild(\n item: NavItem,\n pathname: string,\n activeFn: (pathname: string, href: string) => boolean,\n): boolean {\n return (item.children ?? []).some((child) =>\n child.href ? activeFn(pathname, child.href) : false,\n )\n}\n\n/**\n * Color-coded tone classes for the sidebar environment chip, matching the main\n * VRM app: prod red, staging orange, local/dev green, unknown gray.\n */\nexport function envChipClasses(label: string): string {\n const l = label.toLowerCase()\n if (l === 'production' || l === 'prod')\n return 'bg-[#fee2e2] text-[#ef4444]'\n if (l === 'staging' || l === 'stage')\n return 'bg-[#ffedd5] text-[#f97316]'\n if (l === 'local' || l === 'development' || l === 'dev')\n return 'bg-[#dcfce7] text-[#22c55e]'\n return 'bg-[rgba(107,114,128,0.16)] text-[#6b7280]'\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavBrand = {\n /** Where the logo links to. Defaults to \"/\". */\n homeHref?: string\n /**\n * Brand logo image src. When supplied this renders as the wordmark logo\n * (matching the main app's BrandLogo), and `badgeLabel`/`title`/`subtitle`\n * are used only as the no-image fallback.\n */\n logoSrc?: string\n logoAlt?: string\n /** Short label shown inside the brand badge fallback (e.g. \"P\"). */\n badgeLabel: string\n title: string\n subtitle?: string\n}\n\nexport type NavOrg = {\n name: string | null\n /** Full org id. When present, a copy affordance is shown by the label. */\n id?: string | null\n /** Optional org logo for the pill badge; falls back to initials. */\n logoUrl?: string | null\n /** Solid pill background (the org's brand color). Defaults to race red. */\n brandColor?: string | null\n onClick?: () => void\n}\n\nexport type NavMode = {\n label: string\n icon?: NavIcon\n}\n\nexport type NavFooterLink = { label: string; href: string; external?: boolean }\n\nexport type NavFooter = {\n envLabel: string\n version: string\n commit: string\n links?: NavFooterLink[]\n /** ISO date (or any Date-parseable string) of the deployed commit. */\n commitDate?: string\n /** Full name of the commit author (only the first name is shown). */\n commitAuthor?: string\n}\n\nexport type NavSidebarProps = {\n pathname: string\n brand: NavBrand\n nav: {\n groupLabel?: string\n items: NavItem[]\n isActive?: (pathname: string, href: string) => boolean\n }\n org?: NavOrg | null\n mode?: NavMode | null\n footer?: NavFooter | null\n linkComponent?: NavLinkComponent\n}\n\n// Default org-pill background — race red, matching the main app's fallback\n// (mode primary) when an org has no explicit brand color.\nconst ORG_PILL_DEFAULT = 'var(--color-race-red)'\n\nexport function NavSidebar({\n pathname,\n brand,\n nav,\n org,\n mode,\n footer,\n linkComponent,\n}: NavSidebarProps) {\n const Link = linkComponent ?? DefaultLink\n const activeFn = nav.isActive ?? isNavItemActive\n const ModeIcon = mode?.icon\n const orgBg = org?.brandColor || ORG_PILL_DEFAULT\n\n // Single-open accordion for expandable nav groups, mirroring the main VRM\n // app's Chakra sidebar. `activeGroupKey` is the group (if any) that owns the\n // current route; deriving it as a primitive string keeps the auto-expand\n // effect from firing when `nav.items` is a fresh array reference each render\n // (which would otherwise clobber a manual toggle).\n const activeGroupKey = useMemo(() => {\n for (let i = 0; i < nav.items.length; i++) {\n const item = nav.items[i]\n if (item.children && item.children.length > 0 && hasActiveChild(item, pathname, activeFn)) {\n return groupKeyOf(item, i)\n }\n }\n return null\n }, [nav.items, pathname, activeFn])\n\n // Seed the open group from the active route on first paint (no expand flash),\n // then keep it synced as the route changes. Manual toggles between route\n // changes are preserved because the effect only reruns when the *derived*\n // active group actually changes.\n const [openGroup, setOpenGroup] = useState<string | null>(activeGroupKey)\n useEffect(() => {\n setOpenGroup(activeGroupKey)\n }, [activeGroupKey])\n const toggleGroup = (key: string) =>\n setOpenGroup((prev) => (prev === key ? null : key))\n\n return (\n <aside className=\"fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--panel-elevated)] lg:flex\">\n {/* Brand — logo image (preferred) or badge fallback */}\n <Link\n href={brand.homeHref ?? '/'}\n className=\"flex h-[64px] flex-shrink-0 items-center gap-2.5 px-6\"\n >\n {brand.logoSrc ? (\n <img\n src={brand.logoSrc}\n alt={brand.logoAlt ?? brand.title}\n draggable={false}\n className=\"h-10 w-auto object-contain\"\n />\n ) : (\n <>\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-[color:var(--color-race-red)] text-base font-black text-white shadow-sm\">\n {brand.badgeLabel}\n </span>\n <span className=\"flex flex-col leading-tight\">\n <span className=\"text-base font-extrabold tracking-[-0.01em] text-[color:var(--color-race-red)]\">\n {brand.title}\n </span>\n {brand.subtitle ? (\n <span className=\"text-[11px] font-semibold uppercase tracking-[0.16em] text-[color:var(--muted)]\">\n {brand.subtitle}\n </span>\n ) : null}\n </span>\n </>\n )}\n </Link>\n\n {/* Scroll region: org pill, mode pill, nav */}\n <div className=\"flex flex-1 flex-col overflow-y-auto px-4 pb-2\">\n {/* Organization switcher */}\n {org ? (\n <div className=\"mb-3\">\n <div className=\"mb-2 flex items-center justify-between px-1\">\n <p className=\"text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Organization\n </p>\n {org.id ? <OrgIdCopyButton id={org.id} /> : null}\n </div>\n <button\n type=\"button\"\n onClick={org.onClick}\n style={{ backgroundColor: orgBg }}\n className=\"flex w-full items-center justify-between gap-2 rounded-md px-2.5 py-2 text-left text-white shadow-sm transition hover:opacity-95\"\n >\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-white/20 text-[11px] font-bold text-white\">\n {org.logoUrl ? (\n <img src={org.logoUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n (org.name ?? 'Org').slice(0, 2).toUpperCase()\n )}\n </span>\n <span className=\"truncate text-sm font-semibold\">\n {org.name ?? 'No organizations'}\n </span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Mode pill */}\n {mode ? (\n <div className=\"mb-4\">\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 rounded-md bg-[color:var(--color-race-red)] px-2.5 py-2 text-white shadow-sm\"\n >\n <span className=\"flex items-center gap-2.5\">\n {ModeIcon ? <ModeIcon size={16} className=\"shrink-0\" /> : null}\n <span className=\"text-sm font-semibold tracking-[-0.01em]\">{mode.label}</span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Nav list */}\n <nav className=\"flex flex-col gap-1\">\n {nav.groupLabel ? (\n <p className=\"px-2 pb-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n {nav.groupLabel}\n </p>\n ) : null}\n {nav.items.map((item, idx) => {\n // Expandable group: renders a toggle header + collapsible children.\n if (item.children && item.children.length > 0) {\n const key = groupKeyOf(item, idx)\n const selfActive = item.href ? activeFn(pathname, item.href) : false\n const parentActive = selfActive || hasActiveChild(item, pathname, activeFn)\n return (\n <NavGroup\n key={key}\n item={item}\n active={parentActive}\n open={openGroup === key}\n onToggle={() => toggleGroup(key)}\n pathname={pathname}\n activeFn={activeFn}\n Link={Link}\n />\n )\n }\n const active = item.href ? activeFn(pathname, item.href) : false\n return (\n <NavRow\n key={item.href ?? `nav-${idx}-${item.label}`}\n item={item}\n active={active}\n Link={Link}\n />\n )\n })}\n </nav>\n </div>\n\n {/* Footer — pipe-separated links + commit/version string */}\n {footer ? (\n <div className=\"flex-shrink-0 border-t border-[color:var(--line)] px-4 py-3\">\n {footer.links && footer.links.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-1.5 text-xs\">\n {footer.links.map((l, idx) => (\n <span key={l.label} className=\"inline-flex items-center gap-1.5\">\n {idx > 0 ? <span className=\"text-[color:var(--muted)]\">|</span> : null}\n <a\n href={safeHref(l.href)}\n className=\"font-medium text-[color:var(--color-race-red)] hover:underline\"\n >\n {l.label}\n </a>\n </span>\n ))}\n </div>\n ) : null}\n <div className=\"mt-1.5 flex flex-col items-center gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--muted)]\">\n {/* Row 1: env chip | commit | version */}\n <div className=\"flex items-center gap-1.5\">\n <span\n className={[\n 'rounded-md px-1.5 py-0.5 text-[10px] font-semibold',\n envChipClasses(footer.envLabel),\n ].join(' ')}\n >\n {footer.envLabel}\n </span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>{footer.commit.slice(-4)}</span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>v{footer.version}</span>\n </div>\n {/* Row 2: date | author (only when supplied) */}\n {footer.commitDate || footer.commitAuthor ? (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitDate ? (\n <span>\n {new Date(footer.commitDate).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitAuthor ? (\n <span>{footer.commitAuthor.split(/\\s+/)[0]}</span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n </div>\n ) : null}\n </div>\n </div>\n ) : null}\n </aside>\n )\n}\n\n// Inline chevron-down (mirrors lucide `ChevronDown`) — no icon dependency.\n// Callers may override `className` to add a rotation (used by expandable groups).\nfunction ChevronDown({ className }: { className?: string } = {}) {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className ?? 'shrink-0 opacity-80'}\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\n// A single sidebar nav row. Renders as a routed <Link> (href) or a <button>\n// (onClick), styled identically. Inactive rows animate a left→right gradient\n// sweep on hover (matching the main app); active rows keep solid race-red.\n//\n// `variant=\"sub\"` renders the smaller child rows inside an expanded group: a\n// tighter row whose ACTIVE state is a lighter elevated surface with race-red\n// text (not a solid-red fill — that stays reserved for top-level/parent rows,\n// exactly as the main VRM app's Chakra sidebar treats active sub-items).\n// Specs race-red ramp (hover → active primary).\nconst NAV_HOVER_GRADIENT = 'linear-gradient(90deg,#EA4751 0%,#E63946 100%)'\n\nfunction NavRow({\n item,\n active,\n Link,\n variant = 'top',\n}: {\n item: NavItem\n active: boolean\n Link: NavLinkComponent\n variant?: 'top' | 'sub'\n}) {\n const Icon = item.icon\n const isSub = variant === 'sub'\n const activeClasses = isSub\n ? 'bg-[color:var(--panel-elevated)] text-[color:var(--color-race-red)] shadow-sm'\n : 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n const wrapperClasses = [\n 'group relative block overflow-hidden rounded-md transition',\n active ? activeClasses : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n const rowPadding = isSub ? 'px-3 py-1.5 text-[13px]' : 'px-3 py-2 text-sm'\n const iconSize = isSub ? 16 : 18\n // Top-level active rows use white glyphs on the red fill; sub-item active\n // rows inherit the race-red text color via `text-current`.\n const iconClass = active && !isSub ? 'text-white' : 'text-current'\n\n const inner = (\n <>\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className={`relative z-10 flex items-center gap-3 font-semibold ${rowPadding}`}>\n {Icon ? <Icon size={iconSize} className={iconClass} /> : null}\n {item.label}\n </span>\n </>\n )\n\n if (item.onClick && !item.href) {\n return (\n <button type=\"button\" onClick={item.onClick} className={`w-full text-left ${wrapperClasses}`}>\n {inner}\n </button>\n )\n }\n\n return (\n <Link\n href={item.href ?? '#'}\n aria-current={active ? 'page' : undefined}\n className={wrapperClasses}\n >\n {inner}\n </Link>\n )\n}\n\n// An expandable nav GROUP: a toggle header + a collapsible list of child rows.\n// Faithful twin of the main VRM app's Chakra accordion (Sidebar.tsx /\n// NavItem.tsx):\n// - Clicking the header toggles the children — it never navigates, even when\n// the group carries an `href`.\n// - A right-aligned chevron rotates 180° when open.\n// - The header goes solid race-red (white text) when the group owns the active\n// route (its own href OR any child), matching top-level active rows; when\n// merely open it lifts onto the `--panel` surface; otherwise it's a muted row\n// with the same left→right gradient hover sweep as every other nav row.\n// - Children sit on the lighter `--panel` surface, indented and rounded, each\n// rendered through the SAME injected LinkComponent (or as a button for\n// `onClick` children) via <NavRow variant=\"sub\" />.\nfunction NavGroup({\n item,\n active,\n open,\n onToggle,\n pathname,\n activeFn,\n Link,\n}: {\n item: NavItem\n active: boolean\n open: boolean\n onToggle: () => void\n pathname: string\n activeFn: (pathname: string, href: string) => boolean\n Link: NavLinkComponent\n}) {\n const Icon = item.icon\n const headerClasses = [\n 'group relative block w-full overflow-hidden text-left transition',\n open ? 'rounded-t-md' : 'rounded-md',\n active\n ? 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n : open\n ? 'bg-[color:var(--panel)] text-[color:var(--foreground)]'\n : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n return (\n <div>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n className={headerClasses}\n >\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className=\"relative z-10 flex items-center gap-3 px-3 py-2 text-sm font-semibold\">\n {Icon ? (\n <Icon size={18} className={active ? 'text-white' : 'text-current'} />\n ) : null}\n <span className=\"flex-1\">{item.label}</span>\n <ChevronDown\n className={[\n 'shrink-0 opacity-80 transition-transform duration-200',\n open ? 'rotate-180' : '',\n ].join(' ')}\n />\n </span>\n </button>\n\n {open ? (\n <div className=\"overflow-hidden rounded-b-md bg-[color:var(--panel)] p-1\">\n <div className=\"flex flex-col gap-0.5\">\n {item.children!.map((child, i) => {\n const childActive = child.href ? activeFn(pathname, child.href) : false\n return (\n <NavRow\n key={child.href ?? `sub-${i}-${child.label}`}\n item={child}\n active={childActive}\n Link={Link}\n variant=\"sub\"\n />\n )\n })}\n </div>\n </div>\n ) : null}\n </div>\n )\n}\n\n// Right-aligned copy affordance for the org id, shown beside the \"Organization\"\n// label. Copies the full id and briefly swaps its text to \"Copied\".\nfunction OrgIdCopyButton({ id }: { id: string }) {\n const [copied, setCopied] = useState(false)\n return (\n <button\n type=\"button\"\n onClick={() => {\n try {\n void navigator.clipboard?.writeText(id)\n } catch {\n /* clipboard unavailable — ignore */\n }\n setCopied(true)\n setTimeout(() => setCopied(false), 1500)\n }}\n title=\"Copy organization id\"\n className=\"rounded px-1 text-[11px] text-[color:var(--muted)] hover:bg-[color:var(--panel)]\"\n >\n {copied ? 'Copied' : `...${id.slice(-8)}`}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavUser = {\n name: string | null\n email?: string | null\n /** Avatar image URL; falls back to initials on the brand color. */\n avatarUrl?: string | null\n tier?: string | null\n role?: string | null\n}\n\nexport type NavTopBarAction = {\n key: string\n /**\n * Canonical top-bar slot. When set, the glyph is sourced by NAME from the\n * Brand API via `--topbar-icon-<slot>`; `icon` becomes the fallback used\n * until the runtime Brand stylesheet lands (or when the token is unset).\n */\n slot?: TopBarIconSlot\n icon: NavIcon\n label: string\n onClick?: () => void\n href?: string\n badge?: number | null\n tone?: 'default' | 'warning' | 'danger'\n}\n\nexport type NavTopBarProps = {\n title: string\n subtitle?: string\n user?: NavUser | null\n onSignOut?: () => void\n /**\n * Structured icon-button action cluster (32×32 circular buttons with optional\n * count badges), rendered before the `actions` slot. Matches the main app's\n * topbar action icons.\n */\n actionsList?: NavTopBarAction[]\n /** App-specific action cluster rendered left of the theme toggle. */\n actions?: ReactNode\n /** Theme toggle slot (injected so this package needs no theme dependency). */\n themeToggle?: ReactNode\n}\n\nexport function NavTopBar({\n title,\n subtitle,\n user,\n onSignOut,\n actionsList,\n actions,\n themeToggle,\n}: NavTopBarProps) {\n const initials = (user?.name ?? 'Politogy').slice(0, 2).toUpperCase()\n const secondary = user?.email || [user?.tier, user?.role].filter(Boolean).join(' · ') || 'member'\n return (\n <header className=\"sticky top-0 z-20 flex h-20 items-center justify-between gap-4 border-b border-[color:var(--line)] bg-[color:var(--panel)] px-4 backdrop-blur-xl\">\n <div className=\"min-w-0\">\n <h1\n className=\"truncate text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]\"\n data-display=\"true\"\n >\n {title}\n </h1>\n {subtitle ? (\n <p className=\"truncate text-sm text-[color:var(--muted)]\">{subtitle}</p>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]\">\n {actionsList && actionsList.length > 0\n ? actionsList.map((action) => (\n <NavTopBarActionButton key={action.key} action={action} />\n ))\n : null}\n {actions}\n {themeToggle}\n\n {/* User menu — avatar + name/email + chevron; sign-out in a native\n <details> popover so the package needs no JS state. */}\n <details className=\"group relative\">\n <summary className=\"flex cursor-pointer list-none items-center gap-2.5 rounded-full py-1 pl-1 pr-2 transition hover:bg-[color:var(--panel-elevated)] [&::-webkit-details-marker]:hidden\">\n <span className=\"flex h-9 w-9 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-race-red)] text-xs font-bold text-white\">\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n initials\n )}\n </span>\n <span className=\"hidden flex-col leading-tight md:flex\">\n <span className=\"text-sm font-semibold text-[color:var(--foreground)]\">\n {user?.name ?? 'Signed in'}\n </span>\n <span className=\"text-xs text-[color:var(--muted)]\">{secondary}</span>\n </span>\n <ChevronDown />\n </summary>\n {onSignOut ? (\n <div className=\"absolute right-0 z-30 mt-2 w-44 overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]\">\n <button\n type=\"button\"\n onClick={onSignOut}\n className=\"flex w-full items-center gap-2.5 px-4 py-2 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-race-red)]\"\n >\n <SignOutIcon />\n Sign out\n </button>\n </div>\n ) : null}\n </details>\n </div>\n </header>\n )\n}\n\n// Inline log-out glyph (mirrors lucide `LogOut`) to avoid an icon dependency.\nfunction SignOutIcon() {\n return (\n <svg\n width={15}\n height={15}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n\n// A single 32×32 circular icon button for the top bar's structured action list.\n// Renders an <a> when `href` is present (external links open in a new tab),\n// otherwise a <button>. Shows a red count badge when `badge > 0`.\nfunction NavTopBarActionButton({ action }: { action: NavTopBarAction }) {\n const Icon = action.icon\n const tone = action.tone ?? 'default'\n // Universal treatment (Global Rules v9): size, color and hover are a single\n // shared value across every top-bar slot — only the glyph varies per slot.\n // Tone is a semantic state, not a bespoke per-slot style.\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 const className = [\n '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 // Per-slot glyph from Brand; `icon` is the fallback until the token resolves.\n // Brand emits Feather/Lucide glyph NAMES, not asset paths.\n const glyphName = useTopBarIconSlotGlyph(action.slot ?? 'apps')\n const BrandGlyph = action.slot ? resolveBrandGlyph(glyphName) : null\n const Glyph = BrandGlyph ?? Icon\n\n const content = (\n <>\n <Glyph size={20} className=\"text-current\" />\n {typeof action.badge === 'number' && action.badge > 0 ? (\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 {action.badge}\n </span>\n ) : null}\n </>\n )\n\n const isExternal = action.href ? /^https?:\\/\\//.test(action.href) : false\n\n if (action.href) {\n return (\n <a\n href={safeHref(action.href)}\n aria-label={action.label}\n title={action.label}\n className={className}\n {...(isExternal ? { target: '_blank', rel: 'noreferrer' } : {})}\n >\n {content}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={action.onClick}\n aria-label={action.label}\n title={action.label}\n className={className}\n >\n {content}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Icon-only tab strip — the standard secondary navigation the three Next.js\n// worker apps (Forms / Surveys / Polls) render below the top bar: a horizontal\n// row of icon-only tabs where the SELECTED tab merges into the content panel\n// below it (top/left/right border, no bottom border, sharing --tab-content-bg).\n//\n// A faithful twin of the hand-rolled `.tabstrip`/`.tab-strip` markup those apps\n// carried, promoted into the shell so every app renders the same accessible,\n// token-driven strip. All geometry is driven by the Brand `--tab-*` CSS vars\n// shipped in chrome.css (with literal fallbacks so the strip still renders in\n// an app that hasn't loaded the runtime tokens link yet):\n// --tab-height (row height) · --tab-icon-size (glyph) · --tab-radius (top\n// corners) · --tab-gap (between tabs) · --tab-content-bg (selected + panel\n// surface) · --tab-unselected-opacity (dimmed inactive tabs, default 0.6).\n// ---------------------------------------------------------------------------\n\nexport type NavTab = {\n /** Stable identity (used as the React key). */\n key: string\n /** Accessible name — becomes both the `title` tooltip and `aria-label`. */\n label: string\n icon: NavIcon\n /** Route to link to (rendered through `linkComponent`). */\n href?: string\n /** Click handler — rendered as a `<button>` when there's no `href`. */\n onSelect?: () => void\n /** Whether this tab is the active one (drives the merged-panel geometry). */\n selected?: boolean\n /**\n * Non-interactive, dimmed tab (e.g. Surveys' Canvas/Results before a survey\n * is chosen). Renders a non-navigating span; `disabledTitle` overrides the\n * tooltip to explain why (falls back to `label`).\n */\n disabled?: boolean\n disabledTitle?: string\n}\n\nexport type NavTabStripProps = {\n tabs: NavTab[]\n /** Accessible name for the tablist. */\n 'aria-label'?: string\n /** Routing primitive for `href` tabs (Next `<Link>`, etc). Defaults to <a>. */\n linkComponent?: NavLinkComponent\n /** Extra classes on the tablist container. */\n className?: string\n /**\n * Optional content panel rendered directly below the strip. When supplied it\n * renders on the shared `--tab-content-bg` surface with a square top-left\n * corner so the selected tab visually merges into it. Omit to render only the\n * strip and compose the panel yourself.\n */\n children?: ReactNode\n}\n\n/** Default icon glyph size — mirrors the `--tab-icon-size` token default. */\nconst TAB_ICON_SIZE = 18\n\nfunction NavTabButton({\n tab,\n Link,\n}: {\n tab: NavTab\n Link: NavLinkComponent\n}) {\n const { label, icon: Icon, href, onSelect, selected, disabled, disabledTitle } = tab\n const title = disabled ? disabledTitle ?? label : label\n\n // Base geometry shared by every state. Selected tabs sit above the content\n // panel (`z-10`) so their missing bottom border merges cleanly into it.\n const base =\n 'inline-flex shrink-0 items-center justify-center border border-b-0 transition-opacity'\n const stateClass = disabled\n ? 'cursor-not-allowed border-transparent opacity-40'\n : selected\n ? 'relative z-10 opacity-100 border-[color:var(--line)]'\n : 'border-transparent opacity-[var(--tab-unselected-opacity,0.6)] hover:opacity-90'\n const className = `${base} ${stateClass}`\n\n const style: CSSProperties = {\n height: 'var(--tab-height, 44px)',\n width: 'var(--tab-width, 3rem)',\n color: 'var(--foreground)',\n borderTopLeftRadius: 'var(--tab-radius, 12px)',\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n ...(selected ? { background: 'var(--tab-content-bg)' } : null),\n }\n\n const glyph = <Icon size={TAB_ICON_SIZE} className=\"text-current\" />\n\n // Disabled: non-navigating span, still exposed as a tab for AT.\n if (disabled) {\n return (\n <span\n role=\"tab\"\n aria-selected={false}\n aria-disabled=\"true\"\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </span>\n )\n }\n\n if (href) {\n return (\n <Link\n href={href}\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </Link>\n )\n }\n\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n onClick={onSelect}\n className={className}\n style={style}\n >\n {glyph}\n </button>\n )\n}\n\n/**\n * Icon-only, token-driven tab strip. Render it below `NavTopBar`; pass the\n * app's `Link` as `linkComponent` for `href` tabs. Supply `children` to get the\n * merged content panel, or omit it and compose your own panel on\n * `var(--tab-content-bg)`.\n */\nexport function NavTabStrip({\n tabs,\n 'aria-label': ariaLabel,\n linkComponent,\n className,\n children,\n}: NavTabStripProps) {\n const Link = linkComponent ?? DefaultLink\n return (\n <>\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n className={['flex items-end gap-[var(--tab-gap,8px)]', className]\n .filter(Boolean)\n .join(' ')}\n >\n {tabs.map((tab) => (\n <NavTabButton key={tab.key} tab={tab} Link={Link} />\n ))}\n </div>\n {children !== undefined ? (\n <div\n className=\"relative -mt-px border border-[color:var(--line)] p-5\"\n style={{\n background: 'var(--tab-content-bg)',\n borderTopLeftRadius: 0,\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n borderBottomLeftRadius: 'var(--tab-radius, 12px)',\n borderBottomRightRadius: 'var(--tab-radius, 12px)',\n }}\n >\n {children}\n </div>\n ) : null}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavAppShellProps = {\n sidebar: NavSidebarProps\n topBar: NavTopBarProps\n children: ReactNode\n}\n\n/**\n * Full chrome: branded left sidebar + sticky top navbar + scrollable content\n * region. Presentational only — wrap it in app-level auth/gating as needed.\n */\nexport function NavAppShell({ sidebar, topBar, children }: NavAppShellProps) {\n return (\n <div className=\"min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]\">\n <NavSidebar {...sidebar} />\n <div className=\"lg:pl-[240px]\">\n <NavTopBar {...topBar} />\n <main className=\"px-6 py-7\">\n <div className=\"mx-auto max-w-7xl\">{children}</div>\n </main>\n </div>\n </div>\n )\n}\n\n// Canonical Politogy VRM menu — the standard nav structure every politogy app\n// renders, with hooks for the app-owned \"Contacts\" item and Support handler.\nexport {\n standardPolitogyNav,\n type StandardNavIconKey,\n type StandardNavOptions,\n} from './standardNav'\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/native/standardNav.ts","../src/native/index.tsx"],"names":[],"mappings":"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","file":"native.js","sourcesContent":["import type { NavIcon, NavItem } from './index'\n\n// ---------------------------------------------------------------------------\n// standardPolitogyNav — the canonical Politogy VRM menu.\n//\n// This is the single source of truth for the navigation every politogy app\n// renders (extracted verbatim from VRM core's relationship-mode sidebar,\n// `getRelationshipLinkItems`). Apps consume the same menu everywhere; an app\n// that owns one of the items (e.g. the standalone Contacts app) nests its own\n// pages as that item's children while every other entry links out to VRM core\n// as an absolute URL — full-page navigation with SSO shared across\n// *.politogyvrm.com.\n// ---------------------------------------------------------------------------\n\n/**\n * Icon slots used by the standard menu. The shell stays icon-library-agnostic:\n * callers map each key to their own icon components (lucide, react-icons, …).\n * A missing key simply renders that row without an icon.\n */\nexport type StandardNavIconKey =\n | 'home'\n | 'users'\n | 'mail'\n | 'messageSquare'\n | 'layout'\n | 'activity'\n | 'lifeBuoy'\n | 'grid'\n | 'list'\n | 'upload'\n | 'edit'\n | 'fileText'\n | 'send'\n | 'clock'\n | 'user'\n | 'barChart'\n\nexport interface StandardNavOptions {\n /** VRM core origin, e.g. \"https://app.politogyvrm.com\". Trailing slash OK. */\n coreBaseUrl: string\n /** Icon component per slot; omitted slots render icon-less rows. */\n icons?: Partial<Record<StandardNavIconKey, NavIcon>>\n /**\n * App-local override for the \"Contacts\" item. `children` are used verbatim\n * (NOT absolutized) so the owning app nests its own routes; `href` (also\n * verbatim) feeds active-detection for the group header. When omitted, the\n * item carries VRM core's own contacts sub-pages as absolute links.\n */\n contactsItem?: { href?: string; children?: NavItem[] }\n /**\n * The trailing \"Support\" row. VRM core opens its SupportRequestModal here;\n * other apps supply their own handler (`onClick`) or a link (`href`).\n * Omitted or `false` → no Support row.\n */\n supportItem?: { onClick?: () => void; href?: string } | false\n}\n\n/** Core-relative route + icon slot for one standard entry. */\ntype CoreLeaf = { label: string; icon: StandardNavIconKey; path: string }\n\nconst CONTACTS_DEFAULT_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/contacts/dashboard' },\n { label: 'All Contacts', icon: 'list', path: '/relationship/contacts/all' },\n { label: 'Tribes', icon: 'users', path: '/relationship/contacts/groups' },\n { label: 'Import', icon: 'upload', path: '/relationship/contacts/import' },\n { label: 'Import History', icon: 'fileText', path: '/relationship/contacts/import-history' },\n { label: 'Merge Rules', icon: 'layout', path: '/relationship/contacts/merge-rules' },\n]\n\nconst EMAIL_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/email/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/email/create-and-edit' },\n { label: 'Sender Information', icon: 'mail', path: '/relationship/email/inbox' },\n { label: 'Recipients', icon: 'user', path: '/relationship/email/send-to' },\n { label: 'Send & Automate', icon: 'clock', path: '/relationship/email/send-and-automate' },\n { label: 'Statistics', icon: 'barChart', path: '/relationship/email/statistics' },\n]\n\nconst SMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/sms-mms-blast/dashboard' },\n { label: 'Compose & Send', icon: 'send', path: '/relationship/sms-mms-blast/compose-and-send' },\n { label: 'Conversations', icon: 'messageSquare', path: '/relationship/sms-mms-blast/conversations' },\n]\n\nconst CTA_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/cta-database/dashboard' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/cta-creator/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/cta-submissions/submissions' },\n]\n\nconst FORMS_CHILDREN: CoreLeaf[] = [\n { label: 'Dashboard', icon: 'grid', path: '/relationship/forms' },\n { label: 'Create & Edit', icon: 'edit', path: '/relationship/forms/create-and-edit' },\n { label: 'Submissions', icon: 'fileText', path: '/relationship/forms/submissions' },\n]\n\n/**\n * Build the standard Politogy VRM menu (relationship mode), in the exact order\n * and wording the main app renders it. See `StandardNavOptions` for the two\n * app-specific hooks (`contactsItem`, `supportItem`).\n */\nexport function standardPolitogyNav(opts: StandardNavOptions): NavItem[] {\n const base = opts.coreBaseUrl.replace(/\\/+$/, '')\n const abs = (path: string): string => `${base}${path.startsWith('/') ? path : `/${path}`}`\n const icon = (key: StandardNavIconKey): NavIcon | undefined => opts.icons?.[key]\n const leaves = (children: CoreLeaf[]): NavItem[] =>\n children.map((c) => ({ label: c.label, icon: icon(c.icon), href: abs(c.path) }))\n\n const contacts: NavItem = opts.contactsItem\n ? {\n label: 'Contacts',\n icon: icon('users'),\n href: opts.contactsItem.href,\n children: opts.contactsItem.children,\n }\n : {\n label: 'Contacts',\n icon: icon('users'),\n href: abs('/relationship/contacts/dashboard'),\n children: leaves(CONTACTS_DEFAULT_CHILDREN),\n }\n\n const items: NavItem[] = [\n { label: 'Dashboard', icon: icon('home'), href: abs('/relationship/dashboard') },\n contacts,\n {\n label: 'Email Broadcast',\n icon: icon('mail'),\n href: abs('/relationship/email/dashboard'),\n children: leaves(EMAIL_CHILDREN),\n },\n {\n label: 'SMS/MMS Blast',\n icon: icon('messageSquare'),\n href: abs('/relationship/sms-mms-blast/dashboard'),\n children: leaves(SMS_CHILDREN),\n },\n // These two carry no top-level href in VRM core (parent row only toggles).\n { label: 'Calls to Action', icon: icon('layout'), children: leaves(CTA_CHILDREN) },\n { label: 'Forms & Surveys', icon: icon('activity'), children: leaves(FORMS_CHILDREN) },\n ]\n\n if (opts.supportItem) {\n items.push({\n label: 'Support',\n icon: icon('lifeBuoy'),\n href: opts.supportItem.href,\n onClick: opts.supportItem.onClick,\n })\n }\n\n return items\n}\n","// ---------------------------------------------------------------------------\n// Framework-agnostic chrome (sidebar + top navbar) for @the-portland-company/shell.\n//\n// The other chrome in this package (ShellChrome, Sidebar, Header, …) is built\n// on Chakra UI v2 + react-router and targets Vite SPAs. That stack cannot be\n// imported into a Next.js / React 19 / Tailwind app. This \"native\" module is a\n// dependency-light alternative: pure React (no Chakra, no emotion, no\n// react-router, no icon library) whose styling is driven entirely by the CSS\n// design tokens shipped in `@the-portland-company/shell/chrome.css`.\n//\n// It is a FAITHFUL VISUAL TWIN of the Chakra chrome (Sidebar.tsx / Header.tsx /\n// OrgPill / ModePill / NavItem / UserMenu): same 240px sidebar, brand-logo\n// slot, \"ORGANIZATION\" org pill, mode pill, solid active nav rows, pipe-\n// separated footer links + commit string, and an avatar+name+email+chevron user\n// menu — so an app rendering this looks identical to the main VRM app.\n//\n// Every app concern (nav items, org, mode, user, links, icons, the routing\n// Link component, the theme toggle) is injected via props, so both the Contacts\n// app (Next.js) and the VRM app could consume the same components.\n// ---------------------------------------------------------------------------\n\nimport type { ComponentType, CSSProperties, ReactNode } from 'react'\nimport { useEffect, useMemo, useState } from 'react'\nimport { useTopBarIconSlotGlyph, type TopBarIconSlot } from '../lib/topbarIconSlot'\nimport { resolveBrandGlyph } from '../lib/brandGlyphs'\n\n// An icon is any component that accepts an optional size + className. This\n// matches both `lucide-react` and `react-icons` icon signatures, so consuming\n// apps pass their own icon set without this package depending on one.\nexport type NavIcon = ComponentType<{ size?: number; className?: string }>\n\nexport type NavItem = {\n /** Route to link to. Optional when `onClick` is supplied (renders a button). */\n href?: string\n label: string\n icon?: NavIcon\n /**\n * When supplied the row renders as a `<button>` (styled identically to the\n * link rows) instead of a routed link — used for actions like \"Support\".\n */\n onClick?: () => void\n /**\n * Nested sub-items. When present, the row becomes an expandable GROUP header:\n * clicking it toggles the children open/closed (it never navigates, even if\n * `href` is set) and renders a right-aligned chevron that rotates 180° when\n * open. The sidebar runs a single-open accordion (opening one group closes\n * the others) and auto-expands whichever group contains the active route —\n * mirroring the main VRM app's Chakra sidebar. Children render as smaller nav\n * rows on a lighter panel and support both `href` links and `onClick` actions.\n */\n children?: NavItem[]\n}\n\n// The routing primitive is injected so each app supplies its own (Next.js\n// `<Link>`, react-router `<Link>`, or a plain `<a>`). Defaults to an anchor.\nexport type NavLinkProps = {\n href: string\n className?: string\n 'aria-current'?: 'page' | undefined\n children: ReactNode\n // Optional passthrough attributes so the same injected link can back a\n // routed nav row OR a routed tab (which needs ARIA tab semantics + inline\n // token geometry). Next.js `<Link>`, react-router `<Link>` and a plain <a>\n // all accept these DOM props, and DefaultLink spreads them onto its anchor.\n role?: string\n 'aria-selected'?: boolean\n 'aria-label'?: string\n title?: string\n style?: CSSProperties\n}\nexport type NavLinkComponent = ComponentType<NavLinkProps>\n\n/**\n * URL-scheme allow-list for host-supplied hrefs. React does not neutralize\n * `javascript:`/`data:` schemes on anchor href, so any app-supplied nav/footer/\n * action href must be validated before it reaches the DOM. Permits absolute\n * http(s), mailto/tel, and in-app relative targets; everything else → '#'.\n */\nconst safeHref = (h?: string) =>\n h && /^(https?:|mailto:|tel:|\\/|#|\\.)/i.test(h.trim()) ? h : '#'\n\nconst DefaultLink: NavLinkComponent = ({ href, children, ...rest }) => (\n <a href={safeHref(href)} {...rest}>\n {children}\n </a>\n)\n\n/** Default active-route test: exact match for \"/\", prefix match otherwise. */\nexport function isNavItemActive(pathname: string, href: string): boolean {\n if (href === '/') return pathname === '/'\n return pathname === href || pathname.startsWith(`${href}/`)\n}\n\n/**\n * Stable identity for an expandable nav group's accordion state. Prefers the\n * item's href; falls back to an index-scoped label so two groups can never\n * collide even when they share a label and have no href.\n */\nfunction groupKeyOf(item: NavItem, index: number): string {\n return item.href ?? `nav-group-${index}-${item.label}`\n}\n\n/** True when any of a group's children links to the active route. */\nfunction hasActiveChild(\n item: NavItem,\n pathname: string,\n activeFn: (pathname: string, href: string) => boolean,\n): boolean {\n return (item.children ?? []).some((child) =>\n child.href ? activeFn(pathname, child.href) : false,\n )\n}\n\n/**\n * Color-coded tone classes for the sidebar environment chip, matching the main\n * VRM app: prod red, staging orange, local/dev green, unknown gray.\n */\nexport function envChipClasses(label: string): string {\n const l = label.toLowerCase()\n if (l === 'production' || l === 'prod')\n return 'bg-[#fee2e2] text-[#ef4444]'\n if (l === 'staging' || l === 'stage')\n return 'bg-[#ffedd5] text-[#f97316]'\n if (l === 'local' || l === 'development' || l === 'dev')\n return 'bg-[#dcfce7] text-[#22c55e]'\n return 'bg-[rgba(107,114,128,0.16)] text-[#6b7280]'\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavBrand = {\n /** Where the logo links to. Defaults to \"/\". */\n homeHref?: string\n /**\n * Brand logo image src. When supplied this renders as the wordmark logo\n * (matching the main app's BrandLogo), and `badgeLabel`/`title`/`subtitle`\n * are used only as the no-image fallback.\n */\n logoSrc?: string\n logoAlt?: string\n /** Short label shown inside the brand badge fallback (e.g. \"P\"). */\n badgeLabel: string\n title: string\n subtitle?: string\n}\n\nexport type NavOrg = {\n name: string | null\n /** Full org id. When present, a copy affordance is shown by the label. */\n id?: string | null\n /** Optional org logo for the pill badge; falls back to initials. */\n logoUrl?: string | null\n /** Solid pill background (the org's brand color). Defaults to race red. */\n brandColor?: string | null\n onClick?: () => void\n}\n\nexport type NavMode = {\n label: string\n icon?: NavIcon\n}\n\nexport type NavFooterLink = { label: string; href: string; external?: boolean }\n\nexport type NavFooter = {\n envLabel: string\n version: string\n commit: string\n links?: NavFooterLink[]\n /** ISO date (or any Date-parseable string) of the deployed commit. */\n commitDate?: string\n /** Full name of the commit author (only the first name is shown). */\n commitAuthor?: string\n}\n\nexport type NavSidebarProps = {\n pathname: string\n brand: NavBrand\n nav: {\n groupLabel?: string\n items: NavItem[]\n isActive?: (pathname: string, href: string) => boolean\n }\n org?: NavOrg | null\n mode?: NavMode | null\n footer?: NavFooter | null\n linkComponent?: NavLinkComponent\n}\n\n// Default org-pill background — race red, matching the main app's fallback\n// (mode primary) when an org has no explicit brand color.\nconst ORG_PILL_DEFAULT = 'var(--color-race-red)'\n\nexport function NavSidebar({\n pathname,\n brand,\n nav,\n org,\n mode,\n footer,\n linkComponent,\n}: NavSidebarProps) {\n const Link = linkComponent ?? DefaultLink\n const activeFn = nav.isActive ?? isNavItemActive\n const ModeIcon = mode?.icon\n const orgBg = org?.brandColor || ORG_PILL_DEFAULT\n\n // Single-open accordion for expandable nav groups, mirroring the main VRM\n // app's Chakra sidebar. `activeGroupKey` is the group (if any) that owns the\n // current route; deriving it as a primitive string keeps the auto-expand\n // effect from firing when `nav.items` is a fresh array reference each render\n // (which would otherwise clobber a manual toggle).\n const activeGroupKey = useMemo(() => {\n for (let i = 0; i < nav.items.length; i++) {\n const item = nav.items[i]\n if (item.children && item.children.length > 0 && hasActiveChild(item, pathname, activeFn)) {\n return groupKeyOf(item, i)\n }\n }\n return null\n }, [nav.items, pathname, activeFn])\n\n // Seed the open group from the active route on first paint (no expand flash),\n // then keep it synced as the route changes. Manual toggles between route\n // changes are preserved because the effect only reruns when the *derived*\n // active group actually changes.\n const [openGroup, setOpenGroup] = useState<string | null>(activeGroupKey)\n useEffect(() => {\n setOpenGroup(activeGroupKey)\n }, [activeGroupKey])\n const toggleGroup = (key: string) =>\n setOpenGroup((prev) => (prev === key ? null : key))\n\n return (\n <aside className=\"fixed inset-y-0 left-0 z-30 hidden w-[240px] flex-col border-r border-[color:var(--line)] bg-[color:var(--nav-surface)] lg:flex\">\n {/* Brand — logo image (preferred) or badge fallback */}\n <Link\n href={brand.homeHref ?? '/'}\n className=\"flex h-[64px] flex-shrink-0 items-center gap-2.5 px-6\"\n >\n {brand.logoSrc ? (\n <img\n src={brand.logoSrc}\n alt={brand.logoAlt ?? brand.title}\n draggable={false}\n className=\"h-10 w-auto object-contain\"\n />\n ) : (\n <>\n <span className=\"flex h-9 w-9 items-center justify-center rounded-xl bg-[color:var(--color-race-red)] text-base font-black text-white shadow-sm\">\n {brand.badgeLabel}\n </span>\n <span className=\"flex flex-col leading-tight\">\n <span className=\"text-base font-extrabold tracking-[-0.01em] text-[color:var(--color-race-red)]\">\n {brand.title}\n </span>\n {brand.subtitle ? (\n <span className=\"text-[11px] font-semibold uppercase tracking-[0.16em] text-[color:var(--muted)]\">\n {brand.subtitle}\n </span>\n ) : null}\n </span>\n </>\n )}\n </Link>\n\n {/* Scroll region: org pill, mode pill, nav */}\n <div className=\"flex flex-1 flex-col overflow-y-auto px-4 pb-2\">\n {/* Organization switcher */}\n {org ? (\n <div className=\"mb-3\">\n <div className=\"mb-2 flex items-center justify-between px-1\">\n <p className=\"text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n Organization\n </p>\n {org.id ? <OrgIdCopyButton id={org.id} /> : null}\n </div>\n <button\n type=\"button\"\n onClick={org.onClick}\n style={{ backgroundColor: orgBg }}\n className=\"flex w-full items-center justify-between gap-2 rounded-md px-2.5 py-2 text-left text-white shadow-sm transition hover:opacity-95\"\n >\n <span className=\"flex min-w-0 items-center gap-2.5\">\n <span className=\"flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-white/20 text-[11px] font-bold text-white\">\n {org.logoUrl ? (\n <img src={org.logoUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n (org.name ?? 'Org').slice(0, 2).toUpperCase()\n )}\n </span>\n <span className=\"truncate text-sm font-semibold\">\n {org.name ?? 'No organizations'}\n </span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Mode pill */}\n {mode ? (\n <div className=\"mb-4\">\n <button\n type=\"button\"\n className=\"flex w-full items-center justify-between gap-2 rounded-md bg-[color:var(--color-race-red)] px-2.5 py-2 text-white shadow-sm\"\n >\n <span className=\"flex items-center gap-2.5\">\n {ModeIcon ? <ModeIcon size={16} className=\"shrink-0\" /> : null}\n <span className=\"text-sm font-semibold tracking-[-0.01em]\">{mode.label}</span>\n </span>\n <ChevronDown />\n </button>\n </div>\n ) : null}\n\n {/* Nav list */}\n <nav className=\"flex flex-col gap-1\">\n {nav.groupLabel ? (\n <p className=\"px-2 pb-1 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]\">\n {nav.groupLabel}\n </p>\n ) : null}\n {nav.items.map((item, idx) => {\n // Expandable group: renders a toggle header + collapsible children.\n if (item.children && item.children.length > 0) {\n const key = groupKeyOf(item, idx)\n const selfActive = item.href ? activeFn(pathname, item.href) : false\n const parentActive = selfActive || hasActiveChild(item, pathname, activeFn)\n return (\n <NavGroup\n key={key}\n item={item}\n active={parentActive}\n open={openGroup === key}\n onToggle={() => toggleGroup(key)}\n pathname={pathname}\n activeFn={activeFn}\n Link={Link}\n />\n )\n }\n const active = item.href ? activeFn(pathname, item.href) : false\n return (\n <NavRow\n key={item.href ?? `nav-${idx}-${item.label}`}\n item={item}\n active={active}\n Link={Link}\n />\n )\n })}\n </nav>\n </div>\n\n {/* Footer — pipe-separated links + commit/version string */}\n {footer ? (\n <div className=\"flex-shrink-0 border-t border-[color:var(--line)] px-4 py-3\">\n {footer.links && footer.links.length > 0 ? (\n <div className=\"flex flex-wrap items-center gap-1.5 text-xs\">\n {footer.links.map((l, idx) => (\n <span key={l.label} className=\"inline-flex items-center gap-1.5\">\n {idx > 0 ? <span className=\"text-[color:var(--muted)]\">|</span> : null}\n <a\n href={safeHref(l.href)}\n className=\"font-medium text-[color:var(--color-race-red)] hover:underline\"\n >\n {l.label}\n </a>\n </span>\n ))}\n </div>\n ) : null}\n <div className=\"mt-1.5 flex flex-col items-center gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--muted)]\">\n {/* Row 1: env chip | commit | version */}\n <div className=\"flex items-center gap-1.5\">\n <span\n className={[\n 'rounded-md px-1.5 py-0.5 text-[10px] font-semibold',\n envChipClasses(footer.envLabel),\n ].join(' ')}\n >\n {footer.envLabel}\n </span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>{footer.commit.slice(-4)}</span>\n <span className=\"text-[color:var(--muted)]\">|</span>\n <span>v{footer.version}</span>\n </div>\n {/* Row 2: date | author (only when supplied) */}\n {footer.commitDate || footer.commitAuthor ? (\n <div className=\"flex items-center gap-1.5\">\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitDate ? (\n <span>\n {new Date(footer.commitDate).toLocaleDateString(undefined, {\n month: 'short',\n day: 'numeric',\n })}\n </span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n {footer.commitAuthor ? (\n <span>{footer.commitAuthor.split(/\\s+/)[0]}</span>\n ) : null}\n <span className=\"text-[color:var(--muted)]\">|</span>\n </div>\n ) : null}\n </div>\n </div>\n ) : null}\n </aside>\n )\n}\n\n// Inline chevron-down (mirrors lucide `ChevronDown`) — no icon dependency.\n// Callers may override `className` to add a rotation (used by expandable groups).\nfunction ChevronDown({ className }: { className?: string } = {}) {\n return (\n <svg\n width={16}\n height={16}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n className={className ?? 'shrink-0 opacity-80'}\n aria-hidden=\"true\"\n >\n <path d=\"m6 9 6 6 6-6\" />\n </svg>\n )\n}\n\n// A single sidebar nav row. Renders as a routed <Link> (href) or a <button>\n// (onClick), styled identically. Inactive rows animate a left→right gradient\n// sweep on hover (matching the main app); active rows keep solid race-red.\n//\n// `variant=\"sub\"` renders the smaller child rows inside an expanded group: a\n// tighter row whose ACTIVE state is a lighter elevated surface with race-red\n// text (not a solid-red fill — that stays reserved for top-level/parent rows,\n// exactly as the main VRM app's Chakra sidebar treats active sub-items).\n// Specs race-red ramp (hover → active primary).\nconst NAV_HOVER_GRADIENT = 'linear-gradient(90deg,#EA4751 0%,#E63946 100%)'\n\nfunction NavRow({\n item,\n active,\n Link,\n variant = 'top',\n}: {\n item: NavItem\n active: boolean\n Link: NavLinkComponent\n variant?: 'top' | 'sub'\n}) {\n const Icon = item.icon\n const isSub = variant === 'sub'\n const activeClasses = isSub\n ? 'bg-[color:var(--panel-elevated)] text-[color:var(--color-race-red)] shadow-sm'\n : 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n const wrapperClasses = [\n 'group relative block overflow-hidden rounded-md transition',\n active ? activeClasses : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n const rowPadding = isSub ? 'px-3 py-1.5 text-[13px]' : 'px-3 py-2 text-sm'\n const iconSize = isSub ? 16 : 18\n // Top-level active rows use white glyphs on the red fill; sub-item active\n // rows inherit the race-red text color via `text-current`.\n const iconClass = active && !isSub ? 'text-white' : 'text-current'\n\n const inner = (\n <>\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className={`relative z-10 flex items-center gap-3 font-semibold ${rowPadding}`}>\n {Icon ? <Icon size={iconSize} className={iconClass} /> : null}\n {item.label}\n </span>\n </>\n )\n\n if (item.onClick && !item.href) {\n return (\n <button type=\"button\" onClick={item.onClick} className={`w-full text-left ${wrapperClasses}`}>\n {inner}\n </button>\n )\n }\n\n return (\n <Link\n href={item.href ?? '#'}\n aria-current={active ? 'page' : undefined}\n className={wrapperClasses}\n >\n {inner}\n </Link>\n )\n}\n\n// An expandable nav GROUP: a toggle header + a collapsible list of child rows.\n// Faithful twin of the main VRM app's Chakra accordion (Sidebar.tsx /\n// NavItem.tsx):\n// - Clicking the header toggles the children — it never navigates, even when\n// the group carries an `href`.\n// - A right-aligned chevron rotates 180° when open.\n// - The header goes solid race-red (white text) when the group owns the active\n// route (its own href OR any child), matching top-level active rows; when\n// merely open it lifts onto the `--panel` surface; otherwise it's a muted row\n// with the same left→right gradient hover sweep as every other nav row.\n// - Children sit on the lighter `--panel` surface, indented and rounded, each\n// rendered through the SAME injected LinkComponent (or as a button for\n// `onClick` children) via <NavRow variant=\"sub\" />.\nfunction NavGroup({\n item,\n active,\n open,\n onToggle,\n pathname,\n activeFn,\n Link,\n}: {\n item: NavItem\n active: boolean\n open: boolean\n onToggle: () => void\n pathname: string\n activeFn: (pathname: string, href: string) => boolean\n Link: NavLinkComponent\n}) {\n const Icon = item.icon\n const headerClasses = [\n 'group relative block w-full overflow-hidden text-left transition',\n open ? 'rounded-t-md' : 'rounded-md',\n active\n ? 'bg-[color:var(--color-race-red)] text-white shadow-sm'\n : open\n ? 'bg-[color:var(--panel)] text-[color:var(--foreground)]'\n : 'text-[color:var(--muted)] hover:text-white',\n ].join(' ')\n\n return (\n <div>\n <button\n type=\"button\"\n onClick={onToggle}\n aria-expanded={open}\n className={headerClasses}\n >\n {!active ? (\n <span\n aria-hidden=\"true\"\n className=\"pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full\"\n style={{ background: NAV_HOVER_GRADIENT }}\n />\n ) : null}\n <span className=\"relative z-10 flex items-center gap-3 px-3 py-2 text-sm font-semibold\">\n {Icon ? (\n <Icon size={18} className={active ? 'text-white' : 'text-current'} />\n ) : null}\n <span className=\"flex-1\">{item.label}</span>\n <ChevronDown\n className={[\n 'shrink-0 opacity-80 transition-transform duration-200',\n open ? 'rotate-180' : '',\n ].join(' ')}\n />\n </span>\n </button>\n\n {open ? (\n <div className=\"overflow-hidden rounded-b-md bg-[color:var(--panel)] p-1\">\n <div className=\"flex flex-col gap-0.5\">\n {item.children!.map((child, i) => {\n const childActive = child.href ? activeFn(pathname, child.href) : false\n return (\n <NavRow\n key={child.href ?? `sub-${i}-${child.label}`}\n item={child}\n active={childActive}\n Link={Link}\n variant=\"sub\"\n />\n )\n })}\n </div>\n </div>\n ) : null}\n </div>\n )\n}\n\n// Right-aligned copy affordance for the org id, shown beside the \"Organization\"\n// label. Copies the full id and briefly swaps its text to \"Copied\".\nfunction OrgIdCopyButton({ id }: { id: string }) {\n const [copied, setCopied] = useState(false)\n return (\n <button\n type=\"button\"\n onClick={() => {\n try {\n void navigator.clipboard?.writeText(id)\n } catch {\n /* clipboard unavailable — ignore */\n }\n setCopied(true)\n setTimeout(() => setCopied(false), 1500)\n }}\n title=\"Copy organization id\"\n className=\"rounded px-1 text-[11px] text-[color:var(--muted)] hover:bg-[color:var(--panel)]\"\n >\n {copied ? 'Copied' : `...${id.slice(-8)}`}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavUser = {\n name: string | null\n email?: string | null\n /** Avatar image URL; falls back to initials on the brand color. */\n avatarUrl?: string | null\n tier?: string | null\n role?: string | null\n}\n\nexport type NavTopBarAction = {\n key: string\n /**\n * Canonical top-bar slot. When set, the glyph is sourced by NAME from the\n * Brand API via `--topbar-icon-<slot>`; `icon` becomes the fallback used\n * until the runtime Brand stylesheet lands (or when the token is unset).\n */\n slot?: TopBarIconSlot\n icon: NavIcon\n label: string\n onClick?: () => void\n href?: string\n badge?: number | null\n tone?: 'default' | 'warning' | 'danger'\n}\n\nexport type NavTopBarProps = {\n title: string\n subtitle?: string\n user?: NavUser | null\n onSignOut?: () => void\n /**\n * Structured icon-button action cluster (32×32 circular buttons with optional\n * count badges), rendered before the `actions` slot. Matches the main app's\n * topbar action icons.\n */\n actionsList?: NavTopBarAction[]\n /** App-specific action cluster rendered left of the theme toggle. */\n actions?: ReactNode\n /** Theme toggle slot (injected so this package needs no theme dependency). */\n themeToggle?: ReactNode\n}\n\nexport function NavTopBar({\n title,\n subtitle,\n user,\n onSignOut,\n actionsList,\n actions,\n themeToggle,\n}: NavTopBarProps) {\n const initials = (user?.name ?? 'Politogy').slice(0, 2).toUpperCase()\n const secondary = user?.email || [user?.tier, user?.role].filter(Boolean).join(' · ') || 'member'\n return (\n <header className=\"sticky top-0 z-20 flex h-20 items-center justify-between gap-4 border-b border-[color:var(--line)] bg-[color:var(--panel)] px-4 backdrop-blur-xl\">\n <div className=\"min-w-0\">\n <h1\n className=\"truncate text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]\"\n data-display=\"true\"\n >\n {title}\n </h1>\n {subtitle ? (\n <p className=\"truncate text-sm text-[color:var(--muted)]\">{subtitle}</p>\n ) : null}\n </div>\n\n <div className=\"flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]\">\n {actionsList && actionsList.length > 0\n ? actionsList.map((action) => (\n <NavTopBarActionButton key={action.key} action={action} />\n ))\n : null}\n {actions}\n {themeToggle}\n\n {/* User menu — avatar + name/email + chevron; sign-out in a native\n <details> popover so the package needs no JS state. */}\n <details className=\"group relative\">\n <summary className=\"flex cursor-pointer list-none items-center gap-2.5 rounded-full py-1 pl-1 pr-2 transition hover:bg-[color:var(--panel-elevated)] [&::-webkit-details-marker]:hidden\">\n <span className=\"flex h-9 w-9 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-race-red)] text-xs font-bold text-white\">\n {user?.avatarUrl ? (\n <img src={user.avatarUrl} alt=\"\" className=\"h-full w-full object-cover\" />\n ) : (\n initials\n )}\n </span>\n <span className=\"hidden flex-col leading-tight md:flex\">\n <span className=\"text-sm font-semibold text-[color:var(--foreground)]\">\n {user?.name ?? 'Signed in'}\n </span>\n <span className=\"text-xs text-[color:var(--muted)]\">{secondary}</span>\n </span>\n <ChevronDown />\n </summary>\n {onSignOut ? (\n <div className=\"absolute right-0 z-30 mt-2 w-44 overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]\">\n <button\n type=\"button\"\n onClick={onSignOut}\n className=\"flex w-full items-center gap-2.5 px-4 py-2 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-race-red)]\"\n >\n <SignOutIcon />\n Sign out\n </button>\n </div>\n ) : null}\n </details>\n </div>\n </header>\n )\n}\n\n// Inline log-out glyph (mirrors lucide `LogOut`) to avoid an icon dependency.\nfunction SignOutIcon() {\n return (\n <svg\n width={15}\n height={15}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={2}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden=\"true\"\n >\n <path d=\"M9 21H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h4\" />\n <polyline points=\"16 17 21 12 16 7\" />\n <line x1=\"21\" x2=\"9\" y1=\"12\" y2=\"12\" />\n </svg>\n )\n}\n\n// A single 32×32 circular icon button for the top bar's structured action list.\n// Renders an <a> when `href` is present (external links open in a new tab),\n// otherwise a <button>. Shows a red count badge when `badge > 0`.\nfunction NavTopBarActionButton({ action }: { action: NavTopBarAction }) {\n const Icon = action.icon\n const tone = action.tone ?? 'default'\n // Universal treatment (Global Rules v9): size, color and hover are a single\n // shared value across every top-bar slot — only the glyph varies per slot.\n // Tone is a semantic state, not a bespoke per-slot style.\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 const className = [\n '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 // Per-slot glyph from Brand; `icon` is the fallback until the token resolves.\n // Brand emits Feather/Lucide glyph NAMES, not asset paths.\n const glyphName = useTopBarIconSlotGlyph(action.slot ?? 'apps')\n const BrandGlyph = action.slot ? resolveBrandGlyph(glyphName) : null\n const Glyph = BrandGlyph ?? Icon\n\n const content = (\n <>\n <Glyph size={20} className=\"text-current\" />\n {typeof action.badge === 'number' && action.badge > 0 ? (\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 {action.badge}\n </span>\n ) : null}\n </>\n )\n\n const isExternal = action.href ? /^https?:\\/\\//.test(action.href) : false\n\n if (action.href) {\n return (\n <a\n href={safeHref(action.href)}\n aria-label={action.label}\n title={action.label}\n className={className}\n {...(isExternal ? { target: '_blank', rel: 'noreferrer' } : {})}\n >\n {content}\n </a>\n )\n }\n\n return (\n <button\n type=\"button\"\n onClick={action.onClick}\n aria-label={action.label}\n title={action.label}\n className={className}\n >\n {content}\n </button>\n )\n}\n\n// ---------------------------------------------------------------------------\n// Icon-only tab strip — the standard secondary navigation the three Next.js\n// worker apps (Forms / Surveys / Polls) render below the top bar: a horizontal\n// row of icon-only tabs where the SELECTED tab merges into the content panel\n// below it (top/left/right border, no bottom border, sharing --tab-content-bg).\n//\n// A faithful twin of the hand-rolled `.tabstrip`/`.tab-strip` markup those apps\n// carried, promoted into the shell so every app renders the same accessible,\n// token-driven strip. All geometry is driven by the Brand `--tab-*` CSS vars\n// shipped in chrome.css (with literal fallbacks so the strip still renders in\n// an app that hasn't loaded the runtime tokens link yet):\n// --tab-height (row height) · --tab-icon-size (glyph) · --tab-radius (top\n// corners) · --tab-gap (between tabs) · --tab-content-bg (selected + panel\n// surface) · --tab-unselected-opacity (dimmed inactive tabs, default 0.6).\n// ---------------------------------------------------------------------------\n\nexport type NavTab = {\n /** Stable identity (used as the React key). */\n key: string\n /** Accessible name — becomes both the `title` tooltip and `aria-label`. */\n label: string\n icon: NavIcon\n /** Route to link to (rendered through `linkComponent`). */\n href?: string\n /** Click handler — rendered as a `<button>` when there's no `href`. */\n onSelect?: () => void\n /** Whether this tab is the active one (drives the merged-panel geometry). */\n selected?: boolean\n /**\n * Non-interactive, dimmed tab (e.g. Surveys' Canvas/Results before a survey\n * is chosen). Renders a non-navigating span; `disabledTitle` overrides the\n * tooltip to explain why (falls back to `label`).\n */\n disabled?: boolean\n disabledTitle?: string\n}\n\nexport type NavTabStripProps = {\n tabs: NavTab[]\n /** Accessible name for the tablist. */\n 'aria-label'?: string\n /** Routing primitive for `href` tabs (Next `<Link>`, etc). Defaults to <a>. */\n linkComponent?: NavLinkComponent\n /** Extra classes on the tablist container. */\n className?: string\n /**\n * Optional content panel rendered directly below the strip. When supplied it\n * renders on the shared `--tab-content-bg` surface with a square top-left\n * corner so the selected tab visually merges into it. Omit to render only the\n * strip and compose the panel yourself.\n */\n children?: ReactNode\n}\n\n/** Default icon glyph size — mirrors the `--tab-icon-size` token default. */\nconst TAB_ICON_SIZE = 18\n\nfunction NavTabButton({\n tab,\n Link,\n}: {\n tab: NavTab\n Link: NavLinkComponent\n}) {\n const { label, icon: Icon, href, onSelect, selected, disabled, disabledTitle } = tab\n const title = disabled ? disabledTitle ?? label : label\n\n // Base geometry shared by every state. Selected tabs sit above the content\n // panel (`z-10`) so their missing bottom border merges cleanly into it.\n const base =\n 'inline-flex shrink-0 items-center justify-center border border-b-0 transition-opacity'\n const stateClass = disabled\n ? 'cursor-not-allowed border-transparent opacity-40'\n : selected\n ? 'relative z-10 opacity-100 border-[color:var(--line)]'\n : 'border-transparent opacity-[var(--tab-unselected-opacity,0.6)] hover:opacity-90'\n const className = `${base} ${stateClass}`\n\n const style: CSSProperties = {\n height: 'var(--tab-height, 44px)',\n width: 'var(--tab-width, 3rem)',\n color: 'var(--foreground)',\n borderTopLeftRadius: 'var(--tab-radius, 12px)',\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n ...(selected ? { background: 'var(--tab-content-bg)' } : null),\n }\n\n const glyph = <Icon size={TAB_ICON_SIZE} className=\"text-current\" />\n\n // Disabled: non-navigating span, still exposed as a tab for AT.\n if (disabled) {\n return (\n <span\n role=\"tab\"\n aria-selected={false}\n aria-disabled=\"true\"\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </span>\n )\n }\n\n if (href) {\n return (\n <Link\n href={href}\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n className={className}\n style={style}\n >\n {glyph}\n </Link>\n )\n }\n\n return (\n <button\n type=\"button\"\n role=\"tab\"\n aria-selected={selected ? true : false}\n aria-label={label}\n title={title}\n onClick={onSelect}\n className={className}\n style={style}\n >\n {glyph}\n </button>\n )\n}\n\n/**\n * Icon-only, token-driven tab strip. Render it below `NavTopBar`; pass the\n * app's `Link` as `linkComponent` for `href` tabs. Supply `children` to get the\n * merged content panel, or omit it and compose your own panel on\n * `var(--tab-content-bg)`.\n */\nexport function NavTabStrip({\n tabs,\n 'aria-label': ariaLabel,\n linkComponent,\n className,\n children,\n}: NavTabStripProps) {\n const Link = linkComponent ?? DefaultLink\n return (\n <>\n <div\n role=\"tablist\"\n aria-label={ariaLabel}\n className={['flex items-end gap-[var(--tab-gap,8px)]', className]\n .filter(Boolean)\n .join(' ')}\n >\n {tabs.map((tab) => (\n <NavTabButton key={tab.key} tab={tab} Link={Link} />\n ))}\n </div>\n {children !== undefined ? (\n <div\n className=\"relative -mt-px border border-[color:var(--line)] p-5\"\n style={{\n background: 'var(--tab-content-bg)',\n borderTopLeftRadius: 0,\n borderTopRightRadius: 'var(--tab-radius, 12px)',\n borderBottomLeftRadius: 'var(--tab-radius, 12px)',\n borderBottomRightRadius: 'var(--tab-radius, 12px)',\n }}\n >\n {children}\n </div>\n ) : null}\n </>\n )\n}\n\n// ---------------------------------------------------------------------------\n\nexport type NavAppShellProps = {\n sidebar: NavSidebarProps\n topBar: NavTopBarProps\n children: ReactNode\n}\n\n/**\n * Full chrome: branded left sidebar + sticky top navbar + scrollable content\n * region. Presentational only — wrap it in app-level auth/gating as needed.\n */\nexport function NavAppShell({ sidebar, topBar, children }: NavAppShellProps) {\n return (\n <div className=\"min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]\">\n <NavSidebar {...sidebar} />\n <div className=\"lg:pl-[240px]\">\n <NavTopBar {...topBar} />\n <main className=\"px-6 py-7\">\n <div className=\"mx-auto max-w-7xl\">{children}</div>\n </main>\n </div>\n </div>\n )\n}\n\n// Canonical Politogy VRM menu — the standard nav structure every politogy app\n// renders, with hooks for the app-owned \"Contacts\" item and Support handler.\nexport {\n standardPolitogyNav,\n type StandardNavIconKey,\n type StandardNavOptions,\n} from './standardNav'\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-portland-company/shell",
|
|
3
|
-
"version": "0.14.
|
|
3
|
+
"version": "0.14.3",
|
|
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,
|