minutework 0.1.40 → 0.1.42
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/EXTERNAL_ALPHA.md +17 -1
- package/README.md +21 -1
- package/assets/claude-local/bundle.json +2 -1
- package/assets/claude-local/preambles/base.md +13 -0
- package/assets/claude-local/preambles/mobile.md +17 -0
- package/assets/claude-local/preambles/tenant.md +17 -0
- package/assets/claude-local/preambles/vuilder.md +29 -0
- package/assets/claude-local/skills/README.md +5 -0
- package/assets/claude-local/skills/app-pack-authoring/SKILL.md +15 -0
- package/assets/claude-local/skills/generated-workspace-architecture/SKILL.md +25 -9
- package/assets/claude-local/skills/shell-architecture/SKILL.md +15 -0
- package/assets/claude-local/skills/vuilder-public-site-authoring/SKILL.md +10 -4
- package/assets/claude-local/skills/vuilder-workspace-architecture/SKILL.md +78 -0
- package/assets/templates/vuilder-public-site/.env.example +13 -0
- package/assets/templates/vuilder-public-site/README.md +15 -0
- package/assets/templates/vuilder-public-site/eslint.config.mjs +6 -0
- package/assets/templates/vuilder-public-site/next-env.d.ts +4 -0
- package/assets/templates/vuilder-public-site/next.config.mjs +28 -0
- package/assets/templates/vuilder-public-site/package.json +40 -0
- package/assets/templates/vuilder-public-site/postcss.config.mjs +5 -0
- package/assets/templates/vuilder-public-site/src/app/api/onboarding/start/route.ts +19 -0
- package/assets/templates/vuilder-public-site/src/app/blog/[slug]/page.tsx +25 -0
- package/assets/templates/vuilder-public-site/src/app/blog/page.tsx +26 -0
- package/assets/templates/vuilder-public-site/src/app/globals.css +103 -0
- package/assets/templates/vuilder-public-site/src/app/layout.tsx +18 -0
- package/assets/templates/vuilder-public-site/src/app/onboarding/[[...step]]/page.tsx +39 -0
- package/assets/templates/vuilder-public-site/src/app/page.tsx +43 -0
- package/assets/templates/vuilder-public-site/src/lib/env.server.test.ts +47 -0
- package/assets/templates/vuilder-public-site/src/lib/env.server.ts +92 -0
- package/assets/templates/vuilder-public-site/src/lib/platform.server.ts +47 -0
- package/assets/templates/vuilder-public-site/src/lib/public-dj.server.ts +86 -0
- package/assets/templates/vuilder-public-site/src/lib/public-dj.test.ts +8 -0
- package/assets/templates/vuilder-public-site/src/lib/routes.test.ts +13 -0
- package/assets/templates/vuilder-public-site/src/lib/routes.ts +12 -0
- package/assets/templates/vuilder-public-site/template.json +21 -0
- package/assets/templates/vuilder-public-site/test/server-only-stub.ts +1 -0
- package/assets/templates/vuilder-public-site/tools/env/check-dev-env.mjs +109 -0
- package/assets/templates/vuilder-public-site/tools/env/check-dev-env.test.ts +49 -0
- package/assets/templates/vuilder-public-site/tools/template/validate-template.mjs +44 -0
- package/assets/templates/vuilder-public-site/tsconfig.json +23 -0
- package/assets/templates/vuilder-public-site/vitest.config.ts +15 -0
- package/assets/templates/vuilder-shell/.env.example +8 -0
- package/assets/templates/vuilder-shell/.storybook/main.ts +19 -0
- package/assets/templates/vuilder-shell/.storybook/preview.tsx +38 -0
- package/assets/templates/vuilder-shell/README.md +49 -0
- package/assets/templates/vuilder-shell/components.json +21 -0
- package/assets/templates/vuilder-shell/eslint.config.mjs +41 -0
- package/assets/templates/vuilder-shell/next-env.d.ts +6 -0
- package/assets/templates/vuilder-shell/next.config.mjs +33 -0
- package/assets/templates/vuilder-shell/package.json +61 -0
- package/assets/templates/vuilder-shell/postcss.config.mjs +8 -0
- package/assets/templates/vuilder-shell/public/.gitkeep +1 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/accept-shell-session/route.test.ts +105 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/accept-shell-session/route.ts +63 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/logout/route.test.ts +63 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/logout/route.ts +24 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/session/route.test.ts +70 -0
- package/assets/templates/vuilder-shell/src/app/api/auth/session/route.ts +27 -0
- package/assets/templates/vuilder-shell/src/app/app/layout.tsx +17 -0
- package/assets/templates/vuilder-shell/src/app/app/page.tsx +30 -0
- package/assets/templates/vuilder-shell/src/app/blog/[slug]/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/blog/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/docs/[...slug]/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/docs/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/globals.css +70 -0
- package/assets/templates/vuilder-shell/src/app/layout.tsx +69 -0
- package/assets/templates/vuilder-shell/src/app/login/route.test.ts +33 -0
- package/assets/templates/vuilder-shell/src/app/login/route.ts +21 -0
- package/assets/templates/vuilder-shell/src/app/page.tsx +16 -0
- package/assets/templates/vuilder-shell/src/app/pricing/page.tsx +15 -0
- package/assets/templates/vuilder-shell/src/app/providers.tsx +25 -0
- package/assets/templates/vuilder-shell/src/app/robots.ts +21 -0
- package/assets/templates/vuilder-shell/src/app/sitemap.ts +33 -0
- package/assets/templates/vuilder-shell/src/app/w/[workspace_slug]/connect/page.tsx +31 -0
- package/assets/templates/vuilder-shell/src/app/w/[workspace_slug]/page.tsx +54 -0
- package/assets/templates/vuilder-shell/src/components/ui/button.tsx +59 -0
- package/assets/templates/vuilder-shell/src/components/ui/input.tsx +21 -0
- package/assets/templates/vuilder-shell/src/design-system/docs/governance.mdx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/panel-frame.stories.tsx +48 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/panel-frame.tsx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/status-badge.stories.tsx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/status-badge.tsx +35 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/theme-mode-toggle.stories.tsx +21 -0
- package/assets/templates/vuilder-shell/src/design-system/patterns/theme-mode-toggle.tsx +75 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/button.stories.tsx +37 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/button.ts +1 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/input.stories.tsx +26 -0
- package/assets/templates/vuilder-shell/src/design-system/primitives/input.ts +1 -0
- package/assets/templates/vuilder-shell/src/design-system/recipes/chrome.ts +28 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/foundation.css +31 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/index.css +3 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/manifest.json +85 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/manifest.ts +87 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/semantic.css +105 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/theme.css +59 -0
- package/assets/templates/vuilder-shell/src/design-system/tokens/tokens.stories.tsx +71 -0
- package/assets/templates/vuilder-shell/src/features/dashboard/components/tenant-dashboard.tsx +134 -0
- package/assets/templates/vuilder-shell/src/features/public-shell/components/static-public-page.tsx +58 -0
- package/assets/templates/vuilder-shell/src/features/shell/components/authenticated-app-layout-shell.tsx +84 -0
- package/assets/templates/vuilder-shell/src/features/shell/components/private-app-shell.tsx +22 -0
- package/assets/templates/vuilder-shell/src/features/vuilder-shell/components/vuilder-connect-screen.tsx +89 -0
- package/assets/templates/vuilder-shell/src/features/vuilder-shell/components/vuilder-workspace-screen.tsx +49 -0
- package/assets/templates/vuilder-shell/src/lib/app-routes.test.ts +37 -0
- package/assets/templates/vuilder-shell/src/lib/app-routes.ts +86 -0
- package/assets/templates/vuilder-shell/src/lib/auth-routes.server.test.ts +26 -0
- package/assets/templates/vuilder-shell/src/lib/auth-routes.server.ts +53 -0
- package/assets/templates/vuilder-shell/src/lib/http/same-origin.test.ts +23 -0
- package/assets/templates/vuilder-shell/src/lib/http/same-origin.ts +18 -0
- package/assets/templates/vuilder-shell/src/lib/platform/client.server.test.ts +201 -0
- package/assets/templates/vuilder-shell/src/lib/platform/client.server.ts +540 -0
- package/assets/templates/vuilder-shell/src/lib/platform/contracts.ts +190 -0
- package/assets/templates/vuilder-shell/src/lib/platform/endpoints.server.ts +29 -0
- package/assets/templates/vuilder-shell/src/lib/platform/env.server.ts +82 -0
- package/assets/templates/vuilder-shell/src/lib/platform/route-response.ts +33 -0
- package/assets/templates/vuilder-shell/src/lib/platform/session.server.ts +145 -0
- package/assets/templates/vuilder-shell/src/lib/public-site.test.ts +20 -0
- package/assets/templates/vuilder-shell/src/lib/public-site.ts +48 -0
- package/assets/templates/vuilder-shell/src/lib/theme-config.ts +10 -0
- package/assets/templates/vuilder-shell/src/lib/theme.tsx +159 -0
- package/assets/templates/vuilder-shell/src/lib/utils.ts +6 -0
- package/assets/templates/vuilder-shell/template.json +28 -0
- package/assets/templates/vuilder-shell/template.schema.json +171 -0
- package/assets/templates/vuilder-shell/test/server-only-stub.ts +1 -0
- package/assets/templates/vuilder-shell/tools/design-system/build-token-manifest.mjs +3 -0
- package/assets/templates/vuilder-shell/tools/design-system/check-imports.mjs +9 -0
- package/assets/templates/vuilder-shell/tools/design-system/check-stories.mjs +9 -0
- package/assets/templates/vuilder-shell/tools/design-system/check-values.mjs +9 -0
- package/assets/templates/vuilder-shell/tools/design-system/checks.mjs +238 -0
- package/assets/templates/vuilder-shell/tools/design-system/eslint-plugin-design-system.mjs +184 -0
- package/assets/templates/vuilder-shell/tools/design-system/playwright.config.mjs +34 -0
- package/assets/templates/vuilder-shell/tools/design-system/run-checks.mjs +22 -0
- package/assets/templates/vuilder-shell/tools/design-system/shared.mjs +166 -0
- package/assets/templates/vuilder-shell/tools/design-system/visual.spec.ts +41 -0
- package/assets/templates/vuilder-shell/tools/template/validate-route-contract.mjs +373 -0
- package/assets/templates/vuilder-shell/tools/template/validate-template.mjs +45 -0
- package/assets/templates/vuilder-shell/tools/template/with-public-site-fixture.mjs +45 -0
- package/assets/templates/vuilder-shell/tsconfig.json +42 -0
- package/assets/templates/vuilder-shell/vitest.config.ts +23 -0
- package/dist/auth.js +97 -31
- package/dist/auth.js.map +1 -1
- package/dist/deploy-state.d.ts +1 -0
- package/dist/deploy-state.js.map +1 -1
- package/dist/deploy.js +18 -4
- package/dist/deploy.js.map +1 -1
- package/dist/developer-client.d.ts +2 -1
- package/dist/developer-client.js.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/init-prompt.js +21 -13
- package/dist/init-prompt.js.map +1 -1
- package/dist/init.d.ts +3 -1
- package/dist/init.js +105 -13
- package/dist/init.js.map +1 -1
- package/dist/orchestrator-context.js +17 -5
- package/dist/orchestrator-context.js.map +1 -1
- package/dist/orchestrator-state.d.ts +2 -2
- package/dist/orchestrator-state.js.map +1 -1
- package/dist/publish.js +12 -2
- package/dist/publish.js.map +1 -1
- package/dist/sandbox.js +11 -1
- package/dist/sandbox.js.map +1 -1
- package/dist/state.d.ts +2 -0
- package/dist/state.js +9 -0
- package/dist/state.js.map +1 -1
- package/dist/workspace-assets.d.ts +13 -0
- package/dist/workspace-assets.js +86 -5
- package/dist/workspace-assets.js.map +1 -1
- package/dist/workspace-bootstrap.d.ts +47 -2
- package/dist/workspace-bootstrap.js +45 -1
- package/dist/workspace-bootstrap.js.map +1 -1
- package/package.json +3 -3
- package/vendor/workspace-mcp/context.d.ts +3 -1
- package/vendor/workspace-mcp/context.js +134 -21
- package/vendor/workspace-mcp/context.js.map +1 -1
- package/vendor/workspace-mcp/types.d.ts +72 -7
- package/vendor/workspace-mcp/types.js +8 -4
- package/vendor/workspace-mcp/types.js.map +1 -1
- package/assets/templates/fastapi-sidecar/poetry.lock +0 -757
- package/assets/templates/next-tenant-app/package-lock.json +0 -9682
- package/assets/templates/next-tenant-app/pnpm-lock.yaml +0 -6062
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
:root {
|
|
2
|
+
--background: #f6fafc;
|
|
3
|
+
--foreground: var(--ds-foundation-neutral-950);
|
|
4
|
+
--card: #fcfdff;
|
|
5
|
+
--card-foreground: var(--ds-foundation-neutral-950);
|
|
6
|
+
--popover: #fcfdff;
|
|
7
|
+
--popover-foreground: var(--ds-foundation-neutral-950);
|
|
8
|
+
--primary: var(--ds-foundation-cyan-600);
|
|
9
|
+
--primary-foreground: var(--ds-foundation-white);
|
|
10
|
+
--secondary: #edf3f7;
|
|
11
|
+
--secondary-foreground: var(--ds-foundation-neutral-950);
|
|
12
|
+
--muted: #eef5f8;
|
|
13
|
+
--muted-foreground: #617487;
|
|
14
|
+
--accent: var(--ds-foundation-cyan-100);
|
|
15
|
+
--accent-foreground: var(--ds-foundation-neutral-950);
|
|
16
|
+
--destructive: var(--ds-foundation-red-500);
|
|
17
|
+
--destructive-foreground: var(--ds-foundation-white);
|
|
18
|
+
--border: #d7e5ed;
|
|
19
|
+
--input: #d7e5ed;
|
|
20
|
+
--ring: var(--ds-foundation-cyan-500);
|
|
21
|
+
--chart-1: var(--ds-foundation-cyan-500);
|
|
22
|
+
--chart-2: var(--ds-foundation-green-500);
|
|
23
|
+
--chart-3: var(--ds-foundation-blue-500);
|
|
24
|
+
--chart-4: var(--ds-foundation-yellow-500);
|
|
25
|
+
--chart-5: var(--ds-foundation-red-500);
|
|
26
|
+
--radius: 0.5rem;
|
|
27
|
+
--sidebar: #f8fbfd;
|
|
28
|
+
--sidebar-foreground: var(--ds-foundation-neutral-950);
|
|
29
|
+
--sidebar-primary: var(--ds-foundation-cyan-600);
|
|
30
|
+
--sidebar-primary-foreground: var(--ds-foundation-white);
|
|
31
|
+
--sidebar-accent: #edf5f8;
|
|
32
|
+
--sidebar-accent-foreground: var(--ds-foundation-neutral-950);
|
|
33
|
+
--sidebar-border: #d7e5ed;
|
|
34
|
+
--sidebar-ring: var(--ds-foundation-cyan-500);
|
|
35
|
+
|
|
36
|
+
--surface: #ffffff;
|
|
37
|
+
--surface-raised: #f3f8fb;
|
|
38
|
+
--text-link: var(--ds-foundation-cyan-700);
|
|
39
|
+
--success: var(--ds-foundation-green-500);
|
|
40
|
+
--warning: var(--ds-foundation-yellow-500);
|
|
41
|
+
--danger: var(--ds-foundation-red-500);
|
|
42
|
+
--info: var(--ds-foundation-blue-500);
|
|
43
|
+
--ai-bubble: #eef5f8;
|
|
44
|
+
--user-bubble: var(--ds-foundation-cyan-600);
|
|
45
|
+
--tenant-rail: var(--ds-foundation-cyan-50);
|
|
46
|
+
--tenant-rail-foreground: var(--ds-foundation-ink-500);
|
|
47
|
+
--tenant-rail-muted: #627789;
|
|
48
|
+
--tenant-rail-border: rgb(148 163 184 / 0.24);
|
|
49
|
+
--tenant-rail-surface: rgb(255 255 255 / 0.72);
|
|
50
|
+
--overlay: var(--ds-foundation-overlay-50);
|
|
51
|
+
--overlay-strong: var(--ds-foundation-overlay-60);
|
|
52
|
+
--strong-foreground: var(--ds-foundation-white);
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
.dark {
|
|
56
|
+
--background: var(--ds-foundation-neutral-950);
|
|
57
|
+
--foreground: var(--ds-foundation-neutral-100);
|
|
58
|
+
--card: var(--ds-foundation-neutral-850);
|
|
59
|
+
--card-foreground: var(--ds-foundation-neutral-100);
|
|
60
|
+
--popover: var(--ds-foundation-neutral-850);
|
|
61
|
+
--popover-foreground: var(--ds-foundation-neutral-100);
|
|
62
|
+
--primary: var(--ds-foundation-cyan-500);
|
|
63
|
+
--primary-foreground: var(--ds-foundation-white);
|
|
64
|
+
--secondary: var(--ds-foundation-neutral-800);
|
|
65
|
+
--secondary-foreground: var(--ds-foundation-neutral-100);
|
|
66
|
+
--muted: var(--ds-foundation-neutral-850);
|
|
67
|
+
--muted-foreground: var(--ds-foundation-neutral-500);
|
|
68
|
+
--accent: var(--ds-foundation-ink-700);
|
|
69
|
+
--accent-foreground: var(--ds-foundation-neutral-100);
|
|
70
|
+
--destructive: var(--ds-foundation-red-500);
|
|
71
|
+
--destructive-foreground: var(--ds-foundation-white);
|
|
72
|
+
--border: var(--ds-foundation-neutral-700);
|
|
73
|
+
--input: var(--ds-foundation-neutral-800);
|
|
74
|
+
--ring: var(--ds-foundation-cyan-500);
|
|
75
|
+
--chart-1: var(--ds-foundation-cyan-500);
|
|
76
|
+
--chart-2: var(--ds-foundation-green-500);
|
|
77
|
+
--chart-3: var(--ds-foundation-blue-500);
|
|
78
|
+
--chart-4: var(--ds-foundation-yellow-500);
|
|
79
|
+
--chart-5: var(--ds-foundation-red-500);
|
|
80
|
+
--sidebar: var(--ds-foundation-neutral-900);
|
|
81
|
+
--sidebar-foreground: var(--ds-foundation-neutral-100);
|
|
82
|
+
--sidebar-primary: var(--ds-foundation-cyan-500);
|
|
83
|
+
--sidebar-primary-foreground: var(--ds-foundation-white);
|
|
84
|
+
--sidebar-accent: var(--ds-foundation-neutral-800);
|
|
85
|
+
--sidebar-accent-foreground: var(--ds-foundation-neutral-100);
|
|
86
|
+
--sidebar-border: var(--ds-foundation-neutral-700);
|
|
87
|
+
--sidebar-ring: var(--ds-foundation-cyan-500);
|
|
88
|
+
--surface: var(--ds-foundation-neutral-850);
|
|
89
|
+
--surface-raised: var(--ds-foundation-neutral-800);
|
|
90
|
+
--text-link: var(--ds-foundation-cyan-300);
|
|
91
|
+
--success: var(--ds-foundation-green-500);
|
|
92
|
+
--warning: var(--ds-foundation-yellow-500);
|
|
93
|
+
--danger: var(--ds-foundation-red-500);
|
|
94
|
+
--info: var(--ds-foundation-blue-500);
|
|
95
|
+
--ai-bubble: var(--ds-foundation-neutral-850);
|
|
96
|
+
--user-bubble: var(--ds-foundation-cyan-600);
|
|
97
|
+
--tenant-rail: var(--ds-foundation-neutral-950);
|
|
98
|
+
--tenant-rail-foreground: var(--ds-foundation-white);
|
|
99
|
+
--tenant-rail-muted: rgb(255 255 255 / 0.72);
|
|
100
|
+
--tenant-rail-border: rgb(255 255 255 / 0.08);
|
|
101
|
+
--tenant-rail-surface: rgb(255 255 255 / 0.06);
|
|
102
|
+
--overlay: var(--ds-foundation-overlay-50);
|
|
103
|
+
--overlay-strong: var(--ds-foundation-overlay-60);
|
|
104
|
+
--strong-foreground: var(--ds-foundation-white);
|
|
105
|
+
}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
@custom-variant dark (&:is(.dark *));
|
|
2
|
+
|
|
3
|
+
@theme inline {
|
|
4
|
+
--font-sans: "Geist", "Geist Fallback";
|
|
5
|
+
--font-mono: "Geist Mono", "Geist Mono Fallback";
|
|
6
|
+
--color-background: var(--background);
|
|
7
|
+
--color-foreground: var(--foreground);
|
|
8
|
+
--color-card: var(--card);
|
|
9
|
+
--color-card-foreground: var(--card-foreground);
|
|
10
|
+
--color-popover: var(--popover);
|
|
11
|
+
--color-popover-foreground: var(--popover-foreground);
|
|
12
|
+
--color-primary: var(--primary);
|
|
13
|
+
--color-primary-foreground: var(--primary-foreground);
|
|
14
|
+
--color-secondary: var(--secondary);
|
|
15
|
+
--color-secondary-foreground: var(--secondary-foreground);
|
|
16
|
+
--color-muted: var(--muted);
|
|
17
|
+
--color-muted-foreground: var(--muted-foreground);
|
|
18
|
+
--color-accent: var(--accent);
|
|
19
|
+
--color-accent-foreground: var(--accent-foreground);
|
|
20
|
+
--color-destructive: var(--destructive);
|
|
21
|
+
--color-destructive-foreground: var(--destructive-foreground);
|
|
22
|
+
--color-border: var(--border);
|
|
23
|
+
--color-input: var(--input);
|
|
24
|
+
--color-ring: var(--ring);
|
|
25
|
+
--color-chart-1: var(--chart-1);
|
|
26
|
+
--color-chart-2: var(--chart-2);
|
|
27
|
+
--color-chart-3: var(--chart-3);
|
|
28
|
+
--color-chart-4: var(--chart-4);
|
|
29
|
+
--color-chart-5: var(--chart-5);
|
|
30
|
+
--radius-sm: calc(var(--radius) - 4px);
|
|
31
|
+
--radius-md: calc(var(--radius) - 2px);
|
|
32
|
+
--radius-lg: var(--radius);
|
|
33
|
+
--radius-xl: calc(var(--radius) + 4px);
|
|
34
|
+
--color-sidebar: var(--sidebar);
|
|
35
|
+
--color-sidebar-foreground: var(--sidebar-foreground);
|
|
36
|
+
--color-sidebar-primary: var(--sidebar-primary);
|
|
37
|
+
--color-sidebar-primary-foreground: var(--sidebar-primary-foreground);
|
|
38
|
+
--color-sidebar-accent: var(--sidebar-accent);
|
|
39
|
+
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|
|
40
|
+
--color-sidebar-border: var(--sidebar-border);
|
|
41
|
+
--color-sidebar-ring: var(--sidebar-ring);
|
|
42
|
+
--color-surface: var(--surface);
|
|
43
|
+
--color-surface-raised: var(--surface-raised);
|
|
44
|
+
--color-text-link: var(--text-link);
|
|
45
|
+
--color-success: var(--success);
|
|
46
|
+
--color-warning: var(--warning);
|
|
47
|
+
--color-danger: var(--danger);
|
|
48
|
+
--color-info: var(--info);
|
|
49
|
+
--color-ai-bubble: var(--ai-bubble);
|
|
50
|
+
--color-user-bubble: var(--user-bubble);
|
|
51
|
+
--color-tenant-rail: var(--tenant-rail);
|
|
52
|
+
--color-tenant-rail-foreground: var(--tenant-rail-foreground);
|
|
53
|
+
--color-tenant-rail-muted: var(--tenant-rail-muted);
|
|
54
|
+
--color-tenant-rail-border: var(--tenant-rail-border);
|
|
55
|
+
--color-tenant-rail-surface: var(--tenant-rail-surface);
|
|
56
|
+
--color-overlay: var(--overlay);
|
|
57
|
+
--color-overlay-strong: var(--overlay-strong);
|
|
58
|
+
--color-strong-foreground: var(--strong-foreground);
|
|
59
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from "@storybook/nextjs-vite";
|
|
2
|
+
|
|
3
|
+
import tokenManifest from "@/design-system/tokens/manifest";
|
|
4
|
+
|
|
5
|
+
function TokenGrid({
|
|
6
|
+
entries,
|
|
7
|
+
}: {
|
|
8
|
+
entries: Array<[string, string]>;
|
|
9
|
+
}) {
|
|
10
|
+
return (
|
|
11
|
+
<div className="grid gap-3 sm:grid-cols-2">
|
|
12
|
+
{entries.map(([name, value]) => (
|
|
13
|
+
<div
|
|
14
|
+
key={name}
|
|
15
|
+
className="flex items-center gap-3 rounded-lg border border-border bg-surface p-3"
|
|
16
|
+
>
|
|
17
|
+
<div
|
|
18
|
+
className="h-10 w-10 rounded-md border border-border"
|
|
19
|
+
style={{ backgroundColor: `var(--${name})` }}
|
|
20
|
+
/>
|
|
21
|
+
<div className="min-w-0">
|
|
22
|
+
<p className="truncate text-sm font-medium text-foreground">{name}</p>
|
|
23
|
+
<p className="truncate text-xs text-muted-foreground">{value}</p>
|
|
24
|
+
</div>
|
|
25
|
+
</div>
|
|
26
|
+
))}
|
|
27
|
+
</div>
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function TokenShowcase() {
|
|
32
|
+
return (
|
|
33
|
+
<div className="w-[720px] space-y-8">
|
|
34
|
+
<section className="space-y-3">
|
|
35
|
+
<div>
|
|
36
|
+
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
37
|
+
Semantic
|
|
38
|
+
</p>
|
|
39
|
+
<h2 className="text-xl font-semibold text-foreground">Shared UI roles</h2>
|
|
40
|
+
</div>
|
|
41
|
+
<TokenGrid entries={Object.entries(tokenManifest.semantic)} />
|
|
42
|
+
</section>
|
|
43
|
+
<section className="space-y-3">
|
|
44
|
+
<div>
|
|
45
|
+
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
46
|
+
Foundation
|
|
47
|
+
</p>
|
|
48
|
+
<h2 className="text-xl font-semibold text-foreground">Literal sources</h2>
|
|
49
|
+
</div>
|
|
50
|
+
<TokenGrid entries={Object.entries(tokenManifest.foundation)} />
|
|
51
|
+
</section>
|
|
52
|
+
</div>
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const meta = {
|
|
57
|
+
title: "Design System/Tokens",
|
|
58
|
+
component: TokenShowcase,
|
|
59
|
+
tags: ["autodocs"],
|
|
60
|
+
parameters: {
|
|
61
|
+
layout: "fullscreen",
|
|
62
|
+
},
|
|
63
|
+
} satisfies Meta<typeof TokenShowcase>;
|
|
64
|
+
|
|
65
|
+
export default meta;
|
|
66
|
+
|
|
67
|
+
type Story = StoryObj<typeof meta>;
|
|
68
|
+
|
|
69
|
+
export const Overview: Story = {
|
|
70
|
+
render: () => <TokenShowcase />,
|
|
71
|
+
};
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import { ArrowRight, Database, ShieldCheck, UserRound } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { PanelFrame } from "@/design-system/patterns/panel-frame";
|
|
5
|
+
import { StatusBadge } from "@/design-system/patterns/status-badge";
|
|
6
|
+
import { Button } from "@/design-system/primitives/button";
|
|
7
|
+
import { appRoutes } from "@/lib/app-routes";
|
|
8
|
+
import type { AuthenticatedPlatformSession } from "@/lib/platform/contracts";
|
|
9
|
+
import type { SessionMembership } from "@/lib/platform/contracts";
|
|
10
|
+
import { preferredWorkspace } from "@/lib/platform/contracts";
|
|
11
|
+
|
|
12
|
+
function DashboardMetric({
|
|
13
|
+
label,
|
|
14
|
+
value,
|
|
15
|
+
}: {
|
|
16
|
+
label: string;
|
|
17
|
+
value: string;
|
|
18
|
+
}) {
|
|
19
|
+
return (
|
|
20
|
+
<PanelFrame tone="raised" radius="xl" padding="md" className="space-y-2">
|
|
21
|
+
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
|
|
22
|
+
{label}
|
|
23
|
+
</p>
|
|
24
|
+
<p className="text-sm font-semibold text-foreground">{value}</p>
|
|
25
|
+
</PanelFrame>
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function TenantDashboard({
|
|
30
|
+
appName,
|
|
31
|
+
membership: resolvedMembership,
|
|
32
|
+
session,
|
|
33
|
+
}: {
|
|
34
|
+
appName: string;
|
|
35
|
+
membership?: SessionMembership | null;
|
|
36
|
+
session: AuthenticatedPlatformSession;
|
|
37
|
+
}) {
|
|
38
|
+
const membership = resolvedMembership ?? preferredWorkspace(session);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<div className="grid gap-6">
|
|
42
|
+
<PanelFrame tone="floating" radius="xl" padding="lg" className="space-y-6">
|
|
43
|
+
<div className="space-y-2">
|
|
44
|
+
<h2 className="text-3xl font-semibold tracking-tight">
|
|
45
|
+
{appName} workspace
|
|
46
|
+
</h2>
|
|
47
|
+
<p className="max-w-3xl text-sm leading-7 text-muted-foreground">
|
|
48
|
+
Customer workspace state is loaded through the platform member
|
|
49
|
+
session established by central SSO.
|
|
50
|
+
</p>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div className="grid gap-3 md:grid-cols-3">
|
|
54
|
+
<DashboardMetric
|
|
55
|
+
label="Customer"
|
|
56
|
+
value={session.user?.display_name || session.user?.email || "Customer"}
|
|
57
|
+
/>
|
|
58
|
+
<DashboardMetric
|
|
59
|
+
label="Tenant"
|
|
60
|
+
value={membership?.workspace_name || membership?.tenant_name || "Workspace"}
|
|
61
|
+
/>
|
|
62
|
+
<DashboardMetric
|
|
63
|
+
label="Role"
|
|
64
|
+
value={
|
|
65
|
+
membership?.roles.map((role) => role.name).join(", ") ||
|
|
66
|
+
membership?.role ||
|
|
67
|
+
"member"
|
|
68
|
+
}
|
|
69
|
+
/>
|
|
70
|
+
</div>
|
|
71
|
+
</PanelFrame>
|
|
72
|
+
|
|
73
|
+
<section className="grid gap-6 xl:grid-cols-[1fr,1fr]">
|
|
74
|
+
<PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-4">
|
|
75
|
+
<div className="flex items-center gap-2">
|
|
76
|
+
<ShieldCheck className="size-5 text-primary" />
|
|
77
|
+
<h3 className="text-xl font-semibold tracking-tight">
|
|
78
|
+
Platform SSO
|
|
79
|
+
</h3>
|
|
80
|
+
</div>
|
|
81
|
+
<div className="flex flex-wrap gap-3">
|
|
82
|
+
<StatusBadge tone="primary">shell token</StatusBadge>
|
|
83
|
+
<StatusBadge tone="info">HttpOnly cookies</StatusBadge>
|
|
84
|
+
<StatusBadge tone="success">CSRF protected</StatusBadge>
|
|
85
|
+
</div>
|
|
86
|
+
<p className="text-sm leading-7 text-muted-foreground">
|
|
87
|
+
The shell consumes a platform member session and leaves identity,
|
|
88
|
+
provisioning, and install authority on platform-owned APIs.
|
|
89
|
+
</p>
|
|
90
|
+
</PanelFrame>
|
|
91
|
+
|
|
92
|
+
<PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-4">
|
|
93
|
+
<div className="flex items-center gap-2">
|
|
94
|
+
<Database className="size-5 text-primary" />
|
|
95
|
+
<h3 className="text-xl font-semibold tracking-tight">
|
|
96
|
+
Gateway surfaces
|
|
97
|
+
</h3>
|
|
98
|
+
</div>
|
|
99
|
+
<p className="text-sm leading-7 text-muted-foreground">
|
|
100
|
+
Runtime data and agent surfaces should be added through approved
|
|
101
|
+
app-pack and platform gateway contracts, not browser-held runtime
|
|
102
|
+
credentials.
|
|
103
|
+
</p>
|
|
104
|
+
<Button asChild className="w-fit">
|
|
105
|
+
<Link href={appRoutes.demo}>
|
|
106
|
+
Open demo
|
|
107
|
+
<ArrowRight className="size-4" />
|
|
108
|
+
</Link>
|
|
109
|
+
</Button>
|
|
110
|
+
</PanelFrame>
|
|
111
|
+
</section>
|
|
112
|
+
|
|
113
|
+
<PanelFrame tone="raised" radius="xl" padding="lg" className="space-y-4">
|
|
114
|
+
<div className="flex items-center gap-2">
|
|
115
|
+
<UserRound className="size-5 text-primary" />
|
|
116
|
+
<h3 className="text-xl font-semibold tracking-tight">
|
|
117
|
+
Session payload
|
|
118
|
+
</h3>
|
|
119
|
+
</div>
|
|
120
|
+
<pre className="overflow-auto rounded-md bg-muted p-4 text-xs text-muted-foreground">
|
|
121
|
+
{JSON.stringify(
|
|
122
|
+
{
|
|
123
|
+
principal_kind: "tenant_member",
|
|
124
|
+
tenant_id: membership?.tenant_id,
|
|
125
|
+
workspace_slug: membership?.workspace_slug,
|
|
126
|
+
},
|
|
127
|
+
null,
|
|
128
|
+
2,
|
|
129
|
+
)}
|
|
130
|
+
</pre>
|
|
131
|
+
</PanelFrame>
|
|
132
|
+
</div>
|
|
133
|
+
);
|
|
134
|
+
}
|
package/assets/templates/vuilder-shell/src/features/public-shell/components/static-public-page.tsx
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import { ArrowRight } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { Button } from "@/design-system/primitives/button";
|
|
5
|
+
import { appRoutes } from "@/lib/app-routes";
|
|
6
|
+
|
|
7
|
+
export function StaticPublicPage({
|
|
8
|
+
eyebrow,
|
|
9
|
+
title,
|
|
10
|
+
body,
|
|
11
|
+
}: {
|
|
12
|
+
eyebrow: string;
|
|
13
|
+
title: string;
|
|
14
|
+
body: string;
|
|
15
|
+
}) {
|
|
16
|
+
return (
|
|
17
|
+
<main className="min-h-screen bg-background text-foreground">
|
|
18
|
+
<div className="mx-auto flex min-h-screen max-w-6xl flex-col px-6 py-6">
|
|
19
|
+
<nav className="flex items-center justify-between">
|
|
20
|
+
<Link className="text-sm font-semibold text-foreground" href={appRoutes.publicHome}>
|
|
21
|
+
Vuilder Shell
|
|
22
|
+
</Link>
|
|
23
|
+
<div className="flex items-center gap-2">
|
|
24
|
+
<Button asChild variant="ghost">
|
|
25
|
+
<Link href={appRoutes.pricing}>Pricing</Link>
|
|
26
|
+
</Button>
|
|
27
|
+
<Button asChild variant="ghost">
|
|
28
|
+
<Link href={appRoutes.docsIndex}>Docs</Link>
|
|
29
|
+
</Button>
|
|
30
|
+
<Button asChild>
|
|
31
|
+
<Link href={appRoutes.login}>Log in</Link>
|
|
32
|
+
</Button>
|
|
33
|
+
</div>
|
|
34
|
+
</nav>
|
|
35
|
+
|
|
36
|
+
<section className="grid flex-1 content-center gap-8 py-16">
|
|
37
|
+
<div className="max-w-3xl space-y-5">
|
|
38
|
+
<p className="text-sm font-semibold uppercase tracking-widest text-muted-foreground">
|
|
39
|
+
{eyebrow}
|
|
40
|
+
</p>
|
|
41
|
+
<h1 className="text-5xl font-semibold tracking-tight text-balance sm:text-6xl">
|
|
42
|
+
{title}
|
|
43
|
+
</h1>
|
|
44
|
+
<p className="max-w-2xl text-lg leading-8 text-muted-foreground">
|
|
45
|
+
{body}
|
|
46
|
+
</p>
|
|
47
|
+
<Button asChild className="w-fit">
|
|
48
|
+
<Link href={appRoutes.login}>
|
|
49
|
+
Continue
|
|
50
|
+
<ArrowRight className="size-4" />
|
|
51
|
+
</Link>
|
|
52
|
+
</Button>
|
|
53
|
+
</div>
|
|
54
|
+
</section>
|
|
55
|
+
</div>
|
|
56
|
+
</main>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import type { ReactNode } from "react";
|
|
4
|
+
import Link from "next/link";
|
|
5
|
+
import { useRouter } from "next/navigation";
|
|
6
|
+
import { LayoutDashboard, LogOut, PlaySquare } from "lucide-react";
|
|
7
|
+
|
|
8
|
+
import { ThemeModeToggle } from "@/design-system/patterns/theme-mode-toggle";
|
|
9
|
+
import { Button } from "@/design-system/primitives/button";
|
|
10
|
+
import { appRoutes } from "@/lib/app-routes";
|
|
11
|
+
import type {
|
|
12
|
+
AuthenticatedPlatformSession,
|
|
13
|
+
SessionMembership,
|
|
14
|
+
} from "@/lib/platform/contracts";
|
|
15
|
+
|
|
16
|
+
export function AuthenticatedAppLayoutShell({
|
|
17
|
+
appName,
|
|
18
|
+
membership,
|
|
19
|
+
session,
|
|
20
|
+
children,
|
|
21
|
+
}: {
|
|
22
|
+
appName: string;
|
|
23
|
+
membership: SessionMembership;
|
|
24
|
+
session: AuthenticatedPlatformSession;
|
|
25
|
+
children: ReactNode;
|
|
26
|
+
}) {
|
|
27
|
+
const router = useRouter();
|
|
28
|
+
|
|
29
|
+
async function handleLogout() {
|
|
30
|
+
await fetch("/api/auth/logout", { method: "POST" }).catch(() => undefined);
|
|
31
|
+
router.replace(appRoutes.loginForWorkspace(membership.workspace_slug));
|
|
32
|
+
router.refresh();
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return (
|
|
36
|
+
<main className="min-h-screen bg-background text-foreground">
|
|
37
|
+
<div className="mx-auto flex min-h-screen max-w-7xl flex-col gap-6 px-6 py-8">
|
|
38
|
+
<header className="flex flex-col gap-6 xl:flex-row xl:items-start xl:justify-between">
|
|
39
|
+
<div className="space-y-2">
|
|
40
|
+
<p className="text-sm font-semibold uppercase tracking-widest text-muted-foreground">
|
|
41
|
+
{membership.workspace_name || membership.tenant_name}
|
|
42
|
+
</p>
|
|
43
|
+
<h1 className="max-w-3xl text-4xl font-semibold tracking-tight text-balance sm:text-5xl">
|
|
44
|
+
{appName}
|
|
45
|
+
</h1>
|
|
46
|
+
<p className="max-w-3xl text-base leading-7 text-muted-foreground sm:text-lg">
|
|
47
|
+
Signed in as {session.user?.email || session.user?.username}.
|
|
48
|
+
</p>
|
|
49
|
+
</div>
|
|
50
|
+
|
|
51
|
+
<div className="flex flex-col gap-3 sm:flex-row sm:items-start">
|
|
52
|
+
<ThemeModeToggle className="w-full sm:w-72" />
|
|
53
|
+
<Button
|
|
54
|
+
type="button"
|
|
55
|
+
variant="outline"
|
|
56
|
+
className="gap-2"
|
|
57
|
+
onClick={handleLogout}
|
|
58
|
+
>
|
|
59
|
+
<LogOut className="size-4" />
|
|
60
|
+
Log out
|
|
61
|
+
</Button>
|
|
62
|
+
</div>
|
|
63
|
+
</header>
|
|
64
|
+
|
|
65
|
+
<nav className="flex flex-wrap gap-2">
|
|
66
|
+
<Button asChild variant="default">
|
|
67
|
+
<Link href={appRoutes.workspaceShell(membership.workspace_slug)}>
|
|
68
|
+
<LayoutDashboard className="size-4" />
|
|
69
|
+
Dashboard
|
|
70
|
+
</Link>
|
|
71
|
+
</Button>
|
|
72
|
+
<Button asChild variant="outline">
|
|
73
|
+
<Link href={appRoutes.demo}>
|
|
74
|
+
<PlaySquare className="size-4" />
|
|
75
|
+
Demo
|
|
76
|
+
</Link>
|
|
77
|
+
</Button>
|
|
78
|
+
</nav>
|
|
79
|
+
|
|
80
|
+
{children}
|
|
81
|
+
</div>
|
|
82
|
+
</main>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { TenantDashboard } from "@/features/dashboard/components/tenant-dashboard";
|
|
2
|
+
import { VuilderConnectScreen } from "@/features/vuilder-shell/components/vuilder-connect-screen";
|
|
3
|
+
import type {
|
|
4
|
+
PlatformSession,
|
|
5
|
+
SessionMembership,
|
|
6
|
+
} from "@/lib/platform/contracts";
|
|
7
|
+
|
|
8
|
+
export function PrivateAppShell({
|
|
9
|
+
appName,
|
|
10
|
+
membership,
|
|
11
|
+
session,
|
|
12
|
+
}: {
|
|
13
|
+
appName: string;
|
|
14
|
+
membership: SessionMembership | null;
|
|
15
|
+
session: PlatformSession;
|
|
16
|
+
}) {
|
|
17
|
+
if (!session.authenticated || !membership) {
|
|
18
|
+
return <VuilderConnectScreen session={session} workspaceSlug="workspace" />;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
return <TenantDashboard appName={appName} membership={membership} session={session} />;
|
|
22
|
+
}
|
|
@@ -0,0 +1,89 @@
|
|
|
1
|
+
import Link from "next/link";
|
|
2
|
+
import { ArrowRight, CheckCircle2, ServerCog } from "lucide-react";
|
|
3
|
+
|
|
4
|
+
import { PanelFrame } from "@/design-system/patterns/panel-frame";
|
|
5
|
+
import { StatusBadge } from "@/design-system/patterns/status-badge";
|
|
6
|
+
import { Button } from "@/design-system/primitives/button";
|
|
7
|
+
import { appRoutes } from "@/lib/app-routes";
|
|
8
|
+
import type { PlatformSession } from "@/lib/platform/contracts";
|
|
9
|
+
import { workspaceMembershipForSession } from "@/lib/platform/contracts";
|
|
10
|
+
|
|
11
|
+
export function VuilderConnectScreen({
|
|
12
|
+
session,
|
|
13
|
+
workspaceSlug,
|
|
14
|
+
}: {
|
|
15
|
+
session: PlatformSession;
|
|
16
|
+
workspaceSlug: string;
|
|
17
|
+
}) {
|
|
18
|
+
const membership = workspaceMembershipForSession(session, workspaceSlug);
|
|
19
|
+
const tenantName = membership?.workspace_name || membership?.tenant_name || workspaceSlug;
|
|
20
|
+
const hasWorkspaceMembership = Boolean(membership);
|
|
21
|
+
const isAuthenticated = session.authenticated;
|
|
22
|
+
|
|
23
|
+
return (
|
|
24
|
+
<main className="min-h-screen bg-background text-foreground">
|
|
25
|
+
<div className="mx-auto flex min-h-screen max-w-5xl items-center px-6 py-10">
|
|
26
|
+
<PanelFrame tone="floating" radius="xl" padding="lg" className="w-full space-y-6">
|
|
27
|
+
<div className="flex items-center gap-3 text-primary">
|
|
28
|
+
{hasWorkspaceMembership ? (
|
|
29
|
+
<CheckCircle2 className="size-5" />
|
|
30
|
+
) : (
|
|
31
|
+
<ServerCog className="size-5" />
|
|
32
|
+
)}
|
|
33
|
+
<p className="text-sm font-semibold uppercase tracking-widest">
|
|
34
|
+
Vuilder Shell
|
|
35
|
+
</p>
|
|
36
|
+
</div>
|
|
37
|
+
|
|
38
|
+
<div className="space-y-3">
|
|
39
|
+
<h1 className="text-4xl font-semibold tracking-tight text-balance">
|
|
40
|
+
{hasWorkspaceMembership
|
|
41
|
+
? `${tenantName} is ready to open.`
|
|
42
|
+
: isAuthenticated
|
|
43
|
+
? "Workspace access is not available."
|
|
44
|
+
: "Sign in to open this customer workspace."}
|
|
45
|
+
</h1>
|
|
46
|
+
<p className="max-w-2xl text-base leading-7 text-muted-foreground">
|
|
47
|
+
Runtime provisioning and app-pack installation are owned by the
|
|
48
|
+
platform onboarding intent. This shell opens the branded tenant
|
|
49
|
+
experience after the customer session is available.
|
|
50
|
+
</p>
|
|
51
|
+
</div>
|
|
52
|
+
|
|
53
|
+
<div className="grid gap-3 sm:grid-cols-3">
|
|
54
|
+
<StatusBadge tone={isAuthenticated ? "success" : "default"}>
|
|
55
|
+
Identity
|
|
56
|
+
</StatusBadge>
|
|
57
|
+
<StatusBadge tone="primary">Runtime</StatusBadge>
|
|
58
|
+
<StatusBadge tone="primary">App Pack</StatusBadge>
|
|
59
|
+
</div>
|
|
60
|
+
|
|
61
|
+
<div className="flex flex-col gap-3 sm:flex-row">
|
|
62
|
+
{hasWorkspaceMembership ? (
|
|
63
|
+
<Button asChild className="gap-2">
|
|
64
|
+
<Link href={appRoutes.workspaceShell(workspaceSlug)}>
|
|
65
|
+
Open Workspace
|
|
66
|
+
<ArrowRight className="size-4" />
|
|
67
|
+
</Link>
|
|
68
|
+
</Button>
|
|
69
|
+
) : !isAuthenticated ? (
|
|
70
|
+
<Button asChild className="gap-2">
|
|
71
|
+
<Link href={appRoutes.loginForWorkspaceConnect(workspaceSlug)}>
|
|
72
|
+
Open Login
|
|
73
|
+
<ArrowRight className="size-4" />
|
|
74
|
+
</Link>
|
|
75
|
+
</Button>
|
|
76
|
+
) : (
|
|
77
|
+
<Button asChild variant="outline" className="gap-2">
|
|
78
|
+
<Link href={appRoutes.appHome}>
|
|
79
|
+
Workspace Home
|
|
80
|
+
<ArrowRight className="size-4" />
|
|
81
|
+
</Link>
|
|
82
|
+
</Button>
|
|
83
|
+
)}
|
|
84
|
+
</div>
|
|
85
|
+
</PanelFrame>
|
|
86
|
+
</div>
|
|
87
|
+
</main>
|
|
88
|
+
);
|
|
89
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { Building2, Package, ServerCog } from "lucide-react";
|
|
2
|
+
|
|
3
|
+
import { PanelFrame } from "@/design-system/patterns/panel-frame";
|
|
4
|
+
import { StatusBadge } from "@/design-system/patterns/status-badge";
|
|
5
|
+
import { TenantDashboard } from "@/features/dashboard/components/tenant-dashboard";
|
|
6
|
+
import type {
|
|
7
|
+
AuthenticatedPlatformSession,
|
|
8
|
+
SessionMembership,
|
|
9
|
+
} from "@/lib/platform/contracts";
|
|
10
|
+
|
|
11
|
+
export function VuilderWorkspaceScreen({
|
|
12
|
+
appName,
|
|
13
|
+
membership,
|
|
14
|
+
session,
|
|
15
|
+
workspaceSlug,
|
|
16
|
+
}: {
|
|
17
|
+
appName: string;
|
|
18
|
+
membership: SessionMembership;
|
|
19
|
+
session: AuthenticatedPlatformSession;
|
|
20
|
+
workspaceSlug: string;
|
|
21
|
+
}) {
|
|
22
|
+
return (
|
|
23
|
+
<div className="grid gap-6">
|
|
24
|
+
<PanelFrame tone="floating" radius="xl" padding="lg" className="space-y-4">
|
|
25
|
+
<div className="flex flex-wrap gap-3">
|
|
26
|
+
<StatusBadge tone="primary">
|
|
27
|
+
<Building2 className="mr-1 size-3" />
|
|
28
|
+
{membership.workspace_slug || workspaceSlug}
|
|
29
|
+
</StatusBadge>
|
|
30
|
+
<StatusBadge tone="primary">
|
|
31
|
+
<ServerCog className="mr-1 size-3" />
|
|
32
|
+
{membership.runtime_status || "Runtime status"}
|
|
33
|
+
</StatusBadge>
|
|
34
|
+
<StatusBadge tone="primary">
|
|
35
|
+
<Package className="mr-1 size-3" />
|
|
36
|
+
App pack status
|
|
37
|
+
</StatusBadge>
|
|
38
|
+
</div>
|
|
39
|
+
<p className="max-w-3xl text-sm leading-7 text-muted-foreground">
|
|
40
|
+
This branded shell renders the tenant experience for the active
|
|
41
|
+
customer session. Identity, provisioning, and install authority remain
|
|
42
|
+
on the MinuteWork platform path.
|
|
43
|
+
</p>
|
|
44
|
+
</PanelFrame>
|
|
45
|
+
|
|
46
|
+
<TenantDashboard appName={appName} membership={membership} session={session} />
|
|
47
|
+
</div>
|
|
48
|
+
);
|
|
49
|
+
}
|