├── .github ├── dependabot.yml └── workflows │ ├── publish.yml │ └── storybook.yml ├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── addon ├── .gitignore ├── README.md ├── package.json ├── preset.js ├── preview.js └── src │ ├── index.ts │ ├── preset.ts │ └── preview.tsx ├── compile.ts ├── framework ├── .gitignore ├── README.md ├── package.json ├── preset.js └── src │ ├── index.ts │ ├── preset.ts │ ├── preview.tsx │ └── types.ts ├── lerna.json ├── package.json ├── website ├── .gitignore ├── .storybook │ └── main.js ├── babel.config.js ├── docs │ └── intro.md ├── docusaurus.config.js ├── package.json ├── sidebars.js ├── src │ ├── css │ │ └── custom.css │ └── theme │ │ ├── CodeBlock │ │ ├── index.stories.tsx │ │ └── index.tsx │ │ ├── ColorModeToggle │ │ ├── index.stories.tsx │ │ └── index.tsx │ │ ├── DocPaginator │ │ ├── index.stories.tsx │ │ └── index.tsx │ │ ├── EditThisPage │ │ ├── index.stories.tsx │ │ └── index.tsx │ │ ├── Footer │ │ ├── Links │ │ │ └── Simple │ │ │ │ ├── index.stories.tsx │ │ │ │ └── index.tsx │ │ ├── index.stories.tsx │ │ └── index.tsx │ │ └── ThemedImage │ │ ├── index.stories.tsx │ │ └── index.tsx ├── static │ ├── .nojekyll │ ├── ignored-plugin.js │ └── img │ │ ├── docusaurus-social-card.jpg │ │ ├── favicon.ico │ │ ├── logo.svg │ │ ├── storybook-dark.svg │ │ └── storybook-light.svg └── yarn.lock └── yarn.lock /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "monthly" 7 | -------------------------------------------------------------------------------- /.github/workflows/publish.yml: -------------------------------------------------------------------------------- 1 | name: Publish Packages to npmjs 2 | on: 3 | push: 4 | branches: 5 | - main 6 | paths: 7 | - "addon/**/*" 8 | - "framework/**/*" 9 | 10 | jobs: 11 | publish: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 16 18 | registry-url: "https://registry.npmjs.org" 19 | - name: Setup and publish package 20 | run: | 21 | yarn install --frozen-lockfile 22 | yarn build 23 | yarn lerna publish from-package --yes 24 | env: 25 | NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} 26 | -------------------------------------------------------------------------------- /.github/workflows/storybook.yml: -------------------------------------------------------------------------------- 1 | name: Storybook 2 | on: 3 | push: 4 | branches: 5 | - main 6 | 7 | jobs: 8 | build-and-deploy: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: actions/checkout@v3 12 | - uses: actions/setup-node@v3 13 | with: 14 | node-version: 16 15 | registry-url: "https://registry.npmjs.org" 16 | 17 | - name: Install and Build Packages 18 | run: | 19 | yarn install --frozen-lockfile 20 | yarn build 21 | 22 | - name: Build Storybook 23 | working-directory: ./website 24 | run: yarn build-storybook 25 | 26 | - name: Deploy 27 | uses: JamesIves/github-pages-deploy-action@v4 28 | with: 29 | branch: gh-pages 30 | folder: website/storybook-static 31 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16.14.0 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Jody Heavener 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # storybook-docusaurus 2 | 3 | **🦖 Storybook integrations to aid in developing with [Docusaurus](https://docusaurus.io/).** 4 | 5 | This repo contains two distributed packages: 6 | 7 | - An [addon](https://storybook.js.org/docs/7.0/react/addons/introduction) that allows you to render and develop Docusaurus components: [`/addon`](./addon/) 8 | - A [framework](https://storybook.js.org/docs/7.0/react/api/new-frameworks) that extends the [@storybook/react-webpack5](https://www.npmjs.com/package/@storybook/react-webpack5) framework and does everything the addon does: [`/framework`](./framework/) 9 | 10 | Check out the latest static Storybook build using the framework [here](https://jodyheavener.github.io/storybook-docusaurus). 11 | 12 | ## License 13 | 14 | MIT 15 | -------------------------------------------------------------------------------- /addon/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | dist 3 | yarn-debug.log* 4 | yarn-error.log* 5 | LICENSE 6 | -------------------------------------------------------------------------------- /addon/README.md: -------------------------------------------------------------------------------- 1 | # storybook-addon-docusaurus 2 | 3 | 🦖 A Storybook addon to aid in developing with [Docusaurus](https://docusaurus.io/). 4 | 5 | ## Features 6 | 7 | - Adds support for Docusaurus module aliases such as `@theme`, `@docusaurus`, `@generated`, and `@site`. [Theme alias](https://docusaurus.io/docs/advanced/client#theme-aliases) loading order is also respected across core theme, plugin-provided, and swizzled components. 8 | - Enables core Docusaurus loaders for JS, SVG, and fonts and other assets. Will prefer [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) over Storybook's SASS loader. 9 | - Loads the [client modules](https://docusaurus.io/docs/api/plugin-methods/lifecycle-apis#getClientModules) and [Webpack configs](https://docusaurus.io/docs/api/plugin-methods/lifecycle-apis#configureWebpack) from all plugins. 10 | - Applies a global decorator that wraps all components in Docusaurus React contexts, allowing the rendering of all swizzled components. 11 | 12 | ## Installing and Usage 13 | 14 | This addon assumes you're working in a project that already has Docusaurus and Storybook set up. 15 | 16 | ### Install the addon 17 | 18 | With npm: 19 | 20 | ```sh 21 | npm i storybook-addon-docusaurus 22 | ``` 23 | 24 | Or with yarn: 25 | 26 | ```sh 27 | yarn add storybook-addon-docusaurus 28 | ``` 29 | 30 | ### Enable the addon 31 | 32 | Add `"storybook-addon-docusaurus"` to the list of `addons` in your Storybook `.storybook/main.js` file. [Learn more.](https://storybook.js.org/docs/react/addons/install-addons/) 33 | 34 | That's it! You should now be able to write stories that make use of Docusaurus components. 35 | 36 | ## License 37 | 38 | MIT 39 | -------------------------------------------------------------------------------- /addon/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "storybook-addon-docusaurus", 3 | "version": "0.3.3", 4 | "description": "Storybook addon to aid in developing with Docusaurus", 5 | "keywords": [ 6 | "storybook-addons", 7 | "docusaurus" 8 | ], 9 | "homepage": "https://github.com/jodyheavener/storybook-docusaurus/tree/main/addon", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/jodyheavener/storybook-docusaurus", 13 | "directory": "addon" 14 | }, 15 | "license": "MIT", 16 | "author": "Jody Heavener ", 17 | "exports": { 18 | ".": { 19 | "node": "./dist/index.cjs", 20 | "require": "./dist/index.cjs", 21 | "import": "./dist/index.mjs" 22 | }, 23 | "./preset": { 24 | "require": "./dist/preset.cjs", 25 | "import": "./dist/preset.mjs" 26 | }, 27 | "./preview": { 28 | "require": "./dist/preview.cjs", 29 | "import": "./dist/preview.mjs" 30 | }, 31 | "./package.json": "./package.json" 32 | }, 33 | "main": "dist/index.js", 34 | "module": "dist/index.mjs", 35 | "files": [ 36 | "dist/**/*", 37 | "*.js", 38 | "*.d.ts" 39 | ], 40 | "scripts": { 41 | "build": "yarn --cwd=\"..\" compile --build --package addon", 42 | "watch": "yarn --cwd=\"..\" compile --watch --package addon", 43 | "prepack": "cp ../LICENSE LICENSE" 44 | }, 45 | "dependencies": { 46 | "@storybook/node-logger": "^6.5.16" 47 | }, 48 | "devDependencies": { 49 | "@docusaurus/core": "^2.3.1", 50 | "@docusaurus/types": "^2.3.1", 51 | "@storybook/react": "^6.5.16", 52 | "react-helmet-async": "^1.3.0", 53 | "react-router-dom": "^5.3.3", 54 | "webpack": "^5.73.0" 55 | }, 56 | "peerDependencies": { 57 | "@docusaurus/core": "^2.3.1", 58 | "react-helmet-async": "^1.3.0", 59 | "react-router-dom": "^5.3.3" 60 | }, 61 | "storybook": { 62 | "displayName": "Docusaurus", 63 | "icon": "https://raw.githubusercontent.com/facebook/docusaurus/main/website/static/img/docusaurus.png" 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /addon/preset.js: -------------------------------------------------------------------------------- 1 | import './dist/index'; 2 | -------------------------------------------------------------------------------- /addon/preview.js: -------------------------------------------------------------------------------- 1 | import './dist/preview'; 2 | -------------------------------------------------------------------------------- /addon/src/index.ts: -------------------------------------------------------------------------------- 1 | export const ADDON_ID = "storybook-addon-docusaurus"; 2 | 3 | if (module && module.hot && module.hot.decline) { 4 | module.hot.decline(); 5 | } 6 | -------------------------------------------------------------------------------- /addon/src/preset.ts: -------------------------------------------------------------------------------- 1 | import type { Configuration, RuleSetRule } from "webpack"; 2 | import createClientConfig from "@docusaurus/core/lib/webpack/client"; 3 | import { applyConfigureWebpack } from "@docusaurus/core/lib/webpack/utils"; 4 | import { loadClientModules } from "@docusaurus/core/lib/server/clientModules"; 5 | import { load } from "@docusaurus/core/lib/server"; 6 | import type { LoadedPlugin, Props } from "@docusaurus/types"; 7 | import { logger } from "@storybook/node-logger"; 8 | 9 | let docusaurusData: Props; 10 | 11 | const loadDocusaurus = async () => { 12 | docusaurusData = 13 | docusaurusData || 14 | (await load({ 15 | siteDir: process.cwd(), 16 | })); 17 | 18 | return docusaurusData; 19 | }; 20 | 21 | const ruleMatches = (rule: RuleSetRule, ...inputs: string[]) => 22 | inputs.some((input) => "test" in rule && (rule.test as RegExp).test(input)); 23 | 24 | const hasPlugin = (plugins: LoadedPlugin[], name: string) => 25 | plugins.map((plugin) => plugin.name).includes(name); 26 | 27 | const log = (message: string) => logger.info(`Docusaurus: ${message}`); 28 | 29 | const config = async (entry: string[] = []) => { 30 | const { plugins } = await loadDocusaurus(); 31 | 32 | const clientModulePlugins = plugins.filter( 33 | (plugin) => "getClientModules" in plugin 34 | ); 35 | if (clientModulePlugins.length > 0) { 36 | log( 37 | `adding client modules from the following plugins: ${clientModulePlugins 38 | .map((p) => p.name) 39 | .join(", ")}` 40 | ); 41 | } 42 | 43 | const clientModules = loadClientModules(clientModulePlugins); 44 | 45 | return [...entry, ...clientModules]; 46 | }; 47 | 48 | const webpackFinal = async (config: Configuration): Promise => { 49 | const props = await loadDocusaurus(); 50 | 51 | // Load up the Docusaurus client Webpack config, 52 | // so we can extract its aliases and rules 53 | const docusaurusConfig = await createClientConfig(props); 54 | 55 | const alias = { 56 | ...config.resolve!.alias, 57 | ...docusaurusConfig.resolve!.alias, 58 | }; 59 | 60 | const rules = (config.module!.rules as RuleSetRule[]) 61 | .map((rule) => { 62 | if (ruleMatches(rule, ".svg")) { 63 | log("preferring Docusaurus SVG loader over Storybook"); 64 | return { 65 | ...rule, 66 | exclude: /\.svg$/, 67 | }; 68 | } 69 | 70 | if ( 71 | hasPlugin(props.plugins, "docusaurus-plugin-sass") && 72 | ruleMatches(rule, ".module.scss") 73 | ) { 74 | log("preferring docusaurus-plugin-sass over Storybook SASS loader"); 75 | return null; 76 | } 77 | 78 | return rule; 79 | }) 80 | .filter(Boolean) as RuleSetRule[]; 81 | 82 | rules.push( 83 | // Use the rules defined by Docusaurus for SVGs and JS 84 | ...(docusaurusConfig.module!.rules as RuleSetRule[]).filter((rule) => 85 | ruleMatches(rule, ".svg", ".js", ".woff") 86 | ) 87 | ); 88 | 89 | let finalConfig: Configuration = { 90 | ...config, 91 | resolve: { 92 | ...config.resolve, 93 | roots: [ 94 | ...(config.resolve!.roots || []), 95 | ...docusaurusConfig.resolve!.roots!, 96 | ], 97 | alias, 98 | }, 99 | module: { 100 | ...config.module, 101 | rules, 102 | }, 103 | plugins: [...config.plugins!, ...docusaurusConfig.plugins!], 104 | }; 105 | 106 | // Allow plugins to make any final tweaks to the config 107 | const appliedWebpackConfigs: string[] = []; 108 | (props.plugins as LoadedPlugin[]) 109 | .filter((plugin) => "configureWebpack" in plugin) 110 | .forEach((plugin) => { 111 | finalConfig = applyConfigureWebpack( 112 | plugin.configureWebpack!.bind(plugin), 113 | finalConfig, 114 | false, 115 | props.siteConfig.webpack?.jsLoader, 116 | plugin.content 117 | ); 118 | appliedWebpackConfigs.push(plugin.name); 119 | }); 120 | 121 | if (appliedWebpackConfigs.length > 0) { 122 | log( 123 | `applying Webpack configs from the following Docusaurus plugins: ${appliedWebpackConfigs.join( 124 | ", " 125 | )}` 126 | ); 127 | } 128 | 129 | // For some reason I've run into `exclude` properties 130 | // with undefined values, so let's filter those out 131 | finalConfig.module!.rules = (finalConfig.module!.rules as RuleSetRule[]).map( 132 | (rule) => { 133 | if (rule.exclude && Array.isArray(rule.exclude)) { 134 | rule.exclude = rule.exclude.filter(Boolean); 135 | } 136 | 137 | return rule; 138 | } 139 | ); 140 | 141 | return finalConfig; 142 | }; 143 | 144 | export { config, webpackFinal }; 145 | -------------------------------------------------------------------------------- /addon/src/preview.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import React from "react"; 4 | import type { DecoratorFn } from "@storybook/react"; 5 | import LayoutProvider from "@theme/Layout/Provider"; 6 | import { RouteContextProvider } from "@docusaurus/core/lib/client/routeContext"; 7 | import { BrowserRouter } from "react-router-dom"; 8 | import { HelmetProvider } from "react-helmet-async"; 9 | 10 | if (window?.docusaurus == null) { 11 | window.docusaurus = { 12 | prefetch: () => false, 13 | preload: () => false, 14 | }; 15 | } 16 | 17 | export const decorators: DecoratorFn[] = [ 18 | (Story) => ( 19 | 20 | 21 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ), 36 | ]; 37 | -------------------------------------------------------------------------------- /compile.ts: -------------------------------------------------------------------------------- 1 | import { resolve } from "path"; 2 | import { context, BuildOptions } from "esbuild"; 3 | import rimraf from "rimraf"; 4 | 5 | const args = process.argv; 6 | 7 | const flagNames = ["watch", "build"] as const; 8 | const flags = flagNames.reduce((acc, name) => { 9 | acc[name] = !!args.slice(2).find((s) => s.startsWith(`--${name}`)); 10 | return acc; 11 | }, {}) as Record; 12 | 13 | const packageDirIndex = args.indexOf("--package"); 14 | const packageDir = args[packageDirIndex + 1]; 15 | if (packageDirIndex < 0 || !packageDir) { 16 | throw new Error("Missing --package flag"); 17 | } 18 | 19 | const srcPath = resolve(__dirname, packageDir, "src"); 20 | const distPath = resolve(__dirname, packageDir, "dist"); 21 | 22 | const run = async () => { 23 | rimraf(distPath); 24 | 25 | const baseOptions: BuildOptions = { 26 | entryPoints: ["index.ts", "preview.tsx", "preset.ts"].map((e) => 27 | resolve(srcPath, e) 28 | ), 29 | platform: "node", 30 | outdir: distPath, 31 | minify: flags.build, 32 | }; 33 | 34 | const esm = await context({ 35 | ...baseOptions, 36 | format: "esm", 37 | outExtension: { 38 | ".js": ".mjs", 39 | }, 40 | }); 41 | 42 | const cjs = await context({ 43 | ...baseOptions, 44 | format: "cjs", 45 | outExtension: { 46 | ".js": ".cjs", 47 | }, 48 | }); 49 | 50 | if (flags.watch) { 51 | console.log("Watching for changes..."); 52 | await Promise.all([esm.watch(), cjs.watch()]); 53 | } else { 54 | console.log(`Building ${packageDir}...`); 55 | await Promise.all([esm.rebuild(), cjs.rebuild()]); 56 | 57 | await esm.dispose(); 58 | await cjs.dispose(); 59 | } 60 | }; 61 | 62 | run().catch((err: unknown) => { 63 | if (err instanceof Error) { 64 | console.error(err.stack); 65 | } 66 | 67 | process.exit(1); 68 | }); 69 | -------------------------------------------------------------------------------- /framework/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | dist 3 | yarn-debug.log* 4 | yarn-error.log* 5 | LICENSE 6 | -------------------------------------------------------------------------------- /framework/README.md: -------------------------------------------------------------------------------- 1 | # storybook-framework-docusaurus 2 | 3 | 🦖 A Storybook framework to aid in developing with [Docusaurus](https://docusaurus.io/). It uses Storybook's new [Frameworks API](https://storybook.js.org/blog/framework-api/). 4 | 5 | ## Features 6 | 7 | - Adds support for Docusaurus module aliases such as `@theme`, `@docusaurus`, `@generated`, and `@site`. [Theme alias](https://docusaurus.io/docs/advanced/client#theme-aliases) loading order is also respected across core theme, plugin-provided, and swizzled components. 8 | - Enables core Docusaurus loaders for JS, SVG, and fonts and other assets. Will prefer [docusaurus-plugin-sass](https://github.com/rlamana/docusaurus-plugin-sass) over Storybook's SASS loader. 9 | - Loads the [client modules](https://docusaurus.io/docs/api/plugin-methods/lifecycle-apis#getClientModules) and [Webpack configs](https://docusaurus.io/docs/api/plugin-methods/lifecycle-apis#configureWebpack) from all plugins. 10 | - Applies a global decorator that wraps all components in Docusaurus React contexts, allowing the rendering of all swizzled components. 11 | 12 | ## Installing and Usage 13 | 14 | This framework assumes you're working in a project that already has Docusaurus and Storybook (^7) set up. 15 | 16 | ### Install the framework 17 | 18 | With npm: 19 | 20 | ```sh 21 | npm i storybook-framework-docusaurus 22 | ``` 23 | 24 | Or with yarn: 25 | 26 | ```sh 27 | yarn add storybook-framework-docusaurus 28 | ``` 29 | 30 | ### Enable the framework 31 | 32 | Set `"storybook-framework-docusaurus"` as the `framework` in your Storybook `.storybook/main.js` file. 33 | 34 | ```json 35 | "framework": { 36 | "name": "storybook-framework-docusaurus", 37 | "options": { 38 | "ignoreClientModules": [ 39 | "ignored-custom-plugin" 40 | ], 41 | "ignoreWebpackConfigs": [ 42 | "ignored-custom-plugin" 43 | ] 44 | }, 45 | }, 46 | ``` 47 | 48 | This framework extends [@storybook/react-webpack5](https://www.npmjs.com/package/@storybook/react-webpack5), so you can use all its existing options in addition to the following: 49 | 50 | - `ignoreClientModules` will ignore the client modules from the listed Docusaurus plugins. 51 | - `ignoreWebpackConfigs` will ignore the Webpack configs from the listed Docusaurus plugins. 52 | 53 | That's it! You should now be able to write stories that make use of Docusaurus components. 54 | 55 | ## License 56 | 57 | MIT 58 | -------------------------------------------------------------------------------- /framework/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "storybook-framework-docusaurus", 3 | "version": "0.1.0-alpha.0", 4 | "description": "Storybook for Docusaurus: develop Docusaurus components in isolation. Based on @storybook/react-webpack5.", 5 | "keywords": [ 6 | "storybook", 7 | "docusaurus" 8 | ], 9 | "homepage": "https://github.com/jodyheavener/storybook-docusaurus/tree/main/framework", 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/jodyheavener/storybook-docusaurus", 13 | "directory": "framework" 14 | }, 15 | "license": "MIT", 16 | "author": "Jody Heavener ", 17 | "exports": { 18 | ".": { 19 | "node": "./dist/index.cjs", 20 | "require": "./dist/index.cjs", 21 | "import": "./dist/index.mjs" 22 | }, 23 | "./preset": { 24 | "require": "./dist/preset.cjs", 25 | "import": "./dist/preset.mjs" 26 | }, 27 | "./preview": { 28 | "require": "./dist/preview.cjs", 29 | "import": "./dist/preview.mjs" 30 | }, 31 | "./package.json": "./package.json" 32 | }, 33 | "main": "dist/index.js", 34 | "module": "dist/index.mjs", 35 | "files": [ 36 | "dist/**/*", 37 | "*.js", 38 | "*.d.ts" 39 | ], 40 | "scripts": { 41 | "build": "yarn --cwd=\"..\" compile --build --package framework", 42 | "watch": "yarn --cwd=\"..\" compile --watch --package framework", 43 | "prepack": "cp ../LICENSE LICENSE" 44 | }, 45 | "dependencies": { 46 | "@storybook/node-logger": "^7.0.0-beta.54", 47 | "@storybook/react-webpack5": "^7.0.0-beta.54" 48 | }, 49 | "devDependencies": { 50 | "@docusaurus/core": "^2.3.1", 51 | "@docusaurus/types": "^2.3.1", 52 | "@storybook/react": "^6.5.16", 53 | "react-helmet-async": "^1.3.0", 54 | "react-router-dom": "^5.3.3", 55 | "webpack": "^5.73.0" 56 | }, 57 | "peerDependencies": { 58 | "@docusaurus/core": "^2.3.1", 59 | "react-helmet-async": "^1.3.0", 60 | "react-router-dom": "^5.3.3" 61 | }, 62 | "storybook": { 63 | "displayName": "Docusaurus", 64 | "icon": "https://raw.githubusercontent.com/facebook/docusaurus/main/website/static/img/docusaurus.png" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /framework/preset.js: -------------------------------------------------------------------------------- 1 | module.exports = require('./dist/preset'); 2 | -------------------------------------------------------------------------------- /framework/src/index.ts: -------------------------------------------------------------------------------- 1 | export * from "./types"; 2 | -------------------------------------------------------------------------------- /framework/src/preset.ts: -------------------------------------------------------------------------------- 1 | import type { Configuration, RuleSetRule } from "webpack"; 2 | import createClientConfig from "@docusaurus/core/lib/webpack/client"; 3 | import { applyConfigureWebpack } from "@docusaurus/core/lib/webpack/utils"; 4 | import { loadClientModules } from "@docusaurus/core/lib/server/clientModules"; 5 | import { load } from "@docusaurus/core/lib/server"; 6 | import type { LoadedPlugin, Props } from "@docusaurus/types"; 7 | import { logger } from "@storybook/node-logger"; 8 | import { type StorybookConfig, type FrameworkOptions } from "./types"; 9 | import { join } from "path"; 10 | 11 | export { 12 | addons, 13 | frameworkOptions, 14 | core, 15 | webpack, 16 | } from "@storybook/react-webpack5/preset"; 17 | 18 | let docusaurusData: Props; 19 | 20 | const loadDocusaurus = async () => { 21 | docusaurusData = 22 | docusaurusData || 23 | (await load({ 24 | siteDir: process.cwd(), 25 | })); 26 | 27 | return docusaurusData; 28 | }; 29 | 30 | const ruleMatches = (rule: RuleSetRule, ...inputs: string[]) => 31 | inputs.some((input) => "test" in rule && (rule.test as RegExp).test(input)); 32 | 33 | const filterPlugins = ( 34 | plugins: LoadedPlugin[], 35 | ignoredPlugins: string[] 36 | ): LoadedPlugin[] => plugins.filter((p) => !ignoredPlugins.includes(p.name)); 37 | 38 | const hasPlugin = (plugins: LoadedPlugin[], name: string) => 39 | plugins.map((plugin) => plugin.name).includes(name); 40 | 41 | const log = (message: string) => logger.info(`Docusaurus: ${message}`); 42 | 43 | const getFrameworkOption = ( 44 | frameworkConfig: StorybookConfig["framework"], 45 | optionName: TName, 46 | fallback: FrameworkOptions[TName] 47 | ): FrameworkOptions[TName] => 48 | (typeof frameworkConfig === "object" && 49 | frameworkConfig.options[optionName]) || 50 | fallback; 51 | 52 | const previewAnnotations: NonNullable = 53 | async (entry: string[] = [], options) => { 54 | const frameworkConfig = await options.presets.apply< 55 | StorybookConfig["framework"] 56 | >("framework"); 57 | 58 | const props = await loadDocusaurus(); 59 | const plugins = filterPlugins( 60 | props.plugins, 61 | getFrameworkOption(frameworkConfig, "ignoreClientModules", []) 62 | ); 63 | 64 | const clientModulePlugins = plugins.filter( 65 | (plugin) => "getClientModules" in plugin 66 | ); 67 | if (clientModulePlugins.length > 0) { 68 | log( 69 | `adding client modules from the following plugins: ${clientModulePlugins 70 | .map((p) => p.name) 71 | .join(", ")}` 72 | ); 73 | } 74 | 75 | const clientModules = loadClientModules(clientModulePlugins); 76 | const preview = require.resolve(join(__dirname, "preview")); 77 | 78 | return [...entry, ...clientModules, preview]; 79 | }; 80 | 81 | const webpackFinal: NonNullable = async ( 82 | baseConfig, 83 | options 84 | ) => { 85 | const frameworkConfig = await options.presets.apply< 86 | StorybookConfig["framework"] 87 | >("framework"); 88 | 89 | const props = await loadDocusaurus(); 90 | const plugins = filterPlugins( 91 | props.plugins, 92 | getFrameworkOption(frameworkConfig, "ignoreWebpackConfigs", []) 93 | ); 94 | 95 | // Load up the Docusaurus client Webpack config, 96 | // so we can extract its aliases and rules 97 | const docusaurusConfig = await createClientConfig(props); 98 | 99 | const webpackAlias = { 100 | ...baseConfig.resolve!.alias, 101 | ...docusaurusConfig.resolve!.alias, 102 | }; 103 | 104 | const rules = (baseConfig.module!.rules as RuleSetRule[]) 105 | .map((rule) => { 106 | if (ruleMatches(rule, ".svg")) { 107 | log("preferring SVG loader over Storybook"); 108 | return { 109 | ...rule, 110 | exclude: /\.svg$/, 111 | }; 112 | } 113 | 114 | if ( 115 | hasPlugin(plugins, "docusaurus-plugin-sass") && 116 | ruleMatches(rule, ".module.scss") 117 | ) { 118 | log("preferring docusaurus-plugin-sass over Storybook SASS loader"); 119 | return null; 120 | } 121 | 122 | return rule; 123 | }) 124 | .filter(Boolean) as RuleSetRule[]; 125 | 126 | rules.push( 127 | // Use the rules defined by Docusaurus for SVGs and JS 128 | ...(docusaurusConfig.module!.rules as RuleSetRule[]).filter((rule) => 129 | ruleMatches(rule, ".svg", ".js", ".woff") 130 | ) 131 | ); 132 | 133 | let finalConfig: Configuration = { 134 | ...baseConfig, 135 | resolve: { 136 | ...baseConfig.resolve, 137 | roots: [ 138 | ...(baseConfig.resolve!.roots || []), 139 | ...docusaurusConfig.resolve!.roots!, 140 | ], 141 | alias: webpackAlias, 142 | }, 143 | module: { 144 | ...baseConfig.module, 145 | rules, 146 | }, 147 | plugins: [...baseConfig.plugins!, ...docusaurusConfig.plugins!], 148 | }; 149 | 150 | // Allow plugins to make any final tweaks to the config 151 | const appliedWebpackConfigs: string[] = []; 152 | plugins 153 | .filter((plugin) => "configureWebpack" in plugin) 154 | .forEach((plugin) => { 155 | finalConfig = applyConfigureWebpack( 156 | plugin.configureWebpack!.bind(plugin), 157 | finalConfig, 158 | false, 159 | props.siteConfig.webpack?.jsLoader, 160 | plugin.content 161 | ); 162 | appliedWebpackConfigs.push(plugin.name); 163 | }); 164 | 165 | if (appliedWebpackConfigs.length > 0) { 166 | log( 167 | `applying Webpack configs from the following plugins: ${appliedWebpackConfigs.join( 168 | ", " 169 | )}` 170 | ); 171 | } 172 | 173 | // For some reason I've run into `exclude` properties 174 | // with undefined values, so let's filter those out 175 | finalConfig.module!.rules = (finalConfig.module!.rules as RuleSetRule[]).map( 176 | (rule) => { 177 | if (rule.exclude && Array.isArray(rule.exclude)) { 178 | rule.exclude = rule.exclude.filter(Boolean); 179 | } 180 | 181 | return rule; 182 | } 183 | ); 184 | 185 | return finalConfig; 186 | }; 187 | 188 | export { previewAnnotations, webpackFinal }; 189 | -------------------------------------------------------------------------------- /framework/src/preview.tsx: -------------------------------------------------------------------------------- 1 | /// 2 | 3 | import React from "react"; 4 | import type { DecoratorFn } from "@storybook/react"; 5 | import LayoutProvider from "@theme/Layout/Provider"; 6 | import { RouteContextProvider } from "@docusaurus/core/lib/client/routeContext"; 7 | import { BrowserRouter } from "react-router-dom"; 8 | import { HelmetProvider } from "react-helmet-async"; 9 | 10 | if (window?.docusaurus == null) { 11 | window.docusaurus = { 12 | prefetch: () => false, 13 | preload: () => false, 14 | }; 15 | } 16 | 17 | export const decorators: DecoratorFn[] = [ 18 | (Story) => ( 19 | 20 | 21 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | ), 36 | ]; 37 | -------------------------------------------------------------------------------- /framework/src/types.ts: -------------------------------------------------------------------------------- 1 | import type { StorybookConfig as StorybookConfigBase } from "@storybook/preset-react-webpack"; 2 | import type { StorybookConfigWebpack } from "@storybook/builder-webpack5"; 3 | 4 | import type { 5 | FrameworkOptions as ReactFrameworkOptions, 6 | StorybookConfig as ReactStorybookConfig, 7 | } from "@storybook/react-webpack5"; 8 | 9 | type FrameworkName = "storybook-framework-docusaurus"; 10 | 11 | export type FrameworkOptions = ReactFrameworkOptions & { 12 | ignoreWebpackConfigs: string[]; 13 | ignoreClientModules: string[]; 14 | }; 15 | 16 | type StorybookConfigFramework = { 17 | framework: 18 | | FrameworkName 19 | | { 20 | name: FrameworkName; 21 | options: FrameworkOptions; 22 | }; 23 | } & Pick; 24 | 25 | /** 26 | * The interface for Storybook configuration in `main.ts` files. 27 | */ 28 | export type StorybookConfig = Omit< 29 | StorybookConfigBase, 30 | keyof StorybookConfigWebpack | keyof StorybookConfigFramework 31 | > & 32 | StorybookConfigWebpack & 33 | StorybookConfigFramework; 34 | -------------------------------------------------------------------------------- /lerna.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "node_modules/lerna/schemas/lerna-schema.json", 3 | "useNx": true, 4 | "version": "independent", 5 | "useWorkspaces": true 6 | } 7 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "root", 3 | "private": true, 4 | "workspaces": [ 5 | "addon", 6 | "framework", 7 | "website" 8 | ], 9 | "scripts": { 10 | "compile": "node -r esbuild-register ./compile.ts", 11 | "build": "yarn workspace storybook-addon-docusaurus build && yarn workspace storybook-framework-docusaurus build" 12 | }, 13 | "devDependencies": { 14 | "esbuild": "^0.17.11", 15 | "esbuild-register": "^3.4.2", 16 | "lerna": "^5.6.2", 17 | "rimraf": "^4.3.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /website/.gitignore: -------------------------------------------------------------------------------- 1 | # Dependencies 2 | /node_modules 3 | 4 | # Production 5 | /build 6 | 7 | # Generated files 8 | .docusaurus 9 | .cache-loader 10 | 11 | # Misc 12 | .DS_Store 13 | .env.local 14 | .env.development.local 15 | .env.test.local 16 | .env.production.local 17 | 18 | npm-debug.log* 19 | yarn-debug.log* 20 | yarn-error.log* 21 | -------------------------------------------------------------------------------- /website/.storybook/main.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "stories": [ 3 | "../src/**/*.stories.@(js|jsx|ts|tsx)", 4 | ], 5 | "addons": [ 6 | "@storybook/addon-links", 7 | "@storybook/addon-essentials", 8 | "@storybook/addon-interactions" 9 | ], 10 | "framework": { 11 | "name": "storybook-framework-docusaurus", 12 | "options": { 13 | "fastRefresh": true, 14 | "ignoreClientModules": [ 15 | "ignored-custom-plugin" 16 | ], 17 | "ignoreWebpackConfigs": [ 18 | "ignored-custom-plugin" 19 | ] 20 | }, 21 | }, 22 | "docs": { 23 | "autodocs": false 24 | }, 25 | "staticDirs": ['../static'], 26 | } 27 | -------------------------------------------------------------------------------- /website/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [require.resolve('@docusaurus/core/lib/babel/preset')], 3 | }; 4 | -------------------------------------------------------------------------------- /website/docs/intro.md: -------------------------------------------------------------------------------- 1 | --- 2 | slug: / 3 | sidebar_position: 1 4 | sidebar_label: Intro 5 | --- 6 | 7 | # Hello! 8 | 9 | This is a test site for the `storybook-framework-docusaurus` package. 10 | -------------------------------------------------------------------------------- /website/docusaurus.config.js: -------------------------------------------------------------------------------- 1 | const { resolve } = require("path"); 2 | 3 | // @ts-check 4 | // Note: type annotations allow type checking and IDEs autocompletion 5 | 6 | const lightCodeTheme = require('prism-react-renderer/themes/github'); 7 | const darkCodeTheme = require('prism-react-renderer/themes/dracula'); 8 | 9 | /** @type {import('@docusaurus/types').Config} */ 10 | const config = { 11 | title: 'My Site', 12 | tagline: 'Dinosaurs are cool', 13 | favicon: 'img/favicon.ico', 14 | 15 | // Set the production url of your site here 16 | url: 'https://your-docusaurus-test-site.com', 17 | // Set the // pathname under which your site is served 18 | // For GitHub pages deployment, it is often '//' 19 | baseUrl: '/', 20 | 21 | // GitHub pages deployment config. 22 | // If you aren't using GitHub pages, you don't need these. 23 | organizationName: 'facebook', // Usually your GitHub org/user name. 24 | projectName: 'docusaurus', // Usually your repo name. 25 | 26 | onBrokenLinks: 'throw', 27 | onBrokenMarkdownLinks: 'warn', 28 | 29 | // Even if you don't use internalization, you can use this field to set useful 30 | // metadata like html lang. For example, if your site is Chinese, you may want 31 | // to replace "en" with "zh-Hans". 32 | i18n: { 33 | defaultLocale: 'en', 34 | locales: ['en'], 35 | }, 36 | 37 | plugins: [ 38 | () => ({ 39 | name: "ignored-custom-plugin", 40 | getClientModules() { 41 | return [resolve("./static/ignored-plugin.js")]; 42 | }, 43 | configureWebpack() { 44 | throw new Error("Should not have included this plugin's Webpack config."); 45 | } 46 | }), 47 | ], 48 | 49 | presets: [ 50 | [ 51 | 'classic', 52 | /** @type {import('@docusaurus/preset-classic').Options} */ 53 | ({ 54 | docs: { 55 | routeBasePath: "/", 56 | sidebarPath: require.resolve("./sidebars.js"), 57 | }, 58 | blog: false, 59 | theme: { 60 | customCss: require.resolve('./src/css/custom.css'), 61 | }, 62 | }), 63 | ], 64 | ], 65 | 66 | themeConfig: 67 | /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ 68 | ({ 69 | // Replace with your project's social card 70 | image: 'img/docusaurus-social-card.jpg', 71 | navbar: { 72 | title: 'My Site', 73 | logo: { 74 | alt: 'My Site Logo', 75 | src: 'img/logo.svg', 76 | }, 77 | }, 78 | footer: { 79 | style: 'dark', 80 | copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, 81 | }, 82 | prism: { 83 | theme: lightCodeTheme, 84 | darkTheme: darkCodeTheme, 85 | }, 86 | }), 87 | }; 88 | 89 | module.exports = config; 90 | -------------------------------------------------------------------------------- /website/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "website", 3 | "version": "0.0.0", 4 | "private": true, 5 | "scripts": { 6 | "docusaurus": "docusaurus", 7 | "start": "docusaurus start", 8 | "build": "docusaurus build", 9 | "swizzle": "docusaurus swizzle", 10 | "deploy": "docusaurus deploy", 11 | "clear": "docusaurus clear", 12 | "serve": "docusaurus serve", 13 | "write-translations": "docusaurus write-translations", 14 | "write-heading-ids": "docusaurus write-heading-ids", 15 | "storybook": "storybook dev -p 6006", 16 | "build-storybook": "storybook build" 17 | }, 18 | "dependencies": { 19 | "@docusaurus/core": "2.3.1", 20 | "@docusaurus/preset-classic": "2.3.1", 21 | "@mdx-js/react": "^1.6.22", 22 | "clsx": "^1.2.1", 23 | "prism-react-renderer": "^1.3.5", 24 | "react": "^17.0.2", 25 | "react-dom": "^17.0.2" 26 | }, 27 | "devDependencies": { 28 | "@babel/core": "^7.21.0", 29 | "@docusaurus/module-type-aliases": "2.3.1", 30 | "@storybook/addon-actions": "^7.0.0-beta.54", 31 | "@storybook/addon-essentials": "^7.0.0-beta.54", 32 | "@storybook/addon-interactions": "^7.0.0-beta.54", 33 | "@storybook/addon-links": "^7.0.0-beta.54", 34 | "@storybook/react-webpack5": "^7.0.0-beta.54", 35 | "@storybook/react": "^7.0.0-beta.54", 36 | "@storybook/testing-library": "^0.0.14-next.1", 37 | "babel-loader": "^8.3.0", 38 | "storybook": "next" 39 | }, 40 | "browserslist": { 41 | "production": [ 42 | ">0.5%", 43 | "not dead", 44 | "not op_mini all" 45 | ], 46 | "development": [ 47 | "last 1 chrome version", 48 | "last 1 firefox version", 49 | "last 1 safari version" 50 | ] 51 | }, 52 | "engines": { 53 | "node": ">=16.14" 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /website/sidebars.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Creating a sidebar enables you to: 3 | - create an ordered group of docs 4 | - render a sidebar for each doc of that group 5 | - provide next/previous navigation 6 | 7 | The sidebars can be generated from the filesystem, or explicitly defined here. 8 | 9 | Create as many sidebars as you want. 10 | */ 11 | 12 | // @ts-check 13 | 14 | /** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */ 15 | const sidebars = { 16 | // By default, Docusaurus generates a sidebar from the docs folder structure 17 | tutorialSidebar: [{type: 'autogenerated', dirName: '.'}], 18 | 19 | // But you can create a sidebar manually 20 | /* 21 | tutorialSidebar: [ 22 | 'intro', 23 | 'hello', 24 | { 25 | type: 'category', 26 | label: 'Tutorial', 27 | items: ['tutorial-basics/create-a-document'], 28 | }, 29 | ], 30 | */ 31 | }; 32 | 33 | module.exports = sidebars; 34 | -------------------------------------------------------------------------------- /website/src/css/custom.css: -------------------------------------------------------------------------------- 1 | /** 2 | * Any CSS included here will be global. The classic template 3 | * bundles Infima by default. Infima is a CSS framework designed to 4 | * work well for content-centric websites. 5 | */ 6 | 7 | /* You can override the default Infima variables here. */ 8 | :root { 9 | --ifm-color-primary: #2e8555; 10 | --ifm-color-primary-dark: #29784c; 11 | --ifm-color-primary-darker: #277148; 12 | --ifm-color-primary-darkest: #205d3b; 13 | --ifm-color-primary-light: #33925d; 14 | --ifm-color-primary-lighter: #359962; 15 | --ifm-color-primary-lightest: #3cad6e; 16 | --ifm-code-font-size: 95%; 17 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1); 18 | } 19 | 20 | /* For readability concerns, you should choose a lighter palette in dark mode. */ 21 | [data-theme='dark'] { 22 | --ifm-color-primary: #25c2a0; 23 | --ifm-color-primary-dark: #21af90; 24 | --ifm-color-primary-darker: #1fa588; 25 | --ifm-color-primary-darkest: #1a8870; 26 | --ifm-color-primary-light: #29d5b0; 27 | --ifm-color-primary-lighter: #32d8b4; 28 | --ifm-color-primary-lightest: #4fddbf; 29 | --docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.3); 30 | } 31 | -------------------------------------------------------------------------------- /website/src/theme/CodeBlock/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import CodeBlock from "."; 4 | 5 | export default { 6 | title: "CodeBlock", 7 | component: CodeBlock, 8 | } as Meta; 9 | 10 | type Story = StoryObj; 11 | 12 | export const Default: Story = { 13 | args: { 14 | children: 'console.log("Hello World!")', 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /website/src/theme/CodeBlock/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import CodeBlock from '@theme-original/CodeBlock'; 3 | import type CodeBlockType from '@theme/CodeBlock'; 4 | import type {WrapperProps} from '@docusaurus/types'; 5 | 6 | type Props = WrapperProps; 7 | 8 | export default function CodeBlockWrapper(props: Props): JSX.Element { 9 | return ( 10 | <> 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /website/src/theme/ColorModeToggle/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import ColorModeToggle from "."; 4 | 5 | export default { 6 | title: "ColorModeToggle", 7 | component: ColorModeToggle, 8 | } as Meta; 9 | 10 | type Story = StoryObj; 11 | 12 | export const Default: Story = {}; 13 | -------------------------------------------------------------------------------- /website/src/theme/ColorModeToggle/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import ColorModeToggle from '@theme-original/ColorModeToggle'; 3 | import type ColorModeToggleType from '@theme/ColorModeToggle'; 4 | import type {WrapperProps} from '@docusaurus/types'; 5 | 6 | type Props = WrapperProps; 7 | 8 | export default function ColorModeToggleWrapper(props: Props): JSX.Element { 9 | return ( 10 | <> 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /website/src/theme/DocPaginator/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import DocPaginator from "."; 4 | 5 | export default { 6 | title: "DocPaginator", 7 | component: DocPaginator, 8 | } as Meta; 9 | 10 | type Story = StoryObj; 11 | 12 | export const Default: Story = { 13 | args: { 14 | previous: { 15 | title: "Previous", 16 | permalink: "/previous", 17 | }, 18 | next: { 19 | title: "Next", 20 | permalink: "/next", 21 | }, 22 | }, 23 | }; 24 | -------------------------------------------------------------------------------- /website/src/theme/DocPaginator/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import DocPaginator from '@theme-original/DocPaginator'; 3 | import type DocPaginatorType from '@theme/DocPaginator'; 4 | import type {WrapperProps} from '@docusaurus/types'; 5 | 6 | type Props = WrapperProps; 7 | 8 | export default function DocPaginatorWrapper(props: Props): JSX.Element { 9 | return ( 10 | <> 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /website/src/theme/EditThisPage/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import EditThisPage from "."; 4 | 5 | export default { 6 | title: "EditThisPage", 7 | component: EditThisPage, 8 | } as Meta; 9 | 10 | type Story = StoryObj; 11 | 12 | export const Default: Story = { 13 | args: { 14 | editUrl: "/edit" 15 | }, 16 | }; 17 | -------------------------------------------------------------------------------- /website/src/theme/EditThisPage/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import EditThisPage from '@theme-original/EditThisPage'; 3 | import type EditThisPageType from '@theme/EditThisPage'; 4 | import type {WrapperProps} from '@docusaurus/types'; 5 | 6 | type Props = WrapperProps; 7 | 8 | export default function EditThisPageWrapper(props: Props): JSX.Element { 9 | return ( 10 | <> 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /website/src/theme/Footer/Links/Simple/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import Simple from "."; 4 | 5 | export default { 6 | title: "Footer/Links/Simple", 7 | component: Simple, 8 | } as Meta; 9 | 10 | type Story = StoryObj; 11 | 12 | export const Default: Story = { 13 | args: { 14 | links: [ 15 | { 16 | label: "Hello World", 17 | href: "/" 18 | }, 19 | ], 20 | }, 21 | }; 22 | -------------------------------------------------------------------------------- /website/src/theme/Footer/Links/Simple/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Simple from '@theme-original/Footer/Links/Simple'; 3 | import type SimpleType from '@theme/Footer/Links/Simple'; 4 | import type {WrapperProps} from '@docusaurus/types'; 5 | 6 | type Props = WrapperProps; 7 | 8 | export default function SimpleWrapper(props: Props): JSX.Element { 9 | return ( 10 | <> 11 | 12 | 13 | ); 14 | } 15 | -------------------------------------------------------------------------------- /website/src/theme/Footer/index.stories.tsx: -------------------------------------------------------------------------------- 1 | import type { Meta, StoryObj } from "@storybook/react"; 2 | 3 | import Footer from "."; 4 | 5 | export default { 6 | title: "Footer", 7 | component: Footer, 8 | } as Meta; 9 | 10 | type Story = StoryObj; 11 | 12 | export const Default: Story = {}; 13 | -------------------------------------------------------------------------------- /website/src/theme/Footer/index.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import Footer from '@theme-original/Footer'; 3 | import type FooterType from '@theme/Footer'; 4 | import type {WrapperProps} from '@docusaurus/types'; 5 | 6 | type Props = WrapperProps; 7 | 8 | export default function FooterWrapper(props: Props): JSX.Element { 9 | return ( 10 | <> 11 |