@sybilion/uilib 1.2.4 → 1.2.5

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.
Files changed (42) hide show
  1. package/dist/esm/components/ui/AppHeader/appChromeAnchors.js +3 -1
  2. package/dist/esm/components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.js +62 -0
  3. package/dist/esm/components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.styl.js +7 -0
  4. package/dist/esm/components/ui/WorkspaceAppSwitcher/workspaceApp.types.js +4 -0
  5. package/dist/esm/components/ui/WorkspaceAppSwitcher/workspaceAppIcons.js +16 -0
  6. package/dist/esm/components/ui/WorkspaceAppSwitcher/workspaceAppPaths.js +29 -0
  7. package/dist/esm/components/ui/WorkspaceAppSwitcher/workspaceAppsConstants.js +4 -0
  8. package/dist/esm/components/ui/WorkspaceAppSwitcher/workspaceAppsLocalStorage.js +84 -0
  9. package/dist/esm/components/widgets/SybilionAppHeader/SybilionAppHeader.js +16 -0
  10. package/dist/esm/components/widgets/SybilionAppHeader/SybilionAppHeader.styl.js +7 -0
  11. package/dist/esm/index.js +8 -1
  12. package/dist/esm/types/src/components/ui/AppHeader/appChromeAnchors.d.ts +2 -0
  13. package/dist/esm/types/src/components/ui/AppHeader/index.d.ts +1 -1
  14. package/dist/esm/types/src/components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.d.ts +12 -0
  15. package/dist/esm/types/src/components/ui/WorkspaceAppSwitcher/index.d.ts +7 -0
  16. package/dist/esm/types/src/components/ui/WorkspaceAppSwitcher/workspaceApp.types.d.ts +19 -0
  17. package/dist/esm/types/src/components/ui/WorkspaceAppSwitcher/workspaceAppIcons.d.ts +9 -0
  18. package/dist/esm/types/src/components/ui/WorkspaceAppSwitcher/workspaceAppPaths.d.ts +3 -0
  19. package/dist/esm/types/src/components/ui/WorkspaceAppSwitcher/workspaceAppsConstants.d.ts +2 -0
  20. package/dist/esm/types/src/components/ui/WorkspaceAppSwitcher/workspaceAppsLocalStorage.d.ts +6 -0
  21. package/dist/esm/types/src/components/widgets/SybilionAppHeader/SybilionAppHeader.d.ts +8 -0
  22. package/dist/esm/types/src/components/widgets/SybilionAppHeader/index.d.ts +1 -0
  23. package/dist/esm/types/src/index.d.ts +2 -0
  24. package/docs/standalone-apps.md +113 -52
  25. package/package.json +1 -1
  26. package/src/components/ui/AppHeader/appChromeAnchors.ts +3 -0
  27. package/src/components/ui/AppHeader/index.ts +1 -1
  28. package/src/components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.styl +91 -0
  29. package/src/components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.styl.d.ts +15 -0
  30. package/src/components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.tsx +163 -0
  31. package/src/components/ui/WorkspaceAppSwitcher/index.ts +20 -0
  32. package/src/components/ui/WorkspaceAppSwitcher/workspaceApp.types.ts +21 -0
  33. package/src/components/ui/WorkspaceAppSwitcher/workspaceAppIcons.ts +27 -0
  34. package/src/components/ui/WorkspaceAppSwitcher/workspaceAppPaths.ts +34 -0
  35. package/src/components/ui/WorkspaceAppSwitcher/workspaceAppsConstants.ts +2 -0
  36. package/src/components/ui/WorkspaceAppSwitcher/workspaceAppsLocalStorage.ts +95 -0
  37. package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.styl +7 -0
  38. package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.styl.d.ts +7 -0
  39. package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.tsx +51 -0
  40. package/src/components/widgets/SybilionAppHeader/index.ts +4 -0
  41. package/src/docs/pages/StandaloneAppLayoutPage.tsx +102 -34
  42. package/src/index.ts +2 -0
@@ -1,4 +1,6 @@
1
1
  /** DOM anchor id for portaling page-level header actions into `AppHeader`. */
2
2
  const PAGE_HEADER_ID = 'page-header';
3
+ /** DOM id for `#page-header-actions`; `AppHeaderActions` portaling target. */
4
+ const PAGE_HEADER_ACTIONS_ID = 'page-header-actions';
3
5
 
4
- export { PAGE_HEADER_ID };
6
+ export { PAGE_HEADER_ACTIONS_ID, PAGE_HEADER_ID };
@@ -0,0 +1,62 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { useState, useEffect } from 'react';
4
+ import { Button } from '../Button/Button.js';
5
+ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuItem } from '../DropdownMenu/DropdownMenu.js';
6
+ import { WORKSPACE_APP_ICONS } from './workspaceAppIcons.js';
7
+ import { findWorkspaceAppByPathname } from './workspaceAppPaths.js';
8
+ import { readWorkspaceAppsFromLocalStorage } from './workspaceAppsLocalStorage.js';
9
+ import { ChevronDown } from 'lucide-react';
10
+ import S from './WorkspaceAppSwitcher.styl.js';
11
+
12
+ function entryKey(entry) {
13
+ return entry.id;
14
+ }
15
+ function IconTile({ iconKey, accentMuted, accent, }) {
16
+ const IconComponent = WORKSPACE_APP_ICONS[iconKey];
17
+ return (jsx("span", { className: S.iconTile, style: {
18
+ '--bg-color': accentMuted,
19
+ '--fg-color': accent,
20
+ }, children: jsx(IconComponent, { className: S.icon, "aria-hidden": true }) }));
21
+ }
22
+ function useResolvedApps(appsStorageKey, defaultApps) {
23
+ const [apps, setApps] = useState(() => {
24
+ if (typeof localStorage !== 'undefined' &&
25
+ appsStorageKey != null &&
26
+ appsStorageKey !== '') {
27
+ const fromLs = readWorkspaceAppsFromLocalStorage(appsStorageKey);
28
+ if (fromLs != null && fromLs.length > 0) {
29
+ return fromLs;
30
+ }
31
+ }
32
+ return defaultApps ?? [];
33
+ });
34
+ useEffect(() => {
35
+ if (!appsStorageKey || typeof localStorage === 'undefined') {
36
+ setApps(defaultApps ?? []);
37
+ return;
38
+ }
39
+ const fromLs = readWorkspaceAppsFromLocalStorage(appsStorageKey);
40
+ setApps(fromLs != null && fromLs.length > 0 ? fromLs : (defaultApps ?? []));
41
+ }, [appsStorageKey, defaultApps]);
42
+ return apps;
43
+ }
44
+ function WorkspaceAppSwitcher({ pathname, onNavigate, authenticated = true, defaultApps, appsStorageKey, }) {
45
+ const apps = useResolvedApps(appsStorageKey, defaultApps);
46
+ const current = findWorkspaceAppByPathname(pathname, apps);
47
+ if (!authenticated || apps.length === 0) {
48
+ return null;
49
+ }
50
+ const displayApp = current ?? apps[0];
51
+ if (!displayApp) {
52
+ return null;
53
+ }
54
+ return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs(Button, { variant: "ghost", className: S.trigger, "aria-label": "Select workspace app", children: [jsx(IconTile, { iconKey: displayApp.iconKey, accentMuted: displayApp.accentMuted, accent: displayApp.accent }), jsxs("span", { className: S.textCol, children: [jsx("span", { className: S.name, children: displayApp.displayName }), jsx("span", { className: S.sub, children: displayApp.subtitle })] }), jsx(ChevronDown, { size: 12 })] }) }), jsx(DropdownMenuContent, { className: S.menuContent, align: "start", sideOffset: 8, elevation: "md", children: apps.map(entry => {
55
+ const active = current != null ? entryKey(entry) === entryKey(current) : false;
56
+ return (jsxs(DropdownMenuItem, { className: cn(S.item, active && S.itemActive), onSelect: () => {
57
+ onNavigate(entry.href);
58
+ }, children: [jsx(IconTile, { iconKey: entry.iconKey, accentMuted: entry.accentMuted, accent: entry.accent }), jsxs("span", { className: S.textCol, children: [jsx("span", { className: S.name, children: entry.displayName }), jsx("span", { className: S.sub, children: entry.subtitle })] })] }, entry.id));
59
+ }) })] }));
60
+ }
61
+
62
+ export { WorkspaceAppSwitcher };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.WorkspaceAppSwitcher_trigger__s6qYT{align-items:center;background:transparent;border:none;border-radius:12px;color:inherit;cursor:pointer;display:flex;font:inherit;gap:var(--p-2);height:auto;margin-left:var(--p-3)!important;max-width:320px;padding:var(--p-1)!important;padding-right:var(--p-3)!important;text-align:left}.WorkspaceAppSwitcher_trigger__s6qYT:hover{background-color:var(--muted)}.WorkspaceAppSwitcher_iconTile__tVDr8{align-items:center;border-radius:10px;color:var(--fg-color);display:flex;flex-shrink:0;height:40px;justify-content:center;position:relative;width:40px}.WorkspaceAppSwitcher_iconTile__tVDr8:after,.WorkspaceAppSwitcher_iconTile__tVDr8:before{border-radius:inherit;content:\"\";display:block;height:100%;position:absolute;width:100%}.WorkspaceAppSwitcher_iconTile__tVDr8:before{background-color:var(--background)}.WorkspaceAppSwitcher_iconTile__tVDr8:after{background-color:var(--bg-color)}.WorkspaceAppSwitcher_icon__Jgw14{color:var(--fg-color)!important;height:22px!important;width:22px!important;z-index:1}.WorkspaceAppSwitcher_textCol__K1gfI{display:flex;flex:1;flex-direction:column;gap:2px;min-width:0}.WorkspaceAppSwitcher_name__ewMYP{color:var(--foreground);font-size:var(--text-sm);font-weight:600}.WorkspaceAppSwitcher_name__ewMYP,.WorkspaceAppSwitcher_sub__b7w1p{line-height:1.2;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.WorkspaceAppSwitcher_sub__b7w1p{color:var(--muted-foreground);font-size:var(--text-xs)}.WorkspaceAppSwitcher_menuContent__4-UNY{max-width:360px;min-width:280px}.WorkspaceAppSwitcher_item__nnufY{align-items:center;cursor:pointer;display:flex;gap:var(--p-3);outline:none;padding:var(--p-3)}.WorkspaceAppSwitcher_itemActive__3mPlO{background-color:var(--muted)}";
4
+ var S = {"trigger":"WorkspaceAppSwitcher_trigger__s6qYT","iconTile":"WorkspaceAppSwitcher_iconTile__tVDr8","icon":"WorkspaceAppSwitcher_icon__Jgw14","textCol":"WorkspaceAppSwitcher_textCol__K1gfI","name":"WorkspaceAppSwitcher_name__ewMYP","sub":"WorkspaceAppSwitcher_sub__b7w1p","menuContent":"WorkspaceAppSwitcher_menuContent__4-UNY","item":"WorkspaceAppSwitcher_item__nnufY","itemActive":"WorkspaceAppSwitcher_itemActive__3mPlO"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,4 @@
1
+ /** Path segment for slug apps: pathname matches `/apps/{id}` */
2
+ const WORKSPACE_APP_SLUG_BASE_PATH = '/apps';
3
+
4
+ export { WORKSPACE_APP_SLUG_BASE_PATH };
@@ -0,0 +1,16 @@
1
+ import { Boat, Package, TreeStructure } from '@phosphor-icons/react';
2
+ import { LayoutDashboard, ClockAlert } from 'lucide-react';
3
+
4
+ const WORKSPACE_APP_ICONS = {
5
+ 'grid-four': LayoutDashboard,
6
+ clock: ClockAlert,
7
+ boat: Boat,
8
+ package: Package,
9
+ 'tree-structure': TreeStructure,
10
+ };
11
+ const ICON_KEYS = Object.keys(WORKSPACE_APP_ICONS);
12
+ function isWorkspaceAppIconKey(v) {
13
+ return ICON_KEYS.includes(v);
14
+ }
15
+
16
+ export { WORKSPACE_APP_ICONS, isWorkspaceAppIconKey };
@@ -0,0 +1,29 @@
1
+ import { WORKSPACE_APP_SLUG_BASE_PATH } from './workspaceApp.types.js';
2
+
3
+ function workspaceAppSlugPath(id) {
4
+ return `${WORKSPACE_APP_SLUG_BASE_PATH}/${id}`;
5
+ }
6
+ function pathnameMatchesPrefix(pathname, prefix) {
7
+ return pathname === prefix || pathname.startsWith(`${prefix}/`);
8
+ }
9
+ function pathnameMatchesSlugApp(pathname, id) {
10
+ const base = workspaceAppSlugPath(id);
11
+ return pathname === base || pathname.startsWith(`${base}/`);
12
+ }
13
+ function findWorkspaceAppByPathname(pathname, apps) {
14
+ for (const app of apps) {
15
+ const prefixes = app.matchPathPrefixes;
16
+ if (prefixes && prefixes.length > 0) {
17
+ if (prefixes.some(prefix => pathnameMatchesPrefix(pathname, prefix))) {
18
+ return app;
19
+ }
20
+ continue;
21
+ }
22
+ if (pathnameMatchesSlugApp(pathname, app.id)) {
23
+ return app;
24
+ }
25
+ }
26
+ return null;
27
+ }
28
+
29
+ export { findWorkspaceAppByPathname, workspaceAppSlugPath };
@@ -0,0 +1,4 @@
1
+ /** localStorage key for workspace app list JSON (shared by host app + demos). */
2
+ const WORKSPACE_APPS_LS_KEY = 'sybilion.workspaceApps.v1';
3
+
4
+ export { WORKSPACE_APPS_LS_KEY };
@@ -0,0 +1,84 @@
1
+ import { isWorkspaceAppIconKey } from './workspaceAppIcons.js';
2
+
3
+ function parseEntry(raw) {
4
+ if (!raw || typeof raw !== 'object') {
5
+ return null;
6
+ }
7
+ const o = raw;
8
+ const idRaw = o.id ?? o.nativeId;
9
+ const displayName = o.displayName;
10
+ const subtitle = o.subtitle;
11
+ const iconKey = o.iconKey;
12
+ const accent = o.accent;
13
+ const accentMuted = o.accentMuted;
14
+ const href = o.href;
15
+ const prefixesRaw = o.matchPathPrefixes;
16
+ if (typeof idRaw !== 'string' ||
17
+ !idRaw ||
18
+ typeof displayName !== 'string' ||
19
+ typeof subtitle !== 'string' ||
20
+ typeof iconKey !== 'string' ||
21
+ !isWorkspaceAppIconKey(iconKey) ||
22
+ typeof accent !== 'string' ||
23
+ typeof accentMuted !== 'string' ||
24
+ typeof href !== 'string' ||
25
+ !href) {
26
+ return null;
27
+ }
28
+ let matchPathPrefixes;
29
+ if (prefixesRaw != null) {
30
+ if (!Array.isArray(prefixesRaw)) {
31
+ return null;
32
+ }
33
+ const prefixes = prefixesRaw.filter((p) => typeof p === 'string');
34
+ if (prefixes.length > 0) {
35
+ matchPathPrefixes = prefixes;
36
+ }
37
+ }
38
+ return {
39
+ id: idRaw,
40
+ displayName,
41
+ subtitle,
42
+ iconKey,
43
+ accent,
44
+ accentMuted,
45
+ href,
46
+ matchPathPrefixes,
47
+ };
48
+ }
49
+ /**
50
+ * Read validated workspace apps JSON from localStorage; returns null if missing or invalid.
51
+ */
52
+ function readWorkspaceAppsFromLocalStorage(key) {
53
+ try {
54
+ const raw = localStorage.getItem(key);
55
+ if (raw == null || raw === '') {
56
+ return null;
57
+ }
58
+ const parsed = JSON.parse(raw);
59
+ if (!Array.isArray(parsed) || parsed.length === 0) {
60
+ return null;
61
+ }
62
+ const apps = [];
63
+ for (const item of parsed) {
64
+ const entry = parseEntry(item);
65
+ if (entry) {
66
+ apps.push(entry);
67
+ }
68
+ }
69
+ return apps.length > 0 ? apps : null;
70
+ }
71
+ catch {
72
+ return null;
73
+ }
74
+ }
75
+ function writeWorkspaceAppsToLocalStorage(key, apps) {
76
+ try {
77
+ localStorage.setItem(key, JSON.stringify(apps));
78
+ }
79
+ catch {
80
+ // ignore quota / private mode
81
+ }
82
+ }
83
+
84
+ export { readWorkspaceAppsFromLocalStorage, writeWorkspaceAppsToLocalStorage };
@@ -0,0 +1,16 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { AppHeaderPortal } from '../../ui/AppHeader/AppHeader.js';
4
+ import { PAGE_HEADER_ACTIONS_ID } from '../../ui/AppHeader/appChromeAnchors.js';
5
+ import { Gap } from '../../ui/Gap/Gap.js';
6
+ import { NavUserHeader } from '../../ui/NavUserHeader/NavUserHeader.js';
7
+ import { WorkspaceAppSwitcher } from '../../ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.js';
8
+ import '@phosphor-icons/react';
9
+ import 'lucide-react';
10
+ import S from './SybilionAppHeader.styl.js';
11
+
12
+ function SybilionAppHeader({ pageHeaderId, actionsAnchorId = PAGE_HEADER_ACTIONS_ID, actionsAnchorClassName, pathname, onNavigate, authenticated, defaultApps, appsStorageKey, ...navUserHeaderProps }) {
13
+ return (jsxs(AppHeaderPortal, { pageHeaderId: pageHeaderId, children: [jsx(WorkspaceAppSwitcher, { pathname: pathname, onNavigate: onNavigate, authenticated: authenticated, defaultApps: defaultApps, appsStorageKey: appsStorageKey }), jsx(Gap, {}), jsx("div", { id: actionsAnchorId, className: cn(S.actionsAnchor, actionsAnchorClassName), children: jsx(NavUserHeader, { ...navUserHeaderProps }) })] }));
14
+ }
15
+
16
+ export { SybilionAppHeader };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.SybilionAppHeader_actionsAnchor__ress2{align-items:center;display:flex;flex-shrink:0;gap:var(--p-4)}";
4
+ var S = {"actionsAnchor":"SybilionAppHeader_actionsAnchor__ress2"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
package/dist/esm/index.js CHANGED
@@ -5,7 +5,7 @@ export { ChatContext, ChatProvider, useChat, useChats, useChatsForDataset, useCh
5
5
  export { AnalysesSelector } from './components/ui/AnalysesSelector/AnalysesSelector.js';
6
6
  export { AnalysisLineIcon } from './components/ui/AnalysisLineIcon/AnalysisLineIcon.js';
7
7
  export { AppHeaderHost, AppHeaderPortal } from './components/ui/AppHeader/AppHeader.js';
8
- export { PAGE_HEADER_ID } from './components/ui/AppHeader/appChromeAnchors.js';
8
+ export { PAGE_HEADER_ACTIONS_ID, PAGE_HEADER_ID } from './components/ui/AppHeader/appChromeAnchors.js';
9
9
  export { Avatar, AvatarFallback, AvatarImage } from './components/ui/Avatar/Avatar.js';
10
10
  export { Badge } from './components/ui/Badge/Badge.js';
11
11
  export { Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage, BreadcrumbSeparator } from './components/ui/Breadcrumb/Breadcrumb.js';
@@ -77,8 +77,15 @@ export { Toggle } from './components/ui/Toggle/Toggle.js';
77
77
  export { ToggleGroup, ToggleGroupItem } from './components/ui/ToggleGroup/ToggleGroup.js';
78
78
  export { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from './components/ui/Tooltip/Tooltip.js';
79
79
  export { VimeoEmbed } from './components/ui/VimeoEmbed/VimeoEmbed.js';
80
+ export { WorkspaceAppSwitcher } from './components/ui/WorkspaceAppSwitcher/WorkspaceAppSwitcher.js';
81
+ export { WORKSPACE_APP_SLUG_BASE_PATH } from './components/ui/WorkspaceAppSwitcher/workspaceApp.types.js';
82
+ export { WORKSPACE_APPS_LS_KEY } from './components/ui/WorkspaceAppSwitcher/workspaceAppsConstants.js';
83
+ export { readWorkspaceAppsFromLocalStorage, writeWorkspaceAppsToLocalStorage } from './components/ui/WorkspaceAppSwitcher/workspaceAppsLocalStorage.js';
84
+ export { WORKSPACE_APP_ICONS, isWorkspaceAppIconKey } from './components/ui/WorkspaceAppSwitcher/workspaceAppIcons.js';
85
+ export { findWorkspaceAppByPathname, workspaceAppSlugPath } from './components/ui/WorkspaceAppSwitcher/workspaceAppPaths.js';
80
86
  export { SidebarDatasetsItemsGrouped } from './components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js';
81
87
  export { groupSidebarDatasets } from './components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.js';
88
+ export { SybilionAppHeader } from './components/widgets/SybilionAppHeader/SybilionAppHeader.js';
82
89
  export { ChartTooltipItem } from './components/ui/Chart/components/ChartTooltipItem.js';
83
90
  export { ChartLegendItem } from './components/ui/Chart/components/ChartLegendItem.js';
84
91
  export { CustomChartLegend } from './components/ui/Chart/components/CustomChartLegend/CustomChartLegend.js';
@@ -1,2 +1,4 @@
1
1
  /** DOM anchor id for portaling page-level header actions into `AppHeader`. */
2
2
  export declare const PAGE_HEADER_ID = "page-header";
3
+ /** DOM id for `#page-header-actions`; `AppHeaderActions` portaling target. */
4
+ export declare const PAGE_HEADER_ACTIONS_ID = "page-header-actions";
@@ -1,3 +1,3 @@
1
1
  export type { AppHeaderProps, AppHeaderPortalProps } from './AppHeader';
2
2
  export { AppHeaderHost, AppHeaderPortal } from './AppHeader';
3
- export { PAGE_HEADER_ID } from './appChromeAnchors';
3
+ export { PAGE_HEADER_ACTIONS_ID, PAGE_HEADER_ID } from './appChromeAnchors';
@@ -0,0 +1,12 @@
1
+ import type { WorkspaceAppEntry } from '#uilib/components/ui/WorkspaceAppSwitcher/workspaceApp.types';
2
+ export type WorkspaceAppSwitcherProps = {
3
+ pathname: string;
4
+ onNavigate: (href: string) => void;
5
+ /** When false, renders nothing (host maps from auth Loading + signed-in). */
6
+ authenticated?: boolean;
7
+ /** Fallback when localStorage missing/invalid/unset — keep referentially stable across renders where possible */
8
+ defaultApps?: WorkspaceAppEntry[];
9
+ /** When set, read apps from localStorage (`readWorkspaceAppsFromLocalStorage`). */
10
+ appsStorageKey?: string;
11
+ };
12
+ export declare function WorkspaceAppSwitcher({ pathname, onNavigate, authenticated, defaultApps, appsStorageKey, }: WorkspaceAppSwitcherProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ export { WorkspaceAppSwitcher, type WorkspaceAppSwitcherProps, } from './WorkspaceAppSwitcher';
2
+ export type { WorkspaceAppEntry } from './workspaceApp.types';
3
+ export { WORKSPACE_APP_SLUG_BASE_PATH } from './workspaceApp.types';
4
+ export { WORKSPACE_APPS_LS_KEY } from './workspaceAppsConstants';
5
+ export { readWorkspaceAppsFromLocalStorage, writeWorkspaceAppsToLocalStorage, } from './workspaceAppsLocalStorage';
6
+ export { WORKSPACE_APP_ICONS, type WorkspaceAppIconKey, isWorkspaceAppIconKey, } from './workspaceAppIcons';
7
+ export { findWorkspaceAppByPathname, workspaceAppSlugPath, } from './workspaceAppPaths';
@@ -0,0 +1,19 @@
1
+ import type { WorkspaceAppIconKey } from './workspaceAppIcons';
2
+ /** Path segment for slug apps: pathname matches `/apps/{id}` */
3
+ export declare const WORKSPACE_APP_SLUG_BASE_PATH = "/apps";
4
+ /** One surface in the workspace app switcher (serializable for localStorage). */
5
+ export type WorkspaceAppEntry = {
6
+ /** Slug (e.g. `my-custom-app` → `https://sybilion.io/apps/my-custom-app` via `href`). */
7
+ id: string;
8
+ displayName: string;
9
+ subtitle: string;
10
+ iconKey: WorkspaceAppIconKey;
11
+ accent: string;
12
+ accentMuted: string;
13
+ href: string;
14
+ /**
15
+ * Optional. Native / multi-route shells: match current app by pathname prefix.
16
+ * Omit for custom apps deployed under a single slug (`/apps/{id}` only).
17
+ */
18
+ matchPathPrefixes?: readonly string[];
19
+ };
@@ -0,0 +1,9 @@
1
+ import type { ComponentType } from 'react';
2
+ type IconLike = ComponentType<{
3
+ className?: string;
4
+ 'aria-hidden'?: boolean;
5
+ }>;
6
+ export type WorkspaceAppIconKey = 'grid-four' | 'clock' | 'boat' | 'package' | 'tree-structure';
7
+ export declare const WORKSPACE_APP_ICONS: Record<WorkspaceAppIconKey, IconLike>;
8
+ export declare function isWorkspaceAppIconKey(v: string): v is WorkspaceAppIconKey;
9
+ export {};
@@ -0,0 +1,3 @@
1
+ import type { WorkspaceAppEntry } from './workspaceApp.types';
2
+ export declare function workspaceAppSlugPath(id: string): string;
3
+ export declare function findWorkspaceAppByPathname(pathname: string, apps: readonly WorkspaceAppEntry[]): WorkspaceAppEntry | null;
@@ -0,0 +1,2 @@
1
+ /** localStorage key for workspace app list JSON (shared by host app + demos). */
2
+ export declare const WORKSPACE_APPS_LS_KEY = "sybilion.workspaceApps.v1";
@@ -0,0 +1,6 @@
1
+ import type { WorkspaceAppEntry } from './workspaceApp.types';
2
+ /**
3
+ * Read validated workspace apps JSON from localStorage; returns null if missing or invalid.
4
+ */
5
+ export declare function readWorkspaceAppsFromLocalStorage(key: string): WorkspaceAppEntry[] | null;
6
+ export declare function writeWorkspaceAppsToLocalStorage(key: string, apps: WorkspaceAppEntry[]): void;
@@ -0,0 +1,8 @@
1
+ import type { NavUserHeaderProps } from '#uilib/components/ui/NavUserHeader';
2
+ import { type WorkspaceAppSwitcherProps } from '#uilib/components/ui/WorkspaceAppSwitcher';
3
+ export type SybilionAppHeaderProps = WorkspaceAppSwitcherProps & NavUserHeaderProps & {
4
+ pageHeaderId?: string;
5
+ actionsAnchorId?: string;
6
+ actionsAnchorClassName?: string;
7
+ };
8
+ export declare function SybilionAppHeader({ pageHeaderId, actionsAnchorId, actionsAnchorClassName, pathname, onNavigate, authenticated, defaultApps, appsStorageKey, ...navUserHeaderProps }: SybilionAppHeaderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export { SybilionAppHeader, type SybilionAppHeaderProps, } from './SybilionAppHeader';
@@ -55,4 +55,6 @@ export * from './components/ui/Toggle';
55
55
  export * from './components/ui/ToggleGroup';
56
56
  export * from './components/ui/Tooltip';
57
57
  export * from './components/ui/VimeoEmbed';
58
+ export * from './components/ui/WorkspaceAppSwitcher';
58
59
  export * from './components/widgets/SidebarDatasetsItemsGrouped';
60
+ export * from './components/widgets/SybilionAppHeader';