import type { MarkdownIt } from 'markdown-it'; import type { UseHeadInput } from 'unhead/types'; import type { UserConfig as ViteConfig, ConfigEnv as ViteConfigEnv } from 'vite'; import type { Plugin } from './plugin.js'; import type { ServerTreeFile, StoryProps } from './story.js'; export interface SupportMatchPattern { id: string; patterns: string[]; pluginIds: string[]; } export type CustomizableColors = 'primary' | 'gray'; export type ColorKeys = '50' | '100' | '200' | '300' | '400' | '500' | '600' | '700' | '800' | '900'; export type GrayColorKeys = ColorKeys | '750' | '850' | '950'; export interface ResponsivePreset { label: string; width: number; height?: number | null; } export interface BackgroundPreset { label: string; color: string; contrastColor?: string; } export interface TreeGroupConfig { title: string; id?: string; include?: (file: ServerTreeFile) => boolean; } /** * @deprecated Use `PovesteConfig` instead. Kept for drop-in compat with histoire. */ export type HistoireConfig = PovesteConfig; export interface PovesteConfig { plugins: Plugin[]; /** * Output directory. */ outDir: string; /** * Glob patterns for story files to include. */ storyMatch: string[]; /** * Glob patterns to ignore files while searching for story files. * Added to the defaults (`node_modules`, `dist`), not a replacement for them. */ storyIgnored: string[]; /** * Patterns to match stories to support plugins automatically. */ supportMatch: SupportMatchPattern[]; /** * Master switch for CSS isolation between Poveste chrome and user stories. * When true (default), user CSS imported via poveste.setup is scoped to story * containers, chrome CSS is scoped away from them, and grid items render * in iframes. Set to false to restore pre-1.0 behavior. See guide/css.md. */ isolateStyles?: boolean; /** * CSS files loaded into the main app (not into stories). Wrapped in * @layer poveste-user-globals — lower priority than chrome. * Use for design tokens or anything intentionally global. */ globalStyles?: string[]; /** * How to generate the story tree. */ tree: { /** * Use `'title'` to create the path from the title of the story, using `/` as the separator. * * Use `'path'` use the real folder structure on your computer. */ file?: 'title' | 'path' | ((file: ServerTreeFile) => string[]); order?: 'asc' | ((a: string, b: string) => number); groups?: TreeGroupConfig[]; }; /** * Customize the look of the book. */ theme: { /** * Main page title. For example: 'Acme Inc.' */ title?: string; /** * Custom logo files. Should be import paths (processed by Vite). * * Example: `'/src/assets/my-logo.svg'` */ logo?: { /** * Square logo without text. */ square?: string; /** * Full logo for light theme. */ light?: string; /** * Full logo for dark theme. */ dark?: string; }; /** * Href to the favicon file (**not** processed by Vite). Put the file in the `public` directory. * * Example: `'/favicon.ico'` */ favicon?: string; /** * Customize the colors. Each color should be an object with shades as keys. * * Example: ```{ primary: { 50: '#eef2ff', 100: '#e0e7ff', ..., 900: '#312e81' } }``` * * You can import `defaultColors` from `'poveste'` to use predefined colors or you can create your own colors from scratch. */ colors?: { [key in CustomizableColors]?: key extends 'gray' ? { [key in GrayColorKeys]?: string; } : { [key in ColorKeys]?: string; }; }; /** * Add a link to the main logo */ logoHref?: string; /** * Default color scheme for the app. */ defaultColorScheme?: 'light' | 'dark' | 'auto'; /** * Hides the dark mode button in the toolbar. */ hideColorSchemeSwitch?: boolean; /** * Enable persistence of the color scheme in the browser. */ storeColorScheme?: boolean; /** * Class added to the story preview when dark mode is enabled. */ darkClass?: string; /** * Language of the book, emitted as `` on the shell and the * sandbox. * * `html-has-lang` is WCAG 3.1.1 Level A: without it a screen reader falls * back to the user agent's locale and may read the page in the wrong * language. Defaults to `'en'`, because leaving it unset would keep that * failure for everyone who does not read a changelog. * * @default 'en' */ lang?: string; }; /** * Setup file exporting a default function executed when setting up each story preview. * * Import custom CSS files from this file. * * Example: `'/src/poveste-setup.ts'` */ setupFile?: string | { /** * Only loaded in the browser client. */ browser: string; } | { /** * Only loaded while collecting stories in the node server. */ server: string; } | { /** * Only loaded in the browser client. */ browser: string; /** * Only loaded while collecting stories in the node server. */ server: string; }; /** * Setup code created by plugins */ setupCode?: string[]; /** * Predefined responsive sizes for story playgrounds. */ responsivePresets?: ResponsivePreset[]; /** * Background color of the story preview. */ backgroundPresets?: BackgroundPreset[]; /** * Initial background color used for story previews before the user picks one. * * Should match a `color` from `backgroundPresets` to also highlight the corresponding * entry in the dropdown; any other value is still applied as a CSS color. * * @default 'transparent' */ defaultBackgroundColor?: string; /** * Automatically apply the current background preset's contrast color to the story preview text. */ autoApplyContrastColor?: boolean; /** * Extra `` tags injected into the Poveste app and the story sandbox. * Same input shape as Nuxt's `useHead`. Use for global stylesheets, web fonts, * analytics snippets, or any meta tag that needs to apply in both contexts. * * Example: `head: { link: [{ rel: 'stylesheet', href: '...' }] }` */ head?: UseHeadInput; /** * Class added to the html root of the story preview when dark mode is enabled. * * Applied only when you set it. It has no default, so a book that configures * `theme.darkClass` alone gets that one class on every render path rather * than a second, different one (#126). * @deprecated use `theme.darkClass` instead */ sandboxDarkClass?: string; /** * Default props for stories. */ defaultStoryProps?: Omit; /** * Customize the markdown-it renderer */ markdown?: (md: MarkdownIt) => MarkdownIt | Promise; /** * Change the router mode. * - history: use HTML history with cleaner URLs * - hash: use hashtag hack in the URL to support more hosting services */ routerMode?: 'history' | 'hash'; /** * Vite config override */ vite?: ViteConfig | ((config: ViteConfig, env: ViteConfigEnv) => void | ViteConfig | Promise); /** * Remove those plugins from the Vite configuration */ viteIgnorePlugins?: string[]; /** * Transpile dependencies when collecting stories on Node.js */ viteNodeInlineDeps?: (string | RegExp)[]; /** * Determine the transform method of modules */ viteNodeTransformMode?: { /** * Use SSR transform pipeline for the specified files. * Vite plugins will receive `ssr: true` flag when processing those files. * * @default [/\.([cm]?[jt]sx?|json)$/] */ ssr?: RegExp[]; /** * First do a normal transform pipeline (targeting browser), * then then do a SSR rewrite to run the code in Node. * Vite plugins will receive `ssr: false` flag when processing those files. * * @default other than `ssr` */ web?: RegExp[]; }; /** * Maximum number of threads used to collect stories. * By default based on available number of cores. */ collectMaxThreads?: number; /** * Build options */ build?: { /** * By default all dependencies in `node_modules` are bundled into a single 'vendors' file. * You can use this option to exclude some dependencies from this file. */ excludeFromVendorsChunk?: (string | RegExp)[]; }; } export type ConfigMode = 'build' | 'dev';