chore: backport retro compatible commits for the Docusaurus v2.4 release (#8809)

Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
Co-authored-by: Ben Gubler <nebrelbug@gmail.com>
Co-authored-by: Davide Donadio <davide.donadio@it.clara.net>
Co-authored-by: Petter Drønnen <36735557+dr0nn1@users.noreply.github.com>
Co-authored-by: Moritz Stückler <moritz@bitbetter.de>
Co-authored-by: Mysterious_Dev <40738104+Mysterious-Dev@users.noreply.github.com>
Co-authored-by: TrueQAP <32407751+trueqap@users.noreply.github.com>
Co-authored-by: Kagan <34136752+kagankan@users.noreply.github.com>
Co-authored-by: Dewansh Thakur <71703033+dewanshDT@users.noreply.github.com>
Co-authored-by: Armano <armano2@users.noreply.github.com>
Co-authored-by: Anas <60762285+Anasqx@users.noreply.github.com>
Co-authored-by: Tanner Dolby <tannercdolby@gmail.com>
Co-authored-by: Davide Donadio <davide.donadio94@gmail.com>
Co-authored-by: biplavmz <68702055+biplavmz@users.noreply.github.com>
Co-authored-by: Vishruta Patil <72292532+Vishruta-Patil@users.noreply.github.com>
fix(theme-classic): fix tab focus bug in dropdown (#8697) (#8699)
fix(theme): improve color toggle when using dark navbar (#8615)
fix(theme-translations): fix wrong arabic words (tip/next) (#8744)
fix(core): baseUrl error banner link anchor case (#8746)
fix(search): search page should react to querystring changes + cleanup/refactor (#8757)
fix(theme): allow tabs children to be falsy (#8801)
fix(theme): codeblock buttons should be kept on the right when using RTL locale (#8803)
This commit is contained in:
Sébastien Lorber 2023-03-24 09:23:58 +01:00 committed by GitHub
parent 985a64ad22
commit 4fb67ef11b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
122 changed files with 1732 additions and 494 deletions

View file

@ -28,6 +28,7 @@
"__snapshots__",
"website/src/data/users.tsx",
"website/src/data/tweets.tsx",
"website/docusaurus.config.localized.json",
"*.xyz",
"*.docx",
"versioned_docs",

View file

@ -1,6 +1,6 @@
{
"name": "new.docusaurus.io",
"version": "2.3.1",
"version": "2.4.0",
"private": true,
"scripts": {
"start": "npx --package netlify-cli netlify dev"

View file

@ -1,5 +1,5 @@
{
"version": "2.3.1",
"version": "2.4.0",
"npmClient": "yarn",
"useWorkspaces": true,
"changelog": {

View file

@ -1,6 +1,6 @@
{
"name": "create-docusaurus",
"version": "2.3.1",
"version": "2.4.0",
"description": "Create Docusaurus apps easily.",
"type": "module",
"repository": {
@ -22,8 +22,8 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/logger": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/logger": "2.4.0",
"@docusaurus/utils": "2.4.0",
"commander": "^5.1.0",
"fs-extra": "^10.1.0",
"lodash": "^4.17.21",

View file

@ -1,6 +1,6 @@
{
"name": "docusaurus-2-classic-typescript-template",
"version": "2.3.1",
"version": "2.4.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
@ -15,8 +15,8 @@
"typecheck": "tsc"
},
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/preset-classic": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/preset-classic": "2.4.0",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
@ -24,7 +24,7 @@
"react-dom": "^17.0.2"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/module-type-aliases": "2.4.0",
"@tsconfig/docusaurus": "^1.0.5",
"typescript": "^4.7.4"
},

View file

@ -71,8 +71,8 @@ const config = {
},
items: [
{
type: 'doc',
docId: 'intro',
type: 'docSidebar',
sidebarId: 'tutorialSidebar',
position: 'left',
label: 'Tutorial',
},

View file

@ -1,6 +1,6 @@
{
"name": "docusaurus-2-classic-template",
"version": "2.3.1",
"version": "2.4.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
@ -14,8 +14,8 @@
"write-heading-ids": "docusaurus write-heading-ids"
},
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/preset-classic": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/preset-classic": "2.4.0",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"prism-react-renderer": "^1.3.5",
@ -23,7 +23,7 @@
"react-dom": "^17.0.2"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.3.1"
"@docusaurus/module-type-aliases": "2.4.0"
},
"browserslist": {
"production": [

View file

@ -67,8 +67,8 @@ const config = {
},
items: [
{
type: 'doc',
docId: 'intro',
type: 'docSidebar',
sidebarId: 'tutorialSidebar',
position: 'left',
label: 'Tutorial',
},

View file

@ -1,6 +1,6 @@
{
"name": "docusaurus-2-facebook-template",
"version": "2.3.1",
"version": "2.4.0",
"private": true,
"scripts": {
"docusaurus": "docusaurus",
@ -18,8 +18,8 @@
"format:diff": "prettier --config .prettierrc --list-different \"**/*.{js,jsx,ts,tsx,md,mdx}\""
},
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/preset-classic": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/preset-classic": "2.4.0",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"react": "^17.0.2",

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/cssnano-preset",
"version": "2.3.1",
"version": "2.4.0",
"description": "Advanced cssnano preset for maximum optimization.",
"main": "lib/index.js",
"license": "MIT",

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/logger",
"version": "2.3.1",
"version": "2.4.0",
"description": "An encapsulated logger for semantically formatting console messages.",
"main": "./lib/index.js",
"repository": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/mdx-loader",
"version": "2.3.1",
"version": "2.4.0",
"description": "Docusaurus Loader for MDX",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -20,8 +20,8 @@
"dependencies": {
"@babel/parser": "^7.18.8",
"@babel/traverse": "^7.18.8",
"@docusaurus/logger": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/logger": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@mdx-js/mdx": "^1.6.22",
"escape-html": "^1.0.3",
"file-loader": "^6.2.0",
@ -37,7 +37,7 @@
"webpack": "^5.73.0"
},
"devDependencies": {
"@docusaurus/types": "2.3.1",
"@docusaurus/types": "2.4.0",
"@types/escape-html": "^1.0.2",
"@types/mdast": "^3.0.10",
"@types/stringify-object": "^3.3.1",

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/migrate",
"version": "2.3.1",
"version": "2.4.0",
"description": "A CLI tool to migrate from older versions of Docusaurus.",
"license": "MIT",
"engines": {
@ -24,8 +24,8 @@
"dependencies": {
"@babel/core": "^7.18.6",
"@babel/preset-env": "^7.18.6",
"@docusaurus/logger": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/logger": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@mapbox/hast-util-to-jsx": "^2.0.0",
"color": "^4.2.3",
"commander": "^5.1.0",

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/module-type-aliases",
"version": "2.3.1",
"version": "2.4.0",
"description": "Docusaurus module type aliases.",
"types": "./src/index.d.ts",
"publishConfig": {
@ -13,7 +13,7 @@
},
"dependencies": {
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/types": "2.3.1",
"@docusaurus/types": "2.4.0",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-client-redirects",
"version": "2.3.1",
"version": "2.4.0",
"description": "Client redirects plugin for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -18,18 +18,18 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/logger": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-common": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/logger": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-common": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"eta": "^2.0.0",
"fs-extra": "^10.1.0",
"lodash": "^4.17.21",
"tslib": "^2.4.0"
},
"devDependencies": {
"@docusaurus/types": "2.3.1"
"@docusaurus/types": "2.4.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-content-blog",
"version": "2.3.1",
"version": "2.4.0",
"description": "Blog plugin for Docusaurus.",
"main": "lib/index.js",
"types": "src/plugin-content-blog.d.ts",
@ -18,13 +18,13 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/logger": "2.3.1",
"@docusaurus/mdx-loader": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-common": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/logger": "2.4.0",
"@docusaurus/mdx-loader": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-common": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"cheerio": "^1.0.0-rc.12",
"feed": "^4.2.2",
"fs-extra": "^10.1.0",

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-content-docs",
"version": "2.3.1",
"version": "2.4.0",
"description": "Docs plugin for Docusaurus.",
"main": "lib/index.js",
"sideEffects": false,
@ -35,13 +35,13 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/logger": "2.3.1",
"@docusaurus/mdx-loader": "2.3.1",
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/logger": "2.4.0",
"@docusaurus/mdx-loader": "2.4.0",
"@docusaurus/module-type-aliases": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"@types/react-router-config": "^5.0.6",
"combine-promises": "^1.1.0",
"fs-extra": "^10.1.0",

View file

@ -45,6 +45,7 @@ export type SidebarItemLink = SidebarItemBase & {
href: string;
label: string;
autoAddBaseUrl?: boolean;
description?: string;
};
export type SidebarItemAutogenerated = SidebarItemBase & {
@ -57,6 +58,7 @@ type SidebarItemCategoryBase = SidebarItemBase & {
label: string;
collapsed: boolean;
collapsible: boolean;
description?: string;
};
export type SidebarItemCategoryLinkDoc = {type: 'doc'; id: string};

View file

@ -63,6 +63,9 @@ const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
label: Joi.string()
.required()
.messages({'any.unknown': '"label" must be a string'}),
description: Joi.string().optional().messages({
'any.unknown': '"description" must be a string',
}),
});
const sidebarItemCategoryLinkSchema = Joi.object<SidebarItemCategoryLink>()
@ -116,6 +119,9 @@ const sidebarItemCategorySchema =
collapsible: Joi.boolean().messages({
'any.unknown': '"collapsible" must be a boolean',
}),
description: Joi.string().optional().messages({
'any.unknown': '"description" must be a string',
}),
});
const sidebarItemSchema = Joi.object<SidebarItemConfig>().when('.type', {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-content-pages",
"version": "2.3.1",
"version": "2.4.0",
"description": "Pages plugin for Docusaurus.",
"main": "lib/index.js",
"types": "src/plugin-content-pages.d.ts",
@ -18,11 +18,11 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/mdx-loader": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/mdx-loader": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"fs-extra": "^10.1.0",
"tslib": "^2.4.0",
"webpack": "^5.73.0"

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-debug",
"version": "2.3.1",
"version": "2.4.0",
"description": "Debug plugin for Docusaurus.",
"main": "lib/index.js",
"types": "src/plugin-debug.d.ts",
@ -20,9 +20,9 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils": "2.4.0",
"fs-extra": "^10.1.0",
"react-json-view": "^1.21.3",
"tslib": "^2.4.0"

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-google-analytics",
"version": "2.3.1",
"version": "2.4.0",
"description": "Global analytics (analytics.js) plugin for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -18,9 +18,9 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"tslib": "^2.4.0"
},
"peerDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-google-gtag",
"version": "2.3.1",
"version": "2.4.0",
"description": "Global Site Tag (gtag.js) plugin for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -18,9 +18,9 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"tslib": "^2.4.0"
},
"peerDependencies": {

View file

@ -0,0 +1,156 @@
/**
* 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 {normalizePluginOptions} from '@docusaurus/utils-validation';
import {
validateOptions,
type PluginOptions,
type Options,
DEFAULT_OPTIONS,
} from '../options';
import type {Validate} from '@docusaurus/types';
function testValidateOptions(options: Options) {
return validateOptions({
validate: normalizePluginOptions as Validate<Options, PluginOptions>,
options,
});
}
function validationResult(options: Options) {
return {
id: 'default',
...DEFAULT_OPTIONS,
...options,
trackingID:
typeof options.trackingID === 'string'
? [options.trackingID]
: options.trackingID,
};
}
const MinimalConfig: Options = {
trackingID: 'G-XYZ12345',
};
describe('validateOptions', () => {
it('throws for undefined options', () => {
expect(
// @ts-expect-error: TS should error
() => testValidateOptions(undefined),
).toThrowErrorMatchingInlineSnapshot(`""trackingID" is required"`);
});
it('throws for null options', () => {
expect(
// @ts-expect-error: TS should error
() => testValidateOptions(null),
).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`);
});
it('throws for empty object options', () => {
expect(
// @ts-expect-error: TS should error
() => testValidateOptions({}),
).toThrowErrorMatchingInlineSnapshot(`""trackingID" is required"`);
});
it('throws for number options', () => {
expect(
// @ts-expect-error: TS should error
() => testValidateOptions(42),
).toThrowErrorMatchingInlineSnapshot(`""value" must be of type object"`);
});
it('throws for null trackingID', () => {
expect(
// @ts-expect-error: TS should error
() => testValidateOptions({trackingID: null}),
).toThrowErrorMatchingInlineSnapshot(
`""trackingID" does not match any of the allowed types"`,
);
});
it('throws for number trackingID', () => {
expect(
// @ts-expect-error: TS should error
() => testValidateOptions({trackingID: 42}),
).toThrowErrorMatchingInlineSnapshot(
`""trackingID" does not match any of the allowed types"`,
);
});
it('throws for empty trackingID', () => {
expect(() =>
testValidateOptions({trackingID: ''}),
).toThrowErrorMatchingInlineSnapshot(
`""trackingID" does not match any of the allowed types"`,
);
});
it('accepts minimal config', () => {
expect(testValidateOptions(MinimalConfig)).toEqual(
validationResult(MinimalConfig),
);
});
it('accepts anonymizeIP', () => {
const config: Options = {
...MinimalConfig,
anonymizeIP: true,
};
expect(testValidateOptions(config)).toEqual(validationResult(config));
});
it('accepts single trackingID', () => {
const config: Options = {
trackingID: 'G-ABCDEF123',
};
expect(testValidateOptions(config)).toEqual(validationResult(config));
});
it('accepts multiple trackingIDs', () => {
const config: Options = {
trackingID: ['G-ABCDEF123', 'UA-XYZ456789'],
};
expect(testValidateOptions(config)).toEqual(validationResult(config));
});
it('throws for empty trackingID arrays', () => {
const config: Options = {
// @ts-expect-error: TS should error
trackingID: [],
};
expect(() =>
testValidateOptions(config),
).toThrowErrorMatchingInlineSnapshot(
`""trackingID" does not match any of the allowed types"`,
);
});
it('throws for sparse trackingID arrays', () => {
const config: Options = {
// @ts-expect-error: TS should error
trackingID: ['G-ABCDEF123', null, 'UA-XYZ456789'],
};
expect(() =>
testValidateOptions(config),
).toThrowErrorMatchingInlineSnapshot(
`""trackingID" does not match any of the allowed types"`,
);
});
it('throws for bad trackingID arrays', () => {
const config: Options = {
// @ts-expect-error: TS should error
trackingID: ['G-ABCDEF123', 42],
};
expect(() =>
testValidateOptions(config),
).toThrowErrorMatchingInlineSnapshot(
`""trackingID" does not match any of the allowed types"`,
);
});
});

View file

@ -5,23 +5,38 @@
* LICENSE file in the root directory of this source tree.
*/
import {Joi} from '@docusaurus/utils-validation';
import type {
LoadContext,
Plugin,
OptionValidationContext,
ThemeConfig,
ThemeConfigValidationContext,
} from '@docusaurus/types';
import type {LoadContext, Plugin} from '@docusaurus/types';
import type {PluginOptions, Options} from './options';
function createConfigSnippet({
trackingID,
anonymizeIP,
}: {
trackingID: string;
anonymizeIP: boolean;
}): string {
return `gtag('config', '${trackingID}', { ${
anonymizeIP ? "'anonymize_ip': true" : ''
} });`;
}
function createConfigSnippets({
trackingID: trackingIDArray,
anonymizeIP,
}: PluginOptions): string {
return trackingIDArray
.map((trackingID) => createConfigSnippet({trackingID, anonymizeIP}))
.join('\n');
}
export default function pluginGoogleGtag(
context: LoadContext,
options: PluginOptions,
): Plugin {
const {anonymizeIP, trackingID} = options;
const isProd = process.env.NODE_ENV === 'production';
const firstTrackingId = options.trackingID[0];
return {
name: 'docusaurus-plugin-google-gtag',
@ -60,7 +75,11 @@ export default function pluginGoogleGtag(
tagName: 'script',
attributes: {
async: true,
src: `https://www.googletagmanager.com/gtag/js?id=${trackingID}`,
// We only include the first tracking id here because google says
// we shouldn't install multiple tags/scripts on the same page
// Instead we should load one script and use n * gtag("config",id)
// See https://developers.google.com/tag-platform/gtagjs/install#add-products
src: `https://www.googletagmanager.com/gtag/js?id=${firstTrackingId}`,
},
},
{
@ -69,9 +88,8 @@ export default function pluginGoogleGtag(
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '${trackingID}', { ${
anonymizeIP ? "'anonymize_ip': true" : ''
} });`,
${createConfigSnippets(options)};
`,
},
],
};
@ -79,27 +97,6 @@ export default function pluginGoogleGtag(
};
}
const pluginOptionsSchema = Joi.object<PluginOptions>({
trackingID: Joi.string().required(),
anonymizeIP: Joi.boolean().default(false),
});
export function validateOptions({
validate,
options,
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
return validate(pluginOptionsSchema, options);
}
export function validateThemeConfig({
themeConfig,
}: ThemeConfigValidationContext<ThemeConfig>): ThemeConfig {
if ('gtag' in themeConfig) {
throw new Error(
'The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.',
);
}
return themeConfig;
}
export {validateThemeConfig, validateOptions} from './options';
export type {PluginOptions, Options};

View file

@ -4,10 +4,58 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {Joi} from '@docusaurus/utils-validation';
import type {
OptionValidationContext,
ThemeConfig,
ThemeConfigValidationContext,
} from '@docusaurus/types';
export type PluginOptions = {
trackingID: string;
trackingID: [string, ...string[]];
// TODO deprecate anonymizeIP after June 2023
// "In Google Analytics 4, IP masking is not necessary
// since IP addresses are not logged or stored."
// https://support.google.com/analytics/answer/2763052?hl=en
anonymizeIP: boolean;
};
export type Options = Partial<PluginOptions>;
export type Options = {
trackingID: string | [string, ...string[]];
anonymizeIP?: boolean;
};
export const DEFAULT_OPTIONS: Partial<PluginOptions> = {
anonymizeIP: false,
};
const pluginOptionsSchema = Joi.object<PluginOptions>({
// We normalize trackingID as a string[]
trackingID: Joi.alternatives()
.try(
Joi.alternatives().conditional(Joi.string().required(), {
then: Joi.custom((val: boolean) => [val]),
}),
Joi.array().items(Joi.string().required()),
)
.required(),
anonymizeIP: Joi.boolean().default(DEFAULT_OPTIONS.anonymizeIP),
});
export function validateOptions({
validate,
options,
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
return validate(pluginOptionsSchema, options);
}
export function validateThemeConfig({
themeConfig,
}: ThemeConfigValidationContext<ThemeConfig>): ThemeConfig {
if ('gtag' in themeConfig) {
throw new Error(
'The "gtag" field in themeConfig should now be specified as option for plugin-google-gtag. More information at https://github.com/facebook/docusaurus/pull/5832.',
);
}
return themeConfig;
}

View file

@ -10,6 +10,6 @@
"rootDir": "src",
"outDir": "lib"
},
"include": ["src/gtag.ts", "src/options.ts", "src/*.d.ts"],
"include": ["src/gtag.ts", "src/*.d.ts"],
"exclude": ["**/__tests__/**"]
}

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-google-tag-manager",
"version": "2.3.1",
"version": "2.4.0",
"description": "Google Tag Manager (gtm.js) plugin for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -18,9 +18,9 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"tslib": "^2.4.0"
},
"peerDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-ideal-image",
"version": "2.3.1",
"version": "2.4.0",
"description": "Docusaurus Plugin to generate an almost ideal image (responsive, lazy-loading, and low quality placeholder).",
"main": "lib/index.js",
"types": "src/plugin-ideal-image.d.ts",
@ -20,12 +20,12 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/lqip-loader": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/lqip-loader": "2.4.0",
"@docusaurus/responsive-loader": "^1.7.0",
"@docusaurus/theme-translations": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/theme-translations": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"@endiliey/react-ideal-image": "^0.0.11",
"react-waypoint": "^10.3.0",
"sharp": "^0.30.7",
@ -33,7 +33,7 @@
"webpack": "^5.73.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/module-type-aliases": "2.4.0",
"fs-extra": "^10.1.0"
},
"peerDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-pwa",
"version": "2.3.1",
"version": "2.4.0",
"description": "Docusaurus Plugin to add PWA support.",
"main": "lib/index.js",
"types": "src/plugin-pwa.d.ts",
@ -22,12 +22,12 @@
"dependencies": {
"@babel/core": "^7.18.6",
"@babel/preset-env": "^7.18.6",
"@docusaurus/core": "2.3.1",
"@docusaurus/theme-common": "2.3.1",
"@docusaurus/theme-translations": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/theme-common": "2.4.0",
"@docusaurus/theme-translations": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"babel-loader": "^8.2.5",
"clsx": "^1.2.1",
"core-js": "^3.23.3",
@ -40,7 +40,7 @@
"workbox-window": "^6.5.3"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/module-type-aliases": "2.4.0",
"fs-extra": "^10.1.0"
},
"peerDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/plugin-sitemap",
"version": "2.3.1",
"version": "2.4.0",
"description": "Simple sitemap generation plugin for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -18,12 +18,12 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/logger": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-common": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/logger": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-common": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"fs-extra": "^10.1.0",
"sitemap": "^7.1.1",
"tslib": "^2.4.0"

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/preset-classic",
"version": "2.3.1",
"version": "2.4.0",
"description": "Classic preset for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -18,19 +18,19 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/plugin-content-blog": "2.3.1",
"@docusaurus/plugin-content-docs": "2.3.1",
"@docusaurus/plugin-content-pages": "2.3.1",
"@docusaurus/plugin-debug": "2.3.1",
"@docusaurus/plugin-google-analytics": "2.3.1",
"@docusaurus/plugin-google-gtag": "2.3.1",
"@docusaurus/plugin-google-tag-manager": "2.3.1",
"@docusaurus/plugin-sitemap": "2.3.1",
"@docusaurus/theme-classic": "2.3.1",
"@docusaurus/theme-common": "2.3.1",
"@docusaurus/theme-search-algolia": "2.3.1",
"@docusaurus/types": "2.3.1"
"@docusaurus/core": "2.4.0",
"@docusaurus/plugin-content-blog": "2.4.0",
"@docusaurus/plugin-content-docs": "2.4.0",
"@docusaurus/plugin-content-pages": "2.4.0",
"@docusaurus/plugin-debug": "2.4.0",
"@docusaurus/plugin-google-analytics": "2.4.0",
"@docusaurus/plugin-google-gtag": "2.4.0",
"@docusaurus/plugin-google-tag-manager": "2.4.0",
"@docusaurus/plugin-sitemap": "2.4.0",
"@docusaurus/theme-classic": "2.4.0",
"@docusaurus/theme-common": "2.4.0",
"@docusaurus/theme-search-algolia": "2.4.0",
"@docusaurus/types": "2.4.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",

View file

@ -63,3 +63,30 @@ module.exports = {
| Property | Type | Default | Description |
| --- | --- | --- | --- |
| `sync` | `boolean` | `false` | Syncing tab choices (Yarn and npm). See https://docusaurus.io/docs/markdown-features/#syncing-tab-choices for details. |
| `converters` | `array` | `'yarn'`, `'pnpm'` | The list of converters to use. The order of the converters is important, as the first converter will be used as the default choice. |
## Custom converters
In case you want to convert npm commands to something else than `yarn` or `pnpm`, you can use custom converters:
```ts
type CustomConverter = [name: string, cb: (npmCode: string) => string];
```
```ts
{
remarkPlugins: [
[
require('@docusaurus/remark-plugin-npm2yarn'),
{
sync: true,
converters: [
'yarn',
'pnpm',
['Turbo', (code) => code.replace(/npm/g, 'turbo')],
],
},
],
];
}
```

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/remark-plugin-npm2yarn",
"version": "2.3.1",
"version": "2.4.0",
"description": "Remark plugin for converting npm commands to Yarn commands as tabs.",
"main": "lib/index.js",
"publishConfig": {
@ -17,8 +17,8 @@
},
"license": "MIT",
"dependencies": {
"npm-to-yarn": "^1.0.1",
"tslib": "^2.4.0",
"npm-to-yarn": "^2.0.0",
"tslib": "^2.4.1",
"unist-util-visit": "^2.0.3"
},
"devDependencies": {

View file

@ -0,0 +1,16 @@
```bash npm2yarn
npm run xxx -- --arg
```
```bash npm2yarn
npm install package
```
```bash npm2yarn
npm remove package-name
```
```bash npm2yarn
npm init docusaurus
npm init docusaurus@latest my-website classic
```

View file

@ -6,6 +6,7 @@ exports[`npm2yarn plugin does not re-import tabs components when already importe
import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="npm">
\`\`\`bash
@ -13,19 +14,30 @@ import TabItem from '@theme/TabItem';
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
$ yarn add --global docusaurus
$ yarn global add docusaurus
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
$ pnpm add --global docusaurus
\`\`\`
</TabItem>
</Tabs>
"
`;
exports[`npm2yarn plugin does not re-import tabs components when already imported below 1`] = `
"<Tabs>
<TabItem value="npm">
\`\`\`bash
@ -33,13 +45,23 @@ exports[`npm2yarn plugin does not re-import tabs components when already importe
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
$ yarn add --global docusaurus
$ yarn global add docusaurus
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
$ pnpm add --global docusaurus
\`\`\`
</TabItem>
</Tabs>
import Tabs from '@theme/Tabs';
@ -63,11 +85,102 @@ npm install --save docusaurus-plugin-name
"
`;
exports[`npm2yarn plugin work with custom converter 1`] = `
"import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Installing a plugin
A plugin is usually a npm package, so you install them like other npm packages using npm.
<Tabs>
<TabItem value="npm">
\`\`\`bash
npm install --save docusaurus-plugin-name
\`\`\`
</TabItem>
<TabItem value="Turbo">
\`\`\`bash
turbo install --save docusaurus-plugin-name
\`\`\`
</TabItem>
</Tabs>
"
`;
exports[`npm2yarn plugin work with pnpm converter 1`] = `
"import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Installing a plugin
A plugin is usually a npm package, so you install them like other npm packages using npm.
<Tabs>
<TabItem value="npm">
\`\`\`bash
npm install --save docusaurus-plugin-name
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
pnpm add docusaurus-plugin-name
\`\`\`
</TabItem>
</Tabs>
"
`;
exports[`npm2yarn plugin work with yarn converter 1`] = `
"import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
## Installing a plugin
A plugin is usually a npm package, so you install them like other npm packages using npm.
<Tabs>
<TabItem value="npm">
\`\`\`bash
npm install --save docusaurus-plugin-name
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
yarn add docusaurus-plugin-name
\`\`\`
</TabItem>
</Tabs>
"
`;
exports[`npm2yarn plugin works on installation file 1`] = `
"import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs>
<TabItem value="npm">
\`\`\`bash
@ -75,13 +188,23 @@ import TabItem from '@theme/TabItem';
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
$ yarn add --global docusaurus
$ yarn global add docusaurus
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
$ pnpm add --global docusaurus
\`\`\`
</TabItem>
</Tabs>
"
`;
@ -95,6 +218,7 @@ import TabItem from '@theme/TabItem';
A plugin is usually a npm package, so you install them like other npm packages using npm.
<Tabs>
<TabItem value="npm">
\`\`\`bash
@ -102,6 +226,7 @@ npm install --save docusaurus-plugin-name
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
@ -109,6 +234,136 @@ yarn add docusaurus-plugin-name
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
pnpm add docusaurus-plugin-name
\`\`\`
</TabItem>
</Tabs>
"
`;
exports[`npm2yarn plugin works with common commands 1`] = `
"import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';
<Tabs groupId="npm2yarn">
<TabItem value="npm">
\`\`\`bash
npm run xxx -- --arg
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
yarn xxx --arg
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
pnpm run xxx -- --arg
\`\`\`
</TabItem>
</Tabs>
<Tabs groupId="npm2yarn">
<TabItem value="npm">
\`\`\`bash
npm install package
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
yarn add package
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
pnpm add package
\`\`\`
</TabItem>
</Tabs>
<Tabs groupId="npm2yarn">
<TabItem value="npm">
\`\`\`bash
npm remove package-name
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
yarn remove package-name
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
pnpm remove package-name
\`\`\`
</TabItem>
</Tabs>
<Tabs groupId="npm2yarn">
<TabItem value="npm">
\`\`\`bash
npm init docusaurus
npm init docusaurus@latest my-website classic
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
yarn create docusaurus
yarn create docusaurus@latest my-website classic
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
pnpm create docusaurus
pnpm create docusaurus@latest my-website classic
\`\`\`
</TabItem>
</Tabs>
"
`;
@ -122,6 +377,7 @@ import TabItem from '@theme/TabItem';
A plugin is usually a npm package, so you install them like other npm packages using npm.
<Tabs groupId="npm2yarn">
<TabItem value="npm">
\`\`\`bash
@ -129,6 +385,7 @@ npm install --save docusaurus-plugin-name
\`\`\`
</TabItem>
<TabItem value="yarn" label="Yarn">
\`\`\`bash
@ -136,6 +393,15 @@ yarn add docusaurus-plugin-name
\`\`\`
</TabItem>
<TabItem value="pnpm" label="pnpm">
\`\`\`bash
pnpm add docusaurus-plugin-name
\`\`\`
</TabItem>
</Tabs>
"
`;

View file

@ -11,7 +11,10 @@ import mdx from 'remark-mdx';
import remark from 'remark';
import npm2yarn from '../index';
const processFixture = async (name: string, options?: {sync?: boolean}) => {
const processFixture = async (
name: string,
options?: Parameters<typeof npm2yarn>[0],
) => {
const filePath = path.join(__dirname, '__fixtures__', `${name}.md`);
const file = await vfile.read(filePath);
const result = await remark().use(mdx).use(npm2yarn, options).process(file);
@ -32,6 +35,12 @@ describe('npm2yarn plugin', () => {
expect(result).toMatchSnapshot();
});
it('works with common commands', async () => {
const result = await processFixture('conversion-test', {sync: true});
expect(result).toMatchSnapshot();
});
it('works with sync option', async () => {
const result = await processFixture('plugin', {sync: true});
@ -55,4 +64,24 @@ describe('npm2yarn plugin', () => {
expect(result).toMatchSnapshot();
});
it('work with yarn converter', async () => {
const result = await processFixture('plugin', {converters: ['yarn']});
expect(result).toMatchSnapshot();
});
it('work with pnpm converter', async () => {
const result = await processFixture('plugin', {converters: ['pnpm']});
expect(result).toMatchSnapshot();
});
it('work with custom converter', async () => {
const result = await processFixture('plugin', {
converters: [['Turbo', (code) => code.replace(/npm/g, 'turbo')]],
});
expect(result).toMatchSnapshot();
});
});

View file

@ -11,39 +11,62 @@ import type {Code, Content, Literal} from 'mdast';
import type {Plugin} from 'unified';
import type {Node, Parent} from 'unist';
type CustomConverter = [name: string, cb: (npmCode: string) => string];
type PluginOptions = {
sync?: boolean;
converters?: (CustomConverter | 'yarn' | 'pnpm')[];
};
// E.g. global install: 'npm i' -> 'yarn'
const convertNpmToYarn = (npmCode: string) => npmToYarn(npmCode, 'yarn');
const transformNode = (node: Code, isSync: boolean) => {
const groupIdProp = isSync ? ' groupId="npm2yarn"' : '';
const npmCode = node.value;
const yarnCode = convertNpmToYarn(node.value);
function createTabItem(
code: string,
node: Code,
value: string,
label?: string,
) {
return [
{
type: 'jsx',
value: `<Tabs${groupIdProp}>\n<TabItem value="npm">`,
value: `<TabItem value="${value}"${label ? ` label="${label}"` : ''}>`,
},
{
type: node.type,
lang: node.lang,
value: npmCode,
value: code,
},
{
type: 'jsx',
value: '</TabItem>\n<TabItem value="yarn" label="Yarn">',
},
{
type: node.type,
lang: node.lang,
value: yarnCode,
value: '</TabItem>',
},
] as Content[];
}
const transformNode = (
node: Code,
isSync: boolean,
converters: (CustomConverter | 'yarn' | 'pnpm')[],
) => {
const groupIdProp = isSync ? ' groupId="npm2yarn"' : '';
const npmCode = node.value;
return [
{
type: 'jsx',
value: '</TabItem>\n</Tabs>',
value: `<Tabs${groupIdProp}>`,
},
...createTabItem(npmCode, node, 'npm'),
...converters.flatMap((converter) =>
typeof converter === 'string'
? createTabItem(
npmToYarn(npmCode, converter),
node,
converter,
converter === 'yarn' ? 'Yarn' : converter,
)
: createTabItem(converter[1](npmCode), node, converter[0]),
),
{
type: 'jsx',
value: '</Tabs>',
},
] as Content[];
};
@ -60,7 +83,7 @@ const nodeForImport: Literal = {
};
const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
const {sync = false} = options;
const {sync = false, converters = ['yarn', 'pnpm']} = options;
return (root) => {
let transformed = false as boolean;
let alreadyImported = false as boolean;
@ -73,7 +96,7 @@ const plugin: Plugin<[PluginOptions?]> = (options = {}) => {
while (index < node.children.length) {
const child = node.children[index]!;
if (matchNode(child)) {
const result = transformNode(child, sync);
const result = transformNode(child, sync, converters);
node.children.splice(index, 1, ...result);
index += result.length;
transformed = true;

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/theme-classic",
"version": "2.3.1",
"version": "2.4.0",
"description": "Classic theme for Docusaurus",
"main": "lib/index.js",
"types": "src/theme-classic.d.ts",
@ -20,22 +20,22 @@
"copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
},
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/mdx-loader": "2.3.1",
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/plugin-content-blog": "2.3.1",
"@docusaurus/plugin-content-docs": "2.3.1",
"@docusaurus/plugin-content-pages": "2.3.1",
"@docusaurus/theme-common": "2.3.1",
"@docusaurus/theme-translations": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-common": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/mdx-loader": "2.4.0",
"@docusaurus/module-type-aliases": "2.4.0",
"@docusaurus/plugin-content-blog": "2.4.0",
"@docusaurus/plugin-content-docs": "2.4.0",
"@docusaurus/plugin-content-pages": "2.4.0",
"@docusaurus/theme-common": "2.4.0",
"@docusaurus/theme-translations": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-common": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1",
"copy-text-to-clipboard": "^3.0.1",
"infima": "0.2.0-alpha.42",
"infima": "0.2.0-alpha.43",
"lodash": "^4.17.21",
"nprogress": "^0.2.0",
"postcss": "^8.4.14",

View file

@ -16,6 +16,10 @@ exports[`getTranslationFiles returns translation files matching snapshot 1`] = `
"description": "Navbar item with label Dropdown item 2",
"message": "Dropdown item 2",
},
"logo.alt": {
"description": "The alt text of navbar logo",
"message": "navbar alt text logo",
},
"title": {
"description": "The title in the navbar",
"message": "navbar title",
@ -49,6 +53,10 @@ exports[`getTranslationFiles returns translation files matching snapshot 1`] = `
"description": "The title of the footer links column with title=Footer link column 2 in the footer",
"message": "Footer link column 2",
},
"logo.alt": {
"description": "The alt text of footer logo",
"message": "footer alt text logo",
},
},
"path": "footer",
},
@ -71,6 +79,10 @@ exports[`getTranslationFiles returns translation files matching snapshot 2`] = `
"description": "Navbar item with label Dropdown item 2",
"message": "Dropdown item 2",
},
"logo.alt": {
"description": "The alt text of navbar logo",
"message": "navbar alt text logo",
},
"title": {
"description": "The title in the navbar",
"message": "navbar title",
@ -92,6 +104,10 @@ exports[`getTranslationFiles returns translation files matching snapshot 2`] = `
"description": "The label of footer link with label=Link 2 linking to https://facebook.com",
"message": "Link 2",
},
"logo.alt": {
"description": "The alt text of footer logo",
"message": "footer alt text logo",
},
},
"path": "footer",
},
@ -131,6 +147,10 @@ exports[`translateThemeConfig returns translated themeConfig 1`] = `
"title": "Footer link column 2 (translated)",
},
],
"logo": {
"alt": "footer alt text logo (translated)",
"src": "img/docusaurus.svg",
},
"style": "light",
},
"navbar": {
@ -150,6 +170,10 @@ exports[`translateThemeConfig returns translated themeConfig 1`] = `
"label": "Dropdown (translated)",
},
],
"logo": {
"alt": "navbar alt text logo (translated)",
"src": "img/docusaurus.svg",
},
"style": "dark",
"title": "navbar title (translated)",
},

View file

@ -18,6 +18,10 @@ const ThemeConfigSample = {
},
navbar: {
title: 'navbar title',
logo: {
alt: 'navbar alt text logo',
src: 'img/docusaurus.svg',
},
style: 'dark',
hideOnScroll: false,
items: [
@ -31,6 +35,10 @@ const ThemeConfigSample = {
],
},
footer: {
logo: {
alt: 'footer alt text logo',
src: 'img/docusaurus.svg',
},
copyright: 'Copyright FB',
style: 'light',
links: [
@ -52,6 +60,10 @@ const ThemeConfigSample = {
const ThemeConfigSampleSimpleFooter: ThemeConfig = {
...ThemeConfigSample,
footer: {
logo: {
alt: 'footer alt text logo',
src: 'img/docusaurus.svg',
},
copyright: 'Copyright FB',
style: 'light',
links: [

View file

@ -26,6 +26,8 @@ const ContextReplacementPlugin = requireFromDocusaurusCore(
// Need to be inlined to prevent dark mode FOUC
// Make sure the key is the same as the one in `/theme/hooks/useTheme.js`
const ThemeStorageKey = 'theme';
const ThemeQueryStringKey = 'docusaurus-theme';
const noFlashColorMode = ({
defaultMode,
respectPrefersColorScheme,
@ -39,6 +41,14 @@ const noFlashColorMode = ({
document.documentElement.setAttribute('data-theme', theme);
}
function getQueryStringTheme() {
var theme = null;
try {
theme = new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
} catch(e) {}
return theme;
}
function getStoredTheme() {
var theme = null;
try {
@ -47,9 +57,9 @@ const noFlashColorMode = ({
return theme;
}
var storedTheme = getStoredTheme();
if (storedTheme !== null) {
setDataThemeAttribute(storedTheme);
var initialTheme = getQueryStringTheme() || getStoredTheme();
if (initialTheme !== null) {
setDataThemeAttribute(initialTheme);
} else {
if (
respectPrefersColorScheme &&

View file

@ -1243,6 +1243,7 @@ declare module '@theme/ColorModeToggle' {
export interface Props {
readonly className?: string;
readonly buttonClassName?: string;
readonly value: ColorMode;
/**
* The parameter represents the "to-be" value. For example, if currently in

View file

@ -59,6 +59,7 @@
display: flex;
column-gap: 0.2rem;
position: absolute;
/* rtl:ignore */
right: calc(var(--ifm-pre-padding) / 2);
top: calc(var(--ifm-pre-padding) / 2);
}
@ -72,7 +73,7 @@
border-radius: var(--ifm-global-radius);
padding: 0.4rem;
line-height: 0;
transition: opacity 200ms ease-in-out;
transition: opacity var(--ifm-transition-fast) ease-in-out;
opacity: 0;
}

View file

@ -24,7 +24,7 @@
opacity: inherit;
width: inherit;
height: inherit;
transition: all 0.15s ease;
transition: all var(--ifm-transition-fast) ease;
}
.copyButtonSuccessIcon {

View file

@ -15,7 +15,12 @@ import type {Props} from '@theme/ColorModeToggle';
import styles from './styles.module.css';
function ColorModeToggle({className, value, onChange}: Props): JSX.Element {
function ColorModeToggle({
className,
buttonClassName,
value,
onChange,
}: Props): JSX.Element {
const isBrowser = useIsBrowser();
const title = translate(
@ -47,6 +52,7 @@ function ColorModeToggle({className, value, onChange}: Props): JSX.Element {
'clean-btn',
styles.toggleButton,
!isBrowser && styles.toggleButtonDisabled,
buttonClassName,
)}
type="button"
onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}

View file

@ -82,7 +82,9 @@ function CardCategory({
href={href}
icon="🗃️"
title={item.label}
description={translate(
description={
item.description ??
translate(
{
message: '{count} items',
id: 'theme.docs.DocCard.categoryDescription',
@ -90,7 +92,8 @@ function CardCategory({
'The default description for a category card in the generated index about how many items this category includes',
},
{count: item.items.length},
)}
)
}
/>
);
}
@ -103,7 +106,7 @@ function CardLink({item}: {item: PropSidebarItemLink}): JSX.Element {
href={item.href}
icon={icon}
title={item.label}
description={doc?.description}
description={item.description ?? doc?.description}
/>
);
}

View file

@ -7,6 +7,10 @@
import React from 'react';
import Translate from '@docusaurus/Translate';
import {
ErrorBoundaryError,
ErrorBoundaryTryAgainButton,
} from '@docusaurus/theme-common';
import type {Props} from '@theme/Error';
export default function ErrorPageContent({
@ -24,15 +28,15 @@ export default function ErrorPageContent({
This page crashed.
</Translate>
</h1>
<p>{error.message}</p>
<div>
<button type="button" onClick={tryAgain}>
<Translate
id="theme.ErrorPageContent.tryAgain"
description="The label of the button to try again when the page crashed">
Try again
</Translate>
</button>
<div className="margin-vert--lg">
<ErrorBoundaryTryAgainButton
onClick={tryAgain}
className="button button--primary shadow--lw"
/>
</div>
<hr />
<div className="margin-vert--md">
<ErrorBoundaryError error={error} />
</div>
</div>
</div>

View file

@ -9,10 +9,12 @@ import React from 'react';
import {useColorMode, useThemeConfig} from '@docusaurus/theme-common';
import ColorModeToggle from '@theme/ColorModeToggle';
import type {Props} from '@theme/Navbar/ColorModeToggle';
import styles from './styles.module.css';
export default function NavbarColorModeToggle({
className,
}: Props): JSX.Element | null {
const navbarStyle = useThemeConfig().navbar.style;
const disabled = useThemeConfig().colorMode.disableSwitch;
const {colorMode, setColorMode} = useColorMode();
@ -23,6 +25,9 @@ export default function NavbarColorModeToggle({
return (
<ColorModeToggle
className={className}
buttonClassName={
navbarStyle === 'dark' ? styles.darkNavbarColorModeToggle : undefined
}
value={colorMode}
onChange={setColorMode}
/>

View file

@ -0,0 +1,10 @@
/**
* 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.
*/
.darkNavbarColorModeToggle:hover {
background: var(--ifm-color-gray-800);
}

View file

@ -6,7 +6,7 @@
*/
import React, {type ReactNode} from 'react';
import {useThemeConfig} from '@docusaurus/theme-common';
import {useThemeConfig, ErrorCauseBoundary} from '@docusaurus/theme-common';
import {
splitNavbarItems,
useNavbarMobileSidebar,
@ -29,7 +29,18 @@ function NavbarItems({items}: {items: NavbarItemConfig[]}): JSX.Element {
return (
<>
{items.map((item, i) => (
<NavbarItem {...item} key={i} />
<ErrorCauseBoundary
key={i}
onError={(error) =>
new Error(
`A theme navbar item failed to render.
Please double-check the following navbar item (themeConfig.navbar.items) of your Docusaurus config:
${JSON.stringify(item, null, 2)}`,
{cause: error},
)
}>
<NavbarItem {...item} />
</ErrorCauseBoundary>
))}
</>
);

View file

@ -54,7 +54,9 @@ function DropdownNavbarItemDesktop({
const [showDropdown, setShowDropdown] = useState(false);
useEffect(() => {
const handleClickOutside = (event: MouseEvent | TouchEvent) => {
const handleClickOutside = (
event: MouseEvent | TouchEvent | FocusEvent,
) => {
if (
!dropdownRef.current ||
dropdownRef.current.contains(event.target as Node)
@ -66,10 +68,12 @@ function DropdownNavbarItemDesktop({
document.addEventListener('mousedown', handleClickOutside);
document.addEventListener('touchstart', handleClickOutside);
document.addEventListener('focusin', handleClickOutside);
return () => {
document.removeEventListener('mousedown', handleClickOutside);
document.removeEventListener('touchstart', handleClickOutside);
document.removeEventListener('focusin', handleClickOutside);
};
}, [dropdownRef]);
@ -100,22 +104,6 @@ function DropdownNavbarItemDesktop({
{items.map((childItemProps, i) => (
<NavbarItem
isDropdownItem
onKeyDown={(e) => {
if (i === items.length - 1 && e.key === 'Tab') {
e.preventDefault();
setShowDropdown(false);
const nextNavbarItem = dropdownRef.current!.nextElementSibling;
if (nextNavbarItem) {
const targetItem =
nextNavbarItem instanceof HTMLAnchorElement
? nextNavbarItem
: // Next item is another dropdown; focus on the inner
// anchor element instead so there's outline
nextNavbarItem.querySelector('a')!;
targetItem.focus();
}
}
}}
activeClassName="dropdown__link--active"
{...childItemProps}
key={i}

View file

@ -132,12 +132,9 @@ describe('Tabs', () => {
renderer.create(
<TestProviders>
<Tabs
// @ts-expect-error: for an edge-case that we didn't write types for
values={tabs.map((t, idx) => ({label: t, value: idx}))}
// @ts-expect-error: for an edge-case that we didn't write types for
defaultValue={0}>
{tabs.map((t, idx) => (
// @ts-expect-error: for an edge-case that we didn't write types for
<TabItem key={idx} value={idx}>
{t}
</TabItem>
@ -199,4 +196,19 @@ describe('Tabs', () => {
);
}).not.toThrow();
});
it('allows a tab to be falsy', () => {
expect(() => {
renderer.create(
<TestProviders>
<Tabs>
<TabItem value="val1">Val1</TabItem>
{null}
{false}
{undefined}
</Tabs>
</TestProviders>,
);
}).not.toThrow();
});
});

View file

@ -5,11 +5,12 @@
* LICENSE file in the root directory of this source tree.
*/
import React, {cloneElement} from 'react';
import React, {cloneElement, type ReactElement} from 'react';
import clsx from 'clsx';
import {
useScrollPositionBlocker,
useTabs,
type TabItemProps,
} from '@docusaurus/theme-common/internal';
import useIsBrowser from '@docusaurus/useIsBrowser';
import type {Props} from '@theme/Tabs';
@ -109,10 +110,11 @@ function TabContent({
children,
selectedValue,
}: Props & ReturnType<typeof useTabs>) {
// eslint-disable-next-line no-param-reassign
children = Array.isArray(children) ? children : [children];
const childTabs = (Array.isArray(children) ? children : [children]).filter(
Boolean,
) as ReactElement<TabItemProps>[];
if (lazy) {
const selectedTabItem = children.find(
const selectedTabItem = childTabs.find(
(tabItem) => tabItem.props.value === selectedValue,
);
if (!selectedTabItem) {
@ -123,7 +125,7 @@ function TabContent({
}
return (
<div className="margin-top--md">
{children.map((tabItem, i) =>
{childTabs.map((tabItem, i) =>
cloneElement(tabItem, {
key: i,
hidden: tabItem.props.value !== selectedValue,

View file

@ -45,7 +45,20 @@ function getNavbarTranslationFile(navbar: Navbar): TranslationFileContent {
? {title: {message: navbar.title, description: 'The title in the navbar'}}
: {};
return mergeTranslations([titleTranslations, navbarItemsTranslations]);
const logoAlt: TranslationFileContent = navbar.logo?.alt
? {
'logo.alt': {
message: navbar.logo.alt,
description: 'The alt text of navbar logo',
},
}
: {};
return mergeTranslations([
titleTranslations,
logoAlt,
navbarItemsTranslations,
]);
}
function translateNavbar(
navbar: Navbar,
@ -54,9 +67,18 @@ function translateNavbar(
if (!navbarTranslations) {
return navbar;
}
const logo = navbar.logo
? {
...navbar.logo,
alt: navbarTranslations[`logo.alt`]?.message ?? navbar.logo?.alt,
}
: undefined;
return {
...navbar,
title: navbarTranslations.title?.message ?? navbar.title,
logo,
// TODO handle properly all the navbar item types here!
items: navbar.items.map((item) => {
const subItems = item.items?.map((subItem) => ({
@ -119,7 +141,21 @@ function getFooterTranslationFile(footer: Footer): TranslationFileContent {
}
: {};
return mergeTranslations([footerLinkTitles, footerLinkLabels, copyright]);
const logoAlt: TranslationFileContent = footer.logo?.alt
? {
'logo.alt': {
message: footer.logo.alt,
description: 'The alt text of footer logo',
},
}
: {};
return mergeTranslations([
footerLinkTitles,
footerLinkLabels,
copyright,
logoAlt,
]);
}
function translateFooter(
footer: Footer,
@ -149,10 +185,18 @@ function translateFooter(
const copyright = footerTranslations.copyright?.message ?? footer.copyright;
const logo = footer.logo
? {
...footer.logo,
alt: footerTranslations[`logo.alt`]?.message ?? footer.logo?.alt,
}
: undefined;
return {
...footer,
links,
copyright,
logo,
};
}

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/theme-common",
"version": "2.3.1",
"version": "2.4.0",
"description": "Common code for Docusaurus themes.",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
@ -30,12 +30,13 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/mdx-loader": "2.3.1",
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/plugin-content-blog": "2.3.1",
"@docusaurus/plugin-content-docs": "2.3.1",
"@docusaurus/plugin-content-pages": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/mdx-loader": "2.4.0",
"@docusaurus/module-type-aliases": "2.4.0",
"@docusaurus/plugin-content-blog": "2.4.0",
"@docusaurus/plugin-content-docs": "2.4.0",
"@docusaurus/plugin-content-pages": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-common": "2.4.0",
"@types/history": "^4.7.11",
"@types/react": "*",
"@types/react-router-config": "*",
@ -47,8 +48,8 @@
"utility-types": "^3.10.0"
},
"devDependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/types": "2.4.0",
"fs-extra": "^10.1.0",
"lodash": "^4.17.21"
},

View file

@ -65,6 +65,10 @@ function applyCollapsedStyle(el: HTMLElement, collapsed: boolean) {
el.style.height = collapsedStyles.height;
}
function userPrefersReducedMotion(): boolean {
return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}
/*
Lex111: Dynamic transition duration is used in Material design, this technique
is good for a large number of items.
@ -72,6 +76,9 @@ https://material.io/archive/guidelines/motion/duration-easing.html#duration-easi
https://github.com/mui-org/material-ui/blob/e724d98eba018e55e1a684236a2037e24bcf050c/packages/material-ui/src/styles/createTransitions.js#L40-L43
*/
function getAutoHeightDuration(height: number) {
if (userPrefersReducedMotion()) {
return 0;
}
const constant = height / 36;
return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10);
}

View file

@ -31,8 +31,11 @@ function hasParent(node: HTMLElement | null, parent: HTMLElement): boolean {
}
export type DetailsProps = {
/** Summary is provided as props, including the wrapping `<summary>` tag */
summary?: ReactElement;
/**
* Summary is provided as props, optionally including the wrapping
* `<summary>` tag
*/
summary?: ReactElement | string;
} & ComponentProps<'details'>;
/**
@ -54,6 +57,12 @@ export function Details({
// only after animation completes, otherwise close animations won't work
const [open, setOpen] = useState(props.open);
const summaryElement = React.isValidElement(summary) ? (
summary
) : (
<summary>{summary ?? 'Details'}</summary>
);
return (
// eslint-disable-next-line jsx-a11y/click-events-have-key-events, jsx-a11y/no-noninteractive-element-interactions
<details
@ -91,8 +100,7 @@ export function Details({
// setOpen(false);
}
}}>
{/* eslint-disable-next-line @docusaurus/no-untranslated-text */}
{summary ?? <summary>Details</summary>}
{summaryElement}
<Collapsible
lazy={false} // Content might matter for SEO in this case

View file

@ -5,32 +5,24 @@
* LICENSE file in the root directory of this source tree.
*/
import {useCallback, useEffect, useState} from 'react';
import {useHistory} from '@docusaurus/router';
import {useCallback} from 'react';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import {useQueryString} from '../utils/historyUtils';
import type {ThemeConfig as AlgoliaThemeConfig} from '@docusaurus/theme-search-algolia';
const SEARCH_PARAM_QUERY = 'q';
/** Some utility functions around search queries. */
export function useSearchPage(): {
/**
* Works hand-in-hand with `setSearchQuery`; whatever the user has inputted
* into the search box.
* Permits to read/write the current search query string
*/
searchQuery: string;
export function useSearchQueryString(): [string, (newValue: string) => void] {
return useQueryString(SEARCH_PARAM_QUERY);
}
/**
* Set a new search query. In addition to updating `searchQuery`, this handle
* also mutates the location and appends the query.
* Permits to create links to the search page with the appropriate query string
*/
setSearchQuery: (newSearchQuery: string) => void;
/**
* Given a query, this handle generates the corresponding search page link,
* with base URL prepended.
*/
generateSearchPageLink: (targetSearchQuery: string) => string;
} {
const history = useHistory();
export function useSearchLinkCreator(): (searchValue: string) => string {
const {
siteConfig: {baseUrl, themeConfig},
} = useDocusaurusContext();
@ -38,47 +30,13 @@ export function useSearchPage(): {
algolia: {searchPagePath},
} = themeConfig as AlgoliaThemeConfig;
const [searchQuery, setSearchQueryState] = useState('');
// Init search query just after React hydration
useEffect(() => {
const searchQueryStringValue =
new URLSearchParams(window.location.search).get(SEARCH_PARAM_QUERY) ?? '';
setSearchQueryState(searchQueryStringValue);
}, []);
const setSearchQuery = useCallback(
(newSearchQuery: string) => {
const searchParams = new URLSearchParams(window.location.search);
if (newSearchQuery) {
searchParams.set(SEARCH_PARAM_QUERY, newSearchQuery);
} else {
searchParams.delete(SEARCH_PARAM_QUERY);
}
history.replace({
search: searchParams.toString(),
});
setSearchQueryState(newSearchQuery);
},
[history],
);
const generateSearchPageLink = useCallback(
(targetSearchQuery: string) =>
return useCallback(
(searchValue: string) =>
// Refer to https://github.com/facebook/docusaurus/pull/2838
// Note: if searchPagePath is falsy, useSearchPage() will not be called
`${baseUrl}${
searchPagePath as string
}?${SEARCH_PARAM_QUERY}=${encodeURIComponent(targetSearchQuery)}`,
}?${SEARCH_PARAM_QUERY}=${encodeURIComponent(searchValue)}`,
[baseUrl, searchPagePath],
);
return {
searchQuery,
setSearchQuery,
generateSearchPageLink,
};
}

View file

@ -73,6 +73,11 @@ export {
type TagLetterEntry,
} from './utils/tagsUtils';
export {
useSearchQueryString,
useSearchLinkCreator,
} from './hooks/useSearchPage';
export {isMultiColumnFooterLinks} from './utils/footerUtils';
export {isRegexpStringMatch} from './utils/regexpUtils';
@ -89,3 +94,9 @@ export {
SkipToContentFallbackId,
SkipToContentLink,
} from './utils/skipToContentUtils';
export {
ErrorBoundaryTryAgainButton,
ErrorBoundaryError,
ErrorCauseBoundary,
} from './utils/errorBoundaryUtils';

View file

@ -117,7 +117,6 @@ export {
keyboardFocusedClassName,
} from './hooks/useKeyboardNavigation';
export {useLockBodyScroll} from './hooks/useLockBodyScroll';
export {useSearchPage} from './hooks/useSearchPage';
export {useCodeWordWrap} from './hooks/useCodeWordWrap';
export {getPrismCssVariables} from './utils/codeBlockUtils';
export {useBackToTopButton} from './hooks/useBackToTopButton';

View file

@ -304,9 +304,9 @@ export function useLayoutDoc(
return null;
}
throw new Error(
`DocNavbarItem: couldn't find any doc with id "${docId}" in version${
`Couldn't find any doc with id "${docId}" in version${
versions.length > 1 ? 's' : ''
} ${versions.map((version) => version.name).join(', ')}".
} "${versions.map((version) => version.name).join(', ')}".
Available doc ids are:
- ${uniq(allDocs.map((versionDoc) => versionDoc.id)).join('\n- ')}`,
);

View file

@ -0,0 +1,11 @@
/**
* 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.
*/
.errorBoundaryError {
white-space: pre-wrap;
color: red;
}

View file

@ -0,0 +1,56 @@
/**
* 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 React, {type ComponentProps} from 'react';
import Translate from '@docusaurus/Translate';
import {getErrorCausalChain} from '@docusaurus/utils-common';
import styles from './errorBoundaryUtils.module.css';
export function ErrorBoundaryTryAgainButton(
props: ComponentProps<'button'>,
): JSX.Element {
return (
<button type="button" {...props}>
<Translate
id="theme.ErrorPageContent.tryAgain"
description="The label of the button to try again rendering when the React error boundary captures an error">
Try again
</Translate>
</button>
);
}
export function ErrorBoundaryError({error}: {error: Error}): JSX.Element {
const causalChain = getErrorCausalChain(error);
const fullMessage = causalChain.map((e) => e.message).join('\n\nCause:\n');
return <p className={styles.errorBoundaryError}>{fullMessage}</p>;
}
/**
* This component is useful to wrap a low-level error into a more meaningful
* error with extra context, using the ES error-cause feature.
*
* <ErrorCauseBoundary
* onError={(error) => new Error("extra context message",{cause: error})}
* >
* <RiskyComponent>
* </ErrorCauseBoundary>
*/
export class ErrorCauseBoundary extends React.Component<
{
children: React.ReactNode;
onError: (error: Error, errorInfo: React.ErrorInfo) => Error;
},
unknown
> {
override componentDidCatch(error: Error, errorInfo: React.ErrorInfo): never {
throw this.props.onError(error, errorInfo);
}
override render(): React.ReactNode {
return this.props.children;
}
}

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree.
*/
import {useEffect} from 'react';
import {useCallback, useEffect} from 'react';
import {useHistory} from '@docusaurus/router';
// @ts-expect-error: TODO temporary until React 18 upgrade
import {useSyncExternalStore} from 'use-sync-external-store/shim';
@ -75,3 +75,42 @@ export function useQueryStringValue(key: string | null): string | null {
return new URLSearchParams(history.location.search).get(key);
});
}
export function useQueryStringKeySetter(): (
key: string,
newValue: string | null,
options?: {push: boolean},
) => void {
const history = useHistory();
return useCallback(
(key, newValue, options) => {
const searchParams = new URLSearchParams(history.location.search);
if (newValue) {
searchParams.set(key, newValue);
} else {
searchParams.delete(key);
}
const updaterFn = options?.push ? history.push : history.replace;
updaterFn({
search: searchParams.toString(),
});
},
[history],
);
}
export function useQueryString(
key: string,
): [string, (newValue: string, options?: {push: boolean}) => void] {
const value = useQueryStringValue(key) ?? '';
const setQueryString = useQueryStringKeySetter();
return [
value,
useCallback(
(newValue: string, options) => {
setQueryString(key, newValue, options);
},
[setQueryString, key],
),
];
}

View file

@ -29,12 +29,12 @@ export interface TabValue {
readonly default?: boolean;
}
type TabItem = ReactElement<TabItemProps> | null | false | undefined;
export interface TabsProps {
readonly lazy?: boolean;
readonly block?: boolean;
readonly children:
| readonly ReactElement<TabItemProps>[]
| ReactElement<TabItemProps>;
readonly children: TabItem[] | TabItem;
readonly defaultValue?: string | null;
readonly values?: readonly TabValue[];
readonly groupId?: string;
@ -55,14 +55,16 @@ export interface TabItemProps {
// A very rough duck type, but good enough to guard against mistakes while
// allowing customization
function isTabItem(
comp: ReactElement<object>,
comp: ReactElement<unknown>,
): comp is ReactElement<TabItemProps> {
return 'value' in comp.props;
const {props} = comp;
return !!props && typeof props === 'object' && 'value' in props;
}
function ensureValidChildren(children: TabsProps['children']) {
return React.Children.map(children, (child) => {
if (isValidElement(child) && isTabItem(child)) {
return (React.Children.map(children, (child) => {
// Pass falsy values through: allow conditionally not rendering a tab
if (!child || (isValidElement(child) && isTabItem(child))) {
return child;
}
// child.type.name will give non-sensical values in prod because of
@ -73,7 +75,7 @@ function ensureValidChildren(children: TabsProps['children']) {
typeof child.type === 'string' ? child.type : child.type.name
}>: all children of the <Tabs> component should be <TabItem>, and every <TabItem> should have a unique "value" prop.`,
);
});
})?.filter(Boolean) ?? []) as ReactElement<TabItemProps>[];
}
function extractChildrenTabValues(children: TabsProps['children']): TabValue[] {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/theme-live-codeblock",
"version": "2.3.1",
"version": "2.4.0",
"description": "Docusaurus live code block component.",
"main": "lib/index.js",
"types": "src/theme-live-codeblock.d.ts",
@ -23,10 +23,10 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/theme-common": "2.3.1",
"@docusaurus/theme-translations": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/theme-common": "2.4.0",
"@docusaurus/theme-translations": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"@philpl/buble": "^0.19.7",
"clsx": "^1.2.1",
"fs-extra": "^10.1.0",
@ -34,7 +34,7 @@
"tslib": "^2.4.0"
},
"devDependencies": {
"@docusaurus/types": "2.3.1",
"@docusaurus/types": "2.4.0",
"@types/buble": "^0.20.1"
},
"peerDependencies": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/theme-mermaid",
"version": "2.3.1",
"version": "2.4.0",
"description": "Mermaid components for Docusaurus.",
"main": "lib/index.js",
"types": "src/theme-mermaid.d.ts",
@ -33,11 +33,11 @@
"copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
},
"dependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/theme-common": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/module-type-aliases": "2.4.0",
"@docusaurus/theme-common": "2.4.0",
"@docusaurus/types": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"@mdx-js/react": "^1.6.22",
"mermaid": "^9.2.2",
"tslib": "^2.4.0"

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/theme-search-algolia",
"version": "2.3.1",
"version": "2.4.0",
"description": "Algolia search component for Docusaurus.",
"main": "lib/index.js",
"sideEffects": [
@ -34,13 +34,13 @@
},
"dependencies": {
"@docsearch/react": "^3.1.1",
"@docusaurus/core": "2.3.1",
"@docusaurus/logger": "2.3.1",
"@docusaurus/plugin-content-docs": "2.3.1",
"@docusaurus/theme-common": "2.3.1",
"@docusaurus/theme-translations": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/logger": "2.4.0",
"@docusaurus/plugin-content-docs": "2.4.0",
"@docusaurus/theme-common": "2.4.0",
"@docusaurus/theme-translations": "2.4.0",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"algoliasearch": "^4.13.1",
"algoliasearch-helper": "^3.10.0",
"clsx": "^1.2.1",
@ -51,7 +51,7 @@
"utility-types": "^3.10.0"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.3.1"
"@docusaurus/module-type-aliases": "2.4.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",

View file

@ -10,8 +10,10 @@ import {DocSearchButton, useDocSearchKeyboardEvents} from '@docsearch/react';
import Head from '@docusaurus/Head';
import Link from '@docusaurus/Link';
import {useHistory} from '@docusaurus/router';
import {isRegexpStringMatch} from '@docusaurus/theme-common';
import {useSearchPage} from '@docusaurus/theme-common/internal';
import {
isRegexpStringMatch,
useSearchLinkCreator,
} from '@docusaurus/theme-common';
import {
useAlgoliaContextualFacetFilters,
useSearchResultUrlProcessor,
@ -59,10 +61,10 @@ type ResultsFooterProps = {
};
function ResultsFooter({state, onClose}: ResultsFooterProps) {
const {generateSearchPageLink} = useSearchPage();
const createSearchLink = useSearchLinkCreator();
return (
<Link to={generateSearchPageLink(state.query)} onClick={onClose}>
<Link to={createSearchLink(state.query)} onClick={onClose}>
<Translate
id="theme.SearchBar.seeAll"
values={{count: state.context.nbHits}}>

View file

@ -21,11 +21,9 @@ import {
HtmlClassNameProvider,
useEvent,
usePluralForm,
useSearchQueryString,
} from '@docusaurus/theme-common';
import {
useSearchPage,
useTitleFormatter,
} from '@docusaurus/theme-common/internal';
import {useTitleFormatter} from '@docusaurus/theme-common/internal';
import Translate, {translate} from '@docusaurus/Translate';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import {
@ -167,7 +165,7 @@ function SearchPageContent(): JSX.Element {
const documentsFoundPlural = useDocumentsFoundPlural();
const docsSearchVersionsHelpers = useDocsSearchVersionsHelpers();
const {searchQuery, setSearchQuery} = useSearchPage();
const [searchQuery, setSearchQuery] = useSearchQueryString();
const initialSearchResultState: ResultDispatcherState = {
items: [],
query: null,

View file

@ -17,7 +17,7 @@
"theme.admonition.danger": "خطر",
"theme.admonition.info": "معلومات",
"theme.admonition.note": "ملاحظة",
"theme.admonition.tip": مليح",
"theme.admonition.tip": لميح",
"theme.blog.archive.description": "أرشيف",
"theme.blog.archive.title": "أرشيف",
"theme.blog.paginator.navAriaLabel": "التنقل في صفحة قائمة المدونة",
@ -42,7 +42,7 @@
"theme.docs.breadcrumbs.home": "الرئيسية",
"theme.docs.breadcrumbs.navAriaLabel": "التنقل التفصيلي",
"theme.docs.paginator.navAriaLabel": "التنقل بين صفحات الددات",
"theme.docs.paginator.next": "التالى",
"theme.docs.paginator.next": "التالي",
"theme.docs.paginator.previous": "السابق",
"theme.docs.sidebar.closeSidebarButtonAriaLabel": "Close navigation bar",
"theme.docs.sidebar.collapseButtonAriaLabel": "طي الشريط الجانبي",

View file

@ -0,0 +1,7 @@
{
"theme.IdealImageMessage.404error": "404. A kép nem található",
"theme.IdealImageMessage.error": "Hiba. Kattints újratöltéshez",
"theme.IdealImageMessage.load": "Kattints a(z) {sizeMessage} betöltéséhez",
"theme.IdealImageMessage.loading": "Betöltés...",
"theme.IdealImageMessage.offline": "A böngésződ offline módban van. A kép nem töltődött be"
}

View file

@ -0,0 +1,5 @@
{
"theme.PwaReloadPopup.closeButtonAriaLabel": "Bezárás",
"theme.PwaReloadPopup.info": "Új verzió elérhető el",
"theme.PwaReloadPopup.refreshButtonText": "Frissítés"
}

View file

@ -0,0 +1,70 @@
{
"theme.AnnouncementBar.closeButtonAriaLabel": "Bezárás",
"theme.BackToTopButton.buttonAriaLabel": "Vissza a tetejére",
"theme.CodeBlock.copied": "Másolva",
"theme.CodeBlock.copy": "Másolás",
"theme.CodeBlock.copyButtonAriaLabel": "Másolás a vágólapra",
"theme.CodeBlock.wordWrapToggle": "Szótörés váltása",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Összecsukás/kibontás kategória '{label}'",
"theme.ErrorPageContent.title": "Hiba történt a oldalon.",
"theme.ErrorPageContent.tryAgain": "Próbáld újra",
"theme.NavBar.navAriaLabel": "Fő",
"theme.NotFound.p1": "Sajnos nem találtuk azt az oldalt, amit kerestél.",
"theme.NotFound.p2": "Kérjük, lépj kapcsolatba az oldal tulajdonosával, ahonnan erre a hivatkozásra léptél, hogy jelezd, hogy a hivatkozás nem működik.",
"theme.NotFound.title": "Az oldal nem található",
"theme.TOCCollapsible.toggleButtonLabel": "Ezen az oldalon tartalomjegyzék",
"theme.admonition.caution": "vigyázat",
"theme.admonition.danger": "veszély",
"theme.admonition.info": "információ",
"theme.admonition.note": "megjegyzés",
"theme.admonition.tip": "tanács",
"theme.blog.archive.description": "Archívum",
"theme.blog.archive.title": "Archívum",
"theme.blog.paginator.navAriaLabel": "Bloglista oldalának navigációja",
"theme.blog.paginator.newerEntries": "Újabb bejegyzések",
"theme.blog.paginator.olderEntries": "Régebbi bejegyzések",
"theme.blog.post.paginator.navAriaLabel": "Blogbejegyzés oldalának navigációja",
"theme.blog.post.paginator.newerPost": "Újabb bejegyzés",
"theme.blog.post.paginator.olderPost": "Régebbi bejegyzés",
"theme.blog.post.plurals": "Egy bejegyzés|{count} bejegyzés",
"theme.blog.post.readMore": "Olvass tovább",
"theme.blog.post.readMoreLabel": "További információ erről: {title}",
"theme.blog.post.readingTime.plurals": "Egy perc olvasás|{readingTime} perc olvasás",
"theme.blog.sidebar.navAriaLabel": "Navigáció a blog legutóbbi bejegyzései között",
"theme.blog.tagTitle": "{nPosts} a(z) \"{tagName}\" címkével",
"theme.colorToggle.ariaLabel": "Váltás a sötét és világos mód között (jelenleg {mode} van beállítva)",
"theme.colorToggle.ariaLabel.mode.dark": "Sötét mód",
"theme.colorToggle.ariaLabel.mode.light": "Világos mód",
"theme.common.editThisPage": "Szerkesztés GitHub-on",
"theme.common.headingLinkTitle": "Közvetlen hivatkozás erre: {heading}",
"theme.common.skipToMainContent": "Ugrás a fő tartalomhoz",
"theme.docs.DocCard.categoryDescription": "{count} elemek",
"theme.docs.breadcrumbs.home": "Kezdőlap",
"theme.docs.breadcrumbs.navAriaLabel": "Navigációs sáv a jelenlegi oldalhoz",
"theme.docs.paginator.navAriaLabel": "Dokumentációs oldal navigációja",
"theme.docs.paginator.next": "Következő oldal",
"theme.docs.paginator.previous": "Előző oldal",
"theme.docs.sidebar.closeSidebarButtonAriaLabel": "Navigációs sáv bezárása",
"theme.docs.sidebar.collapseButtonAriaLabel": "Oldalsáv összecsukása",
"theme.docs.sidebar.collapseButtonTitle": "Oldalsáv összecsukása",
"theme.docs.sidebar.expandButtonAriaLabel": "Oldalsáv kibontása",
"theme.docs.sidebar.expandButtonTitle": "Oldalsáv kibontása",
"theme.docs.sidebar.navAriaLabel": "Dokumentációs oldalsáv",
"theme.docs.sidebar.toggleSidebarButtonAriaLabel": "Navigációs sáv ki- és bekapcsolása",
"theme.docs.tagDocListPageTitle": "{nDocsTagged} címkével: \"{tagName}\" ",
"theme.docs.tagDocListPageTitle.nDocsTagged": "Egy oldal|{count} oldal",
"theme.docs.versionBadge.label": "Verzió: {versionLabel}",
"theme.docs.versions.latestVersionLinkLabel": "legutolsó verzió",
"theme.docs.versions.latestVersionSuggestionLabel": "Az aktuális dokumentáció itt található: {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Ez a {siteTitle} dokumentáció a {versionLabel} verzióhoz, amely már nem támogatott.",
"theme.docs.versions.unreleasedVersionLabel": "Ez a dokumentáció a jövőbeli {siteTitle} {versionLabel} verzióhoz.",
"theme.lastUpdated.atDate": " {date}-kor",
"theme.lastUpdated.byUser": " {user}-tól",
"theme.lastUpdated.lastUpdatedAtBy": "Utolsó frissítés{atDate}{byUser}",
"theme.navbar.mobileLanguageDropdown.label": "Nyelvek",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Vissza a főmenühöz",
"theme.navbar.mobileVersionsDropdown.label": "Verziók",
"theme.tags.tagsListLabel": "Címkék:",
"theme.tags.tagsPageLink": "Összes címke megtekintése",
"theme.tags.tagsPageTitle": "Címkék"
}

View file

@ -0,0 +1,4 @@
{
"theme.Playground.liveEditor": "Interaktív szerkesztő",
"theme.Playground.result": "Eredmény"
}

View file

@ -0,0 +1,36 @@
{
"theme.SearchBar.label": "Keresés",
"theme.SearchBar.seeAll": "Összes eredmény megtekintése ({count})",
"theme.SearchModal.errorScreen.helpText": "Ellenőrizze a hálózati kapcsolatot.",
"theme.SearchModal.errorScreen.titleText": "Nem sikerült az eredményeket lekérni",
"theme.SearchModal.footer.closeKeyAriaLabel": "Escape billentyű",
"theme.SearchModal.footer.closeText": "bezárás",
"theme.SearchModal.footer.navigateDownKeyAriaLabel": "Lefelé nyíl",
"theme.SearchModal.footer.navigateText": "navigációhoz",
"theme.SearchModal.footer.navigateUpKeyAriaLabel": "Felfelé nyíl",
"theme.SearchModal.footer.searchByText": "Motor:",
"theme.SearchModal.footer.selectKeyAriaLabel": "Enter billentyű",
"theme.SearchModal.footer.selectText": "kiválasztás",
"theme.SearchModal.noResultsScreen.noResultsText": "Nincs eredmény",
"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": "Adja meg nekünk.",
"theme.SearchModal.noResultsScreen.reportMissingResultsText": "Úgy gondolja, hogy ez a keresés eredményt kellene adnia?",
"theme.SearchModal.noResultsScreen.suggestedQueryText": "Próbálja meg keresni",
"theme.SearchModal.placeholder": "Dokumentumok keresése",
"theme.SearchModal.searchBox.cancelButtonText": "Mégse",
"theme.SearchModal.searchBox.resetButtonTitle": "Keresési kérés törlése",
"theme.SearchModal.startScreen.favoriteSearchesTitle": "Kedvencek",
"theme.SearchModal.startScreen.noRecentSearchesText": "Nincsenek legutóbbi keresések",
"theme.SearchModal.startScreen.recentSearchesTitle": "Legutóbbi",
"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": "Törölje ezt a keresést a kedvencekből",
"theme.SearchModal.startScreen.removeRecentSearchButtonTitle": "Törölje ezt a keresést az előzményekből",
"theme.SearchModal.startScreen.saveRecentSearchButtonTitle": "Mentsük el ezt a keresést",
"theme.SearchPage.saveRecentSearchButtonTitle": "Mentse ezt a keresést",
"theme.SearchPage.algoliaLabel": "Keresés az Algolia segítségével",
"theme.SearchPage.documentsFound.plurals": "Egy dokumentum|{count} dokumentumok",
"theme.SearchPage.emptyResultsTitle": "Keresés a webhelyen",
"theme.SearchPage.existingResultsTitle": "\"{query}\" keresési eredményei",
"theme.SearchPage.fetchingNewResults": "Új keresési eredmények betöltése...",
"theme.SearchPage.inputLabel": "Keresés",
"theme.SearchPage.inputPlaceholder": "Adja meg a keresendő kifejezést",
"theme.SearchPage.noResultsText": "Nincs találat a keresésre"
}

View file

@ -0,0 +1,7 @@
{
"theme.IdealImageMessage.404error": "404. Bildet kunne ikke lastes inn",
"theme.IdealImageMessage.error": "Noe gikk galt. Klikk for å laste på nytt",
"theme.IdealImageMessage.load": "Klikk for å laste inn på nytt{sizeMessage}",
"theme.IdealImageMessage.loading": "Laster inn...",
"theme.IdealImageMessage.offline": "Nettleseren din er offline. Bildet ble ikke lastet inn."
}

View file

@ -0,0 +1,5 @@
{
"theme.PwaReloadPopup.closeButtonAriaLabel": "Lukk",
"theme.PwaReloadPopup.info": "Ny versjon tilgjengelig",
"theme.PwaReloadPopup.refreshButtonText": "Last inn på nytt"
}

View file

@ -0,0 +1,70 @@
{
"theme.AnnouncementBar.closeButtonAriaLabel": "Lukk",
"theme.BackToTopButton.buttonAriaLabel": "Rull tilbake til toppen",
"theme.CodeBlock.copied": "Kopiert",
"theme.CodeBlock.copy": "Kopiere",
"theme.CodeBlock.copyButtonAriaLabel": "Kopier koden til utklippstavlen",
"theme.CodeBlock.wordWrapToggle": "Slå tekstbryting av/på",
"theme.DocSidebarItem.toggleCollapsedCategoryAriaLabel": "Veksle på den sammenleggbare sidefeltkategorien '{label}'",
"theme.ErrorPageContent.title": "Denne siden krasjet.",
"theme.ErrorPageContent.tryAgain": "Prøv på nytt",
"theme.NavBar.navAriaLabel": "Hoved",
"theme.NotFound.p1": "Vi kunne ikke finne det du lette etter.",
"theme.NotFound.p2": "Kontakt eieren av nettstedet som koblet deg til den opprinnelige nettadressen og la dem få vite at koblingen deres er ødelagt.",
"theme.NotFound.title": "Siden ble ikke funnet",
"theme.TOCCollapsible.toggleButtonLabel": "På denne siden",
"theme.admonition.caution": "forsiktig",
"theme.admonition.danger": "fare",
"theme.admonition.info": "info",
"theme.admonition.note": "merknad",
"theme.admonition.tip": "tips",
"theme.blog.archive.description": "Arkiv",
"theme.blog.archive.title": "Arkiv",
"theme.blog.paginator.navAriaLabel": "Navigering av bloggliste",
"theme.blog.paginator.newerEntries": "Nyere innlegg",
"theme.blog.paginator.olderEntries": "Eldre innlegg",
"theme.blog.post.paginator.navAriaLabel": "Navigering på blogginnlegg",
"theme.blog.post.paginator.newerPost": "Nyere innlegg",
"theme.blog.post.paginator.olderPost": "Eldre innlegg",
"theme.blog.post.plurals": "Ett innlegg|{count} innlegg",
"theme.blog.post.readMore": "Les mer",
"theme.blog.post.readMoreLabel": "Les mer om {title}",
"theme.blog.post.readingTime.plurals": "Ett min lesetid|{readingTime} min lesetid",
"theme.blog.sidebar.navAriaLabel": "Navigering av siste blogginnlegg",
"theme.blog.tagTitle": "{nPosts} merket med \"{tagName}\"",
"theme.colorToggle.ariaLabel": "Bytt mellom mørk og lys utseende (nå {mode})",
"theme.colorToggle.ariaLabel.mode.dark": "mørk utseende",
"theme.colorToggle.ariaLabel.mode.light": "lys utseende",
"theme.common.editThisPage": "Rediger denne siden",
"theme.common.headingLinkTitle": "Direkte lenke til {heading}",
"theme.common.skipToMainContent": "Gå til hovedinnhold",
"theme.docs.DocCard.categoryDescription": "{count} artikler",
"theme.docs.breadcrumbs.home": "Hjemmeside",
"theme.docs.breadcrumbs.navAriaLabel": "Søkvei",
"theme.docs.paginator.navAriaLabel": "Dokumenter-sidernavigasjon",
"theme.docs.paginator.next": "Neste",
"theme.docs.paginator.previous": "Forrige",
"theme.docs.sidebar.closeSidebarButtonAriaLabel": "Lukk navigasjonslinjen",
"theme.docs.sidebar.collapseButtonAriaLabel": "Skjul sidefeltet",
"theme.docs.sidebar.collapseButtonTitle": "Collapse sidebar",
"theme.docs.sidebar.expandButtonAriaLabel": "Utvid sidefeltet",
"theme.docs.sidebar.expandButtonTitle": "Utvid sidefeltet",
"theme.docs.sidebar.navAriaLabel": "Dokumenter sidefelt",
"theme.docs.sidebar.toggleSidebarButtonAriaLabel": "Vis/skjul navigasjonslinjen",
"theme.docs.tagDocListPageTitle": "{nDocsTagged} med \"{tagName}\"",
"theme.docs.tagDocListPageTitle.nDocsTagged": "Ett dokument merket|{count} dokumenter merket",
"theme.docs.versionBadge.label": "Versjon: {versionLabel}",
"theme.docs.versions.latestVersionLinkLabel": "siste Versjon",
"theme.docs.versions.latestVersionSuggestionLabel": "For oppdatert dokumentasjon, se {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Dette er dokumentasjon for {siteTitle} {versionLabel}, som ikke lenger vedlikeholdes aktivt.",
"theme.docs.versions.unreleasedVersionLabel": "Dette er uutgitt dokumentasjon for {siteTitle} {versionLabel} versjon.",
"theme.lastUpdated.atDate": " den {date}",
"theme.lastUpdated.byUser": " av {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Sist oppdatert{atDate}{byUser}",
"theme.navbar.mobileLanguageDropdown.label": "Språk",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Tilbake til hovedmenyen",
"theme.navbar.mobileVersionsDropdown.label": "Versjoner",
"theme.tags.tagsListLabel": "Tagger:",
"theme.tags.tagsPageLink": "Vis alle tagger",
"theme.tags.tagsPageTitle": "Tagger"
}

View file

@ -0,0 +1,4 @@
{
"theme.Playground.liveEditor": "Live Editor",
"theme.Playground.result": "Resultat"
}

View file

@ -0,0 +1,35 @@
{
"theme.SearchBar.label": "Søk",
"theme.SearchBar.seeAll": "Se alle {count} resultat",
"theme.SearchModal.errorScreen.helpText": "Det kan være lurt å sjekke nettverkstilkoblingen.",
"theme.SearchModal.errorScreen.titleText": "Kan ikke hente resultater",
"theme.SearchModal.footer.closeKeyAriaLabel": "Escape-tasten",
"theme.SearchModal.footer.closeText": "Lukk",
"theme.SearchModal.footer.navigateDownKeyAriaLabel": "Pil ned",
"theme.SearchModal.footer.navigateText": "for å navigere",
"theme.SearchModal.footer.navigateUpKeyAriaLabel": "Pil opp",
"theme.SearchModal.footer.searchByText": "Søk på",
"theme.SearchModal.footer.selectKeyAriaLabel": "Enter-tasten",
"theme.SearchModal.footer.selectText": "for å velge",
"theme.SearchModal.noResultsScreen.noResultsText": "Ingen resultat",
"theme.SearchModal.noResultsScreen.reportMissingResultsLinkText": "Gi oss beskjed.",
"theme.SearchModal.noResultsScreen.reportMissingResultsText": "Tenker du at denne spørringen bør gi resultater?",
"theme.SearchModal.noResultsScreen.suggestedQueryText": "Prøv å søke etter",
"theme.SearchModal.placeholder": "Søk i dokumenter",
"theme.SearchModal.searchBox.cancelButtonText": "Avbryt",
"theme.SearchModal.searchBox.resetButtonTitle": "Fjern søket",
"theme.SearchModal.startScreen.favoriteSearchesTitle": "Favoritt",
"theme.SearchModal.startScreen.noRecentSearchesText": "Ingen nylige søk",
"theme.SearchModal.startScreen.recentSearchesTitle": "Nylig",
"theme.SearchModal.startScreen.removeFavoriteSearchButtonTitle": "Fjern dette søket fra favoritter",
"theme.SearchModal.startScreen.removeRecentSearchButtonTitle": "Fjern dette søket fra loggen",
"theme.SearchModal.startScreen.saveRecentSearchButtonTitle": "Lagre dette søket",
"theme.SearchPage.algoliaLabel": "Søk med Algolia",
"theme.SearchPage.documentsFound.plurals": "Ett dokument funnet|{count} dokumenter funnet",
"theme.SearchPage.emptyResultsTitle": "Søk i dokumentasjonen",
"theme.SearchPage.existingResultsTitle": "Søkeresultater for \"{query}\"",
"theme.SearchPage.fetchingNewResults": "Henter nye resultater...",
"theme.SearchPage.inputLabel": "Søk",
"theme.SearchPage.inputPlaceholder": "Skriv inn søket ditt her",
"theme.SearchPage.noResultsText": "Ingen resultater ble funnet"
}

View file

@ -66,7 +66,5 @@
"theme.navbar.mobileVersionsDropdown.label": "Verzije",
"theme.tags.tagsListLabel": "Oznake:",
"theme.tags.tagsPageLink": "Poglej vse oznake",
"theme.tags.tagsPageTitle": "Oznake",
"theme.unlistedContent.message": "Ta stran ni zabeležena. Iskalniki je ne bodo indeksirali, do nje bodo uporabniki lahko dostopali le z direktno povezavo.",
"theme.unlistedContent.title": "Nezabeležena stran"
"theme.tags.tagsPageTitle": "Oznake"
}

View file

@ -66,7 +66,5 @@
"theme.navbar.mobileVersionsDropdown.label": "Versiyonlar",
"theme.tags.tagsListLabel": "Etiketler:",
"theme.tags.tagsPageLink": "Tüm Etiketleri Görüntüle",
"theme.tags.tagsPageTitle": "Etiketler",
"theme.unlistedContent.message": "Bu sayfa listelenmemiş. Arama motorları dizine eklemez ve yalnızca doğrudan bağlantısı olan kullanıcılar buna erişebilir.",
"theme.unlistedContent.title": "Listelenmeyen sayfa"
"theme.tags.tagsPageTitle": "Etiketler"
}

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/theme-translations",
"version": "2.3.1",
"version": "2.4.0",
"description": "Docusaurus theme translations.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
@ -23,8 +23,8 @@
"tslib": "^2.4.0"
},
"devDependencies": {
"@docusaurus/core": "2.3.1",
"@docusaurus/logger": "2.3.1",
"@docusaurus/core": "2.4.0",
"@docusaurus/logger": "2.4.0",
"lodash": "^4.17.21"
},
"engines": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/types",
"version": "2.3.1",
"version": "2.4.0",
"description": "Common types for Docusaurus packages.",
"types": "./src/index.d.ts",
"publishConfig": {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/utils-common",
"version": "2.3.1",
"version": "2.4.0",
"description": "Common (Node/Browser) utility functions for Docusaurus packages.",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",

View file

@ -0,0 +1,26 @@
/**
* 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 {getErrorCausalChain} from '../errorUtils';
describe('getErrorCausalChain', () => {
it('works for simple error', () => {
const error = new Error('msg');
expect(getErrorCausalChain(error)).toEqual([error]);
});
it('works for nested errors', () => {
const error = new Error('msg', {
cause: new Error('msg', {cause: new Error('msg')}),
});
expect(getErrorCausalChain(error)).toEqual([
error,
error.cause,
(error.cause as Error).cause,
]);
});
});

View file

@ -0,0 +1,14 @@
/**
* 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.
*/
type CausalChain = [Error, ...Error[]];
export function getErrorCausalChain(error: Error): CausalChain {
if (error.cause) {
return [error, ...getErrorCausalChain(error.cause as Error)];
}
return [error];
}

View file

@ -10,3 +10,4 @@ export {
default as applyTrailingSlash,
type ApplyTrailingSlashParams,
} from './applyTrailingSlash';
export {getErrorCausalChain} from './errorUtils';

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/utils-validation",
"version": "2.3.1",
"version": "2.4.0",
"description": "Node validation utility functions for Docusaurus packages.",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
@ -18,8 +18,8 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/logger": "2.3.1",
"@docusaurus/utils": "2.3.1",
"@docusaurus/logger": "2.4.0",
"@docusaurus/utils": "2.4.0",
"joi": "^17.6.0",
"js-yaml": "^4.1.0",
"tslib": "^2.4.0"

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/utils",
"version": "2.3.1",
"version": "2.4.0",
"description": "Node utility functions for Docusaurus packages.",
"main": "./lib/index.js",
"types": "./lib/index.d.ts",
@ -18,7 +18,7 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/logger": "2.3.1",
"@docusaurus/logger": "2.4.0",
"@svgr/webpack": "^6.2.1",
"escape-string-regexp": "^4.0.0",
"file-loader": "^6.2.0",
@ -39,7 +39,7 @@
"node": ">=16.14"
},
"devDependencies": {
"@docusaurus/types": "2.3.1",
"@docusaurus/types": "2.4.0",
"@types/dedent": "^0.7.0",
"@types/github-slugger": "^1.3.0",
"@types/micromatch": "^4.0.2",

View file

@ -24,6 +24,12 @@ import {
} from '../lib/index.js';
import beforeCli from './beforeCli.mjs';
// Env variables are initialized to dev, but can be overridden by each command
// For example, "docusaurus build" overrides them to "production"
// See also https://github.com/facebook/docusaurus/issues/8599
process.env.BABEL_ENV ??= 'development';
process.env.NODE_ENV ??= 'development';
await beforeCli();
cli.version(DOCUSAURUS_VERSION).usage('<command> [options]');

View file

@ -1,7 +1,7 @@
{
"name": "@docusaurus/core",
"description": "Easy to Maintain Open Source Documentation Websites",
"version": "2.3.1",
"version": "2.4.0",
"license": "MIT",
"publishConfig": {
"access": "public"
@ -43,13 +43,13 @@
"@babel/runtime": "^7.18.6",
"@babel/runtime-corejs3": "^7.18.6",
"@babel/traverse": "^7.18.8",
"@docusaurus/cssnano-preset": "2.3.1",
"@docusaurus/logger": "2.3.1",
"@docusaurus/mdx-loader": "2.3.1",
"@docusaurus/cssnano-preset": "2.4.0",
"@docusaurus/logger": "2.4.0",
"@docusaurus/mdx-loader": "2.4.0",
"@docusaurus/react-loadable": "5.5.2",
"@docusaurus/utils": "2.3.1",
"@docusaurus/utils-common": "2.3.1",
"@docusaurus/utils-validation": "2.3.1",
"@docusaurus/utils": "2.4.0",
"@docusaurus/utils-common": "2.4.0",
"@docusaurus/utils-validation": "2.4.0",
"@slorber/static-site-generator-webpack-plugin": "^4.0.7",
"@svgr/webpack": "^6.2.1",
"autoprefixer": "^10.4.7",
@ -106,8 +106,8 @@
"webpackbar": "^5.0.2"
},
"devDependencies": {
"@docusaurus/module-type-aliases": "2.3.1",
"@docusaurus/types": "2.3.1",
"@docusaurus/module-type-aliases": "2.4.0",
"@docusaurus/types": "2.4.0",
"@types/detect-port": "^1.3.2",
"@types/react-dom": "^18.0.6",
"@types/react-router-config": "^5.0.6",

View file

@ -32,7 +32,7 @@ function createInlineHtmlBanner(baseUrl: string) {
return `
<div id="${BannerId}" style="border: thick solid red; background-color: rgb(255, 230, 179); margin: 20px; padding: 20px; font-size: 20px;">
<p style="font-weight: bold; font-size: 30px;">Your Docusaurus site did not load properly.</p>
<p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseurl" style="font-weight: bold;">baseUrl configuration</a>.</p>
<p>A very common reason is a wrong site <a href="https://docusaurus.io/docs/docusaurus.config.js/#baseUrl" style="font-weight: bold;">baseUrl configuration</a>.</p>
<p>Current configured baseUrl = <span style="font-weight: bold; color: red;">${baseUrl}</span> ${
baseUrl === '/' ? ' (default value)' : ''
}</p>

View file

@ -11,6 +11,7 @@
import React from 'react';
import Head from '@docusaurus/Head';
import ErrorBoundary from '@docusaurus/ErrorBoundary';
import {getErrorCausalChain} from '@docusaurus/utils-common';
import Layout from '@theme/Layout';
import type {Props} from '@theme/Error';
@ -21,20 +22,38 @@ function ErrorDisplay({error, tryAgain}: Props): JSX.Element {
display: 'flex',
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
height: '50vh',
alignItems: 'flex-start',
minHeight: '100vh',
width: '100%',
maxWidth: '80ch',
fontSize: '20px',
margin: '0 auto',
padding: '1rem',
}}>
<h1 style={{fontSize: '3rem'}}>This page crashed</h1>
<button
type="button"
onClick={tryAgain}
style={{
margin: '1rem 0',
fontSize: '2rem',
cursor: 'pointer',
borderRadius: 20,
padding: '1rem',
}}>
<h1>This page crashed.</h1>
<p>{error.message}</p>
<button type="button" onClick={tryAgain}>
Try again
</button>
<ErrorBoundaryError error={error} />
</div>
);
}
function ErrorBoundaryError({error}: {error: Error}): JSX.Element {
const causalChain = getErrorCausalChain(error);
const fullMessage = causalChain.map((e) => e.message).join('\n\nCause:\n');
return <p style={{whiteSpace: 'pre-wrap'}}>{fullMessage}</p>;
}
export default function Error({error, tryAgain}: Props): JSX.Element {
// We wrap the error in its own error boundary because the layout can actually
// throw too... Only the ErrorDisplay component is simple enough to be

View file

@ -46,6 +46,10 @@ export async function build(
// See https://github.com/facebook/docusaurus/pull/2496
forceTerminate: boolean = true,
): Promise<string> {
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
process.env.DOCUSAURUS_CURRENT_LOCALE = cliOptions.locale;
const siteDir = await fs.realpath(siteDirParam);
['SIGINT', 'SIGTERM'].forEach((sig) => {
@ -117,8 +121,11 @@ async function buildLocale({
forceTerminate: boolean;
isLastLocale: boolean;
}): Promise<string> {
process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// Temporary workaround to unlock the ability to translate the site config
// We'll remove it if a better official API can be designed
// See https://github.com/facebook/docusaurus/issues/4542
process.env.DOCUSAURUS_CURRENT_LOCALE = locale;
logger.info`name=${`[${locale}]`} Creating an optimized production build...`;
const props: Props = await load({

View file

@ -39,10 +39,13 @@ export async function start(
siteDirParam: string = '.',
cliOptions: Partial<StartCLIOptions> = {},
): Promise<void> {
// Temporary workaround to unlock the ability to translate the site config
// We'll remove it if a better official API can be designed
// See https://github.com/facebook/docusaurus/issues/4542
process.env.DOCUSAURUS_CURRENT_LOCALE = cliOptions.locale;
const siteDir = await fs.realpath(siteDirParam);
process.env.NODE_ENV = 'development';
process.env.BABEL_ENV = 'development';
logger.info('Starting the development server...');
function loadSite() {

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/eslint-plugin",
"version": "2.3.1",
"version": "2.4.0",
"description": "ESLint plugin to enforce best Docusaurus practices.",
"main": "lib/index.js",
"keywords": [

View file

@ -1,6 +1,6 @@
{
"name": "@docusaurus/lqip-loader",
"version": "2.3.1",
"version": "2.4.0",
"description": "Low Quality Image Placeholders (LQIP) loader for webpack.",
"main": "lib/index.js",
"publishConfig": {
@ -17,7 +17,7 @@
},
"license": "MIT",
"dependencies": {
"@docusaurus/logger": "2.3.1",
"@docusaurus/logger": "2.4.0",
"file-loader": "^6.2.0",
"lodash": "^4.17.21",
"sharp": "^0.30.7",

Some files were not shown because too many files have changed in this diff Show more