Add SumiButton and SumiCanvas components with lavis ink wash aesthetic. Add useSeason and useTimeOfDay hooks for time-aware UI tinting. Update storybook config, UI components, locales (en/es/fr), and dependencies. Add Chromatic CI workflow. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
60 lines
2.2 KiB
TypeScript
60 lines
2.2 KiB
TypeScript
/**
|
|
* Global Storybook decorator: single point of entry for all app providers.
|
|
* No story should import or wrap with these providers directly; they are applied here.
|
|
* Stories that need a specific route can set parameters.router.initialEntries.
|
|
*
|
|
* This ensures useAuth, useNavigate, useSearchParams, useQueryClient, useToast
|
|
* and similar hooks never run without context (no "must be used within XProvider" crashes).
|
|
*/
|
|
import React from 'react';
|
|
import type { Decorator } from '@storybook/react';
|
|
import { cn } from '../src/lib/utils';
|
|
import { ThemeProvider } from '../src/components/theme/ThemeProvider';
|
|
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
|
|
import { MemoryRouter } from 'react-router-dom';
|
|
import { LazyToaster } from '../src/components/feedback/LazyToaster';
|
|
import { AudioProvider } from '../src/context/AudioContext';
|
|
import { AuthProvider } from '../src/providers/AuthProvider';
|
|
import { I18nextProvider } from 'react-i18next';
|
|
import i18n from '../src/lib/i18n';
|
|
|
|
const queryClient = new QueryClient({
|
|
defaultOptions: {
|
|
queries: {
|
|
retry: false,
|
|
staleTime: Infinity,
|
|
throwOnError: false,
|
|
},
|
|
},
|
|
});
|
|
|
|
export const StorybookDecorator: Decorator = (Story, context) => {
|
|
const bgValue = context.globals?.backgrounds?.value;
|
|
const isDark = bgValue !== 'light'; // only 'light' triggers light mode, everything else = dark
|
|
const initialEntries =
|
|
(context.parameters?.router as { initialEntries?: string[] } | undefined)?.initialEntries ?? ['/'];
|
|
|
|
return (
|
|
<I18nextProvider i18n={i18n}>
|
|
<ThemeProvider defaultTheme={isDark ? 'dark' : 'light'}>
|
|
<div
|
|
className={cn(
|
|
isDark ? 'dark' : '',
|
|
'min-h-layout-story min-h-screen p-4 bg-background text-foreground',
|
|
)}
|
|
>
|
|
<QueryClientProvider client={queryClient}>
|
|
<LazyToaster position="top-right" />
|
|
<AudioProvider>
|
|
<AuthProvider>
|
|
<MemoryRouter initialEntries={initialEntries}>
|
|
<Story />
|
|
</MemoryRouter>
|
|
</AuthProvider>
|
|
</AudioProvider>
|
|
</QueryClientProvider>
|
|
</div>
|
|
</ThemeProvider>
|
|
</I18nextProvider>
|
|
);
|
|
};
|