@the-portland-company/shell 0.16.0 → 0.16.2
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/dist/chrome.css +35 -0
- package/dist/chunk-ZZWM7BZZ.js +68 -0
- package/dist/chunk-ZZWM7BZZ.js.map +1 -0
- package/dist/native.cjs +213 -55
- package/dist/native.cjs.map +1 -1
- package/dist/native.d.cts +7 -2
- package/dist/native.d.ts +7 -2
- package/dist/native.js +150 -57
- package/dist/native.js.map +1 -1
- package/dist/theme-preference.cjs +77 -0
- package/dist/theme-preference.cjs.map +1 -0
- package/dist/theme-preference.d.cts +14 -0
- package/dist/theme-preference.d.ts +14 -0
- package/dist/theme-preference.js +3 -0
- package/dist/theme-preference.js.map +1 -0
- package/package.json +7 -2
package/dist/chrome.css
CHANGED
|
@@ -349,3 +349,38 @@
|
|
|
349
349
|
font-weight: 400;
|
|
350
350
|
line-height: 1;
|
|
351
351
|
}
|
|
352
|
+
|
|
353
|
+
/* DevNotes (and any widget-slot popover) — dark-theme inheritance. The
|
|
354
|
+
package's compiled sheet hardcodes light utility colors (bg-white,
|
|
355
|
+
text-gray-*, border-gray-*), so its dropdown rendered light-on-dark. Remap
|
|
356
|
+
those inside the slot to the chrome tokens under `.dark`. */
|
|
357
|
+
.dark .topbar-widget-slot [class*="bg-white"] {
|
|
358
|
+
background-color: var(--panel-elevated);
|
|
359
|
+
}
|
|
360
|
+
.dark .topbar-widget-slot [class*="text-gray-9"],
|
|
361
|
+
.dark .topbar-widget-slot [class*="text-gray-8"],
|
|
362
|
+
.dark .topbar-widget-slot [class*="text-gray-7"],
|
|
363
|
+
.dark .topbar-widget-slot [class*="text-slate-9"],
|
|
364
|
+
.dark .topbar-widget-slot [class*="text-slate-8"] {
|
|
365
|
+
color: var(--foreground);
|
|
366
|
+
}
|
|
367
|
+
.dark .topbar-widget-slot [class*="text-gray-6"],
|
|
368
|
+
.dark .topbar-widget-slot [class*="text-gray-5"],
|
|
369
|
+
.dark .topbar-widget-slot [class*="text-gray-4"],
|
|
370
|
+
.dark .topbar-widget-slot [class*="text-slate-5"] {
|
|
371
|
+
color: var(--muted);
|
|
372
|
+
}
|
|
373
|
+
.dark .topbar-widget-slot [class*="border-gray-"],
|
|
374
|
+
.dark .topbar-widget-slot [class*="border-slate-"] {
|
|
375
|
+
border-color: var(--line);
|
|
376
|
+
}
|
|
377
|
+
.dark .topbar-widget-slot [class*="bg-gray-50"],
|
|
378
|
+
.dark .topbar-widget-slot [class*="bg-gray-100"],
|
|
379
|
+
.dark .topbar-widget-slot [class*="bg-slate-50"],
|
|
380
|
+
.dark .topbar-widget-slot [class*="bg-slate-100"] {
|
|
381
|
+
background-color: var(--panel);
|
|
382
|
+
}
|
|
383
|
+
.dark .topbar-widget-slot [class*="hover:bg-gray-"]:hover,
|
|
384
|
+
.dark .topbar-widget-slot [class*="hover:bg-slate-"]:hover {
|
|
385
|
+
background-color: var(--panel);
|
|
386
|
+
}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
// src/theme-preference.ts
|
|
2
|
+
var THEME_STORAGE_KEY = "politogy_theme";
|
|
3
|
+
var THEME_COOKIE = "politogy_theme";
|
|
4
|
+
var VALID = ["light", "dark", "system"];
|
|
5
|
+
function isThemePreference(v) {
|
|
6
|
+
return typeof v === "string" && VALID.includes(v);
|
|
7
|
+
}
|
|
8
|
+
function readThemeCookie() {
|
|
9
|
+
if (typeof document === "undefined") return null;
|
|
10
|
+
try {
|
|
11
|
+
const m = document.cookie.match(
|
|
12
|
+
new RegExp(`(?:^|;\\s*)${THEME_COOKIE}=([^;]+)`)
|
|
13
|
+
);
|
|
14
|
+
const v = m ? decodeURIComponent(m[1]) : null;
|
|
15
|
+
return isThemePreference(v) ? v : null;
|
|
16
|
+
} catch {
|
|
17
|
+
return null;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function writeThemeCookie(pref) {
|
|
21
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
22
|
+
const host = window.location.hostname;
|
|
23
|
+
const onParentDomain = /(^|\.)politogyvrm\.com$/i.test(host);
|
|
24
|
+
const domainAttr = onParentDomain ? "; Domain=.politogyvrm.com" : "";
|
|
25
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
26
|
+
document.cookie = `${THEME_COOKIE}=${encodeURIComponent(
|
|
27
|
+
pref
|
|
28
|
+
)}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
|
|
29
|
+
}
|
|
30
|
+
function resolveTheme(pref) {
|
|
31
|
+
if (pref === "system") {
|
|
32
|
+
try {
|
|
33
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
34
|
+
} catch {
|
|
35
|
+
return "light";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
return pref;
|
|
39
|
+
}
|
|
40
|
+
function applyThemePreference(pref) {
|
|
41
|
+
if (typeof document === "undefined") return;
|
|
42
|
+
const resolved = resolveTheme(pref);
|
|
43
|
+
const d = document.documentElement;
|
|
44
|
+
d.classList.toggle("dark", resolved === "dark");
|
|
45
|
+
try {
|
|
46
|
+
d.style.colorScheme = resolved;
|
|
47
|
+
} catch {
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
var THEME_PREPAINT_SCRIPT = `(function(){try{
|
|
51
|
+
var KEY=${JSON.stringify(THEME_STORAGE_KEY)};
|
|
52
|
+
var VALID=["light","dark","system"];
|
|
53
|
+
function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${THEME_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
|
|
54
|
+
var cookie=fromCookie();
|
|
55
|
+
var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
|
|
56
|
+
var pref=cookie||ls||"system";
|
|
57
|
+
if(VALID.indexOf(pref)===-1)pref="system";
|
|
58
|
+
if(cookie&&cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}
|
|
59
|
+
var resolved=pref;
|
|
60
|
+
if(pref==="system"){try{resolved=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";}catch(e){resolved="light";}}
|
|
61
|
+
var d=document.documentElement;
|
|
62
|
+
if(resolved==="dark"){d.classList.add("dark");}else{d.classList.remove("dark");}
|
|
63
|
+
try{d.style.colorScheme=resolved;}catch(e){}
|
|
64
|
+
}catch(e){}})();`;
|
|
65
|
+
|
|
66
|
+
export { THEME_COOKIE, THEME_PREPAINT_SCRIPT, THEME_STORAGE_KEY, applyThemePreference, isThemePreference, readThemeCookie, resolveTheme, writeThemeCookie };
|
|
67
|
+
//# sourceMappingURL=chunk-ZZWM7BZZ.js.map
|
|
68
|
+
//# sourceMappingURL=chunk-ZZWM7BZZ.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/theme-preference.ts"],"names":[],"mappings":";AAqBO,IAAM,iBAAA,GAAoB;AAC1B,IAAM,YAAA,GAAe;AAE5B,IAAM,KAAA,GAAoC,CAAC,OAAA,EAAS,MAAA,EAAQ,QAAQ,CAAA;AAE7D,SAAS,kBAAkB,CAAA,EAAkC;AAClE,EAAA,OAAO,OAAO,CAAA,KAAM,QAAA,IAAa,KAAA,CAA4B,SAAS,CAAC,CAAA;AACzE;AAGO,SAAS,eAAA,GAA0C;AACxD,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,EAAa,OAAO,IAAA;AAC5C,EAAA,IAAI;AACF,IAAA,MAAM,CAAA,GAAI,SAAS,MAAA,CAAO,KAAA;AAAA,MACxB,IAAI,MAAA,CAAO,CAAA,WAAA,EAAc,YAAY,CAAA,QAAA,CAAU;AAAA,KACjD;AACA,IAAA,MAAM,IAAI,CAAA,GAAI,kBAAA,CAAmB,CAAA,CAAE,CAAC,CAAC,CAAA,GAAI,IAAA;AACzC,IAAA,OAAO,iBAAA,CAAkB,CAAC,CAAA,GAAI,CAAA,GAAI,IAAA;AAAA,EACpC,CAAA,CAAA,MAAQ;AACN,IAAA,OAAO,IAAA;AAAA,EACT;AACF;AAOO,SAAS,iBAAiB,IAAA,EAA6B;AAC5D,EAAA,IAAI,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,WAAW,WAAA,EAAa;AACtE,EAAA,MAAM,IAAA,GAAO,OAAO,QAAA,CAAS,QAAA;AAC7B,EAAA,MAAM,cAAA,GAAiB,0BAAA,CAA2B,IAAA,CAAK,IAAI,CAAA;AAC3D,EAAA,MAAM,UAAA,GAAa,iBAAiB,2BAAA,GAA8B,EAAA;AAClE,EAAA,MAAM,MAAA,GAAS,MAAA,CAAO,QAAA,CAAS,QAAA,KAAa,WAAW,UAAA,GAAa,EAAA;AACpE,EAAA,QAAA,CAAS,MAAA,GAAS,CAAA,EAAG,YAAY,CAAA,CAAA,EAAI,kBAAA;AAAA,IACnC;AAAA,GACD,CAAA,wCAAA,EAA2C,UAAU,CAAA,EAAG,MAAM,CAAA,CAAA;AACjE;AAGO,SAAS,aAAa,IAAA,EAAyC;AACpE,EAAA,IAAI,SAAS,QAAA,EAAU;AACrB,IAAA,IAAI;AACF,MAAA,OAAO,MAAA,CAAO,UAAA,CAAW,8BAA8B,CAAA,CAAE,UACrD,MAAA,GACA,OAAA;AAAA,IACN,CAAA,CAAA,MAAQ;AACN,MAAA,OAAO,OAAA;AAAA,IACT;AAAA,EACF;AACA,EAAA,OAAO,IAAA;AACT;AAGO,SAAS,qBAAqB,IAAA,EAA6B;AAChE,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACrC,EAAA,MAAM,QAAA,GAAW,aAAa,IAAI,CAAA;AAClC,EAAA,MAAM,IAAI,QAAA,CAAS,eAAA;AACnB,EAAA,CAAA,CAAE,SAAA,CAAU,MAAA,CAAO,MAAA,EAAQ,QAAA,KAAa,MAAM,CAAA;AAC9C,EAAA,IAAI;AACF,IAAA,CAAA,CAAE,MAAM,WAAA,GAAc,QAAA;AAAA,EACxB,CAAA,CAAA,MAAQ;AAAA,EAER;AACF;AAQO,IAAM,qBAAA,GAAwB,CAAA;AAAA,QAAA,EAC3B,IAAA,CAAK,SAAA,CAAU,iBAAiB,CAAC,CAAA;AAAA;AAAA,kEAAA,EAEyB,YAAY,CAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,gBAAA","file":"chunk-ZZWM7BZZ.js","sourcesContent":["// Universal theme preference — the ONE cross-app contract.\n//\n// One theme choice (Light / Dark / System) follows the authenticated user\n// across every Politogy app + subdomain. Three layers cooperate:\n// 1. VRM Core `profiles.theme_preference` — source of truth, persisted via\n// the chrome API (`PATCH me/preferences { themePreference }`) and read\n// back from `GET me` (`themePreference`).\n// 2. `.politogyvrm.com` cookie `politogy_theme` — zero-flash pre-paint\n// vehicle that crosses subdomains (auth session cookies are host-only).\n// 3. localStorage `politogy_theme` — offline fallback store.\n//\n// Ported verbatim from contacts/apps/web/src/lib/theme.ts (the origin of the\n// contract) so every app runs the identical behavior from npm. This module is\n// server-safe (no 'use client'): layouts import THEME_PREPAINT_SCRIPT for the\n// pre-paint inline script. The client-side hook lives in ./native\n// (useThemePreference).\n\nexport type ThemePreference = 'light' | 'dark' | 'system'\n\n// Single converged key for BOTH the localStorage store and the\n// cross-subdomain cookie, so a choice in one app is the same key in the next.\nexport const THEME_STORAGE_KEY = 'politogy_theme'\nexport const THEME_COOKIE = 'politogy_theme'\n\nconst VALID: readonly ThemePreference[] = ['light', 'dark', 'system']\n\nexport function isThemePreference(v: unknown): v is ThemePreference {\n return typeof v === 'string' && (VALID as readonly string[]).includes(v)\n}\n\n/** Read the shared cookie (browser only; null on the server or when unset). */\nexport function readThemeCookie(): ThemePreference | null {\n if (typeof document === 'undefined') return null\n try {\n const m = document.cookie.match(\n new RegExp(`(?:^|;\\\\s*)${THEME_COOKIE}=([^;]+)`),\n )\n const v = m ? decodeURIComponent(m[1]) : null\n return isThemePreference(v) ? v : null\n } catch {\n return null\n }\n}\n\n// Set the cross-subdomain cookie. On a *.politogyvrm.com host we scope it to\n// the parent domain so every app subdomain reads it; on any other host\n// (localhost, *.pages.dev preview) we fall back to a host-only cookie so\n// local/preview theming still works without a mismatched Domain attribute\n// (which browsers silently drop). 1-year, SameSite=Lax, Secure on https.\nexport function writeThemeCookie(pref: ThemePreference): void {\n if (typeof document === 'undefined' || typeof window === 'undefined') return\n const host = window.location.hostname\n const onParentDomain = /(^|\\.)politogyvrm\\.com$/i.test(host)\n const domainAttr = onParentDomain ? '; Domain=.politogyvrm.com' : ''\n const secure = window.location.protocol === 'https:' ? '; Secure' : ''\n document.cookie = `${THEME_COOKIE}=${encodeURIComponent(\n pref,\n )}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`\n}\n\n/** Resolve a preference to the concrete light/dark it renders as right now. */\nexport function resolveTheme(pref: ThemePreference): 'light' | 'dark' {\n if (pref === 'system') {\n try {\n return window.matchMedia('(prefers-color-scheme: dark)').matches\n ? 'dark'\n : 'light'\n } catch {\n return 'light'\n }\n }\n return pref\n}\n\n/** Apply a preference to the document (`.dark` class + color-scheme). */\nexport function applyThemePreference(pref: ThemePreference): void {\n if (typeof document === 'undefined') return\n const resolved = resolveTheme(pref)\n const d = document.documentElement\n d.classList.toggle('dark', resolved === 'dark')\n try {\n d.style.colorScheme = resolved\n } catch {\n /* non-fatal */\n }\n}\n\n// Inline pre-paint script — render it in <head> (or as the first child of\n// <body>) so the theme applies before first paint. Resolves the preference\n// from cookie → localStorage → OS, applies the `.dark` class + `color-scheme`,\n// and seeds localStorage from the cookie so the app hydrates to the synced\n// value (the cross-subdomain flash fix). Self-contained, dependency-free, and\n// wrapped so any failure is silent (never blocks paint).\nexport const THEME_PREPAINT_SCRIPT = `(function(){try{\nvar KEY=${JSON.stringify(THEME_STORAGE_KEY)};\nvar VALID=[\"light\",\"dark\",\"system\"];\nfunction fromCookie(){try{var m=document.cookie.match(/(?:^|;\\\\s*)${THEME_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}\nvar cookie=fromCookie();\nvar ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}\nvar pref=cookie||ls||\"system\";\nif(VALID.indexOf(pref)===-1)pref=\"system\";\nif(cookie&&cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}\nvar resolved=pref;\nif(pref===\"system\"){try{resolved=window.matchMedia(\"(prefers-color-scheme: dark)\").matches?\"dark\":\"light\";}catch(e){resolved=\"light\";}}\nvar d=document.documentElement;\nif(resolved===\"dark\"){d.classList.add(\"dark\");}else{d.classList.remove(\"dark\");}\ntry{d.style.colorScheme=resolved;}catch(e){}\n}catch(e){}})();`\n"]}
|
package/dist/native.cjs
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
var react = require('react');
|
|
5
5
|
var fi = require('react-icons/fi');
|
|
6
|
+
var reactDom = require('react-dom');
|
|
6
7
|
var jsxRuntime = require('react/jsx-runtime');
|
|
7
8
|
|
|
8
9
|
// src/native/index.tsx
|
|
@@ -52,6 +53,71 @@ function resolveBrandGlyph(name) {
|
|
|
52
53
|
if (!name) return null;
|
|
53
54
|
return GLYPHS[name.trim().toLowerCase()] ?? null;
|
|
54
55
|
}
|
|
56
|
+
|
|
57
|
+
// src/theme-preference.ts
|
|
58
|
+
var THEME_STORAGE_KEY = "politogy_theme";
|
|
59
|
+
var THEME_COOKIE = "politogy_theme";
|
|
60
|
+
var VALID = ["light", "dark", "system"];
|
|
61
|
+
function isThemePreference(v) {
|
|
62
|
+
return typeof v === "string" && VALID.includes(v);
|
|
63
|
+
}
|
|
64
|
+
function readThemeCookie() {
|
|
65
|
+
if (typeof document === "undefined") return null;
|
|
66
|
+
try {
|
|
67
|
+
const m = document.cookie.match(
|
|
68
|
+
new RegExp(`(?:^|;\\s*)${THEME_COOKIE}=([^;]+)`)
|
|
69
|
+
);
|
|
70
|
+
const v = m ? decodeURIComponent(m[1]) : null;
|
|
71
|
+
return isThemePreference(v) ? v : null;
|
|
72
|
+
} catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
function writeThemeCookie(pref) {
|
|
77
|
+
if (typeof document === "undefined" || typeof window === "undefined") return;
|
|
78
|
+
const host = window.location.hostname;
|
|
79
|
+
const onParentDomain = /(^|\.)politogyvrm\.com$/i.test(host);
|
|
80
|
+
const domainAttr = onParentDomain ? "; Domain=.politogyvrm.com" : "";
|
|
81
|
+
const secure = window.location.protocol === "https:" ? "; Secure" : "";
|
|
82
|
+
document.cookie = `${THEME_COOKIE}=${encodeURIComponent(
|
|
83
|
+
pref
|
|
84
|
+
)}; Path=/; Max-Age=31536000; SameSite=Lax${domainAttr}${secure}`;
|
|
85
|
+
}
|
|
86
|
+
function resolveTheme(pref) {
|
|
87
|
+
if (pref === "system") {
|
|
88
|
+
try {
|
|
89
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
90
|
+
} catch {
|
|
91
|
+
return "light";
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return pref;
|
|
95
|
+
}
|
|
96
|
+
function applyThemePreference(pref) {
|
|
97
|
+
if (typeof document === "undefined") return;
|
|
98
|
+
const resolved = resolveTheme(pref);
|
|
99
|
+
const d = document.documentElement;
|
|
100
|
+
d.classList.toggle("dark", resolved === "dark");
|
|
101
|
+
try {
|
|
102
|
+
d.style.colorScheme = resolved;
|
|
103
|
+
} catch {
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
`(function(){try{
|
|
107
|
+
var KEY=${JSON.stringify(THEME_STORAGE_KEY)};
|
|
108
|
+
var VALID=["light","dark","system"];
|
|
109
|
+
function fromCookie(){try{var m=document.cookie.match(/(?:^|;\\s*)${THEME_COOKIE}=([^;]+)/);return m?decodeURIComponent(m[1]):null;}catch(e){return null;}}
|
|
110
|
+
var cookie=fromCookie();
|
|
111
|
+
var ls=null;try{ls=localStorage.getItem(KEY);}catch(e){}
|
|
112
|
+
var pref=cookie||ls||"system";
|
|
113
|
+
if(VALID.indexOf(pref)===-1)pref="system";
|
|
114
|
+
if(cookie&&cookie!==ls){try{localStorage.setItem(KEY,cookie);}catch(e){}}
|
|
115
|
+
var resolved=pref;
|
|
116
|
+
if(pref==="system"){try{resolved=window.matchMedia("(prefers-color-scheme: dark)").matches?"dark":"light";}catch(e){resolved="light";}}
|
|
117
|
+
var d=document.documentElement;
|
|
118
|
+
if(resolved==="dark"){d.classList.add("dark");}else{d.classList.remove("dark");}
|
|
119
|
+
try{d.style.colorScheme=resolved;}catch(e){}
|
|
120
|
+
}catch(e){}})();`;
|
|
55
121
|
function topBarIconButtonClass(tone = "default") {
|
|
56
122
|
const toneClass = tone === "danger" || tone === "warning" ? "text-[color:var(--color-race-red)] hover:text-[color:var(--color-race-red)]" : "text-[color:var(--topbar-icon-color,var(--muted))] hover:text-[color:var(--topbar-icon-hover-color,var(--foreground))] hover:bg-[color:var(--topbar-icon-hover-bg,transparent)]";
|
|
57
123
|
return [
|
|
@@ -480,66 +546,69 @@ function SupportAction() {
|
|
|
480
546
|
]
|
|
481
547
|
}
|
|
482
548
|
),
|
|
483
|
-
open
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
/* @__PURE__ */ jsxRuntime.
|
|
495
|
-
|
|
496
|
-
/* @__PURE__ */ jsxRuntime.
|
|
497
|
-
|
|
498
|
-
"
|
|
499
|
-
{
|
|
500
|
-
type: "button",
|
|
501
|
-
onClick: close,
|
|
502
|
-
className: "rounded-full bg-[color:var(--color-race-red)] px-4 py-2 text-sm font-semibold text-white hover:opacity-90",
|
|
503
|
-
children: "Done"
|
|
504
|
-
}
|
|
505
|
-
) })
|
|
506
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
507
|
-
/* @__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." }),
|
|
508
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
509
|
-
"textarea",
|
|
510
|
-
{
|
|
511
|
-
value: message,
|
|
512
|
-
onChange: (e) => setMessage(e.target.value),
|
|
513
|
-
rows: 5,
|
|
514
|
-
placeholder: "How can we help?",
|
|
515
|
-
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-race-red)]"
|
|
516
|
-
}
|
|
517
|
-
),
|
|
518
|
-
state === "error" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-[color:var(--color-race-red)]", children: "Sending failed \u2014 try again." }) : null,
|
|
519
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [
|
|
520
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
549
|
+
open && typeof document !== "undefined" ? reactDom.createPortal(
|
|
550
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
551
|
+
"div",
|
|
552
|
+
{
|
|
553
|
+
className: "fixed inset-0 z-50 flex items-center justify-center bg-black/40 p-4",
|
|
554
|
+
role: "dialog",
|
|
555
|
+
"aria-modal": "true",
|
|
556
|
+
"aria-label": "Support request",
|
|
557
|
+
onMouseDown: (e) => {
|
|
558
|
+
if (e.target === e.currentTarget) close();
|
|
559
|
+
},
|
|
560
|
+
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: [
|
|
561
|
+
/* @__PURE__ */ jsxRuntime.jsx("h2", { className: "text-lg font-bold tracking-[-0.01em] text-[color:var(--foreground)]", children: "Contact Support" }),
|
|
562
|
+
state === "sent" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
563
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-3 text-sm text-[color:var(--muted)]", children: "Your request was sent. The team will reply by email." }),
|
|
564
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-5 flex justify-end", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
521
565
|
"button",
|
|
522
566
|
{
|
|
523
567
|
type: "button",
|
|
524
568
|
onClick: close,
|
|
525
|
-
className: "rounded-full
|
|
526
|
-
children: "
|
|
569
|
+
className: "rounded-full bg-[color:var(--color-race-red)] px-4 py-2 text-sm font-semibold text-white hover:opacity-90",
|
|
570
|
+
children: "Done"
|
|
527
571
|
}
|
|
528
|
-
)
|
|
572
|
+
) })
|
|
573
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
574
|
+
/* @__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." }),
|
|
529
575
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
530
|
-
"
|
|
576
|
+
"textarea",
|
|
531
577
|
{
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
578
|
+
value: message,
|
|
579
|
+
onChange: (e) => setMessage(e.target.value),
|
|
580
|
+
rows: 5,
|
|
581
|
+
placeholder: "How can we help?",
|
|
582
|
+
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-race-red)]"
|
|
537
583
|
}
|
|
538
|
-
)
|
|
584
|
+
),
|
|
585
|
+
state === "error" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-2 text-sm text-[color:var(--color-race-red)]", children: "Sending failed \u2014 try again." }) : null,
|
|
586
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex justify-end gap-2", children: [
|
|
587
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
588
|
+
"button",
|
|
589
|
+
{
|
|
590
|
+
type: "button",
|
|
591
|
+
onClick: close,
|
|
592
|
+
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)]",
|
|
593
|
+
children: "Cancel"
|
|
594
|
+
}
|
|
595
|
+
),
|
|
596
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
597
|
+
"button",
|
|
598
|
+
{
|
|
599
|
+
type: "button",
|
|
600
|
+
onClick: submit,
|
|
601
|
+
disabled: !message.trim() || state === "sending",
|
|
602
|
+
className: "rounded-full bg-[color:var(--color-race-red)] px-4 py-2 text-sm font-semibold text-white transition hover:opacity-90 disabled:cursor-not-allowed disabled:opacity-50",
|
|
603
|
+
children: state === "sending" ? "Sending\u2026" : "Send request"
|
|
604
|
+
}
|
|
605
|
+
)
|
|
606
|
+
] })
|
|
539
607
|
] })
|
|
540
608
|
] })
|
|
541
|
-
|
|
542
|
-
|
|
609
|
+
}
|
|
610
|
+
),
|
|
611
|
+
document.body
|
|
543
612
|
) : null
|
|
544
613
|
] });
|
|
545
614
|
}
|
|
@@ -580,6 +649,96 @@ function NavDisplayAction({
|
|
|
580
649
|
}
|
|
581
650
|
);
|
|
582
651
|
}
|
|
652
|
+
function useThemePreference() {
|
|
653
|
+
const ctx = react.useContext(NavChromeContext);
|
|
654
|
+
const fetchJson = ctx?.fetchJson ?? null;
|
|
655
|
+
const [value, setValueState] = react.useState("system");
|
|
656
|
+
const reconciled = react.useRef(false);
|
|
657
|
+
react.useEffect(() => {
|
|
658
|
+
const cookie = readThemeCookie();
|
|
659
|
+
let ls = null;
|
|
660
|
+
try {
|
|
661
|
+
ls = localStorage.getItem(THEME_STORAGE_KEY);
|
|
662
|
+
} catch {
|
|
663
|
+
}
|
|
664
|
+
const pref = cookie ?? (isThemePreference(ls) ? ls : null) ?? "system";
|
|
665
|
+
setValueState(pref);
|
|
666
|
+
applyThemePreference(pref);
|
|
667
|
+
}, []);
|
|
668
|
+
react.useEffect(() => {
|
|
669
|
+
if (!fetchJson || reconciled.current) return;
|
|
670
|
+
reconciled.current = true;
|
|
671
|
+
fetchJson("me").then((data) => {
|
|
672
|
+
const pref = data?.themePreference;
|
|
673
|
+
if (isThemePreference(pref)) {
|
|
674
|
+
setValueState(pref);
|
|
675
|
+
applyThemePreference(pref);
|
|
676
|
+
writeThemeCookie(pref);
|
|
677
|
+
try {
|
|
678
|
+
localStorage.setItem(THEME_STORAGE_KEY, pref);
|
|
679
|
+
} catch {
|
|
680
|
+
}
|
|
681
|
+
}
|
|
682
|
+
}).catch(() => {
|
|
683
|
+
});
|
|
684
|
+
}, [fetchJson]);
|
|
685
|
+
react.useEffect(() => {
|
|
686
|
+
const onStorage = (e) => {
|
|
687
|
+
if (e.key === THEME_STORAGE_KEY && isThemePreference(e.newValue)) {
|
|
688
|
+
setValueState(e.newValue);
|
|
689
|
+
applyThemePreference(e.newValue);
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
const onWake = () => {
|
|
693
|
+
const cookie = readThemeCookie();
|
|
694
|
+
if (cookie) {
|
|
695
|
+
setValueState((prev) => {
|
|
696
|
+
if (cookie !== prev) applyThemePreference(cookie);
|
|
697
|
+
return cookie;
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
};
|
|
701
|
+
window.addEventListener("storage", onStorage);
|
|
702
|
+
window.addEventListener("focus", onWake);
|
|
703
|
+
document.addEventListener("visibilitychange", onWake);
|
|
704
|
+
return () => {
|
|
705
|
+
window.removeEventListener("storage", onStorage);
|
|
706
|
+
window.removeEventListener("focus", onWake);
|
|
707
|
+
document.removeEventListener("visibilitychange", onWake);
|
|
708
|
+
};
|
|
709
|
+
}, []);
|
|
710
|
+
react.useEffect(() => {
|
|
711
|
+
if (value !== "system") return;
|
|
712
|
+
let mq;
|
|
713
|
+
try {
|
|
714
|
+
mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
715
|
+
} catch {
|
|
716
|
+
return;
|
|
717
|
+
}
|
|
718
|
+
const onChange = () => applyThemePreference("system");
|
|
719
|
+
mq.addEventListener("change", onChange);
|
|
720
|
+
return () => mq.removeEventListener("change", onChange);
|
|
721
|
+
}, [value]);
|
|
722
|
+
const setValue = react.useCallback(
|
|
723
|
+
(next) => {
|
|
724
|
+
setValueState(next);
|
|
725
|
+
applyThemePreference(next);
|
|
726
|
+
writeThemeCookie(next);
|
|
727
|
+
try {
|
|
728
|
+
localStorage.setItem(THEME_STORAGE_KEY, next);
|
|
729
|
+
} catch {
|
|
730
|
+
}
|
|
731
|
+
fetchJson?.("me/preferences", {
|
|
732
|
+
method: "PATCH",
|
|
733
|
+
headers: { "Content-Type": "application/json" },
|
|
734
|
+
body: JSON.stringify({ themePreference: next })
|
|
735
|
+
}).catch(() => {
|
|
736
|
+
});
|
|
737
|
+
},
|
|
738
|
+
[fetchJson]
|
|
739
|
+
);
|
|
740
|
+
return { value, setValue };
|
|
741
|
+
}
|
|
583
742
|
|
|
584
743
|
// src/native/standardNav.ts
|
|
585
744
|
var CONTACTS_DEFAULT_CHILDREN = [
|
|
@@ -856,7 +1015,7 @@ function NavSidebar({
|
|
|
856
1015
|
] })
|
|
857
1016
|
] }),
|
|
858
1017
|
footer ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-shrink-0 border-t border-[color:var(--line)] px-4 py-3", children: [
|
|
859
|
-
footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center gap-1.5 text-xs", children: footer.links.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
1018
|
+
footer.links && footer.links.length > 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap items-center justify-center gap-1.5 text-xs", children: footer.links.map((l, idx) => /* @__PURE__ */ jsxRuntime.jsxs("span", { className: "inline-flex items-center gap-1.5", children: [
|
|
860
1019
|
idx > 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }) : null,
|
|
861
1020
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
862
1021
|
"a",
|
|
@@ -888,14 +1047,12 @@ function NavSidebar({
|
|
|
888
1047
|
] })
|
|
889
1048
|
] }),
|
|
890
1049
|
footer.commitDate || footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
891
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }),
|
|
892
1050
|
footer.commitDate ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: new Date(footer.commitDate).toLocaleDateString(void 0, {
|
|
893
1051
|
month: "short",
|
|
894
1052
|
day: "numeric"
|
|
895
1053
|
}) }) : null,
|
|
896
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }),
|
|
897
|
-
footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: footer.commitAuthor.split(/\s+/)[0] }) : null
|
|
898
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" })
|
|
1054
|
+
footer.commitDate && footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[color:var(--muted)]", children: "|" }) : null,
|
|
1055
|
+
footer.commitAuthor ? /* @__PURE__ */ jsxRuntime.jsx("span", { children: footer.commitAuthor.split(/\s+/)[0] }) : null
|
|
899
1056
|
] }) : null
|
|
900
1057
|
] })
|
|
901
1058
|
] }) : null
|
|
@@ -1426,5 +1583,6 @@ exports.isNavItemActive = isNavItemActive;
|
|
|
1426
1583
|
exports.standardPolitogyNav = standardPolitogyNav;
|
|
1427
1584
|
exports.topBarIconButtonClass = topBarIconButtonClass;
|
|
1428
1585
|
exports.useChromeOrgs = useChromeOrgs;
|
|
1586
|
+
exports.useThemePreference = useThemePreference;
|
|
1429
1587
|
//# sourceMappingURL=native.cjs.map
|
|
1430
1588
|
//# sourceMappingURL=native.cjs.map
|