@treasuryspatial/viewer-ui-kit 0.1.41 → 0.1.56

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 (90) hide show
  1. package/dist/AdminLayout.js +1 -1
  2. package/dist/AdminShell.d.ts +6 -1
  3. package/dist/AdminShell.d.ts.map +1 -1
  4. package/dist/AdminShell.js +45 -3
  5. package/dist/ChooserActionCard.d.ts +10 -0
  6. package/dist/ChooserActionCard.d.ts.map +1 -0
  7. package/dist/ChooserActionCard.js +39 -0
  8. package/dist/ComposerRightRail.d.ts +3 -1
  9. package/dist/ComposerRightRail.d.ts.map +1 -1
  10. package/dist/ComposerRightRail.js +11 -43
  11. package/dist/ConfiguratorShell.js +1 -1
  12. package/dist/LandingShell.d.ts +2 -1
  13. package/dist/LandingShell.d.ts.map +1 -1
  14. package/dist/LandingShell.js +162 -32
  15. package/dist/LoginForm.js +2 -2
  16. package/dist/LoginShell.d.ts +2 -1
  17. package/dist/LoginShell.d.ts.map +1 -1
  18. package/dist/LoginShell.js +38 -15
  19. package/dist/ManifestTopBar.d.ts +7 -1
  20. package/dist/ManifestTopBar.d.ts.map +1 -1
  21. package/dist/ManifestTopBar.js +249 -38
  22. package/dist/MetricsPanel.d.ts +1 -1
  23. package/dist/MetricsPanel.d.ts.map +1 -1
  24. package/dist/MetricsPanel.js +19 -29
  25. package/dist/MetricsPanelContent.d.ts +38 -17
  26. package/dist/MetricsPanelContent.d.ts.map +1 -1
  27. package/dist/MetricsPanelContent.js +84 -90
  28. package/dist/ModeBar.d.ts +6 -2
  29. package/dist/ModeBar.d.ts.map +1 -1
  30. package/dist/ModeBar.js +49 -82
  31. package/dist/ModuleSelectorPanel.d.ts +2 -1
  32. package/dist/ModuleSelectorPanel.d.ts.map +1 -1
  33. package/dist/ModuleSelectorPanel.js +47 -49
  34. package/dist/PanelSkin.d.ts.map +1 -1
  35. package/dist/PanelSkin.js +1598 -312
  36. package/dist/PanelSystem.d.ts +45 -0
  37. package/dist/PanelSystem.d.ts.map +1 -0
  38. package/dist/PanelSystem.js +450 -0
  39. package/dist/PanelTabs.d.ts.map +1 -1
  40. package/dist/PanelTabs.js +8 -34
  41. package/dist/PanelToggleDock.d.ts +10 -0
  42. package/dist/PanelToggleDock.d.ts.map +1 -0
  43. package/dist/PanelToggleDock.js +40 -0
  44. package/dist/PromptPackChooserPanel.d.ts +12 -11
  45. package/dist/PromptPackChooserPanel.d.ts.map +1 -1
  46. package/dist/PromptPackChooserPanel.js +103 -63
  47. package/dist/SceneInspectorPanel.d.ts +42 -0
  48. package/dist/SceneInspectorPanel.d.ts.map +1 -0
  49. package/dist/SceneInspectorPanel.js +135 -0
  50. package/dist/ScienceDataPanelContent.d.ts +16 -0
  51. package/dist/ScienceDataPanelContent.d.ts.map +1 -0
  52. package/dist/ScienceDataPanelContent.js +31 -0
  53. package/dist/ScienceMetricsPanelContent.d.ts +53 -0
  54. package/dist/ScienceMetricsPanelContent.d.ts.map +1 -0
  55. package/dist/ScienceMetricsPanelContent.js +415 -0
  56. package/dist/SpatialHud.d.ts +18 -0
  57. package/dist/SpatialHud.d.ts.map +1 -0
  58. package/dist/SpatialHud.js +120 -0
  59. package/dist/StreetviewModeSurface.d.ts +40 -0
  60. package/dist/StreetviewModeSurface.d.ts.map +1 -0
  61. package/dist/StreetviewModeSurface.js +358 -0
  62. package/dist/SurfaceSwitcher.d.ts +11 -0
  63. package/dist/SurfaceSwitcher.d.ts.map +1 -0
  64. package/dist/SurfaceSwitcher.js +46 -0
  65. package/dist/TopBar.d.ts +2 -0
  66. package/dist/TopBar.d.ts.map +1 -1
  67. package/dist/TopBar.js +3 -1
  68. package/dist/UnknownModeSurface.d.ts +6 -0
  69. package/dist/UnknownModeSurface.d.ts.map +1 -0
  70. package/dist/UnknownModeSurface.js +41 -0
  71. package/dist/index.d.ts +19 -0
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +12 -0
  74. package/dist/landingTokens.d.ts +7 -0
  75. package/dist/landingTokens.d.ts.map +1 -0
  76. package/dist/landingTokens.js +6 -0
  77. package/dist/layout.d.ts +27 -27
  78. package/dist/layout.d.ts.map +1 -1
  79. package/dist/layout.js +33 -27
  80. package/dist/mapMetrics.d.ts +88 -0
  81. package/dist/mapMetrics.d.ts.map +1 -0
  82. package/dist/mapMetrics.js +1 -0
  83. package/dist/panelPrimitives.d.ts +11 -0
  84. package/dist/panelPrimitives.d.ts.map +1 -0
  85. package/dist/panelPrimitives.js +41 -0
  86. package/dist/topbarLogoPolicy.d.ts +14 -0
  87. package/dist/topbarLogoPolicy.d.ts.map +1 -0
  88. package/dist/topbarLogoPolicy.js +41 -0
  89. package/dist/tsconfig.tsbuildinfo +1 -1
  90. package/package.json +18 -5
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import styled from 'styled-components';
4
4
  import ManifestTopBar from './ManifestTopBar.js';
5
5
  const Root = styled.main `
@@ -8,14 +8,14 @@ const Root = styled.main `
8
8
  color: var(--brand-text-primary);
9
9
  `;
10
10
  const Shell = styled.section `
11
- min-height: 100vh;
11
+ min-height: calc(100vh - var(--ui-nav-height));
12
12
  display: flex;
13
13
  align-items: center;
14
14
  justify-content: center;
15
- padding: calc(var(--ui-nav-height) + 40px) 24px 40px;
15
+ padding: calc(var(--ui-nav-height) + 16px) 32px 32px;
16
16
 
17
17
  @media (min-width: 768px) {
18
- padding: calc(var(--ui-nav-height) + 48px) 40px 48px;
18
+ padding: calc(var(--ui-nav-height) + 24px) 32px 32px;
19
19
  }
20
20
  `;
21
21
  const Inner = styled.div `
@@ -28,24 +28,44 @@ const Header = styled.header `
28
28
  const Title = styled.h1 `
29
29
  margin: 0;
30
30
  font-family: var(--ui-font-family, system-ui);
31
- font-size: clamp(44px, 7vw, 72px);
32
- line-height: 0.96;
33
- letter-spacing: -0.03em;
31
+ font-size: clamp(54px, 7vw, 72px);
32
+ line-height: 1;
33
+ letter-spacing: -0.02em;
34
34
  font-weight: 400;
35
35
  color: var(--brand-text-primary);
36
36
  `;
37
+ const TitleAccent = styled.span `
38
+ color: var(--brand-primary);
39
+ `;
37
40
  const Strap = styled.p `
38
41
  margin: 16px 0 0;
39
- max-width: 42ch;
42
+ max-width: 672px;
40
43
  font-size: 18px;
41
- line-height: 1.45;
44
+ line-height: 1.6;
42
45
  color: var(--brand-text-secondary);
43
46
  `;
47
+ function renderTitle(title, accentLabel) {
48
+ const normalizedTitle = title.trim();
49
+ const accent = accentLabel?.trim();
50
+ if (!normalizedTitle || !accent)
51
+ return normalizedTitle;
52
+ const titleLower = normalizedTitle.toLowerCase();
53
+ const accentLower = accent.toLowerCase();
54
+ if (titleLower === accentLower || !titleLower.endsWith(accentLower)) {
55
+ return normalizedTitle;
56
+ }
57
+ const accentStart = normalizedTitle.length - accent.length;
58
+ const prefix = normalizedTitle.slice(0, accentStart).trimEnd();
59
+ if (!prefix)
60
+ return normalizedTitle;
61
+ const separator = normalizedTitle.slice(prefix.length, accentStart) || ' ';
62
+ return (_jsxs(_Fragment, { children: [prefix, separator, _jsx(TitleAccent, { children: normalizedTitle.slice(accentStart) })] }));
63
+ }
44
64
  const Body = styled.p `
45
- margin: 18px 0 0;
46
- max-width: 52ch;
47
- font-size: 15px;
48
- line-height: 1.75;
65
+ margin: 20px 0 0;
66
+ max-width: 720px;
67
+ font-size: 16px;
68
+ line-height: 1.7;
49
69
  color: var(--brand-text-secondary);
50
70
  `;
51
71
  const Disclaimer = styled.p `
@@ -55,7 +75,10 @@ const Disclaimer = styled.p `
55
75
  line-height: 1.7;
56
76
  color: var(--brand-text-secondary);
57
77
  `;
58
- export default function LoginShell({ manifest, content, children, showLogout = false, showPoweredBy = false, className, }) {
78
+ export default function LoginShell({ manifest, content, subtitle, children, showLogout = false, showPoweredBy = false, className, }) {
59
79
  const fallbackHeading = `${manifest.topbar.title} ${manifest.surface?.label || manifest.topbar.productLabel}`.trim();
60
- return (_jsxs(Root, { className: className, children: [_jsx(ManifestTopBar, { manifest: manifest, variant: "landing", showPoweredBy: showPoweredBy, showLogout: showLogout }), _jsx(Shell, { children: _jsxs(Inner, { children: [_jsxs(Header, { children: [_jsx(Title, { children: content?.heading || fallbackHeading }), content?.strap ? _jsx(Strap, { children: content.strap }) : null, content?.body ? _jsx(Body, { children: content.body }) : null] }), children, content?.disclaimer ? _jsx(Disclaimer, { children: content.disclaimer }) : null] }) })] }));
80
+ const heading = content?.heading || fallbackHeading;
81
+ const displaySubtitle = subtitle || content?.strap;
82
+ const accentLabel = manifest.topbar.productLabel || null;
83
+ return (_jsxs(Root, { className: className, children: [_jsx(ManifestTopBar, { manifest: manifest, variant: "landing", topbarContext: "login", showPoweredBy: showPoweredBy, showLogout: showLogout }), _jsx(Shell, { children: _jsxs(Inner, { children: [_jsxs(Header, { children: [_jsx(Title, { children: renderTitle(heading, accentLabel) }), displaySubtitle ? _jsx(Strap, { children: displaySubtitle }) : null, content?.body ? _jsx(Body, { children: content.body }) : null] }), children, content?.disclaimer ? _jsx(Disclaimer, { children: content.disclaimer }) : null] }) })] }));
61
84
  }
@@ -1,13 +1,19 @@
1
+ import { type ReactNode } from 'react';
1
2
  import type { UiManifest } from '@treasuryspatial/ui-manifest';
3
+ export type ManifestTopBarContext = 'landing' | 'login' | 'composer' | 'admin';
2
4
  export type ManifestTopBarProps = {
3
5
  manifest: UiManifest;
4
6
  variant?: 'landing' | 'canvas';
7
+ topbarContext?: ManifestTopBarContext;
5
8
  showPoweredBy?: boolean;
6
9
  showLogout?: boolean;
7
10
  showSubtitle?: boolean;
11
+ hidden?: boolean;
12
+ center?: ReactNode;
13
+ bottomOverlay?: ReactNode;
8
14
  logoutCookieNames?: string[];
9
15
  logoutEndpoint?: string;
10
16
  logoutHref?: string;
11
17
  };
12
- export default function ManifestTopBar({ manifest, variant, showPoweredBy, showLogout, showSubtitle, logoutCookieNames, logoutEndpoint, logoutHref, }: ManifestTopBarProps): import("react/jsx-runtime").JSX.Element;
18
+ export default function ManifestTopBar({ manifest, variant, topbarContext, showPoweredBy, showLogout, showSubtitle, hidden, center, bottomOverlay, logoutCookieNames, logoutEndpoint, logoutHref, }: ManifestTopBarProps): import("react/jsx-runtime").JSX.Element;
13
19
  //# sourceMappingURL=ManifestTopBar.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ManifestTopBar.d.ts","sourceRoot":"","sources":["../src/ManifestTopBar.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAY/D,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AA+KF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,QAAQ,EACR,OAAkB,EAClB,aAAqB,EACrB,UAAkB,EAClB,YAAoB,EACpB,iBAAiB,EACjB,cAAmC,EACnC,UAAqB,GACtB,EAAE,mBAAmB,2CA+HrB"}
1
+ {"version":3,"file":"ManifestTopBar.d.ts","sourceRoot":"","sources":["../src/ManifestTopBar.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAwC,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAG7E,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAuB/D,MAAM,MAAM,qBAAqB,GAAG,SAAS,GAAG,OAAO,GAAG,UAAU,GAAG,OAAO,CAAC;AAE/E,MAAM,MAAM,mBAAmB,GAAG;IAChC,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,CAAC,EAAE,SAAS,GAAG,QAAQ,CAAC;IAC/B,aAAa,CAAC,EAAE,qBAAqB,CAAC;IACtC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC7B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AA6UF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,QAAQ,EACR,OAAkB,EAClB,aAAa,EACb,aAAqB,EACrB,UAAkB,EAClB,YAAoB,EACpB,MAAc,EACd,MAAM,EACN,aAAa,EACb,iBAAiB,EACjB,cAAmC,EACnC,UAAqB,GACtB,EAAE,mBAAmB,2CAiPrB"}
@@ -4,61 +4,187 @@ import { useEffect, useMemo, useRef, useState } from 'react';
4
4
  import Link from 'next/link';
5
5
  import { usePathname, useSearchParams } from 'next/navigation';
6
6
  import { buildLoginHref, useClientHydrated, useComposerAuthState, useSessionLogout, useSurfaceComposerData, } from '@treasuryspatial/viewer-react';
7
- import styled from 'styled-components';
7
+ import styled, { keyframes } from 'styled-components';
8
8
  import TopBar from './TopBar.js';
9
+ import { LANDING_LOGO_SIZE, LANDING_TITLE_SIZE, } from './landingTokens.js';
10
+ import { resolveVisibleTopbarSecondaryLogo } from './topbarLogoPolicy.js';
11
+ const drawTreasuryMark = keyframes `
12
+ to {
13
+ stroke-dashoffset: 0;
14
+ }
15
+ `;
9
16
  const BrandLink = styled(Link) `
10
17
  display: flex;
11
18
  align-items: center;
12
- gap: 14px;
19
+ gap: ${(props) => (props.$variant === 'landing' ? '10px' : '8px')};
13
20
  text-decoration: none;
14
21
  color: inherit;
15
22
  min-width: 0;
16
23
 
17
- &:hover {
18
- opacity: 0.75;
24
+ &:hover ${() => TreasuryMark} {
25
+ color: var(--brand-primary);
26
+ }
27
+ `;
28
+ const BrandLogoCluster = styled.div `
29
+ display: flex;
30
+ align-items: center;
31
+ gap: ${(props) => (props.$variant === 'landing' ? '10px' : '8px')};
32
+ flex-shrink: 0;
33
+ `;
34
+ const TreasuryMark = styled.svg `
35
+ width: ${(props) => (props.$variant === 'landing' ? LANDING_LOGO_SIZE : '31px')};
36
+ height: ${(props) => (props.$variant === 'landing' ? LANDING_LOGO_SIZE : '31px')};
37
+ margin-top: ${(props) => (props.$variant === 'landing' ? '6px' : '3px')};
38
+ color: var(--brand-text-primary);
39
+ transition: color 0.2s ease-in-out;
40
+ flex-shrink: 0;
41
+
42
+ path {
43
+ fill: none;
44
+ stroke: currentColor;
45
+ stroke-miterlimit: 3.86;
46
+ stroke-width: ${(props) => (props.$variant === 'landing' ? '27.4px' : '27.4px')};
47
+ stroke-dasharray: 243.60040283203125;
48
+ stroke-dashoffset: 243.60040283203125;
49
+ animation: ${drawTreasuryMark} 2s ease-out forwards;
19
50
  }
20
51
  `;
21
52
  const BrandLogo = styled.img `
22
- width: ${(props) => (props.$variant === 'landing' ? 'clamp(32px, 4vw + 8px, 64px)' : '32px')};
23
- height: ${(props) => (props.$variant === 'landing' ? 'clamp(32px, 4vw + 8px, 64px)' : '32px')};
53
+ width: ${(props) => (props.$variant === 'landing' ? LANDING_LOGO_SIZE : '28px')};
54
+ height: ${(props) => (props.$variant === 'landing' ? LANDING_LOGO_SIZE : '28px')};
55
+ object-fit: contain;
56
+ flex-shrink: 0;
57
+ `;
58
+ const BrandLogoDivider = styled.div `
59
+ width: 1px;
60
+ height: ${(props) => (props.$variant === 'landing' ? '28px' : '20px')};
61
+ background: var(--brand-panel-border);
62
+ opacity: 0.65;
63
+ flex-shrink: 0;
64
+ `;
65
+ const BrandSecondaryLogo = styled.img `
66
+ width: ${(props) => (props.$variant === 'landing' ? '30px' : '20px')};
67
+ height: ${(props) => (props.$variant === 'landing' ? '30px' : '20px')};
24
68
  object-fit: contain;
25
69
  flex-shrink: 0;
26
70
  `;
71
+ const BrandText = styled.div `
72
+ min-width: 0;
73
+ display: flex;
74
+ align-items: ${(props) => (props.$stacked ? 'center' : 'baseline')};
75
+ gap: ${(props) => (props.$stacked ? (props.$variant === 'landing' ? '12px' : '10px') : '0')};
76
+ `;
27
77
  const BrandTitle = styled.div `
28
78
  display: flex;
29
- align-items: baseline;
30
- gap: ${(props) => (props.$variant === 'landing' ? '8px' : '6px')};
31
- font-family: var(--ui-font-family, system-ui);
32
- font-size: ${(props) => (props.$variant === 'landing' ? 'clamp(18px, 2vw + 10px, 48px)' : '18px')};
33
- line-height: 1;
34
- white-space: nowrap;
79
+ flex-direction: ${(props) => (props.$stacked ? 'column' : 'row')};
80
+ align-items: ${(props) => (props.$stacked ? 'flex-start' : 'baseline')};
81
+ gap: ${(props) => (props.$stacked ? (props.$variant === 'landing' ? '4px' : '2px') : props.$variant === 'landing' ? '10px' : '6px')};
82
+ font-family: var(--viewer-ui-font-display, var(--ui-font-family, system-ui));
83
+ font-size: ${(props) => {
84
+ if (props.$stacked)
85
+ return props.$variant === 'landing' ? 'clamp(13px, 1.1vw + 7px, 18px)' : '11px';
86
+ return props.$variant === 'landing' ? LANDING_TITLE_SIZE : '16px';
87
+ }};
88
+ line-height: ${(props) => (props.$stacked ? '1.05' : '1')};
89
+ letter-spacing: ${(props) => (props.$stacked ? '-0.02em' : '-0.03em')};
90
+ min-width: 0;
91
+ max-width: ${(props) => (props.$stacked ? (props.$variant === 'landing' ? 'min(50vw, 560px)' : 'min(36vw, 420px)') : 'none')};
92
+ `;
93
+ const BrandTitleRow = styled.div `
94
+ display: flex;
95
+ align-items: ${(props) => (props.$stacked ? 'center' : 'baseline')};
96
+ gap: 6px;
97
+ min-width: 0;
35
98
  `;
36
99
  const BrandTenant = styled.span `
37
100
  color: var(--brand-text-primary);
38
101
  font-weight: 400;
102
+ font-size: ${(props) => (props.$stacked ? '1em' : 'inherit')};
103
+ white-space: nowrap;
104
+ overflow: hidden;
105
+ text-overflow: ellipsis;
39
106
  `;
40
107
  const BrandSurface = styled.span `
41
108
  color: var(--brand-primary);
42
109
  font-weight: 400;
110
+ font-family: var(--viewer-ui-font-display, var(--ui-font-family, system-ui));
111
+ font-size: ${(props) => {
112
+ if (props.$variant === 'landing')
113
+ return '1em';
114
+ return '16px';
115
+ }};
116
+ letter-spacing: 0;
117
+ text-transform: none;
118
+ line-height: 1;
119
+ white-space: nowrap;
120
+ overflow: hidden;
121
+ text-overflow: ellipsis;
122
+ `;
123
+ const BrandProductSuffix = styled.span `
124
+ color: var(--brand-text-primary);
125
+ font-weight: 400;
126
+ font-family: var(--viewer-ui-font-display, var(--ui-font-family, system-ui));
127
+ font-size: ${(props) => {
128
+ if (props.$variant === 'landing')
129
+ return '1em';
130
+ return '16px';
131
+ }};
132
+ letter-spacing: 0;
133
+ text-transform: none;
134
+ line-height: 1;
135
+ white-space: nowrap;
136
+ overflow: hidden;
137
+ text-overflow: ellipsis;
138
+ `;
139
+ const BrandSubtitle = styled.span `
140
+ color: var(--brand-text-secondary);
141
+ font-weight: 400;
142
+ font-size: ${(props) => (props.$variant === 'landing' ? '0.72em' : '11px')};
143
+ letter-spacing: 0.02em;
144
+ line-height: 1.1;
145
+ white-space: nowrap;
146
+ overflow: hidden;
147
+ text-overflow: ellipsis;
43
148
  `;
44
149
  const Actions = styled.div `
45
150
  display: flex;
46
151
  align-items: center;
47
- gap: ${(props) => (props.$variant === 'landing' ? '22px' : '16px')};
48
- font-size: ${(props) => (props.$variant === 'landing' ? '14px' : '13px')};
152
+ gap: ${(props) => (props.$variant === 'landing' ? '18px' : '16px')};
153
+ font-family: var(--viewer-ui-font-body, var(--ui-font-family, system-ui));
154
+ font-size: ${(props) => (props.$variant === 'landing' ? '16px' : '15px')};
155
+ font-weight: 400;
156
+ line-height: 1.45;
49
157
  min-width: 0;
50
158
  `;
51
159
  const NavLink = styled(Link) `
52
160
  color: ${(props) => (props.$active ? 'var(--brand-primary)' : 'var(--brand-text-primary)')};
53
161
  text-decoration: none;
54
162
  font-weight: 400;
163
+ text-transform: none;
164
+ white-space: nowrap;
165
+
166
+ &:hover {
167
+ color: var(--brand-primary);
168
+ }
169
+ `;
170
+ const NavAnchor = styled.a `
171
+ color: ${(props) => (props.$active ? 'var(--brand-primary)' : 'var(--brand-text-primary)')};
172
+ text-decoration: none;
173
+ font-weight: 400;
174
+ text-transform: none;
55
175
  white-space: nowrap;
56
176
 
57
177
  &:hover {
58
178
  color: var(--brand-primary);
59
179
  }
60
180
  `;
61
- const AuthButton = styled.button `
181
+ const AccountCluster = styled.div `
182
+ display: flex;
183
+ align-items: center;
184
+ gap: 12px;
185
+ min-width: 0;
186
+ `;
187
+ const AccountPrimaryAction = styled.button `
62
188
  border: none;
63
189
  background: transparent;
64
190
  color: var(--brand-text-primary);
@@ -69,39 +195,39 @@ const AuthButton = styled.button `
69
195
  white-space: nowrap;
70
196
  display: inline-grid;
71
197
  align-items: center;
72
- grid-template-areas: 'auth';
198
+ text-transform: none;
73
199
 
74
- &:hover {
75
- color: var(--brand-text-primary);
200
+ > span {
201
+ grid-area: 1 / 1;
202
+ transition: opacity 160ms ease, transform 160ms ease;
76
203
  }
77
204
 
78
- .auth-default,
79
- .auth-logout {
80
- grid-area: auth;
81
- transition: opacity 0.16s ease;
205
+ .account-primary-default {
206
+ opacity: 1;
82
207
  }
83
208
 
84
- .auth-logout {
209
+ .account-primary-hover {
85
210
  opacity: 0;
86
- visibility: hidden;
211
+ color: var(--brand-primary);
87
212
  }
88
213
 
89
- &:hover .auth-default,
90
- &:focus-visible .auth-default {
214
+ &:hover .account-primary-default,
215
+ &:focus-visible .account-primary-default {
91
216
  opacity: 0;
92
- visibility: hidden;
217
+ transform: translateY(-1px);
93
218
  }
94
219
 
95
- &:hover .auth-logout,
96
- &:focus-visible .auth-logout {
220
+ &:hover .account-primary-hover,
221
+ &:focus-visible .account-primary-hover {
97
222
  opacity: 1;
98
- visibility: visible;
223
+ transform: translateY(0);
99
224
  }
100
225
  `;
101
226
  const AuthLink = styled(Link) `
102
227
  color: var(--brand-text-primary);
103
228
  text-decoration: none;
104
229
  font-weight: 400;
230
+ text-transform: none;
105
231
  white-space: nowrap;
106
232
 
107
233
  &:hover {
@@ -166,26 +292,84 @@ const isRouteActive = (pathname, href) => {
166
292
  return pathname === '/';
167
293
  return pathname === routePath || pathname.startsWith(`${routePath}/`);
168
294
  };
169
- export default function ManifestTopBar({ manifest, variant = 'canvas', showPoweredBy = false, showLogout = false, showSubtitle = false, logoutCookieNames, logoutEndpoint = '/api/auth/logout', logoutHref = '/login', }) {
295
+ const isInternalHref = (href) => href.startsWith('/');
296
+ const isGalleryHref = (href) => {
297
+ if (!href)
298
+ return false;
299
+ const normalized = href.trim();
300
+ if (!normalized)
301
+ return false;
302
+ const path = normalized.split('?')[0] || normalized;
303
+ if (path === '/gallery' ||
304
+ path.startsWith('/gallery/') ||
305
+ path === '/composer/gallery' ||
306
+ path.startsWith('/composer/gallery/')) {
307
+ return true;
308
+ }
309
+ try {
310
+ const params = new URLSearchParams(normalized.split('?')[1] || '');
311
+ return params.get('mode') === 'gallery';
312
+ }
313
+ catch {
314
+ return false;
315
+ }
316
+ };
317
+ const isGalleryTopbarLink = (link) => link.route === 'gallery' || isGalleryHref(link.href);
318
+ export default function ManifestTopBar({ manifest, variant = 'canvas', topbarContext, showPoweredBy = false, showLogout = false, showSubtitle = false, hidden = false, center, bottomOverlay, logoutCookieNames, logoutEndpoint = '/api/auth/logout', logoutHref = '/login', }) {
170
319
  const pathname = usePathname();
171
320
  const searchParams = useSearchParams();
172
321
  const hydrated = useClientHydrated();
173
322
  const composerData = useSurfaceComposerData();
174
- const { auth } = useComposerAuthState();
323
+ const { auth, authHydrated } = useComposerAuthState();
175
324
  const [searchOpen, setSearchOpen] = useState(false);
176
325
  const [searchQuery, setSearchQuery] = useState('');
177
326
  const searchRef = useRef(null);
178
327
  const inputRef = useRef(null);
179
328
  const navigation = composerData.navigation;
329
+ const topbar = composerData.topbar;
330
+ const effectiveTopbarContext = topbarContext ?? (variant === 'landing' ? 'landing' : 'composer');
331
+ const contextTopbar = topbar?.contexts?.[effectiveTopbarContext];
180
332
  const introHref = navigation?.introHref || '/';
181
- const composeHref = navigation?.composeHref || composerData.routePolicy?.homeRoute || '/compose';
182
- const surfaceTitle = navigation?.surfaceTitle ||
333
+ const composeHref = navigation?.composeHref || composerData.routePolicy?.homeRoute || '/composer/compose';
334
+ const brandTitle = contextTopbar?.title || topbar?.title || manifest.topbar.title;
335
+ const surfaceSubtitle = contextTopbar?.subtitle ||
336
+ topbar?.subtitle ||
337
+ (showSubtitle ? manifest.topbar.subtitle : null);
338
+ const surfaceTitle = contextTopbar?.productLabel ||
339
+ topbar?.productLabel ||
340
+ navigation?.surfaceTitle ||
183
341
  composerData.title ||
184
342
  manifest.surface?.label ||
185
343
  manifest.topbar.productLabel ||
186
344
  'Composer';
345
+ const productSuffixLabel = contextTopbar?.productSuffixLabel ||
346
+ (effectiveTopbarContext === 'landing' || effectiveTopbarContext === 'login'
347
+ ? ''
348
+ : topbar?.productSuffixLabel || manifest.topbar.productSuffixLabel || '');
187
349
  const searchEnabled = navigation?.searchEnabled ?? true;
350
+ const displaySubtitle = Boolean(surfaceSubtitle) && (showSubtitle || Boolean(contextTopbar?.subtitle || topbar?.subtitle));
188
351
  const brandLogo = manifest.topbar.logo;
352
+ const treasuryNative = manifest.surface?.brandProfile === 'treasury-native';
353
+ const secondaryLogo = resolveVisibleTopbarSecondaryLogo({
354
+ primaryLogo: brandLogo,
355
+ subtenantLogo: manifest.topbar.subtenantLogo,
356
+ composerDataSecondaryLogo: topbar?.secondaryLogo,
357
+ manifestSecondaryLogo: manifest.topbar.secondaryLogo,
358
+ hasSubtenant: Boolean(composerData.subtenantSlug),
359
+ });
360
+ const manifestTopbarLinks = (manifest.topbar.links ?? []).map((link) => ({
361
+ label: link.label,
362
+ href: link.href,
363
+ ...(link.target ? { target: link.target } : {}),
364
+ }));
365
+ const topbarLinksSource = contextTopbar?.links ?? (topbar ? (topbar.links ?? []) : manifestTopbarLinks);
366
+ const topbarLinks = topbarLinksSource.filter((entry) => Boolean(entry?.label?.trim() && (entry?.route || entry?.href?.trim()) && !isGalleryTopbarLink(entry)));
367
+ const visibleLinks = topbarLinks.length > 0
368
+ ? topbarLinks
369
+ : [
370
+ { label: 'Introduction', route: 'intro' },
371
+ { label: 'Composer', route: 'compose' },
372
+ ];
189
373
  const loginHref = hydrated
190
374
  ? buildLoginHref({
191
375
  pathname,
@@ -215,19 +399,46 @@ export default function ManifestTopBar({ manifest, variant = 'canvas', showPower
215
399
  const authControl = useMemo(() => {
216
400
  if (!showLogout)
217
401
  return null;
402
+ if (!authHydrated)
403
+ return null;
218
404
  if (hydrated && auth.isAuthenticated) {
219
405
  const authLabel = formatDisplayName(auth.name || auth.user);
220
- return (_jsxs(AuthButton, { type: "button", onClick: handleLogout, "aria-label": "logout", children: [_jsx("span", { className: "auth-default", children: authLabel }), _jsx("span", { className: "auth-logout", children: "logout" })] }));
406
+ return (_jsx(AccountCluster, { children: _jsxs(AccountPrimaryAction, { type: "button", onClick: () => handleLogout(), "aria-label": "Logout", children: [_jsx("span", { className: "account-primary-default", children: authLabel }), _jsx("span", { className: "account-primary-hover", children: "Logout" })] }) }));
221
407
  }
222
408
  if (pathname === logoutHref)
223
409
  return null;
224
410
  return _jsx(AuthLink, { href: loginHref, children: "Login" });
225
- }, [auth.isAuthenticated, auth.name, auth.user, handleLogout, hydrated, loginHref, logoutHref, pathname, showLogout]);
226
- const actions = (_jsxs(Actions, { "$variant": variant, children: [_jsx(NavLink, { href: introHref, "$active": isRouteActive(pathname, introHref), children: "Introduction" }), _jsx(NavLink, { href: composeHref, "$active": isRouteActive(pathname, composeHref), children: "Compose" }), authControl, searchEnabled ? (_jsx(SearchWrap, { ref: searchRef, children: _jsx(SearchControl, { "$expanded": searchOpen, onClick: !searchOpen ? () => setSearchOpen(true) : undefined, children: searchOpen ? (_jsxs(_Fragment, { children: [_jsx(SearchInput, { ref: inputRef, type: "text", placeholder: "Search...", value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => {
411
+ }, [
412
+ auth.isAuthenticated,
413
+ auth.name,
414
+ auth.user,
415
+ authHydrated,
416
+ handleLogout,
417
+ hydrated,
418
+ loginHref,
419
+ logoutHref,
420
+ pathname,
421
+ showLogout,
422
+ ]);
423
+ const actions = (_jsxs(Actions, { "$variant": variant, children: [visibleLinks.map((link) => (() => {
424
+ const resolvedHref = link.route === 'intro'
425
+ ? introHref
426
+ : link.route === 'compose'
427
+ ? composeHref
428
+ : link.href;
429
+ if (!resolvedHref)
430
+ return null;
431
+ if (isGalleryHref(resolvedHref))
432
+ return null;
433
+ if (isInternalHref(resolvedHref) && isRouteActive(pathname, resolvedHref))
434
+ return null;
435
+ return isInternalHref(resolvedHref) ? (_jsx(NavLink, { href: resolvedHref, "$active": isRouteActive(pathname, resolvedHref), children: link.label }, `${link.label}:${resolvedHref}`)) : (_jsx(NavAnchor, { href: resolvedHref, target: link.target === '_blank' ? '_blank' : undefined, rel: link.target === '_blank' ? 'noreferrer' : undefined, "$active": false, children: link.label }, `${link.label}:${resolvedHref}`));
436
+ })()), authControl, searchEnabled ? (_jsx(SearchWrap, { ref: searchRef, children: _jsx(SearchControl, { "$expanded": searchOpen, onClick: !searchOpen ? () => setSearchOpen(true) : undefined, children: searchOpen ? (_jsxs(_Fragment, { children: [_jsx(SearchInput, { ref: inputRef, type: "text", placeholder: "Search...", value: searchQuery, onChange: (event) => setSearchQuery(event.target.value), onClick: (event) => event.stopPropagation(), onKeyDown: (event) => {
227
437
  if (event.key === 'Escape') {
228
438
  setSearchOpen(false);
229
439
  setSearchQuery('');
230
440
  }
231
441
  } }), searchQuery ? _jsx(SearchReset, { onClick: () => setSearchQuery(''), children: "\u00D7" }) : null] })) : null }) })) : null] }));
232
- return (_jsx(TopBar, { compact: variant === 'canvas', hidden: false, brand: _jsxs(BrandLink, { href: introHref, children: [brandLogo?.src ? _jsx(BrandLogo, { "$variant": variant, src: brandLogo.src, alt: brandLogo.alt }) : null, _jsxs("div", { children: [_jsxs(BrandTitle, { "$variant": variant, children: [_jsx(BrandTenant, { children: manifest.topbar.title }), _jsx(BrandSurface, { children: surfaceTitle })] }), showSubtitle && manifest.topbar.subtitle ? _jsx("div", { children: manifest.topbar.subtitle }) : null] })] }), center: showPoweredBy ? null : null, actions: actions }));
442
+ const centerSlot = center ?? (showPoweredBy ? null : null);
443
+ return (_jsx(TopBar, { compact: variant === 'canvas', hidden: hidden, brand: _jsxs(BrandLink, { href: introHref, "$variant": variant, children: [_jsxs(BrandLogoCluster, { "$variant": variant, children: [treasuryNative && !brandLogo?.src ? (_jsxs(TreasuryMark, { "$variant": variant, xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 268.52 268.01", "aria-hidden": "true", children: [_jsx("path", { d: "M289.12,263.83l-.29,70.25c0,46.25-26.29,63.78-65.48,63.78H154.81", transform: "translate(-154.81 -263.78)" }), _jsx("path", { d: "M289,531.73l.29-70.24c0-46.25,26.29-63.78,65.49-63.78h68.53", transform: "translate(-154.81 -263.78)" })] })) : brandLogo?.src ? (_jsx(BrandLogo, { "$variant": variant, src: brandLogo.src, alt: brandLogo.alt })) : null, brandLogo?.src && secondaryLogo?.src ? (_jsxs(_Fragment, { children: [_jsx(BrandLogoDivider, { "$variant": variant }), _jsx(BrandSecondaryLogo, { "$variant": variant, src: secondaryLogo.src, alt: secondaryLogo.alt })] })) : null] }), _jsxs(BrandText, { "$variant": variant, "$stacked": displaySubtitle, children: [_jsx(BrandTitle, { "$variant": variant, "$stacked": displaySubtitle, children: displaySubtitle ? (_jsxs(_Fragment, { children: [_jsx(BrandTitleRow, { "$stacked": true, children: _jsx(BrandTenant, { "$stacked": true, children: brandTitle }) }), _jsx(BrandTitleRow, { "$stacked": true, children: _jsx(BrandSubtitle, { "$variant": variant, children: surfaceSubtitle }) })] })) : (_jsxs(BrandTitleRow, { children: [_jsx(BrandTenant, { children: brandTitle }), surfaceTitle ? _jsx(BrandSurface, { "$variant": variant, children: surfaceTitle }) : null, productSuffixLabel ? (_jsx(BrandProductSuffix, { "$variant": variant, children: productSuffixLabel })) : null] })) }), displaySubtitle && surfaceTitle ? (_jsxs(BrandTitleRow, { children: [_jsx(BrandSurface, { "$variant": variant, children: surfaceTitle }), productSuffixLabel ? (_jsx(BrandProductSuffix, { "$variant": variant, children: productSuffixLabel })) : null] })) : null] })] }), center: centerSlot, actions: actions, bottomOverlay: bottomOverlay }));
233
444
  }
@@ -8,7 +8,7 @@ export interface RenderInputSummary {
8
8
  id: string;
9
9
  label: string;
10
10
  description?: string;
11
- mode?: 'gradient' | 'hdr' | 'cube' | 'none';
11
+ mode?: 'gradient' | 'hdr' | 'image' | 'cube' | 'none';
12
12
  src?: string;
13
13
  exposure?: number;
14
14
  } | null;
@@ -1 +1 @@
1
- {"version":3,"file":"MetricsPanel.d.ts","sourceRoot":"","sources":["../src/MetricsPanel.tsx"],"names":[],"mappings":"AAKA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,MAAM,CAAC;QAC5C,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;CACV;AAED,UAAU,iBAAiB;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC1C;AAuGD,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,SAAS,EACT,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACZ,UAAU,EACV,WAAW,EACX,aAAa,EACb,YAAY,GACb,EAAE,iBAAiB,2CAwInB"}
1
+ {"version":3,"file":"MetricsPanel.d.ts","sourceRoot":"","sources":["../src/MetricsPanel.tsx"],"names":[],"mappings":"AAOA,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,GAAG,CAAC,EAAE;QACJ,EAAE,EAAE,MAAM,CAAC;QACX,KAAK,EAAE,MAAM,CAAC;QACd,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,IAAI,CAAC,EAAE,UAAU,GAAG,KAAK,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;QACtD,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,GAAG,IAAI,CAAC;CACV;AAED,UAAU,iBAAiB;IACzB,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,eAAe,EAAE,MAAM,CAAC;IACxB,iBAAiB,EAAE,MAAM,CAAC;IAC1B,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,MAAM,CAAC;IACxB,cAAc,EAAE,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,kBAAkB,GAAG,IAAI,CAAC;CAC1C;AA4FD,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,SAAS,EACT,QAAQ,EACR,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACZ,UAAU,EACV,WAAW,EACX,aAAa,EACb,YAAY,GACb,EAAE,iBAAiB,2CAwInB"}