diff --git a/examples/classic-typescript/docusaurus.config.ts b/examples/classic-typescript/docusaurus.config.ts index 4058eac59e23..09e075ac4f21 100644 --- a/examples/classic-typescript/docusaurus.config.ts +++ b/examples/classic-typescript/docusaurus.config.ts @@ -1,4 +1,3 @@ -import {themes as prismThemes} from 'prism-react-renderer'; import type {Config} from '@docusaurus/types'; import type * as Preset from '@docusaurus/preset-classic'; @@ -53,81 +52,6 @@ const config: Config = { } satisfies Preset.Options, ], ], - - themeConfig: { - // Replace with your project's social card - image: 'img/docusaurus-social-card.jpg', - navbar: { - title: 'My Site', - logo: { - alt: 'My Site Logo', - src: 'img/logo.svg', - }, - items: [ - { - type: 'docSidebar', - sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Tutorial', - }, - {to: '/blog', label: 'Blog', position: 'left'}, - { - href: 'https://github.com/facebook/docusaurus', - label: 'GitHub', - position: 'right', - }, - ], - }, - footer: { - style: 'dark', - links: [ - { - title: 'Docs', - items: [ - { - label: 'Tutorial', - to: '/docs/intro', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/docusaurus', - }, - { - label: 'Discord', - href: 'https://discordapp.com/invite/docusaurus', - }, - { - label: 'Twitter', - href: 'https://twitter.com/docusaurus', - }, - ], - }, - { - title: 'More', - items: [ - { - label: 'Blog', - to: '/blog', - }, - { - label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', - }, - ], - }, - ], - copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, - }, - prism: { - theme: prismThemes.github, - darkTheme: prismThemes.dracula, - }, - } satisfies Preset.ThemeConfig, }; export default config; diff --git a/examples/classic-typescript/docusaurus.theme.tsx b/examples/classic-typescript/docusaurus.theme.tsx new file mode 100644 index 000000000000..7799f867a932 --- /dev/null +++ b/examples/classic-typescript/docusaurus.theme.tsx @@ -0,0 +1,78 @@ +import { themes as prismThemes } from 'prism-react-renderer'; +import type * as Preset from '@docusaurus/preset-classic'; + +export default { + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: 'My Site', + logo: { + alt: 'My Site Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Tutorial', + }, + { to: '/blog', label: 'Blog', position: 'left' }, + { + href: 'https://github.com/facebook/docusaurus', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Tutorial', + to: '/docs/intro', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/docusaurus', + }, + { + label: 'Discord', + href: 'https://discordapp.com/invite/docusaurus', + }, + { + label: 'Twitter', + href: 'https://twitter.com/docusaurus', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Blog', + to: '/blog', + }, + { + label: 'GitHub', + href: 'https://github.com/facebook/docusaurus', + }, + ], + }, + ], + copyright: `Copyright © ${ new Date().getFullYear() } My Project, Inc. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, + +} satisfies Preset.ThemeConfig diff --git a/examples/classic/docusaurus.config.js b/examples/classic/docusaurus.config.js index 7b8d5b1c7f11..99c74ccd430a 100644 --- a/examples/classic/docusaurus.config.js +++ b/examples/classic/docusaurus.config.js @@ -4,8 +4,6 @@ // There are various equivalent ways to declare your Docusaurus config. // See: https://docusaurus.io/docs/api/docusaurus-config -import {themes as prismThemes} from 'prism-react-renderer'; - /** @type {import('@docusaurus/types').Config} */ const config = { title: 'My Site', @@ -59,83 +57,6 @@ const config = { }), ], ], - - themeConfig: - /** @type {import('@docusaurus/preset-classic').ThemeConfig} */ - ({ - // Replace with your project's social card - image: 'img/docusaurus-social-card.jpg', - navbar: { - title: 'My Site', - logo: { - alt: 'My Site Logo', - src: 'img/logo.svg', - }, - items: [ - { - type: 'docSidebar', - sidebarId: 'tutorialSidebar', - position: 'left', - label: 'Tutorial', - }, - {to: '/blog', label: 'Blog', position: 'left'}, - { - href: 'https://github.com/facebook/docusaurus', - label: 'GitHub', - position: 'right', - }, - ], - }, - footer: { - style: 'dark', - links: [ - { - title: 'Docs', - items: [ - { - label: 'Tutorial', - to: '/docs/intro', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/docusaurus', - }, - { - label: 'Discord', - href: 'https://discordapp.com/invite/docusaurus', - }, - { - label: 'Twitter', - href: 'https://twitter.com/docusaurus', - }, - ], - }, - { - title: 'More', - items: [ - { - label: 'Blog', - to: '/blog', - }, - { - label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', - }, - ], - }, - ], - copyright: `Copyright © ${new Date().getFullYear()} My Project, Inc. Built with Docusaurus.`, - }, - prism: { - theme: prismThemes.github, - darkTheme: prismThemes.dracula, - }, - }), }; export default config; diff --git a/examples/classic/docusaurus.theme.jsx b/examples/classic/docusaurus.theme.jsx new file mode 100644 index 000000000000..abc2ef643386 --- /dev/null +++ b/examples/classic/docusaurus.theme.jsx @@ -0,0 +1,74 @@ +export default { + // Replace with your project's social card + image: 'img/docusaurus-social-card.jpg', + navbar: { + title: 'My Site', + logo: { + alt: 'My Site Logo', + src: 'img/logo.svg', + }, + items: [ + { + type: 'docSidebar', + sidebarId: 'tutorialSidebar', + position: 'left', + label: 'Tutorial', + }, + { to: '/blog', label: 'Blog', position: 'left' }, + { + href: 'https://github.com/facebook/docusaurus', + label: 'GitHub', + position: 'right', + }, + ], + }, + footer: { + style: 'dark', + links: [ + { + title: 'Docs', + items: [ + { + label: 'Tutorial', + to: '/docs/intro', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/docusaurus', + }, + { + label: 'Discord', + href: 'https://discordapp.com/invite/docusaurus', + }, + { + label: 'Twitter', + href: 'https://twitter.com/docusaurus', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Blog', + to: '/blog', + }, + { + label: 'GitHub', + href: 'https://github.com/facebook/docusaurus', + }, + ], + }, + ], + copyright: `Copyright © ${ new Date().getFullYear() } My Project, Inc. Built with Docusaurus.`, + }, + prism: { + theme: prismThemes.github, + darkTheme: prismThemes.dracula, + }, +} diff --git a/packages/docusaurus-module-type-aliases/src/index.d.ts b/packages/docusaurus-module-type-aliases/src/index.d.ts index 1f0e7679420a..b24f992ef920 100644 --- a/packages/docusaurus-module-type-aliases/src/index.d.ts +++ b/packages/docusaurus-module-type-aliases/src/index.d.ts @@ -19,6 +19,13 @@ declare module '@generated/docusaurus.config' { export default config; } +declare module '@generated/docusaurus.theme' { + import type {ThemeConfig} from '@docusaurus/types'; + + const themeConfig: ThemeConfig; + export default themeConfig; +} + declare module '@generated/site-metadata' { import type {SiteMetadata} from '@docusaurus/types'; diff --git a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/Content/index.tsx b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/Content/index.tsx index 4feb2bc2b7d7..8fd04be5ed9e 100644 --- a/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/Content/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/AnnouncementBar/Content/index.tsx @@ -15,14 +15,23 @@ export default function AnnouncementBarContent( props: Props, ): JSX.Element | null { const {announcementBar} = useThemeConfig(); - const {content} = announcementBar!; + const {content: Content} = announcementBar!; + + // TODO Docusaurus v4: remove legacy announcement bar html string form? + if (typeof Content === 'string') { + return ( +
+ ); + } return ( -
+
+ +
); } diff --git a/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx b/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx index e14b77f1f31d..5d8d7e217faa 100644 --- a/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/Footer/Links/Simple/index.tsx @@ -6,6 +6,7 @@ */ import React from 'react'; +import {type FooterLinkItem} from '@docusaurus/theme-common'; import LinkItem from '@theme/Footer/LinkItem'; import type {Props} from '@theme/Footer/Links/Simple'; @@ -30,7 +31,7 @@ export default function FooterLinksSimple({links}: Props): JSX.Element { return (
- {links.map((item, i) => ( + {links.map((item: FooterLinkItem, i: number) => ( {links.length !== i + 1 && } diff --git a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts index 17b4fbda6b81..2903b2d9e00c 100644 --- a/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts +++ b/packages/docusaurus-theme-common/src/utils/useThemeConfig.ts @@ -5,6 +5,7 @@ * LICENSE file in the root directory of this source tree. */ +import type {ComponentType} from 'react'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import type {PrismTheme} from 'prism-react-renderer'; import type {DeepPartial} from 'utility-types'; @@ -51,7 +52,7 @@ export type ColorModeConfig = { export type AnnouncementBarConfig = { id: string; - content: string; + content: string | ComponentType; backgroundColor: string; textColor: string; isCloseable: boolean; @@ -99,6 +100,7 @@ export type TableOfContents = { maxHeadingLevel: number; }; +// TODO use TS interface declaration merging? // Theme config after validation/normalization export type ThemeConfig = { docs: { @@ -129,7 +131,25 @@ export type UserThemeConfig = DeepPartial; /** * A convenient/more semantic way to get theme config from context. + * TODO remove old themeConfig in Docusaurus v4? + * TODO remove this hook in v4 in favor of a core hook? */ export function useThemeConfig(): ThemeConfig { - return useDocusaurusContext().siteConfig.themeConfig as ThemeConfig; + const oldThemeConfig = useDocusaurusContext().siteConfig + .themeConfig as ThemeConfig; + const newThemeConfig = useDocusaurusContext().themeConfig as ThemeConfig; + + // TODO docusaurus-theme-classic/src/options.ts + // assigns default values in oldThemeConfig (navbar, footer...) + const duplicateKeys = Object.keys(oldThemeConfig).filter((key) => + Object.prototype.hasOwnProperty.call(newThemeConfig, key), + ); + + if (duplicateKeys.length > 0) { + console.warn( + `Duplicate keys found in siteConfig.themeConfig and themeConfig: ${duplicateKeys}`, + ); + } + + return {...oldThemeConfig, ...newThemeConfig}; } diff --git a/packages/docusaurus-types/src/config.d.ts b/packages/docusaurus-types/src/config.d.ts index 3a7bb99ae743..355855387f80 100644 --- a/packages/docusaurus-types/src/config.d.ts +++ b/packages/docusaurus-types/src/config.d.ts @@ -12,6 +12,7 @@ import type {PluginConfig, PresetConfig, HtmlTagObject} from './plugin'; export type ReportingSeverity = 'ignore' | 'log' | 'warn' | 'throw'; +// TODO use TypeScript interface declaration merging export type ThemeConfig = { [key: string]: unknown; }; diff --git a/packages/docusaurus-types/src/context.d.ts b/packages/docusaurus-types/src/context.d.ts index e05f8a9a3256..e7aac7f10b9d 100644 --- a/packages/docusaurus-types/src/context.d.ts +++ b/packages/docusaurus-types/src/context.d.ts @@ -4,7 +4,7 @@ * This source code is licensed under the MIT license found in the * LICENSE file in the root directory of this source tree. */ -import type {DocusaurusConfig} from './config'; +import type {DocusaurusConfig, ThemeConfig} from './config'; import type {CodeTranslations, I18n} from './i18n'; import type {LoadedPlugin, PluginVersionInformation} from './plugin'; import type {RouteConfig} from './routing'; @@ -12,6 +12,7 @@ import type {RouteConfig} from './routing'; export type DocusaurusContext = { siteConfig: DocusaurusConfig; siteMetadata: SiteMetadata; + themeConfig: ThemeConfig; globalData: GlobalData; i18n: I18n; codeTranslations: CodeTranslations; @@ -34,6 +35,7 @@ export type LoadContext = { generatedFilesDir: string; siteConfig: DocusaurusConfig; siteConfigPath: string; + themeConfigPath: string | undefined; // TODO Docusaurus v4: make it required outDir: string; /** * Directory where all source translations for the current locale can be found diff --git a/packages/docusaurus-utils/src/constants.ts b/packages/docusaurus-utils/src/constants.ts index 5039d6989b00..e3ff22713882 100644 --- a/packages/docusaurus-utils/src/constants.ts +++ b/packages/docusaurus-utils/src/constants.ts @@ -36,6 +36,8 @@ export const DEFAULT_BUILD_DIR_NAME = 'build'; */ export const DEFAULT_CONFIG_FILE_NAME = 'docusaurus.config'; +export const DEFAULT_THEME_FILE_NAME = 'docusaurus.theme'; + /** Can be absolute or relative to site directory. */ export const BABEL_CONFIG_FILE_NAME = process.env.DOCUSAURUS_BABEL_CONFIG_FILE_NAME ?? 'babel.config.js'; diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 5bb77a0c054f..352cc92ba3af 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -11,6 +11,7 @@ export { DOCUSAURUS_VERSION, DEFAULT_BUILD_DIR_NAME, DEFAULT_CONFIG_FILE_NAME, + DEFAULT_THEME_FILE_NAME, BABEL_CONFIG_FILE_NAME, GENERATED_FILES_DIR_NAME, SRC_DIR_NAME, diff --git a/packages/docusaurus/src/client/__tests__/docusaurusContext.test.tsx b/packages/docusaurus/src/client/__tests__/docusaurusContext.test.tsx index 24713c596f5c..c7566ae7198e 100644 --- a/packages/docusaurus/src/client/__tests__/docusaurusContext.test.tsx +++ b/packages/docusaurus/src/client/__tests__/docusaurusContext.test.tsx @@ -33,6 +33,7 @@ describe('DocusaurusContextProvider', () => { "i18n": {}, "siteConfig": {}, "siteMetadata": {}, + "themeConfig": {}, } `); }); diff --git a/packages/docusaurus/src/client/docusaurusContext.tsx b/packages/docusaurus/src/client/docusaurusContext.tsx index 5bed42737f37..40c4510484a9 100644 --- a/packages/docusaurus/src/client/docusaurusContext.tsx +++ b/packages/docusaurus/src/client/docusaurusContext.tsx @@ -7,6 +7,7 @@ import React, {type ReactNode} from 'react'; import siteConfig from '@generated/docusaurus.config'; +import themeConfig from '@generated/docusaurus.theme'; import globalData from '@generated/globalData'; import i18n from '@generated/i18n'; import codeTranslations from '@generated/codeTranslations'; @@ -18,6 +19,7 @@ import type {DocusaurusContext} from '@docusaurus/types'; const contextValue: DocusaurusContext = { siteConfig, siteMetadata, + themeConfig, globalData, i18n, codeTranslations, diff --git a/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap index 45b94b869406..d8c37243b745 100644 --- a/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus/src/server/__tests__/__snapshots__/index.test.ts.snap @@ -125,5 +125,6 @@ exports[`load loads props for site with custom i18n path 1`] = ` "pluginVersions": {}, "siteVersion": undefined, }, + "themeConfigPath": undefined, } `; diff --git a/packages/docusaurus/src/server/config.ts b/packages/docusaurus/src/server/config.ts index 59b30b133e24..43502b255b01 100644 --- a/packages/docusaurus/src/server/config.ts +++ b/packages/docusaurus/src/server/config.ts @@ -10,13 +10,14 @@ import fs from 'fs-extra'; import logger from '@docusaurus/logger'; import { DEFAULT_CONFIG_FILE_NAME, + DEFAULT_THEME_FILE_NAME, findAsyncSequential, loadFreshModule, } from '@docusaurus/utils'; import {validateConfig} from './configValidation'; -import type {LoadContext} from '@docusaurus/types'; +import type {DocusaurusConfig, LoadContext} from '@docusaurus/types'; -async function findConfig(siteDir: string) { +async function getConventionalSiteConfigPath(siteDir: string) { // We could support .mjs, .ts, etc. in the future const candidates = ['.ts', '.mts', '.cts', '.js', '.mjs', '.cjs'].map( (ext) => DEFAULT_CONFIG_FILE_NAME + ext, @@ -26,10 +27,10 @@ async function findConfig(siteDir: string) { fs.pathExists, ); if (!configPath) { - logger.error('No config file found.'); - logger.info`Expected one of:${candidates} + const errorMessage = logger.interpolate`No config file found. +Expected one of:${candidates} You can provide a custom config path with the code=${'--config'} option.`; - throw new Error(); + throw new Error(errorMessage); } return configPath; } @@ -43,7 +44,7 @@ export async function loadSiteConfig({ }): Promise> { const siteConfigPath = customConfigFilePath ? path.resolve(siteDir, customConfigFilePath) - : await findConfig(siteDir); + : await getConventionalSiteConfigPath(siteDir); if (!(await fs.pathExists(siteConfigPath))) { throw new Error(`Config file at "${siteConfigPath}" not found.`); @@ -62,3 +63,50 @@ export async function loadSiteConfig({ ); return {siteConfig, siteConfigPath}; } + +async function findConventionalThemeConfigPath( + siteDir: string, +): Promise { + // We could support .mjs, .ts, etc. in the future + const candidates = ['.tsx', '.ts', '.jsx', '.js'].map( + (ext) => DEFAULT_THEME_FILE_NAME + ext, + ); + const themeConfigPath = await findAsyncSequential( + candidates.map((file) => path.join(siteDir, file)), + fs.pathExists, + ); + + return themeConfigPath; +} + +// TODO add tests for this +export async function findThemeConfigPath( + siteDir: string, + siteConfig: DocusaurusConfig, +): Promise { + // TODO add support for custom themeConfig file path + // EX: siteConfig.themeConfig: './theme.tsx' + // Note: maybe it would be simpler to provide this path through the CLI? + if (typeof siteConfig.themeConfig === 'string') { + const customThemeConfigPath = siteConfig.themeConfig; + if (!(await fs.pathExists(customThemeConfigPath))) { + throw new Error( + `Theme config file at "${customThemeConfigPath}" not found.`, + ); + } + return customThemeConfigPath; + } + const conventionalThemeConfigPath = await findConventionalThemeConfigPath( + siteDir, + ); + // In Docusaurus v3 we require users to provide either the theme config + // through the conventional path, or through the legacy siteConfig attribute + // To avoid issues we warn users when no theme config is provided at all + if ( + !conventionalThemeConfigPath && + Object.keys(siteConfig.themeConfig ?? {}).length === 0 + ) { + logger.warn`Theme config file couldn't be found at ${DEFAULT_THEME_FILE_NAME}.js or ${DEFAULT_THEME_FILE_NAME}.tsx`; + } + return conventionalThemeConfigPath; +} diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts index ab50c1883d31..450e6945202f 100644 --- a/packages/docusaurus/src/server/index.ts +++ b/packages/docusaurus/src/server/index.ts @@ -13,9 +13,10 @@ import { localizePath, DEFAULT_BUILD_DIR_NAME, DEFAULT_CONFIG_FILE_NAME, + DEFAULT_THEME_FILE_NAME, GENERATED_FILES_DIR_NAME, } from '@docusaurus/utils'; -import {loadSiteConfig} from './config'; +import {findThemeConfigPath, loadSiteConfig} from './config'; import {loadClientModules} from './clientModules'; import {loadPlugins} from './plugins'; import {loadRoutes} from './routes'; @@ -68,6 +69,8 @@ export async function loadContext( customConfigFilePath, }); + const themeConfigPath = await findThemeConfigPath(siteDir, initialSiteConfig); + const i18n = await loadI18n(initialSiteConfig, {locale}); const baseUrl = localizePath({ @@ -106,6 +109,7 @@ export async function loadContext( localizationDir, siteConfig, siteConfigPath, + themeConfigPath, outDir, baseUrl, i18n, @@ -126,6 +130,7 @@ export async function load(options: LoadContextOptions): Promise { generatedFilesDir, siteConfig, siteConfigPath, + themeConfigPath, outDir, baseUrl, i18n, @@ -172,6 +177,25 @@ export default ${JSON.stringify(siteConfig, null, 2)}; `, ); + const themeConfigContent = themeConfigPath + ? `export {default} from '@site/${path.relative( + siteDir, + themeConfigPath, + )}';` + : // TODO Docusaurus v4: require theme config file, remove this fallback + `export default {};`; + const genThemeConfig = generate( + generatedFilesDir, + `${DEFAULT_THEME_FILE_NAME}.js`, + `/* + * AUTOGENERATED - DON'T EDIT + * Your edits in this file will be overwritten in the next build! + * Modify the docusaurus.config.js file at your site's root instead. + */ +${themeConfigContent} +`, + ); + const genClientModules = generate( generatedFilesDir, 'client-modules.js', @@ -236,6 +260,7 @@ ${Object.entries(registry) genWarning, genClientModules, genSiteConfig, + genThemeConfig, genRegistry, genRoutesChunkNames, genRoutes, @@ -248,6 +273,7 @@ ${Object.entries(registry) return { siteConfig, siteConfigPath, + themeConfigPath, siteMetadata, siteDir, outDir, diff --git a/website/docusaurus.config.ts b/website/docusaurus.config.ts index b3dca14db3ba..2ea5c93c8f97 100644 --- a/website/docusaurus.config.ts +++ b/website/docusaurus.config.ts @@ -12,7 +12,6 @@ import rehypeKatex from 'rehype-katex'; import configTabs from './src/remark/configTabs'; import versions from './versions.json'; -import VersionsArchived from './versionsArchived.json'; import { dogfoodingPluginInstances, dogfoodingThemeInstances, @@ -21,10 +20,6 @@ import { import ConfigLocalized from './docusaurus.config.localized.json'; -import PrismLight from './src/utils/prismLight'; -import PrismDark from './src/utils/prismDark'; - -import type {Config} from '@docusaurus/types'; import type * as Preset from '@docusaurus/preset-classic'; import type {Options as DocsOptions} from '@docusaurus/plugin-content-docs'; import type {Options as BlogOptions} from '@docusaurus/plugin-content-blog'; @@ -32,11 +27,6 @@ import type {Options as PageOptions} from '@docusaurus/plugin-content-pages'; import type {Options as IdealImageOptions} from '@docusaurus/plugin-ideal-image'; import type {Options as ClientRedirectsOptions} from '@docusaurus/plugin-client-redirects'; -const ArchivedVersionsDropdownItems = Object.entries(VersionsArchived).splice( - 0, - 5, -); - function isPrerelease(version: string) { return ( version.includes('alpha') || @@ -149,7 +139,7 @@ export default async function createConfigAsync() { [defaultLocale, 'fr', 'pt-BR', 'ko', 'zh-CN'], }, webpack: { - jsLoader: (isServer) => ({ + jsLoader: (isServer: boolean) => ({ loader: require.resolve('swc-loader'), options: { jsc: { @@ -176,7 +166,13 @@ export default async function createConfigAsync() { mdx1Compat: { // comments: false, }, - preprocessor: ({filePath, fileContent}) => { + preprocessor: ({ + filePath, + fileContent, + }: { + filePath: string; + fileContent: string; + }) => { let result = fileContent; result = result.replaceAll('{/_', '{/*'); @@ -263,7 +259,7 @@ export default async function createConfigAsync() { 'client-redirects', { fromExtensions: ['html'], - createRedirects(routePath) { + createRedirects(routePath: string) { // Redirect to /docs from /docs/introduction (now docs root doc) if (routePath === '/docs' || routePath === '/docs/') { return [`${routePath}/introduction`]; @@ -375,7 +371,7 @@ export default async function createConfigAsync() { sidebarPath: 'sidebars.ts', // sidebarCollapsible: false, // sidebarCollapsed: true, - editUrl: ({locale, docPath}) => { + editUrl: ({locale, docPath}: {locale: string; docPath: string}) => { if (locale !== defaultLocale) { return `https://crowdin.com/project/docusaurus-v2/${locale}`; } @@ -458,55 +454,7 @@ export default async function createConfigAsync() { } satisfies Preset.Options, ], ], - themeConfig: { - liveCodeBlock: { - playgroundPosition: 'bottom', - }, - docs: { - sidebar: { - hideable: true, - autoCollapseCategories: true, - }, - }, - colorMode: { - defaultMode: 'light', - disableSwitch: false, - respectPrefersColorScheme: true, - }, - announcementBar: { - id: 'announcementBar-3', // Increment on change - // content: `⭐️ If you like Docusaurus, give it a star on GitHub and follow us on Twitter ${TwitterSvg}`, - content: `🎉️ Docusaurus v3.0 is now out! 🥳️`, - }, - prism: { - additionalLanguages: [ - 'java', - 'latex', - 'haskell', - 'matlab', - 'PHp', - 'bash', - 'diff', - 'json', - 'scss', - ], - magicComments: [ - { - className: 'theme-code-block-highlighted-line', - line: 'highlight-next-line', - block: {start: 'highlight-start', end: 'highlight-end'}, - }, - { - className: 'code-block-error-line', - line: 'This will error', - }, - ], - theme: PrismLight, - darkTheme: PrismDark, - }, - image: 'img/docusaurus-social-card.jpg', - // metadata: [{name: 'twitter:card', content: 'summary'}], algolia: { appId: 'X1Z85QJPUV', apiKey: 'bf7211c161e8205da2f933a02534105a', @@ -519,207 +467,6 @@ export default async function createConfigAsync() { } : undefined, }, - navbar: { - hideOnScroll: true, - title: 'Docusaurus', - logo: { - alt: '', - src: 'img/docusaurus.svg', - srcDark: 'img/docusaurus_keytar.svg', - width: 32, - height: 32, - }, - items: [ - { - type: 'doc', - position: 'left', - docId: 'introduction', - label: 'Docs', - }, - { - type: 'docSidebar', - position: 'left', - sidebarId: 'api', - label: 'API', - }, - {to: 'blog', label: 'Blog', position: 'left'}, - {to: 'showcase', label: 'Showcase', position: 'left'}, - { - to: '/community/support', - label: 'Community', - position: 'left', - activeBaseRegex: `/community/`, - }, - // This item links to a draft doc: only displayed in dev - { - type: 'doc', - docId: 'index', - label: 'Tests', - docsPluginId: 'docs-tests', - }, - isDev && {to: '/__docusaurus/debug', label: 'Debug'}, - // Custom item for dogfooding: only displayed in /tests/ routes - { - type: 'custom-dogfood-navbar-item', - content: '😉', - }, - // Right - { - type: 'docsVersionDropdown', - position: 'right', - dropdownActiveClassDisabled: true, - dropdownItemsAfter: [ - { - type: 'html', - value: '', - }, - { - type: 'html', - className: 'dropdown-archived-versions', - value: 'Archived versions', - }, - ...ArchivedVersionsDropdownItems.map( - ([versionName, versionUrl]) => ({ - label: versionName, - href: versionUrl, - }), - ), - { - href: 'https://v1.docusaurus.io', - label: '1.x.x', - }, - { - type: 'html', - value: '', - }, - { - to: '/versions', - label: 'All versions', - }, - ], - }, - { - type: 'localeDropdown', - position: 'right', - dropdownItemsAfter: [ - { - type: 'html', - value: '
', - }, - { - href: 'https://github.com/facebook/docusaurus/issues/3526', - label: 'Help Us Translate', - }, - ], - }, - { - href: 'https://github.com/facebook/docusaurus', - position: 'right', - className: 'header-github-link', - 'aria-label': 'GitHub repository', - }, - ] - // TODO fix type - .filter(Boolean) as NonNullable< - Preset.ThemeConfig['navbar'] - >['items'], - }, - footer: { - style: 'dark', - links: [ - { - title: 'Learn', - items: [ - { - label: 'Introduction', - to: 'docs', - }, - { - label: 'Installation', - to: 'docs/installation', - }, - { - label: 'Migration from v1 to v2', - to: 'docs/migration', - }, - ], - }, - { - title: 'Community', - items: [ - { - label: 'Stack Overflow', - href: 'https://stackoverflow.com/questions/tagged/docusaurus', - }, - { - label: 'Feature Requests', - to: '/feature-requests', - }, - { - label: 'Discord', - href: 'https://discordapp.com/invite/docusaurus', - }, - { - label: 'Help', - to: '/community/support', - }, - ], - }, - { - title: 'More', - items: [ - { - label: 'Blog', - to: 'blog', - }, - { - label: 'Changelog', - to: '/changelog', - }, - { - label: 'GitHub', - href: 'https://github.com/facebook/docusaurus', - }, - { - label: 'Twitter', - href: 'https://twitter.com/docusaurus', - }, - { - html: ` - - Deploys by Netlify - - `, - }, - ], - }, - { - title: 'Legal', - // Please don't remove the privacy and terms, it's a legal - // requirement. - items: [ - { - label: 'Privacy', - href: 'https://opensource.facebook.com/legal/privacy/', - }, - { - label: 'Terms', - href: 'https://opensource.facebook.com/legal/terms/', - }, - { - label: 'Cookie Policy', - href: 'https://opensource.facebook.com/legal/cookie-policy/', - }, - ], - }, - ], - logo: { - alt: 'Meta Open Source Logo', - src: '/img/meta_opensource_logo_negative.svg', - href: 'https://opensource.fb.com', - }, - copyright: `Copyright © ${new Date().getFullYear()} Meta Platforms, Inc. Built with Docusaurus.`, - }, - } satisfies Preset.ThemeConfig, - } satisfies Config; + }, + }; } diff --git a/website/docusaurus.theme.tsx b/website/docusaurus.theme.tsx new file mode 100644 index 000000000000..e38f29cc126a --- /dev/null +++ b/website/docusaurus.theme.tsx @@ -0,0 +1,298 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import type {ReactNode} from 'react'; +import React from 'react'; +import Link from '@docusaurus/Link'; +import Translate from '@docusaurus/Translate'; +import VersionsArchived from './versionsArchived.json'; +import PrismLight from './src/utils/prismLight'; +import PrismDark from './src/utils/prismDark'; +import type * as Preset from '@docusaurus/preset-classic'; + +const ArchivedVersionsDropdownItems = Object.entries(VersionsArchived).splice( + 0, + 5, +); +const isDev = process.env.NODE_ENV === 'development'; +// const isDeployPreview = +// !!process.env.NETLIFY && process.env.CONTEXT === 'deploy-preview'; + +export default { + metadata: [{name: 'twitter:card', content: 'summary'}], + // algolia: { + // appId: 'X1Z85QJPUV', + // apiKey: 'bf7211c161e8205da2f933a02534105a', + // indexName: 'docusaurus-2', + // replaceSearchResultPathname: + // isDev || isDeployPreview + // ? { + // from: /^\/docs\/next/g.source, + // to: '/docs', + // } + // : undefined, + // }, + announcementBar: { + id: 'announcementBar-3', // Increment on change + content: function AnnouncementBarContent(): ReactNode { + return ( + + + TEST IT WORKS Docusaurus v3.0 + + ), + }}> + {'🎉 {link}, is now out! 🥳'} + + + ); + }, + }, + prism: { + additionalLanguages: [ + 'java', + 'latex', + 'haskell', + 'matlab', + 'PHp', + 'bash', + 'diff', + 'json', + 'scss', + ], + magicComments: [ + { + className: 'theme-code-block-highlighted-line', + line: 'highlight-next-line', + block: {start: 'highlight-start', end: 'highlight-end'}, + }, + { + className: 'code-block-error-line', + line: 'This will error', + }, + ], + theme: PrismLight, + darkTheme: PrismDark, + }, + liveCodeBlock: { + playgroundPosition: 'top', + }, + image: 'img/docusaurus-social-card.jpg', + docs: { + sidebar: { + hideable: true, + autoCollapseCategories: true, + }, + }, + colorMode: { + defaultMode: 'light', + disableSwitch: false, + respectPrefersColorScheme: true, + }, + + footer: { + style: 'dark', + links: [ + { + title: 'Learn', + items: [ + { + label: 'Introduction', + to: 'docs', + }, + { + label: 'Installation', + to: 'docs/installation', + }, + { + label: 'Migration from v1 to v2', + to: 'docs/migration', + }, + ], + }, + { + title: 'Community', + items: [ + { + label: 'Stack Overflow', + href: 'https://stackoverflow.com/questions/tagged/docusaurus', + }, + { + label: 'Feature Requests', + to: '/feature-requests', + }, + { + label: 'Discord', + href: 'https://discordapp.com/invite/docusaurus', + }, + { + label: 'Help', + to: '/community/support', + }, + ], + }, + { + title: 'More', + items: [ + { + label: 'Blog', + to: 'blog', + }, + { + label: 'Changelog', + to: '/changelog', + }, + { + label: 'GitHub', + href: 'https://github.com/facebook/docusaurus', + }, + { + label: 'Twitter', + href: 'https://twitter.com/docusaurus', + }, + { + html: ` + + Deploys by Netlify + + `, + }, + ], + }, + { + title: 'Legal', + // Please don't remove the privacy and terms, it's a legal + // requirement. + items: [ + { + label: 'Privacy', + href: 'https://opensource.facebook.com/legal/privacy/', + }, + { + label: 'Terms', + href: 'https://opensource.facebook.com/legal/terms/', + }, + { + label: 'Cookie Policy', + href: 'https://opensource.facebook.com/legal/cookie-policy/', + }, + ], + }, + ], + logo: { + alt: 'Meta Open Source Logo', + src: '/img/meta_opensource_logo_negative.svg', + href: 'https://opensource.fb.com', + }, + copyright: `Copyright © ${new Date().getFullYear()} Meta Platforms, Inc. Built with Docusaurus.`, + }, + navbar: { + hideOnScroll: true, + title: 'Docusaurus', + logo: { + alt: '', + src: 'img/docusaurus.svg', + srcDark: 'img/docusaurus_keytar.svg', + width: 32, + height: 32, + }, + items: [ + { + type: 'doc', + position: 'left', + docId: 'introduction', + label: 'Docs', + }, + { + type: 'docSidebar', + position: 'left', + sidebarId: 'api', + label: 'API', + }, + {to: 'blog', label: 'Blog', position: 'left'}, + {to: 'showcase', label: 'Showcase', position: 'left'}, + { + to: '/community/support', + label: 'Community', + position: 'left', + activeBaseRegex: `/community/`, + }, + // This item links to a draft doc: only displayed in dev + { + type: 'doc', + docId: 'index', + label: 'Tests', + docsPluginId: 'docs-tests', + }, + isDev && {to: '/__docusaurus/debug', label: 'Debug'}, + // Custom item for dogfooding: only displayed in /tests/ routes + { + type: 'custom-dogfood-navbar-item', + content: '😉', + }, + // Right + { + type: 'docsVersionDropdown', + position: 'right', + dropdownActiveClassDisabled: true, + dropdownItemsAfter: [ + { + type: 'html', + value: '', + }, + { + type: 'html', + className: 'dropdown-archived-versions', + value: 'Archived versions', + }, + ...ArchivedVersionsDropdownItems.map(([versionName, versionUrl]) => ({ + label: versionName, + href: versionUrl, + })), + { + href: 'https://v1.docusaurus.io', + label: '1.x.x', + }, + { + type: 'html', + value: '', + }, + { + to: '/versions', + label: 'All versions', + }, + ], + dropdownItemsBefore: [], + }, + { + type: 'localeDropdown', + position: 'right', + dropdownItemsAfter: [ + { + type: 'html', + value: '
', + }, + { + href: 'https://github.com/facebook/docusaurus/issues/3526', + label: 'Help Us Translate', + }, + ], + dropdownItemsBefore: [], + }, + { + href: 'https://github.com/facebook/docusaurus', + position: 'right', + className: 'header-github-link', + 'aria-label': 'GitHub repository', + }, + ] + // TODO fix type + .filter(Boolean) as NonNullable['items'], + }, +}; diff --git a/website/src/utils/prismDark.ts b/website/src/utils/prismDark.ts index 5bbfdfb0af84..fdcc7fd1ead9 100644 --- a/website/src/utils/prismDark.ts +++ b/website/src/utils/prismDark.ts @@ -5,7 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -import {themes, type PrismTheme} from 'prism-react-renderer'; +import {themes} from 'prism-react-renderer'; + +// TODO satisfies cause an error const baseTheme = themes.vsDark; @@ -78,4 +80,4 @@ export default { }, }, ], -} satisfies PrismTheme; +}; diff --git a/website/src/utils/prismLight.ts b/website/src/utils/prismLight.ts index 76bf2caa372c..ad1acea61d38 100644 --- a/website/src/utils/prismLight.ts +++ b/website/src/utils/prismLight.ts @@ -5,7 +5,9 @@ * LICENSE file in the root directory of this source tree. */ -import {themes, type PrismTheme} from 'prism-react-renderer'; +import {themes} from 'prism-react-renderer'; + +// TODO satisfies cause an error const baseTheme = themes.github; @@ -99,4 +101,4 @@ export default { }, }, ], -} satisfies PrismTheme; +};