@the-portland-company/shell 0.96.2 → 0.97.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 +12 -0
- package/dist/app-chrome.cjs +41 -624
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +6 -3
- package/dist/app-chrome.d.ts +6 -3
- package/dist/app-chrome.js +14 -23
- package/dist/app-chrome.js.map +1 -1
- package/dist/{chunk-537NZZVP.js → chunk-VAQNZD37.js} +32 -4
- package/dist/chunk-VAQNZD37.js.map +1 -0
- package/dist/{chunk-SKXBGQ33.js → chunk-WQR42AGC.js} +7 -6
- package/dist/chunk-WQR42AGC.js.map +1 -0
- package/dist/{index-HwDXhFOA.d.ts → index-BEMGfLpI.d.ts} +24 -1
- package/dist/{index-DJtKw0Fd.d.cts → index-BaUIPQpN.d.cts} +24 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/native.cjs +35 -3
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +1 -1
- package/dist/native.d.ts +1 -1
- package/dist/native.js +2 -2
- package/package.json +1 -1
- package/dist/chunk-537NZZVP.js.map +0 -1
- package/dist/chunk-SKXBGQ33.js.map +0 -1
package/dist/app-chrome.cjs
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var clsx = require('clsx');
|
|
6
6
|
var fi = require('react-icons/fi');
|
|
7
|
-
|
|
8
|
-
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
require('react-dom');
|
|
9
8
|
var lu = require('react-icons/lu');
|
|
9
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
10
10
|
var devnotes = require('@the-portland-company/devnotes');
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -575,7 +575,6 @@ var SETTINGS_APP_ORIGIN = "https://settings.politogyvrm.com";
|
|
|
575
575
|
var CORE_BILLING_PATH = "/organization-settings/subscription-billing";
|
|
576
576
|
var CORE_BILLING_URL = `${SETTINGS_APP_ORIGIN}${CORE_BILLING_PATH}`;
|
|
577
577
|
var QUARANTINED_CONTACTS_URL = `https://contacts.politogyvrm.com/duplicates`;
|
|
578
|
-
var SPECS_ORIGIN = "https://specs.politogyvrm.com";
|
|
579
578
|
function withOrgParam(url, orgId) {
|
|
580
579
|
if (!orgId) return url;
|
|
581
580
|
return `${url}${url.includes("?") ? "&" : "?"}org=${orgId}`;
|
|
@@ -653,16 +652,6 @@ function TopBarPanelArrow() {
|
|
|
653
652
|
}
|
|
654
653
|
);
|
|
655
654
|
}
|
|
656
|
-
function TopBarWidgetSlot({
|
|
657
|
-
title,
|
|
658
|
-
description,
|
|
659
|
-
children
|
|
660
|
-
}) {
|
|
661
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "topbar-widget-slot group/tbtip relative inline-flex", children: [
|
|
662
|
-
children,
|
|
663
|
-
/* @__PURE__ */ jsxRuntime.jsx(TopBarTooltip, { title, description })
|
|
664
|
-
] });
|
|
665
|
-
}
|
|
666
655
|
var THEME_OPTIONS = [
|
|
667
656
|
{ value: "light", label: "Light" }
|
|
668
657
|
];
|
|
@@ -946,23 +935,6 @@ function BellOffGlyph({ size = 14, className }) {
|
|
|
946
935
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "1", y1: "1", x2: "23", y2: "23" })
|
|
947
936
|
] });
|
|
948
937
|
}
|
|
949
|
-
function LifeBuoyGlyph({ size = TOPBAR_GLYPH_SIZE, className }) {
|
|
950
|
-
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: [
|
|
951
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "10" }),
|
|
952
|
-
/* @__PURE__ */ jsxRuntime.jsx("circle", { cx: "12", cy: "12", r: "4" }),
|
|
953
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4.93", y1: "4.93", x2: "9.17", y2: "9.17" }),
|
|
954
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "14.83", y1: "14.83", x2: "19.07", y2: "19.07" }),
|
|
955
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "14.83", y1: "9.17", x2: "19.07", y2: "4.93" }),
|
|
956
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "4.93", y1: "19.07", x2: "9.17", y2: "14.83" })
|
|
957
|
-
] });
|
|
958
|
-
}
|
|
959
|
-
function LayoutGlyph({ size = TOPBAR_GLYPH_SIZE, className }) {
|
|
960
|
-
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: [
|
|
961
|
-
/* @__PURE__ */ jsxRuntime.jsx("rect", { x: "3", y: "3", width: "18", height: "18", rx: "2", ry: "2" }),
|
|
962
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "3", y1: "9", x2: "21", y2: "9" }),
|
|
963
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "9", y1: "21", x2: "9", y2: "9" })
|
|
964
|
-
] });
|
|
965
|
-
}
|
|
966
938
|
function PlusGlyph({ size = 14, className }) {
|
|
967
939
|
return /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", strokeLinejoin: "round", className, "aria-hidden": true, children: [
|
|
968
940
|
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "12", y1: "5", x2: "12", y2: "19" }),
|
|
@@ -1596,586 +1568,39 @@ function NotificationsAction({ orgId }) {
|
|
|
1596
1568
|
] })
|
|
1597
1569
|
);
|
|
1598
1570
|
}
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
}
|
|
1609
|
-
function SupportAction({
|
|
1610
|
-
orgId,
|
|
1611
|
-
orgs: knownOrgs
|
|
1612
|
-
} = {}) {
|
|
1613
|
-
const { fetchJson } = useNavChrome("SupportAction");
|
|
1614
|
-
const { me, loaded } = useChromeMe();
|
|
1615
|
-
const { orgs: fetchedOrgs } = useChromeOrgs({ enabled: !knownOrgs });
|
|
1616
|
-
const orgs = knownOrgs ?? fetchedOrgs;
|
|
1617
|
-
const [open, setOpen] = react.useState(false);
|
|
1618
|
-
const [message, setMessage] = react.useState("");
|
|
1619
|
-
const [email, setEmail] = react.useState("");
|
|
1620
|
-
const [phone, setPhone] = react.useState("");
|
|
1621
|
-
const [showEmailError, setShowEmailError] = react.useState(false);
|
|
1622
|
-
const [state, setState] = react.useState("idle");
|
|
1623
|
-
const meEmail = me?.email ?? null;
|
|
1624
|
-
const mePhone = me?.phone ?? null;
|
|
1625
|
-
const missingEmail = loaded && !meEmail;
|
|
1626
|
-
const missingPhone = loaded && !mePhone;
|
|
1627
|
-
const activeOrg = (orgId ? orgs?.find((o) => o.id === orgId) : null) ?? (orgs && orgs.length === 1 ? orgs[0] : null);
|
|
1628
|
-
const orgName = activeOrg?.name ?? null;
|
|
1629
|
-
const close = react.useCallback(() => {
|
|
1630
|
-
setOpen(false);
|
|
1631
|
-
setState("idle");
|
|
1632
|
-
setMessage("");
|
|
1633
|
-
setShowEmailError(false);
|
|
1634
|
-
}, []);
|
|
1635
|
-
react.useEffect(() => {
|
|
1636
|
-
if (!open) return;
|
|
1637
|
-
setEmail(meEmail ?? "");
|
|
1638
|
-
setPhone(mePhone ?? "");
|
|
1639
|
-
setShowEmailError(false);
|
|
1640
|
-
}, [open, meEmail, mePhone]);
|
|
1641
|
-
react.useEffect(() => {
|
|
1642
|
-
if (!open) return;
|
|
1643
|
-
const onKey = (e) => {
|
|
1644
|
-
if (e.key === "Escape") close();
|
|
1645
|
-
};
|
|
1646
|
-
document.addEventListener("keydown", onKey);
|
|
1647
|
-
return () => document.removeEventListener("keydown", onKey);
|
|
1648
|
-
}, [open, close]);
|
|
1649
|
-
const submit = async () => {
|
|
1650
|
-
if (!message.trim() || state === "sending") return;
|
|
1651
|
-
const resolvedEmail = (missingEmail ? email : meEmail ?? "").trim();
|
|
1652
|
-
const resolvedPhone = (missingPhone ? phone : mePhone ?? "").trim();
|
|
1653
|
-
if (missingEmail && !resolvedEmail) {
|
|
1654
|
-
setShowEmailError(true);
|
|
1655
|
-
return;
|
|
1656
|
-
}
|
|
1657
|
-
setShowEmailError(false);
|
|
1658
|
-
const collectedContact = missingEmail || missingPhone;
|
|
1659
|
-
const fullMessage = composeSupportMessage({
|
|
1660
|
-
note: message,
|
|
1661
|
-
pageTitle: typeof document !== "undefined" ? document.title : "",
|
|
1662
|
-
url: typeof window !== "undefined" ? window.location.href : "",
|
|
1663
|
-
orgName,
|
|
1664
|
-
replyEmail: collectedContact ? resolvedEmail : void 0,
|
|
1665
|
-
replyPhone: collectedContact ? resolvedPhone : void 0
|
|
1666
|
-
});
|
|
1667
|
-
setState("sending");
|
|
1668
|
-
try {
|
|
1669
|
-
await fetchJson("support", {
|
|
1670
|
-
method: "POST",
|
|
1671
|
-
headers: { "Content-Type": "application/json" },
|
|
1672
|
-
body: JSON.stringify({ message: fullMessage })
|
|
1673
|
-
});
|
|
1674
|
-
setState("sent");
|
|
1675
|
-
} catch {
|
|
1676
|
-
setState("error");
|
|
1677
|
-
}
|
|
1678
|
-
};
|
|
1679
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1680
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1681
|
-
"button",
|
|
1682
|
-
{
|
|
1683
|
-
type: "button",
|
|
1684
|
-
"aria-label": "Support",
|
|
1685
|
-
className: topBarIconButtonClass(),
|
|
1686
|
-
onClick: () => setOpen(true),
|
|
1687
|
-
children: [
|
|
1688
|
-
/* @__PURE__ */ jsxRuntime.jsx(SlotGlyph, { slot: "support", fallback: LifeBuoyGlyph }),
|
|
1689
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1690
|
-
TopBarTooltip,
|
|
1691
|
-
{
|
|
1692
|
-
title: "Support",
|
|
1693
|
-
description: "Send a support request to the Politogy team."
|
|
1694
|
-
}
|
|
1695
|
-
)
|
|
1696
|
-
]
|
|
1697
|
-
}
|
|
1698
|
-
),
|
|
1699
|
-
open && typeof document !== "undefined" ? reactDom.createPortal(
|
|
1700
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1701
|
-
"div",
|
|
1702
|
-
{
|
|
1703
|
-
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
|
|
1704
|
-
role: "dialog",
|
|
1705
|
-
"aria-modal": "true",
|
|
1706
|
-
"aria-label": "Support request",
|
|
1707
|
-
onMouseDown: (e) => {
|
|
1708
|
-
if (e.target === e.currentTarget) close();
|
|
1709
|
-
},
|
|
1710
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-md rounded-2xl border border-[color:var(--line)] bg-[color:var(--panel-elevated)] p-6 shadow-[var(--shadow-soft)]", children: [
|
|
1711
|
-
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]", children: "Contact Support" }),
|
|
1712
|
-
state === "sent" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1713
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-sm text-[color:var(--muted)]", children: "Your request was sent. The team will reply by email." }),
|
|
1714
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-5 flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1715
|
-
"button",
|
|
1716
|
-
{
|
|
1717
|
-
type: "button",
|
|
1718
|
-
onClick: close,
|
|
1719
|
-
className: "rounded-full bg-[color:var(--color-accent-bg-safe,var(--color-accent))] px-4 py-2 text-sm font-semibold text-[#FFFFFF] hover:opacity-90",
|
|
1720
|
-
children: "Done"
|
|
1721
|
-
}
|
|
1722
|
-
) })
|
|
1723
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1724
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-[color:var(--muted)]", children: "Describe the problem or question. Your account details ride along automatically." }),
|
|
1725
|
-
missingEmail ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mt-4 block", children: [
|
|
1726
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block text-xs font-semibold text-[color:var(--foreground)]", children: "Your email" }),
|
|
1727
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1728
|
-
"input",
|
|
1729
|
-
{
|
|
1730
|
-
type: "email",
|
|
1731
|
-
value: email,
|
|
1732
|
-
onChange: (e) => setEmail(e.target.value),
|
|
1733
|
-
placeholder: "you@example.com",
|
|
1734
|
-
className: "w-full rounded-lg border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2 text-sm text-[color:var(--foreground)] placeholder:text-[color:var(--muted)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-accent)]"
|
|
1735
|
-
}
|
|
1736
|
-
),
|
|
1737
|
-
showEmailError ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mt-1 block text-xs text-[color:var(--chrome-danger)]", children: "Enter an email so support can reply." }) : null
|
|
1738
|
-
] }) : null,
|
|
1739
|
-
missingPhone ? /* @__PURE__ */ jsxRuntime.jsxs("label", { className: "mt-3 block", children: [
|
|
1740
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 block text-xs font-semibold text-[color:var(--foreground)]", children: "Your phone \u2014 optional" }),
|
|
1741
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1742
|
-
"input",
|
|
1743
|
-
{
|
|
1744
|
-
type: "tel",
|
|
1745
|
-
value: phone,
|
|
1746
|
-
onChange: (e) => setPhone(e.target.value),
|
|
1747
|
-
placeholder: "(503) 555-1212",
|
|
1748
|
-
className: "w-full rounded-lg border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2 text-sm text-[color:var(--foreground)] placeholder:text-[color:var(--muted)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-accent)]"
|
|
1749
|
-
}
|
|
1750
|
-
)
|
|
1751
|
-
] }) : null,
|
|
1752
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1753
|
-
"textarea",
|
|
1754
|
-
{
|
|
1755
|
-
value: message,
|
|
1756
|
-
onChange: (e) => setMessage(e.target.value),
|
|
1757
|
-
rows: 5,
|
|
1758
|
-
placeholder: "How can we help?",
|
|
1759
|
-
className: "mt-4 w-full resize-y rounded-lg border border-[color:var(--line)] bg-[color:var(--panel)] px-3 py-2 text-sm text-[color:var(--foreground)] placeholder:text-[color:var(--muted)] focus:outline-none focus:ring-2 focus:ring-[color:var(--color-accent)]"
|
|
1760
|
-
}
|
|
1761
|
-
),
|
|
1762
|
-
state === "error" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-[color:var(--chrome-danger)]", children: "Sending failed \u2014 try again." }) : null,
|
|
1763
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [
|
|
1764
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1765
|
-
"button",
|
|
1766
|
-
{
|
|
1767
|
-
type: "button",
|
|
1768
|
-
onClick: close,
|
|
1769
|
-
className: "rounded-full border border-[color:var(--line)] px-4 py-2 text-sm font-semibold text-[color:var(--foreground)] hover:bg-[color:var(--panel)]",
|
|
1770
|
-
children: "Cancel"
|
|
1771
|
-
}
|
|
1772
|
-
),
|
|
1773
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1774
|
-
"button",
|
|
1775
|
-
{
|
|
1776
|
-
type: "button",
|
|
1777
|
-
onClick: submit,
|
|
1778
|
-
disabled: !message.trim() || state === "sending",
|
|
1779
|
-
className: "rounded-full bg-[color:var(--color-accent-bg-safe,var(--color-accent))] px-4 py-2 text-sm font-semibold text-[#FFFFFF] transition hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50",
|
|
1780
|
-
children: state === "sending" ? "Sending\u2026" : "Send request"
|
|
1781
|
-
}
|
|
1782
|
-
)
|
|
1783
|
-
] })
|
|
1784
|
-
] })
|
|
1785
|
-
] })
|
|
1786
|
-
}
|
|
1787
|
-
),
|
|
1788
|
-
document.body
|
|
1789
|
-
) : null
|
|
1571
|
+
var NAV_DISPLAY_OPTIONS = [
|
|
1572
|
+
{ value: "menu", label: "Sub Menu" },
|
|
1573
|
+
{ value: "tabs", label: "Tabs Only" },
|
|
1574
|
+
{ value: "both", label: "Both" }
|
|
1575
|
+
];
|
|
1576
|
+
function TopBarLinkAction({ label, description, href, icon: Icon }) {
|
|
1577
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("a", { href, "aria-label": label, className: topBarIconButtonClass(), children: [
|
|
1578
|
+
/* @__PURE__ */ jsxRuntime.jsx(Icon, { size: TOPBAR_GLYPH_SIZE, className: "text-current" }),
|
|
1579
|
+
/* @__PURE__ */ jsxRuntime.jsx(TopBarTooltip, { title: label, description })
|
|
1790
1580
|
] });
|
|
1791
1581
|
}
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
}
|
|
1802
|
-
return null;
|
|
1803
|
-
}
|
|
1804
|
-
function writeSpecOverlayAccessCache(access) {
|
|
1805
|
-
if (typeof window === "undefined") return;
|
|
1806
|
-
try {
|
|
1807
|
-
window.sessionStorage.setItem(SPEC_OVERLAY_ACCESS_CACHE_KEY, JSON.stringify(access));
|
|
1808
|
-
} catch {
|
|
1809
|
-
}
|
|
1810
|
-
}
|
|
1811
|
-
var locationChangeListeners = /* @__PURE__ */ new Set();
|
|
1812
|
-
var historyPatched = false;
|
|
1813
|
-
function ensureHistoryPatched() {
|
|
1814
|
-
if (historyPatched || typeof window === "undefined") return;
|
|
1815
|
-
historyPatched = true;
|
|
1816
|
-
const notify = () => locationChangeListeners.forEach((fn) => fn());
|
|
1817
|
-
const originalPushState = window.history.pushState.bind(window.history);
|
|
1818
|
-
const originalReplaceState = window.history.replaceState.bind(window.history);
|
|
1819
|
-
window.history.pushState = (...args) => {
|
|
1820
|
-
originalPushState(...args);
|
|
1821
|
-
notify();
|
|
1822
|
-
};
|
|
1823
|
-
window.history.replaceState = (...args) => {
|
|
1824
|
-
originalReplaceState(...args);
|
|
1825
|
-
notify();
|
|
1826
|
-
};
|
|
1827
|
-
window.addEventListener("popstate", notify);
|
|
1828
|
-
}
|
|
1829
|
-
function useLocationHref() {
|
|
1830
|
-
const [href, setHref] = react.useState(
|
|
1831
|
-
() => typeof window === "undefined" ? "" : window.location.href
|
|
1832
|
-
);
|
|
1833
|
-
react.useEffect(() => {
|
|
1834
|
-
ensureHistoryPatched();
|
|
1835
|
-
const onChange = () => setHref(window.location.href);
|
|
1836
|
-
locationChangeListeners.add(onChange);
|
|
1837
|
-
return () => {
|
|
1838
|
-
locationChangeListeners.delete(onChange);
|
|
1839
|
-
};
|
|
1840
|
-
}, []);
|
|
1841
|
-
return href;
|
|
1842
|
-
}
|
|
1843
|
-
function specOverlayFetchJson(path) {
|
|
1844
|
-
return fetch(`${SPECS_ORIGIN}${path}`, { credentials: "include", signal: AbortSignal.timeout(1e4) }).then((res) => {
|
|
1845
|
-
if (!res.ok) throw new Error(`spec overlay ${path}: ${res.status}`);
|
|
1846
|
-
return res.json();
|
|
1847
|
-
});
|
|
1848
|
-
}
|
|
1849
|
-
function isAutomatedCaptureSession() {
|
|
1850
|
-
return typeof navigator !== "undefined" && navigator.webdriver === true;
|
|
1851
|
-
}
|
|
1852
|
-
function currentChromeTheme() {
|
|
1853
|
-
const root = document.documentElement;
|
|
1854
|
-
if (root.classList.contains("dark") || root.getAttribute("data-theme") === "dark") return "dark";
|
|
1855
|
-
if (root.classList.contains("light") || root.getAttribute("data-theme") === "light") return "light";
|
|
1856
|
-
return "light";
|
|
1857
|
-
}
|
|
1858
|
-
var SPEC_OVERLAY_ROOT_ATTR = "data-spec-overlay-root";
|
|
1859
|
-
async function captureMyView(status, orgId, orgName) {
|
|
1860
|
-
const { domToCanvas } = await import('modern-screenshot');
|
|
1861
|
-
const w = window.innerWidth;
|
|
1862
|
-
const h = window.innerHeight;
|
|
1863
|
-
const theme = currentChromeTheme();
|
|
1864
|
-
const bg = getComputedStyle(document.body).backgroundColor || (theme === "dark" ? "#0b0b0c" : "#ffffff");
|
|
1865
|
-
const full = await domToCanvas(document.body, {
|
|
1866
|
-
width: w,
|
|
1867
|
-
height: h,
|
|
1868
|
-
scale: 1,
|
|
1869
|
-
backgroundColor: bg,
|
|
1870
|
-
// Cross-origin images that refuse CORS render blank instead of failing.
|
|
1871
|
-
fetch: { requestInit: { mode: "cors", credentials: "omit" }, placeholderImage: "" },
|
|
1872
|
-
// Drop the Spec drawer and everything fixed (sidebar, toasts, popovers):
|
|
1873
|
-
// the design is the page body only, so chrome would only add noise.
|
|
1874
|
-
filter: (node) => !(node instanceof Element) || !node.hasAttribute(SPEC_OVERLAY_ROOT_ATTR) && getComputedStyle(node).position !== "fixed",
|
|
1875
|
-
style: { transform: `translate(${-window.scrollX}px, ${-window.scrollY}px)` }
|
|
1876
|
-
});
|
|
1877
|
-
const el = (status.live_selector ? document.querySelector(status.live_selector) : null) ?? document.querySelector("[data-shell-content]");
|
|
1878
|
-
let region = { x: 0, y: 0, width: w, height: h };
|
|
1879
|
-
if (el) {
|
|
1880
|
-
const r = el.getBoundingClientRect();
|
|
1881
|
-
const x = Math.max(0, Math.round(r.left));
|
|
1882
|
-
const y = Math.max(0, Math.round(r.top));
|
|
1883
|
-
region = { x, y, width: Math.min(w - x, Math.round(r.width)), height: Math.min(h - y, Math.round(r.height)) };
|
|
1884
|
-
}
|
|
1885
|
-
const out = document.createElement("canvas");
|
|
1886
|
-
out.width = region.width;
|
|
1887
|
-
out.height = region.height;
|
|
1888
|
-
const ctx = out.getContext("2d");
|
|
1889
|
-
if (!ctx) throw new Error("page raster failed");
|
|
1890
|
-
ctx.drawImage(full, region.x, region.y, region.width, region.height, 0, 0, region.width, region.height);
|
|
1891
|
-
const blob = await new Promise((resolve) => out.toBlob(resolve, "image/png"));
|
|
1892
|
-
if (!blob) throw new Error("page raster failed");
|
|
1893
|
-
const form = new FormData();
|
|
1894
|
-
form.append("image", blob, "live.png");
|
|
1895
|
-
form.append(
|
|
1896
|
-
"meta",
|
|
1897
|
-
JSON.stringify({ url: window.location.href, theme, org_id: orgId ?? null, org_name: orgName ?? null, crop: null })
|
|
1582
|
+
function OrganizationSettingsAction({ href }) {
|
|
1583
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1584
|
+
TopBarLinkAction,
|
|
1585
|
+
{
|
|
1586
|
+
label: "Organization settings",
|
|
1587
|
+
description: "Users, Brand Kit, modes and billing for this organization.",
|
|
1588
|
+
href,
|
|
1589
|
+
icon: lu.LuSettings
|
|
1590
|
+
}
|
|
1898
1591
|
);
|
|
1899
|
-
const res = await fetch(status.capture_url ?? `${SPECS_ORIGIN}/api/overlay/capture`, {
|
|
1900
|
-
method: "POST",
|
|
1901
|
-
credentials: "include",
|
|
1902
|
-
headers: { "X-Spec-Capture": "1" },
|
|
1903
|
-
body: form,
|
|
1904
|
-
signal: AbortSignal.timeout(1e4)
|
|
1905
|
-
});
|
|
1906
|
-
if (!res.ok) throw new Error(`capture ${res.status}: ${(await res.text()).slice(0, 160)}`);
|
|
1907
1592
|
}
|
|
1908
|
-
function
|
|
1909
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
}
|
|
1917
|
-
),
|
|
1918
|
-
"Capturing your view and comparing\u2026"
|
|
1919
|
-
] }),
|
|
1920
|
-
["Live \u2014 your view", "Diff"].map((label) => /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-4", children: [
|
|
1921
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mb-1 text-xs font-semibold uppercase tracking-wide text-[color:var(--muted)]", children: label }),
|
|
1922
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { "aria-hidden": "true", className: "h-40 w-full animate-pulse rounded border border-[color:var(--line)] bg-[color:var(--panel)] motion-reduce:animate-none" })
|
|
1923
|
-
] }, label))
|
|
1924
|
-
] });
|
|
1925
|
-
}
|
|
1926
|
-
function specOverlayStatusPath() {
|
|
1927
|
-
return `/api/overlay/status?url=${encodeURIComponent(window.location.href)}&theme=${currentChromeTheme()}`;
|
|
1928
|
-
}
|
|
1929
|
-
function SpecOverlayAction({ orgId, orgName } = {}) {
|
|
1930
|
-
const [access, setAccess] = react.useState(() => readSpecOverlayAccessCache());
|
|
1931
|
-
const [status, setStatus] = react.useState(null);
|
|
1932
|
-
const [open, setOpen] = react.useState(false);
|
|
1933
|
-
const [capture, setCapture] = react.useState({ state: "idle" });
|
|
1934
|
-
const [frameKey, setFrameKey] = react.useState(0);
|
|
1935
|
-
const [copied, setCopied] = react.useState("idle");
|
|
1936
|
-
const href = useLocationHref();
|
|
1937
|
-
const automated = isAutomatedCaptureSession();
|
|
1938
|
-
react.useEffect(() => {
|
|
1939
|
-
if (access || automated) return;
|
|
1940
|
-
let cancelled = false;
|
|
1941
|
-
specOverlayFetchJson("/api/overlay/access").then((data) => {
|
|
1942
|
-
if (cancelled) return;
|
|
1943
|
-
const next = data && typeof data.allowed === "boolean" ? data : { allowed: false };
|
|
1944
|
-
setAccess(next);
|
|
1945
|
-
writeSpecOverlayAccessCache(next);
|
|
1946
|
-
}).catch(() => {
|
|
1947
|
-
if (cancelled) return;
|
|
1948
|
-
const next = { allowed: false };
|
|
1949
|
-
setAccess(next);
|
|
1950
|
-
writeSpecOverlayAccessCache(next);
|
|
1951
|
-
});
|
|
1952
|
-
return () => {
|
|
1953
|
-
cancelled = true;
|
|
1954
|
-
};
|
|
1955
|
-
}, [access]);
|
|
1956
|
-
react.useEffect(() => {
|
|
1957
|
-
if (automated || !access?.allowed || typeof window === "undefined") return;
|
|
1958
|
-
const timer = window.setTimeout(() => {
|
|
1959
|
-
specOverlayFetchJson(specOverlayStatusPath()).then((data) => setStatus(data)).catch(() => setStatus(null));
|
|
1960
|
-
}, 300);
|
|
1961
|
-
return () => window.clearTimeout(timer);
|
|
1962
|
-
}, [access?.allowed, href, orgId]);
|
|
1963
|
-
const captureRun = react.useRef(0);
|
|
1964
|
-
const accessRef = react.useRef(access);
|
|
1965
|
-
accessRef.current = access;
|
|
1966
|
-
const runCapture = async (s) => {
|
|
1967
|
-
const run = ++captureRun.current;
|
|
1968
|
-
const before = s.live_source === "viewer" ? s.finished_at : null;
|
|
1969
|
-
setCapture({ state: "busy" });
|
|
1970
|
-
try {
|
|
1971
|
-
await new Promise((r) => setTimeout(r, 150));
|
|
1972
|
-
await captureMyView(s, orgId, orgName);
|
|
1973
|
-
for (let i = 0; i < 45; i++) {
|
|
1974
|
-
await new Promise((r) => setTimeout(r, 3e3));
|
|
1975
|
-
if (run !== captureRun.current) return;
|
|
1976
|
-
if (!accessRef.current?.allowed) {
|
|
1977
|
-
setCapture({ state: "idle" });
|
|
1978
|
-
return;
|
|
1979
|
-
}
|
|
1980
|
-
const next = await specOverlayFetchJson(specOverlayStatusPath()).catch(() => null);
|
|
1981
|
-
if (next && next.matched && next.live_source === "viewer" && next.finished_at !== before) {
|
|
1982
|
-
setStatus(next);
|
|
1983
|
-
setFrameKey((k) => k + 1);
|
|
1984
|
-
setCapture({ state: "idle" });
|
|
1985
|
-
return;
|
|
1986
|
-
}
|
|
1987
|
-
}
|
|
1988
|
-
setCapture({ state: "error", message: "Compare did not finish in 2 min." });
|
|
1989
|
-
} catch (e) {
|
|
1990
|
-
if (run === captureRun.current) setCapture({ state: "error", message: e instanceof Error ? e.message : String(e) });
|
|
1593
|
+
function MyProfileAction({ href }) {
|
|
1594
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1595
|
+
TopBarLinkAction,
|
|
1596
|
+
{
|
|
1597
|
+
label: "My profile",
|
|
1598
|
+
description: "Your photo, organizations, security and notifications.",
|
|
1599
|
+
href,
|
|
1600
|
+
icon: lu.LuCircleUser
|
|
1991
1601
|
}
|
|
1992
|
-
|
|
1993
|
-
react.useEffect(() => {
|
|
1994
|
-
if (automated || !open || !status || !status.matched) return;
|
|
1995
|
-
void runCapture(status);
|
|
1996
|
-
return () => {
|
|
1997
|
-
captureRun.current++;
|
|
1998
|
-
};
|
|
1999
|
-
}, [open, status && status.matched ? status.target_id : null]);
|
|
2000
|
-
if (automated || !access?.allowed) return null;
|
|
2001
|
-
const hasScore = status && status.matched && typeof status.mismatch_pct === "number";
|
|
2002
|
-
const badgeLabel = hasScore ? `${Math.round(status.mismatch_pct)}%` : status ? "\u2014" : void 0;
|
|
2003
|
-
const badgeTone = hasScore ? status && status.matched && status.passed ? "default" : "danger" : "default";
|
|
2004
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2005
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2006
|
-
"button",
|
|
2007
|
-
{
|
|
2008
|
-
type: "button",
|
|
2009
|
-
"aria-label": "Spec",
|
|
2010
|
-
"aria-expanded": open,
|
|
2011
|
-
className: topBarIconButtonClass(badgeTone),
|
|
2012
|
-
onClick: () => setOpen(true),
|
|
2013
|
-
children: [
|
|
2014
|
-
/* @__PURE__ */ jsxRuntime.jsx(LayoutGlyph, { size: TOPBAR_GLYPH_SIZE, className: "text-current" }),
|
|
2015
|
-
badgeLabel ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2016
|
-
"span",
|
|
2017
|
-
{
|
|
2018
|
-
className: [
|
|
2019
|
-
"absolute -top-1 -right-1 flex h-4 min-w-4 items-center justify-center rounded-full px-1 text-[10px] font-normal leading-none text-[#FFFFFF]",
|
|
2020
|
-
hasScore ? status && status.matched && status.passed ? "bg-[color:var(--chrome-success,#2f855a)]" : "bg-[color:var(--chrome-danger)]" : "bg-[color:var(--muted)]"
|
|
2021
|
-
].join(" "),
|
|
2022
|
-
children: badgeLabel
|
|
2023
|
-
}
|
|
2024
|
-
) : null,
|
|
2025
|
-
!open ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2026
|
-
TopBarTooltip,
|
|
2027
|
-
{
|
|
2028
|
-
title: "Spec",
|
|
2029
|
-
description: "Spec design + visual regression for this page."
|
|
2030
|
-
}
|
|
2031
|
-
) : null
|
|
2032
|
-
]
|
|
2033
|
-
}
|
|
2034
|
-
),
|
|
2035
|
-
open && typeof document !== "undefined" ? reactDom.createPortal(
|
|
2036
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2037
|
-
"div",
|
|
2038
|
-
{
|
|
2039
|
-
className: "fixed inset-0 z-50 flex justify-end bg-black/40",
|
|
2040
|
-
...{ [SPEC_OVERLAY_ROOT_ATTR]: "" },
|
|
2041
|
-
role: "dialog",
|
|
2042
|
-
"aria-modal": "true",
|
|
2043
|
-
"aria-label": "Spec overlay",
|
|
2044
|
-
onMouseDown: (e) => {
|
|
2045
|
-
if (e.target === e.currentTarget) setOpen(false);
|
|
2046
|
-
},
|
|
2047
|
-
onKeyDown: (e) => {
|
|
2048
|
-
if (e.key === "Escape") setOpen(false);
|
|
2049
|
-
},
|
|
2050
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full w-full max-w-[480px] flex-col border-l border-[color:var(--line)] bg-[color:var(--panel-elevated)] shadow-[var(--shadow-soft)]", children: [
|
|
2051
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between gap-2 border-b border-[color:var(--line)] px-4 py-3", children: [
|
|
2052
|
-
/* @__PURE__ */ jsxRuntime.jsxs("h2", { className: "truncate text-sm font-bold tracking-[-0.01em] text-[color:var(--foreground)]", children: [
|
|
2053
|
-
"Spec",
|
|
2054
|
-
status && status.matched ? `: ${status.spec_title}` : ""
|
|
2055
|
-
] }),
|
|
2056
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2057
|
-
"button",
|
|
2058
|
-
{
|
|
2059
|
-
type: "button",
|
|
2060
|
-
"aria-label": "Close",
|
|
2061
|
-
onClick: () => setOpen(false),
|
|
2062
|
-
className: "rounded-full p-1 text-[color:var(--muted)] hover:bg-[color:var(--panel)] hover:text-[color:var(--foreground)]",
|
|
2063
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(CloseGlyph, { size: 16 })
|
|
2064
|
-
}
|
|
2065
|
-
)
|
|
2066
|
-
] }),
|
|
2067
|
-
status && status.matched ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
2068
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 border-b border-[color:var(--line)] px-4 py-2 text-xs font-semibold", children: [
|
|
2069
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2070
|
-
"a",
|
|
2071
|
-
{
|
|
2072
|
-
href: status.spec_url,
|
|
2073
|
-
target: "_blank",
|
|
2074
|
-
rel: "noreferrer",
|
|
2075
|
-
className: "text-[color:var(--color-accent-fg,var(--color-accent))] hover:underline",
|
|
2076
|
-
children: "Open spec \u2197"
|
|
2077
|
-
}
|
|
2078
|
-
),
|
|
2079
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2080
|
-
"a",
|
|
2081
|
-
{
|
|
2082
|
-
href: status.compare_url,
|
|
2083
|
-
target: "_blank",
|
|
2084
|
-
rel: "noreferrer",
|
|
2085
|
-
className: "text-[color:var(--color-accent-fg,var(--color-accent))] hover:underline",
|
|
2086
|
-
children: "Compare tab \u2197"
|
|
2087
|
-
}
|
|
2088
|
-
),
|
|
2089
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2090
|
-
"button",
|
|
2091
|
-
{
|
|
2092
|
-
type: "button",
|
|
2093
|
-
disabled: capture.state === "busy",
|
|
2094
|
-
onClick: () => void runCapture(status),
|
|
2095
|
-
className: "ml-auto rounded-md border border-[color:var(--line)] px-2 py-1 text-[color:var(--foreground)] hover:bg-[color:var(--panel)] disabled:opacity-60",
|
|
2096
|
-
title: "Your view is captured when the drawer opens. Recapture after changing the page.",
|
|
2097
|
-
children: capture.state === "busy" ? "Capturing\u2026" : "Recapture"
|
|
2098
|
-
}
|
|
2099
|
-
),
|
|
2100
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2101
|
-
"button",
|
|
2102
|
-
{
|
|
2103
|
-
type: "button",
|
|
2104
|
-
"data-spec-copy-prompt": "",
|
|
2105
|
-
disabled: capture.state === "busy" || !status.prompt,
|
|
2106
|
-
onClick: () => {
|
|
2107
|
-
const text = status.prompt;
|
|
2108
|
-
if (!text) return;
|
|
2109
|
-
navigator.clipboard.writeText(text).then(() => setCopied("copied")).catch(() => setCopied("failed")).finally(() => window.setTimeout(() => setCopied("idle"), 2e3));
|
|
2110
|
-
},
|
|
2111
|
-
className: "rounded-md border border-[color:var(--line)] px-2 py-1 text-[color:var(--foreground)] hover:bg-[color:var(--panel)] disabled:opacity-60",
|
|
2112
|
-
title: "Copy a repair prompt for an AI agent: spec, score, image links, top mismatched regions and instructions.",
|
|
2113
|
-
children: copied === "copied" ? "Copied \u2713" : copied === "failed" ? "Copy failed" : "Copy prompt"
|
|
2114
|
-
}
|
|
2115
|
-
)
|
|
2116
|
-
] }),
|
|
2117
|
-
status.live_size && status.design_size && capture.state !== "busy" ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2118
|
-
"p",
|
|
2119
|
-
{
|
|
2120
|
-
"data-spec-sizes": "",
|
|
2121
|
-
className: [
|
|
2122
|
-
"border-b border-[color:var(--line)] px-4 py-1.5 text-xs",
|
|
2123
|
-
status.live_size.width === status.design_size.width && status.live_size.height === status.design_size.height ? "text-[color:var(--muted)]" : "font-semibold text-[color:var(--chrome-danger)]"
|
|
2124
|
-
].join(" "),
|
|
2125
|
-
children: [
|
|
2126
|
-
"Live ",
|
|
2127
|
-
status.live_size.width,
|
|
2128
|
-
"\xD7",
|
|
2129
|
-
status.live_size.height,
|
|
2130
|
-
" \xB7 Design ",
|
|
2131
|
-
status.design_size.width,
|
|
2132
|
-
"\xD7",
|
|
2133
|
-
status.design_size.height,
|
|
2134
|
-
status.live_size.width === status.design_size.width && status.live_size.height === status.design_size.height ? " \xB7 sizes match" : " \xB7 SIZE MISMATCH"
|
|
2135
|
-
]
|
|
2136
|
-
}
|
|
2137
|
-
) : null,
|
|
2138
|
-
capture.state === "error" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "border-b border-[color:var(--line)] px-4 py-2 text-xs text-[color:var(--chrome-danger)]", children: capture.message }) : null,
|
|
2139
|
-
capture.state === "busy" ? /* @__PURE__ */ jsxRuntime.jsx(SpecCaptureLoading, {}) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
2140
|
-
"iframe",
|
|
2141
|
-
{
|
|
2142
|
-
src: status.overlay_url,
|
|
2143
|
-
title: "Spec overlay",
|
|
2144
|
-
className: "h-full w-full flex-1 border-0"
|
|
2145
|
-
},
|
|
2146
|
-
frameKey
|
|
2147
|
-
)
|
|
2148
|
-
] }) : status && !status.matched ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "p-4 text-sm text-[color:var(--muted)]", children: [
|
|
2149
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { children: "No compare target covers this page." }),
|
|
2150
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2151
|
-
"a",
|
|
2152
|
-
{
|
|
2153
|
-
href: status.search_url,
|
|
2154
|
-
target: "_blank",
|
|
2155
|
-
rel: "noreferrer",
|
|
2156
|
-
className: "mt-2 inline-block font-semibold text-[color:var(--color-accent-fg,var(--color-accent))] hover:underline",
|
|
2157
|
-
children: "Search specs \u2197"
|
|
2158
|
-
}
|
|
2159
|
-
)
|
|
2160
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-4", children: /* @__PURE__ */ jsxRuntime.jsx(ValueSkeleton, { className: "h-4 w-full" }) })
|
|
2161
|
-
] })
|
|
2162
|
-
}
|
|
2163
|
-
),
|
|
2164
|
-
document.body
|
|
2165
|
-
) : null
|
|
2166
|
-
] });
|
|
2167
|
-
}
|
|
2168
|
-
function CloseGlyph({ size = 16, className }) {
|
|
2169
|
-
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: [
|
|
2170
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "18", y1: "6", x2: "6", y2: "18" }),
|
|
2171
|
-
/* @__PURE__ */ jsxRuntime.jsx("line", { x1: "6", y1: "6", x2: "18", y2: "18" })
|
|
2172
|
-
] });
|
|
1602
|
+
);
|
|
2173
1603
|
}
|
|
2174
|
-
var NAV_DISPLAY_OPTIONS = [
|
|
2175
|
-
{ value: "menu", label: "Sub Menu" },
|
|
2176
|
-
{ value: "tabs", label: "Tabs Only" },
|
|
2177
|
-
{ value: "both", label: "Both" }
|
|
2178
|
-
];
|
|
2179
1604
|
function parseCssUrl(value) {
|
|
2180
1605
|
if (!value) return null;
|
|
2181
1606
|
const m = /^url\(\s*(['"]?)(.*?)\1\s*\)$/i.exec(value.trim());
|
|
@@ -2455,13 +1880,14 @@ function standardPolitogyNav(opts) {
|
|
|
2455
1880
|
});
|
|
2456
1881
|
};
|
|
2457
1882
|
const accountRows = () => [
|
|
2458
|
-
{ kind: "section", label: "Account" },
|
|
1883
|
+
{ kind: "section", label: "Account", railHidden: true },
|
|
2459
1884
|
// My Profile moved to the Politogy ID account app (auth.politogyvrm.com)
|
|
2460
1885
|
// with the retirement of app.politogyvrm.com.
|
|
2461
|
-
{ label: "My profile", icon: icon("circleUser"), href: withOrg(`${AUTH_ORIGIN}my-profile`) },
|
|
1886
|
+
{ label: "My profile", icon: icon("circleUser"), href: withOrg(`${AUTH_ORIGIN}my-profile`), railHidden: true },
|
|
2462
1887
|
{
|
|
2463
1888
|
label: "Organization settings",
|
|
2464
1889
|
icon: icon("settings"),
|
|
1890
|
+
railHidden: true,
|
|
2465
1891
|
// Organization settings moved to the standalone Settings app
|
|
2466
1892
|
// (settings.politogyvrm.com, Specs/Organization-Settings v12).
|
|
2467
1893
|
href: withOrg(`${SETTINGS_ORIGIN}organization-settings`),
|
|
@@ -3108,7 +2534,7 @@ function NavSidebar({
|
|
|
3108
2534
|
] }),
|
|
3109
2535
|
/* @__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: [
|
|
3110
2536
|
nav.groupLabel ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: `${NAV_EYEBROW_CLASS} px-2 pb-1.5 pt-1 ${rc("max-md:hidden")}`, children: nav.groupLabel }) : null,
|
|
3111
|
-
nav.items.map((item, idx) => {
|
|
2537
|
+
nav.items.filter((item) => !item.railHidden).map((item, idx) => {
|
|
3112
2538
|
if (item.kind === "section") {
|
|
3113
2539
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
3114
2540
|
NavSectionRow,
|
|
@@ -5651,26 +5077,15 @@ function ChromeTopBarActions() {
|
|
|
5651
5077
|
const state = useChromeState();
|
|
5652
5078
|
if (!state) return null;
|
|
5653
5079
|
const settledOrgId = state.orgsLoading ? null : state.orgId;
|
|
5080
|
+
const tail = orgIdTail(state.orgId);
|
|
5081
|
+
const orgQuery = tail ? `?${ORG_ID_QUERY_PARAM}=${tail}` : "";
|
|
5654
5082
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
5655
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5656
|
-
TopBarWidgetSlot,
|
|
5657
|
-
{
|
|
5658
|
-
title: "DevNotes",
|
|
5659
|
-
description: "Capture bugs and notes, filed straight to Forge.",
|
|
5660
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(ChromeDevNotesMenu, {})
|
|
5661
|
-
}
|
|
5662
|
-
),
|
|
5663
5083
|
/* @__PURE__ */ jsxRuntime.jsx(FuelAction, { orgId: settledOrgId }),
|
|
5664
|
-
/* @__PURE__ */ jsxRuntime.jsx(SpecOverlayAction, { orgId: state.orgId, orgName: state.orgs.find((o) => o.id === state.orgId)?.name ?? null }),
|
|
5665
5084
|
/* @__PURE__ */ jsxRuntime.jsx(NotificationsAction, { orgId: settledOrgId }),
|
|
5666
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5085
|
+
/* @__PURE__ */ jsxRuntime.jsx(OrganizationSettingsAction, { href: `${settingsBaseUrl()}/organization-settings${orgQuery}` }),
|
|
5086
|
+
/* @__PURE__ */ jsxRuntime.jsx(MyProfileAction, { href: `${authBaseUrl()}/my-profile${orgQuery}` })
|
|
5667
5087
|
] });
|
|
5668
5088
|
}
|
|
5669
|
-
function ChromeDevNotesMenu() {
|
|
5670
|
-
const { ready, openTasks, activate } = react.useContext(DevNotesTasksContext);
|
|
5671
|
-
if (!ready) return null;
|
|
5672
|
-
return /* @__PURE__ */ jsxRuntime.jsx("span", { style: { display: "contents" }, onPointerDownCapture: activate, onFocusCapture: activate, onKeyDownCapture: activate, children: /* @__PURE__ */ jsxRuntime.jsx(devnotes.DevNotesMenu, { position: "top-right", icon: lu.LuNotebookPen, onViewTasks: openTasks }) });
|
|
5673
|
-
}
|
|
5674
5089
|
function useIsSuperAdmin() {
|
|
5675
5090
|
const state = useChromeState();
|
|
5676
5091
|
return (state?.orgs ?? []).some((o) => /super/i.test(o.rawRole ?? ""));
|
|
@@ -5720,11 +5135,13 @@ function useChromeUserMenu({
|
|
|
5720
5135
|
organizationSettingsHref: `${settings}/organization-settings${orgSuffix}`,
|
|
5721
5136
|
roles: (state?.orgs ?? []).filter((o) => o.rawRole || o.role).map((o) => ({ role: o.rawRole ?? o.role, orgName: o.name })),
|
|
5722
5137
|
accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],
|
|
5723
|
-
addAccountHref: `${auth}/my-profile#accounts
|
|
5138
|
+
addAccountHref: `${auth}/my-profile#accounts`
|
|
5724
5139
|
// No theme control: the product is light only (Reference/UI-Platform
|
|
5725
5140
|
// "Theme — light only"; shell 0.73.0 stopped applying dark). The account
|
|
5726
5141
|
// menu rendered an "Appearance" radio with one option until 0.77.0.
|
|
5727
|
-
|
|
5142
|
+
// Ben 2026-11-04: no Navigation display option in the account menu. The
|
|
5143
|
+
// preference itself (state.navDisplay, its storage and the frame's use of
|
|
5144
|
+
// it) is unchanged; only the menu control is gone.
|
|
5728
5145
|
};
|
|
5729
5146
|
}
|
|
5730
5147
|
var MODE_DEFS = [
|