Skip to content
This repository was archived by the owner on Feb 25, 2026. It is now read-only.

Commit 04a6279

Browse files
committed
feat: add complex stories
1 parent 8b1788c commit 04a6279

11 files changed

Lines changed: 1350 additions & 0 deletions
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
/** @jsxImportSource solid-js */
2+
import type { Meta, StoryObj } from "storybook-solidjs-vite"
3+
import { Code } from "@opencode-ai/ui/code"
4+
5+
const meta: Meta = {
6+
title: "Components/Code",
7+
decorators: [
8+
(Story) => (
9+
<div style={{ width: "700px", "min-height": "200px" }}>
10+
<Story />
11+
</div>
12+
),
13+
],
14+
parameters: { layout: "padded" },
15+
}
16+
17+
export default meta
18+
type Story = StoryObj
19+
20+
const jsCode = `import { createSignal } from "solid-js"
21+
22+
export function Counter() {
23+
const [count, setCount] = createSignal(0)
24+
25+
return (
26+
<div>
27+
<p>Count: {count()}</p>
28+
<button onClick={() => setCount(count() + 1)}>
29+
Increment
30+
</button>
31+
</div>
32+
)
33+
}
34+
`
35+
36+
const tsCode = `interface User {
37+
id: string
38+
name: string
39+
email: string
40+
role: "admin" | "user" | "guest"
41+
createdAt: Date
42+
}
43+
44+
async function fetchUser(id: string): Promise<User> {
45+
const response = await fetch(\`/api/users/\${id}\`)
46+
if (!response.ok) {
47+
throw new Error(\`Failed to fetch user: \${response.statusText}\`)
48+
}
49+
return response.json() as Promise<User>
50+
}
51+
52+
export async function updateUser(
53+
id: string,
54+
updates: Partial<Omit<User, "id" | "createdAt">>
55+
): Promise<User> {
56+
const current = await fetchUser(id)
57+
return { ...current, ...updates }
58+
}
59+
`
60+
61+
const pythonCode = `def fibonacci(n: int) -> list[int]:
62+
"""Generate Fibonacci sequence up to n terms."""
63+
if n <= 0:
64+
return []
65+
if n == 1:
66+
return [0]
67+
68+
sequence = [0, 1]
69+
while len(sequence) < n:
70+
sequence.append(sequence[-1] + sequence[-2])
71+
return sequence
72+
73+
74+
class FibonacciCalculator:
75+
def __init__(self, cache_size: int = 100):
76+
self._cache: dict[int, int] = {}
77+
self._cache_size = cache_size
78+
79+
def compute(self, n: int) -> int:
80+
if n in self._cache:
81+
return self._cache[n]
82+
if n <= 1:
83+
return n
84+
result = self.compute(n - 1) + self.compute(n - 2)
85+
if len(self._cache) < self._cache_size:
86+
self._cache[n] = result
87+
return result
88+
`
89+
90+
const shortCode = `const hello = "world"`
91+
92+
export const Default: Story = {
93+
render: () => <Code file={{ name: "counter.tsx", contents: jsCode }} />,
94+
}
95+
96+
export const TypeScript: Story = {
97+
render: () => <Code file={{ name: "user.ts", contents: tsCode }} />,
98+
}
99+
100+
export const Python: Story = {
101+
render: () => <Code file={{ name: "fibonacci.py", contents: pythonCode }} />,
102+
}
103+
104+
export const Short: Story = {
105+
render: () => <Code file={{ name: "hello.ts", contents: shortCode }} />,
106+
}
107+
108+
export const NoLineNumbers: Story = {
109+
render: () => <Code file={{ name: "counter.tsx", contents: jsCode }} disableLineNumbers />,
110+
}
111+
112+
export const SplitOverflow: Story = {
113+
render: () => <Code file={{ name: "counter.tsx", contents: jsCode }} overflow="scroll" />,
114+
}
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/** @jsxImportSource solid-js */
2+
import type { Meta, StoryObj } from "storybook-solidjs-vite"
3+
import { Diff } from "@opencode-ai/ui/diff-ssr"
4+
import { WorkerPoolProvider } from "@opencode-ai/ui/context/worker-pool"
5+
6+
const meta: Meta = {
7+
title: "Components/DiffSSR",
8+
decorators: [
9+
(Story) => (
10+
<WorkerPoolProvider pools={{ unified: undefined, split: undefined }}>
11+
<div style={{ width: "700px", "min-height": "200px" }}>
12+
<Story />
13+
</div>
14+
</WorkerPoolProvider>
15+
),
16+
],
17+
parameters: { layout: "padded" },
18+
}
19+
20+
export default meta
21+
type Story = StoryObj
22+
23+
const beforeCode = `function add(a, b) {
24+
return a + b
25+
}
26+
`
27+
28+
const afterCode = `function add(a: number, b: number): number {
29+
return a + b
30+
}
31+
32+
function subtract(a: number, b: number): number {
33+
return a - b
34+
}
35+
`
36+
37+
const mockPreloaded = {
38+
prerenderedHTML: "",
39+
oldFile: { name: "math.js", contents: beforeCode },
40+
newFile: { name: "math.ts", contents: afterCode },
41+
}
42+
43+
export const Default: Story = {
44+
render: () => (
45+
<Diff
46+
before={{ name: "math.js", contents: beforeCode }}
47+
after={{ name: "math.ts", contents: afterCode }}
48+
preloadedDiff={mockPreloaded}
49+
/>
50+
),
51+
}
52+
53+
export const WithSplitStyle: Story = {
54+
render: () => (
55+
<Diff
56+
before={{ name: "math.js", contents: beforeCode }}
57+
after={{ name: "math.ts", contents: afterCode }}
58+
diffStyle="split"
59+
preloadedDiff={mockPreloaded}
60+
/>
61+
),
62+
}
Lines changed: 137 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,137 @@
1+
/** @jsxImportSource solid-js */
2+
import type { Meta, StoryObj } from "storybook-solidjs-vite"
3+
import { Diff } from "@opencode-ai/ui/diff"
4+
5+
const meta: Meta = {
6+
title: "Components/Diff",
7+
decorators: [
8+
(Story) => (
9+
<div style={{ width: "700px", "min-height": "200px" }}>
10+
<Story />
11+
</div>
12+
),
13+
],
14+
parameters: { layout: "padded" },
15+
}
16+
17+
export default meta
18+
type Story = StoryObj
19+
20+
const beforeCode = `import { createSignal } from "solid-js"
21+
22+
export function Counter() {
23+
const [count, setCount] = createSignal(0)
24+
25+
return (
26+
<div>
27+
<p>Count: {count()}</p>
28+
<button onClick={() => setCount(count() + 1)}>
29+
Increment
30+
</button>
31+
</div>
32+
)
33+
}
34+
`
35+
36+
const afterCode = `import { createSignal, createEffect } from "solid-js"
37+
38+
export function Counter(props: { initial?: number }) {
39+
const [count, setCount] = createSignal(props.initial ?? 0)
40+
41+
createEffect(() => {
42+
document.title = \`Count: \${count()}\`
43+
})
44+
45+
const reset = () => setCount(props.initial ?? 0)
46+
47+
return (
48+
<div class="counter">
49+
<p>Count: {count()}</p>
50+
<button onClick={() => setCount(count() + 1)}>
51+
Increment
52+
</button>
53+
<button onClick={reset}>Reset</button>
54+
</div>
55+
)
56+
}
57+
`
58+
59+
const beforeEmpty = ``
60+
61+
const afterAdded = `export const VERSION = "1.0.0"
62+
63+
export function getVersion(): string {
64+
return VERSION
65+
}
66+
`
67+
68+
const beforeDeleted = `export const LEGACY_API_URL = "https://old.api.example.com"
69+
70+
export function callLegacyApi(endpoint: string) {
71+
return fetch(\`\${LEGACY_API_URL}/\${endpoint}\`)
72+
}
73+
`
74+
75+
const afterDeleted = ``
76+
77+
const beforeConfig = `{
78+
"name": "my-app",
79+
"version": "1.0.0",
80+
"dependencies": {
81+
"solid-js": "^1.8.0"
82+
}
83+
}
84+
`
85+
86+
const afterConfig = `{
87+
"name": "my-app",
88+
"version": "1.1.0",
89+
"dependencies": {
90+
"solid-js": "^1.9.0",
91+
"@solidjs/router": "^0.14.0"
92+
},
93+
"devDependencies": {
94+
"typescript": "^5.0.0"
95+
}
96+
}
97+
`
98+
99+
export const Default: Story = {
100+
render: () => (
101+
<Diff before={{ name: "counter.tsx", contents: beforeCode }} after={{ name: "counter.tsx", contents: afterCode }} />
102+
),
103+
}
104+
105+
export const SplitView: Story = {
106+
render: () => (
107+
<Diff
108+
before={{ name: "counter.tsx", contents: beforeCode }}
109+
after={{ name: "counter.tsx", contents: afterCode }}
110+
diffStyle="split"
111+
/>
112+
),
113+
}
114+
115+
export const AddedFile: Story = {
116+
render: () => (
117+
<Diff before={{ name: "version.ts", contents: beforeEmpty }} after={{ name: "version.ts", contents: afterAdded }} />
118+
),
119+
}
120+
121+
export const DeletedFile: Story = {
122+
render: () => (
123+
<Diff
124+
before={{ name: "legacy.ts", contents: beforeDeleted }}
125+
after={{ name: "legacy.ts", contents: afterDeleted }}
126+
/>
127+
),
128+
}
129+
130+
export const ConfigChange: Story = {
131+
render: () => (
132+
<Diff
133+
before={{ name: "package.json", contents: beforeConfig }}
134+
after={{ name: "package.json", contents: afterConfig }}
135+
/>
136+
),
137+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
/** @jsxImportSource solid-js */
2+
import type { Meta, StoryObj } from "storybook-solidjs-vite"
3+
import { Favicon } from "@opencode-ai/ui/favicon"
4+
5+
const meta: Meta = {
6+
title: "Components/Favicon",
7+
parameters: { layout: "centered" },
8+
}
9+
10+
export default meta
11+
type Story = StoryObj
12+
13+
export const Default: Story = {
14+
render: () => (
15+
<div style={{ display: "flex", "flex-direction": "column", gap: "12px", "max-width": "400px" }}>
16+
<Favicon />
17+
<p style={{ "font-size": "14px", color: "var(--text-base)", margin: 0 }}>
18+
The <code>Favicon</code> component injects favicon and meta tags into the document <code>&lt;head&gt;</code>. It
19+
has no visible UI output in the page body.
20+
</p>
21+
<p style={{ "font-size": "13px", color: "var(--text-weak)", margin: 0 }}>
22+
Check the browser tab icon and the <code>&lt;head&gt;</code> of this preview to see the injected tags.
23+
</p>
24+
<div
25+
style={{
26+
"background-color": "var(--surface-base)",
27+
padding: "12px",
28+
"border-radius": "6px",
29+
"font-size": "12px",
30+
"font-family": "monospace",
31+
color: "var(--text-weak)",
32+
}}
33+
>
34+
{`<link rel="icon" type="image/png" href="/favicon-96x96-v3.png" sizes="96x96">`}
35+
<br />
36+
{`<link rel="shortcut icon" href="/favicon-v3.ico">`}
37+
<br />
38+
{`<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-v3.png">`}
39+
<br />
40+
{`<link rel="manifest" href="/site.webmanifest">`}
41+
<br />
42+
{`<meta name="apple-mobile-web-app-title" content="Kilo">`}
43+
</div>
44+
</div>
45+
),
46+
}

0 commit comments

Comments
 (0)