@the-portland-company/shell 0.69.0 → 0.70.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 +16 -0
- package/dist/app-chrome.cjs +242 -158
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.js +43 -36
- package/dist/app-chrome.js.map +1 -1
- package/dist/{chunk-6UHJV2FH.js → chunk-7YVJ7HQG.js} +41 -3
- package/dist/chunk-7YVJ7HQG.js.map +1 -0
- package/dist/{chunk-WFUWFMCA.js → chunk-CZI66JVG.js} +104 -65
- package/dist/chunk-CZI66JVG.js.map +1 -0
- package/dist/native.cjs +151 -63
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +13 -2
- package/dist/native.d.ts +13 -2
- package/dist/native.js +2 -1
- package/dist/nav-preference.cjs +44 -0
- package/dist/nav-preference.cjs.map +1 -1
- package/dist/nav-preference.d.cts +8 -1
- package/dist/nav-preference.d.ts +8 -1
- package/dist/nav-preference.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-6UHJV2FH.js.map +0 -1
- package/dist/chunk-WFUWFMCA.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,19 @@
|
|
|
1
|
+
## 0.70.0 — 2026-10-06
|
|
2
|
+
|
|
3
|
+
The top bar and left rail match Specs/Left-Navigation and Reference/UI-Platform.
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
|
|
7
|
+
- **No Build notes control.** The top bar has exactly the five UI-Platform elements: search, Dev notes, Credits, Notifications, Help. `<PolitogyAppFrame>` no longer passes `buildNotes`; `NavTopBar` renders Build notes only when a caller passes the prop. (#101)
|
|
8
|
+
- **The top bar fits a 390px phone.** Search shrinks below `md` (fixed 320px from `md` up), the `/` hint hides below `md`, and the header gap narrows. (#104)
|
|
9
|
+
- **No hamburger on phone.** The top bar draws no hamburger. Below `md` the collapsed rail's logo tile is the expand control ("Expand navigation"); the drawer's close button is "Collapse navigation". The drawer itself is unchanged (Left-Navigation §11.6). The expand choice is remembered per user (`politogy_rail` cookie on `.politogyvrm.com` plus localStorage, via `readRailPreference` / `writeRailPreference` in `nav-preference`) and read back on the next load below `md`; a nav-link click closes the overlay without changing it. New `NavSidebar` props `onOpen` and `onNavigate`. `NavTopBar` still renders a hamburger for direct callers that pass `onOpenNav`. (#106, #108, #110)
|
|
10
|
+
- **Lucide icons.** `standardNavIcons` maps every slot to Lucide (`react-icons/lu`); the mode switcher uses contact-round, megaphone and file-signature. New slots: `layoutDashboard`, `usersRound`, `mousePointerClick`, `clipboardList`, `circleUser`, `crosshair`, `landmark`, `chartNoAxes`, `doorOpen`, `signpost`. (#105, #106)
|
|
11
|
+
- **Nav trees follow Left-Navigation §9.** Relationship: Relationship (Dashboard, Contacts, Email broadcast, SMS/MMS blast) · Collect (Calls to action, Forms, Surveys) · Account. Polls and CTAs rows removed. Campaign: Race data (Battleground, District data) · Research (Polling) · GOTV (Field canvassing, Phone banking, A2P texting, Sign mapping) · Account. Dashboard, Voter Contact and Tribes rows removed; Battleground is the landing row. A section left empty by availability flags is dropped. The Petition tree is unchanged. (#106)
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- react-router 6.30.6 clears the publish audit gate (#102); lockfile regenerated with npm 10 so CI `npm ci` succeeds (#103).
|
|
16
|
+
|
|
1
17
|
## 0.69.0 — 2026-10-04
|
|
2
18
|
|
|
3
19
|
The left rail collapses instead of hiding, `<main>` is fluid, and there is one page tab strip. Implements Specs/Left-Navigation §11.6 and §5, the Brand guidelines "Content width is fluid", "Content body padding", "Tabs are an underlined strip" and "Logo standard", and the two "Known shell defect" notes in Reference/UI-Platform (Brand v135).
|
package/dist/app-chrome.cjs
CHANGED
|
@@ -7,6 +7,7 @@ var fi = require('react-icons/fi');
|
|
|
7
7
|
var reactDom = require('react-dom');
|
|
8
8
|
var jsxRuntime = require('react/jsx-runtime');
|
|
9
9
|
var devnotes = require('@the-portland-company/devnotes');
|
|
10
|
+
var lu = require('react-icons/lu');
|
|
10
11
|
|
|
11
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
13
|
|
|
@@ -88,13 +89,111 @@ function normalize(s) {
|
|
|
88
89
|
return s.normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim();
|
|
89
90
|
}
|
|
90
91
|
|
|
92
|
+
// src/nav-preference.ts
|
|
93
|
+
var NAV_DISPLAY_STORAGE_KEY = "politogy_nav_display";
|
|
94
|
+
var NAV_DISPLAY_COOKIE = "politogy_nav_display";
|
|
95
|
+
var LEGACY_NAV_DISPLAY_KEY = "vrm.navDisplay";
|
|
96
|
+
var NAV_DISPLAY_DEFAULT = "both";
|
|
97
|
+
var VALID = ["menu", "tabs", "both"];
|
|
98
|
+
function isNavDisplayPreference(v) {
|
|
99
|
+
return typeof v === "string" && VALID.includes(v);
|
|
100
|
+
}
|
|
101
|
+
function readNavDisplayCookie() {
|
|
102
|
+
if (typeof document === "undefined") return null;
|
|
103
|
+
try {
|
|
104
|
+
const m = document.cookie.match(
|
|
105
|
+
new RegExp(`(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)`)
|
|
106
|
+
);
|
|
107
|
+
const v = m ? decodeURIComponent(m[1]) : null;
|
|
108
|
+
return isNavDisplayPreference(v) ? v : null;
|
|
109
|
+
} catch {
|
|
110
|
+
return null;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function writeNavDisplayCookie(pref) {
|
|
114
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
115
|
+
const host = window.location.hostname;
|
|
116
|
+
const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
|
|
117
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
118
|
+
document.cookie = `${NAV_DISPLAY_COOKIE}=${encodeURIComponent(
|
|
119
|
+
pref
|
|
120
|
+
)}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
|
|
121
|
+
}
|
|
122
|
+
function readNavDisplayLocal() {
|
|
123
|
+
if (typeof localStorage === "undefined") return null;
|
|
124
|
+
try {
|
|
125
|
+
const current = localStorage.getItem(NAV_DISPLAY_STORAGE_KEY);
|
|
126
|
+
if (isNavDisplayPreference(current)) return current;
|
|
127
|
+
const legacy = localStorage.getItem(LEGACY_NAV_DISPLAY_KEY);
|
|
128
|
+
return isNavDisplayPreference(legacy) ? legacy : null;
|
|
129
|
+
} catch {
|
|
130
|
+
return null;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function writeNavDisplayLocal(pref) {
|
|
134
|
+
if (typeof localStorage === "undefined") return;
|
|
135
|
+
try {
|
|
136
|
+
localStorage.setItem(NAV_DISPLAY_STORAGE_KEY, pref);
|
|
137
|
+
} catch {
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
function resolveNavDisplay() {
|
|
141
|
+
return readNavDisplayCookie() ?? readNavDisplayLocal() ?? NAV_DISPLAY_DEFAULT;
|
|
142
|
+
}
|
|
143
|
+
`(function(){try{
|
|
144
|
+
var KEY=${JSON.stringify(NAV_DISPLAY_STORAGE_KEY)};
|
|
145
|
+
var VALID=["menu","tabs","both"];
|
|
146
|
+
function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
|
|
147
|
+
var cookie=fromCookie();
|
|
148
|
+
if(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
|
|
149
|
+
if(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}
|
|
150
|
+
}catch(e){}})();`;
|
|
151
|
+
var RAIL_STORAGE_KEY = "politogy_rail";
|
|
152
|
+
var RAIL_COOKIE = "politogy_rail";
|
|
153
|
+
var RAIL_DEFAULT = "collapsed";
|
|
154
|
+
function isRailPreference(v) {
|
|
155
|
+
return v === "expanded" || v === "collapsed";
|
|
156
|
+
}
|
|
157
|
+
function readRailPreference() {
|
|
158
|
+
if (typeof document !== "undefined") {
|
|
159
|
+
try {
|
|
160
|
+
const m = document.cookie.match(new RegExp(`(?:^|;\\s*)${RAIL_COOKIE}=([^;]+)`));
|
|
161
|
+
const v = m ? decodeURIComponent(m[1]) : null;
|
|
162
|
+
if (isRailPreference(v)) return v;
|
|
163
|
+
} catch {
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
if (typeof localStorage !== "undefined") {
|
|
167
|
+
try {
|
|
168
|
+
const v = localStorage.getItem(RAIL_STORAGE_KEY);
|
|
169
|
+
if (isRailPreference(v)) return v;
|
|
170
|
+
} catch {
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
return RAIL_DEFAULT;
|
|
174
|
+
}
|
|
175
|
+
function writeRailPreference(pref) {
|
|
176
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
177
|
+
const host = window.location.hostname;
|
|
178
|
+
const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
|
|
179
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
180
|
+
try {
|
|
181
|
+
document.cookie = `${RAIL_COOKIE}=${pref}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
|
|
182
|
+
} catch {
|
|
183
|
+
}
|
|
184
|
+
try {
|
|
185
|
+
localStorage.setItem(RAIL_STORAGE_KEY, pref);
|
|
186
|
+
} catch {
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
91
190
|
// src/theme-preference.ts
|
|
92
191
|
var THEME_STORAGE_KEY = "politogy_theme";
|
|
93
192
|
var THEME_COOKIE = "politogy_theme";
|
|
94
193
|
var THEME_PENDING_COOKIE = "politogy_theme_pending";
|
|
95
|
-
var
|
|
194
|
+
var VALID2 = ["light", "dark", "system"];
|
|
96
195
|
function isThemePreference(v) {
|
|
97
|
-
return typeof v === "string" &&
|
|
196
|
+
return typeof v === "string" && VALID2.includes(v);
|
|
98
197
|
}
|
|
99
198
|
function readThemeCookie() {
|
|
100
199
|
if (typeof document === "undefined") return null;
|
|
@@ -1847,7 +1946,6 @@ var PHONEBANK_ORIGIN = "https://phonebank.politogyvrm.com/";
|
|
|
1847
1946
|
var CANVASS_ORIGIN = "https://canvass.politogyvrm.com/";
|
|
1848
1947
|
var SIGNS_ORIGIN = "https://signs.politogyvrm.com/";
|
|
1849
1948
|
var POLLS_ORIGIN = "https://polls.politogyvrm.com/";
|
|
1850
|
-
var CONTACTS_TRIBES = "https://contacts.politogyvrm.com/tribes";
|
|
1851
1949
|
var PETITION_MODE_ORIGIN = "https://petition-mode.politogyvrm.com/";
|
|
1852
1950
|
function applyHiddenItems(items, hidden) {
|
|
1853
1951
|
if (!hidden || hidden.length === 0) return items;
|
|
@@ -1917,10 +2015,6 @@ var APP_POLLS_CHILDREN = [
|
|
|
1917
2015
|
{ label: "Command Center", icon: "grid", href: "https://polls.politogyvrm.com/" },
|
|
1918
2016
|
{ label: "New Poll", icon: "edit", href: "https://polls.politogyvrm.com/polls/new" }
|
|
1919
2017
|
];
|
|
1920
|
-
var APP_CTAS_CHILDREN = [
|
|
1921
|
-
{ label: "CTAs", icon: "list", href: "https://ctas.politogyvrm.com/" },
|
|
1922
|
-
{ label: "Canvas", icon: "edit", href: "https://ctas.politogyvrm.com/?tab=canvas" }
|
|
1923
|
-
];
|
|
1924
2018
|
var APP_A2P_CHILDREN = [
|
|
1925
2019
|
{ label: "Dashboard", icon: "grid", path: "dashboard" },
|
|
1926
2020
|
{ label: "Compose", icon: "edit", path: "compose" },
|
|
@@ -1968,16 +2062,27 @@ function standardPolitogyNav(opts) {
|
|
|
1968
2062
|
return { label: c.label, icon: icon(c.icon), href: withOrg(withMode) };
|
|
1969
2063
|
});
|
|
1970
2064
|
};
|
|
2065
|
+
const accountRows = () => [
|
|
2066
|
+
{ kind: "section", label: "Account" },
|
|
2067
|
+
// My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
|
|
2068
|
+
{ label: "My profile", icon: icon("circleUser"), href: withOrg(abs("/my-profile")) },
|
|
2069
|
+
{
|
|
2070
|
+
label: "Organization settings",
|
|
2071
|
+
icon: icon("settings"),
|
|
2072
|
+
href: withOrg(abs("/organization-settings")),
|
|
2073
|
+
children: branches(ORG_SETTINGS_CHILDREN)
|
|
2074
|
+
}
|
|
2075
|
+
];
|
|
1971
2076
|
const buildRelationship = () => {
|
|
1972
2077
|
const contacts = opts.contactsItem ? {
|
|
1973
2078
|
label: "Contacts",
|
|
1974
|
-
icon: icon("
|
|
2079
|
+
icon: icon("usersRound"),
|
|
1975
2080
|
href: opts.contactsItem.href,
|
|
1976
2081
|
children: opts.contactsItem.children,
|
|
1977
2082
|
badge: opts.contactsItem.count ?? void 0
|
|
1978
2083
|
} : {
|
|
1979
2084
|
label: "Contacts",
|
|
1980
|
-
icon: icon("
|
|
2085
|
+
icon: icon("usersRound"),
|
|
1981
2086
|
href: withOrg(`${CONTACTS_APP}/`),
|
|
1982
2087
|
children: APP_CONTACTS_CHILDREN.map((c) => ({
|
|
1983
2088
|
label: c.label,
|
|
@@ -1987,7 +2092,7 @@ function standardPolitogyNav(opts) {
|
|
|
1987
2092
|
};
|
|
1988
2093
|
return [
|
|
1989
2094
|
{ kind: "section", label: "Relationship" },
|
|
1990
|
-
{ label: "Dashboard", icon: icon("
|
|
2095
|
+
{ label: "Dashboard", icon: icon("layoutDashboard"), href: withOrg(abs("/relationship/dashboard")) },
|
|
1991
2096
|
contacts,
|
|
1992
2097
|
{
|
|
1993
2098
|
label: "Email broadcast",
|
|
@@ -2010,40 +2115,20 @@ function standardPolitogyNav(opts) {
|
|
|
2010
2115
|
},
|
|
2011
2116
|
{ kind: "section", label: "Collect" },
|
|
2012
2117
|
// Carries no top-level href in VRM core (parent row only toggles).
|
|
2013
|
-
{ label: "Calls to action", icon: icon("
|
|
2118
|
+
{ label: "Calls to action", icon: icon("mousePointerClick"), children: leaves(CTA_CHILDREN) },
|
|
2014
2119
|
{
|
|
2015
2120
|
label: "Forms",
|
|
2016
|
-
icon: icon("
|
|
2121
|
+
icon: icon("fileText"),
|
|
2017
2122
|
href: withOrg("https://forms.politogyvrm.com/"),
|
|
2018
2123
|
children: APP_FORMS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
2019
2124
|
},
|
|
2020
2125
|
{
|
|
2021
2126
|
label: "Surveys",
|
|
2022
|
-
icon: icon("
|
|
2127
|
+
icon: icon("clipboardList"),
|
|
2023
2128
|
href: withOrg("https://surveys.politogyvrm.com/surveys"),
|
|
2024
2129
|
children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
2025
2130
|
},
|
|
2026
|
-
|
|
2027
|
-
label: "Polls",
|
|
2028
|
-
icon: icon("barChart"),
|
|
2029
|
-
href: withOrg("https://polls.politogyvrm.com/"),
|
|
2030
|
-
children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
2031
|
-
},
|
|
2032
|
-
{
|
|
2033
|
-
label: "CTAs",
|
|
2034
|
-
icon: icon("layout"),
|
|
2035
|
-
href: withOrg("https://ctas.politogyvrm.com/"),
|
|
2036
|
-
children: APP_CTAS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
2037
|
-
},
|
|
2038
|
-
{ kind: "section", label: "Account" },
|
|
2039
|
-
// My Profile is global — NOT org-suffixed (main-app ShellChromeBridge).
|
|
2040
|
-
{ label: "My profile", icon: icon("user"), href: withOrg(abs("/my-profile")) },
|
|
2041
|
-
{
|
|
2042
|
-
label: "Organization settings",
|
|
2043
|
-
icon: icon("settings"),
|
|
2044
|
-
href: withOrg(abs("/organization-settings")),
|
|
2045
|
-
children: branches(ORG_SETTINGS_CHILDREN)
|
|
2046
|
-
}
|
|
2131
|
+
...accountRows()
|
|
2047
2132
|
];
|
|
2048
2133
|
};
|
|
2049
2134
|
const buildCampaign = () => {
|
|
@@ -2052,40 +2137,57 @@ function standardPolitogyNav(opts) {
|
|
|
2052
2137
|
...opts.campaignAvailability
|
|
2053
2138
|
};
|
|
2054
2139
|
const rows = [
|
|
2055
|
-
|
|
2056
|
-
|
|
2140
|
+
// Left-Navigation §9.2: Race data -> Research -> GOTV -> Account.
|
|
2141
|
+
// Battleground is the Campaign landing page; there is no Campaign
|
|
2142
|
+
// Dashboard row, and Voter Contact and Tribes have no row.
|
|
2143
|
+
{ kind: "section", label: "Race data" },
|
|
2144
|
+
{ label: "Battleground", icon: icon("crosshair"), href: withOrg(abs("/campaign/battleground")) },
|
|
2145
|
+
{ label: "District data", icon: icon("landmark"), href: withOrg(abs("/campaign/districts")) },
|
|
2146
|
+
{ kind: "section", label: "Research" },
|
|
2057
2147
|
{
|
|
2058
|
-
label: "
|
|
2059
|
-
icon: icon("
|
|
2060
|
-
href: withOrg(
|
|
2061
|
-
children:
|
|
2062
|
-
flag: "
|
|
2148
|
+
label: "Polling",
|
|
2149
|
+
icon: icon("chartNoAxes"),
|
|
2150
|
+
href: withOrg(POLLS_ORIGIN),
|
|
2151
|
+
children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) })),
|
|
2152
|
+
flag: "polling"
|
|
2153
|
+
},
|
|
2154
|
+
{ kind: "section", label: "GOTV" },
|
|
2155
|
+
{
|
|
2156
|
+
label: "Field canvassing",
|
|
2157
|
+
icon: icon("doorOpen"),
|
|
2158
|
+
href: withOrg(CANVASS_ORIGIN),
|
|
2159
|
+
children: appLeaves(CANVASS_ORIGIN, APP_CANVASS_CHILDREN),
|
|
2160
|
+
flag: "canvass"
|
|
2063
2161
|
},
|
|
2064
2162
|
{
|
|
2065
|
-
label: "Phone
|
|
2163
|
+
label: "Phone banking",
|
|
2066
2164
|
icon: icon("phone"),
|
|
2067
2165
|
href: withOrg(PHONEBANK_ORIGIN),
|
|
2068
2166
|
children: appLeaves(PHONEBANK_ORIGIN, APP_PHONEBANK_CHILDREN),
|
|
2069
2167
|
flag: "phonebank"
|
|
2070
2168
|
},
|
|
2071
2169
|
{
|
|
2072
|
-
label: "
|
|
2073
|
-
icon: icon("
|
|
2074
|
-
href: withOrg(
|
|
2075
|
-
children: appLeaves(
|
|
2076
|
-
flag: "
|
|
2170
|
+
label: "A2P texting",
|
|
2171
|
+
icon: icon("messageSquare"),
|
|
2172
|
+
href: withOrg(A2P_ORIGIN),
|
|
2173
|
+
children: appLeaves(A2P_ORIGIN, APP_A2P_CHILDREN),
|
|
2174
|
+
flag: "a2p"
|
|
2077
2175
|
},
|
|
2078
2176
|
{
|
|
2079
|
-
label: "Sign
|
|
2080
|
-
icon: icon("
|
|
2177
|
+
label: "Sign mapping",
|
|
2178
|
+
icon: icon("signpost"),
|
|
2081
2179
|
href: withOrg(SIGNS_ORIGIN),
|
|
2082
2180
|
children: appLeaves(SIGNS_ORIGIN, APP_SIGNS_CHILDREN),
|
|
2083
2181
|
flag: "signs"
|
|
2084
2182
|
},
|
|
2085
|
-
|
|
2086
|
-
{ label: "Polling Engine", icon: icon("barChart"), href: withOrg(POLLS_ORIGIN), flag: "polling" }
|
|
2183
|
+
...accountRows()
|
|
2087
2184
|
];
|
|
2088
|
-
|
|
2185
|
+
const kept = rows.filter((r) => !r.flag || avail[r.flag]).map(({ flag: _flag, ...item }) => item);
|
|
2186
|
+
return kept.filter((item, idx) => {
|
|
2187
|
+
if (item.kind !== "section") return true;
|
|
2188
|
+
const next = kept[idx + 1];
|
|
2189
|
+
return !!next && next.kind !== "section";
|
|
2190
|
+
});
|
|
2089
2191
|
};
|
|
2090
2192
|
const buildPetition = () => [
|
|
2091
2193
|
opts.petitionsItem ? {
|
|
@@ -2192,7 +2294,9 @@ function NavSidebar({
|
|
|
2192
2294
|
footer,
|
|
2193
2295
|
linkComponent,
|
|
2194
2296
|
open,
|
|
2195
|
-
onClose
|
|
2297
|
+
onClose,
|
|
2298
|
+
onOpen,
|
|
2299
|
+
onNavigate
|
|
2196
2300
|
}) {
|
|
2197
2301
|
const Link = linkComponent ?? DefaultLink;
|
|
2198
2302
|
const collapsible = !open;
|
|
@@ -2289,7 +2393,7 @@ function NavSidebar({
|
|
|
2289
2393
|
style: { fontFamily: 'var(--font-family, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif)' },
|
|
2290
2394
|
onKeyDown: trapTab,
|
|
2291
2395
|
onClick: (e) => {
|
|
2292
|
-
if (open && e.target.closest("a[href]")) onClose?.();
|
|
2396
|
+
if (open && e.target.closest("a[href]")) (onNavigate ?? onClose)?.();
|
|
2293
2397
|
},
|
|
2294
2398
|
children: [
|
|
2295
2399
|
open ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2298,18 +2402,30 @@ function NavSidebar({
|
|
|
2298
2402
|
type: "button",
|
|
2299
2403
|
ref: closeButtonRef,
|
|
2300
2404
|
onClick: onClose,
|
|
2301
|
-
"aria-label": "
|
|
2405
|
+
"aria-label": "Collapse navigation",
|
|
2302
2406
|
className: "absolute right-3 top-3 flex h-8 w-8 items-center justify-center rounded-full text-[color:var(--muted)] transition hover:bg-[color:var(--panel-elevated)] hover:text-[color:var(--foreground)] md:hidden",
|
|
2303
2407
|
children: /* @__PURE__ */ jsxRuntime.jsx(CloseIcon, {})
|
|
2304
2408
|
}
|
|
2305
2409
|
) : null,
|
|
2306
2410
|
/* @__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 ${rc("max-md:items-center max-md:px-[10px]")}`, children: [
|
|
2411
|
+
onOpen ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2412
|
+
"button",
|
|
2413
|
+
{
|
|
2414
|
+
type: "button",
|
|
2415
|
+
onClick: onOpen,
|
|
2416
|
+
"aria-label": "Expand navigation",
|
|
2417
|
+
"aria-expanded": open ?? false,
|
|
2418
|
+
"data-rail-toggle": "expand",
|
|
2419
|
+
className: `hidden h-8 w-8 items-center justify-center rounded-lg ${rc("max-md:flex")}`,
|
|
2420
|
+
children: brand.logoSquareSrc ? /* @__PURE__ */ jsxRuntime.jsx("img", { src: brand.logoSquareSrc, alt: "", draggable: false, className: "h-8 w-8 object-contain" }) : brand.logoPending ? /* @__PURE__ */ jsxRuntime.jsx("span", { "aria-hidden": true, className: "block h-8 w-8" }) : /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex h-8 w-8 items-center justify-center rounded-xl bg-[color:var(--color-accent)] text-sm font-black text-[#FFFFFF]", children: brand.badgeLabel })
|
|
2421
|
+
}
|
|
2422
|
+
) : null,
|
|
2307
2423
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2308
2424
|
Link,
|
|
2309
2425
|
{
|
|
2310
2426
|
href: brand.homeHref ?? "/",
|
|
2311
2427
|
"aria-label": brand.logoAlt ?? brand.title,
|
|
2312
|
-
className: `flex items-center gap-2.5 ${rc("max-md:justify-center")}`,
|
|
2428
|
+
className: `flex items-center gap-2.5 ${rc("max-md:justify-center")} ${onOpen ? rc("max-md:hidden") : ""}`,
|
|
2313
2429
|
children: [
|
|
2314
2430
|
brand.logoSquareSrc ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
2315
2431
|
"img",
|
|
@@ -3083,7 +3199,7 @@ function NavTopBar({
|
|
|
3083
3199
|
const initials = (hasRealName ? rawName : user?.email ?? "P").slice(0, 2).toUpperCase();
|
|
3084
3200
|
const secondary = hasRealName ? user?.email || [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member" : [user?.tier, user?.role].filter(Boolean).join(" \xB7 ") || "member";
|
|
3085
3201
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "sticky top-0 z-20", children: [
|
|
3086
|
-
/* @__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: [
|
|
3202
|
+
/* @__PURE__ */ jsxRuntime.jsxs("header", { className: "flex min-w-0 h-[var(--topbar-height,60px)] items-center justify-between gap-[8px] md:gap-[14px] border-b border-[color:var(--line)] bg-[color:var(--panel)] px-[var(--topbar-padding-x,20px)]", children: [
|
|
3087
3203
|
onOpenNav ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
3088
3204
|
"button",
|
|
3089
3205
|
{
|
|
@@ -3096,7 +3212,7 @@ function NavTopBar({
|
|
|
3096
3212
|
children: /* @__PURE__ */ jsxRuntime.jsx(HamburgerIcon, {})
|
|
3097
3213
|
}
|
|
3098
3214
|
) : null,
|
|
3099
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex h-9 w-[320px] max-w-full shrink
|
|
3215
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: "relative flex h-9 w-[320px] min-w-0 max-w-full shrink items-center md:shrink-0", children: [
|
|
3100
3216
|
/* @__PURE__ */ jsxRuntime.jsx(SearchIcon, { className: "pointer-events-none absolute left-[10px] h-[15px] w-[15px] text-[color:var(--muted)]" }),
|
|
3101
3217
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3102
3218
|
"input",
|
|
@@ -3116,13 +3232,13 @@ function NavTopBar({
|
|
|
3116
3232
|
"kbd",
|
|
3117
3233
|
{
|
|
3118
3234
|
"aria-hidden": true,
|
|
3119
|
-
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)]",
|
|
3235
|
+
className: "pointer-events-none absolute right-[10px] hidden md:block 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)]",
|
|
3120
3236
|
children: "/"
|
|
3121
3237
|
}
|
|
3122
3238
|
)
|
|
3123
3239
|
] }),
|
|
3124
3240
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative ml-auto flex shrink-0 items-center gap-[var(--topbar-icon-gap,8px)]", children: [
|
|
3125
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3241
|
+
buildNotes ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3126
3242
|
"button",
|
|
3127
3243
|
{
|
|
3128
3244
|
type: "button",
|
|
@@ -3133,7 +3249,7 @@ function NavTopBar({
|
|
|
3133
3249
|
buildNotes?.label ?? "Build notes"
|
|
3134
3250
|
]
|
|
3135
3251
|
}
|
|
3136
|
-
),
|
|
3252
|
+
) : null,
|
|
3137
3253
|
actionsList && actionsList.length > 0 ? actionsList.map((action) => /* @__PURE__ */ jsxRuntime.jsx(NavTopBarActionButton, { action }, action.key)) : null,
|
|
3138
3254
|
actions,
|
|
3139
3255
|
themeToggle,
|
|
@@ -3624,9 +3740,22 @@ function NavAppShell({
|
|
|
3624
3740
|
);
|
|
3625
3741
|
}
|
|
3626
3742
|
const [navOpen, setNavOpen] = react.useState(false);
|
|
3743
|
+
const expandRail = () => {
|
|
3744
|
+
writeRailPreference("expanded");
|
|
3745
|
+
setNavOpen(true);
|
|
3746
|
+
};
|
|
3747
|
+
const collapseRail = () => {
|
|
3748
|
+
writeRailPreference("collapsed");
|
|
3749
|
+
setNavOpen(false);
|
|
3750
|
+
};
|
|
3627
3751
|
react.useEffect(() => {
|
|
3628
3752
|
setNavOpen(false);
|
|
3629
3753
|
}, [sidebar.pathname]);
|
|
3754
|
+
react.useEffect(() => {
|
|
3755
|
+
if (readRailPreference() !== "expanded") return;
|
|
3756
|
+
const narrow = typeof window !== "undefined" && typeof window.matchMedia === "function" ? window.matchMedia("(max-width: 767.98px)").matches : false;
|
|
3757
|
+
if (narrow) setNavOpen(true);
|
|
3758
|
+
}, []);
|
|
3630
3759
|
react.useEffect(() => {
|
|
3631
3760
|
if (!navOpen) return;
|
|
3632
3761
|
const previous = document.body.style.overflow;
|
|
@@ -3647,15 +3776,23 @@ function NavAppShell({
|
|
|
3647
3776
|
"data-politogy-mode": modeId,
|
|
3648
3777
|
className: "min-h-screen bg-[color:var(--background)] text-[color:var(--foreground)]",
|
|
3649
3778
|
children: [
|
|
3650
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3779
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3780
|
+
NavSidebar,
|
|
3781
|
+
{
|
|
3782
|
+
...sidebar,
|
|
3783
|
+
footer: sidebarFooter,
|
|
3784
|
+
open: navOpen,
|
|
3785
|
+
onClose: collapseRail,
|
|
3786
|
+
onOpen: expandRail,
|
|
3787
|
+
onNavigate: () => setNavOpen(false)
|
|
3788
|
+
}
|
|
3789
|
+
),
|
|
3651
3790
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "pl-[var(--sidebar-collapsed-width,64px)] md:pl-[var(--sidebar-width,236px)]", children: [
|
|
3652
3791
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3653
3792
|
NavTopBar,
|
|
3654
3793
|
{
|
|
3655
3794
|
...topBar,
|
|
3656
|
-
accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar")
|
|
3657
|
-
onOpenNav: () => setNavOpen(true),
|
|
3658
|
-
navOpen
|
|
3795
|
+
accountMenu: topBar.accountMenu ?? (accountMenuPlacement === "sidebar" ? "sidebar" : "topbar")
|
|
3659
3796
|
}
|
|
3660
3797
|
),
|
|
3661
3798
|
betaBanner ? /* @__PURE__ */ jsxRuntime.jsx(NavBetaBanner, { ...betaBanner }) : null,
|
|
@@ -3730,66 +3867,6 @@ function resolveActiveOrg(search) {
|
|
|
3730
3867
|
return readActiveOrgCookie();
|
|
3731
3868
|
}
|
|
3732
3869
|
|
|
3733
|
-
// src/nav-preference.ts
|
|
3734
|
-
var NAV_DISPLAY_STORAGE_KEY = "politogy_nav_display";
|
|
3735
|
-
var NAV_DISPLAY_COOKIE = "politogy_nav_display";
|
|
3736
|
-
var LEGACY_NAV_DISPLAY_KEY = "vrm.navDisplay";
|
|
3737
|
-
var NAV_DISPLAY_DEFAULT = "both";
|
|
3738
|
-
var VALID2 = ["menu", "tabs", "both"];
|
|
3739
|
-
function isNavDisplayPreference(v) {
|
|
3740
|
-
return typeof v === "string" && VALID2.includes(v);
|
|
3741
|
-
}
|
|
3742
|
-
function readNavDisplayCookie() {
|
|
3743
|
-
if (typeof document === "undefined") return null;
|
|
3744
|
-
try {
|
|
3745
|
-
const m = document.cookie.match(
|
|
3746
|
-
new RegExp(`(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)`)
|
|
3747
|
-
);
|
|
3748
|
-
const v = m ? decodeURIComponent(m[1]) : null;
|
|
3749
|
-
return isNavDisplayPreference(v) ? v : null;
|
|
3750
|
-
} catch {
|
|
3751
|
-
return null;
|
|
3752
|
-
}
|
|
3753
|
-
}
|
|
3754
|
-
function writeNavDisplayCookie(pref) {
|
|
3755
|
-
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
3756
|
-
const host = window.location.hostname;
|
|
3757
|
-
const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
|
|
3758
|
-
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
3759
|
-
document.cookie = `${NAV_DISPLAY_COOKIE}=${encodeURIComponent(
|
|
3760
|
-
pref
|
|
3761
|
-
)}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
|
|
3762
|
-
}
|
|
3763
|
-
function readNavDisplayLocal() {
|
|
3764
|
-
if (typeof localStorage === "undefined") return null;
|
|
3765
|
-
try {
|
|
3766
|
-
const current = localStorage.getItem(NAV_DISPLAY_STORAGE_KEY);
|
|
3767
|
-
if (isNavDisplayPreference(current)) return current;
|
|
3768
|
-
const legacy = localStorage.getItem(LEGACY_NAV_DISPLAY_KEY);
|
|
3769
|
-
return isNavDisplayPreference(legacy) ? legacy : null;
|
|
3770
|
-
} catch {
|
|
3771
|
-
return null;
|
|
3772
|
-
}
|
|
3773
|
-
}
|
|
3774
|
-
function writeNavDisplayLocal(pref) {
|
|
3775
|
-
if (typeof localStorage === "undefined") return;
|
|
3776
|
-
try {
|
|
3777
|
-
localStorage.setItem(NAV_DISPLAY_STORAGE_KEY, pref);
|
|
3778
|
-
} catch {
|
|
3779
|
-
}
|
|
3780
|
-
}
|
|
3781
|
-
function resolveNavDisplay() {
|
|
3782
|
-
return readNavDisplayCookie() ?? readNavDisplayLocal() ?? NAV_DISPLAY_DEFAULT;
|
|
3783
|
-
}
|
|
3784
|
-
`(function(){try{
|
|
3785
|
-
var KEY=${JSON.stringify(NAV_DISPLAY_STORAGE_KEY)};
|
|
3786
|
-
var VALID=["menu","tabs","both"];
|
|
3787
|
-
function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${NAV_DISPLAY_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
|
|
3788
|
-
var cookie=fromCookie();
|
|
3789
|
-
if(cookie&&VALID.indexOf(cookie)!==-1){var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
|
|
3790
|
-
if(cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}}
|
|
3791
|
-
}catch(e){}})();`;
|
|
3792
|
-
|
|
3793
3870
|
// src/lib/breadcrumbs.ts
|
|
3794
3871
|
function deriveBreadcrumbs(items, pathname, opts) {
|
|
3795
3872
|
const search = opts?.search ?? (typeof window !== "undefined" ? window.location.search : "");
|
|
@@ -4698,10 +4775,7 @@ function FrameBody({
|
|
|
4698
4775
|
// search yet, so this stays decorative (`NavTopBarProps.search` — "an
|
|
4699
4776
|
// app that has not wired search yet still gets the correct chrome").
|
|
4700
4777
|
search: { placeholder: data?.searchPlaceholder ?? DEFAULT_SEARCH_PLACEHOLDER[app] ?? "Search" },
|
|
4701
|
-
//
|
|
4702
|
-
// group. The spec names the element and its position but not its
|
|
4703
|
-
// destination content; `onOpen` is left unset until that is defined.
|
|
4704
|
-
buildNotes: {},
|
|
4778
|
+
// No Build notes control (Reference/UI-Platform, decided 2026-10-03).
|
|
4705
4779
|
// The action cluster is IDENTICAL everywhere — core included. Page
|
|
4706
4780
|
// actions sit BEFORE it, never inside it, so the Alerts bell keeps its
|
|
4707
4781
|
// required position: farthest right, immediately before My Account.
|
|
@@ -4716,33 +4790,43 @@ function FrameBody({
|
|
|
4716
4790
|
] });
|
|
4717
4791
|
}
|
|
4718
4792
|
var standardNavIcons = {
|
|
4719
|
-
home:
|
|
4720
|
-
users:
|
|
4721
|
-
mail:
|
|
4722
|
-
messageSquare:
|
|
4723
|
-
layout:
|
|
4724
|
-
activity:
|
|
4725
|
-
lifeBuoy:
|
|
4726
|
-
grid:
|
|
4727
|
-
list:
|
|
4728
|
-
upload:
|
|
4729
|
-
edit:
|
|
4730
|
-
fileText:
|
|
4731
|
-
send:
|
|
4732
|
-
clock:
|
|
4733
|
-
user:
|
|
4734
|
-
barChart:
|
|
4735
|
-
briefcase:
|
|
4736
|
-
settings:
|
|
4737
|
-
creditCard:
|
|
4738
|
-
dollarSign:
|
|
4739
|
-
share:
|
|
4793
|
+
home: lu.LuHouse,
|
|
4794
|
+
users: lu.LuUsers,
|
|
4795
|
+
mail: lu.LuMail,
|
|
4796
|
+
messageSquare: lu.LuMessageSquare,
|
|
4797
|
+
layout: lu.LuLayoutDashboard,
|
|
4798
|
+
activity: lu.LuActivity,
|
|
4799
|
+
lifeBuoy: lu.LuLifeBuoy,
|
|
4800
|
+
grid: lu.LuLayoutGrid,
|
|
4801
|
+
list: lu.LuList,
|
|
4802
|
+
upload: lu.LuUpload,
|
|
4803
|
+
edit: lu.LuPencil,
|
|
4804
|
+
fileText: lu.LuFileText,
|
|
4805
|
+
send: lu.LuSend,
|
|
4806
|
+
clock: lu.LuClock,
|
|
4807
|
+
user: lu.LuUser,
|
|
4808
|
+
barChart: lu.LuChartColumn,
|
|
4809
|
+
briefcase: lu.LuBriefcase,
|
|
4810
|
+
settings: lu.LuSettings,
|
|
4811
|
+
creditCard: lu.LuCreditCard,
|
|
4812
|
+
dollarSign: lu.LuDollarSign,
|
|
4813
|
+
share: lu.LuShare2,
|
|
4740
4814
|
// Campaign / Petition mode slots.
|
|
4741
|
-
phone:
|
|
4742
|
-
map:
|
|
4743
|
-
mapPin:
|
|
4744
|
-
target:
|
|
4745
|
-
flag:
|
|
4815
|
+
phone: lu.LuPhone,
|
|
4816
|
+
map: lu.LuMap,
|
|
4817
|
+
mapPin: lu.LuMapPin,
|
|
4818
|
+
target: lu.LuTarget,
|
|
4819
|
+
flag: lu.LuFlag,
|
|
4820
|
+
layoutDashboard: lu.LuLayoutDashboard,
|
|
4821
|
+
usersRound: lu.LuUsersRound,
|
|
4822
|
+
mousePointerClick: lu.LuMousePointerClick,
|
|
4823
|
+
clipboardList: lu.LuClipboardList,
|
|
4824
|
+
circleUser: lu.LuCircleUser,
|
|
4825
|
+
crosshair: lu.LuCrosshair,
|
|
4826
|
+
landmark: lu.LuLandmark,
|
|
4827
|
+
chartNoAxes: lu.LuChartNoAxesColumn,
|
|
4828
|
+
doorOpen: lu.LuDoorOpen,
|
|
4829
|
+
signpost: lu.LuSignpost
|
|
4746
4830
|
};
|
|
4747
4831
|
var ORG_STORAGE_KEY = "vrm.activeOrg";
|
|
4748
4832
|
var MODE_STORAGE_KEY = "vrm.activeMode";
|
|
@@ -5169,14 +5253,14 @@ var MODE_DEFS = [
|
|
|
5169
5253
|
{
|
|
5170
5254
|
id: "relationship",
|
|
5171
5255
|
label: "Relationship Mode",
|
|
5172
|
-
icon:
|
|
5256
|
+
icon: lu.LuContactRound,
|
|
5173
5257
|
href: `${CORE_BASE_URL}/relationship/dashboard`,
|
|
5174
5258
|
orgQuery: true
|
|
5175
5259
|
},
|
|
5176
5260
|
{
|
|
5177
5261
|
id: "campaign",
|
|
5178
5262
|
label: "Campaign Mode",
|
|
5179
|
-
icon:
|
|
5263
|
+
icon: lu.LuMegaphone,
|
|
5180
5264
|
href: `${CORE_BASE_URL}/campaign/dashboard`,
|
|
5181
5265
|
orgQuery: true
|
|
5182
5266
|
},
|
|
@@ -5185,7 +5269,7 @@ var MODE_DEFS = [
|
|
|
5185
5269
|
// petitions repo deploys production to petition-mode.politogyvrm.com.
|
|
5186
5270
|
id: "petition",
|
|
5187
5271
|
label: "Petition Mode",
|
|
5188
|
-
icon:
|
|
5272
|
+
icon: lu.LuFilePenLine,
|
|
5189
5273
|
href: "https://petition-mode.politogyvrm.com/",
|
|
5190
5274
|
orgQuery: true
|
|
5191
5275
|
}
|