@tangle-network/ui 1.0.0
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/CHANGELOG.md +12 -0
- package/LICENSE +21 -0
- package/README.md +33 -0
- package/dist/active-sessions-store-CeOmXgv5.d.ts +85 -0
- package/dist/artifact-pane-DvJyPWV4.d.ts +24 -0
- package/dist/auth.d.ts +74 -0
- package/dist/auth.js +15 -0
- package/dist/button-CMQuQEW_.d.ts +17 -0
- package/dist/chat.d.ts +232 -0
- package/dist/chat.js +30 -0
- package/dist/chunk-2NFQRQOD.js +1009 -0
- package/dist/chunk-2VH6PUXD.js +186 -0
- package/dist/chunk-34A66VBG.js +214 -0
- package/dist/chunk-3OI2QKFD.js +0 -0
- package/dist/chunk-4CLN43XT.js +45 -0
- package/dist/chunk-54SQQMMM.js +156 -0
- package/dist/chunk-5Z5ZYMOJ.js +0 -0
- package/dist/chunk-66BNMOVT.js +167 -0
- package/dist/chunk-6BGQA4BQ.js +0 -0
- package/dist/chunk-7UO2ZMRQ.js +133 -0
- package/dist/chunk-BX6AQMUS.js +183 -0
- package/dist/chunk-CD53GZOM.js +59 -0
- package/dist/chunk-CSAIKY36.js +54 -0
- package/dist/chunk-EEE55AVS.js +1201 -0
- package/dist/chunk-GYPQXTJU.js +230 -0
- package/dist/chunk-HFL6R6IF.js +37 -0
- package/dist/chunk-HJKCSXCH.js +737 -0
- package/dist/chunk-LISXUB4D.js +1222 -0
- package/dist/chunk-LQS34IGP.js +0 -0
- package/dist/chunk-MKTSMWVD.js +109 -0
- package/dist/chunk-NKDZ7GZE.js +192 -0
- package/dist/chunk-OEX7NZE3.js +321 -0
- package/dist/chunk-Q56BYXQF.js +61 -0
- package/dist/chunk-Q7EIIWTC.js +0 -0
- package/dist/chunk-REJESC5U.js +117 -0
- package/dist/chunk-RQGKSCEZ.js +0 -0
- package/dist/chunk-RQHJBTEU.js +10 -0
- package/dist/chunk-TMFOPHHN.js +299 -0
- package/dist/chunk-XGKULLYE.js +40 -0
- package/dist/chunk-XIHMJ7ZQ.js +614 -0
- package/dist/chunk-YJ2G3XO5.js +1048 -0
- package/dist/chunk-YNN4O57I.js +754 -0
- package/dist/code-block-DjXf8eOG.d.ts +19 -0
- package/dist/document-editor-pane-A5LT5H4N.js +12 -0
- package/dist/document-editor-pane-DyDEX_Zm.d.ts +124 -0
- package/dist/editor.d.ts +120 -0
- package/dist/editor.js +34 -0
- package/dist/files.d.ts +175 -0
- package/dist/files.js +20 -0
- package/dist/hooks.d.ts +56 -0
- package/dist/hooks.js +41 -0
- package/dist/index.d.ts +43 -0
- package/dist/index.js +446 -0
- package/dist/markdown.d.ts +15 -0
- package/dist/markdown.js +14 -0
- package/dist/message-BHWbxBtT.d.ts +15 -0
- package/dist/openui.d.ts +115 -0
- package/dist/openui.js +12 -0
- package/dist/parts-dj7AcUg0.d.ts +36 -0
- package/dist/primitives.d.ts +332 -0
- package/dist/primitives.js +191 -0
- package/dist/run-PfLmDAox.d.ts +41 -0
- package/dist/run.d.ts +69 -0
- package/dist/run.js +36 -0
- package/dist/sdk-hooks.d.ts +285 -0
- package/dist/sdk-hooks.js +31 -0
- package/dist/stores.d.ts +17 -0
- package/dist/stores.js +76 -0
- package/dist/tool-call-feed-Bs3MyQMT.d.ts +68 -0
- package/dist/tool-display-z4JcDmMQ.d.ts +32 -0
- package/dist/tool-previews.d.ts +48 -0
- package/dist/tool-previews.js +21 -0
- package/dist/types.d.ts +19 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +45 -0
- package/dist/utils.js +32 -0
- package/package.json +193 -0
- package/src/auth/auth.tsx +228 -0
- package/src/auth/index.ts +13 -0
- package/src/auth/login-layout.tsx +46 -0
- package/src/chat/agent-timeline.stories.tsx +429 -0
- package/src/chat/agent-timeline.tsx +360 -0
- package/src/chat/chat-container.tsx +486 -0
- package/src/chat/chat-input.stories.tsx +142 -0
- package/src/chat/chat-input.tsx +389 -0
- package/src/chat/chat-message.stories.tsx +237 -0
- package/src/chat/chat-message.tsx +129 -0
- package/src/chat/index.ts +18 -0
- package/src/chat/message-list.stories.tsx +336 -0
- package/src/chat/message-list.tsx +79 -0
- package/src/chat/thinking-indicator.stories.tsx +56 -0
- package/src/chat/thinking-indicator.tsx +30 -0
- package/src/chat/user-message.stories.tsx +92 -0
- package/src/chat/user-message.tsx +43 -0
- package/src/editor/document-editor-pane.tsx +351 -0
- package/src/editor/editor-provider.tsx +428 -0
- package/src/editor/editor-toolbar.tsx +130 -0
- package/src/editor/index.ts +31 -0
- package/src/editor/markdown-conversion.ts +21 -0
- package/src/editor/markdown-document-editor.tsx +137 -0
- package/src/editor/tiptap-editor.tsx +331 -0
- package/src/editor/use-editor.ts +221 -0
- package/src/files/file-artifact-pane.tsx +183 -0
- package/src/files/file-preview.tsx +342 -0
- package/src/files/file-tabs.tsx +71 -0
- package/src/files/file-tree.tsx +258 -0
- package/src/files/index.ts +17 -0
- package/src/files/rich-file-tree.stories.tsx +104 -0
- package/src/files/rich-file-tree.test.tsx +42 -0
- package/src/files/rich-file-tree.tsx +232 -0
- package/src/hooks/index.ts +10 -0
- package/src/hooks/use-auth.ts +153 -0
- package/src/hooks/use-auto-scroll.ts +59 -0
- package/src/hooks/use-dropdown-menu.ts +40 -0
- package/src/hooks/use-live-time.test.tsx +40 -0
- package/src/hooks/use-live-time.ts +27 -0
- package/src/hooks/use-realtime-session.ts +319 -0
- package/src/hooks/use-run-collapse-state.ts +25 -0
- package/src/hooks/use-run-groups.ts +111 -0
- package/src/hooks/use-sdk-session.ts +575 -0
- package/src/hooks/use-sse-stream.ts +475 -0
- package/src/hooks/use-tool-call-stream.ts +96 -0
- package/src/index.ts +14 -0
- package/src/lib/utils.ts +6 -0
- package/src/markdown/code-block.tsx +198 -0
- package/src/markdown/index.ts +2 -0
- package/src/markdown/markdown.stories.tsx +190 -0
- package/src/markdown/markdown.tsx +62 -0
- package/src/openui/index.ts +20 -0
- package/src/openui/openui-artifact-renderer.tsx +542 -0
- package/src/primitives/artifact-pane.tsx +91 -0
- package/src/primitives/avatar.stories.tsx +95 -0
- package/src/primitives/avatar.tsx +47 -0
- package/src/primitives/badge.stories.tsx +57 -0
- package/src/primitives/badge.tsx +97 -0
- package/src/primitives/button.stories.tsx +48 -0
- package/src/primitives/button.tsx +115 -0
- package/src/primitives/card.stories.tsx +53 -0
- package/src/primitives/card.tsx +98 -0
- package/src/primitives/code-block.stories.tsx +115 -0
- package/src/primitives/code-block.tsx +22 -0
- package/src/primitives/design-tokens.stories.tsx +162 -0
- package/src/primitives/dialog.stories.tsx +176 -0
- package/src/primitives/dialog.tsx +137 -0
- package/src/primitives/drop-zone.stories.tsx +123 -0
- package/src/primitives/drop-zone.tsx +131 -0
- package/src/primitives/dropdown-menu.stories.tsx +122 -0
- package/src/primitives/dropdown-menu.tsx +214 -0
- package/src/primitives/empty-state.stories.tsx +81 -0
- package/src/primitives/empty-state.tsx +40 -0
- package/src/primitives/index.ts +118 -0
- package/src/primitives/input.stories.tsx +113 -0
- package/src/primitives/input.tsx +136 -0
- package/src/primitives/label.stories.tsx +84 -0
- package/src/primitives/label.tsx +24 -0
- package/src/primitives/progress.stories.tsx +93 -0
- package/src/primitives/progress.tsx +50 -0
- package/src/primitives/segmented-control.test.tsx +328 -0
- package/src/primitives/segmented-control.tsx +154 -0
- package/src/primitives/select.stories.tsx +164 -0
- package/src/primitives/select.tsx +158 -0
- package/src/primitives/sidebar-drop-zone.stories.tsx +100 -0
- package/src/primitives/sidebar-drop-zone.tsx +149 -0
- package/src/primitives/skeleton.stories.tsx +79 -0
- package/src/primitives/skeleton.tsx +55 -0
- package/src/primitives/stat-card.stories.tsx +137 -0
- package/src/primitives/stat-card.tsx +97 -0
- package/src/primitives/switch.stories.tsx +85 -0
- package/src/primitives/switch.tsx +28 -0
- package/src/primitives/table.stories.tsx +170 -0
- package/src/primitives/table.tsx +116 -0
- package/src/primitives/tabs.stories.tsx +180 -0
- package/src/primitives/tabs.tsx +71 -0
- package/src/primitives/terminal-display.stories.tsx +191 -0
- package/src/primitives/terminal-display.tsx +189 -0
- package/src/primitives/theme-toggle.stories.tsx +32 -0
- package/src/primitives/theme-toggle.tsx +96 -0
- package/src/primitives/toast.stories.tsx +155 -0
- package/src/primitives/toast.tsx +190 -0
- package/src/primitives/upload-progress.stories.tsx +120 -0
- package/src/primitives/upload-progress.tsx +110 -0
- package/src/run/expanded-tool-detail.stories.tsx +182 -0
- package/src/run/expanded-tool-detail.tsx +186 -0
- package/src/run/index.ts +13 -0
- package/src/run/inline-thinking-item.stories.tsx +136 -0
- package/src/run/inline-thinking-item.tsx +120 -0
- package/src/run/inline-tool-item.stories.tsx +222 -0
- package/src/run/inline-tool-item.tsx +190 -0
- package/src/run/run-group.stories.tsx +322 -0
- package/src/run/run-group.tsx +569 -0
- package/src/run/run-item-primitives.tsx +17 -0
- package/src/run/tool-call-feed.stories.tsx +294 -0
- package/src/run/tool-call-feed.tsx +192 -0
- package/src/run/tool-call-step.stories.tsx +198 -0
- package/src/run/tool-call-step.tsx +240 -0
- package/src/sdk-hooks.ts +38 -0
- package/src/stores/active-sessions-store.ts +455 -0
- package/src/stores/chat-store.ts +43 -0
- package/src/stores/index.ts +2 -0
- package/src/tool-previews/command-preview.tsx +116 -0
- package/src/tool-previews/diff-preview.tsx +85 -0
- package/src/tool-previews/glob-results-preview.tsx +98 -0
- package/src/tool-previews/grep-results-preview.tsx +157 -0
- package/src/tool-previews/index.ts +22 -0
- package/src/tool-previews/preview-primitives.tsx +84 -0
- package/src/tool-previews/question-preview.tsx +101 -0
- package/src/tool-previews/web-search-preview.tsx +117 -0
- package/src/tool-previews/write-file-preview.tsx +80 -0
- package/src/types/branding.ts +11 -0
- package/src/types/index.ts +5 -0
- package/src/types/message.ts +13 -0
- package/src/types/parts.ts +51 -0
- package/src/types/run.ts +56 -0
- package/src/types/tool-display.ts +41 -0
- package/src/utils/copy-text.ts +30 -0
- package/src/utils/format.test.ts +43 -0
- package/src/utils/format.ts +56 -0
- package/src/utils/index.ts +10 -0
- package/src/utils/time-ago.ts +9 -0
- package/src/utils/tool-display.ts +238 -0
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { CodeBlock, InlineCode } from './code-block'
|
|
3
|
+
|
|
4
|
+
const meta: Meta<typeof CodeBlock> = {
|
|
5
|
+
title: 'Primitives/CodeBlock',
|
|
6
|
+
component: CodeBlock,
|
|
7
|
+
parameters: { layout: 'centered', backgrounds: { default: 'dark' } },
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default meta
|
|
11
|
+
type Story = StoryObj<typeof CodeBlock>
|
|
12
|
+
|
|
13
|
+
const sandboxClientCode = `import { SandboxClient } from '@tangle/sandbox-sdk'
|
|
14
|
+
|
|
15
|
+
const client = new SandboxClient({
|
|
16
|
+
apiKey: process.env.TANGLE_API_KEY,
|
|
17
|
+
region: 'us-east-1',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const session = await client.sessions.create({
|
|
21
|
+
image: 'node:20-alpine',
|
|
22
|
+
resources: { cpu: 2, memoryMb: 512 },
|
|
23
|
+
timeout: 300,
|
|
24
|
+
})
|
|
25
|
+
|
|
26
|
+
const result = await session.exec('node -e "console.log(process.version)"')
|
|
27
|
+
console.log(result.stdout) // v20.11.0
|
|
28
|
+
|
|
29
|
+
await session.terminate()`
|
|
30
|
+
|
|
31
|
+
const hookCode = `import { useState, useCallback } from 'react'
|
|
32
|
+
|
|
33
|
+
type Status = 'idle' | 'running' | 'success' | 'error'
|
|
34
|
+
|
|
35
|
+
export function useSandboxSession(sessionId: string) {
|
|
36
|
+
const [status, setStatus] = useState<Status>('idle')
|
|
37
|
+
const [output, setOutput] = useState<string[]>([])
|
|
38
|
+
|
|
39
|
+
const exec = useCallback(async (command: string) => {
|
|
40
|
+
setStatus('running')
|
|
41
|
+
try {
|
|
42
|
+
const res = await fetch(\`/api/sessions/\${sessionId}/exec\`, {
|
|
43
|
+
method: 'POST',
|
|
44
|
+
body: JSON.stringify({ command }),
|
|
45
|
+
})
|
|
46
|
+
const data = await res.json()
|
|
47
|
+
setOutput((prev) => [...prev, data.stdout])
|
|
48
|
+
setStatus('success')
|
|
49
|
+
} catch (err) {
|
|
50
|
+
setStatus('error')
|
|
51
|
+
}
|
|
52
|
+
}, [sessionId])
|
|
53
|
+
|
|
54
|
+
return { status, output, exec }
|
|
55
|
+
}`
|
|
56
|
+
|
|
57
|
+
export const Default: Story = {
|
|
58
|
+
args: {
|
|
59
|
+
code: sandboxClientCode,
|
|
60
|
+
language: 'typescript',
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const WithLineNumbers: Story = {
|
|
65
|
+
name: 'With Line Numbers',
|
|
66
|
+
args: {
|
|
67
|
+
code: sandboxClientCode,
|
|
68
|
+
language: 'typescript',
|
|
69
|
+
showLineNumbers: true,
|
|
70
|
+
},
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export const ShortSnippet: Story = {
|
|
74
|
+
name: 'Short Snippet',
|
|
75
|
+
args: {
|
|
76
|
+
code: `const session = await client.sessions.create({ image: 'node:20' })`,
|
|
77
|
+
language: 'typescript',
|
|
78
|
+
showLineNumbers: false,
|
|
79
|
+
},
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export const HookExample: Story = {
|
|
83
|
+
name: 'Hook Example',
|
|
84
|
+
args: {
|
|
85
|
+
code: hookCode,
|
|
86
|
+
language: 'typescript',
|
|
87
|
+
showLineNumbers: true,
|
|
88
|
+
},
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
export const NoCopyButton: Story = {
|
|
92
|
+
name: 'No Copy Button',
|
|
93
|
+
args: {
|
|
94
|
+
code: `$ curl -X POST https://api.tangle.network/v1/sessions \\\n -H "Authorization: Bearer $TANGLE_API_KEY" \\\n -d '{"image": "node:20-alpine"}'`,
|
|
95
|
+
showLineNumbers: false,
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export const InlineCodeExample: Story = {
|
|
100
|
+
name: 'Inline Code',
|
|
101
|
+
render: () => (
|
|
102
|
+
<div className="space-y-3 text-sm text-foreground max-w-prose">
|
|
103
|
+
<p>
|
|
104
|
+
Use <InlineCode>client.sessions.create()</InlineCode> to provision a new sandbox
|
|
105
|
+
session. Pass <InlineCode>resources.memoryMb</InlineCode> to set memory limits.
|
|
106
|
+
</p>
|
|
107
|
+
<p>
|
|
108
|
+
The <InlineCode>exec()</InlineCode> method returns a{' '}
|
|
109
|
+
<InlineCode>Promise{'<ExecResult>'}</InlineCode> with{' '}
|
|
110
|
+
<InlineCode>stdout</InlineCode>, <InlineCode>stderr</InlineCode>, and{' '}
|
|
111
|
+
<InlineCode>exitCode</InlineCode>.
|
|
112
|
+
</p>
|
|
113
|
+
</div>
|
|
114
|
+
),
|
|
115
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Re-exports the canonical themed CodeBlock from the markdown package.
|
|
2
|
+
// Kept here for backwards compatibility with openui and other importers.
|
|
3
|
+
export { CodeBlock, CopyButton } from "../markdown/code-block";
|
|
4
|
+
export type { CodeBlockProps } from "../markdown/code-block";
|
|
5
|
+
|
|
6
|
+
import { cn } from "../lib/utils";
|
|
7
|
+
|
|
8
|
+
export interface InlineCodeProps extends React.HTMLAttributes<HTMLElement> {}
|
|
9
|
+
|
|
10
|
+
export function InlineCode({ className, children, ...props }: InlineCodeProps) {
|
|
11
|
+
return (
|
|
12
|
+
<code
|
|
13
|
+
className={cn(
|
|
14
|
+
"rounded border border-border bg-card px-1.5 py-0.5 font-mono text-[0.85em] text-[var(--code-keyword)]",
|
|
15
|
+
className,
|
|
16
|
+
)}
|
|
17
|
+
{...props}
|
|
18
|
+
>
|
|
19
|
+
{children}
|
|
20
|
+
</code>
|
|
21
|
+
);
|
|
22
|
+
}
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
|
|
3
|
+
const meta: Meta = {
|
|
4
|
+
title: 'Design System/Tokens',
|
|
5
|
+
parameters: { layout: 'fullscreen' },
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export default meta
|
|
9
|
+
type Story = StoryObj
|
|
10
|
+
|
|
11
|
+
const ColorSwatch = ({ name, value, label }: { name: string; value: string; label?: string }) => (
|
|
12
|
+
<div className="flex flex-col gap-1.5">
|
|
13
|
+
<div
|
|
14
|
+
className="h-12 w-full rounded-lg border border-[var(--glass-border)]"
|
|
15
|
+
style={{ background: value }}
|
|
16
|
+
/>
|
|
17
|
+
<div className="text-foreground text-xs font-medium">{name}</div>
|
|
18
|
+
{label && <div className="text-muted-foreground text-[10px] font-mono">{label}</div>}
|
|
19
|
+
</div>
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const DepthSwatch = ({ level, hex }: { level: string; hex: string }) => (
|
|
23
|
+
<div className="flex items-center gap-3">
|
|
24
|
+
<div
|
|
25
|
+
className="h-10 w-10 rounded-lg border border-[var(--glass-border)] flex-shrink-0"
|
|
26
|
+
style={{ background: hex }}
|
|
27
|
+
/>
|
|
28
|
+
<div>
|
|
29
|
+
<div className="text-foreground text-xs font-medium">{level}</div>
|
|
30
|
+
<div className="text-muted-foreground text-[10px] font-mono">{hex}</div>
|
|
31
|
+
</div>
|
|
32
|
+
</div>
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
const StatusSwatch = ({ name, cssVar, label }: { name: string; cssVar: string; label: string }) => (
|
|
36
|
+
<div className="flex items-center gap-3">
|
|
37
|
+
<div
|
|
38
|
+
className="h-3 w-3 rounded-full flex-shrink-0"
|
|
39
|
+
style={{ background: `var(${cssVar})` }}
|
|
40
|
+
/>
|
|
41
|
+
<div>
|
|
42
|
+
<div className="text-foreground text-xs font-medium">{name}</div>
|
|
43
|
+
<div className="text-muted-foreground text-[10px] font-mono">{label}</div>
|
|
44
|
+
</div>
|
|
45
|
+
</div>
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
export const Colors: Story = {
|
|
49
|
+
render: () => (
|
|
50
|
+
<div className="bg-background p-8 min-h-screen">
|
|
51
|
+
<div className="max-w-4xl mx-auto space-y-10">
|
|
52
|
+
|
|
53
|
+
<div>
|
|
54
|
+
<h2 className="text-foreground font-semibold text-lg mb-1">Background Depth</h2>
|
|
55
|
+
<p className="text-muted-foreground text-sm mb-4">4-level hierarchy for layering UI surfaces</p>
|
|
56
|
+
<div className="flex flex-col gap-3">
|
|
57
|
+
<DepthSwatch level="--depth-1 (root)" hex="#08071A" />
|
|
58
|
+
<DepthSwatch level="--depth-2 (surface)" hex="#131228" />
|
|
59
|
+
<DepthSwatch level="--depth-3 (card)" hex="#1C1A3A" />
|
|
60
|
+
<DepthSwatch level="--depth-4 (elevated)" hex="#26244C" />
|
|
61
|
+
</div>
|
|
62
|
+
</div>
|
|
63
|
+
|
|
64
|
+
<div>
|
|
65
|
+
<h2 className="text-foreground font-semibold text-lg mb-1">Brand Palette</h2>
|
|
66
|
+
<p className="text-muted-foreground text-sm mb-4">Core identity colors</p>
|
|
67
|
+
<div className="grid grid-cols-3 gap-4">
|
|
68
|
+
<ColorSwatch name="Brand Primary" value="#4a3aff" label="#4a3aff — electric indigo" />
|
|
69
|
+
<ColorSwatch name="Brand Cool" value="#8263FF" label="#8263FF — violet" />
|
|
70
|
+
<ColorSwatch name="Brand Glow" value="#6D6AFF" label="#6D6AFF — periwinkle" />
|
|
71
|
+
<ColorSwatch name="Brand Purple" value="#A78FFF" label="#A78FFF — lavender accent" />
|
|
72
|
+
<ColorSwatch name="Brand Emerald" value="#10b981" label="#10b981 — runtime green" />
|
|
73
|
+
<ColorSwatch name="Text Muted" value="#6B7094" label="#6B7094 — muted label" />
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<div>
|
|
78
|
+
<h2 className="text-foreground font-semibold text-lg mb-1">Operational Status</h2>
|
|
79
|
+
<p className="text-muted-foreground text-sm mb-4">Infrastructure and agent state vocabulary</p>
|
|
80
|
+
<div className="grid grid-cols-2 gap-3">
|
|
81
|
+
<StatusSwatch name="Running" cssVar="--status-running" label="#10b981" />
|
|
82
|
+
<StatusSwatch name="Creating" cssVar="--status-creating" label="#8263FF" />
|
|
83
|
+
<StatusSwatch name="Stopped" cssVar="--status-stopped" label="#FFB800" />
|
|
84
|
+
<StatusSwatch name="Warm" cssVar="--status-warm" label="#FF8A4C" />
|
|
85
|
+
<StatusSwatch name="Cold" cssVar="--status-cold" label="#4AABFF" />
|
|
86
|
+
<StatusSwatch name="Error" cssVar="--status-error" label="#FF4D6D" />
|
|
87
|
+
<StatusSwatch name="Deleted" cssVar="--status-deleted" label="#6B7094" />
|
|
88
|
+
</div>
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
<div>
|
|
92
|
+
<h2 className="text-foreground font-semibold text-lg mb-1">Glass Morphism</h2>
|
|
93
|
+
<p className="text-muted-foreground text-sm mb-4">Layered transparency system</p>
|
|
94
|
+
<div className="bg-mesh rounded-xl p-6 flex gap-4">
|
|
95
|
+
<div className="glass-card rounded-xl p-4 flex-1">
|
|
96
|
+
<div className="text-foreground text-sm font-medium mb-1">glass-card</div>
|
|
97
|
+
<div className="text-muted-foreground text-xs">65% opacity · 16px blur</div>
|
|
98
|
+
</div>
|
|
99
|
+
<div className="glass-card-strong rounded-xl p-4 flex-1">
|
|
100
|
+
<div className="text-foreground text-sm font-medium mb-1">glass-card-strong</div>
|
|
101
|
+
<div className="text-muted-foreground text-xs">85% opacity · 24px blur</div>
|
|
102
|
+
</div>
|
|
103
|
+
</div>
|
|
104
|
+
</div>
|
|
105
|
+
|
|
106
|
+
<div>
|
|
107
|
+
<h2 className="text-foreground font-semibold text-lg mb-1">Typography</h2>
|
|
108
|
+
<p className="text-muted-foreground text-sm mb-4">Geist (UI) · Outfit (display) · Geist Mono (code)</p>
|
|
109
|
+
<div className="space-y-3">
|
|
110
|
+
<div style={{ fontFamily: 'var(--font-display)' }} className="text-foreground text-4xl font-bold">
|
|
111
|
+
Display Heading
|
|
112
|
+
</div>
|
|
113
|
+
<div style={{ fontFamily: 'var(--font-sans)' }} className="text-foreground text-xl">
|
|
114
|
+
UI Body — Geist, clean and precise
|
|
115
|
+
</div>
|
|
116
|
+
<div style={{ fontFamily: 'var(--font-mono)' }} className="text-foreground text-sm text-[var(--code-string)]">
|
|
117
|
+
{'const agent = await sandbox.run({ model: "gpt-4o" })'}
|
|
118
|
+
</div>
|
|
119
|
+
</div>
|
|
120
|
+
</div>
|
|
121
|
+
|
|
122
|
+
<div>
|
|
123
|
+
<h2 className="text-foreground font-semibold text-lg mb-1">Gradients</h2>
|
|
124
|
+
<p className="text-muted-foreground text-sm mb-4">Brand gradient system</p>
|
|
125
|
+
<div className="space-y-3">
|
|
126
|
+
<div className="rounded-lg h-12" style={{ background: 'var(--tangle-gradient)' }} />
|
|
127
|
+
<div className="rounded-lg h-12" style={{ background: 'var(--accent-gradient-strong)' }} />
|
|
128
|
+
<div className="text-gradient-sandbox text-3xl font-bold">
|
|
129
|
+
Gradient Text
|
|
130
|
+
</div>
|
|
131
|
+
</div>
|
|
132
|
+
</div>
|
|
133
|
+
|
|
134
|
+
</div>
|
|
135
|
+
</div>
|
|
136
|
+
),
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export const StatusDots: Story = {
|
|
140
|
+
name: 'Status Dots',
|
|
141
|
+
render: () => (
|
|
142
|
+
<div className="bg-background p-8 min-h-screen">
|
|
143
|
+
<div className="space-y-6 max-w-sm">
|
|
144
|
+
<h2 className="text-foreground font-semibold text-lg">Status Dot Indicators</h2>
|
|
145
|
+
{[
|
|
146
|
+
{ label: 'Running', cls: 'status-dot status-dot-running' },
|
|
147
|
+
{ label: 'Creating', cls: 'status-dot status-dot-creating' },
|
|
148
|
+
{ label: 'Stopped', cls: 'status-dot status-dot-stopped' },
|
|
149
|
+
{ label: 'Warm', cls: 'status-dot status-dot-warm' },
|
|
150
|
+
{ label: 'Cold', cls: 'status-dot status-dot-cold' },
|
|
151
|
+
{ label: 'Error', cls: 'status-dot status-dot-error' },
|
|
152
|
+
{ label: 'Deleted', cls: 'status-dot status-dot-deleted' },
|
|
153
|
+
].map(({ label, cls }) => (
|
|
154
|
+
<div key={label} className="flex items-center gap-3">
|
|
155
|
+
<span className={cls} />
|
|
156
|
+
<span className="text-foreground text-sm">{label}</span>
|
|
157
|
+
</div>
|
|
158
|
+
))}
|
|
159
|
+
</div>
|
|
160
|
+
</div>
|
|
161
|
+
),
|
|
162
|
+
}
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import type { Meta, StoryObj } from '@storybook/react'
|
|
2
|
+
import { useState } from 'react'
|
|
3
|
+
import {
|
|
4
|
+
Dialog,
|
|
5
|
+
DialogContent,
|
|
6
|
+
DialogDescription,
|
|
7
|
+
DialogFooter,
|
|
8
|
+
DialogHeader,
|
|
9
|
+
DialogTitle,
|
|
10
|
+
DialogTrigger,
|
|
11
|
+
} from './dialog'
|
|
12
|
+
|
|
13
|
+
const meta: Meta = {
|
|
14
|
+
title: 'Primitives/Dialog',
|
|
15
|
+
parameters: { layout: 'centered', backgrounds: { default: 'dark' } },
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
export default meta
|
|
19
|
+
type Story = StoryObj
|
|
20
|
+
|
|
21
|
+
export const Default: Story = {
|
|
22
|
+
name: 'Default',
|
|
23
|
+
render: () => {
|
|
24
|
+
const [open, setOpen] = useState(true)
|
|
25
|
+
return (
|
|
26
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
27
|
+
<DialogTrigger asChild>
|
|
28
|
+
<button className="rounded-md bg-muted px-4 py-2 text-sm text-foreground hover:bg-muted/80">
|
|
29
|
+
Open Dialog
|
|
30
|
+
</button>
|
|
31
|
+
</DialogTrigger>
|
|
32
|
+
<DialogContent>
|
|
33
|
+
<DialogHeader>
|
|
34
|
+
<DialogTitle>Session Configuration</DialogTitle>
|
|
35
|
+
<DialogDescription>
|
|
36
|
+
Configure the runtime environment for your sandbox session. Changes
|
|
37
|
+
take effect on the next session start.
|
|
38
|
+
</DialogDescription>
|
|
39
|
+
</DialogHeader>
|
|
40
|
+
<div className="grid gap-3 py-2">
|
|
41
|
+
<div className="flex flex-col gap-1.5">
|
|
42
|
+
<label className="text-sm font-medium text-foreground">Image</label>
|
|
43
|
+
<input
|
|
44
|
+
className="rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
|
|
45
|
+
defaultValue="node:20-alpine"
|
|
46
|
+
/>
|
|
47
|
+
</div>
|
|
48
|
+
<div className="flex flex-col gap-1.5">
|
|
49
|
+
<label className="text-sm font-medium text-foreground">Memory (MB)</label>
|
|
50
|
+
<input
|
|
51
|
+
type="number"
|
|
52
|
+
className="rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
|
|
53
|
+
defaultValue={512}
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<DialogFooter>
|
|
58
|
+
<button
|
|
59
|
+
onClick={() => setOpen(false)}
|
|
60
|
+
className="rounded-md border border-border px-4 py-2 text-sm text-muted-foreground hover:bg-muted"
|
|
61
|
+
>
|
|
62
|
+
Cancel
|
|
63
|
+
</button>
|
|
64
|
+
<button
|
|
65
|
+
onClick={() => setOpen(false)}
|
|
66
|
+
className="rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground hover:bg-primary/90"
|
|
67
|
+
>
|
|
68
|
+
Save changes
|
|
69
|
+
</button>
|
|
70
|
+
</DialogFooter>
|
|
71
|
+
</DialogContent>
|
|
72
|
+
</Dialog>
|
|
73
|
+
)
|
|
74
|
+
},
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export const SandboxVariant: Story = {
|
|
78
|
+
name: 'Sandbox Variant',
|
|
79
|
+
render: () => {
|
|
80
|
+
const [open, setOpen] = useState(true)
|
|
81
|
+
return (
|
|
82
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
83
|
+
<DialogTrigger asChild>
|
|
84
|
+
<button className="rounded-md bg-muted px-4 py-2 text-sm text-foreground hover:bg-muted/80">
|
|
85
|
+
Open Sandbox Dialog
|
|
86
|
+
</button>
|
|
87
|
+
</DialogTrigger>
|
|
88
|
+
<DialogContent variant="sandbox">
|
|
89
|
+
<DialogHeader>
|
|
90
|
+
<DialogTitle>New Sandbox Session</DialogTitle>
|
|
91
|
+
<DialogDescription>
|
|
92
|
+
Provision a fresh container with your selected runtime. Sessions
|
|
93
|
+
auto-terminate after the configured timeout.
|
|
94
|
+
</DialogDescription>
|
|
95
|
+
</DialogHeader>
|
|
96
|
+
<div className="grid gap-3 py-2">
|
|
97
|
+
<div className="flex flex-col gap-1.5">
|
|
98
|
+
<label className="text-sm font-medium text-foreground">Runtime</label>
|
|
99
|
+
<select className="rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none">
|
|
100
|
+
<option>node:20-alpine</option>
|
|
101
|
+
<option>python:3.12-slim</option>
|
|
102
|
+
<option>golang:1.22-alpine</option>
|
|
103
|
+
<option>rust:1.77-slim</option>
|
|
104
|
+
</select>
|
|
105
|
+
</div>
|
|
106
|
+
<div className="flex flex-col gap-1.5">
|
|
107
|
+
<label className="text-sm font-medium text-foreground">Timeout (seconds)</label>
|
|
108
|
+
<input
|
|
109
|
+
type="number"
|
|
110
|
+
className="rounded-md border border-border bg-background px-3 py-2 text-sm text-foreground outline-none focus:ring-2 focus:ring-ring"
|
|
111
|
+
defaultValue={300}
|
|
112
|
+
/>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
<DialogFooter>
|
|
116
|
+
<button
|
|
117
|
+
onClick={() => setOpen(false)}
|
|
118
|
+
className="rounded-md border border-border px-4 py-2 text-sm text-muted-foreground hover:bg-muted"
|
|
119
|
+
>
|
|
120
|
+
Cancel
|
|
121
|
+
</button>
|
|
122
|
+
<button
|
|
123
|
+
onClick={() => setOpen(false)}
|
|
124
|
+
className="rounded-md bg-primary px-4 py-2 text-sm text-primary-foreground hover:bg-primary/90"
|
|
125
|
+
>
|
|
126
|
+
Create session
|
|
127
|
+
</button>
|
|
128
|
+
</DialogFooter>
|
|
129
|
+
</DialogContent>
|
|
130
|
+
</Dialog>
|
|
131
|
+
)
|
|
132
|
+
},
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export const DestructiveAction: Story = {
|
|
136
|
+
name: 'Destructive Action',
|
|
137
|
+
render: () => {
|
|
138
|
+
const [open, setOpen] = useState(true)
|
|
139
|
+
return (
|
|
140
|
+
<Dialog open={open} onOpenChange={setOpen}>
|
|
141
|
+
<DialogTrigger asChild>
|
|
142
|
+
<button className="rounded-md bg-muted px-4 py-2 text-sm text-foreground hover:bg-muted/80">
|
|
143
|
+
Terminate Session
|
|
144
|
+
</button>
|
|
145
|
+
</DialogTrigger>
|
|
146
|
+
<DialogContent>
|
|
147
|
+
<DialogHeader>
|
|
148
|
+
<DialogTitle>Terminate session?</DialogTitle>
|
|
149
|
+
<DialogDescription>
|
|
150
|
+
This will immediately kill the running process and destroy all
|
|
151
|
+
ephemeral data. This action cannot be undone.
|
|
152
|
+
</DialogDescription>
|
|
153
|
+
</DialogHeader>
|
|
154
|
+
<div className="rounded-lg border border-red-500/20 bg-red-500/10 px-4 py-3 text-sm text-red-400">
|
|
155
|
+
Session <span className="font-mono">sess_01j9x8k2m...</span> has been
|
|
156
|
+
running for 47 minutes. Unsaved work will be lost.
|
|
157
|
+
</div>
|
|
158
|
+
<DialogFooter>
|
|
159
|
+
<button
|
|
160
|
+
onClick={() => setOpen(false)}
|
|
161
|
+
className="rounded-md border border-border px-4 py-2 text-sm text-muted-foreground hover:bg-muted"
|
|
162
|
+
>
|
|
163
|
+
Keep running
|
|
164
|
+
</button>
|
|
165
|
+
<button
|
|
166
|
+
onClick={() => setOpen(false)}
|
|
167
|
+
className="rounded-md bg-red-600 px-4 py-2 text-sm text-white hover:bg-red-700"
|
|
168
|
+
>
|
|
169
|
+
Terminate
|
|
170
|
+
</button>
|
|
171
|
+
</DialogFooter>
|
|
172
|
+
</DialogContent>
|
|
173
|
+
</Dialog>
|
|
174
|
+
)
|
|
175
|
+
},
|
|
176
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import * as DialogPrimitive from "@radix-ui/react-dialog";
|
|
2
|
+
import { X } from "lucide-react";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { cn } from "../lib/utils";
|
|
5
|
+
|
|
6
|
+
const Dialog = DialogPrimitive.Root;
|
|
7
|
+
|
|
8
|
+
const DialogTrigger = DialogPrimitive.Trigger;
|
|
9
|
+
|
|
10
|
+
const DialogPortal = DialogPrimitive.Portal;
|
|
11
|
+
|
|
12
|
+
const DialogClose = DialogPrimitive.Close;
|
|
13
|
+
|
|
14
|
+
const DialogOverlay = React.forwardRef<
|
|
15
|
+
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
|
16
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
|
17
|
+
>(({ className, ...props }, ref) => (
|
|
18
|
+
<DialogPrimitive.Overlay
|
|
19
|
+
ref={ref}
|
|
20
|
+
className={cn(
|
|
21
|
+
"fixed inset-0 z-50 bg-black/40",
|
|
22
|
+
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
23
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
24
|
+
className,
|
|
25
|
+
)}
|
|
26
|
+
{...props}
|
|
27
|
+
/>
|
|
28
|
+
));
|
|
29
|
+
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|
30
|
+
|
|
31
|
+
const DialogContent = React.forwardRef<
|
|
32
|
+
React.ElementRef<typeof DialogPrimitive.Content>,
|
|
33
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
|
34
|
+
variant?: "default" | "sandbox";
|
|
35
|
+
}
|
|
36
|
+
>(({ className, children, variant = "default", ...props }, ref) => {
|
|
37
|
+
const variants = {
|
|
38
|
+
default: "border-border",
|
|
39
|
+
sandbox: "border-[var(--border-accent)] shadow-[var(--shadow-accent)]",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return (
|
|
43
|
+
<DialogPortal>
|
|
44
|
+
<DialogOverlay />
|
|
45
|
+
<DialogPrimitive.Content
|
|
46
|
+
ref={ref}
|
|
47
|
+
className={cn(
|
|
48
|
+
"fixed top-[50%] left-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%]",
|
|
49
|
+
"gap-4 rounded-lg border bg-card p-6 shadow-lg duration-200",
|
|
50
|
+
"data-[state=closed]:animate-out data-[state=open]:animate-in",
|
|
51
|
+
"data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0",
|
|
52
|
+
"data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95",
|
|
53
|
+
"data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%]",
|
|
54
|
+
"data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%]",
|
|
55
|
+
variants[variant],
|
|
56
|
+
className,
|
|
57
|
+
)}
|
|
58
|
+
{...props}
|
|
59
|
+
>
|
|
60
|
+
{children}
|
|
61
|
+
<DialogPrimitive.Close className="absolute top-4 right-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
|
62
|
+
<X className="h-4 w-4" />
|
|
63
|
+
<span className="sr-only">Close</span>
|
|
64
|
+
</DialogPrimitive.Close>
|
|
65
|
+
</DialogPrimitive.Content>
|
|
66
|
+
</DialogPortal>
|
|
67
|
+
);
|
|
68
|
+
});
|
|
69
|
+
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
|
70
|
+
|
|
71
|
+
const DialogHeader = ({
|
|
72
|
+
className,
|
|
73
|
+
...props
|
|
74
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
75
|
+
<div
|
|
76
|
+
className={cn(
|
|
77
|
+
"flex flex-col space-y-1.5 text-center sm:text-left",
|
|
78
|
+
className,
|
|
79
|
+
)}
|
|
80
|
+
{...props}
|
|
81
|
+
/>
|
|
82
|
+
);
|
|
83
|
+
DialogHeader.displayName = "DialogHeader";
|
|
84
|
+
|
|
85
|
+
const DialogFooter = ({
|
|
86
|
+
className,
|
|
87
|
+
...props
|
|
88
|
+
}: React.HTMLAttributes<HTMLDivElement>) => (
|
|
89
|
+
<div
|
|
90
|
+
className={cn(
|
|
91
|
+
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
|
|
92
|
+
className,
|
|
93
|
+
)}
|
|
94
|
+
{...props}
|
|
95
|
+
/>
|
|
96
|
+
);
|
|
97
|
+
DialogFooter.displayName = "DialogFooter";
|
|
98
|
+
|
|
99
|
+
const DialogTitle = React.forwardRef<
|
|
100
|
+
React.ElementRef<typeof DialogPrimitive.Title>,
|
|
101
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
|
102
|
+
>(({ className, ...props }, ref) => (
|
|
103
|
+
<DialogPrimitive.Title
|
|
104
|
+
ref={ref}
|
|
105
|
+
className={cn(
|
|
106
|
+
"font-semibold text-lg leading-none tracking-tight",
|
|
107
|
+
className,
|
|
108
|
+
)}
|
|
109
|
+
{...props}
|
|
110
|
+
/>
|
|
111
|
+
));
|
|
112
|
+
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
|
113
|
+
|
|
114
|
+
const DialogDescription = React.forwardRef<
|
|
115
|
+
React.ElementRef<typeof DialogPrimitive.Description>,
|
|
116
|
+
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
|
117
|
+
>(({ className, ...props }, ref) => (
|
|
118
|
+
<DialogPrimitive.Description
|
|
119
|
+
ref={ref}
|
|
120
|
+
className={cn("text-muted-foreground text-sm", className)}
|
|
121
|
+
{...props}
|
|
122
|
+
/>
|
|
123
|
+
));
|
|
124
|
+
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
Dialog,
|
|
128
|
+
DialogPortal,
|
|
129
|
+
DialogOverlay,
|
|
130
|
+
DialogClose,
|
|
131
|
+
DialogTrigger,
|
|
132
|
+
DialogContent,
|
|
133
|
+
DialogHeader,
|
|
134
|
+
DialogFooter,
|
|
135
|
+
DialogTitle,
|
|
136
|
+
DialogDescription,
|
|
137
|
+
};
|