Skip to content

Commit 05d77b7

Browse files
chore: storybook (#15285)
Co-authored-by: David Hill <iamdavidhill@gmail.com>
1 parent 8c484a0 commit 05d77b7

85 files changed

Lines changed: 5407 additions & 9 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

bun.lock

Lines changed: 195 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

packages/storybook/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules/
2+
storybook-static/
3+
.storybook-cache/
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { defineMain } from "storybook-solidjs-vite"
2+
import path from "node:path"
3+
import { fileURLToPath } from "node:url"
4+
5+
const here = path.dirname(fileURLToPath(import.meta.url))
6+
const ui = path.resolve(here, "../../ui")
7+
8+
export default defineMain({
9+
framework: {
10+
name: "storybook-solidjs-vite",
11+
options: {},
12+
},
13+
addons: [
14+
"@storybook/addon-onboarding",
15+
"@storybook/addon-docs",
16+
"@storybook/addon-links",
17+
"@storybook/addon-a11y",
18+
"@storybook/addon-vitest",
19+
],
20+
stories: ["../../ui/src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
21+
async viteFinal(config) {
22+
const { mergeConfig, searchForWorkspaceRoot } = await import("vite")
23+
return mergeConfig(config, {
24+
resolve: {
25+
dedupe: ["solid-js", "solid-js/web", "@solidjs/meta"],
26+
},
27+
worker: {
28+
format: "es",
29+
},
30+
server: {
31+
fs: {
32+
allow: [searchForWorkspaceRoot(process.cwd()), ui],
33+
},
34+
},
35+
})
36+
},
37+
})
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
import { addons, types } from "storybook/manager-api"
2+
import { ThemeTool } from "./theme-tool"
3+
4+
addons.register("opencode/theme-toggle", () => {
5+
addons.add("opencode/theme-toggle/tool", {
6+
type: types.TOOL,
7+
title: "Theme",
8+
match: ({ viewMode }) => viewMode === "story" || viewMode === "docs",
9+
render: ThemeTool,
10+
})
11+
})
Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
import "@opencode-ai/ui/styles"
2+
3+
import { createEffect, onCleanup, onMount } from "solid-js"
4+
import addonA11y from "@storybook/addon-a11y"
5+
import addonDocs from "@storybook/addon-docs"
6+
import { MetaProvider } from "@solidjs/meta"
7+
import { addons } from "storybook/preview-api"
8+
import { GLOBALS_UPDATED } from "storybook/internal/core-events"
9+
import { createJSXDecorator, definePreview } from "storybook-solidjs-vite"
10+
import { Code } from "@opencode-ai/ui/code"
11+
import { CodeComponentProvider } from "@opencode-ai/ui/context/code"
12+
import { DialogProvider } from "@opencode-ai/ui/context/dialog"
13+
import { DiffComponentProvider } from "@opencode-ai/ui/context/diff"
14+
import { MarkedProvider } from "@opencode-ai/ui/context/marked"
15+
import { Diff } from "@opencode-ai/ui/diff"
16+
import { ThemeProvider, useTheme, type ColorScheme } from "@opencode-ai/ui/theme"
17+
import { Font } from "@opencode-ai/ui/font"
18+
19+
function resolveScheme(value: unknown): ColorScheme {
20+
if (value === "light" || value === "dark" || value === "system") return value
21+
return "system"
22+
}
23+
24+
const channel = addons.getChannel()
25+
26+
const Scheme = (props: { value?: unknown }) => {
27+
const theme = useTheme()
28+
const apply = (value?: unknown) => {
29+
theme.setColorScheme(resolveScheme(value))
30+
}
31+
createEffect(() => {
32+
apply(props.value)
33+
})
34+
createEffect(() => {
35+
const root = document.documentElement
36+
root.classList.remove("light", "dark")
37+
root.classList.add(theme.mode())
38+
})
39+
onMount(() => {
40+
const handler = (event: { globals?: Record<string, unknown> }) => {
41+
apply(event.globals?.theme)
42+
}
43+
channel.on(GLOBALS_UPDATED, handler)
44+
onCleanup(() => channel.off(GLOBALS_UPDATED, handler))
45+
})
46+
return null
47+
}
48+
49+
const frame = createJSXDecorator((Story, context) => {
50+
const override = context.parameters?.themes?.themeOverride
51+
const selected = context.globals?.theme
52+
const pick = override === "light" || override === "dark" ? override : selected
53+
const scheme = resolveScheme(pick)
54+
return (
55+
<MetaProvider>
56+
<Font />
57+
<ThemeProvider>
58+
<Scheme value={scheme} />
59+
<DialogProvider>
60+
<MarkedProvider>
61+
<DiffComponentProvider component={Diff}>
62+
<CodeComponentProvider component={Code}>
63+
<div
64+
style={{
65+
"min-height": "100vh",
66+
padding: "24px",
67+
"background-color": "var(--background-base)",
68+
color: "var(--text-base)",
69+
}}
70+
>
71+
<Story />
72+
</div>
73+
</CodeComponentProvider>
74+
</DiffComponentProvider>
75+
</MarkedProvider>
76+
</DialogProvider>
77+
</ThemeProvider>
78+
</MetaProvider>
79+
)
80+
})
81+
82+
export default definePreview({
83+
addons: [addonDocs(), addonA11y()],
84+
decorators: [frame],
85+
globalTypes: {
86+
theme: {
87+
name: "Theme",
88+
description: "Global theme",
89+
defaultValue: "light",
90+
},
91+
},
92+
parameters: {
93+
actions: {
94+
argTypesRegex: "^on.*",
95+
},
96+
controls: {
97+
matchers: {
98+
color: /(background|color)$/i,
99+
date: /Date$/i,
100+
},
101+
},
102+
a11y: {
103+
test: "todo",
104+
},
105+
},
106+
})
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import { createElement } from "react"
2+
import { useGlobals } from "storybook/manager-api"
3+
import { ToggleButton } from "storybook/internal/components"
4+
5+
export function ThemeTool() {
6+
const [globals, updateGlobals] = useGlobals()
7+
const mode = globals.theme === "dark" ? "dark" : "light"
8+
const toggle = () => {
9+
const next = mode === "dark" ? "light" : "dark"
10+
updateGlobals({ theme: next })
11+
}
12+
return createElement(
13+
ToggleButton,
14+
{
15+
title: "Toggle theme",
16+
active: mode === "dark",
17+
onClick: toggle,
18+
},
19+
mode === "dark" ? "Dark" : "Light",
20+
)
21+
}

0 commit comments

Comments
 (0)