Skip to content

Commit 2100537

Browse files
committed
feat(client): add Storybook with component stories
- Set up Storybook with Vite and dark theme support - Add Chromatic CI workflow for visual regression testing - Create stories for 37+ UI components - Fix GameCard text color for cartridge preset compatibility
1 parent 0c5b9e1 commit 2100537

Some content is hidden

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

48 files changed

+4509
-11
lines changed

.claude-modified-files

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
/Users/valentindosimont/.claude/plans/dreamy-drifting-hippo.md
2+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/main.ts
3+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/preview.ts
4+
/Users/valentindosimont/www/c7e/arcade/client/package.json
5+
/Users/valentindosimont/www/c7e/arcade/turbo.json
6+
/Users/valentindosimont/www/c7e/arcade/.gitignore
7+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/button.stories.tsx
8+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/label.stories.tsx
9+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/floating-loading-spinner.stories.tsx
10+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/pagination.stories.tsx
11+
/Users/valentindosimont/www/c7e/arcade/.github/workflows/ci-chromatic.yml
12+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/main.ts
13+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/storybook.css
14+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/preview.ts
15+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/storybook.css
16+
/Users/valentindosimont/www/c7e/arcade/client/biome.json
17+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/carousel.stories.tsx
18+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/form.stories.tsx
19+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/tab.stories.tsx
20+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/sub-tab.stories.tsx
21+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/menu-button.stories.tsx
22+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/menu-item.stories.tsx
23+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/leaderboard-row.stories.tsx
24+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/leaderboard-username.stories.tsx
25+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/copy-address.stories.tsx
26+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/follow-tag.stories.tsx
27+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/player-label.stories.tsx
28+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/player-header.stories.tsx
29+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/search-input.stories.tsx
30+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-header.stories.tsx
31+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/link-item.stories.tsx
32+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/edition-item.stories.tsx
33+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/index.stories.tsx
34+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/header.stories.tsx
35+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/footer.stories.tsx
36+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/preview.stories.tsx
37+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/filters/AttributeSearch.stories.tsx
38+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/filters/PropertyItem.stories.tsx
39+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/filters/OwnerFilterSection.stories.tsx
40+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/token-detail/TokenProperties.stories.tsx
41+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/token-detail/TokenTabs.stories.tsx
42+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/token-detail/AssetPreview.stories.tsx
43+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
44+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/icons/index.stories.tsx
45+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-socials.stories.tsx
46+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/controller-action.stories.tsx
47+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-social.stories.tsx
48+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/edition-actions.stories.tsx
49+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-select.stories.tsx
50+
/Users/valentindosimont/.claude/plans/dreamy-drifting-hippo.md
51+
/Users/valentindosimont/.claude/plans/dreamy-drifting-hippo.md
52+
/Users/valentindosimont/.claude/plans/dreamy-drifting-hippo.md
53+
/Users/valentindosimont/.claude/plans/dreamy-drifting-hippo.md
54+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/preview.tsx
55+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/mocks/project.ts
56+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/main.ts
57+
/Users/valentindosimont/.claude/plans/dreamy-drifting-hippo.md
58+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/preview.tsx
59+
/Users/valentindosimont/.claude/plans/dreamy-drifting-hippo.md
60+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/preview.ts
61+
/Users/valentindosimont/www/c7e/arcade/client/.storybook/main.ts
62+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
63+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-select.stories.tsx
64+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-select.stories.tsx
65+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-select.stories.tsx
66+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
67+
/Users/valentindosimont/.claude/plans/zazzy-percolating-wreath.md
68+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
69+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-select.stories.tsx
70+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/index.stories.tsx
71+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/token-detail/AssetPreview.stories.tsx
72+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/token-detail/AssetPreview.stories.tsx
73+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/header.stories.tsx
74+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/preview.stories.tsx
75+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/preview.stories.tsx
76+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/footer.stories.tsx
77+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-header.stories.tsx
78+
/Users/valentindosimont/.claude/plans/zazzy-percolating-wreath.md
79+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
80+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-select.stories.tsx
81+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-header.stories.tsx
82+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/index.stories.tsx
83+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/preview.stories.tsx
84+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/preview.stories.tsx
85+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/header.stories.tsx
86+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/collectible-card/footer.stories.tsx
87+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/token-detail/AssetPreview.stories.tsx
88+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/marketplace/token-detail/AssetPreview.stories.tsx
89+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
90+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/game-select.stories.tsx
91+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
92+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
93+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
94+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
95+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.tsx
96+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
97+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
98+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
99+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/dashboard/GameCard.stories.tsx
100+
/Users/valentindosimont/.claude/plans/zazzy-percolating-wreath.md
101+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/edition-actions.stories.tsx
102+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/edition-actions.stories.tsx
103+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/edition-actions.stories.tsx
104+
/Users/valentindosimont/www/c7e/arcade/client/src/components/ui/modules/edition-actions.stories.tsx
105+
/Users/valentindosimont/.claude/plans/zazzy-percolating-wreath.md

.github/workflows/ci-chromatic.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
name: chromatic
2+
3+
on:
4+
push:
5+
branches:
6+
- main
7+
paths:
8+
- 'client/**'
9+
- '.github/workflows/ci-chromatic.yml'
10+
pull_request:
11+
branches:
12+
- main
13+
paths:
14+
- 'client/**'
15+
- '.github/workflows/ci-chromatic.yml'
16+
17+
concurrency:
18+
group: chromatic-${{ github.event.pull_request.number || github.ref }}
19+
cancel-in-progress: true
20+
21+
jobs:
22+
chromatic:
23+
runs-on: ubuntu-latest
24+
steps:
25+
- uses: actions/checkout@v4
26+
with:
27+
fetch-depth: 0
28+
29+
- uses: pnpm/action-setup@v4
30+
with:
31+
version: 10.5.2
32+
33+
- uses: actions/setup-node@v4
34+
with:
35+
node-version: 20
36+
cache: "pnpm"
37+
38+
- name: Cache turbo
39+
uses: actions/cache@v4
40+
with:
41+
path: .turbo
42+
key: ${{ runner.os }}-turbo-chromatic-${{ github.sha }}
43+
restore-keys: |
44+
${{ runner.os }}-turbo-chromatic-
45+
${{ runner.os }}-turbo-
46+
47+
- name: Install dependencies
48+
run: pnpm install --frozen-lockfile --ignore-scripts
49+
50+
- name: Build dependencies
51+
run: pnpm turbo run build:deps --filter=@cartridge/client
52+
53+
- name: Publish to Chromatic
54+
uses: chromaui/action@latest
55+
with:
56+
workingDir: client
57+
projectToken: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
58+
onlyChanged: true
59+
autoAcceptChanges: ${{ github.ref == 'refs/heads/main' }}
60+
exitZeroOnChanges: ${{ github.event_name == 'pull_request' }}
61+
exitOnceUploaded: true
62+
skip: ${{ contains(github.event.head_commit.message, '[skip ci]') }}

.gitignore

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ vite.config.ts.*
1515
.rules
1616
.DS_Store
1717
packages/*/tsup.config.bundled_*.mjs
18+
19+
# Storybook
20+
storybook-static/
21+
*storybook.log

client/.storybook/main.ts

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
import type { StorybookConfig } from "@storybook/react-vite";
2+
import { mergeConfig } from "vite";
3+
import { resolve } from "node:path";
4+
import { fileURLToPath } from "node:url";
5+
6+
const __dirname = fileURLToPath(new URL(".", import.meta.url));
7+
8+
const config: StorybookConfig = {
9+
stories: ["../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
10+
addons: [
11+
"@storybook/addon-essentials",
12+
"@storybook/addon-links",
13+
"@storybook/addon-interactions",
14+
"@storybook/addon-themes",
15+
],
16+
framework: {
17+
name: "@storybook/react-vite",
18+
options: {},
19+
},
20+
docs: {
21+
autodocs: "tag",
22+
},
23+
staticDirs: ["../public"],
24+
viteFinal: async (config) => {
25+
const filteredPlugins = (config.plugins || []).filter((plugin) => {
26+
if (!plugin) return false;
27+
const pluginName = Array.isArray(plugin) ? undefined : (plugin as { name?: string }).name;
28+
return pluginName !== "vite-plugin-pwa:build" && pluginName !== "vite-plugin-pwa:dev";
29+
});
30+
31+
return mergeConfig(
32+
{ ...config, plugins: filteredPlugins },
33+
{
34+
resolve: {
35+
alias: {
36+
"@": resolve(__dirname, "../src"),
37+
},
38+
},
39+
optimizeDeps: {
40+
include: ["@cartridge/ui"],
41+
exclude: ["@dojoengine/torii-wasm"],
42+
},
43+
define: {
44+
__COMMIT_SHA__: JSON.stringify("storybook"),
45+
},
46+
}
47+
);
48+
},
49+
typescript: {
50+
check: false,
51+
reactDocgen: "react-docgen-typescript",
52+
reactDocgenTypescriptOptions: {
53+
shouldExtractLiteralValuesFromEnum: true,
54+
propFilter: (prop) =>
55+
prop.parent ? !/node_modules/.test(prop.parent.fileName) : true,
56+
},
57+
},
58+
};
59+
60+
export default config;

client/.storybook/preview.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import type { Preview } from "@storybook/react";
2+
import { withThemeByClassName } from "@storybook/addon-themes";
3+
4+
import "./storybook.css";
5+
6+
const preview: Preview = {
7+
parameters: {
8+
controls: {
9+
matchers: {
10+
color: /(background|color)$/i,
11+
date: /Date$/i,
12+
},
13+
},
14+
backgrounds: {
15+
default: "dark",
16+
values: [
17+
{ name: "dark", value: "#161A17" },
18+
{ name: "light", value: "#ffffff" },
19+
],
20+
},
21+
layout: "centered",
22+
},
23+
decorators: [
24+
withThemeByClassName({
25+
themes: {
26+
light: "",
27+
dark: "dark",
28+
},
29+
defaultTheme: "dark",
30+
}),
31+
],
32+
tags: ["autodocs"],
33+
};
34+
35+
export default preview;

client/.storybook/storybook.css

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
@import "@cartridge/ui/themes/default.css";
2+
@import "@cartridge/ui/themes/dark.css";
3+
@import "@cartridge/ui/themes/fonts.css";
4+
5+
@tailwind base;
6+
@tailwind components;
7+
@tailwind utilities;
8+
9+
@layer base {
10+
:root {
11+
--chart-1: 12 76% 61%;
12+
--chart-2: 173 58% 39%;
13+
--chart-3: 197 37% 24%;
14+
--chart-4: 43 74% 66%;
15+
--chart-5: 27 87% 67%;
16+
}
17+
18+
.dark {
19+
--chart-1: 220 70% 50%;
20+
--chart-2: 160 60% 45%;
21+
--chart-3: 30 80% 55%;
22+
--chart-4: 280 65% 60%;
23+
--chart-5: 340 75% 55%;
24+
}
25+
}
26+
27+
#storybook-root {
28+
min-height: 100vh;
29+
}

client/biome.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,8 @@
1313
".vercel/**",
1414
"node_modules/**",
1515
"public/**",
16-
"src/*.gen.ts"
16+
"src/*.gen.ts",
17+
"storybook-static/**"
1718
]
1819
},
1920
"formatter": {

client/package.json

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,10 @@
1919
"test": "vitest run",
2020
"test:ts": "vitest run",
2121
"test:coverage": "vitest run --coverage",
22-
"test:watch": "vitest"
22+
"test:watch": "vitest",
23+
"storybook": "storybook dev -p 6006",
24+
"build-storybook": "storybook build -o storybook-static",
25+
"chromatic": "chromatic --only-changed --exit-zero-on-changes"
2326
},
2427
"dependencies": {
2528
"@cartridge/arcade": "workspace:*",
@@ -85,6 +88,14 @@
8588
},
8689
"devDependencies": {
8790
"@eslint/js": "^9.9.0",
91+
"@storybook/addon-essentials": "^8.5.0",
92+
"@storybook/addon-interactions": "^8.5.0",
93+
"@storybook/addon-links": "^8.5.0",
94+
"@storybook/addon-themes": "^8.5.0",
95+
"@storybook/blocks": "^8.5.0",
96+
"@storybook/react": "^8.5.0",
97+
"@storybook/react-vite": "^8.5.0",
98+
"@storybook/test": "^8.5.0",
8899
"@tanstack/react-router-devtools": "^1.131.8",
89100
"@tanstack/router-plugin": "^1.131.8",
90101
"@testing-library/react": "^16.3.0",
@@ -94,11 +105,13 @@
94105
"@types/react-dom": "^19.2.3",
95106
"@vitejs/plugin-react-swc": "^3.5.0",
96107
"autoprefixer": "^10.4.18",
108+
"chromatic": "^11.20.0",
97109
"eslint": "^9.12.0",
98110
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
99111
"eslint-plugin-react-refresh": "^0.4.9",
100112
"globals": "^15.9.0",
101113
"postcss": "^8.4.35",
114+
"storybook": "^8.5.0",
102115
"tailwindcss": "^3.4.3",
103116
"typescript": "^5.5.3",
104117
"typescript-eslint": "^8.0.1",

0 commit comments

Comments
 (0)