@the-portland-company/shell 0.76.18 → 0.78.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 +22 -0
- package/dist/app-chrome.cjs +29 -202
- package/dist/app-chrome.cjs.map +1 -1
- package/dist/app-chrome.d.cts +5 -5
- package/dist/app-chrome.d.ts +5 -5
- package/dist/app-chrome.js +22 -9
- package/dist/app-chrome.js.map +1 -1
- package/dist/{chunk-GGM4AD43.js → chunk-FUEIKJLN.js} +12 -16
- package/dist/chunk-FUEIKJLN.js.map +1 -0
- package/dist/{index-DJ3qBzfQ.d.ts → index-KGYMc_1i.d.ts} +3 -4
- package/dist/{index-Cu5frXRQ.d.cts → index-fydj5EU2.d.cts} +3 -4
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/native.cjs +10 -14
- 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 +1 -1
- package/package.json +1 -1
- package/dist/chunk-GGM4AD43.js.map +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,25 @@
|
|
|
1
|
+
## 0.78.0
|
|
2
|
+
|
|
3
|
+
Dashboard, Battleground and District Data are three features in two Modes; no Polls row in the Relationship left bar. Specs cited: Reference/UI-Platform "Dashboard, Battleground and District Data are three features in two Modes" (decided 2026-10-12, Ben), Specs/Left-Navigation §9.1 and §9.2.
|
|
4
|
+
|
|
5
|
+
- **New registry rows `battleground` and `districts`**, both `mode: 'campaign'`, titles "Battleground" and "District Data". The Dashboard deployment must render those two pages with `app="battleground"` / `app="districts"`, never `app="dashboard"`: the `dashboard` row is unscoped, so it draws the Relationship rail, which is how both pages showed inside Relationship Mode with a "Dashboard · Battleground · District Data" strip above the header (measured 2026-10-12). Their hosts are decided (`battleground.politogyvrm.com`, `districts.politogyvrm.com`; UI-Platform, 2026-10-12) but not live, so both origins and both left-bar links stay on the dashboard host until each goes live.
|
|
6
|
+
- **`dashboard` row unchanged** in behavior; its comment now says it is the Relationship Dashboard only.
|
|
7
|
+
|
|
8
|
+
Polls: Spec cited: Specs/Left-Navigation §9.1 ("Polls is not a Relationship row. Polling is a Campaign Mode feature only").
|
|
9
|
+
|
|
10
|
+
- **Relationship tree.** `standardPolitogyNav` no longer adds a `Polls` row to the Collect section (it was restored in 0.75.0). Collect is Calls to action, Forms, Surveys. Seen live on dashboard.politogyvrm.com in Relationship Mode on 2026-10-12.
|
|
11
|
+
- **Campaign tree unchanged.** `Polling` stays under Research, and the `polls` registry entry is already `mode: 'campaign'`, so the Polls app keeps an active row.
|
|
12
|
+
- **For consumers.** `hiddenItems: ['Polls']` is now a no-op and can be dropped.
|
|
13
|
+
- Tests: `__tests__/standardNav.test.ts`.
|
|
14
|
+
|
|
15
|
+
## 0.77.0
|
|
16
|
+
|
|
17
|
+
No theme control in the account menu. Specs cited: Reference/UI-Platform "Theme — light only (Dark Mode retired)" and "There is no theme control … Apps must not render any theme control"; Reference/Global-Rules "Theming — Light Only".
|
|
18
|
+
|
|
19
|
+
- **Breaking for the eye only.** `PolitogyAppFrame` no longer passes `theme` to the account menu, so the "Appearance" radio group (one option, "Light", since 0.73.0 made the theme light only) is gone from every app. `NavUserMenu.theme` stays optional for a caller that still passes it; nothing in the shell does.
|
|
20
|
+
- `./theme-preference` and `useThemePreference` are unchanged: they still resolve every stored preference to light and keep the cross-app cookie contract for the apps that import them.
|
|
21
|
+
- **Audit note (closeout 2026-10-12, item 1).** The "Known shell defect — dark theme restored in 0.68.0" paragraph in Reference/UI-Platform is stale: 0.73.0 (#116, 2026-10-06) removed dark rendering, `chrome.css` ships no `.dark` block (the remaining mentions are comments), and the pre-paint script hardcodes light. The runtime Brand token sheet (specs app, `lib/brand-authoring.ts`) still emits `.dark {}` blocks that nothing applies.
|
|
22
|
+
|
|
1
23
|
## 0.76.18
|
|
2
24
|
|
|
3
25
|
Consolidates 0.76.16 and 0.76.17, neither of which reached npm (their publish gates failed). Specs cited: Global-Rules v38, UI-Platform v46, Specs/Left-Navigation (no Tribes row, §9.1), Specs/System-Communications §6.3 and §12.2 (Binding, 2026-10-03).
|
package/dist/app-chrome.cjs
CHANGED
|
@@ -487,92 +487,6 @@ function notificationsFeedToPayload(feed, orgId) {
|
|
|
487
487
|
badge: feed.badge
|
|
488
488
|
};
|
|
489
489
|
}
|
|
490
|
-
|
|
491
|
-
// src/theme-preference.ts
|
|
492
|
-
var THEME_STORAGE_KEY = "politogy_theme";
|
|
493
|
-
var THEME_COOKIE = "politogy_theme";
|
|
494
|
-
var THEME_PENDING_COOKIE = "politogy_theme_pending";
|
|
495
|
-
var VALID2 = ["light", "dark", "system"];
|
|
496
|
-
function isThemePreference(v) {
|
|
497
|
-
return typeof v === "string" && VALID2.includes(v);
|
|
498
|
-
}
|
|
499
|
-
function readThemeCookie() {
|
|
500
|
-
if (typeof document === "undefined") return null;
|
|
501
|
-
try {
|
|
502
|
-
const m = document.cookie.match(
|
|
503
|
-
new RegExp(`(?:^|;\\s*)${THEME_COOKIE}=([^;]+)`)
|
|
504
|
-
);
|
|
505
|
-
const v = m ? decodeURIComponent(m[1]) : null;
|
|
506
|
-
return isThemePreference(v) ? v : null;
|
|
507
|
-
} catch {
|
|
508
|
-
return null;
|
|
509
|
-
}
|
|
510
|
-
}
|
|
511
|
-
function writeThemeCookie(pref) {
|
|
512
|
-
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
513
|
-
const host = window.location.hostname;
|
|
514
|
-
const onParentDomain = /(^|\.)politogyvrm\.com$/i.test(host);
|
|
515
|
-
const domainAttr = onParentDomain ? "; Domain=.politogyvrm.com" : "";
|
|
516
|
-
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
517
|
-
document.cookie = `${THEME_COOKIE}=${encodeURIComponent(
|
|
518
|
-
pref
|
|
519
|
-
)}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
|
|
520
|
-
}
|
|
521
|
-
function writeSharedCookie(name, value, maxAgeSeconds) {
|
|
522
|
-
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
523
|
-
const host = window.location.hostname;
|
|
524
|
-
const domainAttr = /(^|\.)politogyvrm\.com$/i.test(host) ? "; Domain=.politogyvrm.com" : "";
|
|
525
|
-
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
526
|
-
document.cookie = `${name}=${encodeURIComponent(
|
|
527
|
-
value
|
|
528
|
-
)}; Path=/; Max-Age=${maxAgeSeconds}; SameSite=Lax${domainAttr}${secure}`;
|
|
529
|
-
}
|
|
530
|
-
function markThemeChoicePending(pref) {
|
|
531
|
-
writeSharedCookie(THEME_PENDING_COOKIE, pref, 31536e3);
|
|
532
|
-
}
|
|
533
|
-
function readPendingThemeChoice() {
|
|
534
|
-
if (typeof document === "undefined") return null;
|
|
535
|
-
try {
|
|
536
|
-
const m = document.cookie.match(
|
|
537
|
-
new RegExp(`(?:^|;\\s*)${THEME_PENDING_COOKIE}=([^;]+)`)
|
|
538
|
-
);
|
|
539
|
-
const v = m ? decodeURIComponent(m[1]) : null;
|
|
540
|
-
return isThemePreference(v) ? v : null;
|
|
541
|
-
} catch {
|
|
542
|
-
return null;
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
|
-
function clearPendingThemeChoice() {
|
|
546
|
-
writeSharedCookie(THEME_PENDING_COOKIE, "", 0);
|
|
547
|
-
}
|
|
548
|
-
function resolveTheme(_pref) {
|
|
549
|
-
return "light";
|
|
550
|
-
}
|
|
551
|
-
function applyThemePreference(pref) {
|
|
552
|
-
if (typeof document === "undefined") return;
|
|
553
|
-
const resolved = resolveTheme();
|
|
554
|
-
const d = document.documentElement;
|
|
555
|
-
d.classList.toggle("dark", resolved === "dark");
|
|
556
|
-
try {
|
|
557
|
-
d.setAttribute("data-theme", resolved);
|
|
558
|
-
d.style.colorScheme = resolved;
|
|
559
|
-
} catch {
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
`(function(){try{
|
|
563
|
-
var KEY=${JSON.stringify(THEME_STORAGE_KEY)};
|
|
564
|
-
var VALID=["light","dark","system"];
|
|
565
|
-
function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${THEME_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
|
|
566
|
-
var cookie=fromCookie();
|
|
567
|
-
var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
|
|
568
|
-
var pref=cookie||ls||"system";
|
|
569
|
-
if(VALID.indexOf(pref)===-1)pref="system";
|
|
570
|
-
if(cookie&&cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}
|
|
571
|
-
var dark=false;
|
|
572
|
-
var d=document.documentElement;
|
|
573
|
-
if(dark)d.classList.add("dark");else d.classList.remove("dark");
|
|
574
|
-
try{d.setAttribute("data-theme",dark?"dark":"light");d.style.colorScheme=dark?"dark":"light";}catch(e){}
|
|
575
|
-
}catch(e){}})();`;
|
|
576
490
|
var CORE_APP_ORIGIN = "https://app.politogyvrm.com";
|
|
577
491
|
var CORE_BILLING_PATH = "/organization-settings/subscription-billing/text-email";
|
|
578
492
|
var CORE_BILLING_URL = `${CORE_APP_ORIGIN}${CORE_BILLING_PATH}`;
|
|
@@ -2201,102 +2115,6 @@ var NAV_DISPLAY_OPTIONS = [
|
|
|
2201
2115
|
{ value: "tabs", label: "Tabs Only" },
|
|
2202
2116
|
{ value: "both", label: "Both" }
|
|
2203
2117
|
];
|
|
2204
|
-
function useThemePreference() {
|
|
2205
|
-
const ctx = react.useContext(NavChromeContext);
|
|
2206
|
-
const fetchJson = ctx?.fetchJson ?? null;
|
|
2207
|
-
const [value, setValueState] = react.useState("system");
|
|
2208
|
-
const reconciled = react.useRef(false);
|
|
2209
|
-
react.useEffect(() => {
|
|
2210
|
-
const cookie = readThemeCookie();
|
|
2211
|
-
let ls = null;
|
|
2212
|
-
try {
|
|
2213
|
-
ls = localStorage.getItem(THEME_STORAGE_KEY);
|
|
2214
|
-
} catch {
|
|
2215
|
-
}
|
|
2216
|
-
const pref = cookie ?? (isThemePreference(ls) ? ls : null) ?? "system";
|
|
2217
|
-
setValueState(pref);
|
|
2218
|
-
applyThemePreference();
|
|
2219
|
-
}, []);
|
|
2220
|
-
const meCtx = react.useContext(NavChromeContext);
|
|
2221
|
-
react.useEffect(() => {
|
|
2222
|
-
if (reconciled.current) return;
|
|
2223
|
-
const pending = readPendingThemeChoice();
|
|
2224
|
-
if (pending) {
|
|
2225
|
-
if (meCtx?.me) reconciled.current = true;
|
|
2226
|
-
setValueState(pending);
|
|
2227
|
-
applyThemePreference();
|
|
2228
|
-
writeThemeCookie(pending);
|
|
2229
|
-
try {
|
|
2230
|
-
localStorage.setItem(THEME_STORAGE_KEY, pending);
|
|
2231
|
-
} catch {
|
|
2232
|
-
}
|
|
2233
|
-
if (!meCtx?.me) return;
|
|
2234
|
-
fetchJson?.("me/preferences", {
|
|
2235
|
-
method: "PATCH",
|
|
2236
|
-
headers: { "Content-Type": "application/json" },
|
|
2237
|
-
body: JSON.stringify({ themePreference: pending })
|
|
2238
|
-
}).then(() => clearPendingThemeChoice()).catch(() => {
|
|
2239
|
-
});
|
|
2240
|
-
return;
|
|
2241
|
-
}
|
|
2242
|
-
const pref = meCtx?.me?.themePreference;
|
|
2243
|
-
if (isThemePreference(pref)) {
|
|
2244
|
-
reconciled.current = true;
|
|
2245
|
-
setValueState(pref);
|
|
2246
|
-
applyThemePreference();
|
|
2247
|
-
writeThemeCookie(pref);
|
|
2248
|
-
try {
|
|
2249
|
-
localStorage.setItem(THEME_STORAGE_KEY, pref);
|
|
2250
|
-
} catch {
|
|
2251
|
-
}
|
|
2252
|
-
}
|
|
2253
|
-
}, [meCtx?.me]);
|
|
2254
|
-
react.useEffect(() => {
|
|
2255
|
-
const onStorage = (e) => {
|
|
2256
|
-
if (e.key === THEME_STORAGE_KEY && isThemePreference(e.newValue)) {
|
|
2257
|
-
setValueState(e.newValue);
|
|
2258
|
-
applyThemePreference(e.newValue);
|
|
2259
|
-
}
|
|
2260
|
-
};
|
|
2261
|
-
const onWake = () => {
|
|
2262
|
-
const cookie = readThemeCookie();
|
|
2263
|
-
if (cookie) {
|
|
2264
|
-
setValueState((prev) => {
|
|
2265
|
-
if (cookie !== prev) applyThemePreference();
|
|
2266
|
-
return cookie;
|
|
2267
|
-
});
|
|
2268
|
-
}
|
|
2269
|
-
};
|
|
2270
|
-
window.addEventListener("storage", onStorage);
|
|
2271
|
-
window.addEventListener("focus", onWake);
|
|
2272
|
-
document.addEventListener("visibilitychange", onWake);
|
|
2273
|
-
return () => {
|
|
2274
|
-
window.removeEventListener("storage", onStorage);
|
|
2275
|
-
window.removeEventListener("focus", onWake);
|
|
2276
|
-
document.removeEventListener("visibilitychange", onWake);
|
|
2277
|
-
};
|
|
2278
|
-
}, []);
|
|
2279
|
-
const setValue = react.useCallback(
|
|
2280
|
-
(next) => {
|
|
2281
|
-
setValueState(next);
|
|
2282
|
-
applyThemePreference();
|
|
2283
|
-
writeThemeCookie(next);
|
|
2284
|
-
try {
|
|
2285
|
-
localStorage.setItem(THEME_STORAGE_KEY, next);
|
|
2286
|
-
} catch {
|
|
2287
|
-
}
|
|
2288
|
-
markThemeChoicePending(next);
|
|
2289
|
-
fetchJson?.("me/preferences", {
|
|
2290
|
-
method: "PATCH",
|
|
2291
|
-
headers: { "Content-Type": "application/json" },
|
|
2292
|
-
body: JSON.stringify({ themePreference: next })
|
|
2293
|
-
}).then(() => clearPendingThemeChoice()).catch(() => {
|
|
2294
|
-
});
|
|
2295
|
-
},
|
|
2296
|
-
[fetchJson]
|
|
2297
|
-
);
|
|
2298
|
-
return { value, setValue };
|
|
2299
|
-
}
|
|
2300
2118
|
var standardNavIcons = {
|
|
2301
2119
|
home: lu.LuHouse,
|
|
2302
2120
|
users: lu.LuUsers,
|
|
@@ -2543,16 +2361,9 @@ function standardPolitogyNav(opts) {
|
|
|
2543
2361
|
href: withOrg("https://surveys.politogyvrm.com/surveys"),
|
|
2544
2362
|
children: APP_SURVEYS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
2545
2363
|
},
|
|
2546
|
-
// Polls
|
|
2547
|
-
//
|
|
2548
|
-
//
|
|
2549
|
-
// here (this row is independent of the retired app).
|
|
2550
|
-
{
|
|
2551
|
-
label: "Polls",
|
|
2552
|
-
icon: icon("chartNoAxes"),
|
|
2553
|
-
href: withOrg(POLLS_ORIGIN),
|
|
2554
|
-
children: APP_POLLS_CHILDREN.map((c) => ({ label: c.label, icon: icon(c.icon), href: withOrg(c.href) }))
|
|
2555
|
-
},
|
|
2364
|
+
// No Polls row here: Polling is a Campaign Mode feature only
|
|
2365
|
+
// (Specs/Left-Navigation §9.1 "Polls is not a Relationship row"). Its
|
|
2366
|
+
// row is "Polling" under Research in the Campaign tree below.
|
|
2556
2367
|
...accountRows()
|
|
2557
2368
|
];
|
|
2558
2369
|
};
|
|
@@ -2566,11 +2377,14 @@ function standardPolitogyNav(opts) {
|
|
|
2566
2377
|
// Battleground is the Campaign landing page; there is no Campaign
|
|
2567
2378
|
// Dashboard row, and Voter Contact and Tribes have no row.
|
|
2568
2379
|
{ kind: "section", label: "Race data" },
|
|
2569
|
-
// Battleground
|
|
2570
|
-
//
|
|
2380
|
+
// Battleground is its own Campaign Mode app (registry key
|
|
2381
|
+
// `battleground`), not part of the Dashboard. It is served from the
|
|
2382
|
+
// dashboard deployment only until battleground.politogyvrm.com is live
|
|
2383
|
+
// (Reference/UI-Platform, decided 2026-10-12).
|
|
2571
2384
|
{ label: "Battleground", icon: icon("crosshair"), href: withOrg(`${DASHBOARD_ORIGIN}battleground`) },
|
|
2572
|
-
// District
|
|
2573
|
-
//
|
|
2385
|
+
// District Data is its own Campaign Mode app (registry key
|
|
2386
|
+
// `districts`); served from the dashboard deployment until
|
|
2387
|
+
// districts.politogyvrm.com is live.
|
|
2574
2388
|
{ label: "District data", icon: icon("landmark"), href: withOrg(`${DASHBOARD_ORIGIN}districts`) },
|
|
2575
2389
|
{ kind: "section", label: "Research" },
|
|
2576
2390
|
{
|
|
@@ -4731,11 +4545,23 @@ var POLITOGY_APPS = {
|
|
|
4731
4545
|
polls: { title: "Polls", origin: "https://polls.politogyvrm.com", storagePrefix: "polls", mode: "campaign", grants: ["title"] },
|
|
4732
4546
|
ctas: { title: "CTAs", origin: "https://ctas.politogyvrm.com", storagePrefix: "ctas", grants: ["title"] },
|
|
4733
4547
|
// V2 apps that replace retired app.politogyvrm.com pages (Reference/
|
|
4734
|
-
// UI-Platform v42 "Retirement of app.politogyvrm.com"). Dashboard
|
|
4735
|
-
// Relationship Dashboard
|
|
4736
|
-
// (Specs/Relationship-Dashboard
|
|
4737
|
-
// (Specs/Organization-Settings).
|
|
4548
|
+
// UI-Platform v42 "Retirement of app.politogyvrm.com"). Dashboard is the
|
|
4549
|
+
// Relationship Dashboard, the Relationship Mode landing page, and nothing
|
|
4550
|
+
// else (Specs/Relationship-Dashboard §1A "Relationship Mode only"); Settings
|
|
4551
|
+
// hosts org settings & billing (Specs/Organization-Settings).
|
|
4738
4552
|
dashboard: { title: "Dashboard", origin: "https://dashboard.politogyvrm.com", storagePrefix: "dashboard" },
|
|
4553
|
+
// Battleground (the Campaign Mode landing page) and District Data are
|
|
4554
|
+
// Campaign Mode features, each its own app (Specs/Left-Navigation §9.2;
|
|
4555
|
+
// Reference/UI-Platform, decided 2026-10-12). They are never rendered with
|
|
4556
|
+
// `app="dashboard"`: that frame is the Relationship rail, which is how they
|
|
4557
|
+
// came to show inside Relationship Mode. Their hosts are decided
|
|
4558
|
+
// (UI-Platform, 2026-10-12): battleground.politogyvrm.com and
|
|
4559
|
+
// districts.politogyvrm.com. Neither is live yet, so the pages are still
|
|
4560
|
+
// served from the dashboard deployment and the origin below is that host.
|
|
4561
|
+
// When a host goes live, change its origin here and its row's href in
|
|
4562
|
+
// standardNav in the same release.
|
|
4563
|
+
battleground: { title: "Battleground", origin: "https://dashboard.politogyvrm.com", storagePrefix: "battleground", mode: "campaign" },
|
|
4564
|
+
districts: { title: "District Data", origin: "https://dashboard.politogyvrm.com", storagePrefix: "districts", mode: "campaign" },
|
|
4739
4565
|
settings: { title: "Settings", origin: "https://settings.politogyvrm.com", storagePrefix: "settings" },
|
|
4740
4566
|
petitions: {
|
|
4741
4567
|
title: "Petitions",
|
|
@@ -5597,7 +5423,6 @@ function useChromeUserMenu({
|
|
|
5597
5423
|
email
|
|
5598
5424
|
}) {
|
|
5599
5425
|
const state = useChromeState();
|
|
5600
|
-
const theme = useThemePreference();
|
|
5601
5426
|
const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null;
|
|
5602
5427
|
const orgSuffix = activeOrg ? `?org=${activeOrg.id}` : "";
|
|
5603
5428
|
const coreBase = getCoreBaseUrl();
|
|
@@ -5608,7 +5433,9 @@ function useChromeUserMenu({
|
|
|
5608
5433
|
roles: (state?.orgs ?? []).filter((o) => o.rawRole || o.role).map((o) => ({ role: o.rawRole ?? o.role, orgName: o.name })),
|
|
5609
5434
|
accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],
|
|
5610
5435
|
addAccountHref: `${coreBase}/my-profile#accounts`,
|
|
5611
|
-
theme:
|
|
5436
|
+
// No theme control: the product is light only (Reference/UI-Platform
|
|
5437
|
+
// "Theme — light only"; shell 0.73.0 stopped applying dark). The account
|
|
5438
|
+
// menu rendered an "Appearance" radio with one option until 0.77.0.
|
|
5612
5439
|
navDisplay: state ? { value: state.navDisplay, onChange: state.setNavDisplay } : void 0
|
|
5613
5440
|
};
|
|
5614
5441
|
}
|