@treasuryspatial/viewer-ui-kit 0.1.33 → 0.1.36

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.
@@ -1 +1 @@
1
- {"version":3,"file":"ComposerRightRail.d.ts","sourceRoot":"","sources":["../src/ComposerRightRail.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,SAAS,EACT,QAAQ,EACR,SAAS,EACT,WAAW,EACX,IAAI,EACJ,KAAsB,EACtB,WAAoB,GACrB,EAAE,sBAAsB,2CAiExB"}
1
+ {"version":3,"file":"ComposerRightRail.d.ts","sourceRoot":"","sources":["../src/ComposerRightRail.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAOvC,MAAM,MAAM,oBAAoB,GAAG;IACjC,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,CAAC;CACpB,CAAC;AAEF,KAAK,sBAAsB,GAAG;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,IAAI,EAAE,oBAAoB,EAAE,CAAC;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,SAAS,EACT,QAAQ,EACR,SAAS,EACT,WAAW,EACX,IAAI,EACJ,KAAsB,EACtB,WAAoB,GACrB,EAAE,sBAAsB,2CAmExB"}
@@ -3,7 +3,8 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
3
3
  import { RightPanel, RightPanelCollapseToggle, RightPanelShowToggle, } from './layout.js';
4
4
  export default function ComposerRightRail({ isVisible, onToggle, activeTab, onTabChange, tabs, title = 'image system', statusLabel = 'live', }) {
5
5
  const active = tabs.find((tab) => tab.id === activeTab) ?? tabs[0] ?? null;
6
- return (_jsxs(_Fragment, { children: [isVisible ? (_jsxs(RightPanel, { "$open": isVisible, children: [_jsx(RightPanelCollapseToggle, { type: "button", onClick: onToggle, "aria-label": "Hide right panel", title: "Hide right panel", children: _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" }) }) }), _jsxs("div", { className: "border-b viewer-ui-kit-border px-5 py-4", children: [_jsxs("div", { className: "flex items-center justify-between gap-3 text-[11px] uppercase tracking-[0.14em] viewer-ui-kit-text-subtle", children: [_jsx("span", { children: title }), _jsx("span", { children: statusLabel })] }), _jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: tabs.map((tab) => (_jsx("button", { type: "button", onClick: () => onTabChange(tab.id), className: `rounded-full px-3.5 py-2.5 text-[12px] font-neusa font-black lowercase tracking-[0.06em] whitespace-nowrap transition border ${active?.id === tab.id
6
+ const hasStatus = Boolean(statusLabel && statusLabel.trim().length > 0);
7
+ return (_jsxs(_Fragment, { children: [isVisible ? (_jsxs(RightPanel, { "$open": isVisible, children: [_jsx(RightPanelCollapseToggle, { type: "button", onClick: onToggle, "aria-label": "Hide right panel", title: "Hide right panel", children: _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" }) }) }), _jsxs("div", { className: "border-b viewer-ui-kit-border px-5 py-4", children: [_jsxs("div", { className: "flex items-center gap-2 text-[11px] uppercase tracking-[0.14em] viewer-ui-kit-text-subtle", children: [_jsx("span", { children: title }), hasStatus ? _jsx("span", { "aria-hidden": "true", children: "/" }) : null, hasStatus ? _jsx("span", { children: statusLabel }) : null] }), _jsx("div", { className: "mt-3 flex flex-wrap gap-2", children: tabs.map((tab) => (_jsx("button", { type: "button", onClick: () => onTabChange(tab.id), className: `rounded-full px-3.5 py-2.5 text-[12px] font-neusa font-black lowercase tracking-[0.06em] whitespace-nowrap transition border ${active?.id === tab.id
7
8
  ? 'bg-[var(--viewer-ui-color-toggle)] text-[var(--viewer-ui-color-toggle-text)] border-[var(--viewer-ui-color-toggle)]'
8
9
  : 'bg-[var(--viewer-ui-color-tab-bg)] text-[var(--viewer-ui-color-text-muted)] border-[var(--viewer-ui-color-panel-border-subtle)] hover:bg-[var(--viewer-ui-color-button-secondary)] hover:text-[var(--viewer-ui-color-text-strong)]'}`, children: tab.label }, tab.id))) })] }), _jsx("div", { className: "viewer-ui-shell-right-body flex-1 overflow-y-auto px-5 py-5", children: active?.content ?? null })] })) : null, !isVisible ? (_jsx(RightPanelShowToggle, { type: "button", onClick: onToggle, "aria-label": "Show right panel", title: "Show right panel", children: _jsx("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 20 20", fill: "currentColor", children: _jsx("path", { fillRule: "evenodd", d: "M12.707 14.707a1 1 0 010-1.414L9.414 10l3.293-3.293a1 1 0 00-1.414-1.414l-4 4a1 1 0 000 1.414l4 4a1 1 0 001.414 0z", clipRule: "evenodd" }) }) })) : null] }));
9
10
  }
@@ -1,11 +1,17 @@
1
1
  import type { ReactNode } from 'react';
2
+ import type { UiManifestImage, UiScaffoldShellMeta } from '@treasuryspatial/ui-manifest';
2
3
  type CustomModeSurfaceProps = {
3
4
  modeLabel: string;
4
5
  title: string;
5
6
  summary?: string;
6
7
  children: ReactNode;
7
8
  footer?: ReactNode;
9
+ badge?: string;
10
+ primaryLogo?: UiManifestImage;
11
+ secondaryLogo?: UiManifestImage;
12
+ meta?: UiScaffoldShellMeta[];
13
+ headerActions?: ReactNode;
8
14
  };
9
- export default function CustomModeSurface({ modeLabel, title, summary, children, footer, }: CustomModeSurfaceProps): import("react/jsx-runtime").JSX.Element;
15
+ export default function CustomModeSurface({ modeLabel, title, summary, children, footer, badge, primaryLogo, secondaryLogo, meta, headerActions, }: CustomModeSurfaceProps): import("react/jsx-runtime").JSX.Element;
10
16
  export {};
11
17
  //# sourceMappingURL=CustomModeSurface.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"CustomModeSurface.d.ts","sourceRoot":"","sources":["../src/CustomModeSurface.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAGvC,KAAK,sBAAsB,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;CACpB,CAAC;AA2EF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,SAAS,EACT,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,GACP,EAAE,sBAAsB,2CAcxB"}
1
+ {"version":3,"file":"CustomModeSurface.d.ts","sourceRoot":"","sources":["../src/CustomModeSurface.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,8BAA8B,CAAC;AAEzF,KAAK,sBAAsB,GAAG;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,SAAS,CAAC;IACpB,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,eAAe,CAAC;IAC9B,aAAa,CAAC,EAAE,eAAe,CAAC;IAChC,IAAI,CAAC,EAAE,mBAAmB,EAAE,CAAC;IAC7B,aAAa,CAAC,EAAE,SAAS,CAAC;CAC3B,CAAC;AA4HF,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EACxC,SAAS,EACT,KAAK,EACL,OAAO,EACP,QAAQ,EACR,MAAM,EACN,KAAK,EACL,WAAW,EACX,aAAa,EACb,IAAI,EACJ,aAAa,GACd,EAAE,sBAAsB,2CAmCxB"}
@@ -13,9 +13,8 @@ const SurfaceRoot = styled.section `
13
13
  grid-template-rows: auto 1fr auto;
14
14
  `;
15
15
  const SurfaceHeader = styled.header `
16
- display: flex;
17
- align-items: flex-end;
18
- justify-content: space-between;
16
+ display: grid;
17
+ grid-template-columns: minmax(0, 1fr) auto;
19
18
  gap: 18px;
20
19
  padding: 14px 18px 12px;
21
20
  border-bottom: 1px solid var(--viewer-ui-color-panel-border, #d8dee9);
@@ -27,6 +26,12 @@ const SurfaceMeta = styled.div `
27
26
  flex-direction: column;
28
27
  gap: 4px;
29
28
  `;
29
+ const SurfaceHeaderAside = styled.div `
30
+ display: flex;
31
+ align-items: flex-start;
32
+ justify-content: flex-end;
33
+ gap: 10px;
34
+ `;
30
35
  const ModePill = styled.span `
31
36
  display: inline-flex;
32
37
  align-items: center;
@@ -41,6 +46,20 @@ const ModePill = styled.span `
41
46
  border: 1px solid rgba(15, 23, 42, 0.16);
42
47
  background: rgba(255, 255, 255, 0.9);
43
48
  `;
49
+ const HeaderLogos = styled.div `
50
+ display: flex;
51
+ align-items: center;
52
+ gap: 8px;
53
+ `;
54
+ const HeaderLogo = styled.img `
55
+ width: 32px;
56
+ height: 32px;
57
+ object-fit: contain;
58
+ border-radius: 10px;
59
+ background: rgba(255, 255, 255, 0.84);
60
+ border: 1px solid rgba(15, 23, 42, 0.12);
61
+ padding: 4px;
62
+ `;
44
63
  const SurfaceTitle = styled.h3 `
45
64
  margin: 0;
46
65
  font-size: 18px;
@@ -55,6 +74,29 @@ const SurfaceSummary = styled.p `
55
74
  text-transform: lowercase;
56
75
  letter-spacing: 0.03em;
57
76
  `;
77
+ const SurfaceMetaRow = styled.dl `
78
+ margin: 2px 0 0;
79
+ display: flex;
80
+ flex-wrap: wrap;
81
+ gap: 12px;
82
+ `;
83
+ const SurfaceMetaItem = styled.div `
84
+ display: inline-flex;
85
+ align-items: baseline;
86
+ gap: 5px;
87
+ font-size: 11px;
88
+ color: #475569;
89
+ `;
90
+ const SurfaceMetaLabel = styled.dt `
91
+ margin: 0;
92
+ text-transform: uppercase;
93
+ letter-spacing: 0.08em;
94
+ color: #64748b;
95
+ `;
96
+ const SurfaceMetaValue = styled.dd `
97
+ margin: 0;
98
+ color: #0f172a;
99
+ `;
58
100
  const SurfaceContent = styled.div `
59
101
  position: relative;
60
102
  min-height: 0;
@@ -66,6 +108,6 @@ const SurfaceFooter = styled.footer `
66
108
  color: #475569;
67
109
  background: rgba(255, 255, 255, 0.78);
68
110
  `;
69
- export default function CustomModeSurface({ modeLabel, title, summary, children, footer, }) {
70
- return (_jsxs(SurfaceRoot, { children: [_jsx(SurfaceHeader, { children: _jsxs(SurfaceMeta, { children: [_jsx(ModePill, { children: modeLabel }), _jsx(SurfaceTitle, { children: title }), summary ? _jsx(SurfaceSummary, { children: summary }) : null] }) }), _jsx(SurfaceContent, { children: children }), footer ? _jsx(SurfaceFooter, { children: footer }) : null] }));
111
+ export default function CustomModeSurface({ modeLabel, title, summary, children, footer, badge, primaryLogo, secondaryLogo, meta, headerActions, }) {
112
+ return (_jsxs(SurfaceRoot, { children: [_jsxs(SurfaceHeader, { children: [_jsxs(SurfaceMeta, { children: [_jsx(ModePill, { children: badge || modeLabel }), _jsx(SurfaceTitle, { children: title }), summary ? _jsx(SurfaceSummary, { children: summary }) : null, Array.isArray(meta) && meta.length > 0 ? (_jsx(SurfaceMetaRow, { children: meta.map((item, index) => (_jsxs(SurfaceMetaItem, { children: [_jsx(SurfaceMetaLabel, { children: item.label }), _jsx(SurfaceMetaValue, { children: item.value })] }, item.id || `${item.label}-${index}`))) })) : null] }), primaryLogo || secondaryLogo || headerActions ? (_jsxs(SurfaceHeaderAside, { children: [headerActions, primaryLogo || secondaryLogo ? (_jsxs(HeaderLogos, { children: [primaryLogo ? _jsx(HeaderLogo, { src: primaryLogo.src, alt: primaryLogo.alt }) : null, secondaryLogo ? _jsx(HeaderLogo, { src: secondaryLogo.src, alt: secondaryLogo.alt }) : null] })) : null] })) : null] }), _jsx(SurfaceContent, { children: children }), footer ? _jsx(SurfaceFooter, { children: footer }) : null] }));
71
113
  }
@@ -0,0 +1,11 @@
1
+ import type { UiManifest } from '@treasuryspatial/ui-manifest';
2
+ import type { SurfaceShellLandingContent } from '@treasuryspatial/surface-kit';
3
+ export type LandingShellProps = {
4
+ manifest: UiManifest;
5
+ content: SurfaceShellLandingContent;
6
+ showPoweredBy?: boolean;
7
+ showLogout?: boolean;
8
+ className?: string;
9
+ };
10
+ export default function LandingShell({ manifest, content, showPoweredBy, showLogout, className, }: LandingShellProps): import("react/jsx-runtime").JSX.Element;
11
+ //# sourceMappingURL=LandingShell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LandingShell.d.ts","sourceRoot":"","sources":["../src/LandingShell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,8BAA8B,CAAC;AA4P/E,MAAM,MAAM,iBAAiB,GAAG;IAC9B,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,EAAE,0BAA0B,CAAC;IACpC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAKF,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EACnC,QAAQ,EACR,OAAO,EACP,aAAqB,EACrB,UAAiB,EACjB,SAAS,GACV,EAAE,iBAAiB,2CA4DnB"}
@@ -0,0 +1,231 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import styled from 'styled-components';
4
+ import ManifestTopBar from './ManifestTopBar.js';
5
+ const Root = styled.main `
6
+ min-height: 100vh;
7
+ background:
8
+ radial-gradient(circle at top left, color-mix(in srgb, var(--brand-accent) 12%, transparent), transparent 32%),
9
+ linear-gradient(180deg, color-mix(in srgb, var(--brand-background) 90%, white 10%), var(--brand-background));
10
+ color: var(--brand-text-primary);
11
+ overflow-x: hidden;
12
+ `;
13
+ const HeroShell = styled.section `
14
+ padding: calc(var(--ui-nav-height) + 48px) 24px 40px;
15
+
16
+ @media (min-width: 768px) {
17
+ padding: calc(var(--ui-nav-height) + 72px) 40px 56px;
18
+ }
19
+
20
+ @media (min-width: 1024px) {
21
+ padding: calc(var(--ui-nav-height) + 96px) 56px 72px;
22
+ }
23
+ `;
24
+ const HeroGrid = styled.div `
25
+ display: grid;
26
+ gap: 28px;
27
+ max-width: 1480px;
28
+ margin: 0 auto;
29
+
30
+ @media (min-width: 1024px) {
31
+ grid-template-columns: minmax(0, 1.25fr) minmax(320px, 440px);
32
+ align-items: stretch;
33
+ }
34
+ `;
35
+ const HeroCopy = styled.div `
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: 18px;
39
+ padding: 30px 28px;
40
+ border-radius: 28px;
41
+ background:
42
+ linear-gradient(145deg, color-mix(in srgb, var(--brand-panel) 94%, white 6%), color-mix(in srgb, var(--brand-background) 82%, var(--brand-panel) 18%));
43
+ border: 1px solid color-mix(in srgb, var(--brand-panel-border) 72%, transparent);
44
+ box-shadow: 0 24px 60px rgba(32, 33, 36, 0.08);
45
+
46
+ @media (min-width: 1024px) {
47
+ padding: 42px 40px;
48
+ }
49
+ `;
50
+ const Eyebrow = styled.div `
51
+ font-size: 12px;
52
+ font-weight: 700;
53
+ letter-spacing: 0.22em;
54
+ text-transform: uppercase;
55
+ color: var(--brand-accent);
56
+ `;
57
+ const HeroTitle = styled.h1 `
58
+ margin: 0;
59
+ font-family: var(--ui-font-family, system-ui);
60
+ font-size: clamp(42px, 8vw, 96px);
61
+ line-height: 0.98;
62
+ letter-spacing: -0.03em;
63
+ color: var(--brand-primary);
64
+ `;
65
+ const HeroSubtitle = styled.p `
66
+ margin: 0;
67
+ max-width: 26ch;
68
+ font-size: clamp(22px, 3.4vw, 40px);
69
+ line-height: 1.04;
70
+ color: color-mix(in srgb, var(--brand-primary) 86%, var(--brand-accent) 14%);
71
+ `;
72
+ const HeroDescription = styled.p `
73
+ margin: 0;
74
+ max-width: 64ch;
75
+ font-size: 16px;
76
+ line-height: 1.7;
77
+ color: var(--brand-text-secondary);
78
+
79
+ @media (min-width: 768px) {
80
+ font-size: 18px;
81
+ }
82
+ `;
83
+ const HeroActions = styled.div `
84
+ display: flex;
85
+ flex-wrap: wrap;
86
+ gap: 12px;
87
+ padding-top: 8px;
88
+ `;
89
+ const PrimaryLink = styled.a `
90
+ display: inline-flex;
91
+ align-items: center;
92
+ justify-content: center;
93
+ min-height: 46px;
94
+ padding: 0 18px;
95
+ border-radius: 999px;
96
+ font-size: 13px;
97
+ font-weight: 700;
98
+ letter-spacing: 0.08em;
99
+ text-transform: uppercase;
100
+ text-decoration: none;
101
+ transition: transform 0.18s ease;
102
+ background: var(--brand-accent);
103
+ border: 1px solid var(--brand-accent);
104
+ color: #ffffff;
105
+
106
+ &:hover {
107
+ transform: translateY(-1px);
108
+ }
109
+ `;
110
+ const SecondaryAnchor = styled.a `
111
+ display: inline-flex;
112
+ align-items: center;
113
+ justify-content: center;
114
+ min-height: 46px;
115
+ padding: 0 18px;
116
+ border-radius: 999px;
117
+ font-size: 13px;
118
+ font-weight: 700;
119
+ letter-spacing: 0.08em;
120
+ text-transform: uppercase;
121
+ text-decoration: none;
122
+ transition: transform 0.18s ease;
123
+ background: transparent;
124
+ border: 1px solid var(--brand-panel-border);
125
+ color: var(--brand-text-primary);
126
+
127
+ &:hover {
128
+ transform: translateY(-1px);
129
+ }
130
+ `;
131
+ const CardGrid = styled.aside `
132
+ display: grid;
133
+ gap: 14px;
134
+ `;
135
+ const Card = styled.div `
136
+ padding: 20px 18px;
137
+ border-radius: 22px;
138
+ background: color-mix(in srgb, var(--brand-panel) 90%, white 10%);
139
+ border: 1px solid color-mix(in srgb, var(--brand-panel-border) 74%, transparent);
140
+ box-shadow: 0 18px 46px rgba(32, 33, 36, 0.06);
141
+ `;
142
+ const CardLabel = styled.div `
143
+ font-size: 11px;
144
+ font-weight: 700;
145
+ letter-spacing: 0.18em;
146
+ text-transform: uppercase;
147
+ color: var(--brand-text-secondary);
148
+ `;
149
+ const CardValue = styled.div `
150
+ margin-top: 10px;
151
+ font-size: 24px;
152
+ line-height: 1.1;
153
+ font-weight: 700;
154
+ `;
155
+ const CardText = styled.p `
156
+ margin: 10px 0 0;
157
+ font-size: 14px;
158
+ line-height: 1.6;
159
+ color: var(--brand-text-secondary);
160
+ `;
161
+ const Sections = styled.section `
162
+ max-width: 1480px;
163
+ margin: 0 auto;
164
+ padding: 0 24px 64px;
165
+ display: grid;
166
+ gap: 20px;
167
+
168
+ @media (min-width: 768px) {
169
+ padding: 0 40px 80px;
170
+ }
171
+
172
+ @media (min-width: 1024px) {
173
+ padding: 0 56px 96px;
174
+ grid-template-columns: repeat(2, minmax(0, 1fr));
175
+ }
176
+ `;
177
+ const SectionCard = styled.article `
178
+ border-radius: 24px;
179
+ padding: 26px 24px;
180
+ background: color-mix(in srgb, var(--brand-panel) 92%, white 8%);
181
+ border: 1px solid color-mix(in srgb, var(--brand-panel-border) 72%, transparent);
182
+ box-shadow: 0 14px 36px rgba(15, 23, 42, 0.05);
183
+ `;
184
+ const SectionTitle = styled.h2 `
185
+ margin: 0;
186
+ font-size: 24px;
187
+ line-height: 1.1;
188
+ color: var(--brand-primary);
189
+ `;
190
+ const SectionDescription = styled.p `
191
+ margin: 14px 0 0;
192
+ font-size: 15px;
193
+ line-height: 1.7;
194
+ color: var(--brand-text-secondary);
195
+ `;
196
+ const SectionBody = styled.div `
197
+ margin-top: 16px;
198
+ display: flex;
199
+ flex-direction: column;
200
+ gap: 14px;
201
+ font-size: 15px;
202
+ line-height: 1.75;
203
+ color: var(--brand-text-secondary);
204
+ `;
205
+ const BulletList = styled.ul `
206
+ margin: 16px 0 0;
207
+ padding-left: 18px;
208
+ display: flex;
209
+ flex-direction: column;
210
+ gap: 10px;
211
+ color: var(--brand-text-secondary);
212
+ `;
213
+ const Notice = styled.p `
214
+ max-width: 1480px;
215
+ margin: 0 auto;
216
+ padding: 0 24px 80px;
217
+ font-size: 13px;
218
+ line-height: 1.7;
219
+ color: var(--brand-text-secondary);
220
+
221
+ @media (min-width: 768px) {
222
+ padding: 0 40px 88px;
223
+ }
224
+
225
+ @media (min-width: 1024px) {
226
+ padding: 0 56px 104px;
227
+ }
228
+ `;
229
+ export default function LandingShell({ manifest, content, showPoweredBy = false, showLogout = true, className, }) {
230
+ return (_jsxs(Root, { className: className, children: [_jsx(ManifestTopBar, { manifest: manifest, variant: "landing", showPoweredBy: showPoweredBy, showLogout: showLogout }), _jsx(HeroShell, { children: _jsxs(HeroGrid, { children: [_jsxs(HeroCopy, { children: [_jsx(Eyebrow, { children: content.hero.eyebrow }), _jsx(HeroTitle, { children: content.hero.title }), _jsx(HeroSubtitle, { children: content.hero.subtitle }), _jsx(HeroDescription, { children: content.hero.description }), _jsxs(HeroActions, { children: [_jsx(PrimaryLink, { href: content.hero.primaryCta.href, children: content.hero.primaryCta.label }), content.hero.secondaryCta ? (_jsx(SecondaryAnchor, { href: content.hero.secondaryCta.href, target: "_blank", rel: "noreferrer", children: content.hero.secondaryCta.label })) : null] })] }), content.cards?.length ? (_jsx(CardGrid, { children: content.cards.map((card) => (_jsxs(Card, { children: [_jsx(CardLabel, { children: card.label }), _jsx(CardValue, { children: card.value }), _jsx(CardText, { children: card.text })] }, card.id))) })) : null] }) }), content.sections?.length ? (_jsx(Sections, { children: content.sections.map((section) => (_jsxs(SectionCard, { children: [_jsx(SectionTitle, { children: section.title }), section.description ? _jsx(SectionDescription, { children: section.description }) : null, section.paragraphs?.length ? (_jsx(SectionBody, { children: section.paragraphs.map((paragraph) => (_jsx("p", { children: paragraph }, paragraph))) })) : null, section.bullets?.length ? (_jsx(BulletList, { children: section.bullets.map((bullet) => (_jsx("li", { children: bullet }, bullet))) })) : null] }, section.id))) })) : null, content.notice ? _jsx(Notice, { children: content.notice }) : null] }));
231
+ }
@@ -0,0 +1,16 @@
1
+ import type { FormEvent } from 'react';
2
+ export type LoginFormProps = {
3
+ email: string;
4
+ password: string;
5
+ onEmailChange: (value: string) => void;
6
+ onPasswordChange: (value: string) => void;
7
+ onSubmit: (event: FormEvent<HTMLFormElement>) => void;
8
+ busy?: boolean;
9
+ status?: string | null;
10
+ emailLabel?: string;
11
+ passwordLabel?: string;
12
+ submitLabel?: string;
13
+ busyLabel?: string;
14
+ };
15
+ export default function LoginForm({ email, password, onEmailChange, onPasswordChange, onSubmit, busy, status, emailLabel, passwordLabel, submitLabel, busyLabel, }: LoginFormProps): import("react/jsx-runtime").JSX.Element;
16
+ //# sourceMappingURL=LoginForm.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoginForm.d.ts","sourceRoot":"","sources":["../src/LoginForm.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AA0EvC,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,gBAAgB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1C,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,CAAC,eAAe,CAAC,KAAK,IAAI,CAAC;IACtD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAChC,KAAK,EACL,QAAQ,EACR,aAAa,EACb,gBAAgB,EAChB,QAAQ,EACR,IAAY,EACZ,MAAa,EACb,UAAoB,EACpB,aAA0B,EAC1B,WAAqB,EACrB,SAAyB,GAC1B,EAAE,cAAc,2CAsChB"}
@@ -0,0 +1,69 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import styled from 'styled-components';
4
+ const Form = styled.form `
5
+ display: flex;
6
+ flex-direction: column;
7
+ gap: 0;
8
+ width: 100%;
9
+ max-width: 720px;
10
+ `;
11
+ const Row = styled.div `
12
+ display: flex;
13
+ `;
14
+ const LabelCell = styled.div `
15
+ background: var(--brand-secondary);
16
+ width: 296px;
17
+ padding: 16px;
18
+ color: white;
19
+ font-size: 16px;
20
+ font-weight: 400;
21
+ `;
22
+ const Input = styled.input `
23
+ outline: none;
24
+ flex: 1;
25
+ border: none;
26
+ background: color-mix(in srgb, var(--brand-panel) 88%, var(--brand-background) 12%);
27
+ padding: 16px;
28
+ font-size: 16px;
29
+ color: var(--brand-text-primary);
30
+ `;
31
+ const ButtonRow = styled.div `
32
+ display: flex;
33
+ align-items: center;
34
+ `;
35
+ const Button = styled.button `
36
+ outline: none;
37
+ border: none;
38
+ width: 296px;
39
+ box-sizing: border-box;
40
+ padding: 16px;
41
+ color: white;
42
+ font-size: 16px;
43
+ font-weight: 400;
44
+ transition: background-color 0.2s ease;
45
+ background: var(--brand-primary);
46
+ cursor: pointer;
47
+
48
+ &:hover:not(:disabled) {
49
+ background: color-mix(in srgb, var(--brand-primary) 85%, #0f172a 15%);
50
+ }
51
+
52
+ &:disabled {
53
+ background: var(--brand-panel-border);
54
+ color: color-mix(in srgb, var(--brand-text-primary) 45%, white 55%);
55
+ cursor: not-allowed;
56
+ }
57
+ `;
58
+ const Spacer = styled.div `
59
+ flex: 1;
60
+ `;
61
+ const Notice = styled.p `
62
+ color: var(--brand-text-secondary);
63
+ font-size: 14px;
64
+ margin-top: 20px;
65
+ max-width: 720px;
66
+ `;
67
+ export default function LoginForm({ email, password, onEmailChange, onPasswordChange, onSubmit, busy = false, status = null, emailLabel = 'Email', passwordLabel = 'Password', submitLabel = 'Login', busyLabel = 'Logging in…', }) {
68
+ return (_jsxs(Form, { onSubmit: onSubmit, autoComplete: "off", children: [_jsxs(Row, { children: [_jsx(LabelCell, { children: emailLabel }), _jsx(Input, { "aria-label": emailLabel, name: "email", placeholder: emailLabel, value: email, onChange: (event) => onEmailChange(event.target.value), autoComplete: "email", "data-lpignore": "true" })] }), _jsxs(Row, { style: { marginTop: '1px' }, children: [_jsx(LabelCell, { children: passwordLabel }), _jsx(Input, { type: "password", "aria-label": passwordLabel, name: "password", placeholder: passwordLabel, required: true, value: password, onChange: (event) => onPasswordChange(event.target.value), autoComplete: "new-password", "data-lpignore": "true" })] }), _jsxs(ButtonRow, { style: { marginTop: '1px' }, children: [_jsx(Button, { type: "submit", "aria-label": submitLabel, disabled: busy || password.trim() === '', children: busy ? busyLabel : submitLabel }), _jsx(Spacer, {})] }), status ? _jsx(Notice, { style: { color: '#9f1d1d' }, children: status }) : null] }));
69
+ }
@@ -0,0 +1,13 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { UiManifest } from '@treasuryspatial/ui-manifest';
3
+ import type { SurfaceShellLoginContent } from '@treasuryspatial/surface-kit';
4
+ export type LoginShellProps = {
5
+ manifest: UiManifest;
6
+ content?: SurfaceShellLoginContent | null;
7
+ children: ReactNode;
8
+ showLogout?: boolean;
9
+ showPoweredBy?: boolean;
10
+ className?: string;
11
+ };
12
+ export default function LoginShell({ manifest, content, children, showLogout, showPoweredBy, className, }: LoginShellProps): import("react/jsx-runtime").JSX.Element;
13
+ //# sourceMappingURL=LoginShell.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"LoginShell.d.ts","sourceRoot":"","sources":["../src/LoginShell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACvC,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,8BAA8B,CAAC;AAyH7E,MAAM,MAAM,eAAe,GAAG;IAC5B,QAAQ,EAAE,UAAU,CAAC;IACrB,OAAO,CAAC,EAAE,wBAAwB,GAAG,IAAI,CAAC;IAC1C,QAAQ,EAAE,SAAS,CAAC;IACpB,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,QAAQ,EACR,OAAO,EACP,QAAQ,EACR,UAAkB,EAClB,aAAqB,EACrB,SAAS,GACV,EAAE,eAAe,2CAsCjB"}
@@ -0,0 +1,114 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import styled from 'styled-components';
4
+ import ManifestTopBar from './ManifestTopBar.js';
5
+ const Root = styled.main `
6
+ min-height: 100vh;
7
+ background:
8
+ radial-gradient(circle at top left, color-mix(in srgb, var(--brand-accent) 10%, transparent), transparent 36%),
9
+ linear-gradient(180deg, color-mix(in srgb, var(--brand-background) 94%, white 6%), var(--brand-background));
10
+ color: var(--brand-text-primary);
11
+ `;
12
+ const Shell = styled.section `
13
+ min-height: 100vh;
14
+ padding: calc(var(--ui-nav-height) + 48px) 24px 40px;
15
+
16
+ @media (min-width: 768px) {
17
+ padding: calc(var(--ui-nav-height) + 64px) 40px 56px;
18
+ }
19
+
20
+ @media (min-width: 1024px) {
21
+ padding: calc(var(--ui-nav-height) + 72px) 56px 72px;
22
+ }
23
+ `;
24
+ const Grid = styled.div `
25
+ display: grid;
26
+ gap: 28px;
27
+ max-width: 1280px;
28
+ margin: 0 auto;
29
+
30
+ @media (min-width: 1024px) {
31
+ grid-template-columns: minmax(0, 1.05fr) minmax(360px, 520px);
32
+ align-items: start;
33
+ }
34
+ `;
35
+ const Intro = styled.div `
36
+ display: flex;
37
+ flex-direction: column;
38
+ gap: 16px;
39
+ padding: 24px 0;
40
+ `;
41
+ const Eyebrow = styled.div `
42
+ font-size: 12px;
43
+ font-weight: 700;
44
+ letter-spacing: 0.2em;
45
+ text-transform: uppercase;
46
+ color: var(--brand-accent);
47
+ `;
48
+ const Title = styled.h1 `
49
+ margin: 0;
50
+ font-family: var(--ui-font-family, system-ui);
51
+ font-size: clamp(44px, 5.5vw, 82px);
52
+ line-height: 0.96;
53
+ letter-spacing: -0.03em;
54
+ color: var(--brand-primary);
55
+ `;
56
+ const Subtitle = styled.p `
57
+ margin: 0;
58
+ max-width: 28ch;
59
+ font-size: clamp(20px, 2.8vw, 34px);
60
+ line-height: 1.06;
61
+ color: color-mix(in srgb, var(--brand-primary) 86%, var(--brand-accent) 14%);
62
+ `;
63
+ const Description = styled.p `
64
+ margin: 0;
65
+ max-width: 64ch;
66
+ font-size: 16px;
67
+ line-height: 1.7;
68
+ color: var(--brand-text-secondary);
69
+ `;
70
+ const SupportLink = styled.a `
71
+ display: inline-flex;
72
+ align-items: center;
73
+ gap: 8px;
74
+ width: fit-content;
75
+ text-decoration: none;
76
+ font-size: 13px;
77
+ font-weight: 700;
78
+ letter-spacing: 0.08em;
79
+ text-transform: uppercase;
80
+ color: var(--brand-primary);
81
+
82
+ &:hover {
83
+ color: var(--brand-text-primary);
84
+ }
85
+ `;
86
+ const Panel = styled.div `
87
+ border-radius: 28px;
88
+ background: color-mix(in srgb, var(--brand-panel) 94%, white 6%);
89
+ border: 1px solid color-mix(in srgb, var(--brand-panel-border) 76%, transparent);
90
+ box-shadow: 0 24px 60px rgba(15, 23, 42, 0.08);
91
+ padding: 26px 22px;
92
+
93
+ @media (min-width: 768px) {
94
+ padding: 32px 28px;
95
+ }
96
+ `;
97
+ const Meta = styled.div `
98
+ display: flex;
99
+ flex-direction: column;
100
+ gap: 14px;
101
+ margin-top: 20px;
102
+ `;
103
+ const MetaText = styled.p `
104
+ margin: 0;
105
+ font-size: 13px;
106
+ line-height: 1.6;
107
+ color: var(--brand-text-secondary);
108
+ `;
109
+ export default function LoginShell({ manifest, content, children, showLogout = false, showPoweredBy = false, className, }) {
110
+ const title = content?.title?.trim() ||
111
+ manifest.surface?.label ||
112
+ `${manifest.topbar.title} ${manifest.topbar.productLabel}`.trim();
113
+ return (_jsxs(Root, { className: className, children: [_jsx(ManifestTopBar, { manifest: manifest, variant: "landing", showPoweredBy: showPoweredBy, showLogout: showLogout }), _jsx(Shell, { children: _jsxs(Grid, { children: [_jsxs(Intro, { children: [content?.eyebrow ? _jsx(Eyebrow, { children: content.eyebrow }) : null, _jsx(Title, { children: title }), _jsx(Subtitle, { children: content?.subtitle ?? `${manifest.topbar.title} ${manifest.topbar.productLabel}`.trim() }), content?.description ? _jsx(Description, { children: content.description }) : null, content?.supportLink ? (_jsx(SupportLink, { href: content.supportLink.href, target: "_blank", rel: "noreferrer", children: content.supportLink.label })) : null, (content?.notice || content?.legal) ? (_jsxs(Meta, { children: [content.notice ? _jsx(MetaText, { children: content.notice }) : null, content.legal ? _jsx(MetaText, { children: content.legal }) : null] })) : null] }), _jsx(Panel, { children: children })] }) })] }));
114
+ }
@@ -0,0 +1,15 @@
1
+ import type { UiManifest } from '@treasuryspatial/ui-manifest';
2
+ type ManifestTopBarProps = {
3
+ manifest: UiManifest;
4
+ variant?: 'landing' | 'canvas';
5
+ showPoweredBy?: boolean;
6
+ showLogout?: boolean;
7
+ showPanelToggle?: boolean;
8
+ showSubtitle?: boolean;
9
+ logoutCookieNames?: string[];
10
+ logoutEndpoint?: string;
11
+ logoutHref?: string;
12
+ };
13
+ export default function ManifestTopBar({ manifest, variant, showPoweredBy, showLogout, showPanelToggle, showSubtitle, logoutCookieNames, logoutEndpoint, logoutHref, }: ManifestTopBarProps): import("react/jsx-runtime").JSX.Element;
14
+ export type { ManifestTopBarProps };
15
+ //# sourceMappingURL=ManifestTopBar.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ManifestTopBar.d.ts","sourceRoot":"","sources":["../src/ManifestTopBar.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,8BAA8B,CAAC;AAM/D,KAAK,mBAAmB,GAAG;IACzB,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,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,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;AA0MF,MAAM,CAAC,OAAO,UAAU,cAAc,CAAC,EACrC,QAAQ,EACR,OAAkB,EAClB,aAAoB,EACpB,UAAkB,EAClB,eAAuB,EACvB,YAAoB,EACpB,iBAA2C,EAC3C,cAAmC,EACnC,UAAqB,GACtB,EAAE,mBAAmB,2CA2HrB;AAED,YAAY,EAAE,mBAAmB,EAAE,CAAC"}