114 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			114 lines
		
	
	
		
			2.8 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| import { addons } from '@storybook/addons';
 | |
| import { FORCE_REMOUNT } from '@storybook/core-events';
 | |
| import { type Preview, setup } from '@storybook/vue3';
 | |
| import isChromatic from 'chromatic/isChromatic';
 | |
| import { initialize, mswDecorator } from 'msw-storybook-addon';
 | |
| import locale from './locale';
 | |
| import { commonHandlers, onUnhandledRequest } from './mocks';
 | |
| import themes from './themes';
 | |
| import '../src/style.scss';
 | |
| 
 | |
| const appInitialized = Symbol();
 | |
| 
 | |
| let moduleInitialized = false;
 | |
| let unobserve = () => {};
 | |
| let misskeyOS = null;
 | |
| 
 | |
| function loadTheme(applyTheme: typeof import('../src/scripts/theme')['applyTheme']) {
 | |
| 	unobserve();
 | |
| 	const theme = themes[document.documentElement.dataset.misskeyTheme];
 | |
| 	if (theme) {
 | |
| 		applyTheme(themes[document.documentElement.dataset.misskeyTheme]);
 | |
| 	} else {
 | |
| 		applyTheme(themes['l-light']);
 | |
| 	}
 | |
| 	const observer = new MutationObserver((entries) => {
 | |
| 		for (const entry of entries) {
 | |
| 			if (entry.attributeName === 'data-misskey-theme') {
 | |
| 				const target = entry.target as HTMLElement;
 | |
| 				const theme = themes[target.dataset.misskeyTheme];
 | |
| 				if (theme) {
 | |
| 					applyTheme(themes[target.dataset.misskeyTheme]);
 | |
| 				} else {
 | |
| 					target.removeAttribute('style');
 | |
| 				}
 | |
| 			}
 | |
| 		}
 | |
| 	});
 | |
| 	observer.observe(document.documentElement, {
 | |
| 		attributes: true,
 | |
| 		attributeFilter: ['data-misskey-theme'],
 | |
| 	});
 | |
| 	unobserve = () => observer.disconnect();
 | |
| }
 | |
| 
 | |
| initialize({
 | |
| 	onUnhandledRequest,
 | |
| });
 | |
| localStorage.setItem("locale", JSON.stringify(locale));
 | |
| queueMicrotask(() => {
 | |
| 	Promise.all([
 | |
| 		import('../src/components'),
 | |
| 		import('../src/directives'),
 | |
| 		import('../src/widgets'),
 | |
| 		import('../src/scripts/theme'),
 | |
| 		import('../src/store'),
 | |
| 		import('../src/os'),
 | |
| 	]).then(([{ default: components }, { default: directives }, { default: widgets }, { applyTheme }, { defaultStore }, os]) => {
 | |
| 		setup((app) => {
 | |
| 			moduleInitialized = true;
 | |
| 			if (app[appInitialized]) {
 | |
| 				return;
 | |
| 			}
 | |
| 			app[appInitialized] = true;
 | |
| 			loadTheme(applyTheme);
 | |
| 			components(app);
 | |
| 			directives(app);
 | |
| 			widgets(app);
 | |
| 			misskeyOS = os;
 | |
| 			if (isChromatic()) {
 | |
| 				defaultStore.set('animation', false);
 | |
| 			}
 | |
| 		});
 | |
| 	});
 | |
| });
 | |
| 
 | |
| const preview = {
 | |
| 	decorators: [
 | |
| 		(Story, context) => {
 | |
| 			const story = Story();
 | |
| 			if (!moduleInitialized) {
 | |
| 				const channel = addons.getChannel();
 | |
| 				(globalThis.requestIdleCallback || setTimeout)(() => {
 | |
| 					channel.emit(FORCE_REMOUNT, { storyId: context.id });
 | |
| 				});
 | |
| 			}
 | |
| 			return story;
 | |
| 		},
 | |
| 		mswDecorator,
 | |
| 		(Story, context) => {
 | |
| 			return {
 | |
| 				setup() {
 | |
| 					return {
 | |
| 						context,
 | |
| 						popups: misskeyOS.popups,
 | |
| 					};
 | |
| 				},
 | |
| 				template:
 | |
| 					'<component :is="popup.component" v-for="popup in popups" :key="popup.id" v-bind="popup.props" v-on="popup.events"/>' +
 | |
| 					'<story />',
 | |
| 			};
 | |
| 		},
 | |
| 	],
 | |
| 	parameters: {
 | |
| 		controls: {
 | |
| 			exclude: /^__/,
 | |
| 		},
 | |
| 		msw: {
 | |
| 			handlers: commonHandlers,
 | |
| 		},
 | |
| 	},
 | |
| } satisfies Preview;
 | |
| 
 | |
| export default preview;
 | 
