@the-portland-company/shell 0.76.18 → 0.77.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 CHANGED
@@ -1,3 +1,11 @@
1
+ ## 0.77.0
2
+
3
+ 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".
4
+
5
+ - **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.
6
+ - `./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.
7
+ - **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.
8
+
1
9
  ## 0.76.18
2
10
 
3
11
  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).
@@ -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,
@@ -5597,7 +5415,6 @@ function useChromeUserMenu({
5597
5415
  email
5598
5416
  }) {
5599
5417
  const state = useChromeState();
5600
- const theme = useThemePreference();
5601
5418
  const activeOrg = state?.orgs.find((o) => o.id === state.orgId) ?? null;
5602
5419
  const orgSuffix = activeOrg ? `?org=${activeOrg.id}` : "";
5603
5420
  const coreBase = getCoreBaseUrl();
@@ -5608,7 +5425,9 @@ function useChromeUserMenu({
5608
5425
  roles: (state?.orgs ?? []).filter((o) => o.rawRole || o.role).map((o) => ({ role: o.rawRole ?? o.role, orgName: o.name })),
5609
5426
  accounts: [{ id: userId, name: userName, email, avatarUrl: null, active: true }],
5610
5427
  addAccountHref: `${coreBase}/my-profile#accounts`,
5611
- theme: { value: theme.value, onChange: theme.setValue },
5428
+ // No theme control: the product is light only (Reference/UI-Platform
5429
+ // "Theme — light only"; shell 0.73.0 stopped applying dark). The account
5430
+ // menu rendered an "Appearance" radio with one option until 0.77.0.
5612
5431
  navDisplay: state ? { value: state.navDisplay, onChange: state.setNavDisplay } : void 0
5613
5432
  };
5614
5433
  }