@the-portland-company/shell 0.66.1 → 0.68.0
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/CHANGELOG.md +26 -0
- package/dist/app-chrome.cjs +585 -429
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +39 -11
- package/dist/app-chrome.d.ts +39 -11
- package/dist/app-chrome.js +41 -14
- package/dist/app-chrome.js.map +1 -1
- package/dist/chrome.css +96 -16
- package/dist/{chunk-JHIFJZ73.js → chunk-NHBNM5P3.js} +17 -8
- package/dist/chunk-NHBNM5P3.js.map +1 -0
- package/dist/{chunk-T5ERHFNT.js → chunk-ZKYREVCK.js} +528 -376
- package/dist/chunk-ZKYREVCK.js.map +1 -0
- package/dist/index.cjs +12 -4
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/native.cjs +546 -385
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +62 -3
- package/dist/native.d.ts +62 -3
- package/dist/native.js +2 -2
- package/dist/theme-preference.cjs +15 -6
- package/dist/theme-preference.cjs.map +1 -1
- package/dist/theme-preference.d.cts +3 -3
- package/dist/theme-preference.d.ts +3 -3
- package/dist/theme-preference.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-JHIFJZ73.js.map +0 -1
- package/dist/chunk-T5ERHFNT.js.map +0 -1
package/dist/app-chrome.cjs
CHANGED
|
@@ -131,14 +131,24 @@ function clearPendingThemeChoice() {
|
|
|
131
131
|
writeSharedCookie(THEME_PENDING_COOKIE, "", 0);
|
|
132
132
|
}
|
|
133
133
|
function resolveTheme(pref) {
|
|
134
|
+
if (pref === "dark") return "dark";
|
|
135
|
+
if (pref === "system") {
|
|
136
|
+
try {
|
|
137
|
+
if (typeof window !== "undefined" && typeof window.matchMedia === "function") {
|
|
138
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
139
|
+
}
|
|
140
|
+
} catch {
|
|
141
|
+
}
|
|
142
|
+
}
|
|
134
143
|
return "light";
|
|
135
144
|
}
|
|
136
145
|
function applyThemePreference(pref) {
|
|
137
146
|
if (typeof document === "undefined") return;
|
|
138
|
-
const resolved = resolveTheme();
|
|
147
|
+
const resolved = resolveTheme(pref);
|
|
139
148
|
const d = document.documentElement;
|
|
140
|
-
d.classList.
|
|
149
|
+
d.classList.toggle("dark", resolved === "dark");
|
|
141
150
|
try {
|
|
151
|
+
d.setAttribute("data-theme", resolved);
|
|
142
152
|
d.style.colorScheme = resolved;
|
|
143
153
|
} catch {
|
|
144
154
|
}
|
|
@@ -152,11 +162,10 @@ var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
|
|
|
152
162
|
var pref=cookie||ls||"system";
|
|
153
163
|
if(VALID.indexOf(pref)===-1)pref="system";
|
|
154
164
|
if(cookie&&cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}
|
|
155
|
-
|
|
156
|
-
// stale dark class a pre-retirement cookie/localStorage value left behind.
|
|
165
|
+
var dark=pref==="dark"||(pref==="system"&&!!(window.matchMedia&&window.matchMedia("(prefers-color-scheme: dark)").matches));
|
|
157
166
|
var d=document.documentElement;
|
|
158
|
-
d.classList.remove("dark");
|
|
159
|
-
try{d.style.colorScheme="light";}catch(e){}
|
|
167
|
+
if(dark)d.classList.add("dark");else d.classList.remove("dark");
|
|
168
|
+
try{d.setAttribute("data-theme",dark?"dark":"light");d.style.colorScheme=dark?"dark":"light";}catch(e){}
|
|
160
169
|
}catch(e){}})();`;
|
|
161
170
|
var CORE_APP_ORIGIN = "https://app.politogyvrm.com";
|
|
162
171
|
var CORE_BILLING_PATH = "/organization-settings/subscription-billing/text-email";
|
|
@@ -177,12 +186,13 @@ function resolveOrgLogoUrl(url) {
|
|
|
177
186
|
if (/^(?:[a-z][a-z0-9+.-]*:|\/\/)/i.test(raw)) return raw;
|
|
178
187
|
return `${CORE_APP_ORIGIN}${raw.startsWith("/") ? "" : "/"}${raw}`;
|
|
179
188
|
}
|
|
189
|
+
var TOPBAR_GLYPH_SIZE = 17;
|
|
180
190
|
function topBarIconButtonClass(tone = "default") {
|
|
181
191
|
const toneClass = tone === "danger" || tone === "warning" ? "text-[color:var(--chrome-danger)] hover:text-[color:var(--chrome-danger)]" : "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)]";
|
|
182
192
|
return [
|
|
183
193
|
// `group/tbtip` powers the shared <TopBarTooltip> rendered inside the trigger.
|
|
184
|
-
"group/tbtip relative flex items-center justify-center rounded-
|
|
185
|
-
"h-[var(--topbar-icon-button-size,
|
|
194
|
+
"group/tbtip relative flex items-center justify-center rounded-[var(--topbar-icon-button-radius,5px)] border border-[color:var(--line)] transition",
|
|
195
|
+
"h-[var(--topbar-icon-button-size,34px)] w-[var(--topbar-icon-button-size,34px)]",
|
|
186
196
|
toneClass
|
|
187
197
|
].join(" ");
|
|
188
198
|
}
|
|
@@ -205,7 +215,7 @@ function useAnyTopBarPanelOpen() {
|
|
|
205
215
|
}
|
|
206
216
|
function TopBarCountBadge({ count }) {
|
|
207
217
|
if (!(count > 0)) return null;
|
|
208
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-
|
|
218
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-[5px] -right-[5px] flex h-4 min-w-4 items-center justify-center rounded-full bg-[color:var(--chrome-danger)] px-1 text-[10px] font-bold leading-4 text-white", children: count > 99 ? "99+" : count });
|
|
209
219
|
}
|
|
210
220
|
function TopBarTooltip({
|
|
211
221
|
title,
|
|
@@ -391,7 +401,7 @@ function ValueSkeleton({ className }) {
|
|
|
391
401
|
function SlotGlyph({
|
|
392
402
|
slot,
|
|
393
403
|
fallback: Fallback,
|
|
394
|
-
size =
|
|
404
|
+
size = TOPBAR_GLYPH_SIZE
|
|
395
405
|
}) {
|
|
396
406
|
const glyphName = useTopBarIconSlotGlyph(slot ?? "apps");
|
|
397
407
|
const BrandGlyph = slot ? resolveBrandGlyph(glyphName) : null;
|
|
@@ -483,7 +493,7 @@ function TopBarPopover({
|
|
|
483
493
|
) : null
|
|
484
494
|
] });
|
|
485
495
|
}
|
|
486
|
-
function BatteryGlyph({ size =
|
|
496
|
+
function BatteryGlyph({ size = TOPBAR_GLYPH_SIZE, className }) {
|
|
487
497
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className, "aria-hidden": true, children: [
|
|
488
498
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "1", y: "6", width: "18", height: "12", rx: "2", ry: "2" }),
|
|
489
499
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "23", y1: "10", x2: "23", y2: "14" }),
|
|
@@ -491,7 +501,7 @@ function BatteryGlyph({ size = 20, className }) {
|
|
|
491
501
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "9", y1: "10", x2: "9", y2: "14" })
|
|
492
502
|
] });
|
|
493
503
|
}
|
|
494
|
-
function BellGlyph({ size =
|
|
504
|
+
function BellGlyph({ size = TOPBAR_GLYPH_SIZE, className }) {
|
|
495
505
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className, "aria-hidden": true, children: [
|
|
496
506
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" }),
|
|
497
507
|
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M13.73 21a2 2 0 0 1-3.46 0" })
|
|
@@ -506,7 +516,7 @@ function BellOffGlyph({ size = 14, className }) {
|
|
|
506
516
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
|
|
507
517
|
] });
|
|
508
518
|
}
|
|
509
|
-
function LifeBuoyGlyph({ size =
|
|
519
|
+
function LifeBuoyGlyph({ size = TOPBAR_GLYPH_SIZE, className }) {
|
|
510
520
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className, "aria-hidden": true, children: [
|
|
511
521
|
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
512
522
|
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "4" }),
|
|
@@ -516,7 +526,7 @@ function LifeBuoyGlyph({ size = 20, className }) {
|
|
|
516
526
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4.93", y1: "19.07", x2: "9.17", y2: "14.83" })
|
|
517
527
|
] });
|
|
518
528
|
}
|
|
519
|
-
function LayoutGlyph({ size =
|
|
529
|
+
function LayoutGlyph({ size = TOPBAR_GLYPH_SIZE, className }) {
|
|
520
530
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", className, "aria-hidden": true, children: [
|
|
521
531
|
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
522
532
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "9", x2: "21", y2: "9" }),
|
|
@@ -1534,7 +1544,7 @@ function SpecOverlayAction({ orgId, orgName } = {}) {
|
|
|
1534
1544
|
className: topBarIconButtonClass(badgeTone),
|
|
1535
1545
|
onClick: () => setOpen(true),
|
|
1536
1546
|
children: [
|
|
1537
|
-
/* @__PURE__ */ jsxRuntime.jsx(LayoutGlyph, { size:
|
|
1547
|
+
/* @__PURE__ */ jsxRuntime.jsx(LayoutGlyph, { size: TOPBAR_GLYPH_SIZE, className: "text-current" }),
|
|
1538
1548
|
badgeLabel ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1539
1549
|
"span",
|
|
1540
1550
|
{
|
|
@@ -1699,38 +1709,6 @@ var NAV_DISPLAY_OPTIONS = [
|
|
|
1699
1709
|
{ value: "tabs", label: "Tabs Only" },
|
|
1700
1710
|
{ value: "both", label: "Both" }
|
|
1701
1711
|
];
|
|
1702
|
-
function NavDisplayAction({
|
|
1703
|
-
value,
|
|
1704
|
-
onChange
|
|
1705
|
-
}) {
|
|
1706
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1707
|
-
TopBarPopover,
|
|
1708
|
-
{
|
|
1709
|
-
label: "Navigation Display",
|
|
1710
|
-
description: "Show navigation as a sub-menu, tabs, or both.",
|
|
1711
|
-
fallbackIcon: LayoutGlyph,
|
|
1712
|
-
panelClassName: "w-44",
|
|
1713
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "py-1", role: "radiogroup", "aria-label": "Navigation display", children: NAV_DISPLAY_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1714
|
-
"button",
|
|
1715
|
-
{
|
|
1716
|
-
type: "button",
|
|
1717
|
-
role: "radio",
|
|
1718
|
-
"aria-checked": value === opt.value,
|
|
1719
|
-
onClick: () => onChange(opt.value),
|
|
1720
|
-
className: [
|
|
1721
|
-
"flex w-full items-center justify-between px-4 py-2 text-left text-sm font-medium",
|
|
1722
|
-
value === opt.value ? "text-[color:var(--color-accent)]" : "text-[color:var(--foreground)] hover:bg-[color:var(--panel)]"
|
|
1723
|
-
].join(" "),
|
|
1724
|
-
children: [
|
|
1725
|
-
opt.label,
|
|
1726
|
-
value === opt.value ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\u2713" }) : null
|
|
1727
|
-
]
|
|
1728
|
-
},
|
|
1729
|
-
opt.value
|
|
1730
|
-
)) })
|
|
1731
|
-
}
|
|
1732
|
-
);
|
|
1733
|
-
}
|
|
1734
1712
|
function useThemePreference() {
|
|
1735
1713
|
const ctx = react.useContext(NavChromeContext);
|
|
1736
1714
|
const fetchJson = ctx?.fetchJson ?? null;
|
|
@@ -1745,7 +1723,7 @@ function useThemePreference() {
|
|
|
1745
1723
|
}
|
|
1746
1724
|
const pref = cookie ?? (isThemePreference(ls) ? ls : null) ?? "system";
|
|
1747
1725
|
setValueState(pref);
|
|
1748
|
-
applyThemePreference();
|
|
1726
|
+
applyThemePreference(pref);
|
|
1749
1727
|
}, []);
|
|
1750
1728
|
const meCtx = react.useContext(NavChromeContext);
|
|
1751
1729
|
react.useEffect(() => {
|
|
@@ -1754,7 +1732,7 @@ function useThemePreference() {
|
|
|
1754
1732
|
if (pending) {
|
|
1755
1733
|
if (meCtx?.me) reconciled.current = true;
|
|
1756
1734
|
setValueState(pending);
|
|
1757
|
-
applyThemePreference();
|
|
1735
|
+
applyThemePreference(pending);
|
|
1758
1736
|
writeThemeCookie(pending);
|
|
1759
1737
|
try {
|
|
1760
1738
|
localStorage.setItem(THEME_STORAGE_KEY, pending);
|
|
@@ -1773,7 +1751,7 @@ function useThemePreference() {
|
|
|
1773
1751
|
if (isThemePreference(pref)) {
|
|
1774
1752
|
reconciled.current = true;
|
|
1775
1753
|
setValueState(pref);
|
|
1776
|
-
applyThemePreference();
|
|
1754
|
+
applyThemePreference(pref);
|
|
1777
1755
|
writeThemeCookie(pref);
|
|
1778
1756
|
try {
|
|
1779
1757
|
localStorage.setItem(THEME_STORAGE_KEY, pref);
|
|
@@ -1792,7 +1770,7 @@ function useThemePreference() {
|
|
|
1792
1770
|
const cookie = readThemeCookie();
|
|
1793
1771
|
if (cookie) {
|
|
1794
1772
|
setValueState((prev) => {
|
|
1795
|
-
if (cookie !== prev) applyThemePreference();
|
|
1773
|
+
if (cookie !== prev) applyThemePreference(cookie);
|
|
1796
1774
|
return cookie;
|
|
1797
1775
|
});
|
|
1798
1776
|
}
|
|
@@ -1814,14 +1792,14 @@ function useThemePreference() {
|
|
|
1814
1792
|
} catch {
|
|
1815
1793
|
return;
|
|
1816
1794
|
}
|
|
1817
|
-
const onChange = () => applyThemePreference();
|
|
1795
|
+
const onChange = () => applyThemePreference("system");
|
|
1818
1796
|
mq.addEventListener("change", onChange);
|
|
1819
1797
|
return () => mq.removeEventListener("change", onChange);
|
|
1820
1798
|
}, [value]);
|
|
1821
1799
|
const setValue = react.useCallback(
|
|
1822
1800
|
(next) => {
|
|
1823
1801
|
setValueState(next);
|
|
1824
|
-
applyThemePreference();
|
|
1802
|
+
applyThemePreference(next);
|
|
1825
1803
|
writeThemeCookie(next);
|
|
1826
1804
|
try {
|
|
1827
1805
|
localStorage.setItem(THEME_STORAGE_KEY, next);
|
|
@@ -1856,6 +1834,16 @@ var SIGNS_ORIGIN = "https://signs.politogyvrm.com/";
|
|
|
1856
1834
|
var POLLS_ORIGIN = "https://polls.politogyvrm.com/";
|
|
1857
1835
|
var CONTACTS_TRIBES = "https://contacts.politogyvrm.com/tribes";
|
|
1858
1836
|
var PETITION_MODE_ORIGIN = "https://petition-mode.politogyvrm.com/";
|
|
1837
|
+
function applyHiddenItems(items, hidden) {
|
|
1838
|
+
if (!hidden || hidden.length === 0) return items;
|
|
1839
|
+
const drop = new Set(hidden.map((h) => h.trim().toLowerCase()));
|
|
1840
|
+
const kept = items.filter((i) => i.kind === "section" || !drop.has(i.label.toLowerCase()));
|
|
1841
|
+
return kept.filter((item, idx) => {
|
|
1842
|
+
if (item.kind !== "section") return true;
|
|
1843
|
+
const next = kept[idx + 1];
|
|
1844
|
+
return !!next && next.kind !== "section";
|
|
1845
|
+
});
|
|
1846
|
+
}
|
|
1859
1847
|
var CONTACTS_APP = "https://contacts.politogyvrm.com";
|
|
1860
1848
|
var APP_CONTACTS_CHILDREN = [
|
|
1861
1849
|
{ label: "Dashboard", icon: "grid", href: `${CONTACTS_APP}/` },
|
|
@@ -1970,7 +1958,8 @@ function standardPolitogyNav(opts) {
|
|
|
1970
1958
|
label: "Contacts",
|
|
1971
1959
|
icon: icon("users"),
|
|
1972
1960
|
href: opts.contactsItem.href,
|
|
1973
|
-
children: opts.contactsItem.children
|
|
1961
|
+
children: opts.contactsItem.children,
|
|
1962
|
+
badge: opts.contactsItem.count ?? void 0
|
|
1974
1963
|
} : {
|
|
1975
1964
|
label: "Contacts",
|
|
1976
1965
|
icon: icon("users"),
|
|
@@ -1982,10 +1971,11 @@ function standardPolitogyNav(opts) {
|
|
|
1982
1971
|
}))
|
|
1983
1972
|
};
|
|
1984
1973
|
return [
|
|
1974
|
+
{ kind: "section", label: "Relationship" },
|
|
1985
1975
|
{ label: "Dashboard", icon: icon("home"), href: withOrg(abs("/relationship/dashboard")) },
|
|
1986
1976
|
contacts,
|
|
1987
1977
|
{
|
|
1988
|
-
label: "Email
|
|
1978
|
+
label: "Email broadcast",
|
|
1989
1979
|
icon: icon("mail"),
|
|
1990
1980
|
href: withOrg(`${EMAIL_APP}/dashboard`),
|
|
1991
1981
|
children: [
|
|
@@ -1993,20 +1983,19 @@ function standardPolitogyNav(opts) {
|
|
|
1993
1983
|
...leaves([EMAIL_V1_LEGACY])
|
|
1994
1984
|
]
|
|
1995
1985
|
},
|
|
1996
|
-
// SMS/MMS Blast IS a2p (Specs/A2P) — the standalone delivery engine
|
|
1997
|
-
// shared with Campaign Mode, not a core-hosted surface (the old
|
|
1998
|
-
// `/relationship/sms-mms-blast/*` core routes are dead; core no longer
|
|
1999
|
-
// hosts them). Every link carries `mode=relationship` so a2p's nav
|
|
2000
|
-
// resolves the Relationship tree instead of its own Campaign default
|
|
2001
|
-
// (resolveActiveMode, mode-preference.ts).
|
|
2002
1986
|
{
|
|
2003
|
-
|
|
1987
|
+
// SMS/MMS Blast is the a2p app entered in RELATIONSHIP mode (a2p is
|
|
1988
|
+
// dual-mode; Specs/A2P). The `?mode=relationship` param pins the
|
|
1989
|
+
// destination's tree so the row that got you there is the row that
|
|
1990
|
+
// lights up on arrival.
|
|
1991
|
+
label: "SMS/MMS blast",
|
|
2004
1992
|
icon: icon("messageSquare"),
|
|
2005
1993
|
href: withOrg(`${A2P_ORIGIN}?mode=relationship`),
|
|
2006
1994
|
children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN, "relationship")
|
|
2007
1995
|
},
|
|
2008
|
-
|
|
2009
|
-
|
|
1996
|
+
{ kind: "section", label: "Collect" },
|
|
1997
|
+
// Carries no top-level href in VRM core (parent row only toggles).
|
|
1998
|
+
{ label: "Calls to action", icon: icon("layout"), children: leaves(CTA_CHILDREN) },
|
|
2010
1999
|
{
|
|
2011
2000
|
label: "Forms",
|
|
2012
2001
|
icon: icon("activity"),
|
|
@@ -2031,9 +2020,12 @@ function standardPolitogyNav(opts) {
|
|
|
2031
2020
|
href: withOrg("https://ctas.politogyvrm.com/"),
|
|
2032
2021
|
children: APP_CTAS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
2033
2022
|
},
|
|
2023
|
+
{ kind: "section", label: "Account" },
|
|
2024
|
+
// My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
|
|
2025
|
+
{ label: "My profile", icon: icon("user"), href: withOrg(abs("/my-profile")) },
|
|
2034
2026
|
{
|
|
2035
|
-
label: "Organization
|
|
2036
|
-
icon: icon("
|
|
2027
|
+
label: "Organization settings",
|
|
2028
|
+
icon: icon("settings"),
|
|
2037
2029
|
href: withOrg(abs("/organization-settings")),
|
|
2038
2030
|
children: branches(ORG_SETTINGS_CHILDREN)
|
|
2039
2031
|
}
|
|
@@ -2089,7 +2081,8 @@ function standardPolitogyNav(opts) {
|
|
|
2089
2081
|
} : { label: "Dashboard", icon: icon("home"), href: withOrg(PETITION_MODE_ORIGIN) }
|
|
2090
2082
|
];
|
|
2091
2083
|
const mode = opts.mode ?? "relationship";
|
|
2092
|
-
const
|
|
2084
|
+
const built = mode === "campaign" ? buildCampaign() : mode === "petition" ? buildPetition() : buildRelationship();
|
|
2085
|
+
const items = applyHiddenItems(built, opts.hiddenItems);
|
|
2093
2086
|
if (opts.supportItem) {
|
|
2094
2087
|
items.push({
|
|
2095
2088
|
label: "Support",
|
|
@@ -2219,6 +2212,7 @@ function NavSidebar({
|
|
|
2219
2212
|
const ModeIcon = mode?.icon;
|
|
2220
2213
|
const orgLogoSrc = resolveOrgLogoUrl(org?.logoUrl);
|
|
2221
2214
|
const orgGradient = org?.brandColor ? `linear-gradient(to right, ${org.brandColor}, ${org.brandColorSecondary || org.brandColor})` : "linear-gradient(to right, #007BFF, #A54B7A, #E63946)";
|
|
2215
|
+
const orgCardStyle = hexToRgba(org?.brandColor, 0.42) ? { borderColor: hexToRgba(org?.brandColor, 0.42) } : void 0;
|
|
2222
2216
|
const activeGroupKey = react.useMemo(() => {
|
|
2223
2217
|
for (let i = 0; i < nav.items.length; i++) {
|
|
2224
2218
|
const item = nav.items[i];
|
|
@@ -2252,7 +2246,7 @@ function NavSidebar({
|
|
|
2252
2246
|
"aria-modal": open ? "true" : void 0,
|
|
2253
2247
|
"aria-label": open ? "Navigation" : void 0,
|
|
2254
2248
|
className: clsx__default.default(
|
|
2255
|
-
"fixed inset-y-0 left-0 w-[
|
|
2249
|
+
"fixed inset-y-0 left-0 w-[var(--sidebar-width,236px)] flex-col border-r border-[color:var(--sidebar-line,var(--line))] bg-[color:var(--sidebar-bg,var(--nav-surface))] lg:flex",
|
|
2256
2250
|
open ? "flex z-50" : "hidden z-30"
|
|
2257
2251
|
),
|
|
2258
2252
|
style: { fontFamily: 'var(--font-family, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif)' },
|
|
@@ -2272,31 +2266,31 @@ function NavSidebar({
|
|
|
2272
2266
|
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
|
|
2273
2267
|
}
|
|
2274
2268
|
) : null,
|
|
2275
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2276
|
-
|
|
2277
|
-
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2290
|
-
|
|
2291
|
-
/* @__PURE__ */ jsxRuntime.
|
|
2292
|
-
|
|
2269
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-shrink-0 flex-col gap-[14px] border-b border-[color:var(--sidebar-line,var(--line))] px-[18px] py-4", children: [
|
|
2270
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2271
|
+
Link,
|
|
2272
|
+
{
|
|
2273
|
+
href: brand.homeHref ?? "/",
|
|
2274
|
+
className: "flex items-center gap-2.5",
|
|
2275
|
+
children: brand.logoSrc ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2276
|
+
"img",
|
|
2277
|
+
{
|
|
2278
|
+
src: brand.logoSrc,
|
|
2279
|
+
alt: brand.logoAlt ?? brand.title,
|
|
2280
|
+
draggable: false,
|
|
2281
|
+
className: "h-[var(--sidebar-brand-logo-height,24px)] w-auto object-contain"
|
|
2282
|
+
}
|
|
2283
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2284
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-9 w-9 items-center justify-center rounded-xl bg-[color:var(--color-accent)] text-base font-black text-white shadow-sm", children: brand.badgeLabel }),
|
|
2285
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex flex-col leading-tight", children: [
|
|
2286
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-base font-extrabold tracking-[-0.01em] text-[color:var(--color-accent)]", children: brand.title }),
|
|
2287
|
+
brand.subtitle ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-semibold uppercase tracking-[0.16em] text-[color:var(--muted)]", children: brand.subtitle }) : null
|
|
2288
|
+
] })
|
|
2293
2289
|
] })
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
org ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-3", children: [
|
|
2299
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-2 flex items-center justify-between px-1", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--sidebar-text-muted,var(--muted))]", children: "Organization" }) }),
|
|
2290
|
+
}
|
|
2291
|
+
),
|
|
2292
|
+
org ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2293
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-[7px] flex items-center justify-between", children: /* @__PURE__ */ jsxRuntime.jsx("p", { className: NAV_EYEBROW_CLASS, children: "Organization" }) }),
|
|
2300
2294
|
org.loading ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-full items-center gap-2.5 rounded-md border border-[color:var(--line)] bg-[color:var(--panel-elevated)] px-2.5 py-2 shadow-sm", children: [
|
|
2301
2295
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2302
2296
|
"span",
|
|
@@ -2314,34 +2308,41 @@ function NavSidebar({
|
|
|
2314
2308
|
),
|
|
2315
2309
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Loading organization" })
|
|
2316
2310
|
] }) : org.organizations && org.organizations.length > 0 && org.onSwitch ? /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group relative", children: [
|
|
2317
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2318
|
-
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
className: "
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
"span",
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2337
|
-
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2311
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2312
|
+
"summary",
|
|
2313
|
+
{
|
|
2314
|
+
style: orgCardStyle,
|
|
2315
|
+
className: "flex w-full cursor-pointer list-none flex-col overflow-hidden rounded-[5px] border border-[color:var(--sidebar-card-border,var(--sidebar-line,var(--line)))] bg-[color:var(--sidebar-card-bg,var(--panel-elevated))] text-left text-[color:var(--sidebar-text,var(--foreground))] transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel))] [&::-webkit-details-marker]:hidden",
|
|
2316
|
+
children: [
|
|
2317
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-[var(--sidebar-org-band-height,48px)] w-full items-center justify-center bg-white px-3 py-[7px]", children: [
|
|
2318
|
+
orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2319
|
+
"a",
|
|
2320
|
+
{
|
|
2321
|
+
href: org.uploadLogoHref ?? "#",
|
|
2322
|
+
onClick: (e) => e.stopPropagation(),
|
|
2323
|
+
className: "text-xs font-semibold text-[color:var(--color-accent)] underline",
|
|
2324
|
+
children: "Upload logo"
|
|
2325
|
+
}
|
|
2326
|
+
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
|
|
2327
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
|
|
2328
|
+
] }),
|
|
2329
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-2", children: [
|
|
2330
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
2331
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2332
|
+
"span",
|
|
2333
|
+
{
|
|
2334
|
+
title: org.name ?? void 0,
|
|
2335
|
+
className: "truncate text-[12px] font-semibold leading-[1.2]",
|
|
2336
|
+
children: org.name ?? "No organizations"
|
|
2337
|
+
}
|
|
2338
|
+
),
|
|
2339
|
+
org.id && !org.loading ? /* @__PURE__ */ jsxRuntime.jsx(OrgIdCopyButton, { id: org.id }) : null
|
|
2340
|
+
] }),
|
|
2341
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 14 })
|
|
2342
|
+
] })
|
|
2343
|
+
]
|
|
2344
|
+
}
|
|
2345
|
+
),
|
|
2345
2346
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute left-0 right-0 z-40 mt-1 max-h-[min(60vh,520px)] overflow-y-auto rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]", children: [
|
|
2346
2347
|
shouldShowOrgFilter(org.organizations.length) ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "sticky top-0 z-10 bg-[color:var(--panel-elevated)] px-2 pb-1 pt-1", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
2347
2348
|
"input",
|
|
@@ -2410,10 +2411,11 @@ function NavSidebar({
|
|
|
2410
2411
|
{
|
|
2411
2412
|
type: "button",
|
|
2412
2413
|
onClick: org.onClick,
|
|
2413
|
-
|
|
2414
|
+
style: orgCardStyle,
|
|
2415
|
+
className: "flex w-full flex-col overflow-hidden rounded-[5px] border border-[color:var(--sidebar-card-border,var(--sidebar-line,var(--line)))] bg-[color:var(--sidebar-card-bg,var(--panel-elevated))] text-left text-[color:var(--sidebar-text,var(--foreground))] transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel))]",
|
|
2414
2416
|
children: [
|
|
2415
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-[
|
|
2416
|
-
orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-
|
|
2417
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative flex h-[var(--sidebar-org-band-height,48px)] w-full items-center justify-center bg-white px-3 py-[7px]", children: [
|
|
2418
|
+
orgLogoSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: orgLogoSrc, alt: "", className: "max-h-full max-w-[132px] object-contain" }) : org.canUploadLogo ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2417
2419
|
"a",
|
|
2418
2420
|
{
|
|
2419
2421
|
href: org.uploadLogoHref ?? "#",
|
|
@@ -2424,31 +2426,31 @@ function NavSidebar({
|
|
|
2424
2426
|
) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-sm font-semibold text-neutral-800", children: org.name ?? "Organization" }),
|
|
2425
2427
|
/* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "absolute inset-x-0 bottom-0 h-[3px]", style: { backgroundImage: orgGradient } })
|
|
2426
2428
|
] }),
|
|
2427
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-
|
|
2429
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex w-full min-w-0 items-center justify-between gap-[9px] px-[10px] py-2", children: [
|
|
2428
2430
|
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col", children: [
|
|
2429
2431
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2430
2432
|
"span",
|
|
2431
2433
|
{
|
|
2432
2434
|
title: org.name ?? void 0,
|
|
2433
|
-
className: "truncate text-[
|
|
2435
|
+
className: "truncate text-[12px] font-semibold leading-[1.2]",
|
|
2434
2436
|
children: org.name ?? "No organizations"
|
|
2435
2437
|
}
|
|
2436
2438
|
),
|
|
2437
2439
|
org.id && !org.loading ? /* @__PURE__ */ jsxRuntime.jsx(OrgIdCopyButton, { id: org.id }) : null
|
|
2438
2440
|
] }),
|
|
2439
|
-
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown, {})
|
|
2441
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 14 })
|
|
2440
2442
|
] })
|
|
2441
2443
|
]
|
|
2442
2444
|
}
|
|
2443
2445
|
)
|
|
2444
2446
|
] }) : null,
|
|
2445
|
-
mode ? /* @__PURE__ */ jsxRuntime.jsxs("div", {
|
|
2447
|
+
mode ? /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2446
2448
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2447
2449
|
"div",
|
|
2448
2450
|
{
|
|
2449
2451
|
role: "radiogroup",
|
|
2450
2452
|
"aria-label": "Mode",
|
|
2451
|
-
className: "flex items-center
|
|
2453
|
+
className: "flex w-full items-center gap-1 rounded-lg border border-[color:var(--border-inverse,var(--sidebar-line,var(--line)))] bg-[color:var(--mode-track-bg,var(--panel-elevated))] p-[3px]",
|
|
2452
2454
|
children: (mode.options && mode.options.length > 0 ? mode.options : [{ id: mode.label, label: mode.label, icon: ModeIcon }]).map(
|
|
2453
2455
|
(opt) => {
|
|
2454
2456
|
const selected = opt.label === mode.label;
|
|
@@ -2469,8 +2471,8 @@ function NavSidebar({
|
|
|
2469
2471
|
},
|
|
2470
2472
|
disabled: !available,
|
|
2471
2473
|
className: [
|
|
2472
|
-
"flex
|
|
2473
|
-
!available ? "cursor-not-allowed text-[color:var(--sidebar-text-muted,var(--muted))] opacity-35" : selected ? "bg-[color:var(--mode-accent,var(--color-accent))] text-[color:var(--mode-on-accent,white)]
|
|
2474
|
+
"flex flex-1 items-center justify-center rounded-[5px] px-[9px] py-[6px] transition",
|
|
2475
|
+
!available ? "cursor-not-allowed text-[color:var(--sidebar-text-muted,var(--muted))] opacity-35" : selected ? "bg-[color:var(--sidebar-mode-selected-bg,var(--mode-accent,var(--color-accent)))] text-[color:var(--mode-on-accent,white)]" : "text-[color:var(--sidebar-text-muted,var(--muted))] hover:bg-white/5 hover:text-[color:var(--sidebar-text,var(--foreground))]"
|
|
2474
2476
|
].join(" "),
|
|
2475
2477
|
children: OptIcon ? /* @__PURE__ */ jsxRuntime.jsx(OptIcon, { size: 15, className: "shrink-0" }) : null
|
|
2476
2478
|
},
|
|
@@ -2480,93 +2482,99 @@ function NavSidebar({
|
|
|
2480
2482
|
)
|
|
2481
2483
|
}
|
|
2482
2484
|
),
|
|
2483
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-
|
|
2484
|
-
] }) : null
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
NavSectionRow,
|
|
2503
|
-
{
|
|
2504
|
-
label: child.label,
|
|
2505
|
-
first: idx === 0 && i === 0
|
|
2506
|
-
},
|
|
2507
|
-
`flat-section-${idx}-${i}-${child.label}`
|
|
2508
|
-
);
|
|
2509
|
-
}
|
|
2485
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1.5 text-left text-[11px] leading-[1.2] text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: modeCaption(mode.label) })
|
|
2486
|
+
] }) : null
|
|
2487
|
+
] }),
|
|
2488
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-1 flex-col overflow-y-auto px-[10px] py-3", children: /* @__PURE__ */ jsxRuntime.jsxs("nav", { className: "flex flex-col gap-0.5", children: [
|
|
2489
|
+
nav.groupLabel ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${NAV_EYEBROW_CLASS} px-2 pb-1.5 pt-1`, children: nav.groupLabel }) : null,
|
|
2490
|
+
nav.items.map((item, idx) => {
|
|
2491
|
+
if (item.kind === "section") {
|
|
2492
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2493
|
+
NavSectionRow,
|
|
2494
|
+
{
|
|
2495
|
+
label: item.label,
|
|
2496
|
+
first: idx === 0
|
|
2497
|
+
},
|
|
2498
|
+
`section-${idx}-${item.label}`
|
|
2499
|
+
);
|
|
2500
|
+
}
|
|
2501
|
+
if (nav.flatten && item.children && item.children.length > 0) {
|
|
2502
|
+
return item.children.map((child, i) => {
|
|
2503
|
+
if (child.kind === "section") {
|
|
2510
2504
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2511
|
-
|
|
2505
|
+
NavSectionRow,
|
|
2512
2506
|
{
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
Link,
|
|
2516
|
-
variant: "flat"
|
|
2507
|
+
label: child.label,
|
|
2508
|
+
first: idx === 0 && i === 0
|
|
2517
2509
|
},
|
|
2518
|
-
|
|
2510
|
+
`flat-section-${idx}-${i}-${child.label}`
|
|
2519
2511
|
);
|
|
2520
|
-
}
|
|
2521
|
-
}
|
|
2522
|
-
if (item.children && item.children.length > 0) {
|
|
2523
|
-
const key = groupKeyOf(item, idx);
|
|
2524
|
-
const selfActive = item.href ? activeFn(pathname, item.href) : false;
|
|
2525
|
-
const parentActive = selfActive || hasActiveChild(item, pathname, activeFn);
|
|
2512
|
+
}
|
|
2526
2513
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2527
|
-
|
|
2514
|
+
NavRow,
|
|
2528
2515
|
{
|
|
2529
|
-
item,
|
|
2530
|
-
active:
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
pathname,
|
|
2534
|
-
activeFn,
|
|
2535
|
-
Link
|
|
2516
|
+
item: child,
|
|
2517
|
+
active: child.href ? activeFn(pathname, child.href) : false,
|
|
2518
|
+
Link,
|
|
2519
|
+
variant: "flat"
|
|
2536
2520
|
},
|
|
2537
|
-
|
|
2521
|
+
child.href ?? `flat-${idx}-${i}-${child.label}`
|
|
2538
2522
|
);
|
|
2539
|
-
}
|
|
2540
|
-
|
|
2523
|
+
});
|
|
2524
|
+
}
|
|
2525
|
+
if (item.children && item.children.length > 0) {
|
|
2526
|
+
const key = groupKeyOf(item, idx);
|
|
2527
|
+
const selfActive = item.href ? activeFn(pathname, item.href) : false;
|
|
2528
|
+
const parentActive = selfActive || hasActiveChild(item, pathname, activeFn);
|
|
2541
2529
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2542
|
-
|
|
2530
|
+
NavGroup,
|
|
2543
2531
|
{
|
|
2544
2532
|
item,
|
|
2545
|
-
active,
|
|
2533
|
+
active: parentActive,
|
|
2534
|
+
open: openGroup === key,
|
|
2535
|
+
onToggle: () => toggleGroup(key),
|
|
2536
|
+
pathname,
|
|
2537
|
+
activeFn,
|
|
2546
2538
|
Link
|
|
2547
2539
|
},
|
|
2548
|
-
|
|
2540
|
+
key
|
|
2549
2541
|
);
|
|
2550
|
-
}
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center justify-center gap-1.5 text-xs", children: footer.links.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
2555
|
-
idx > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }) : null,
|
|
2556
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2557
|
-
"a",
|
|
2542
|
+
}
|
|
2543
|
+
const active = item.href ? activeFn(pathname, item.href) : false;
|
|
2544
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2545
|
+
NavRow,
|
|
2558
2546
|
{
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
}
|
|
2563
|
-
|
|
2564
|
-
|
|
2547
|
+
item,
|
|
2548
|
+
active,
|
|
2549
|
+
Link
|
|
2550
|
+
},
|
|
2551
|
+
item.href ?? `nav-${idx}-${item.label}`
|
|
2552
|
+
);
|
|
2553
|
+
})
|
|
2554
|
+
] }) }),
|
|
2555
|
+
footer ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative flex-shrink-0 border-t border-[color:var(--sidebar-line,var(--line))] px-[14px] py-3", children: [
|
|
2556
|
+
footer.user ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2557
|
+
NavSidebarUserCard,
|
|
2558
|
+
{
|
|
2559
|
+
user: footer.user,
|
|
2560
|
+
userMenu: footer.userMenu ?? void 0,
|
|
2561
|
+
onSignOut: footer.onSignOut
|
|
2562
|
+
}
|
|
2563
|
+
) : null,
|
|
2564
|
+
footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: `flex flex-wrap items-center gap-[10px] text-[11px] leading-[1.2] ${footer.user ? "mt-3" : ""}`, children: footer.links.map((l) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
2565
|
+
"a",
|
|
2566
|
+
{
|
|
2567
|
+
href: safeHref(l.href),
|
|
2568
|
+
className: "text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] hover:text-[color:var(--sidebar-text,var(--foreground))] hover:underline",
|
|
2569
|
+
children: l.label
|
|
2570
|
+
},
|
|
2571
|
+
l.label
|
|
2572
|
+
)) }) : null,
|
|
2565
2573
|
footer.envLabel && footer.envLabel.trim().toLowerCase() !== "production" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2566
2574
|
"div",
|
|
2567
2575
|
{
|
|
2568
2576
|
"data-shell-meta": true,
|
|
2569
|
-
className: "mt-1.5 flex flex-col items-
|
|
2577
|
+
className: "mt-1.5 flex flex-col items-start gap-0.5 font-[family-name:var(--font-plex-mono)] text-[10px] text-[color:var(--sidebar-meta-text,var(--sidebar-text))]",
|
|
2570
2578
|
children: [
|
|
2571
2579
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
2572
2580
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2629,6 +2637,27 @@ function HamburgerIcon() {
|
|
|
2629
2637
|
}
|
|
2630
2638
|
);
|
|
2631
2639
|
}
|
|
2640
|
+
function BookOpenIcon() {
|
|
2641
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2642
|
+
"svg",
|
|
2643
|
+
{
|
|
2644
|
+
width: 14,
|
|
2645
|
+
height: 14,
|
|
2646
|
+
viewBox: "0 0 24 24",
|
|
2647
|
+
fill: "none",
|
|
2648
|
+
stroke: "currentColor",
|
|
2649
|
+
strokeWidth: 2,
|
|
2650
|
+
strokeLinecap: "round",
|
|
2651
|
+
strokeLinejoin: "round",
|
|
2652
|
+
className: "shrink-0",
|
|
2653
|
+
"aria-hidden": "true",
|
|
2654
|
+
children: [
|
|
2655
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M12 7v14" }),
|
|
2656
|
+
/* @__PURE__ */ jsxRuntime.jsx("path", { d: "M3 18a1 1 0 0 1-1-1V4a1 1 0 0 1 1-1h5a4 4 0 0 1 4 4 4 4 0 0 1 4-4h5a1 1 0 0 1 1 1v13a1 1 0 0 1-1 1h-6a3 3 0 0 0-3 3 3 3 0 0 0-3-3z" })
|
|
2657
|
+
]
|
|
2658
|
+
}
|
|
2659
|
+
);
|
|
2660
|
+
}
|
|
2632
2661
|
function SearchIcon({ className } = {}) {
|
|
2633
2662
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2634
2663
|
"svg",
|
|
@@ -2670,12 +2699,12 @@ function CloseIcon() {
|
|
|
2670
2699
|
}
|
|
2671
2700
|
);
|
|
2672
2701
|
}
|
|
2673
|
-
function ChevronDown({ className } = {}) {
|
|
2702
|
+
function ChevronDown({ className, size = 16 } = {}) {
|
|
2674
2703
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2675
2704
|
"svg",
|
|
2676
2705
|
{
|
|
2677
|
-
width:
|
|
2678
|
-
height:
|
|
2706
|
+
width: size,
|
|
2707
|
+
height: size,
|
|
2679
2708
|
viewBox: "0 0 24 24",
|
|
2680
2709
|
fill: "none",
|
|
2681
2710
|
stroke: "currentColor",
|
|
@@ -2689,6 +2718,28 @@ function ChevronDown({ className } = {}) {
|
|
|
2689
2718
|
);
|
|
2690
2719
|
}
|
|
2691
2720
|
var NAV_HOVER_GRADIENT = "var(--nav-hover-gradient)";
|
|
2721
|
+
var NAV_EYEBROW_CLASS = "text-[11px] font-bold uppercase leading-[1.2] tracking-[0.09em] text-[color:var(--sidebar-eyebrow,var(--sidebar-text-muted,var(--muted)))]";
|
|
2722
|
+
var NAV_TOP_ICON_SIZE = 17;
|
|
2723
|
+
var NAV_TOP_ROW_CLASS = (active) => `gap-[11px] px-[10px] py-[9px] text-[13px] leading-none ${active ? "font-semibold" : "font-normal"}`;
|
|
2724
|
+
var NAV_TOP_ACTIVE_CLASS = "bg-[color:var(--sidebar-active-bg,var(--color-accent))] text-[color:var(--sidebar-active-text,white)]";
|
|
2725
|
+
var NAV_TOP_INACTIVE_CLASS = "text-[color:var(--sidebar-row-text,var(--sidebar-text,var(--muted)))] hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel-elevated))] hover:text-[color:var(--sidebar-text,var(--foreground))]";
|
|
2726
|
+
function modeCaption(label) {
|
|
2727
|
+
return label.replace(/\s+Mode$/i, " mode");
|
|
2728
|
+
}
|
|
2729
|
+
function NavActiveRail() {
|
|
2730
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
2731
|
+
"span",
|
|
2732
|
+
{
|
|
2733
|
+
"aria-hidden": "true",
|
|
2734
|
+
className: "pointer-events-none absolute inset-y-0 left-0 w-[2px]",
|
|
2735
|
+
style: { background: "var(--mode-accent, transparent)" }
|
|
2736
|
+
}
|
|
2737
|
+
);
|
|
2738
|
+
}
|
|
2739
|
+
function NavRowBadge({ value }) {
|
|
2740
|
+
if (value === void 0 || value === null || value === "") return null;
|
|
2741
|
+
return /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-auto shrink-0 font-[family-name:var(--font-plex-mono,ui-monospace,monospace)] text-[11px] font-semibold leading-none text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: value });
|
|
2742
|
+
}
|
|
2692
2743
|
function NavSectionRow({
|
|
2693
2744
|
label,
|
|
2694
2745
|
first,
|
|
@@ -2698,9 +2749,9 @@ function NavSectionRow({
|
|
|
2698
2749
|
"p",
|
|
2699
2750
|
{
|
|
2700
2751
|
className: [
|
|
2701
|
-
|
|
2702
|
-
variant === "sub" ? "px-3 pb-0.5" : "px-2 pb-1",
|
|
2703
|
-
first ? "" : "mt-3"
|
|
2752
|
+
NAV_EYEBROW_CLASS,
|
|
2753
|
+
variant === "sub" ? "px-3 pb-0.5" : "px-2 pb-1.5 pt-1",
|
|
2754
|
+
first ? "" : variant === "sub" ? "mt-3" : "mt-[14px]"
|
|
2704
2755
|
].join(" "),
|
|
2705
2756
|
children: label
|
|
2706
2757
|
}
|
|
@@ -2715,39 +2766,32 @@ function NavRow({
|
|
|
2715
2766
|
const Icon = item.icon;
|
|
2716
2767
|
const isSub = variant === "sub";
|
|
2717
2768
|
const washActive = variant !== "top";
|
|
2718
|
-
const activeClasses = washActive ? "bg-[color:var(--mode-accent-surface,var(--panel-elevated))] text-[color:var(--color-accent)] shadow-sm" :
|
|
2769
|
+
const activeClasses = washActive ? "bg-[color:var(--mode-accent-surface,var(--panel-elevated))] text-[color:var(--color-accent)] shadow-sm" : NAV_TOP_ACTIVE_CLASS;
|
|
2719
2770
|
const wrapperClasses = [
|
|
2720
|
-
"group relative block overflow-hidden
|
|
2721
|
-
|
|
2771
|
+
"group relative block overflow-hidden transition",
|
|
2772
|
+
isSub ? "rounded-md" : "rounded-[5px]",
|
|
2773
|
+
active ? activeClasses : isSub ? "text-[color:var(--sidebar-text,var(--muted))] hover:text-white" : NAV_TOP_INACTIVE_CLASS
|
|
2722
2774
|
].join(" ");
|
|
2723
|
-
const rowPadding = isSub ? "px-3 py-1.5 text-[13px]" :
|
|
2724
|
-
const iconSize = isSub ? 16 :
|
|
2725
|
-
const iconClass =
|
|
2775
|
+
const rowPadding = isSub ? "gap-3 px-3 py-1.5 text-[13px] font-semibold" : NAV_TOP_ROW_CLASS(active);
|
|
2776
|
+
const iconSize = isSub ? 16 : NAV_TOP_ICON_SIZE;
|
|
2777
|
+
const iconClass = "text-current";
|
|
2726
2778
|
const inner = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2727
|
-
!active ?
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
className: "pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full",
|
|
2732
|
-
style: { background: NAV_HOVER_GRADIENT }
|
|
2733
|
-
}
|
|
2734
|
-
) : (
|
|
2735
|
-
// Active-row rail, in the Mode's accent. `--mode-accent` is only set by
|
|
2736
|
-
// a declared Mode chrome group, and the inline `transparent` fallback
|
|
2737
|
-
// is what every other app gets — so this span is present but invisible
|
|
2738
|
-
// there, and being absolutely positioned it moves nothing.
|
|
2739
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2779
|
+
!active ? (
|
|
2780
|
+
// Sub rows keep the left→right gradient sweep; top-level rows take a
|
|
2781
|
+
// flat wash on hover (design rail: rgba(255,255,255,.05)).
|
|
2782
|
+
isSub ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2740
2783
|
"span",
|
|
2741
2784
|
{
|
|
2742
2785
|
"aria-hidden": "true",
|
|
2743
|
-
className: "pointer-events-none absolute inset-y-0 left-0 w-[
|
|
2744
|
-
style: { background:
|
|
2786
|
+
className: "pointer-events-none absolute inset-y-0 left-0 w-0 transition-[width] duration-300 group-hover:w-full",
|
|
2787
|
+
style: { background: NAV_HOVER_GRADIENT }
|
|
2745
2788
|
}
|
|
2746
|
-
)
|
|
2747
|
-
),
|
|
2748
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center
|
|
2749
|
-
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: iconSize, className: iconClass }) : null,
|
|
2750
|
-
item.label
|
|
2789
|
+
) : null
|
|
2790
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(NavActiveRail, {}),
|
|
2791
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${rowPadding}`, children: [
|
|
2792
|
+
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: iconSize, className: `shrink-0 ${iconClass}` }) : null,
|
|
2793
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
|
|
2794
|
+
/* @__PURE__ */ jsxRuntime.jsx(NavRowBadge, { value: item.badge })
|
|
2751
2795
|
] })
|
|
2752
2796
|
] });
|
|
2753
2797
|
if (item.disabled) {
|
|
@@ -2786,8 +2830,8 @@ function NavGroup({
|
|
|
2786
2830
|
const Icon = item.icon;
|
|
2787
2831
|
const headerClasses = [
|
|
2788
2832
|
"group relative block w-full overflow-hidden text-left transition",
|
|
2789
|
-
open ? "rounded-t-
|
|
2790
|
-
active ?
|
|
2833
|
+
open ? "rounded-t-[5px]" : "rounded-[5px]",
|
|
2834
|
+
active ? NAV_TOP_ACTIVE_CLASS : open ? "bg-[color:var(--sidebar-row-hover-bg,var(--panel))] text-[color:var(--sidebar-text,var(--foreground))]" : NAV_TOP_INACTIVE_CLASS
|
|
2791
2835
|
].join(" ");
|
|
2792
2836
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2793
2837
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -2801,17 +2845,11 @@ function NavGroup({
|
|
|
2801
2845
|
"aria-expanded": open,
|
|
2802
2846
|
className: headerClasses,
|
|
2803
2847
|
children: [
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
{
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
style: { background: NAV_HOVER_GRADIENT }
|
|
2810
|
-
}
|
|
2811
|
-
) : null,
|
|
2812
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "relative z-10 flex items-center gap-3 px-3 py-2 text-sm font-semibold", children: [
|
|
2813
|
-
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: 18, className: active ? "text-white" : "text-current" }) : null,
|
|
2814
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1", children: item.label }),
|
|
2848
|
+
active ? /* @__PURE__ */ jsxRuntime.jsx(NavActiveRail, {}) : null,
|
|
2849
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: `relative z-10 flex items-center ${NAV_TOP_ROW_CLASS(active)}`, children: [
|
|
2850
|
+
Icon ? /* @__PURE__ */ jsxRuntime.jsx(Icon, { size: NAV_TOP_ICON_SIZE, className: "shrink-0 text-current" }) : null,
|
|
2851
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "min-w-0 flex-1 truncate", children: item.label }),
|
|
2852
|
+
/* @__PURE__ */ jsxRuntime.jsx(NavRowBadge, { value: item.badge }),
|
|
2815
2853
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2816
2854
|
ChevronDown,
|
|
2817
2855
|
{
|
|
@@ -2928,8 +2966,8 @@ function OrgIdCopyButton({ id }) {
|
|
|
2928
2966
|
setTimeout(() => setCopied(false), 1500);
|
|
2929
2967
|
},
|
|
2930
2968
|
title: "Copy organization id",
|
|
2931
|
-
className: "rounded px-1 text-[
|
|
2932
|
-
children: copied ? "Copied" :
|
|
2969
|
+
className: "-ml-1 rounded px-1 text-left font-[family-name:var(--font-plex-mono,ui-monospace,monospace)] text-[12px] leading-[1.2] text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel))]",
|
|
2970
|
+
children: copied ? "Copied" : `\u2026${id.slice(-8)}`
|
|
2933
2971
|
}
|
|
2934
2972
|
);
|
|
2935
2973
|
}
|
|
@@ -2946,7 +2984,8 @@ function NavTopBar({
|
|
|
2946
2984
|
onOpenNav,
|
|
2947
2985
|
navOpen,
|
|
2948
2986
|
search,
|
|
2949
|
-
buildNotes
|
|
2987
|
+
buildNotes,
|
|
2988
|
+
accountMenu = "topbar"
|
|
2950
2989
|
}) {
|
|
2951
2990
|
const rawName = user?.name?.trim() || "";
|
|
2952
2991
|
const hasRealName = rawName.length > 0 && !rawName.includes("@");
|
|
@@ -2954,7 +2993,7 @@ function NavTopBar({
|
|
|
2954
2993
|
const initials = (hasRealName ? rawName : user?.email ?? "P").slice(0, 2).toUpperCase();
|
|
2955
2994
|
const secondary = hasRealName ? user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member" : [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
|
|
2956
2995
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-20", children: [
|
|
2957
|
-
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex h-[var(--topbar-height,60px)] items-center justify-between gap-
|
|
2996
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex h-[var(--topbar-height,60px)] items-center justify-between gap-[14px] border-b border-[color:var(--line)] bg-[color:var(--panel)] px-[var(--topbar-padding-x,20px)]", children: [
|
|
2958
2997
|
onOpenNav ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2959
2998
|
"button",
|
|
2960
2999
|
{
|
|
@@ -2967,8 +3006,8 @@ function NavTopBar({
|
|
|
2967
3006
|
children: /* @__PURE__ */ jsxRuntime.jsx(HamburgerIcon, {})
|
|
2968
3007
|
}
|
|
2969
3008
|
) : null,
|
|
2970
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex w-[320px] max-w-full shrink-0 items-center", children: [
|
|
2971
|
-
/* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "pointer-events-none absolute left-
|
|
3009
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex h-9 w-[320px] max-w-full shrink-0 items-center", children: [
|
|
3010
|
+
/* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "pointer-events-none absolute left-[10px] h-[15px] w-[15px] text-[color:var(--muted)]" }),
|
|
2972
3011
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2973
3012
|
"input",
|
|
2974
3013
|
{
|
|
@@ -2980,32 +3019,35 @@ function NavTopBar({
|
|
|
2980
3019
|
if (e.key === "Enter") search.onSubmit?.(e.target.value);
|
|
2981
3020
|
} : void 0,
|
|
2982
3021
|
readOnly: !search?.onChange,
|
|
2983
|
-
className: "w-full rounded-
|
|
3022
|
+
className: "h-full w-full rounded-[5px] border border-[color:var(--line)] bg-[color:var(--surface-sunken,var(--panel-elevated))] pl-[33px] pr-10 text-[13px] text-[color:var(--foreground)] placeholder:text-[color:var(--muted)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-accent)]"
|
|
2984
3023
|
}
|
|
2985
3024
|
),
|
|
2986
3025
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2987
3026
|
"kbd",
|
|
2988
3027
|
{
|
|
2989
3028
|
"aria-hidden": true,
|
|
2990
|
-
className: "pointer-events-none absolute right-
|
|
3029
|
+
className: "pointer-events-none absolute right-[10px] rounded-[3px] border border-[color:var(--line)] px-[5px] py-px font-[family-name:var(--font-plex-mono,ui-monospace,monospace)] text-[12px] leading-[1.2] text-[color:var(--muted)]",
|
|
2991
3030
|
children: "/"
|
|
2992
3031
|
}
|
|
2993
3032
|
)
|
|
2994
3033
|
] }),
|
|
2995
3034
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative ml-auto flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
|
|
2996
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3035
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2997
3036
|
"button",
|
|
2998
3037
|
{
|
|
2999
3038
|
type: "button",
|
|
3000
3039
|
onClick: buildNotes?.onOpen,
|
|
3001
|
-
className: "shrink-0
|
|
3002
|
-
children:
|
|
3040
|
+
className: "inline-flex h-8 shrink-0 items-center gap-1.5 rounded-[5px] px-3 text-xs font-semibold text-[color:var(--muted)] transition hover:bg-[color:var(--surface-sunken,var(--panel-elevated))] hover:text-[color:var(--foreground)]",
|
|
3041
|
+
children: [
|
|
3042
|
+
/* @__PURE__ */ jsxRuntime.jsx(BookOpenIcon, {}),
|
|
3043
|
+
buildNotes?.label ?? "Build notes"
|
|
3044
|
+
]
|
|
3003
3045
|
}
|
|
3004
3046
|
),
|
|
3005
3047
|
actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsxRuntime.jsx(NavTopBarActionButton, { action }, action.key)) : null,
|
|
3006
3048
|
actions,
|
|
3007
3049
|
themeToggle,
|
|
3008
|
-
/* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
|
|
3050
|
+
accountMenu === "topbar" ? /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
|
|
3009
3051
|
/* @__PURE__ */ jsxRuntime.jsxs("summary", { className: "group/tbtip relative 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", children: [
|
|
3010
3052
|
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-[var(--topbar-icon-button-size,32px)] w-[var(--topbar-icon-button-size,32px)] items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-accent)] text-xs font-bold text-white", children: user?.avatarUrl || user?.memojiUrl ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3011
3053
|
"img",
|
|
@@ -3036,127 +3078,9 @@ function NavTopBar({
|
|
|
3036
3078
|
}
|
|
3037
3079
|
) })
|
|
3038
3080
|
] }),
|
|
3039
|
-
/* @__PURE__ */ jsxRuntime.
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
userMenu?.myProfileHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3043
|
-
"a",
|
|
3044
|
-
{
|
|
3045
|
-
href: safeHref(userMenu.myProfileHref),
|
|
3046
|
-
className: "flex w-full items-center gap-2.5 px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
3047
|
-
children: [
|
|
3048
|
-
/* @__PURE__ */ jsxRuntime.jsx(ProfileIcon, {}),
|
|
3049
|
-
"My Profile"
|
|
3050
|
-
]
|
|
3051
|
-
}
|
|
3052
|
-
) : null,
|
|
3053
|
-
userMenu?.organizationSettingsHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3054
|
-
"a",
|
|
3055
|
-
{
|
|
3056
|
-
href: safeHref(userMenu.organizationSettingsHref),
|
|
3057
|
-
className: "flex w-full items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
3058
|
-
children: [
|
|
3059
|
-
/* @__PURE__ */ jsxRuntime.jsx(BriefcaseIcon, {}),
|
|
3060
|
-
"Organization Settings"
|
|
3061
|
-
]
|
|
3062
|
-
}
|
|
3063
|
-
) : null,
|
|
3064
|
-
userMenu?.roles && userMenu.roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
3065
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Roles & Organizations" }),
|
|
3066
|
-
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1.5", children: userMenu.roles.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-wrap items-center gap-1.5 text-sm", children: [
|
|
3067
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-md bg-[color:var(--panel)] px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-[color:var(--foreground)]", children: r.role }),
|
|
3068
|
-
r.orgName ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[color:var(--muted)]", children: [
|
|
3069
|
-
"in ",
|
|
3070
|
-
r.orgName
|
|
3071
|
-
] }) : null
|
|
3072
|
-
] }, `${r.role}-${i}`)) })
|
|
3073
|
-
] }) : null,
|
|
3074
|
-
userMenu?.accounts && userMenu.accounts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
3075
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Accounts" }),
|
|
3076
|
-
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1", children: userMenu.accounts.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-2.5", children: [
|
|
3077
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3078
|
-
"button",
|
|
3079
|
-
{
|
|
3080
|
-
type: "button",
|
|
3081
|
-
onClick: () => {
|
|
3082
|
-
if (!a.active) userMenu.onSwitchAccount?.(a.id);
|
|
3083
|
-
},
|
|
3084
|
-
className: "flex min-w-0 flex-1 items-center gap-2.5 rounded-lg px-1 py-1 text-left hover:bg-[color:var(--panel)]",
|
|
3085
|
-
children: [
|
|
3086
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-accent)] text-[11px] font-bold text-white", children: a.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: a.avatarUrl, alt: "", className: "h-full w-full object-cover" }) : (a.name ?? a.email ?? "?").slice(0, 2).toUpperCase() }),
|
|
3087
|
-
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col leading-tight", children: [
|
|
3088
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3089
|
-
"span",
|
|
3090
|
-
{
|
|
3091
|
-
className: [
|
|
3092
|
-
"truncate text-sm font-semibold",
|
|
3093
|
-
a.active ? "text-[color:var(--color-accent)]" : "text-[color:var(--foreground)]"
|
|
3094
|
-
].join(" "),
|
|
3095
|
-
children: a.name ?? a.email ?? a.id.slice(0, 8)
|
|
3096
|
-
}
|
|
3097
|
-
),
|
|
3098
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-[color:var(--muted)]", children: a.active ? "Active" : a.email ?? "" })
|
|
3099
|
-
] })
|
|
3100
|
-
]
|
|
3101
|
-
}
|
|
3102
|
-
),
|
|
3103
|
-
!a.active && userMenu.onRemoveAccount ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3104
|
-
"button",
|
|
3105
|
-
{
|
|
3106
|
-
type: "button",
|
|
3107
|
-
"aria-label": `Remove ${a.name ?? a.email ?? "account"}`,
|
|
3108
|
-
onClick: () => userMenu.onRemoveAccount?.(a.id),
|
|
3109
|
-
className: "shrink-0 rounded p-1 text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
|
|
3110
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {})
|
|
3111
|
-
}
|
|
3112
|
-
) : null
|
|
3113
|
-
] }, a.id)) }),
|
|
3114
|
-
userMenu.addAccountHref || userMenu.onAddAccount ? userMenu.addAccountHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3115
|
-
"a",
|
|
3116
|
-
{
|
|
3117
|
-
href: safeHref(userMenu.addAccountHref),
|
|
3118
|
-
className: "mt-1.5 flex items-center gap-2.5 rounded-lg px-1 py-1.5 text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
|
|
3119
|
-
children: [
|
|
3120
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
3121
|
-
"Add Account"
|
|
3122
|
-
]
|
|
3123
|
-
}
|
|
3124
|
-
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3125
|
-
"button",
|
|
3126
|
-
{
|
|
3127
|
-
type: "button",
|
|
3128
|
-
onClick: userMenu.onAddAccount,
|
|
3129
|
-
className: "mt-1.5 flex w-full items-center gap-2.5 rounded-lg px-1 py-1.5 text-left text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
|
|
3130
|
-
children: [
|
|
3131
|
-
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
3132
|
-
"Add Account"
|
|
3133
|
-
]
|
|
3134
|
-
}
|
|
3135
|
-
) : null
|
|
3136
|
-
] }) : null,
|
|
3137
|
-
userMenu?.theme ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[color:var(--line)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3138
|
-
NavThemeControl,
|
|
3139
|
-
{
|
|
3140
|
-
value: userMenu.theme.value,
|
|
3141
|
-
onChange: userMenu.theme.onChange
|
|
3142
|
-
}
|
|
3143
|
-
) }) : null
|
|
3144
|
-
] }),
|
|
3145
|
-
onSignOut ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3146
|
-
"button",
|
|
3147
|
-
{
|
|
3148
|
-
type: "button",
|
|
3149
|
-
onClick: onSignOut,
|
|
3150
|
-
className: "flex w-full shrink-0 items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-accent)]",
|
|
3151
|
-
children: [
|
|
3152
|
-
/* @__PURE__ */ jsxRuntime.jsx(SignOutIcon, {}),
|
|
3153
|
-
"Sign out"
|
|
3154
|
-
]
|
|
3155
|
-
}
|
|
3156
|
-
) : null
|
|
3157
|
-
] })
|
|
3158
|
-
] }),
|
|
3159
|
-
!hasRealName && user ? /* @__PURE__ */ jsxRuntime.jsx(NamePromptBubble, { profileHref: userMenu?.myProfileHref }) : null
|
|
3081
|
+
/* @__PURE__ */ jsxRuntime.jsx(NavAccountMenuPanel, { userMenu, onSignOut, placement: "below" })
|
|
3082
|
+
] }) : null,
|
|
3083
|
+
accountMenu === "topbar" && !hasRealName && user ? /* @__PURE__ */ jsxRuntime.jsx(NamePromptBubble, { profileHref: userMenu?.myProfileHref }) : null
|
|
3160
3084
|
] })
|
|
3161
3085
|
] }),
|
|
3162
3086
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -3171,7 +3095,191 @@ function NavTopBar({
|
|
|
3171
3095
|
)
|
|
3172
3096
|
] });
|
|
3173
3097
|
}
|
|
3174
|
-
function
|
|
3098
|
+
function NavAccountMenuPanel({
|
|
3099
|
+
userMenu,
|
|
3100
|
+
onSignOut,
|
|
3101
|
+
placement
|
|
3102
|
+
}) {
|
|
3103
|
+
const wrapper = placement === "above" ? "absolute bottom-full left-0 right-0 z-40 mb-2 flex max-h-[calc(100vh-5rem)] flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 text-[color:var(--foreground)] shadow-[var(--shadow-soft)]" : "absolute right-0 z-30 mt-2 flex max-h-[calc(100vh-5rem)] w-72 flex-col overflow-hidden rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] py-1 shadow-[var(--shadow-soft)]";
|
|
3104
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: wrapper, children: [
|
|
3105
|
+
placement === "below" ? /* @__PURE__ */ jsxRuntime.jsx(TopBarPanelArrow, {}) : null,
|
|
3106
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "min-h-0 flex-1 overflow-y-auto overscroll-contain", children: [
|
|
3107
|
+
userMenu?.myProfileHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3108
|
+
"a",
|
|
3109
|
+
{
|
|
3110
|
+
href: safeHref(userMenu.myProfileHref),
|
|
3111
|
+
className: "flex w-full items-center gap-2.5 px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
3112
|
+
children: [
|
|
3113
|
+
/* @__PURE__ */ jsxRuntime.jsx(ProfileIcon, {}),
|
|
3114
|
+
"My Profile"
|
|
3115
|
+
]
|
|
3116
|
+
}
|
|
3117
|
+
) : null,
|
|
3118
|
+
userMenu?.organizationSettingsHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3119
|
+
"a",
|
|
3120
|
+
{
|
|
3121
|
+
href: safeHref(userMenu.organizationSettingsHref),
|
|
3122
|
+
className: "flex w-full items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
3123
|
+
children: [
|
|
3124
|
+
/* @__PURE__ */ jsxRuntime.jsx(BriefcaseIcon, {}),
|
|
3125
|
+
"Organization Settings"
|
|
3126
|
+
]
|
|
3127
|
+
}
|
|
3128
|
+
) : null,
|
|
3129
|
+
userMenu?.roles && userMenu.roles.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
3130
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Roles & Organizations" }),
|
|
3131
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1.5", children: userMenu.roles.map((r, i) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex flex-wrap items-center gap-1.5 text-sm", children: [
|
|
3132
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "rounded-md bg-[color:var(--panel)] px-2 py-0.5 text-xs font-bold uppercase tracking-wide text-[color:var(--foreground)]", children: r.role }),
|
|
3133
|
+
r.orgName ? /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "text-[color:var(--muted)]", children: [
|
|
3134
|
+
"in ",
|
|
3135
|
+
r.orgName
|
|
3136
|
+
] }) : null
|
|
3137
|
+
] }, `${r.role}-${i}`)) })
|
|
3138
|
+
] }) : null,
|
|
3139
|
+
userMenu?.accounts && userMenu.accounts.length > 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
3140
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Accounts" }),
|
|
3141
|
+
/* @__PURE__ */ jsxRuntime.jsx("ul", { className: "flex flex-col gap-1", children: userMenu.accounts.map((a) => /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center gap-2.5", children: [
|
|
3142
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3143
|
+
"button",
|
|
3144
|
+
{
|
|
3145
|
+
type: "button",
|
|
3146
|
+
onClick: () => {
|
|
3147
|
+
if (!a.active) userMenu.onSwitchAccount?.(a.id);
|
|
3148
|
+
},
|
|
3149
|
+
className: "flex min-w-0 flex-1 items-center gap-2.5 rounded-lg px-1 py-1 text-left hover:bg-[color:var(--panel)]",
|
|
3150
|
+
children: [
|
|
3151
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[color:var(--color-accent)] text-[11px] font-bold text-white", children: a.avatarUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: a.avatarUrl, alt: "", className: "h-full w-full object-cover" }) : (a.name ?? a.email ?? "?").slice(0, 2).toUpperCase() }),
|
|
3152
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-col leading-tight", children: [
|
|
3153
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3154
|
+
"span",
|
|
3155
|
+
{
|
|
3156
|
+
className: [
|
|
3157
|
+
"truncate text-sm font-semibold",
|
|
3158
|
+
a.active ? "text-[color:var(--color-accent)]" : "text-[color:var(--foreground)]"
|
|
3159
|
+
].join(" "),
|
|
3160
|
+
children: a.name ?? a.email ?? a.id.slice(0, 8)
|
|
3161
|
+
}
|
|
3162
|
+
),
|
|
3163
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-xs text-[color:var(--muted)]", children: a.active ? "Active" : a.email ?? "" })
|
|
3164
|
+
] })
|
|
3165
|
+
]
|
|
3166
|
+
}
|
|
3167
|
+
),
|
|
3168
|
+
!a.active && userMenu.onRemoveAccount ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3169
|
+
"button",
|
|
3170
|
+
{
|
|
3171
|
+
type: "button",
|
|
3172
|
+
"aria-label": `Remove ${a.name ?? a.email ?? "account"}`,
|
|
3173
|
+
onClick: () => userMenu.onRemoveAccount?.(a.id),
|
|
3174
|
+
className: "shrink-0 rounded p-1 text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
|
|
3175
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(TrashIcon, {})
|
|
3176
|
+
}
|
|
3177
|
+
) : null
|
|
3178
|
+
] }, a.id)) }),
|
|
3179
|
+
userMenu.addAccountHref || userMenu.onAddAccount ? userMenu.addAccountHref ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3180
|
+
"a",
|
|
3181
|
+
{
|
|
3182
|
+
href: safeHref(userMenu.addAccountHref),
|
|
3183
|
+
className: "mt-1.5 flex items-center gap-2.5 rounded-lg px-1 py-1.5 text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
|
|
3184
|
+
children: [
|
|
3185
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
3186
|
+
"Add Account"
|
|
3187
|
+
]
|
|
3188
|
+
}
|
|
3189
|
+
) : /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3190
|
+
"button",
|
|
3191
|
+
{
|
|
3192
|
+
type: "button",
|
|
3193
|
+
onClick: userMenu.onAddAccount,
|
|
3194
|
+
className: "mt-1.5 flex w-full items-center gap-2.5 rounded-lg px-1 py-1.5 text-left text-sm font-semibold text-[color:var(--color-accent)] hover:bg-[color:var(--panel)]",
|
|
3195
|
+
children: [
|
|
3196
|
+
/* @__PURE__ */ jsxRuntime.jsx(AddUserIcon, {}),
|
|
3197
|
+
"Add Account"
|
|
3198
|
+
]
|
|
3199
|
+
}
|
|
3200
|
+
) : null
|
|
3201
|
+
] }) : null,
|
|
3202
|
+
userMenu?.theme ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-[color:var(--line)]", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3203
|
+
NavThemeControl,
|
|
3204
|
+
{
|
|
3205
|
+
value: userMenu.theme.value,
|
|
3206
|
+
onChange: userMenu.theme.onChange
|
|
3207
|
+
}
|
|
3208
|
+
) }) : null,
|
|
3209
|
+
userMenu?.navDisplay ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
3210
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-2 text-[11px] font-semibold uppercase tracking-[0.08em] text-[color:var(--muted)]", children: "Navigation display" }),
|
|
3211
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { role: "radiogroup", "aria-label": "Navigation display", className: "flex flex-col gap-0.5", children: NAV_DISPLAY_OPTIONS.map((opt) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3212
|
+
"button",
|
|
3213
|
+
{
|
|
3214
|
+
type: "button",
|
|
3215
|
+
role: "radio",
|
|
3216
|
+
"aria-checked": userMenu.navDisplay?.value === opt.value,
|
|
3217
|
+
onClick: () => userMenu.navDisplay?.onChange(opt.value),
|
|
3218
|
+
className: [
|
|
3219
|
+
"flex w-full items-center justify-between rounded-md px-2 py-1.5 text-left text-sm font-medium",
|
|
3220
|
+
userMenu.navDisplay?.value === opt.value ? "text-[color:var(--color-accent)]" : "text-[color:var(--foreground)] hover:bg-[color:var(--panel)]"
|
|
3221
|
+
].join(" "),
|
|
3222
|
+
children: [
|
|
3223
|
+
opt.label,
|
|
3224
|
+
userMenu.navDisplay?.value === opt.value ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, children: "\u2713" }) : null
|
|
3225
|
+
]
|
|
3226
|
+
},
|
|
3227
|
+
opt.value
|
|
3228
|
+
)) })
|
|
3229
|
+
] }) : null
|
|
3230
|
+
] }),
|
|
3231
|
+
onSignOut ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3232
|
+
"button",
|
|
3233
|
+
{
|
|
3234
|
+
type: "button",
|
|
3235
|
+
onClick: onSignOut,
|
|
3236
|
+
className: "flex w-full shrink-0 items-center gap-2.5 border-t border-[color:var(--line)] px-4 py-2.5 text-left text-sm font-medium text-[color:var(--foreground)] hover:bg-[color:var(--panel)] hover:text-[color:var(--color-accent)]",
|
|
3237
|
+
children: [
|
|
3238
|
+
/* @__PURE__ */ jsxRuntime.jsx(SignOutIcon, {}),
|
|
3239
|
+
"Sign out"
|
|
3240
|
+
]
|
|
3241
|
+
}
|
|
3242
|
+
) : null
|
|
3243
|
+
] });
|
|
3244
|
+
}
|
|
3245
|
+
function NavSidebarUserCard({
|
|
3246
|
+
user,
|
|
3247
|
+
userMenu,
|
|
3248
|
+
onSignOut
|
|
3249
|
+
}) {
|
|
3250
|
+
const rawName = user.name?.trim() || "";
|
|
3251
|
+
const hasRealName = rawName.length > 0 && !rawName.includes("@");
|
|
3252
|
+
const displayName = hasRealName ? rawName : user.email ?? "Signed in";
|
|
3253
|
+
const initials = (hasRealName ? rawName : user.email ?? "P").slice(0, 2).toUpperCase();
|
|
3254
|
+
const secondary = hasRealName ? user.email || [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member" : [user.tier, user.role].filter(Boolean).join(" \xB7 ") || "member";
|
|
3255
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("details", { "data-nav-details": true, className: "group/acct relative", children: [
|
|
3256
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3257
|
+
"summary",
|
|
3258
|
+
{
|
|
3259
|
+
"aria-label": "My Account",
|
|
3260
|
+
className: "flex w-full cursor-pointer list-none items-center gap-[9px] rounded-[5px] px-1 py-1 text-left transition hover:bg-[color:var(--sidebar-row-hover-bg,var(--panel-elevated))] [&::-webkit-details-marker]:hidden",
|
|
3261
|
+
children: [
|
|
3262
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-7 w-7 shrink-0 items-center justify-center overflow-hidden rounded-full bg-[color:var(--sidebar-avatar-bg,var(--color-accent))] text-[11px] font-bold text-white", children: user.avatarUrl || user.memojiUrl ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: user.avatarUrl || user.memojiUrl, alt: "", className: "h-full w-full object-cover" }) : initials }),
|
|
3263
|
+
/* @__PURE__ */ jsxRuntime.jsxs("span", { className: "flex min-w-0 flex-1 flex-col", children: [
|
|
3264
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[12px] font-semibold leading-[1.2] text-[color:var(--sidebar-text,var(--foreground))]", children: displayName }),
|
|
3265
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "truncate text-[11px] leading-[1.3] text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))]", children: secondary })
|
|
3266
|
+
] }),
|
|
3267
|
+
/* @__PURE__ */ jsxRuntime.jsx(ChevronDown, { size: 14, className: "shrink-0 rotate-180 text-[color:var(--sidebar-caption,var(--sidebar-text-muted,var(--muted)))] transition group-open/acct:rotate-0" })
|
|
3268
|
+
]
|
|
3269
|
+
}
|
|
3270
|
+
),
|
|
3271
|
+
/* @__PURE__ */ jsxRuntime.jsx(NavAccountMenuPanel, { userMenu, onSignOut, placement: "above" }),
|
|
3272
|
+
!hasRealName ? /* @__PURE__ */ jsxRuntime.jsx(NamePromptBubble, { profileHref: userMenu?.myProfileHref, placement: "above" }) : null
|
|
3273
|
+
] });
|
|
3274
|
+
}
|
|
3275
|
+
function hexToRgba(hex, alpha) {
|
|
3276
|
+
if (!hex) return void 0;
|
|
3277
|
+
const m = /^#?([0-9a-f]{6})$/i.exec(hex.trim());
|
|
3278
|
+
if (!m) return void 0;
|
|
3279
|
+
const n = parseInt(m[1], 16);
|
|
3280
|
+
return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${alpha})`;
|
|
3281
|
+
}
|
|
3282
|
+
function NamePromptBubble({ profileHref, placement = "below" }) {
|
|
3175
3283
|
const KEY = "politogy_name_prompt_dismissed";
|
|
3176
3284
|
const [dismissed, setDismissed] = react.useState(true);
|
|
3177
3285
|
react.useEffect(() => {
|
|
@@ -3182,42 +3290,48 @@ function NamePromptBubble({ profileHref }) {
|
|
|
3182
3290
|
}
|
|
3183
3291
|
}, []);
|
|
3184
3292
|
if (dismissed) return null;
|
|
3185
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
"
|
|
3198
|
-
{
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
{
|
|
3207
|
-
type: "button",
|
|
3208
|
-
onClick: () => {
|
|
3209
|
-
setDismissed(true);
|
|
3210
|
-
try {
|
|
3211
|
-
sessionStorage.setItem(KEY, "1");
|
|
3212
|
-
} catch {
|
|
3293
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3294
|
+
"div",
|
|
3295
|
+
{
|
|
3296
|
+
className: placement === "above" ? "absolute bottom-full left-0 z-30 mb-2 w-64 rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] p-3 text-left shadow-[var(--shadow-soft)]" : "absolute right-4 top-full z-30 mt-2 w-64 rounded-xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] p-3 shadow-[var(--shadow-soft)]",
|
|
3297
|
+
children: [
|
|
3298
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3299
|
+
"span",
|
|
3300
|
+
{
|
|
3301
|
+
"aria-hidden": true,
|
|
3302
|
+
className: placement === "above" ? "absolute -bottom-[5px] left-[14px] h-2.5 w-2.5 rotate-45 border-b border-r border-[color:var(--line)] bg-[color:var(--panel-elevated)]" : "absolute -top-[5px] right-[11px] h-2.5 w-2.5 rotate-45 border-l border-t border-[color:var(--line)] bg-[color:var(--panel-elevated)]"
|
|
3303
|
+
}
|
|
3304
|
+
),
|
|
3305
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-semibold text-[color:var(--foreground)]", children: "Add your name" }),
|
|
3306
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-0.5 text-xs leading-snug text-[color:var(--muted)]", children: "Set your first and last name so teammates see you \u2014 not your email." }),
|
|
3307
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-2 flex items-center gap-2", children: [
|
|
3308
|
+
profileHref ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3309
|
+
"a",
|
|
3310
|
+
{
|
|
3311
|
+
href: safeHref(profileHref),
|
|
3312
|
+
className: "rounded-full bg-[color:var(--color-accent)] px-3 py-1 text-xs font-semibold text-white hover:opacity-90",
|
|
3313
|
+
children: "Set name"
|
|
3213
3314
|
}
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3315
|
+
) : null,
|
|
3316
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3317
|
+
"button",
|
|
3318
|
+
{
|
|
3319
|
+
type: "button",
|
|
3320
|
+
onClick: () => {
|
|
3321
|
+
setDismissed(true);
|
|
3322
|
+
try {
|
|
3323
|
+
sessionStorage.setItem(KEY, "1");
|
|
3324
|
+
} catch {
|
|
3325
|
+
}
|
|
3326
|
+
},
|
|
3327
|
+
className: "rounded-full border border-[color:var(--line)] px-3 py-1 text-xs font-semibold text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
3328
|
+
children: "Dismiss"
|
|
3329
|
+
}
|
|
3330
|
+
)
|
|
3331
|
+
] })
|
|
3332
|
+
]
|
|
3333
|
+
}
|
|
3334
|
+
);
|
|
3221
3335
|
}
|
|
3222
3336
|
function formatFirstLast(name) {
|
|
3223
3337
|
const parts = name.split(/\s+/).filter(Boolean);
|
|
@@ -3278,8 +3392,8 @@ function NavTopBarActionButton({ action }) {
|
|
|
3278
3392
|
const BrandGlyph = action.slot ? resolveBrandGlyph(glyphName) : null;
|
|
3279
3393
|
const Glyph = BrandGlyph ?? Icon;
|
|
3280
3394
|
const content = /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
3281
|
-
/* @__PURE__ */ jsxRuntime.jsx(Glyph, { size:
|
|
3282
|
-
typeof action.badge === "number" && action.badge > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-
|
|
3395
|
+
/* @__PURE__ */ jsxRuntime.jsx(Glyph, { size: TOPBAR_GLYPH_SIZE, className: "text-current" }),
|
|
3396
|
+
typeof action.badge === "number" && action.badge > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "absolute -top-[5px] -right-[5px] flex h-4 min-w-4 items-center justify-center rounded-full bg-[color:var(--chrome-danger,var(--color-accent))] px-1 text-[10px] font-bold leading-4 text-white", children: action.badge }) : null,
|
|
3283
3397
|
/* @__PURE__ */ jsxRuntime.jsx(TopBarTooltip, { title: action.label, description: action.description })
|
|
3284
3398
|
] });
|
|
3285
3399
|
const isExternal = action.href ? /^https?:\/\//.test(action.href) : false;
|
|
@@ -3406,6 +3520,7 @@ function NavAppShell({
|
|
|
3406
3520
|
topBar,
|
|
3407
3521
|
betaBanner,
|
|
3408
3522
|
contentWrapper = "padded",
|
|
3523
|
+
accountMenuPlacement = "sidebar",
|
|
3409
3524
|
modeId,
|
|
3410
3525
|
children
|
|
3411
3526
|
}) {
|
|
@@ -3422,15 +3537,29 @@ function NavAppShell({
|
|
|
3422
3537
|
document.body.style.overflow = previous;
|
|
3423
3538
|
};
|
|
3424
3539
|
}, [navOpen]);
|
|
3540
|
+
const sidebarFooter = accountMenuPlacement === "sidebar" && topBar.user ? {
|
|
3541
|
+
...sidebar.footer ?? {},
|
|
3542
|
+
user: sidebar.footer?.user ?? topBar.user,
|
|
3543
|
+
userMenu: sidebar.footer?.userMenu ?? topBar.userMenu,
|
|
3544
|
+
onSignOut: sidebar.footer?.onSignOut ?? topBar.onSignOut
|
|
3545
|
+
} : sidebar.footer;
|
|
3425
3546
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3426
3547
|
"div",
|
|
3427
3548
|
{
|
|
3428
3549
|
"data-politogy-mode": modeId,
|
|
3429
3550
|
className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
|
|
3430
3551
|
children: [
|
|
3431
|
-
/* @__PURE__ */ jsxRuntime.jsx(NavSidebar, { ...sidebar, open: navOpen, onClose: () => setNavOpen(false) }),
|
|
3432
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:pl-[
|
|
3433
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3552
|
+
/* @__PURE__ */ jsxRuntime.jsx(NavSidebar, { ...sidebar, footer: sidebarFooter, open: navOpen, onClose: () => setNavOpen(false) }),
|
|
3553
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "lg:pl-[var(--sidebar-width,236px)]", children: [
|
|
3554
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3555
|
+
NavTopBar,
|
|
3556
|
+
{
|
|
3557
|
+
...topBar,
|
|
3558
|
+
accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar"),
|
|
3559
|
+
onOpenNav: () => setNavOpen(true),
|
|
3560
|
+
navOpen
|
|
3561
|
+
}
|
|
3562
|
+
),
|
|
3434
3563
|
betaBanner ? /* @__PURE__ */ jsxRuntime.jsx(NavBetaBanner, { ...betaBanner }) : null,
|
|
3435
3564
|
topBar.title ? /* @__PURE__ */ jsxRuntime.jsx("h1", { className: "px-6 pt-7 text-xl font-semibold text-[color:var(--foreground)]", children: topBar.title }) : null,
|
|
3436
3565
|
contentWrapper === "bare" ? /* @__PURE__ */ jsxRuntime.jsx("div", { "data-shell-content": "", className: topBar.title ? "mt-[22px]" : void 0, children }) : (
|
|
@@ -4108,7 +4237,12 @@ var MODE_BRAND_LOGOS = {
|
|
|
4108
4237
|
var modeBrandLogo = (mode) => mode && MODE_BRAND_LOGOS[mode] || DEFAULT_BRAND_LOGO;
|
|
4109
4238
|
var POLITOGY_APPS = {
|
|
4110
4239
|
vrm: { title: "Politogy VRM", origin: "https://app.politogyvrm.com", storagePrefix: "vrm" },
|
|
4111
|
-
contacts: {
|
|
4240
|
+
contacts: {
|
|
4241
|
+
title: "Contacts",
|
|
4242
|
+
origin: "https://contacts.politogyvrm.com",
|
|
4243
|
+
storagePrefix: "contacts",
|
|
4244
|
+
pageTitle: false
|
|
4245
|
+
},
|
|
4112
4246
|
forms: { title: "Forms", origin: "https://forms.politogyvrm.com", storagePrefix: "forms" },
|
|
4113
4247
|
surveys: { title: "Surveys", origin: "https://surveys.politogyvrm.com", storagePrefix: "surveys" },
|
|
4114
4248
|
polls: { title: "Polls", origin: "https://polls.politogyvrm.com", storagePrefix: "polls" },
|
|
@@ -4149,6 +4283,9 @@ var POLITOGY_APPS = {
|
|
|
4149
4283
|
canvass: { title: "Field Canvassing", origin: "https://canvass.politogyvrm.com", storagePrefix: "canvass", mode: "campaign" },
|
|
4150
4284
|
signs: { title: "Sign Mapping", origin: "https://signs.politogyvrm.com", storagePrefix: "signs", mode: "campaign" }
|
|
4151
4285
|
};
|
|
4286
|
+
var DEFAULT_SEARCH_PLACEHOLDER = {
|
|
4287
|
+
contacts: "Search contacts, segments, forms"
|
|
4288
|
+
};
|
|
4152
4289
|
function PolitogyAppFrame({
|
|
4153
4290
|
app,
|
|
4154
4291
|
pathname,
|
|
@@ -4307,10 +4444,11 @@ function FrameBody({
|
|
|
4307
4444
|
// under it. This is routing data, not chrome configuration.
|
|
4308
4445
|
contactsItem: data?.contactsItem,
|
|
4309
4446
|
petitionsItem: data?.petitionsItem,
|
|
4447
|
+
hiddenItems: data?.hiddenNavItems,
|
|
4310
4448
|
mode: navMode,
|
|
4311
4449
|
activeOrgId
|
|
4312
4450
|
}),
|
|
4313
|
-
[data?.contactsItem, data?.petitionsItem, navMode, activeOrgId]
|
|
4451
|
+
[data?.contactsItem, data?.petitionsItem, data?.hiddenNavItems, navMode, activeOrgId]
|
|
4314
4452
|
);
|
|
4315
4453
|
const navItems = core?.nav ?? derivedNavItems;
|
|
4316
4454
|
const navIsActive = react.useMemo(() => {
|
|
@@ -4359,7 +4497,7 @@ function FrameBody({
|
|
|
4359
4497
|
// A flat rail's sub-menu IS the nav, so the 'tabs only' preference
|
|
4360
4498
|
// (which strips children) would leave one childless parent row —
|
|
4361
4499
|
// flat apps ignore the stripping.
|
|
4362
|
-
items: navDisplay === "tabs" && meta.navShape !== "flat" ? navItems.map(({ children: _sub, ...item }) => item) : navItems,
|
|
4500
|
+
items: (navDisplay === "tabs" || data?.flatNav === true) && meta.navShape !== "flat" ? navItems.map(({ children: _sub, ...item }) => item) : navItems,
|
|
4363
4501
|
isActive: navIsActive,
|
|
4364
4502
|
flatten: meta.navShape === "flat"
|
|
4365
4503
|
},
|
|
@@ -4386,7 +4524,7 @@ function FrameBody({
|
|
|
4386
4524
|
topBar: {
|
|
4387
4525
|
// Core's pages publish their own identity; every other app is one
|
|
4388
4526
|
// product surface and takes its registry title.
|
|
4389
|
-
title: core?.page?.title ?? (grants?.includes("title") ? data?.frame?.title : void 0) ?? meta.title,
|
|
4527
|
+
title: core?.page?.title ?? (grants?.includes("title") ? data?.frame?.title : void 0) ?? (meta.pageTitle === false ? void 0 : meta.title),
|
|
4390
4528
|
breadcrumbs,
|
|
4391
4529
|
user: {
|
|
4392
4530
|
name: identity.userName,
|
|
@@ -4398,6 +4536,15 @@ function FrameBody({
|
|
|
4398
4536
|
},
|
|
4399
4537
|
userMenu,
|
|
4400
4538
|
onSignOut: handleSignOut,
|
|
4539
|
+
// Reference/UI-Platform "Top bar — required elements": Universal
|
|
4540
|
+
// search is the only thing on the left end of the bar. No app wires
|
|
4541
|
+
// search yet, so this stays decorative (`NavTopBarProps.search` — "an
|
|
4542
|
+
// app that has not wired search yet still gets the correct chrome").
|
|
4543
|
+
search: { placeholder: data?.searchPlaceholder ?? DEFAULT_SEARCH_PLACEHOLDER[app] ?? "Search" },
|
|
4544
|
+
// "Build notes" — a quiet text button that starts the right-hand
|
|
4545
|
+
// group. The spec names the element and its position but not its
|
|
4546
|
+
// destination content; `onOpen` is left unset until that is defined.
|
|
4547
|
+
buildNotes: {},
|
|
4401
4548
|
// The action cluster is IDENTICAL everywhere — core included. Page
|
|
4402
4549
|
// actions sit BEFORE it, never inside it, so the Alerts bell keeps its
|
|
4403
4550
|
// required position: farthest right, immediately before My Account.
|
|
@@ -4792,8 +4939,6 @@ function ChromeTopBarActions() {
|
|
|
4792
4939
|
const state = useChromeState();
|
|
4793
4940
|
if (!state) return null;
|
|
4794
4941
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
4795
|
-
/* @__PURE__ */ jsxRuntime.jsx(FuelAction, { orgId: state.orgId }),
|
|
4796
|
-
/* @__PURE__ */ jsxRuntime.jsx(NavDisplayAction, { value: state.navDisplay, onChange: state.setNavDisplay }),
|
|
4797
4942
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4798
4943
|
TopBarWidgetSlot,
|
|
4799
4944
|
{
|
|
@@ -4802,9 +4947,10 @@ function ChromeTopBarActions() {
|
|
|
4802
4947
|
children: /* @__PURE__ */ jsxRuntime.jsx(ChromeDevNotesMenu, {})
|
|
4803
4948
|
}
|
|
4804
4949
|
),
|
|
4950
|
+
/* @__PURE__ */ jsxRuntime.jsx(FuelAction, { orgId: state.orgId }),
|
|
4805
4951
|
/* @__PURE__ */ jsxRuntime.jsx(SpecOverlayAction, { orgId: state.orgId, orgName: state.orgs.find((o) => o.id === state.orgId)?.name ?? null }),
|
|
4806
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4807
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4952
|
+
/* @__PURE__ */ jsxRuntime.jsx(NotificationsAction, { orgId: state.orgId }),
|
|
4953
|
+
/* @__PURE__ */ jsxRuntime.jsx(SupportAction, { orgId: state.orgId })
|
|
4808
4954
|
] });
|
|
4809
4955
|
}
|
|
4810
4956
|
function ChromeDevNotesMenu() {
|
|
@@ -4858,7 +5004,8 @@ function useChromeUserMenu({
|
|
|
4858
5004
|
roles: (state?.orgs ?? []).filter((o) => o.rawRole || o.role).map((o) => ({ role: o.rawRole ?? o.role, orgName: o.name })),
|
|
4859
5005
|
accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],
|
|
4860
5006
|
addAccountHref: `${coreBase}/my-profile#accounts`,
|
|
4861
|
-
theme: { value: theme.value, onChange: theme.setValue }
|
|
5007
|
+
theme: { value: theme.value, onChange: theme.setValue },
|
|
5008
|
+
navDisplay: state ? { value: state.navDisplay, onChange: state.setNavDisplay } : void 0
|
|
4862
5009
|
};
|
|
4863
5010
|
}
|
|
4864
5011
|
var MODE_DEFS = [
|
|
@@ -4921,10 +5068,19 @@ function useChromeMode(arg = {}) {
|
|
|
4921
5068
|
return {
|
|
4922
5069
|
label: current.label,
|
|
4923
5070
|
icon: current.icon,
|
|
4924
|
-
|
|
4925
|
-
|
|
5071
|
+
// Left-Navigation §7 / Reference/UI-Platform: always the row of three icon
|
|
5072
|
+
// buttons. A mode the organization does not hold is shown dimmed and not
|
|
5073
|
+
// selectable, never hidden. Before entitlements land only the current mode
|
|
5074
|
+
// reads as available (no layout shift, nothing clickable it shouldn't be).
|
|
5075
|
+
options: MODE_DEFS.map((o) => ({
|
|
5076
|
+
id: o.id,
|
|
5077
|
+
label: o.label,
|
|
5078
|
+
icon: o.icon,
|
|
5079
|
+
available: entitled ? Boolean(entitled[o.id]) || o.id === current.id : o.id === current.id
|
|
5080
|
+
})),
|
|
5081
|
+
onSelect: options.length > 0 ? (id) => {
|
|
4926
5082
|
const def = MODE_DEFS.find((m) => m.id === id);
|
|
4927
|
-
if (!def) return;
|
|
5083
|
+
if (!def || !entitled?.[def.id]) return;
|
|
4928
5084
|
setSelectedModeId(id);
|
|
4929
5085
|
try {
|
|
4930
5086
|
localStorage.setItem(MODE_STORAGE_KEY, id);
|