docs: note about Storybook
This commit is contained in:
		
							parent
							
								
									c2d8759812
								
							
						
					
					
						commit
						bd7cc6ac38
					
				|  | @ -203,6 +203,90 @@ niraxは、Misskeyで使用しているオリジナルのフロントエンド | |||
| vue-routerとの最大の違いは、niraxは複数のルーターが存在することを許可している点です。 | ||||
| これにより、アプリ内ウィンドウでブラウザとは個別にルーティングすることなどが可能になります。 | ||||
| 
 | ||||
| ## Storybook | ||||
| 
 | ||||
| Misskey uses [Storybook](https://storybook.js.org/) for UI development. | ||||
| 
 | ||||
| ### Setup | ||||
| 
 | ||||
| ```bash | ||||
| cd path/to/packages/frontend | ||||
| pnpm tsc -p .storybook && (node .storybook/generate.js & node .storybook/preload-locale.js & node .storybook/preload-theme.js) | ||||
| ``` | ||||
| 
 | ||||
| ### Run | ||||
| 
 | ||||
| ```bash | ||||
| cd path/to/packages/frontend | ||||
| pnpm storybook dev | ||||
| ``` | ||||
| 
 | ||||
| ### Usage | ||||
| 
 | ||||
| When you create a new component (in this example, `MyComponent.vue`), the story file (`MyComponent.stories.ts`) will be automatically generated by the `.storybook/generate.js` script. | ||||
| You can override the default story by creating a impl story file (`MyComponent.stories.impl.ts`). | ||||
| 
 | ||||
| ```ts | ||||
| /* eslint-disable @typescript-eslint/explicit-function-return-type */ | ||||
| /* eslint-disable import/no-duplicates */ | ||||
| import { StoryObj } from '@storybook/vue3'; | ||||
| import MyComponent from './MyComponent.vue'; | ||||
| export const Default = { | ||||
| 	render(args) { | ||||
| 		return { | ||||
| 			components: { | ||||
| 				MyComponent, | ||||
| 			}, | ||||
| 			setup() { | ||||
| 				return { | ||||
| 					args, | ||||
| 				}; | ||||
| 			}, | ||||
| 			computed: { | ||||
| 				props() { | ||||
| 					return { | ||||
| 						...args, | ||||
| 					}; | ||||
| 				}, | ||||
| 			}, | ||||
| 			template: '<MyComponent v-bind="props" />', | ||||
| 		}; | ||||
| 	}, | ||||
| 	args: { | ||||
| 		foo: 'bar', | ||||
| 	}, | ||||
| 	parameters: { | ||||
| 		layout: 'centered', | ||||
| 	}, | ||||
| } satisfies StoryObj<typeof MkAvatar>; | ||||
| ``` | ||||
| 
 | ||||
| If you want to opt-out from the automatic generation, create a `MyComponent.stories.impl.ts` file and add the following line to the file. | ||||
| 
 | ||||
| ```ts | ||||
| import MyComponent from './MyComponent.vue'; | ||||
| void MyComponent; | ||||
| ``` | ||||
| 
 | ||||
| You can use msw to mock API requests in the storybook. Creating a `MyComponent.stories.msw.ts` file and add the following line to the file. | ||||
| 
 | ||||
| ```ts | ||||
| import { rest } from 'msw'; | ||||
| export const handlers = [ | ||||
| 	rest.post('/api/notes/timeline', (req, res, ctx) => { | ||||
| 		return res( | ||||
| 			ctx.json({ | ||||
| 				notes: [], | ||||
| 				users: [], | ||||
| 				hasNext: false, | ||||
| 			}) | ||||
| 		); | ||||
| 	}), | ||||
| ]; | ||||
| ``` | ||||
| 
 | ||||
| Don't forget to re-run the `.storybook/generate.js` script after adding, editing, or removing the above files. | ||||
| 
 | ||||
| ## Notes | ||||
| ### How to resolve conflictions occurred at pnpm-lock.yaml? | ||||
| 
 | ||||
|  |  | |||
|  | @ -1,7 +1,6 @@ | |||
| import { resolve } from 'node:path'; | ||||
| import type { StorybookConfig } from '@storybook/vue3-vite'; | ||||
| import { mergeConfig } from 'vite'; | ||||
| import { getConfig } from '../vite.config'; | ||||
| const config = { | ||||
| 	stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'], | ||||
| 	addons: [ | ||||
|  | @ -22,18 +21,9 @@ const config = { | |||
| 		disableTelemetry: true, | ||||
| 	}, | ||||
| 	async viteFinal(config, options) { | ||||
| 		const { plugins, build: { rollupOptions, ...build }, ...original } = getConfig(); | ||||
| 		console.dir(config, {depth:Infinity}); | ||||
| 		console.dir(original, {depth:Infinity}); | ||||
| 		const x = mergeConfig(config, { | ||||
| 			...original, | ||||
| 			build, | ||||
| 		return mergeConfig(config, { | ||||
| 			assetsInclude: [resolve(__dirname, '../node_modules/@tabler/icons-webfont/**/*.{css,eot,ttf,woff,woff2}')], | ||||
| 			server: { | ||||
| 				hmr: false, | ||||
| 			}, | ||||
| 		}); | ||||
| 		return x; | ||||
| 	}, | ||||
| } satisfies StorybookConfig; | ||||
| export default config; | ||||
|  |  | |||
|  | @ -0,0 +1,2 @@ | |||
| import MkCaptcha from './MkCaptcha.vue'; | ||||
| void MkCaptcha; | ||||
|  | @ -1,34 +1,10 @@ | |||
| /* eslint-disable @typescript-eslint/explicit-function-return-type */ | ||||
| /* eslint-disable import/no-default-export */ | ||||
| import { Meta, StoryObj } from '@storybook/vue3'; | ||||
| import MkCaptcha from './MkCaptcha.vue'; | ||||
| import { Meta } from '@storybook/vue3'; | ||||
| const meta = { | ||||
| 	title: 'components/MkCaptcha', | ||||
| 	component: MkCaptcha, | ||||
| } satisfies Meta<typeof MkCaptcha>; | ||||
| export const Default = { | ||||
| 	render(args) { | ||||
| 		return { | ||||
| 			components: { | ||||
| 				MkCaptcha, | ||||
| 			}, | ||||
| 			setup() { | ||||
| 				return { | ||||
| 					args, | ||||
| 				}; | ||||
| 			}, | ||||
| 			computed: { | ||||
| 				props() { | ||||
| 					return { | ||||
| 						...args, | ||||
| 					}; | ||||
| 				}, | ||||
| 			}, | ||||
| 			template: '<MkCaptcha v-bind="props" />', | ||||
| 		}; | ||||
| 	}, | ||||
| 	parameters: { | ||||
| 		layout: 'centered', | ||||
| 	}, | ||||
| } satisfies StoryObj<typeof MkCaptcha>; | ||||
| export default meta; | ||||
| import MkCaptcha from './MkCaptcha.vue'; | ||||
| void MkCaptcha; | ||||
|  |  | |||
|  | @ -1,5 +1,4 @@ | |||
| /* eslint-disable @typescript-eslint/explicit-function-return-type */ | ||||
| /* eslint-disable import/no-default-export */ | ||||
| /* eslint-disable import/no-duplicates */ | ||||
| import { StoryObj } from '@storybook/vue3'; | ||||
| import MkAvatar from './MkAvatar.vue'; | ||||
|  |  | |||
|  | @ -7,7 +7,6 @@ const meta = { | |||
| } satisfies Meta<typeof MkAvatar>; | ||||
| export default meta; | ||||
| /* eslint-disable @typescript-eslint/explicit-function-return-type */ | ||||
| /* eslint-disable import/no-default-export */ | ||||
| /* eslint-disable import/no-duplicates */ | ||||
| import { StoryObj } from '@storybook/vue3'; | ||||
| import MkAvatar from './MkAvatar.vue'; | ||||
|  | @ -68,13 +67,6 @@ export const ProfilePageCat = { | |||
| 		user: { | ||||
| 			...ProfilePage.args.user, | ||||
| 			isCat: true, | ||||
| 			// avatarUrl: 'https://millionlive-theaterdays.idolmaster-official.jp/assets/data/webp/common/footer/icon_app.png.webp',
 | ||||
| 			// avatarUrl: 'https://cdn.imastodon.net/accounts/avatars/000/144/021/original/8137afa4114ab85f.png',
 | ||||
| 			// avatarUrl: 'https://avatars.githubusercontent.com/u/4439005?v=4',
 | ||||
| 			// avatarUrl: 'https://avatars.githubusercontent.com/u/7973572?v=4',
 | ||||
| 			// avatarUrl: 'https://avatars.githubusercontent.com/u/6533808?v=4',
 | ||||
| 			// avatarUrl: 'https://avatars.githubusercontent.com/u/7106976?v=4',
 | ||||
| 			avatarUrl: 'https://avatars.githubusercontent.com/u/3396686?v=4', | ||||
| 		}, | ||||
| 	}, | ||||
| }; | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue