@psnext/design-system 2.2.0 → 2.3.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/DESIGN.md +2 -2
- package/dist/Header.cjs +63 -88
- package/dist/Header.cjs.map +1 -1
- package/dist/Header.js +64 -89
- package/dist/Header.js.map +1 -1
- package/dist/index.d.cts +5 -5
- package/dist/index.d.ts +5 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index10.d.cts +6 -6
- package/dist/index10.d.ts +7 -7
- package/dist/index10.d.ts.map +1 -1
- package/dist/index11.d.cts +3 -3
- package/dist/index11.d.ts +3 -3
- package/dist/index11.d.ts.map +1 -1
- package/dist/index12.d.cts +12 -12
- package/dist/index12.d.cts.map +1 -1
- package/dist/index12.d.ts +12 -12
- package/dist/index12.d.ts.map +1 -1
- package/dist/index13.d.cts +6 -6
- package/dist/index13.d.ts +6 -6
- package/dist/index14.d.cts +5 -5
- package/dist/index14.d.cts.map +1 -1
- package/dist/index14.d.ts +5 -5
- package/dist/index15.d.cts +3 -3
- package/dist/index15.d.cts.map +1 -1
- package/dist/index15.d.ts +3 -3
- package/dist/index16.d.cts +2 -2
- package/dist/index16.d.cts.map +1 -1
- package/dist/index16.d.ts +2 -2
- package/dist/index17.d.cts +4 -4
- package/dist/index17.d.cts.map +1 -1
- package/dist/index17.d.ts +4 -4
- package/dist/index18.d.cts +11 -11
- package/dist/index18.d.cts.map +1 -1
- package/dist/index18.d.ts +11 -11
- package/dist/index19.d.cts +10 -10
- package/dist/index19.d.ts +10 -10
- package/dist/index2.d.cts +8 -8
- package/dist/index2.d.ts +8 -8
- package/dist/index2.d.ts.map +1 -1
- package/dist/index20.d.cts +16 -16
- package/dist/index20.d.ts +16 -16
- package/dist/index21.d.cts +4 -4
- package/dist/index21.d.ts +4 -4
- package/dist/index22.d.cts +11 -11
- package/dist/index22.d.ts +11 -11
- package/dist/index23.d.cts +16 -16
- package/dist/index23.d.ts +16 -16
- package/dist/index24.d.cts +10 -10
- package/dist/index24.d.cts.map +1 -1
- package/dist/index24.d.ts +10 -10
- package/dist/index25.d.cts +2 -2
- package/dist/index25.d.cts.map +1 -1
- package/dist/index25.d.ts +2 -2
- package/dist/index26.d.cts +13 -13
- package/dist/index26.d.cts.map +1 -1
- package/dist/index26.d.ts +14 -14
- package/dist/index26.d.ts.map +1 -1
- package/dist/index27.d.cts +7 -7
- package/dist/index27.d.ts +7 -7
- package/dist/index28.d.cts +6 -6
- package/dist/index28.d.cts.map +1 -1
- package/dist/index28.d.ts +5 -5
- package/dist/index29.d.cts +4 -4
- package/dist/index29.d.cts.map +1 -1
- package/dist/index29.d.ts +4 -4
- package/dist/index3.d.cts +13 -13
- package/dist/index3.d.cts.map +1 -1
- package/dist/index3.d.ts +13 -13
- package/dist/index30.d.cts +6 -6
- package/dist/index30.d.cts.map +1 -1
- package/dist/index30.d.ts +6 -6
- package/dist/index31.d.cts +4 -4
- package/dist/index31.d.ts +5 -5
- package/dist/index32.d.cts +6 -6
- package/dist/index32.d.cts.map +1 -1
- package/dist/index32.d.ts +5 -5
- package/dist/index33.d.cts +11 -11
- package/dist/index33.d.ts +11 -11
- package/dist/index34.d.cts +5 -5
- package/dist/index34.d.cts.map +1 -1
- package/dist/index34.d.ts +5 -5
- package/dist/index35.d.cts +15 -15
- package/dist/index35.d.cts.map +1 -1
- package/dist/index35.d.ts +15 -15
- package/dist/index35.d.ts.map +1 -1
- package/dist/index36.d.cts +3 -3
- package/dist/index36.d.cts.map +1 -1
- package/dist/index36.d.ts +3 -3
- package/dist/index37.d.cts +4 -4
- package/dist/index37.d.ts +5 -5
- package/dist/index38.d.cts +2 -2
- package/dist/index38.d.cts.map +1 -1
- package/dist/index38.d.ts +2 -2
- package/dist/index39.d.cts +17 -17
- package/dist/index39.d.cts.map +1 -1
- package/dist/index39.d.ts +17 -17
- package/dist/index4.d.cts +2 -2
- package/dist/index4.d.ts +2 -2
- package/dist/index4.d.ts.map +1 -1
- package/dist/index40.d.cts +5 -5
- package/dist/index40.d.cts.map +1 -1
- package/dist/index40.d.ts +5 -5
- package/dist/index41.d.cts +11 -11
- package/dist/index41.d.cts.map +1 -1
- package/dist/index41.d.ts +11 -11
- package/dist/index41.d.ts.map +1 -1
- package/dist/index42.d.cts +8 -8
- package/dist/index42.d.ts +8 -8
- package/dist/index42.d.ts.map +1 -1
- package/dist/index43.d.cts +9 -9
- package/dist/index43.d.ts +9 -9
- package/dist/index43.d.ts.map +1 -1
- package/dist/index45.d.cts +8 -8
- package/dist/index45.d.ts +8 -8
- package/dist/index45.d.ts.map +1 -1
- package/dist/index46.d.cts +2 -2
- package/dist/index46.d.ts +2 -2
- package/dist/index47.d.ts +4 -4
- package/dist/index48.d.cts +4 -4
- package/dist/index48.d.cts.map +1 -1
- package/dist/index48.d.ts +4 -4
- package/dist/index49.d.cts +3 -3
- package/dist/index49.d.ts +3 -3
- package/dist/index5.d.cts +7 -7
- package/dist/index5.d.ts +7 -7
- package/dist/index5.d.ts.map +1 -1
- package/dist/index50.d.cts +11 -11
- package/dist/index50.d.cts.map +1 -1
- package/dist/index50.d.ts +11 -11
- package/dist/index51.d.cts +9 -9
- package/dist/index51.d.ts +9 -9
- package/dist/index52.d.cts +5 -5
- package/dist/index52.d.ts +5 -5
- package/dist/index53.d.cts +27 -27
- package/dist/index53.d.cts.map +1 -1
- package/dist/index53.d.ts +27 -27
- package/dist/index53.d.ts.map +1 -1
- package/dist/index54.d.cts +5 -5
- package/dist/index54.d.ts +5 -5
- package/dist/index55.d.cts +2 -2
- package/dist/index55.d.ts +2 -2
- package/dist/index55.d.ts.map +1 -1
- package/dist/index56.d.cts +2 -2
- package/dist/index56.d.ts +2 -2
- package/dist/index57.d.cts +2 -2
- package/dist/index57.d.cts.map +1 -1
- package/dist/index57.d.ts +2 -2
- package/dist/index58.d.cts +4 -4
- package/dist/index58.d.cts.map +1 -1
- package/dist/index58.d.ts +4 -4
- package/dist/index59.d.cts +9 -9
- package/dist/index59.d.ts +9 -9
- package/dist/index59.d.ts.map +1 -1
- package/dist/index6.d.cts +6 -6
- package/dist/index6.d.ts +5 -5
- package/dist/index6.d.ts.map +1 -1
- package/dist/index60.d.cts +9 -9
- package/dist/index60.d.cts.map +1 -1
- package/dist/index60.d.ts +13 -13
- package/dist/index60.d.ts.map +1 -1
- package/dist/index61.d.cts +8 -8
- package/dist/index61.d.cts.map +1 -1
- package/dist/index61.d.ts +7 -7
- package/dist/index61.d.ts.map +1 -1
- package/dist/index62.d.cts +5 -5
- package/dist/index62.d.cts.map +1 -1
- package/dist/index62.d.ts +4 -4
- package/dist/index62.d.ts.map +1 -1
- package/dist/index63.d.cts +2 -2
- package/dist/index63.d.cts.map +1 -1
- package/dist/index63.d.ts +2 -2
- package/dist/index63.d.ts.map +1 -1
- package/dist/index64.d.cts +6 -6
- package/dist/index64.d.cts.map +1 -1
- package/dist/index64.d.ts +6 -6
- package/dist/index64.d.ts.map +1 -1
- package/dist/index65.d.cts +3 -3
- package/dist/index65.d.ts +3 -3
- package/dist/index65.d.ts.map +1 -1
- package/dist/index66.d.cts +4 -4
- package/dist/index66.d.cts.map +1 -1
- package/dist/index66.d.ts +5 -5
- package/dist/index66.d.ts.map +1 -1
- package/dist/index67.d.cts +2 -2
- package/dist/index67.d.ts +2 -2
- package/dist/index67.d.ts.map +1 -1
- package/dist/index68.d.cts +7 -7
- package/dist/index68.d.cts.map +1 -1
- package/dist/index68.d.ts +8 -8
- package/dist/index68.d.ts.map +1 -1
- package/dist/index69.d.cts +7 -7
- package/dist/index69.d.ts +7 -7
- package/dist/index69.d.ts.map +1 -1
- package/dist/index7.d.cts +8 -8
- package/dist/index7.d.ts +8 -8
- package/dist/index7.d.ts.map +1 -1
- package/dist/index71.d.cts +19 -17
- package/dist/index71.d.cts.map +1 -1
- package/dist/index71.d.ts +19 -17
- package/dist/index71.d.ts.map +1 -1
- package/dist/index8.d.cts +5 -5
- package/dist/index8.d.cts.map +1 -1
- package/dist/index8.d.ts +4 -4
- package/dist/index8.d.ts.map +1 -1
- package/dist/index9.d.cts +2 -2
- package/dist/index9.d.ts +2 -2
- package/dist/index9.d.ts.map +1 -1
- package/dist/patterns/DataTable/index.d.cts +3 -3
- package/dist/patterns/DataTable/index.d.cts.map +1 -1
- package/dist/patterns/DataTable/index.d.ts +3 -3
- package/dist/patterns/DataTable/index.d.ts.map +1 -1
- package/dist/patterns/Footer/index.d.cts +7 -7
- package/dist/patterns/Footer/index.d.ts +7 -7
- package/dist/patterns/Footer/index.d.ts.map +1 -1
- package/dist/patterns/MediaObject/index.d.cts +11 -11
- package/dist/patterns/MediaObject/index.d.ts +13 -13
- package/dist/patterns/SectionCard/index.d.cts +2 -2
- package/dist/patterns/SectionCard/index.d.ts +2 -2
- package/dist/patterns/SectionCard/index.d.ts.map +1 -1
- package/dist/patterns/SectionHeading/index.d.cts +2 -2
- package/dist/patterns/SectionHeading/index.d.ts +2 -2
- package/dist/patterns/SectionHeading/index.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/Header.js
CHANGED
|
@@ -9,7 +9,7 @@ import { Popover, PopoverContent, PopoverTrigger } from "./primitives/Popover/in
|
|
|
9
9
|
import { Skeleton } from "./primitives/Skeleton/index.js";
|
|
10
10
|
import { useTheme } from "./primitives/ThemeProvider/index.js";
|
|
11
11
|
import * as React from "react";
|
|
12
|
-
import { Check, ChevronDown, ChevronRight,
|
|
12
|
+
import { Check, ChevronDown, ChevronRight, LogOut, MessageSquareShare, Moon, Search, Sun } from "lucide-react";
|
|
13
13
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
14
14
|
import { QueryClient, QueryClientProvider, useQuery } from "@tanstack/react-query";
|
|
15
15
|
//#region src/patterns/Header/project-tree.ts
|
|
@@ -25,6 +25,14 @@ function findProjectName(tree, id) {
|
|
|
25
25
|
if (found) return found;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
+
/** First selectable node in the tree (depth-first, skipping context-only ancestors). */
|
|
29
|
+
function firstSelectableProject(tree) {
|
|
30
|
+
for (const node of tree) {
|
|
31
|
+
if (!node.isContextOnly) return node;
|
|
32
|
+
const found = firstSelectableProject(node.children);
|
|
33
|
+
if (found) return found;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
28
36
|
/** Filter the tree to nodes matching `term`, preserving ancestors of matches. */
|
|
29
37
|
function filterTree(nodes, term) {
|
|
30
38
|
if (!term) return nodes;
|
|
@@ -176,16 +184,14 @@ const DEFAULT_LABELS = {
|
|
|
176
184
|
searchPlaceholder: "Search project",
|
|
177
185
|
emptyStateText: "No projects found",
|
|
178
186
|
profileMenuLabel: "Profile menu",
|
|
179
|
-
logoutLabel: "Logout"
|
|
180
|
-
overlayTitle: "Select a Project",
|
|
181
|
-
overlayDescription: "Choose a project to get started. You can change it anytime from the header."
|
|
187
|
+
logoutLabel: "Logout"
|
|
182
188
|
};
|
|
183
189
|
//#endregion
|
|
184
190
|
//#region src/patterns/Header/api.ts
|
|
185
191
|
const PATHS = {
|
|
186
192
|
token: "/api/v1/studio-auth/sessions/token",
|
|
187
193
|
logout: "/api/v1/studio-auth/sessions/logout",
|
|
188
|
-
projects: (clientId) => `/api/v1/
|
|
194
|
+
projects: (clientId) => `/api/v1/client-projects/getAllProjects?limit=50&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,
|
|
189
195
|
credits: "/save/api/v1/users"
|
|
190
196
|
};
|
|
191
197
|
/** Join a base URL and path without doubling slashes. */
|
|
@@ -239,6 +245,7 @@ async function callLogout(endpoints, fetcher) {
|
|
|
239
245
|
//#endregion
|
|
240
246
|
//#region src/patterns/Header/storage.ts
|
|
241
247
|
const PROJECT_KEY = "ds-header-project";
|
|
248
|
+
const LAST_PROJECT_KEY = "lastSelectedProject";
|
|
242
249
|
function getStoredProject() {
|
|
243
250
|
try {
|
|
244
251
|
const raw = sessionStorage.getItem(PROJECT_KEY);
|
|
@@ -257,6 +264,20 @@ function clearStoredProject() {
|
|
|
257
264
|
sessionStorage.removeItem(PROJECT_KEY);
|
|
258
265
|
} catch {}
|
|
259
266
|
}
|
|
267
|
+
/** The project the user last explicitly selected, in any tab (localStorage). */
|
|
268
|
+
function getLastSelectedProject() {
|
|
269
|
+
try {
|
|
270
|
+
const raw = localStorage.getItem(LAST_PROJECT_KEY);
|
|
271
|
+
return raw ? JSON.parse(raw) : null;
|
|
272
|
+
} catch {
|
|
273
|
+
return null;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
function setLastSelectedProject(project) {
|
|
277
|
+
try {
|
|
278
|
+
localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));
|
|
279
|
+
} catch {}
|
|
280
|
+
}
|
|
260
281
|
//#endregion
|
|
261
282
|
//#region src/patterns/Header/header-store.ts
|
|
262
283
|
function initialState() {
|
|
@@ -292,14 +313,22 @@ const headerStore = {
|
|
|
292
313
|
getServerSnapshot() {
|
|
293
314
|
return SERVER_SNAPSHOT;
|
|
294
315
|
},
|
|
295
|
-
/**
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
316
|
+
/**
|
|
317
|
+
* Set the selected project. `name` is best-effort; the Header backfills it from
|
|
318
|
+
* the tree. Explicit selections are also remembered in localStorage as the
|
|
319
|
+
* cross-tab default; pass `remember: false` for internal backfill/auto-select
|
|
320
|
+
* writes so they don't overwrite the user's last explicit choice.
|
|
321
|
+
*/
|
|
322
|
+
setProject(id, name = "", clientId, { remember = true } = {}) {
|
|
323
|
+
if (id) {
|
|
324
|
+
const project = {
|
|
325
|
+
id,
|
|
326
|
+
name,
|
|
327
|
+
clientId: clientId ?? state.clientId
|
|
328
|
+
};
|
|
329
|
+
setStoredProject(project);
|
|
330
|
+
if (remember) setLastSelectedProject(project);
|
|
331
|
+
} else clearStoredProject();
|
|
303
332
|
state = {
|
|
304
333
|
...state,
|
|
305
334
|
selectedProjectId: id,
|
|
@@ -484,6 +513,10 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
|
|
|
484
513
|
}
|
|
485
514
|
}, [apiBaseUrl]);
|
|
486
515
|
const selection = useHeaderStore();
|
|
516
|
+
const onProjectChangeRef = React.useRef(onProjectChange);
|
|
517
|
+
React.useEffect(() => {
|
|
518
|
+
onProjectChangeRef.current = onProjectChange;
|
|
519
|
+
});
|
|
487
520
|
React.useEffect(() => {
|
|
488
521
|
if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);
|
|
489
522
|
}, [effectiveClientId]);
|
|
@@ -491,10 +524,19 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
|
|
|
491
524
|
if (!projectsQuery.data) return;
|
|
492
525
|
const tree = projectsQuery.data.projectsTree;
|
|
493
526
|
const id = headerStore.getSnapshot().selectedProjectId;
|
|
494
|
-
if (id &&
|
|
495
|
-
else if (id) {
|
|
527
|
+
if (id && nodeExistsInTree(tree, id)) {
|
|
496
528
|
const name = findProjectName(tree, id);
|
|
497
|
-
if (name && name !== headerStore.getSnapshot().selectedProjectName) headerStore.setProject(id, name, effectiveClientId);
|
|
529
|
+
if (name && name !== headerStore.getSnapshot().selectedProjectName) headerStore.setProject(id, name, effectiveClientId, { remember: false });
|
|
530
|
+
} else {
|
|
531
|
+
const last = getLastSelectedProject();
|
|
532
|
+
const fallback = last && nodeExistsInTree(tree, last.id) ? {
|
|
533
|
+
id: last.id,
|
|
534
|
+
name: findProjectName(tree, last.id) ?? last.name
|
|
535
|
+
} : firstSelectableProject(tree);
|
|
536
|
+
if (fallback) {
|
|
537
|
+
headerStore.setProject(fallback.id, fallback.name, effectiveClientId, { remember: false });
|
|
538
|
+
onProjectChangeRef.current?.(fallback.id);
|
|
539
|
+
} else if (id) headerStore.clearProject();
|
|
498
540
|
}
|
|
499
541
|
headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);
|
|
500
542
|
}, [projectsQuery.data, effectiveClientId]);
|
|
@@ -532,7 +574,6 @@ function useGlobalHeader({ apiBaseUrl, environmentId, clientId, _dangerouslyInje
|
|
|
532
574
|
credits: selection.credits,
|
|
533
575
|
creditsHref,
|
|
534
576
|
projectDropdownVisible,
|
|
535
|
-
showOverlay: isAuthenticated && projectDropdownVisible && !selection.selectedProjectId,
|
|
536
577
|
selectProject,
|
|
537
578
|
logout
|
|
538
579
|
};
|
|
@@ -644,7 +685,7 @@ function Header(props) {
|
|
|
644
685
|
children: /* @__PURE__ */ jsx(HeaderInner, { ...props })
|
|
645
686
|
});
|
|
646
687
|
}
|
|
647
|
-
function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown = false, showProfile = false, showThemeSwitcher = false, showCredits = false, pageTitle, feedbackUrl, logoAddon,
|
|
688
|
+
function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown = false, showProfile = false, showThemeSwitcher = false, showCredits = false, pageTitle, feedbackUrl, logoAddon, actionsStart, actionsEnd, className, ...rest }) {
|
|
648
689
|
const { product } = useTheme();
|
|
649
690
|
const brand = logoType ?? product;
|
|
650
691
|
const state = useGlobalHeader({
|
|
@@ -658,8 +699,8 @@ function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown
|
|
|
658
699
|
const showOrgUi = showOrg && state.isAuthenticated;
|
|
659
700
|
const showProfileUi = showProfile && state.isAuthenticated;
|
|
660
701
|
const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== void 0;
|
|
661
|
-
const showActions = showThemeSwitcher || showProfileUi || showCreditsUi || !!feedbackUrl;
|
|
662
|
-
return /* @__PURE__ */ jsxs(
|
|
702
|
+
const showActions = showThemeSwitcher || showProfileUi || showCreditsUi || !!feedbackUrl || !!actionsStart || !!actionsEnd;
|
|
703
|
+
return /* @__PURE__ */ jsxs(HeaderBar, {
|
|
663
704
|
className,
|
|
664
705
|
children: [
|
|
665
706
|
/* @__PURE__ */ jsx(HeaderLogo, {
|
|
@@ -693,6 +734,7 @@ function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown
|
|
|
693
734
|
showActions && /* @__PURE__ */ jsxs("div", {
|
|
694
735
|
className: "ml-auto flex items-center gap-2",
|
|
695
736
|
children: [
|
|
737
|
+
actionsStart,
|
|
696
738
|
feedbackUrl && /* @__PURE__ */ jsx(Button, {
|
|
697
739
|
variant: "ghost",
|
|
698
740
|
size: "icon",
|
|
@@ -715,78 +757,11 @@ function HeaderInner({ logoType, logoHref, showOrg = false, showProjectDropdown
|
|
|
715
757
|
showProfileUi && /* @__PURE__ */ jsx(ProfileMenu, {
|
|
716
758
|
email: state.userEmail,
|
|
717
759
|
onLogout: state.logout
|
|
718
|
-
})
|
|
760
|
+
}),
|
|
761
|
+
actionsEnd
|
|
719
762
|
]
|
|
720
763
|
})
|
|
721
764
|
]
|
|
722
|
-
}), showProjectUi && state.showOverlay && /* @__PURE__ */ jsx(ProjectOverlay, {
|
|
723
|
-
organizationName: state.organizationName,
|
|
724
|
-
projectsTree: state.projectsTree,
|
|
725
|
-
selectedProjectId: state.selectedProjectId,
|
|
726
|
-
onSelect: state.selectProject,
|
|
727
|
-
isLoading: state.isProjectsLoading,
|
|
728
|
-
onClose: onCloseProjectOverlay
|
|
729
|
-
})] });
|
|
730
|
-
}
|
|
731
|
-
function ProjectOverlay({ organizationName, projectsTree, selectedProjectId, onSelect, isLoading, onClose }) {
|
|
732
|
-
return /* @__PURE__ */ jsx("div", {
|
|
733
|
-
role: "dialog",
|
|
734
|
-
"aria-modal": "true",
|
|
735
|
-
"aria-label": DEFAULT_LABELS.overlayTitle,
|
|
736
|
-
className: "fixed inset-0 z-50 flex items-center justify-center bg-primary-bg/80 backdrop-blur-sm",
|
|
737
|
-
children: /* @__PURE__ */ jsxs("div", {
|
|
738
|
-
className: "relative mx-1 flex w-full max-w-md flex-col items-center gap-6 rounded-16 border bg-glass-none-bg p-2 text-primary-txt shadow-xl",
|
|
739
|
-
children: [
|
|
740
|
-
/* @__PURE__ */ jsx(Button, {
|
|
741
|
-
variant: "ghost",
|
|
742
|
-
size: "icon",
|
|
743
|
-
onClick: onClose ?? (() => window.history.back()),
|
|
744
|
-
className: "absolute top-4 right-4",
|
|
745
|
-
"aria-label": "Close",
|
|
746
|
-
children: /* @__PURE__ */ jsx(X, { className: "size-5" })
|
|
747
|
-
}),
|
|
748
|
-
/* @__PURE__ */ jsxs("div", {
|
|
749
|
-
className: "flex flex-col items-center gap-3 text-center",
|
|
750
|
-
children: [
|
|
751
|
-
/* @__PURE__ */ jsx("div", {
|
|
752
|
-
className: "rounded-full bg-primary/10 p-4",
|
|
753
|
-
children: /* @__PURE__ */ jsx(FolderOpen, { className: "size-8 text-primary" })
|
|
754
|
-
}),
|
|
755
|
-
/* @__PURE__ */ jsx("h2", {
|
|
756
|
-
className: "font-semibold text-primary-txt text-xl",
|
|
757
|
-
children: DEFAULT_LABELS.overlayTitle
|
|
758
|
-
}),
|
|
759
|
-
/* @__PURE__ */ jsx("p", {
|
|
760
|
-
className: "text-muted-txt text-sm",
|
|
761
|
-
children: DEFAULT_LABELS.overlayDescription
|
|
762
|
-
})
|
|
763
|
-
]
|
|
764
|
-
}),
|
|
765
|
-
/* @__PURE__ */ jsxs("div", {
|
|
766
|
-
className: "flex w-full justify-center gap-2",
|
|
767
|
-
children: [organizationName && /* @__PURE__ */ jsxs("div", {
|
|
768
|
-
className: cn(PILL, "select-none"),
|
|
769
|
-
title: organizationName,
|
|
770
|
-
children: [/* @__PURE__ */ jsxs("span", {
|
|
771
|
-
className: "shrink-0 text-muted-txt",
|
|
772
|
-
children: [DEFAULT_LABELS.orgLabel, ":"]
|
|
773
|
-
}), /* @__PURE__ */ jsx("span", {
|
|
774
|
-
className: "max-w-52 truncate font-medium",
|
|
775
|
-
children: organizationName
|
|
776
|
-
})]
|
|
777
|
-
}), /* @__PURE__ */ jsx(ProjectPicker, {
|
|
778
|
-
projectsTree,
|
|
779
|
-
selectedProjectId,
|
|
780
|
-
onSelect,
|
|
781
|
-
projectLabel: DEFAULT_LABELS.projectLabel,
|
|
782
|
-
projectPlaceholder: DEFAULT_LABELS.projectPlaceholder,
|
|
783
|
-
searchPlaceholder: DEFAULT_LABELS.searchPlaceholder,
|
|
784
|
-
emptyStateText: DEFAULT_LABELS.emptyStateText,
|
|
785
|
-
isLoading
|
|
786
|
-
})]
|
|
787
|
-
})
|
|
788
|
-
]
|
|
789
|
-
})
|
|
790
765
|
});
|
|
791
766
|
}
|
|
792
767
|
//#endregion
|
package/dist/Header.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Header.js","names":["PILL"],"sources":["../src/patterns/Header/project-tree.ts","../src/patterns/Header/ProjectPicker.tsx","../src/patterns/Header/labels.ts","../src/patterns/Header/api.ts","../src/patterns/Header/storage.ts","../src/patterns/Header/header-store.ts","../src/patterns/Header/session.ts","../src/patterns/Header/use-global-header.ts","../src/patterns/Header/Header.tsx"],"sourcesContent":["import type { ProjectNode } from \"./types\";\n\n/** True when a node with the given id exists anywhere in the tree. */\nexport function nodeExistsInTree(tree: ProjectNode[], id: string): boolean {\n return tree.some((node) => node.id === id || nodeExistsInTree(node.children, id));\n}\n\n/** Name of the node with the given id, or undefined. */\nexport function findProjectName(tree: ProjectNode[], id: string): string | undefined {\n for (const node of tree) {\n if (node.id === id) return node.name;\n const found = findProjectName(node.children, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Filter the tree to nodes matching `term`, preserving ancestors of matches. */\nexport function filterTree(nodes: ProjectNode[], term: string): ProjectNode[] {\n if (!term) return nodes;\n const lower = term.toLowerCase();\n return nodes.flatMap((node) => {\n if (node.name.toLowerCase().includes(lower)) return [node];\n const children = filterTree(node.children, term);\n return children.length > 0 ? [{ ...node, children }] : [];\n });\n}\n","\"use client\";\n\nimport { Check, ChevronDown, ChevronRight, Search } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Input } from \"@/primitives/Input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/primitives/Popover\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { cn } from \"@/utils\";\nimport { filterTree, findProjectName } from \"./project-tree\";\nimport type { ProjectNode } from \"./types\";\n\ninterface ProjectPickerProps {\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName?: string;\n onSelect: (id: string) => void;\n projectLabel: string;\n projectPlaceholder: string;\n searchPlaceholder: string;\n emptyStateText: string;\n isLoading?: boolean;\n}\n\n// Pill shared by the trigger and the org pill — keeps the header lockup consistent.\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\nexport function ProjectPicker({\n projectsTree,\n selectedProjectId,\n selectedProjectName,\n onSelect,\n projectLabel,\n projectPlaceholder,\n searchPlaceholder,\n emptyStateText,\n isLoading = false,\n}: Readonly<ProjectPickerProps>) {\n const [open, setOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const [collapsedIds, setCollapsedIds] = React.useState<Set<string>>(new Set());\n\n const toggleCollapse = (id: string) =>\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const handleSelect = (id: string) => {\n onSelect(id);\n setOpen(false);\n };\n\n const selectedName = selectedProjectId\n ? (findProjectName(projectsTree, selectedProjectId) ?? selectedProjectName)\n : undefined;\n\n const filteredTree = filterTree(projectsTree, searchTerm);\n\n if (isLoading) {\n return (\n <div data-slot=\"header-project-picker\" className={cn(PILL, \"min-w-44\")}>\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <Skeleton className=\"h-3 flex-1\" />\n <ChevronDown className=\"size-4 shrink-0 text-muted-txt opacity-40\" />\n </div>\n );\n }\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearchTerm(\"\");\n }}\n >\n <PopoverTrigger\n data-slot=\"header-project-picker\"\n className={cn(PILL, \"text-left transition-colors hover:border-focus/60\")}\n >\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <span className={cn(\"max-w-36 truncate\", selectedName ? \"font-medium\" : \"text-muted-txt\")}>\n {selectedName ?? projectPlaceholder}\n </span>\n <ChevronDown className=\"ml-1 size-4 shrink-0 text-muted-txt\" />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-0\" role=\"tree\" aria-label={projectLabel}>\n <div className=\"border-b p-2\">\n <div className=\"relative\">\n <Search className=\"absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt\" />\n <Input\n size=\"sm\"\n className=\"pl-8\"\n placeholder={searchPlaceholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n />\n </div>\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\">\n {filteredTree.length === 0 ? (\n <p className=\"px-1 py-0.5 text-sm text-muted-txt\">{emptyStateText}</p>\n ) : (\n filteredTree.map((node) => (\n <TreeNode\n key={node.id}\n node={node}\n depth={0}\n selectedId={selectedProjectId}\n onSelect={handleSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={toggleCollapse}\n />\n ))\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\ninterface TreeNodeProps {\n node: ProjectNode;\n depth: number;\n selectedId: string;\n onSelect: (id: string) => void;\n collapsedIds: Set<string>;\n onToggleCollapse: (id: string) => void;\n}\n\nfunction TreeNode({\n node,\n depth,\n selectedId,\n onSelect,\n collapsedIds,\n onToggleCollapse,\n}: Readonly<TreeNodeProps>) {\n const isSelected = !node.isContextOnly && selectedId === node.id;\n const isCollapsed = collapsedIds.has(node.id);\n const hasChildren = node.children.length > 0;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={node.isContextOnly ? undefined : isSelected}\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n >\n <div\n style={{ paddingLeft: `${0.75 + depth}rem` }}\n className={cn(\n \"flex items-center gap-1 py-2 pr-3 text-sm transition-colors\",\n node.isContextOnly\n ? \"cursor-default text-muted-txt\"\n : \"cursor-pointer hover:bg-ghost-hover-bg\",\n isSelected && \"bg-secondary-bg font-medium\",\n )}\n >\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`}\n onClick={() => onToggleCollapse(node.id)}\n className=\"shrink-0 text-muted-txt hover:text-primary-txt\"\n >\n {isCollapsed ? (\n <ChevronRight className=\"size-3.5\" />\n ) : (\n <ChevronDown className=\"size-3.5\" />\n )}\n </button>\n ) : (\n <span className=\"inline-block w-3.5 shrink-0\" />\n )}\n\n {node.isContextOnly ? (\n <span className=\"flex-1 text-left\">{node.name}</span>\n ) : (\n <button type=\"button\" onClick={() => onSelect(node.id)} className=\"flex-1 text-left\">\n {node.name}\n </button>\n )}\n\n {isSelected && <Check className=\"ml-auto size-3.5 shrink-0 text-primary\" />}\n </div>\n {!isCollapsed && hasChildren && (\n <div role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.id}\n node={child}\n depth={depth + 1}\n selectedId={selectedId}\n onSelect={onSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={onToggleCollapse}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/** Default UI strings. Spread-override via the Header `labels` prop if needed. */\nexport const DEFAULT_LABELS = {\n orgLabel: \"Org\",\n projectLabel: \"Project\",\n projectPlaceholder: \"Select project...\",\n searchPlaceholder: \"Search project\",\n emptyStateText: \"No projects found\",\n profileMenuLabel: \"Profile menu\",\n logoutLabel: \"Logout\",\n overlayTitle: \"Select a Project\",\n overlayDescription: \"Choose a project to get started. You can change it anytime from the header.\",\n} as const;\n\nexport type Labels = typeof DEFAULT_LABELS;\n","import type { Fetcher, HeaderEndpoints, HeaderProps, ProjectNode } from \"./types\";\n\n// Studio-auth API. Endpoints are built from the host-provided `apiBaseUrl` (full\n// domain) so the same header works across environments/subdomains. All requests\n// send cookies (`credentials: 'include'`); the parent-domain session cookie is\n// readable cross-subdomain.\n\nconst PATHS = {\n token: \"/api/v1/studio-auth/sessions/token\",\n logout: \"/api/v1/studio-auth/sessions/logout\",\n projects: (clientId: string) => `/api/v1/onboarding/organization/${clientId}/projects`,\n credits: \"/save/api/v1/users\",\n};\n\n/** Join a base URL and path without doubling slashes. */\nfunction join(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/$/, \"\")}${path}`;\n}\n\nexport function buildEndpoints(\n apiBaseUrl: string,\n overrides?: HeaderProps[\"endpoints\"],\n): HeaderEndpoints {\n return {\n token: overrides?.token ?? join(apiBaseUrl, PATHS.token),\n logout: overrides?.logout ?? join(apiBaseUrl, PATHS.logout),\n projects:\n overrides?.projects ?? ((clientId: string) => join(apiBaseUrl, PATHS.projects(clientId))),\n credits: overrides?.credits ?? join(apiBaseUrl, PATHS.credits),\n };\n}\n\ntype ApiEnvelope<T> = { response?: { data?: T } };\n\nexport async function fetchToken(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<string> {\n const res = await fetcher(endpoints.token, { credentials: \"include\" });\n if (!res.ok) throw new Error(`token request failed: ${res.status}`);\n const { accessToken } = (await res.json()) as { accessToken: string };\n return accessToken;\n}\n\nexport async function fetchProjects(\n endpoints: HeaderEndpoints,\n clientId: string,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<{ projectsTree: ProjectNode[]; organizationName: string | undefined }> {\n const res = await fetcher(endpoints.projects(clientId), {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`projects request failed: ${res.status}`);\n const data = (await res.json()) as ApiEnvelope<{\n projectsTree?: ProjectNode[];\n organization?: { name?: string };\n }>;\n return {\n projectsTree: data.response?.data?.projectsTree ?? [],\n organizationName: data.response?.data?.organization?.name,\n };\n}\n\nexport async function fetchCredits(\n endpoints: HeaderEndpoints,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<number | undefined> {\n const res = await fetcher(endpoints.credits, {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`credits request failed: ${res.status}`);\n const data = (await res.json()) as { remainingCredits?: number };\n return data.remainingCredits;\n}\n\nexport async function callLogout(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<void> {\n try {\n await fetcher(endpoints.logout, { method: \"POST\", credentials: \"include\" });\n } finally {\n if (typeof window !== \"undefined\") window.location.href = \"/\";\n }\n}\n","// Persists the user's project selection across reloads (sessionStorage), tagged\n// with the client it belongs to so a stale selection from a different org is\n// discarded on re-login.\n\nconst PROJECT_KEY = \"ds-header-project\";\n\nexport interface StoredProject {\n id: string;\n name: string;\n clientId?: string;\n}\n\nexport function getStoredProject(): StoredProject | null {\n try {\n const raw = sessionStorage.getItem(PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setStoredProject(project: StoredProject): void {\n try {\n sessionStorage.setItem(PROJECT_KEY, JSON.stringify(project));\n } catch {\n // sessionStorage unavailable — degrade silently\n }\n}\n\nexport function clearStoredProject(): void {\n try {\n sessionStorage.removeItem(PROJECT_KEY);\n } catch {\n // noop\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport { clearStoredProject, getStoredProject, setStoredProject } from \"./storage\";\n\n// Module-level store for the current project/org selection. Module scope (not\n// React context) so a host app can read and change the selection from anywhere —\n// including components rendered outside the <Header> subtree. The Header is one\n// writer/reader; `useHeaderProject()` gives apps the same access.\n\nexport interface HeaderSelection {\n selectedProjectId: string;\n selectedProjectName: string;\n organizationName: string | undefined;\n /** Remaining credits for the logged-in user (read-only here; set by the Header). */\n credits: number | undefined;\n /** Client/org the current selection + org belong to (for cross-org invalidation). */\n clientId: string | undefined;\n}\n\nfunction initialState(): HeaderSelection {\n const stored = typeof window !== \"undefined\" ? getStoredProject() : null;\n return {\n selectedProjectId: stored?.id ?? \"\",\n selectedProjectName: stored?.name ?? \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: stored?.clientId,\n };\n}\n\nlet state: HeaderSelection = initialState();\n// Stable reference for SSR / first server render.\nconst SERVER_SNAPSHOT: HeaderSelection = Object.freeze({\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: undefined,\n});\n\nconst listeners = new Set<() => void>();\nfunction emit() {\n for (const listener of listeners) listener();\n}\n\nexport const headerStore = {\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getSnapshot(): HeaderSelection {\n return state;\n },\n getServerSnapshot(): HeaderSelection {\n return SERVER_SNAPSHOT;\n },\n\n /** Set the selected project. `name` is best-effort; the Header backfills it from the tree. */\n setProject(id: string, name = \"\", clientId?: string) {\n if (id) setStoredProject({ id, name, clientId: clientId ?? state.clientId });\n else clearStoredProject();\n state = {\n ...state,\n selectedProjectId: id,\n selectedProjectName: name,\n clientId: clientId ?? state.clientId,\n };\n emit();\n },\n\n clearProject() {\n clearStoredProject();\n state = { ...state, selectedProjectId: \"\", selectedProjectName: \"\" };\n emit();\n },\n\n setOrganization(name: string | undefined, clientId?: string) {\n state = { ...state, organizationName: name, clientId: clientId ?? state.clientId };\n emit();\n },\n\n setCredits(credits: number | undefined) {\n if (state.credits === credits) return;\n state = { ...state, credits };\n emit();\n },\n\n /** When the active client changes, drop a selection/org from the previous one. */\n reconcileClient(clientId: string) {\n if (state.clientId === clientId) return;\n if (state.clientId && state.clientId !== clientId) {\n clearStoredProject();\n state = {\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: state.credits, // user-level — survives org switches\n clientId,\n };\n } else {\n state = { ...state, clientId };\n }\n emit();\n },\n};\n\n/** Internal: subscribe a component to the selection store. */\nexport function useHeaderStore(): HeaderSelection {\n return React.useSyncExternalStore(\n headerStore.subscribe,\n headerStore.getSnapshot,\n headerStore.getServerSnapshot,\n );\n}\n\nexport interface UseHeaderProjectResult {\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n organizationName: string | undefined;\n /** Set the active project from outside the Header (by id). */\n setProject: (id: string) => void;\n /** Clear the active project (e.g. to re-prompt selection). */\n clearProject: () => void;\n}\n\n/**\n * Read the current project/org and change the project from anywhere in the app —\n * no need to be inside the <Header>. Reflects user selections made in the header\n * and updates the header when changed here.\n */\nexport function useHeaderProject(): UseHeaderProjectResult {\n const snapshot = useHeaderStore();\n return {\n selectedProjectId: snapshot.selectedProjectId,\n selectedProjectName: snapshot.selectedProjectName || undefined,\n organizationName: snapshot.organizationName,\n setProject: React.useCallback((id: string) => headerStore.setProject(id), []),\n clearProject: React.useCallback(() => headerStore.clearProject(), []),\n };\n}\n\n/** Read the logged-in user's remaining credits (read-only; the Header owns it). */\nexport function useHeaderCredits(): number | undefined {\n return useHeaderStore().credits;\n}\n","// Client-side session detection. The auth system writes a JS-readable cookie\n// `{environmentId}-sessionId` (a JWT) on the shared parent domain. We decode it\n// and check its expiry to know whether the user is logged in — no network call.\n\ninterface JwtPayload {\n exp?: number;\n [key: string]: unknown;\n}\n\n/** Read the raw session JWT from the `{environmentId}-sessionId` cookie. */\nexport function getSessionToken(environmentId: string): string | null {\n if (typeof document === \"undefined\") return null;\n const name = `${environmentId}-sessionId`;\n for (const part of document.cookie.split(\";\")) {\n const [key, ...rest] = part.trim().split(\"=\");\n if (key === name) return decodeURIComponent(rest.join(\"=\"));\n }\n return null;\n}\n\n/** Decode a JWT payload without verifying the signature (display/expiry only). */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return null;\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = atob(base64);\n return JSON.parse(json) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/** User/session claims carried in the session JWT (the subset the header uses). */\nexport interface SessionClaims {\n email?: string;\n name?: string;\n userId?: string;\n /** Active organisation id (`client_id` claim). */\n clientId?: string;\n exp?: number;\n}\n\n/**\n * Decode the user claims from the session cookie's JWT — no network call.\n * Returns null when the cookie is absent or undecodable.\n */\nexport function getSessionClaims(environmentId: string): SessionClaims | null {\n const token = getSessionToken(environmentId);\n if (!token) return null;\n const payload = decodeJwt(token);\n if (!payload) return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : undefined);\n return {\n email: str(payload.email),\n name: str(payload.name),\n userId: str(payload.user_id),\n clientId: str(payload.client_id),\n exp: typeof payload.exp === \"number\" ? payload.exp : undefined,\n };\n}\n\n/** True when a valid, unexpired session cookie exists for the environment. */\nexport function isSessionValid(environmentId: string): boolean {\n const token = getSessionToken(environmentId);\n if (!token) return false;\n const payload = decodeJwt(token);\n if (!payload) return false;\n // No exp claim → treat as a non-expiring session.\n if (typeof payload.exp !== \"number\") return true;\n return payload.exp * 1000 > Date.now();\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\n\nimport { buildEndpoints, callLogout, fetchCredits, fetchProjects, fetchToken } from \"./api\";\nimport { headerStore, useHeaderStore } from \"./header-store\";\nimport { findProjectName, nodeExistsInTree } from \"./project-tree\";\nimport { getSessionClaims, isSessionValid } from \"./session\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\n\n/** Window event other modules can dispatch to show/hide the project dropdown. */\nexport const TOGGLE_PROJECT_DROPDOWN_EVENT = \"toggle-project-dropdown\";\nexport interface ToggleProjectDropdownDetail {\n show: boolean;\n}\n\nconst DEFAULT_STALE_TIME = 5 * 60_000;\nconst DEFAULT_GC_TIME = 10 * 60_000;\n\nexport interface GlobalHeaderState {\n /** Whether a valid session cookie exists — when false, hide all user content. */\n isAuthenticated: boolean;\n userEmail: string | undefined;\n organizationName: string | undefined;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n isProjectsLoading: boolean;\n isOrgLoading: boolean;\n /** Remaining credits for the user (undefined until loaded / when disabled). */\n credits: number | undefined;\n /** Where the credits pill links to (studio-auth `/user/activity`). */\n creditsHref: string;\n projectDropdownVisible: boolean;\n /** True when the dropdown is on, the user is in, but no project is chosen yet. */\n showOverlay: boolean;\n selectProject: (id: string) => void;\n logout: () => void;\n}\n\ntype UseGlobalHeaderArgs = Pick<\n HeaderProps,\n | \"apiBaseUrl\"\n | \"environmentId\"\n | \"clientId\"\n | \"_dangerouslyInjectAccessToken\"\n | \"showProjectDropdown\"\n | \"showProfile\"\n | \"showOrg\"\n | \"showCredits\"\n | \"endpoints\"\n | \"fetcher\"\n | \"staleTime\"\n | \"gcTime\"\n | \"onProjectChange\"\n>;\n\nexport function useGlobalHeader({\n apiBaseUrl,\n environmentId,\n clientId,\n _dangerouslyInjectAccessToken: injectedToken,\n showProjectDropdown = false,\n showProfile = false,\n showOrg = false,\n showCredits = false,\n endpoints: endpointOverrides,\n fetcher: fetcherProp,\n staleTime = DEFAULT_STALE_TIME,\n gcTime = DEFAULT_GC_TIME,\n onProjectChange,\n}: UseGlobalHeaderArgs): GlobalHeaderState {\n const fetcher = React.useMemo(\n () => fetcherProp ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init)),\n [fetcherProp],\n );\n const endpoints = React.useMemo(\n () => buildEndpoints(apiBaseUrl, endpointOverrides),\n [apiBaseUrl, endpointOverrides],\n );\n\n // Read the session cookie each render (cheap); gates every network call.\n // User identity (email, client id) comes from the JWT claims — no /me call.\n const isAuthenticated = isSessionValid(environmentId);\n const claims = getSessionClaims(environmentId);\n\n // token → projects, enabled only when the previous resolved.\n const tokenQuery = useQuery({\n queryKey: [\"ds-header\", \"token\", endpoints.token],\n queryFn: () => fetchToken(endpoints, fetcher),\n enabled: isAuthenticated && !injectedToken,\n staleTime,\n gcTime,\n });\n const token = injectedToken ?? tokenQuery.data;\n\n const effectiveClientId = clientId ?? claims?.clientId;\n const wantsProjects = showProjectDropdown || showOrg;\n const projectsQuery = useQuery({\n queryKey: [\"ds-header\", \"projects\", effectiveClientId, token],\n queryFn: () => fetchProjects(endpoints, effectiveClientId as string, token as string, fetcher),\n enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,\n staleTime,\n gcTime,\n });\n\n // Credits — only needs the token. Always refetched on mount (staleTime 0) so a\n // page refresh shows the current balance.\n const creditsQuery = useQuery({\n queryKey: [\"ds-header\", \"credits\", endpoints.credits, token],\n queryFn: () => fetchCredits(endpoints, token as string, fetcher),\n enabled: isAuthenticated && !!token && showCredits,\n staleTime: 0,\n gcTime,\n });\n\n const projectsTree = projectsQuery.data?.projectsTree ?? [];\n const userEmail = showProfile ? claims?.email : undefined;\n const creditsHref = React.useMemo(() => {\n try {\n return new URL(\"/user/activity\", apiBaseUrl).toString();\n } catch {\n return \"/user/activity\";\n }\n }, [apiBaseUrl]);\n\n // Selection + org live in a module store so host apps can read/change them\n // from outside the header (see useHeaderProject).\n const selection = useHeaderStore();\n\n // Once the client id resolves, drop a selection/org from a different client.\n React.useEffect(() => {\n if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);\n }, [effectiveClientId]);\n\n // Once projects load: publish the org name and validate/backfill the selection\n // (drop one that no longer exists; fill in its name from the tree).\n React.useEffect(() => {\n if (!projectsQuery.data) return;\n const tree = projectsQuery.data.projectsTree;\n const id = headerStore.getSnapshot().selectedProjectId;\n if (id && !nodeExistsInTree(tree, id)) {\n headerStore.clearProject();\n } else if (id) {\n const name = findProjectName(tree, id);\n if (name && name !== headerStore.getSnapshot().selectedProjectName) {\n headerStore.setProject(id, name, effectiveClientId);\n }\n }\n headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);\n }, [projectsQuery.data, effectiveClientId]);\n\n // Publish credits to the store so host apps can read them via useHeaderCredits.\n React.useEffect(() => {\n if (creditsQuery.data !== undefined) headerStore.setCredits(creditsQuery.data);\n }, [creditsQuery.data]);\n\n const selectProject = (id: string) => {\n const name = findProjectName(projectsTree, id) ?? \"\";\n headerStore.setProject(id, name, effectiveClientId);\n onProjectChange?.(id);\n };\n\n const logout = () => {\n headerStore.clearProject();\n void callLogout(endpoints, fetcher);\n };\n\n // Visibility: declarative from the prop, overridable at runtime via the event.\n const [projectDropdownVisible, setProjectDropdownVisible] = React.useState(showProjectDropdown);\n React.useEffect(() => setProjectDropdownVisible(showProjectDropdown), [showProjectDropdown]);\n React.useEffect(() => {\n const handler = (e: Event) => {\n setProjectDropdownVisible((e as CustomEvent<ToggleProjectDropdownDetail>).detail.show);\n };\n window.addEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n return () => window.removeEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n }, []);\n\n const isProjectsLoading = projectsQuery.isFetching && !projectsQuery.data;\n\n return {\n isAuthenticated,\n userEmail,\n organizationName: selection.organizationName,\n projectsTree,\n selectedProjectId: selection.selectedProjectId,\n selectedProjectName: selection.selectedProjectName || undefined,\n isProjectsLoading,\n isOrgLoading: showOrg && isProjectsLoading,\n credits: selection.credits,\n creditsHref,\n projectDropdownVisible,\n showOverlay: isAuthenticated && projectDropdownVisible && !selection.selectedProjectId,\n selectProject,\n logout,\n };\n}\n","\"use client\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { FolderOpen, LogOut, MessageSquareShare, Moon, Sun, X } from \"lucide-react\";\nimport type * as React from \"react\";\n\nimport { Avatar, AvatarFallback } from \"@/primitives/Avatar\";\nimport { Button } from \"@/primitives/Button\";\nimport { Credits } from \"@/primitives/Credits\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/primitives/DropdownMenu\";\nimport { Logo } from \"@/primitives/Logo\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { type ThemeProduct, useTheme } from \"@/primitives/ThemeProvider\";\nimport { cn } from \"@/utils\";\nimport { ProjectPicker } from \"./ProjectPicker\";\nimport { DEFAULT_LABELS } from \"./labels\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\nimport { useGlobalHeader } from \"./use-global-header\";\n\n// Fallback logo destinations when the host doesn't pass `logoHref`.\nconst LOGO_HREF: Record<ThemeProduct, string> = {\n psai: \"https://sapientaiproducts.com/\",\n slingshot: \"https://sapientaiproducts.com/slingshot\",\n sustain: \"https://www.publicissapient.com/\",\n bodhi: \"https://sapientaiproducts.com/bodhi\",\n};\n\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\n// ── Presentational parts (props-driven; Storybook/VR-able) ──────────────────\n\n/** The header bar shell — a sticky glass strip. */\nfunction HeaderBar({ className, ...props }: React.ComponentProps<\"header\">) {\n return (\n <header\n data-slot=\"header\"\n className={cn(\n \"sticky top-1 z-10 mt-1 flex h-15 items-center gap-5 rounded-16 px-3 py-2\",\n \"bg-glass-60-bg backdrop-blur-glass\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Product logo linking to its home, with a Suspense-safe fallback. */\nfunction HeaderLogo({ brand, href }: { brand: ThemeProduct; href?: string }) {\n return (\n <a href={href ?? LOGO_HREF[brand]} aria-label=\"Go to product home\" data-slot=\"header-logo\">\n <Logo brand={brand} className=\"h-8 w-auto\" />\n </a>\n );\n}\n\n/** Read-only organisation pill. */\nfunction OrgPill({ name, loading }: { name?: string; loading?: boolean }) {\n if (loading && !name) {\n return (\n <div className={cn(PILL, \"ml-3\")} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <Skeleton className=\"h-4 w-24\" />\n </div>\n );\n }\n if (!name) return null;\n return (\n <div className={cn(PILL, \"ml-3 select-none\")} title={name} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-36 truncate text-primary-txt\">{name}</span>\n </div>\n );\n}\n\n/** Light/dark toggle — defers to ThemeProvider. */\nfunction ThemeToggle() {\n const { theme, toggleTheme } = useTheme();\n return (\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleTheme} aria-label=\"Toggle theme\">\n {theme === \"light\" ? <Moon className=\"size-4\" /> : <Sun className=\"size-4\" />}\n </Button>\n );\n}\n\n/** Profile menu — avatar trigger with email + logout. */\nfunction ProfileMenu({ email, onLogout }: { email?: string; onLogout: () => void }) {\n const initial = email?.trim().charAt(0).toUpperCase() || \"?\";\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={DEFAULT_LABELS.profileMenuLabel}>\n <Avatar className=\"size-7\">\n <AvatarFallback>{initial}</AvatarFallback>\n </Avatar>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-44\">\n {email && (\n <>\n <DropdownMenuLabel className=\"truncate font-normal text-muted-txt\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={onLogout} variant=\"destructive\">\n <LogOut />\n {DEFAULT_LABELS.logoutLabel}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { HeaderBar, HeaderLogo, OrgPill, ThemeToggle, ProfileMenu };\n\n// ── Wired Header ─────────────────────────────────────────────────────────────\n\n// Internal singleton client so the header is drop-in (no app setup) while still\n// sharing its cache across mounts/navigation.\nlet sharedClient: QueryClient | undefined;\nfunction getQueryClient(): QueryClient {\n sharedClient ??= new QueryClient({\n defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } },\n });\n return sharedClient;\n}\n\n/** Drop-in global header. Must be rendered inside a <ThemeProvider>. */\nexport function Header(props: HeaderProps) {\n return (\n <QueryClientProvider client={getQueryClient()}>\n <HeaderInner {...props} />\n </QueryClientProvider>\n );\n}\n\nfunction HeaderInner({\n logoType,\n logoHref,\n showOrg = false,\n showProjectDropdown = false,\n showProfile = false,\n showThemeSwitcher = false,\n showCredits = false,\n pageTitle,\n feedbackUrl,\n logoAddon,\n className,\n onCloseProjectOverlay,\n ...rest\n}: HeaderProps) {\n const { product } = useTheme();\n const brand = logoType ?? product;\n const state = useGlobalHeader({\n showOrg,\n showProjectDropdown,\n showProfile,\n showCredits,\n ...rest,\n });\n\n // Logged-out users see no user content (project/org/profile/credits).\n const showProjectUi = showProjectDropdown && state.isAuthenticated;\n const showOrgUi = showOrg && state.isAuthenticated;\n const showProfileUi = showProfile && state.isAuthenticated;\n const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== undefined;\n const showActions = showThemeSwitcher || showProfileUi || showCreditsUi || !!feedbackUrl;\n\n return (\n <>\n <HeaderBar className={className}>\n <HeaderLogo brand={brand} href={logoHref} />\n {/* Page title — 20px (gap-5) from the logo. */}\n {pageTitle && (\n <span data-slot=\"header-title\" className=\"ml-5 font-semibold text-primary-txt text-sm\">\n {pageTitle}\n </span>\n )}\n {logoAddon}\n\n {showOrgUi && <OrgPill name={state.organizationName} loading={state.isOrgLoading} />}\n\n {showProjectUi && state.projectDropdownVisible && (\n <div className=\"ml-2\">\n <ProjectPicker\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n selectedProjectName={state.selectedProjectName}\n onSelect={state.selectProject}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={state.isProjectsLoading}\n />\n </div>\n )}\n\n {showActions && (\n <div className=\"ml-auto flex items-center gap-2\">\n {feedbackUrl && (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a\n href={feedbackUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Share feedback\"\n >\n <MessageSquareShare className=\"size-4\" />\n </a>\n </Button>\n )}\n {showThemeSwitcher && <ThemeToggle />}\n {showCreditsUi && state.credits !== undefined && (\n <a\n href={state.creditsHref}\n aria-label=\"View credit activity\"\n className=\"rounded-full outline-none focus-visible:ring-3 focus-visible:ring-focus\"\n >\n <Credits value={state.credits} />\n </a>\n )}\n {showProfileUi && <ProfileMenu email={state.userEmail} onLogout={state.logout} />}\n </div>\n )}\n </HeaderBar>\n\n {showProjectUi && state.showOverlay && (\n <ProjectOverlay\n organizationName={state.organizationName}\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n onSelect={state.selectProject}\n isLoading={state.isProjectsLoading}\n onClose={onCloseProjectOverlay}\n />\n )}\n </>\n );\n}\n\n// First-run blocking overlay prompting a project selection.\nfunction ProjectOverlay({\n organizationName,\n projectsTree,\n selectedProjectId,\n onSelect,\n isLoading,\n onClose,\n}: {\n organizationName?: string;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n onSelect: (id: string) => void;\n isLoading: boolean;\n onClose?: () => void;\n}) {\n return (\n <div\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label={DEFAULT_LABELS.overlayTitle}\n className=\"fixed inset-0 z-50 flex items-center justify-center bg-primary-bg/80 backdrop-blur-sm\"\n >\n <div className=\"relative mx-1 flex w-full max-w-md flex-col items-center gap-6 rounded-16 border bg-glass-none-bg p-2 text-primary-txt shadow-xl\">\n <Button\n variant=\"ghost\"\n size=\"icon\"\n onClick={onClose ?? (() => window.history.back())}\n className=\"absolute top-4 right-4\"\n aria-label=\"Close\"\n >\n <X className=\"size-5\" />\n </Button>\n <div className=\"flex flex-col items-center gap-3 text-center\">\n <div className=\"rounded-full bg-primary/10 p-4\">\n <FolderOpen className=\"size-8 text-primary\" />\n </div>\n <h2 className=\"font-semibold text-primary-txt text-xl\">{DEFAULT_LABELS.overlayTitle}</h2>\n <p className=\"text-muted-txt text-sm\">{DEFAULT_LABELS.overlayDescription}</p>\n </div>\n <div className=\"flex w-full justify-center gap-2\">\n {organizationName && (\n <div className={cn(PILL, \"select-none\")} title={organizationName}>\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-52 truncate font-medium\">{organizationName}</span>\n </div>\n )}\n <ProjectPicker\n projectsTree={projectsTree}\n selectedProjectId={selectedProjectId}\n onSelect={onSelect}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={isLoading}\n />\n </div>\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Header.js","names":["PILL"],"sources":["../src/patterns/Header/project-tree.ts","../src/patterns/Header/ProjectPicker.tsx","../src/patterns/Header/labels.ts","../src/patterns/Header/api.ts","../src/patterns/Header/storage.ts","../src/patterns/Header/header-store.ts","../src/patterns/Header/session.ts","../src/patterns/Header/use-global-header.ts","../src/patterns/Header/Header.tsx"],"sourcesContent":["import type { ProjectNode } from \"./types\";\n\n/** True when a node with the given id exists anywhere in the tree. */\nexport function nodeExistsInTree(tree: ProjectNode[], id: string): boolean {\n return tree.some((node) => node.id === id || nodeExistsInTree(node.children, id));\n}\n\n/** Name of the node with the given id, or undefined. */\nexport function findProjectName(tree: ProjectNode[], id: string): string | undefined {\n for (const node of tree) {\n if (node.id === id) return node.name;\n const found = findProjectName(node.children, id);\n if (found) return found;\n }\n return undefined;\n}\n\n/** First selectable node in the tree (depth-first, skipping context-only ancestors). */\nexport function firstSelectableProject(tree: ProjectNode[]): ProjectNode | undefined {\n for (const node of tree) {\n if (!node.isContextOnly) return node;\n const found = firstSelectableProject(node.children);\n if (found) return found;\n }\n return undefined;\n}\n\n/** Filter the tree to nodes matching `term`, preserving ancestors of matches. */\nexport function filterTree(nodes: ProjectNode[], term: string): ProjectNode[] {\n if (!term) return nodes;\n const lower = term.toLowerCase();\n return nodes.flatMap((node) => {\n if (node.name.toLowerCase().includes(lower)) return [node];\n const children = filterTree(node.children, term);\n return children.length > 0 ? [{ ...node, children }] : [];\n });\n}\n","\"use client\";\n\nimport { Check, ChevronDown, ChevronRight, Search } from \"lucide-react\";\nimport * as React from \"react\";\n\nimport { Input } from \"@/primitives/Input\";\nimport { Popover, PopoverContent, PopoverTrigger } from \"@/primitives/Popover\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { cn } from \"@/utils\";\nimport { filterTree, findProjectName } from \"./project-tree\";\nimport type { ProjectNode } from \"./types\";\n\ninterface ProjectPickerProps {\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName?: string;\n onSelect: (id: string) => void;\n projectLabel: string;\n projectPlaceholder: string;\n searchPlaceholder: string;\n emptyStateText: string;\n isLoading?: boolean;\n}\n\n// Pill shared by the trigger and the org pill — keeps the header lockup consistent.\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\nexport function ProjectPicker({\n projectsTree,\n selectedProjectId,\n selectedProjectName,\n onSelect,\n projectLabel,\n projectPlaceholder,\n searchPlaceholder,\n emptyStateText,\n isLoading = false,\n}: Readonly<ProjectPickerProps>) {\n const [open, setOpen] = React.useState(false);\n const [searchTerm, setSearchTerm] = React.useState(\"\");\n const [collapsedIds, setCollapsedIds] = React.useState<Set<string>>(new Set());\n\n const toggleCollapse = (id: string) =>\n setCollapsedIds((prev) => {\n const next = new Set(prev);\n if (next.has(id)) next.delete(id);\n else next.add(id);\n return next;\n });\n\n const handleSelect = (id: string) => {\n onSelect(id);\n setOpen(false);\n };\n\n const selectedName = selectedProjectId\n ? (findProjectName(projectsTree, selectedProjectId) ?? selectedProjectName)\n : undefined;\n\n const filteredTree = filterTree(projectsTree, searchTerm);\n\n if (isLoading) {\n return (\n <div data-slot=\"header-project-picker\" className={cn(PILL, \"min-w-44\")}>\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <Skeleton className=\"h-3 flex-1\" />\n <ChevronDown className=\"size-4 shrink-0 text-muted-txt opacity-40\" />\n </div>\n );\n }\n\n return (\n <Popover\n open={open}\n onOpenChange={(next) => {\n setOpen(next);\n if (!next) setSearchTerm(\"\");\n }}\n >\n <PopoverTrigger\n data-slot=\"header-project-picker\"\n className={cn(PILL, \"text-left transition-colors hover:border-focus/60\")}\n >\n <span className=\"shrink-0 text-muted-txt\">{projectLabel}:</span>\n <span className={cn(\"max-w-36 truncate\", selectedName ? \"font-medium\" : \"text-muted-txt\")}>\n {selectedName ?? projectPlaceholder}\n </span>\n <ChevronDown className=\"ml-1 size-4 shrink-0 text-muted-txt\" />\n </PopoverTrigger>\n <PopoverContent align=\"start\" className=\"w-64 p-0\" role=\"tree\" aria-label={projectLabel}>\n <div className=\"border-b p-2\">\n <div className=\"relative\">\n <Search className=\"absolute top-1/2 left-2.5 size-3.5 -translate-y-1/2 text-muted-txt\" />\n <Input\n size=\"sm\"\n className=\"pl-8\"\n placeholder={searchPlaceholder}\n value={searchTerm}\n onChange={(e) => setSearchTerm(e.target.value)}\n />\n </div>\n </div>\n <div className=\"max-h-64 overflow-y-auto py-1\">\n {filteredTree.length === 0 ? (\n <p className=\"px-1 py-0.5 text-sm text-muted-txt\">{emptyStateText}</p>\n ) : (\n filteredTree.map((node) => (\n <TreeNode\n key={node.id}\n node={node}\n depth={0}\n selectedId={selectedProjectId}\n onSelect={handleSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={toggleCollapse}\n />\n ))\n )}\n </div>\n </PopoverContent>\n </Popover>\n );\n}\n\ninterface TreeNodeProps {\n node: ProjectNode;\n depth: number;\n selectedId: string;\n onSelect: (id: string) => void;\n collapsedIds: Set<string>;\n onToggleCollapse: (id: string) => void;\n}\n\nfunction TreeNode({\n node,\n depth,\n selectedId,\n onSelect,\n collapsedIds,\n onToggleCollapse,\n}: Readonly<TreeNodeProps>) {\n const isSelected = !node.isContextOnly && selectedId === node.id;\n const isCollapsed = collapsedIds.has(node.id);\n const hasChildren = node.children.length > 0;\n\n return (\n <div\n role=\"treeitem\"\n aria-selected={node.isContextOnly ? undefined : isSelected}\n aria-expanded={hasChildren ? !isCollapsed : undefined}\n >\n <div\n style={{ paddingLeft: `${0.75 + depth}rem` }}\n className={cn(\n \"flex items-center gap-1 py-2 pr-3 text-sm transition-colors\",\n node.isContextOnly\n ? \"cursor-default text-muted-txt\"\n : \"cursor-pointer hover:bg-ghost-hover-bg\",\n isSelected && \"bg-secondary-bg font-medium\",\n )}\n >\n {hasChildren ? (\n <button\n type=\"button\"\n aria-label={isCollapsed ? `Expand ${node.name}` : `Collapse ${node.name}`}\n onClick={() => onToggleCollapse(node.id)}\n className=\"shrink-0 text-muted-txt hover:text-primary-txt\"\n >\n {isCollapsed ? (\n <ChevronRight className=\"size-3.5\" />\n ) : (\n <ChevronDown className=\"size-3.5\" />\n )}\n </button>\n ) : (\n <span className=\"inline-block w-3.5 shrink-0\" />\n )}\n\n {node.isContextOnly ? (\n <span className=\"flex-1 text-left\">{node.name}</span>\n ) : (\n <button type=\"button\" onClick={() => onSelect(node.id)} className=\"flex-1 text-left\">\n {node.name}\n </button>\n )}\n\n {isSelected && <Check className=\"ml-auto size-3.5 shrink-0 text-primary\" />}\n </div>\n {!isCollapsed && hasChildren && (\n <div role=\"group\">\n {node.children.map((child) => (\n <TreeNode\n key={child.id}\n node={child}\n depth={depth + 1}\n selectedId={selectedId}\n onSelect={onSelect}\n collapsedIds={collapsedIds}\n onToggleCollapse={onToggleCollapse}\n />\n ))}\n </div>\n )}\n </div>\n );\n}\n","/** Default UI strings. Spread-override via the Header `labels` prop if needed. */\nexport const DEFAULT_LABELS = {\n orgLabel: \"Org\",\n projectLabel: \"Project\",\n projectPlaceholder: \"Select project...\",\n searchPlaceholder: \"Search project\",\n emptyStateText: \"No projects found\",\n profileMenuLabel: \"Profile menu\",\n logoutLabel: \"Logout\",\n} as const;\n\nexport type Labels = typeof DEFAULT_LABELS;\n","import type { Fetcher, HeaderEndpoints, HeaderProps, ProjectNode } from \"./types\";\n\n// Studio-auth API. Endpoints are built from the host-provided `apiBaseUrl` (full\n// domain) so the same header works across environments/subdomains. All requests\n// send cookies (`credentials: 'include'`); the parent-domain session cookie is\n// readable cross-subdomain.\n\nconst PATHS = {\n token: \"/api/v1/studio-auth/sessions/token\",\n logout: \"/api/v1/studio-auth/sessions/logout\",\n projects: (clientId: string) =>\n `/api/v1/client-projects/getAllProjects?limit=50&page=1&sort=name&sortOrder=ASC&clientId=${encodeURIComponent(clientId)}&metaData=true`,\n credits: \"/save/api/v1/users\",\n};\n\n/** Join a base URL and path without doubling slashes. */\nfunction join(baseUrl: string, path: string): string {\n return `${baseUrl.replace(/\\/$/, \"\")}${path}`;\n}\n\nexport function buildEndpoints(\n apiBaseUrl: string,\n overrides?: HeaderProps[\"endpoints\"],\n): HeaderEndpoints {\n return {\n token: overrides?.token ?? join(apiBaseUrl, PATHS.token),\n logout: overrides?.logout ?? join(apiBaseUrl, PATHS.logout),\n projects:\n overrides?.projects ?? ((clientId: string) => join(apiBaseUrl, PATHS.projects(clientId))),\n credits: overrides?.credits ?? join(apiBaseUrl, PATHS.credits),\n };\n}\n\ntype ApiEnvelope<T> = { response?: { data?: T } };\n\nexport async function fetchToken(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<string> {\n const res = await fetcher(endpoints.token, { credentials: \"include\" });\n if (!res.ok) throw new Error(`token request failed: ${res.status}`);\n const { accessToken } = (await res.json()) as { accessToken: string };\n return accessToken;\n}\n\nexport async function fetchProjects(\n endpoints: HeaderEndpoints,\n clientId: string,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<{ projectsTree: ProjectNode[]; organizationName: string | undefined }> {\n const res = await fetcher(endpoints.projects(clientId), {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`projects request failed: ${res.status}`);\n const data = (await res.json()) as ApiEnvelope<{\n projectsTree?: ProjectNode[];\n organization?: { name?: string };\n }>;\n return {\n projectsTree: data.response?.data?.projectsTree ?? [],\n organizationName: data.response?.data?.organization?.name,\n };\n}\n\nexport async function fetchCredits(\n endpoints: HeaderEndpoints,\n accessToken: string,\n fetcher: Fetcher,\n): Promise<number | undefined> {\n const res = await fetcher(endpoints.credits, {\n credentials: \"include\",\n headers: { Authorization: `Bearer ${accessToken}` },\n });\n if (!res.ok) throw new Error(`credits request failed: ${res.status}`);\n const data = (await res.json()) as { remainingCredits?: number };\n return data.remainingCredits;\n}\n\nexport async function callLogout(endpoints: HeaderEndpoints, fetcher: Fetcher): Promise<void> {\n try {\n await fetcher(endpoints.logout, { method: \"POST\", credentials: \"include\" });\n } finally {\n if (typeof window !== \"undefined\") window.location.href = \"/\";\n }\n}\n","// Persists the user's project selection across reloads (sessionStorage), tagged\n// with the client it belongs to so a stale selection from a different org is\n// discarded on re-login. Explicit selections are additionally remembered in\n// localStorage (`lastSelectedProject`) so new tabs default to the project the\n// user picked last — while each tab keeps its own per-tab selection.\n\nconst PROJECT_KEY = \"ds-header-project\";\nconst LAST_PROJECT_KEY = \"lastSelectedProject\";\n\nexport interface StoredProject {\n id: string;\n name: string;\n clientId?: string;\n}\n\nexport function getStoredProject(): StoredProject | null {\n try {\n const raw = sessionStorage.getItem(PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setStoredProject(project: StoredProject): void {\n try {\n sessionStorage.setItem(PROJECT_KEY, JSON.stringify(project));\n } catch {\n // sessionStorage unavailable — degrade silently\n }\n}\n\nexport function clearStoredProject(): void {\n try {\n sessionStorage.removeItem(PROJECT_KEY);\n } catch {\n // noop\n }\n}\n\n/** The project the user last explicitly selected, in any tab (localStorage). */\nexport function getLastSelectedProject(): StoredProject | null {\n try {\n const raw = localStorage.getItem(LAST_PROJECT_KEY);\n return raw ? (JSON.parse(raw) as StoredProject) : null;\n } catch {\n return null;\n }\n}\n\nexport function setLastSelectedProject(project: StoredProject): void {\n try {\n localStorage.setItem(LAST_PROJECT_KEY, JSON.stringify(project));\n } catch {\n // localStorage unavailable — degrade silently\n }\n}\n","\"use client\";\n\nimport * as React from \"react\";\n\nimport {\n clearStoredProject,\n getStoredProject,\n setLastSelectedProject,\n setStoredProject,\n} from \"./storage\";\n\n// Module-level store for the current project/org selection. Module scope (not\n// React context) so a host app can read and change the selection from anywhere —\n// including components rendered outside the <Header> subtree. The Header is one\n// writer/reader; `useHeaderProject()` gives apps the same access.\n\nexport interface HeaderSelection {\n selectedProjectId: string;\n selectedProjectName: string;\n organizationName: string | undefined;\n /** Remaining credits for the logged-in user (read-only here; set by the Header). */\n credits: number | undefined;\n /** Client/org the current selection + org belong to (for cross-org invalidation). */\n clientId: string | undefined;\n}\n\nfunction initialState(): HeaderSelection {\n const stored = typeof window !== \"undefined\" ? getStoredProject() : null;\n return {\n selectedProjectId: stored?.id ?? \"\",\n selectedProjectName: stored?.name ?? \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: stored?.clientId,\n };\n}\n\nlet state: HeaderSelection = initialState();\n// Stable reference for SSR / first server render.\nconst SERVER_SNAPSHOT: HeaderSelection = Object.freeze({\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: undefined,\n clientId: undefined,\n});\n\nconst listeners = new Set<() => void>();\nfunction emit() {\n for (const listener of listeners) listener();\n}\n\nexport const headerStore = {\n subscribe(listener: () => void) {\n listeners.add(listener);\n return () => listeners.delete(listener);\n },\n getSnapshot(): HeaderSelection {\n return state;\n },\n getServerSnapshot(): HeaderSelection {\n return SERVER_SNAPSHOT;\n },\n\n /**\n * Set the selected project. `name` is best-effort; the Header backfills it from\n * the tree. Explicit selections are also remembered in localStorage as the\n * cross-tab default; pass `remember: false` for internal backfill/auto-select\n * writes so they don't overwrite the user's last explicit choice.\n */\n setProject(id: string, name = \"\", clientId?: string, { remember = true } = {}) {\n if (id) {\n const project = { id, name, clientId: clientId ?? state.clientId };\n setStoredProject(project);\n if (remember) setLastSelectedProject(project);\n } else clearStoredProject();\n state = {\n ...state,\n selectedProjectId: id,\n selectedProjectName: name,\n clientId: clientId ?? state.clientId,\n };\n emit();\n },\n\n clearProject() {\n clearStoredProject();\n state = { ...state, selectedProjectId: \"\", selectedProjectName: \"\" };\n emit();\n },\n\n setOrganization(name: string | undefined, clientId?: string) {\n state = { ...state, organizationName: name, clientId: clientId ?? state.clientId };\n emit();\n },\n\n setCredits(credits: number | undefined) {\n if (state.credits === credits) return;\n state = { ...state, credits };\n emit();\n },\n\n /** When the active client changes, drop a selection/org from the previous one. */\n reconcileClient(clientId: string) {\n if (state.clientId === clientId) return;\n if (state.clientId && state.clientId !== clientId) {\n clearStoredProject();\n state = {\n selectedProjectId: \"\",\n selectedProjectName: \"\",\n organizationName: undefined,\n credits: state.credits, // user-level — survives org switches\n clientId,\n };\n } else {\n state = { ...state, clientId };\n }\n emit();\n },\n};\n\n/** Internal: subscribe a component to the selection store. */\nexport function useHeaderStore(): HeaderSelection {\n return React.useSyncExternalStore(\n headerStore.subscribe,\n headerStore.getSnapshot,\n headerStore.getServerSnapshot,\n );\n}\n\nexport interface UseHeaderProjectResult {\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n organizationName: string | undefined;\n /** Set the active project from outside the Header (by id). */\n setProject: (id: string) => void;\n /** Clear this tab's active project (the header re-defaults on next projects load). */\n clearProject: () => void;\n}\n\n/**\n * Read the current project/org and change the project from anywhere in the app —\n * no need to be inside the <Header>. Reflects user selections made in the header\n * and updates the header when changed here.\n */\nexport function useHeaderProject(): UseHeaderProjectResult {\n const snapshot = useHeaderStore();\n return {\n selectedProjectId: snapshot.selectedProjectId,\n selectedProjectName: snapshot.selectedProjectName || undefined,\n organizationName: snapshot.organizationName,\n setProject: React.useCallback((id: string) => headerStore.setProject(id), []),\n clearProject: React.useCallback(() => headerStore.clearProject(), []),\n };\n}\n\n/** Read the logged-in user's remaining credits (read-only; the Header owns it). */\nexport function useHeaderCredits(): number | undefined {\n return useHeaderStore().credits;\n}\n","// Client-side session detection. The auth system writes a JS-readable cookie\n// `{environmentId}-sessionId` (a JWT) on the shared parent domain. We decode it\n// and check its expiry to know whether the user is logged in — no network call.\n\ninterface JwtPayload {\n exp?: number;\n [key: string]: unknown;\n}\n\n/** Read the raw session JWT from the `{environmentId}-sessionId` cookie. */\nexport function getSessionToken(environmentId: string): string | null {\n if (typeof document === \"undefined\") return null;\n const name = `${environmentId}-sessionId`;\n for (const part of document.cookie.split(\";\")) {\n const [key, ...rest] = part.trim().split(\"=\");\n if (key === name) return decodeURIComponent(rest.join(\"=\"));\n }\n return null;\n}\n\n/** Decode a JWT payload without verifying the signature (display/expiry only). */\nexport function decodeJwt(token: string): JwtPayload | null {\n try {\n const payload = token.split(\".\")[1];\n if (!payload) return null;\n const base64 = payload.replace(/-/g, \"+\").replace(/_/g, \"/\");\n const json = atob(base64);\n return JSON.parse(json) as JwtPayload;\n } catch {\n return null;\n }\n}\n\n/** User/session claims carried in the session JWT (the subset the header uses). */\nexport interface SessionClaims {\n email?: string;\n name?: string;\n userId?: string;\n /** Active organisation id (`client_id` claim). */\n clientId?: string;\n exp?: number;\n}\n\n/**\n * Decode the user claims from the session cookie's JWT — no network call.\n * Returns null when the cookie is absent or undecodable.\n */\nexport function getSessionClaims(environmentId: string): SessionClaims | null {\n const token = getSessionToken(environmentId);\n if (!token) return null;\n const payload = decodeJwt(token);\n if (!payload) return null;\n const str = (v: unknown) => (typeof v === \"string\" ? v : undefined);\n return {\n email: str(payload.email),\n name: str(payload.name),\n userId: str(payload.user_id),\n clientId: str(payload.client_id),\n exp: typeof payload.exp === \"number\" ? payload.exp : undefined,\n };\n}\n\n/** True when a valid, unexpired session cookie exists for the environment. */\nexport function isSessionValid(environmentId: string): boolean {\n const token = getSessionToken(environmentId);\n if (!token) return false;\n const payload = decodeJwt(token);\n if (!payload) return false;\n // No exp claim → treat as a non-expiring session.\n if (typeof payload.exp !== \"number\") return true;\n return payload.exp * 1000 > Date.now();\n}\n","\"use client\";\n\nimport { useQuery } from \"@tanstack/react-query\";\nimport * as React from \"react\";\n\nimport { buildEndpoints, callLogout, fetchCredits, fetchProjects, fetchToken } from \"./api\";\nimport { headerStore, useHeaderStore } from \"./header-store\";\nimport { findProjectName, firstSelectableProject, nodeExistsInTree } from \"./project-tree\";\nimport { getSessionClaims, isSessionValid } from \"./session\";\nimport { getLastSelectedProject } from \"./storage\";\nimport type { HeaderProps, ProjectNode } from \"./types\";\n\n/** Window event other modules can dispatch to show/hide the project dropdown. */\nexport const TOGGLE_PROJECT_DROPDOWN_EVENT = \"toggle-project-dropdown\";\nexport interface ToggleProjectDropdownDetail {\n show: boolean;\n}\n\nconst DEFAULT_STALE_TIME = 5 * 60_000;\nconst DEFAULT_GC_TIME = 10 * 60_000;\n\nexport interface GlobalHeaderState {\n /** Whether a valid session cookie exists — when false, hide all user content. */\n isAuthenticated: boolean;\n userEmail: string | undefined;\n organizationName: string | undefined;\n projectsTree: ProjectNode[];\n selectedProjectId: string;\n selectedProjectName: string | undefined;\n isProjectsLoading: boolean;\n isOrgLoading: boolean;\n /** Remaining credits for the user (undefined until loaded / when disabled). */\n credits: number | undefined;\n /** Where the credits pill links to (studio-auth `/user/activity`). */\n creditsHref: string;\n projectDropdownVisible: boolean;\n selectProject: (id: string) => void;\n logout: () => void;\n}\n\ntype UseGlobalHeaderArgs = Pick<\n HeaderProps,\n | \"apiBaseUrl\"\n | \"environmentId\"\n | \"clientId\"\n | \"_dangerouslyInjectAccessToken\"\n | \"showProjectDropdown\"\n | \"showProfile\"\n | \"showOrg\"\n | \"showCredits\"\n | \"endpoints\"\n | \"fetcher\"\n | \"staleTime\"\n | \"gcTime\"\n | \"onProjectChange\"\n>;\n\nexport function useGlobalHeader({\n apiBaseUrl,\n environmentId,\n clientId,\n _dangerouslyInjectAccessToken: injectedToken,\n showProjectDropdown = false,\n showProfile = false,\n showOrg = false,\n showCredits = false,\n endpoints: endpointOverrides,\n fetcher: fetcherProp,\n staleTime = DEFAULT_STALE_TIME,\n gcTime = DEFAULT_GC_TIME,\n onProjectChange,\n}: UseGlobalHeaderArgs): GlobalHeaderState {\n const fetcher = React.useMemo(\n () => fetcherProp ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init)),\n [fetcherProp],\n );\n const endpoints = React.useMemo(\n () => buildEndpoints(apiBaseUrl, endpointOverrides),\n [apiBaseUrl, endpointOverrides],\n );\n\n // Read the session cookie each render (cheap); gates every network call.\n // User identity (email, client id) comes from the JWT claims — no /me call.\n const isAuthenticated = isSessionValid(environmentId);\n const claims = getSessionClaims(environmentId);\n\n // token → projects, enabled only when the previous resolved.\n const tokenQuery = useQuery({\n queryKey: [\"ds-header\", \"token\", endpoints.token],\n queryFn: () => fetchToken(endpoints, fetcher),\n enabled: isAuthenticated && !injectedToken,\n staleTime,\n gcTime,\n });\n const token = injectedToken ?? tokenQuery.data;\n\n const effectiveClientId = clientId ?? claims?.clientId;\n const wantsProjects = showProjectDropdown || showOrg;\n const projectsQuery = useQuery({\n queryKey: [\"ds-header\", \"projects\", effectiveClientId, token],\n queryFn: () => fetchProjects(endpoints, effectiveClientId as string, token as string, fetcher),\n enabled: isAuthenticated && !!token && !!effectiveClientId && wantsProjects,\n staleTime,\n gcTime,\n });\n\n // Credits — only needs the token. Always refetched on mount (staleTime 0) so a\n // page refresh shows the current balance.\n const creditsQuery = useQuery({\n queryKey: [\"ds-header\", \"credits\", endpoints.credits, token],\n queryFn: () => fetchCredits(endpoints, token as string, fetcher),\n enabled: isAuthenticated && !!token && showCredits,\n staleTime: 0,\n gcTime,\n });\n\n const projectsTree = projectsQuery.data?.projectsTree ?? [];\n const userEmail = showProfile ? claims?.email : undefined;\n const creditsHref = React.useMemo(() => {\n try {\n return new URL(\"/user/activity\", apiBaseUrl).toString();\n } catch {\n return \"/user/activity\";\n }\n }, [apiBaseUrl]);\n\n // Selection + org live in a module store so host apps can read/change them\n // from outside the header (see useHeaderProject).\n const selection = useHeaderStore();\n\n // Ref so the auto-select effect sees the latest callback without re-running.\n const onProjectChangeRef = React.useRef(onProjectChange);\n React.useEffect(() => {\n onProjectChangeRef.current = onProjectChange;\n });\n\n // Once the client id resolves, drop a selection/org from a different client.\n React.useEffect(() => {\n if (effectiveClientId) headerStore.reconcileClient(effectiveClientId);\n }, [effectiveClientId]);\n\n // Once projects load: publish the org name and validate/backfill the selection.\n // A tab with no valid selection defaults to the user's last explicitly selected\n // project (localStorage `lastSelectedProject`) when it still exists in the\n // tree, else the first selectable project — no selection prompt.\n React.useEffect(() => {\n if (!projectsQuery.data) return;\n const tree = projectsQuery.data.projectsTree;\n const id = headerStore.getSnapshot().selectedProjectId;\n if (id && nodeExistsInTree(tree, id)) {\n const name = findProjectName(tree, id);\n if (name && name !== headerStore.getSnapshot().selectedProjectName) {\n headerStore.setProject(id, name, effectiveClientId, { remember: false });\n }\n } else {\n const last = getLastSelectedProject();\n const fallback =\n last && nodeExistsInTree(tree, last.id)\n ? { id: last.id, name: findProjectName(tree, last.id) ?? last.name }\n : firstSelectableProject(tree);\n if (fallback) {\n headerStore.setProject(fallback.id, fallback.name, effectiveClientId, {\n remember: false,\n });\n onProjectChangeRef.current?.(fallback.id);\n } else if (id) {\n headerStore.clearProject();\n }\n }\n headerStore.setOrganization(projectsQuery.data.organizationName, effectiveClientId);\n }, [projectsQuery.data, effectiveClientId]);\n\n // Publish credits to the store so host apps can read them via useHeaderCredits.\n React.useEffect(() => {\n if (creditsQuery.data !== undefined) headerStore.setCredits(creditsQuery.data);\n }, [creditsQuery.data]);\n\n const selectProject = (id: string) => {\n const name = findProjectName(projectsTree, id) ?? \"\";\n headerStore.setProject(id, name, effectiveClientId);\n onProjectChange?.(id);\n };\n\n const logout = () => {\n headerStore.clearProject();\n void callLogout(endpoints, fetcher);\n };\n\n // Visibility: declarative from the prop, overridable at runtime via the event.\n const [projectDropdownVisible, setProjectDropdownVisible] = React.useState(showProjectDropdown);\n React.useEffect(() => setProjectDropdownVisible(showProjectDropdown), [showProjectDropdown]);\n React.useEffect(() => {\n const handler = (e: Event) => {\n setProjectDropdownVisible((e as CustomEvent<ToggleProjectDropdownDetail>).detail.show);\n };\n window.addEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n return () => window.removeEventListener(TOGGLE_PROJECT_DROPDOWN_EVENT, handler);\n }, []);\n\n const isProjectsLoading = projectsQuery.isFetching && !projectsQuery.data;\n\n return {\n isAuthenticated,\n userEmail,\n organizationName: selection.organizationName,\n projectsTree,\n selectedProjectId: selection.selectedProjectId,\n selectedProjectName: selection.selectedProjectName || undefined,\n isProjectsLoading,\n isOrgLoading: showOrg && isProjectsLoading,\n credits: selection.credits,\n creditsHref,\n projectDropdownVisible,\n selectProject,\n logout,\n };\n}\n","\"use client\";\n\nimport { QueryClient, QueryClientProvider } from \"@tanstack/react-query\";\nimport { LogOut, MessageSquareShare, Moon, Sun } from \"lucide-react\";\nimport type * as React from \"react\";\n\nimport { Avatar, AvatarFallback } from \"@/primitives/Avatar\";\nimport { Button } from \"@/primitives/Button\";\nimport { Credits } from \"@/primitives/Credits\";\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuLabel,\n DropdownMenuSeparator,\n DropdownMenuTrigger,\n} from \"@/primitives/DropdownMenu\";\nimport { Logo } from \"@/primitives/Logo\";\nimport { Skeleton } from \"@/primitives/Skeleton\";\nimport { type ThemeProduct, useTheme } from \"@/primitives/ThemeProvider\";\nimport { cn } from \"@/utils\";\nimport { ProjectPicker } from \"./ProjectPicker\";\nimport { DEFAULT_LABELS } from \"./labels\";\nimport type { HeaderProps } from \"./types\";\nimport { useGlobalHeader } from \"./use-global-header\";\n\n// Fallback logo destinations when the host doesn't pass `logoHref`.\nconst LOGO_HREF: Record<ThemeProduct, string> = {\n psai: \"https://sapientaiproducts.com/\",\n slingshot: \"https://sapientaiproducts.com/slingshot\",\n sustain: \"https://www.publicissapient.com/\",\n bodhi: \"https://sapientaiproducts.com/bodhi\",\n};\n\nconst PILL =\n \"flex min-h-8 items-center gap-1 rounded-12 border border-primary-border bg-input-bg px-3 py-1 text-xs leading-4\";\n\n// ── Presentational parts (props-driven; Storybook/VR-able) ──────────────────\n\n/** The header bar shell — a sticky glass strip. */\nfunction HeaderBar({ className, ...props }: React.ComponentProps<\"header\">) {\n return (\n <header\n data-slot=\"header\"\n className={cn(\n \"sticky top-1 z-10 mt-1 flex h-15 items-center gap-5 rounded-16 px-3 py-2\",\n \"bg-glass-60-bg backdrop-blur-glass\",\n className,\n )}\n {...props}\n />\n );\n}\n\n/** Product logo linking to its home, with a Suspense-safe fallback. */\nfunction HeaderLogo({ brand, href }: { brand: ThemeProduct; href?: string }) {\n return (\n <a href={href ?? LOGO_HREF[brand]} aria-label=\"Go to product home\" data-slot=\"header-logo\">\n <Logo brand={brand} className=\"h-8 w-auto\" />\n </a>\n );\n}\n\n/** Read-only organisation pill. */\nfunction OrgPill({ name, loading }: { name?: string; loading?: boolean }) {\n if (loading && !name) {\n return (\n <div className={cn(PILL, \"ml-3\")} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <Skeleton className=\"h-4 w-24\" />\n </div>\n );\n }\n if (!name) return null;\n return (\n <div className={cn(PILL, \"ml-3 select-none\")} title={name} data-slot=\"header-org\">\n <span className=\"shrink-0 text-muted-txt\">{DEFAULT_LABELS.orgLabel}:</span>\n <span className=\"max-w-36 truncate text-primary-txt\">{name}</span>\n </div>\n );\n}\n\n/** Light/dark toggle — defers to ThemeProvider. */\nfunction ThemeToggle() {\n const { theme, toggleTheme } = useTheme();\n return (\n <Button variant=\"ghost\" size=\"icon\" onClick={toggleTheme} aria-label=\"Toggle theme\">\n {theme === \"light\" ? <Moon className=\"size-4\" /> : <Sun className=\"size-4\" />}\n </Button>\n );\n}\n\n/** Profile menu — avatar trigger with email + logout. */\nfunction ProfileMenu({ email, onLogout }: { email?: string; onLogout: () => void }) {\n const initial = email?.trim().charAt(0).toUpperCase() || \"?\";\n return (\n <DropdownMenu>\n <DropdownMenuTrigger asChild>\n <Button variant=\"ghost\" size=\"icon\" aria-label={DEFAULT_LABELS.profileMenuLabel}>\n <Avatar className=\"size-7\">\n <AvatarFallback>{initial}</AvatarFallback>\n </Avatar>\n </Button>\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"end\" sideOffset={8} className=\"min-w-44\">\n {email && (\n <>\n <DropdownMenuLabel className=\"truncate font-normal text-muted-txt\">\n {email}\n </DropdownMenuLabel>\n <DropdownMenuSeparator />\n </>\n )}\n <DropdownMenuItem onSelect={onLogout} variant=\"destructive\">\n <LogOut />\n {DEFAULT_LABELS.logoutLabel}\n </DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n\nexport { HeaderBar, HeaderLogo, OrgPill, ThemeToggle, ProfileMenu };\n\n// ── Wired Header ─────────────────────────────────────────────────────────────\n\n// Internal singleton client so the header is drop-in (no app setup) while still\n// sharing its cache across mounts/navigation.\nlet sharedClient: QueryClient | undefined;\nfunction getQueryClient(): QueryClient {\n sharedClient ??= new QueryClient({\n defaultOptions: { queries: { retry: 1, refetchOnWindowFocus: false } },\n });\n return sharedClient;\n}\n\n/** Drop-in global header. Must be rendered inside a <ThemeProvider>. */\nexport function Header(props: HeaderProps) {\n return (\n <QueryClientProvider client={getQueryClient()}>\n <HeaderInner {...props} />\n </QueryClientProvider>\n );\n}\n\nfunction HeaderInner({\n logoType,\n logoHref,\n showOrg = false,\n showProjectDropdown = false,\n showProfile = false,\n showThemeSwitcher = false,\n showCredits = false,\n pageTitle,\n feedbackUrl,\n logoAddon,\n actionsStart,\n actionsEnd,\n className,\n ...rest\n}: HeaderProps) {\n const { product } = useTheme();\n const brand = logoType ?? product;\n const state = useGlobalHeader({\n showOrg,\n showProjectDropdown,\n showProfile,\n showCredits,\n ...rest,\n });\n\n // Logged-out users see no user content (project/org/profile/credits).\n const showProjectUi = showProjectDropdown && state.isAuthenticated;\n const showOrgUi = showOrg && state.isAuthenticated;\n const showProfileUi = showProfile && state.isAuthenticated;\n const showCreditsUi = showCredits && state.isAuthenticated && state.credits !== undefined;\n const showActions =\n showThemeSwitcher ||\n showProfileUi ||\n showCreditsUi ||\n !!feedbackUrl ||\n !!actionsStart ||\n !!actionsEnd;\n\n return (\n <HeaderBar className={className}>\n <HeaderLogo brand={brand} href={logoHref} />\n {/* Page title — 20px (gap-5) from the logo. */}\n {pageTitle && (\n <span data-slot=\"header-title\" className=\"ml-5 font-semibold text-primary-txt text-sm\">\n {pageTitle}\n </span>\n )}\n {logoAddon}\n\n {showOrgUi && <OrgPill name={state.organizationName} loading={state.isOrgLoading} />}\n\n {showProjectUi && state.projectDropdownVisible && (\n <div className=\"ml-2\">\n <ProjectPicker\n projectsTree={state.projectsTree}\n selectedProjectId={state.selectedProjectId}\n selectedProjectName={state.selectedProjectName}\n onSelect={state.selectProject}\n projectLabel={DEFAULT_LABELS.projectLabel}\n projectPlaceholder={DEFAULT_LABELS.projectPlaceholder}\n searchPlaceholder={DEFAULT_LABELS.searchPlaceholder}\n emptyStateText={DEFAULT_LABELS.emptyStateText}\n isLoading={state.isProjectsLoading}\n />\n </div>\n )}\n\n {showActions && (\n <div className=\"ml-auto flex items-center gap-2\">\n {actionsStart}\n {feedbackUrl && (\n <Button variant=\"ghost\" size=\"icon\" asChild>\n <a\n href={feedbackUrl}\n target=\"_blank\"\n rel=\"noopener noreferrer\"\n aria-label=\"Share feedback\"\n >\n <MessageSquareShare className=\"size-4\" />\n </a>\n </Button>\n )}\n {showThemeSwitcher && <ThemeToggle />}\n {showCreditsUi && state.credits !== undefined && (\n <a\n href={state.creditsHref}\n aria-label=\"View credit activity\"\n className=\"rounded-full outline-none focus-visible:ring-3 focus-visible:ring-focus\"\n >\n <Credits value={state.credits} />\n </a>\n )}\n {showProfileUi && <ProfileMenu email={state.userEmail} onLogout={state.logout} />}\n {actionsEnd}\n </div>\n )}\n </HeaderBar>\n );\n}\n"],"mappings":"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"}
|
package/dist/index.d.cts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as react_jsx_runtime232 from "react/jsx-runtime";
|
|
2
2
|
import { Accordion } from "radix-ui";
|
|
3
3
|
|
|
4
4
|
//#region src/primitives/Accordion/Accordion.d.ts
|
|
@@ -10,24 +10,24 @@ declare function Accordion$1({
|
|
|
10
10
|
}: React.ComponentProps<typeof Accordion.Root> & {
|
|
11
11
|
/** Visual style: `line` (divider rows) or `bordered` (rounded border with inset rows). */
|
|
12
12
|
variant?: "line" | "bordered";
|
|
13
|
-
}):
|
|
13
|
+
}): react_jsx_runtime232.JSX.Element;
|
|
14
14
|
/** A single collapsible section; identified by its required `value`. */
|
|
15
15
|
declare function AccordionItem({
|
|
16
16
|
className,
|
|
17
17
|
...props
|
|
18
|
-
}: React.ComponentProps<typeof Accordion.Item>):
|
|
18
|
+
}: React.ComponentProps<typeof Accordion.Item>): react_jsx_runtime232.JSX.Element;
|
|
19
19
|
/** The clickable header that toggles its section open or closed. */
|
|
20
20
|
declare function AccordionTrigger({
|
|
21
21
|
className,
|
|
22
22
|
children,
|
|
23
23
|
...props
|
|
24
|
-
}: React.ComponentProps<typeof Accordion.Trigger>):
|
|
24
|
+
}: React.ComponentProps<typeof Accordion.Trigger>): react_jsx_runtime232.JSX.Element;
|
|
25
25
|
/** The animated collapsible panel revealed when its section is open. */
|
|
26
26
|
declare function AccordionContent({
|
|
27
27
|
className,
|
|
28
28
|
children,
|
|
29
29
|
...props
|
|
30
|
-
}: React.ComponentProps<typeof Accordion.Content>):
|
|
30
|
+
}: React.ComponentProps<typeof Accordion.Content>): react_jsx_runtime232.JSX.Element;
|
|
31
31
|
//#endregion
|
|
32
32
|
export { AccordionTrigger as i, AccordionContent as n, AccordionItem as r, Accordion$1 as t };
|
|
33
33
|
//# sourceMappingURL=index.d.cts.map
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Accordion } from "radix-ui";
|
|
2
|
-
import * as
|
|
2
|
+
import * as react_jsx_runtime307 from "react/jsx-runtime";
|
|
3
3
|
|
|
4
4
|
//#region src/primitives/Accordion/Accordion.d.ts
|
|
5
5
|
/** A vertically stacked set of collapsible sections built on Radix Accordion. */
|
|
@@ -10,24 +10,24 @@ declare function Accordion$1({
|
|
|
10
10
|
}: React.ComponentProps<typeof Accordion.Root> & {
|
|
11
11
|
/** Visual style: `line` (divider rows) or `bordered` (rounded border with inset rows). */
|
|
12
12
|
variant?: "line" | "bordered";
|
|
13
|
-
}):
|
|
13
|
+
}): react_jsx_runtime307.JSX.Element;
|
|
14
14
|
/** A single collapsible section; identified by its required `value`. */
|
|
15
15
|
declare function AccordionItem({
|
|
16
16
|
className,
|
|
17
17
|
...props
|
|
18
|
-
}: React.ComponentProps<typeof Accordion.Item>):
|
|
18
|
+
}: React.ComponentProps<typeof Accordion.Item>): react_jsx_runtime307.JSX.Element;
|
|
19
19
|
/** The clickable header that toggles its section open or closed. */
|
|
20
20
|
declare function AccordionTrigger({
|
|
21
21
|
className,
|
|
22
22
|
children,
|
|
23
23
|
...props
|
|
24
|
-
}: React.ComponentProps<typeof Accordion.Trigger>):
|
|
24
|
+
}: React.ComponentProps<typeof Accordion.Trigger>): react_jsx_runtime307.JSX.Element;
|
|
25
25
|
/** The animated collapsible panel revealed when its section is open. */
|
|
26
26
|
declare function AccordionContent({
|
|
27
27
|
className,
|
|
28
28
|
children,
|
|
29
29
|
...props
|
|
30
|
-
}: React.ComponentProps<typeof Accordion.Content>):
|
|
30
|
+
}: React.ComponentProps<typeof Accordion.Content>): react_jsx_runtime307.JSX.Element;
|
|
31
31
|
//#endregion
|
|
32
32
|
export { AccordionTrigger as i, AccordionContent as n, AccordionItem as r, Accordion$1 as t };
|
|
33
33
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/primitives/Accordion/Accordion.tsx"],"mappings":";;;;;iBAKS,WAAA;;;;GAIN,KAAA,CAAM,sBAAsB,SAAA,CAAmB;;EAJzC,OAAA,CAAA,EAAA,MAAS,GAAA,UAAA;CAAA,CAAA,EAOjB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","names":[],"sources":["../src/primitives/Accordion/Accordion.tsx"],"mappings":";;;;;iBAKS,WAAA;;;;GAIN,KAAA,CAAM,sBAAsB,SAAA,CAAmB;;EAJzC,OAAA,CAAA,EAAA,MAAS,GAAA,UAAA;CAAA,CAAA,EAOjB,oBAAA,CAAA,GAAA,CAAA,OAPiB;;iBAyBT,aAAA,CAvBP;EAAA,SAAA;EAAA,GAAA;AAAA,CAAA,EA0BC,KAAA,CAAM,cA1BP,CAAA,OA0B6B,SAAA,CAAmB,IA1BhD,CAAA,CAAA,EA0BqD,oBAAA,CAAA,GAAA,CAAA,OA1BrD;;iBAwCO,gBAAA,CAtCA;EAAA,SAAA;EAAA,QAAA;EAAA,GAAA;AAAA,CAAA,EA0CN,KAAA,CAAM,cA1CA,CAAA,OA0CsB,SAAA,CAAmB,OA1CzC,CAAA,CAAA,EA0CiD,oBAAA,CAAA,GAAA,CAAA,OA1CjD;;AAGR,iBA2DQ,gBAAA,CA3DR;EAAA,SAAA;EAAA,QAAA;EAAA,GAAA;AAAA,CAAA,EA+DE,KAAA,CAAM,cA/DR,CAAA,OA+D8B,SAAA,CAAmB,OA/DjD,CAAA,CAAA,EA+DyD,oBAAA,CAAA,GAAA,CAAA,OA/DzD"}
|