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: `
-
-
-
- `,
- },
- ],
- },
- {
- 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: `
+
+
+
+ `,
+ },
+ ],
+ },
+ {
+ 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;
+};