@treasuryspatial/viewer-ui-kit 0.1.42 → 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 (89) 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 +133 -33
  15. package/dist/LoginShell.d.ts +2 -1
  16. package/dist/LoginShell.d.ts.map +1 -1
  17. package/dist/LoginShell.js +26 -3
  18. package/dist/ManifestTopBar.d.ts +7 -1
  19. package/dist/ManifestTopBar.d.ts.map +1 -1
  20. package/dist/ManifestTopBar.js +249 -38
  21. package/dist/MetricsPanel.d.ts +1 -1
  22. package/dist/MetricsPanel.d.ts.map +1 -1
  23. package/dist/MetricsPanel.js +19 -29
  24. package/dist/MetricsPanelContent.d.ts +38 -17
  25. package/dist/MetricsPanelContent.d.ts.map +1 -1
  26. package/dist/MetricsPanelContent.js +84 -90
  27. package/dist/ModeBar.d.ts +6 -2
  28. package/dist/ModeBar.d.ts.map +1 -1
  29. package/dist/ModeBar.js +49 -82
  30. package/dist/ModuleSelectorPanel.d.ts +2 -1
  31. package/dist/ModuleSelectorPanel.d.ts.map +1 -1
  32. package/dist/ModuleSelectorPanel.js +47 -49
  33. package/dist/PanelSkin.d.ts.map +1 -1
  34. package/dist/PanelSkin.js +1598 -312
  35. package/dist/PanelSystem.d.ts +45 -0
  36. package/dist/PanelSystem.d.ts.map +1 -0
  37. package/dist/PanelSystem.js +450 -0
  38. package/dist/PanelTabs.d.ts.map +1 -1
  39. package/dist/PanelTabs.js +8 -34
  40. package/dist/PanelToggleDock.d.ts +10 -0
  41. package/dist/PanelToggleDock.d.ts.map +1 -0
  42. package/dist/PanelToggleDock.js +40 -0
  43. package/dist/PromptPackChooserPanel.d.ts +12 -11
  44. package/dist/PromptPackChooserPanel.d.ts.map +1 -1
  45. package/dist/PromptPackChooserPanel.js +103 -63
  46. package/dist/SceneInspectorPanel.d.ts +42 -0
  47. package/dist/SceneInspectorPanel.d.ts.map +1 -0
  48. package/dist/SceneInspectorPanel.js +135 -0
  49. package/dist/ScienceDataPanelContent.d.ts +16 -0
  50. package/dist/ScienceDataPanelContent.d.ts.map +1 -0
  51. package/dist/ScienceDataPanelContent.js +31 -0
  52. package/dist/ScienceMetricsPanelContent.d.ts +53 -0
  53. package/dist/ScienceMetricsPanelContent.d.ts.map +1 -0
  54. package/dist/ScienceMetricsPanelContent.js +415 -0
  55. package/dist/SpatialHud.d.ts +18 -0
  56. package/dist/SpatialHud.d.ts.map +1 -0
  57. package/dist/SpatialHud.js +120 -0
  58. package/dist/StreetviewModeSurface.d.ts +40 -0
  59. package/dist/StreetviewModeSurface.d.ts.map +1 -0
  60. package/dist/StreetviewModeSurface.js +358 -0
  61. package/dist/SurfaceSwitcher.d.ts +11 -0
  62. package/dist/SurfaceSwitcher.d.ts.map +1 -0
  63. package/dist/SurfaceSwitcher.js +46 -0
  64. package/dist/TopBar.d.ts +2 -0
  65. package/dist/TopBar.d.ts.map +1 -1
  66. package/dist/TopBar.js +3 -1
  67. package/dist/UnknownModeSurface.d.ts +6 -0
  68. package/dist/UnknownModeSurface.d.ts.map +1 -0
  69. package/dist/UnknownModeSurface.js +41 -0
  70. package/dist/index.d.ts +19 -0
  71. package/dist/index.d.ts.map +1 -1
  72. package/dist/index.js +12 -0
  73. package/dist/landingTokens.d.ts +7 -0
  74. package/dist/landingTokens.d.ts.map +1 -0
  75. package/dist/landingTokens.js +6 -0
  76. package/dist/layout.d.ts +27 -27
  77. package/dist/layout.d.ts.map +1 -1
  78. package/dist/layout.js +33 -27
  79. package/dist/mapMetrics.d.ts +88 -0
  80. package/dist/mapMetrics.d.ts.map +1 -0
  81. package/dist/mapMetrics.js +1 -0
  82. package/dist/panelPrimitives.d.ts +11 -0
  83. package/dist/panelPrimitives.d.ts.map +1 -0
  84. package/dist/panelPrimitives.js +41 -0
  85. package/dist/topbarLogoPolicy.d.ts +14 -0
  86. package/dist/topbarLogoPolicy.d.ts.map +1 -0
  87. package/dist/topbarLogoPolicy.js +41 -0
  88. package/dist/tsconfig.tsbuildinfo +1 -1
  89. package/package.json +18 -5
@@ -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"}
@@ -2,6 +2,7 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useMemo, useState } from 'react';
4
4
  import styled from 'styled-components';
5
+ import { panelEyebrowCss, panelPillButtonCss, panelSectionTitleCss } from './panelPrimitives.js';
5
6
  const Panel = styled.div `
6
7
  position: fixed;
7
8
  right: 0;
@@ -9,9 +10,9 @@ const Panel = styled.div `
9
10
  transform: translateY(-50%) ${(props) => (props.$visible ? 'translateX(0)' : 'translateX(100%)')};
10
11
  width: var(--ui-metrics-width);
11
12
  height: 70vh;
12
- background: rgba(255, 255, 255, 0.96);
13
- border-left: 1px solid var(--brand-panel-border);
14
- box-shadow: 0 16px 32px rgba(15, 23, 42, 0.12);
13
+ background: var(--viewer-ui-color-surface);
14
+ border-left: 1px solid var(--viewer-ui-color-panel-border);
15
+ box-shadow: none;
15
16
  transition: transform 0.3s ease;
16
17
  z-index: 40;
17
18
  display: flex;
@@ -19,14 +20,12 @@ const Panel = styled.div `
19
20
  `;
20
21
  const Header = styled.div `
21
22
  padding: 16px 20px;
22
- border-bottom: 1px solid var(--brand-panel-border);
23
+ border-bottom: 1px solid var(--viewer-ui-color-panel-border);
23
24
  display: flex;
24
25
  align-items: center;
25
26
  justify-content: space-between;
26
- font-size: 11px;
27
- text-transform: uppercase;
28
- letter-spacing: 0.08em;
29
- color: var(--brand-text-secondary);
27
+ ${panelEyebrowCss}
28
+ color: var(--viewer-ui-color-text-muted);
30
29
  `;
31
30
  const TabRow = styled.div `
32
31
  display: flex;
@@ -34,13 +33,10 @@ const TabRow = styled.div `
34
33
  padding: 12px 20px 0;
35
34
  `;
36
35
  const TabButton = styled.button `
37
- border-radius: 999px;
38
- padding: 6px 12px;
39
- font-size: 11px;
40
- text-transform: lowercase;
41
- border: none;
42
- background: ${(props) => (props.$active ? 'var(--brand-primary)' : 'rgba(15, 23, 42, 0.08)')};
43
- color: ${(props) => (props.$active ? '#ffffff' : 'var(--brand-text-secondary)')};
36
+ ${panelPillButtonCss}
37
+ min-height: 30px;
38
+ padding: 0 12px;
39
+ font-size: 10px;
44
40
  cursor: pointer;
45
41
  `;
46
42
  const Body = styled.div `
@@ -57,21 +53,18 @@ const MetricGrid = styled.div `
57
53
  gap: 12px;
58
54
  `;
59
55
  const MetricCard = styled.div `
60
- border-radius: 12px;
61
- border: 1px solid var(--brand-panel-border);
56
+ border-radius: 8px;
57
+ border: 1px solid var(--viewer-ui-color-panel-border-subtle);
62
58
  padding: 8px 10px;
63
- background: rgba(15, 23, 42, 0.04);
59
+ background: var(--viewer-ui-color-surface);
64
60
  `;
65
61
  const MetricLabel = styled.div `
66
- font-size: 10px;
67
- text-transform: uppercase;
68
- letter-spacing: 0.08em;
69
- color: var(--brand-text-secondary);
62
+ ${panelEyebrowCss}
70
63
  `;
71
64
  const MetricValue = styled.div `
72
65
  font-size: 13px;
73
66
  font-weight: 600;
74
- color: var(--brand-text-primary);
67
+ color: var(--viewer-ui-color-text-strong);
75
68
  `;
76
69
  const ToggleWrapper = styled.div `
77
70
  position: fixed;
@@ -83,13 +76,10 @@ const ToggleWrapper = styled.div `
83
76
  `;
84
77
  const Divider = styled.div `
85
78
  height: 1px;
86
- background: var(--brand-panel-border);
79
+ background: var(--viewer-ui-color-panel-border-subtle);
87
80
  `;
88
81
  const SectionTitle = styled.div `
89
- font-size: 12px;
90
- text-transform: uppercase;
91
- letter-spacing: 0.08em;
92
- color: var(--brand-text-secondary);
82
+ ${panelSectionTitleCss}
93
83
  `;
94
84
  export default function MetricsPanel({ isVisible, onToggle, distanceToFloor, distanceToCeiling, distanceToNorth, distanceToSouth, distanceToEast, distanceToWest, compassAngle, pitchAngle, moduleLabel, moduleSummary, renderInputs, }) {
95
85
  const [activeTab, setActiveTab] = useState('inputs');
@@ -103,5 +93,5 @@ export default function MetricsPanel({ isVisible, onToggle, distanceToFloor, dis
103
93
  { label: 'compass', value: `${compassAngle.toFixed(1)} deg` },
104
94
  { label: 'pitch', value: `${pitchAngle.toFixed(1)} deg` },
105
95
  ], [distanceToFloor, distanceToCeiling, distanceToNorth, distanceToSouth, distanceToEast, distanceToWest, compassAngle, pitchAngle]);
106
- return (_jsxs(_Fragment, { children: [_jsx(ToggleWrapper, { "$visible": isVisible, children: _jsx("button", { type: "button", onClick: onToggle, className: "collapse-toggle collapse-toggle--edge-right", title: isVisible ? 'Hide metrics' : 'Show metrics', children: isVisible ? (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", children: _jsx("path", { fillRule: "evenodd", d: "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", clipRule: "evenodd" }) })) : (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", children: _jsx("path", { fillRule: "evenodd", d: "M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z", clipRule: "evenodd" }) })) }) }), _jsxs(Panel, { "$visible": isVisible, children: [_jsxs(Header, { children: [_jsx("span", { children: "analytics" }), _jsx("span", { children: "live" })] }), _jsxs(TabRow, { children: [_jsx(TabButton, { type: "button", "$active": activeTab === 'inputs', onClick: () => setActiveTab('inputs'), children: "inputs" }), _jsx(TabButton, { type: "button", "$active": activeTab === 'outputs', onClick: () => setActiveTab('outputs'), children: "outputs" })] }), _jsxs(Body, { children: [activeTab === 'inputs' ? (_jsxs(_Fragment, { children: [moduleLabel ? (_jsxs("div", { children: [_jsx(SectionTitle, { children: "module" }), _jsx("div", { style: { fontSize: '16px', fontWeight: 600, marginTop: 6 }, children: moduleLabel }), moduleSummary ? (_jsx("div", { style: { fontSize: '12px', color: 'var(--brand-text-secondary)', marginTop: 6 }, children: moduleSummary })) : null] })) : null, renderInputs ? (_jsxs("div", { children: [_jsx(SectionTitle, { children: "render inputs" }), _jsx("div", { style: { marginTop: 8, fontSize: '12px', color: 'var(--brand-text-secondary)' }, children: renderInputs.presetLabel ? `Preset: ${renderInputs.presetLabel}` : 'Preset: default' }), renderInputs.presetSummary ? (_jsx("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--brand-text-secondary)' }, children: renderInputs.presetSummary })) : null, renderInputs.lightingRig ? (_jsxs("div", { style: { marginTop: 6, fontSize: '11px', color: 'var(--brand-text-secondary)' }, children: ["Lighting rig: ", renderInputs.lightingRig] })) : null, typeof renderInputs.toneMappingExposure === 'number' ? (_jsxs("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--brand-text-secondary)' }, children: ["Exposure: ", renderInputs.toneMappingExposure.toFixed(2)] })) : null, renderInputs.sky ? (_jsxs("div", { style: { marginTop: 8 }, children: [_jsx(SectionTitle, { children: "sky & environment" }), _jsxs("div", { style: { marginTop: 6, fontSize: '12px', color: 'var(--brand-text-secondary)' }, children: [renderInputs.sky.label, renderInputs.sky.mode ? ` · ${renderInputs.sky.mode}` : ''] }), renderInputs.sky.description ? (_jsx("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--brand-text-secondary)' }, children: renderInputs.sky.description })) : null, renderInputs.sky.src ? (_jsx("div", { style: { marginTop: 4, fontSize: '10px', color: 'var(--brand-text-secondary)' }, children: renderInputs.sky.src })) : null, typeof renderInputs.sky.exposure === 'number' ? (_jsxs("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--brand-text-secondary)' }, children: ["Sky exposure: ", renderInputs.sky.exposure.toFixed(2)] })) : null] })) : null] })) : null] })) : (_jsxs(_Fragment, { children: [_jsx(SectionTitle, { children: "spatial metrics" }), _jsx(MetricGrid, { children: metrics.map((metric) => (_jsxs(MetricCard, { children: [_jsx(MetricLabel, { children: metric.label }), _jsx(MetricValue, { children: metric.value })] }, metric.label))) })] })), _jsx(Divider, {})] })] })] }));
96
+ return (_jsxs(_Fragment, { children: [_jsx(ToggleWrapper, { "$visible": isVisible, children: _jsx("button", { type: "button", onClick: onToggle, className: "collapse-toggle collapse-toggle--edge-right", title: isVisible ? 'Hide metrics' : 'Show metrics', children: isVisible ? (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", children: _jsx("path", { fillRule: "evenodd", d: "M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z", clipRule: "evenodd" }) })) : (_jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", children: _jsx("path", { fillRule: "evenodd", d: "M12.707 5.293a1 1 0 010 1.414L9.414 10l3.293 3.293a1 1 0 01-1.414 1.414l-4-4a1 1 0 010-1.414l4-4a1 1 0 011.414 0z", clipRule: "evenodd" }) })) }) }), _jsxs(Panel, { "$visible": isVisible, children: [_jsxs(Header, { children: [_jsx("span", { children: "analytics" }), _jsx("span", { children: "live" })] }), _jsxs(TabRow, { children: [_jsx(TabButton, { type: "button", "$active": activeTab === 'inputs', onClick: () => setActiveTab('inputs'), children: "inputs" }), _jsx(TabButton, { type: "button", "$active": activeTab === 'outputs', onClick: () => setActiveTab('outputs'), children: "outputs" })] }), _jsxs(Body, { children: [activeTab === 'inputs' ? (_jsxs(_Fragment, { children: [moduleLabel ? (_jsxs("div", { children: [_jsx(SectionTitle, { children: "module" }), _jsx("div", { style: { fontSize: '16px', fontWeight: 600, marginTop: 6 }, children: moduleLabel }), moduleSummary ? (_jsx("div", { style: { fontSize: '12px', color: 'var(--viewer-ui-color-text-muted)', marginTop: 6 }, children: moduleSummary })) : null] })) : null, renderInputs ? (_jsxs("div", { children: [_jsx(SectionTitle, { children: "render inputs" }), _jsx("div", { style: { marginTop: 8, fontSize: '12px', color: 'var(--viewer-ui-color-text-muted)' }, children: renderInputs.presetLabel ? `Preset: ${renderInputs.presetLabel}` : 'Preset: default' }), renderInputs.presetSummary ? (_jsx("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--viewer-ui-color-text-muted)' }, children: renderInputs.presetSummary })) : null, renderInputs.lightingRig ? (_jsxs("div", { style: { marginTop: 6, fontSize: '11px', color: 'var(--viewer-ui-color-text-muted)' }, children: ["Lighting rig: ", renderInputs.lightingRig] })) : null, typeof renderInputs.toneMappingExposure === 'number' ? (_jsxs("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--viewer-ui-color-text-muted)' }, children: ["Exposure: ", renderInputs.toneMappingExposure.toFixed(2)] })) : null, renderInputs.sky ? (_jsxs("div", { style: { marginTop: 8 }, children: [_jsx(SectionTitle, { children: "sky & environment" }), _jsxs("div", { style: { marginTop: 6, fontSize: '12px', color: 'var(--viewer-ui-color-text-muted)' }, children: [renderInputs.sky.label, renderInputs.sky.mode ? ` · ${renderInputs.sky.mode}` : ''] }), renderInputs.sky.description ? (_jsx("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--viewer-ui-color-text-muted)' }, children: renderInputs.sky.description })) : null, renderInputs.sky.src ? (_jsx("div", { style: { marginTop: 4, fontSize: '10px', color: 'var(--viewer-ui-color-text-muted)' }, children: renderInputs.sky.src })) : null, typeof renderInputs.sky.exposure === 'number' ? (_jsxs("div", { style: { marginTop: 4, fontSize: '11px', color: 'var(--viewer-ui-color-text-muted)' }, children: ["Sky exposure: ", renderInputs.sky.exposure.toFixed(2)] })) : null] })) : null] })) : null] })) : (_jsxs(_Fragment, { children: [_jsx(SectionTitle, { children: "spatial metrics" }), _jsx(MetricGrid, { children: metrics.map((metric) => (_jsxs(MetricCard, { children: [_jsx(MetricLabel, { children: metric.label }), _jsx(MetricValue, { children: metric.value })] }, metric.label))) })] })), _jsx(Divider, {})] })] })] }));
107
97
  }
@@ -1,21 +1,42 @@
1
+ type MetricsFeedKind = 'runtime' | 'viewer' | 'geometry' | 'render' | 'map';
2
+ type ToolMetricDefinition = {
3
+ id: string;
4
+ label: string;
5
+ summary?: string;
6
+ source: {
7
+ kind: MetricsFeedKind;
8
+ path: string;
9
+ };
10
+ format?: 'text' | 'number' | 'count';
11
+ digits?: number;
12
+ prefix?: string;
13
+ suffix?: string;
14
+ emptyLabel?: string;
15
+ };
16
+ type ToolMetricGroupDefinition = {
17
+ id: string;
18
+ label: string;
19
+ summary?: string;
20
+ metrics: ToolMetricDefinition[];
21
+ };
22
+ type ToolMetricsDefinition = {
23
+ title?: string;
24
+ summary?: string;
25
+ groups: ToolMetricGroupDefinition[];
26
+ };
27
+ type ToolMetricsFeeds = Partial<Record<MetricsFeedKind, Record<string, unknown>>>;
1
28
  interface MetricsPanelContentProps {
2
- cameraMetrics: {
3
- position: {
4
- x: number;
5
- y: number;
6
- z: number;
7
- };
8
- heightAboveFloor: number;
9
- } | null;
10
- distanceToFloor: number;
11
- distanceToCeiling: number;
12
- distanceToNorth: number;
13
- distanceToSouth: number;
14
- distanceToEast: number;
15
- distanceToWest: number;
16
- compassAngle: number;
17
- pitchAngle: number;
29
+ modeId: string;
30
+ modeLabel: string;
31
+ moduleLabel?: string | null;
32
+ moduleSummary?: string | null;
33
+ promptPackLabel?: string | null;
34
+ promptPackDescription?: string | null;
35
+ renderCount?: number;
36
+ imageSetCount?: number;
37
+ toolMetrics?: ToolMetricsDefinition | null;
38
+ feeds?: ToolMetricsFeeds | null;
18
39
  }
19
- export default function MetricsPanelContent({ cameraMetrics, distanceToFloor, distanceToCeiling, distanceToNorth, distanceToSouth, distanceToEast, distanceToWest, compassAngle, pitchAngle, }: MetricsPanelContentProps): import("react/jsx-runtime").JSX.Element;
40
+ export default function MetricsPanelContent({ modeId, modeLabel, moduleLabel, moduleSummary, promptPackLabel, promptPackDescription, renderCount, imageSetCount, toolMetrics, feeds, }: MetricsPanelContentProps): import("react/jsx-runtime").JSX.Element;
20
41
  export {};
21
42
  //# sourceMappingURL=MetricsPanelContent.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"MetricsPanelContent.d.ts","sourceRoot":"","sources":["../src/MetricsPanelContent.tsx"],"names":[],"mappings":"AAIA,UAAU,wBAAwB;IAChC,aAAa,EAAE;QAAE,QAAQ,EAAE;YAAE,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAC;YAAC,CAAC,EAAE,MAAM,CAAA;SAAE,CAAC;QAAC,gBAAgB,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IAClG,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;CACpB;AAqED,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAC1C,aAAa,EACb,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,eAAe,EACf,cAAc,EACd,cAAc,EACd,YAAY,EACZ,UAAU,GACX,EAAE,wBAAwB,2CAyD1B"}
1
+ {"version":3,"file":"MetricsPanelContent.d.ts","sourceRoot":"","sources":["../src/MetricsPanelContent.tsx"],"names":[],"mappings":"AAKA,KAAK,eAAe,GAAG,SAAS,GAAG,QAAQ,GAAG,UAAU,GAAG,QAAQ,GAAG,KAAK,CAAC;AAE5E,KAAK,oBAAoB,GAAG;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE;QACN,IAAI,EAAE,eAAe,CAAC;QACtB,IAAI,EAAE,MAAM,CAAC;KACd,CAAC;IACF,MAAM,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAC;IACrC,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAEF,KAAK,yBAAyB,GAAG;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,oBAAoB,EAAE,CAAC;CACjC,CAAC;AAEF,KAAK,qBAAqB,GAAG;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,yBAAyB,EAAE,CAAC;CACrC,CAAC;AAEF,KAAK,gBAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;AAElF,UAAU,wBAAwB;IAChC,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,eAAe,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAChC,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACtC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,qBAAqB,GAAG,IAAI,CAAC;IAC3C,KAAK,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CACjC;AAgED,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,EAC1C,MAAM,EACN,SAAS,EACT,WAAW,EACX,aAAa,EACb,eAAe,EACf,qBAAqB,EACrB,WAAe,EACf,aAAiB,EACjB,WAAW,EACX,KAAK,GACN,EAAE,wBAAwB,2CAwJ1B"}