Compare commits

...

46 Commits
main ... v2.3.0

Author SHA1 Message Date
sebastienlorber ad477781bd v2.3.0 2023-01-27 16:33:16 +01:00
sebastienlorber 86a85c5ad5 fix swizzle test failures related to https://github.com/facebook/docusaurus/pull/7945 not being backported in practice 2023-01-27 10:56:18 +01:00
sebastienlorber 35a691bb73 chore: fix 2.3 backport tests due to failing test after backport, see also comment https://github.com/facebook/docusaurus/pull/7945#issuecomment-1405287563 2023-01-26 17:42:33 +01:00
Jiří 63ec772b83 fix(theme): add accessible name for the heading hash-link #8562 2023-01-26 17:10:53 +01:00
Matija Sirk c6cdf70a6e feat(theme-translations): default translations for Slovenian (sl-SI) (#8541)
Co-authored-by: Matija Sirk <matija.sirk@kopit.si>
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
2023-01-26 17:07:27 +01:00
Joshua Chen 6d575d1971 fix(algolia): make search footer respect searchPagePath (#8539) 2023-01-26 17:05:41 +01:00
Mariusz Krzaczkowski 61f7d568ae chore(theme-translations): complete pl translations #8525 2023-01-26 17:05:14 +01:00
Joshua Chen 41d0043fd7 fix(core): avoid hash collision when generating chunk names (#8538) 2023-01-26 17:02:12 +01:00
dependabot[bot] 74fc82289c chore(deps): bump json5 from 1.0.1 to 1.0.2 (#8502)
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
2023-01-26 16:46:05 +01:00
Lane Goolsby 003729e9fe feat(plugin-google-tag-manager): add new google-tag-manager plugin + deprecate google-analytics plugin #8470 2023-01-26 16:42:29 +01:00
Riccardo 704365c00b fix(theme-classic) extract HomeBreadcrumbItem + fix swizzle bugs (#8445)
Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
2023-01-26 16:39:14 +01:00
John Reilly 25a4ec345d feat(blog): add options.createFeedItems to filter/limit/transform feed items (#8378)
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
2023-01-26 16:39:00 +01:00
mturoci 30573dd7ab fix(search-algolia): pass custom transformItems function to SearchBar (#8462)
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
closes undefined
Closes https://github.com/facebook/docusaurus/pull/8462
Closes https://github.com/facebook/docusaurus/issues/8461
2023-01-26 16:38:49 +01:00
Sébastien Lorber 266209f265 fix(theme): refactor Tabs, make groupId + queryString work fine together (#8486) 2023-01-26 16:38:05 +01:00
Thomas.CA 70bfaae2b3 fix(core): explicitly define CopyWebpackPlugin toType: 'dir' (#8481)
closes undefined
2023-01-26 16:37:56 +01:00
Dongjoon Lee f3507e0505 fix(theme-classic): content container grow to take all the available space (#8463)
fix https://github.com/facebook/docusaurus/issues/8369
fix https://github.com/facebook/docusaurus/pull/8426
2023-01-26 16:37:18 +01:00
sebastienlorber deb376e4a6 feat(theme-algolia): add option.replaceSearchResultPathname to process/replaceAll search result urls
#8428
2023-01-26 16:36:26 +01:00
Nguyễn Thành Nam e5b0707fab fix(theme-translations): complete Vietnamese theme translations #8450 2023-01-26 16:25:23 +01:00
宋锦丰 6aecc23d62 fix(translations): complete Chinese theme translations (#8423) 2023-01-26 16:22:58 +01:00
mturoci 78d5a53c35 feat(theme-classic): store selected tab in query string. (#8225)
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
Closes https://github.com/facebook/docusaurus/issues/7008
2023-01-26 16:19:44 +01:00
Sébastien Lorber cc95fb635f fix(translations): typo in lastUpdatedAtBy Vietnamese translation (#8424) 2023-01-26 16:19:36 +01:00
Lachlan Heywood 3eb866a7fe feat(eslint-plugin): add plugin to exported configs (#8281)
Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
closes undefined
Closes https://github.com/facebook/docusaurus/issues/8280
2023-01-26 16:16:23 +01:00
Sadegh Karimi 9547b05f90 fix(translations): complete farsi theme translations #8406 2023-01-26 16:15:41 +01:00
Robert Lawrence 2d5d7bd951 fix(theme): add missing aria-labels to the main and sidebar navs #8366 2023-01-26 16:14:38 +01:00
John Reilly 5cf826ad12 fix(content-blog): blog Atom feed id + RSS feed guid should be fully qualified urls (#8381)
Closes https://github.com/facebook/docusaurus/issues/8380
2023-01-26 16:13:23 +01:00
Frieder Bluemle 1ff378da24 feat(core): deploy CLI - add support for git url "insteadOf": use 'remote get-url' to determine source repo url (#8397) 2023-01-26 16:12:56 +01:00
Danny Kim d20d144154 fix(theme): preserve sidebar height on collapse (#8328) 2023-01-26 16:12:35 +01:00
Balthasar Hofer 3f55453b8c fix(mdx-loader): support nested admonitions #8303 2023-01-26 16:12:05 +01:00
Denis Al-Khelali cf3ec180c2 fix(content-docs): add trailing slash to contentDirs, before passing it to isMDXPartial (#8275) 2023-01-26 16:07:28 +01:00
Josh Goldberg 8ef6e623ac fix(utils): allow partially backticked markdown h1 contentTitles (#8314) 2023-01-26 16:07:05 +01:00
Muhammad Hammad 029417154c fix(core): normalize input for poll option (#8342)
Fixes https://github.com/facebook/docusaurus/issues/8306
2023-01-26 16:06:46 +01:00
Josh Goldberg 5d2dd9b6b4 fix(theme): forward className prop in theme-classic's Heading (#8350)
Fixes https://github.com/facebook/docusaurus/issues/8327
2023-01-26 16:06:23 +01:00
Sébastien Lorber 21ad8832b3 fix(mermaid): fix Mermaid integration for v9.2 release
#8282
2023-01-26 16:05:20 +01:00
Stefan Norberg a5a1949e67 fix(theme-translations): complete Swedish theme translations (#8312)
Co-authored-by: stnor <stefan@selessia.com>
2023-01-26 15:52:31 +01:00
AHMET BAYHAN BAYRAMOGLU b82c31bd71 fix(theme-translations): complete Turkish theme translations #8289 2023-01-26 15:51:57 +01:00
Sébastien Lorber d531e500ab fix(create-docusaurus): improve init template misleading doc + add Docuaurus social card (#8279) 2023-01-26 15:14:30 +01:00
Sébastien Lorber de972142a8
chore: backport retro compatible commits for the Docusaurus v2.2 release (#8264)
Co-authored-by: Jan Peer Stoecklmair <jan.peer.stoecklmair@dynatrace.com>
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: LittleboyHarry <littleboyharry@qq.com>
Co-authored-by: Mikey O'Toole <mikey@homotechsual.dev>
Co-authored-by: Jan Peer Stöcklmair <jan.oster94@gmail.com>
Co-authored-by: Nguyễn Thành Nam <namnguyenthanh.work@gmail.com>
Co-authored-by: Sanjaiyan Parthipan <parthipankalayini@gmail.com>
Co-authored-by: Ramazan SANCAR <ramazansancar4545@gmail.com>
Co-authored-by: mturoci <64769322+mturoci@users.noreply.github.com>
Co-authored-by: Adnan Hashmi <56730784+adnanhashmi09@users.noreply.github.com>
Co-authored-by: Pranav Joglekar <pranav2000joglekar@gmail.com>
Co-authored-by: forgeRW <20483211+forgeRW@users.noreply.github.com>
Co-authored-by: Masahiko Hara <pasora@sfc.wide.ad.jp>
Co-authored-by: Johan Fagerberg <johanringmann@gmail.com>
Co-authored-by: John Reilly <johnny_reilly@hotmail.com>
Co-authored-by: Sam Wall <oss@samuelwall.co.uk>
Co-authored-by: Jeferson S. Brito <30840709+jeferson-sb@users.noreply.github.com>
Co-authored-by: evan <evanmccarthy@outlook.com>
Co-authored-by: Xabier Lahuerta Vazquez <xlahuerta@protonmail.com>
Co-authored-by: Forresst <forresst17@gmail.com>
Co-authored-by: Shanmughapriyan S <priyanshan03@gmail.com>
Co-authored-by: Alexey Pyltsyn <lex61rus@gmail.com>
2022-10-29 15:13:42 +02:00
Sébastien Lorber 7743aa6307
chore: release Docusaurus v2.1.0 (#8040) 2022-09-02 12:41:55 +02:00
Sébastien Lorber 26d2b9a018
chore: backport retro compatible commits for the Docusaurus v2.1 release (#8033)
Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
Co-authored-by: Joshua Chen <sidachen2003@gmail.com>
Co-authored-by: Sébastien Lorber <slorber@users.noreply.github.com>
Co-authored-by: whiteand <andrewbeletskiy@gmail.com>
Co-authored-by: yzhe819 <68207314+yzhe819@users.noreply.github.com>
Co-authored-by: Ngô Quốc Đạt <56961917+datlechin@users.noreply.github.com>
Co-authored-by: Kevin Østerkilde <kevin@oesterkilde.dk>
Co-authored-by: Bagdasar Ovsepyan <66012777+b-ovsepian@users.noreply.github.com>
Co-authored-by: Yoni Chechik <chechik.yoni@gmail.com>
Co-authored-by: adventure-yunfei <adventure.yunfei@gmail.com>
Co-authored-by: Morgane Dubus <30866152+mdubus@users.noreply.github.com>
2022-09-02 12:20:33 +02:00
Sébastien Lorber bb65b5c578
chore: release v2.0.1 (#7919) 2022-08-08 16:23:27 +02:00
Sébastien Lorber 2ef40c2598
chore: Netlify branch deploys should only deploy default locale "en" (#7788) 2022-07-15 12:45:08 +02:00
Sébastien Lorber d88f248180
chore: add Netlify config for major version branch deploys (docusaurus-v2 branch) (#7787) 2022-07-15 12:10:36 +02:00
sebastienlorber e4fc47bec2 Merge branch 'main' into docusaurus-v2 2022-07-14 19:51:47 +02:00
Sébastien Lorber e78a15eeba
chore: ci tests should run on version branches "docusaurus-vX" (#7783) 2022-07-14 19:18:46 +02:00
Sébastien Lorber c751bc64ea
chore: regen v2.0.0-rc.1 examples (#7780) 2022-07-14 18:46:12 +02:00
Sébastien Lorber d255389e48
chore: prepare v2.0.0-rc.1 release (#7778) 2022-07-14 18:17:25 +02:00
302 changed files with 5709 additions and 1482 deletions

View File

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

View File

@ -8,7 +8,7 @@
set -euo pipefail set -euo pipefail
CUSTOM_REGISTRY_URL="http://localhost:4873" CUSTOM_REGISTRY_URL="http://localhost:4873"
NEW_VERSION="$(node -p "require('./packages/docusaurus/package.json').version").NEW" NEW_VERSION="$(node -p "require('./packages/docusaurus/package.json').version")-NEW"
CONTAINER_NAME="verdaccio" CONTAINER_NAME="verdaccio"
EXTRA_OPTS="" EXTRA_OPTS=""

View File

@ -1,5 +1,5 @@
{ {
"version": "2.0.0-rc.1", "version": "2.3.0",
"npmClient": "yarn", "npmClient": "yarn",
"useWorkspaces": true, "useWorkspaces": true,
"changelog": { "changelog": {

View File

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

View File

@ -456,8 +456,10 @@ export default async function init(
reqTemplate?: string, reqTemplate?: string,
cliOptions: CLIOptions = {}, cliOptions: CLIOptions = {},
): Promise<void> { ): Promise<void> {
const templates = await readTemplates(); const [templates, siteName] = await Promise.all([
const siteName = await getSiteName(reqName, rootDir); readTemplates(),
getSiteName(reqName, rootDir),
]);
const dest = path.resolve(rootDir, siteName); const dest = path.resolve(rootDir, siteName);
const source = await getSource(reqTemplate, templates, cliOptions); const source = await getSource(reqTemplate, templates, cliOptions);

View File

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

View File

@ -8,17 +8,22 @@ const darkCodeTheme = require('prism-react-renderer/themes/dracula');
const config = { const config = {
title: 'My Site', title: 'My Site',
tagline: 'Dinosaurs are cool', tagline: 'Dinosaurs are cool',
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico', favicon: 'img/favicon.ico',
// Set the production url of your site here
url: 'https://your-docusaurus-test-site.com',
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/',
// GitHub pages deployment config. // GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these. // If you aren't using GitHub pages, you don't need these.
organizationName: 'facebook', // Usually your GitHub org/user name. organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name. projectName: 'docusaurus', // Usually your repo name.
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
// Even if you don't use internalization, you can use this field to set useful // Even if you don't use internalization, you can use this field to set useful
// metadata like html lang. For example, if your site is Chinese, you may want // metadata like html lang. For example, if your site is Chinese, you may want
// to replace "en" with "zh-Hans". // to replace "en" with "zh-Hans".
@ -56,6 +61,8 @@ const config = {
themeConfig: themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */ /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({ ({
// Replace with your project's social card
image: 'img/docusaurus-social-card.jpg',
navbar: { navbar: {
title: 'My Site', title: 'My Site',
logo: { logo: {

View File

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

View File

@ -13,17 +13,22 @@
const config = { const config = {
title: 'My Site', title: 'My Site',
tagline: 'The tagline of my site', tagline: 'The tagline of my site',
url: 'https://your-docusaurus-test-site.com',
baseUrl: '/',
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
favicon: 'img/favicon.ico', favicon: 'img/favicon.ico',
// Set the production url of your site here
url: 'https://your-docusaurus-test-site.com',
// Set the /<baseUrl>/ pathname under which your site is served
// For GitHub pages deployment, it is often '/<projectName>/'
baseUrl: '/',
// GitHub pages deployment config. // GitHub pages deployment config.
// If you aren't using GitHub pages, you don't need these. // If you aren't using GitHub pages, you don't need these.
organizationName: 'facebook', // Usually your GitHub org/user name. organizationName: 'facebook', // Usually your GitHub org/user name.
projectName: 'docusaurus', // Usually your repo name. projectName: 'docusaurus', // Usually your repo name.
onBrokenLinks: 'throw',
onBrokenMarkdownLinks: 'warn',
presets: [ presets: [
[ [
'classic', 'classic',
@ -53,6 +58,7 @@ const config = {
themeConfig: themeConfig:
/** @type {import('@docusaurus/preset-classic').ThemeConfig} */ /** @type {import('@docusaurus/preset-classic').ThemeConfig} */
({ ({
image: 'img/docusaurus-social-card.jpg',
navbar: { navbar: {
title: 'My Meta Project', title: 'My Meta Project',
logo: { logo: {

View File

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

View File

@ -25,10 +25,12 @@ module.exports = {
// But you can create a sidebar manually // But you can create a sidebar manually
/* /*
tutorialSidebar: [ tutorialSidebar: [
'intro',
'hello',
{ {
type: 'category', type: 'category',
label: 'Tutorial', label: 'Tutorial',
items: ['hello'], items: ['tutorial-basics/create-a-document'],
}, },
], ],
*/ */

View File

@ -14,7 +14,9 @@ Anything **unclear** or **buggy** in this tutorial? [Please report it!](https://
## What's next? ## What's next?
- Read the [official documentation](https://docusaurus.io/). - Read the [official documentation](https://docusaurus.io/)
- Modify your site configuration with [`docusaurus.config.js`](https://docusaurus.io/docs/api/docusaurus-config)
- Add navbar and footer items with [`themeConfig`](https://docusaurus.io/docs/api/themes/configuration)
- Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout) - Add a custom [Design and Layout](https://docusaurus.io/docs/styling-layout)
- Add a [search bar](https://docusaurus.io/docs/search) - Add a [search bar](https://docusaurus.io/docs/search)
- Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase) - Find inspirations in the [Docusaurus showcase](https://docusaurus.io/showcase)

View File

@ -44,11 +44,13 @@ It is also possible to create your sidebar explicitly in `sidebars.js`:
```js title="sidebars.js" ```js title="sidebars.js"
module.exports = { module.exports = {
tutorialSidebar: [ tutorialSidebar: [
'intro',
// highlight-next-line
'hello',
{ {
type: 'category', type: 'category',
label: 'Tutorial', label: 'Tutorial',
// highlight-next-line items: ['tutorial-basics/create-a-document'],
items: ['hello'],
}, },
], ],
}; };

View File

@ -51,7 +51,11 @@ You can use absolute paths to reference images in the static directory (`static/
![Docusaurus logo](/img/docusaurus.png) ![Docusaurus logo](/img/docusaurus.png)
You can reference images relative to the current file as well, as shown in [the extra guides](../tutorial-extras/manage-docs-versions.md). You can reference images relative to the current file as well. This is particularly useful to colocate images close to the Markdown files using them:
```md
![Docusaurus logo](./img/docusaurus.png)
```
## Code Blocks ## Code Blocks

View File

@ -19,10 +19,12 @@ const sidebars = {
// But you can create a sidebar manually // But you can create a sidebar manually
/* /*
tutorialSidebar: [ tutorialSidebar: [
'intro',
'hello',
{ {
type: 'category', type: 'category',
label: 'Tutorial', label: 'Tutorial',
items: ['hello'], items: ['tutorial-basics/create-a-document'],
}, },
], ],
*/ */

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

View File

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

View File

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

View File

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

View File

@ -22,8 +22,10 @@ import toc from './remark/toc';
import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks'; import unwrapMdxCodeBlocks from './remark/unwrapMdxCodeBlocks';
import transformImage from './remark/transformImage'; import transformImage from './remark/transformImage';
import transformLinks from './remark/transformLinks'; import transformLinks from './remark/transformLinks';
import mermaid from './remark/mermaid';
import transformAdmonitions from './remark/admonitions'; import transformAdmonitions from './remark/admonitions';
import type {MarkdownConfig} from '@docusaurus/types';
import type {LoaderContext} from 'webpack'; import type {LoaderContext} from 'webpack';
import type {Processor, Plugin} from 'unified'; import type {Processor, Plugin} from 'unified';
import type {AdmonitionOptions} from './remark/admonitions'; import type {AdmonitionOptions} from './remark/admonitions';
@ -61,6 +63,7 @@ export type MDXOptions = {
}; };
export type Options = Partial<MDXOptions> & { export type Options = Partial<MDXOptions> & {
markdownConfig: MarkdownConfig;
staticDirs: string[]; staticDirs: string[];
siteDir: string; siteDir: string;
isMDXPartial?: (filePath: string) => boolean; isMDXPartial?: (filePath: string) => boolean;
@ -71,7 +74,6 @@ export type Options = Partial<MDXOptions> & {
frontMatter: {[key: string]: unknown}; frontMatter: {[key: string]: unknown};
metadata: {[key: string]: unknown}; metadata: {[key: string]: unknown};
}) => {[key: string]: unknown}; }) => {[key: string]: unknown};
filepath: string;
}; };
/** /**
@ -171,6 +173,7 @@ export async function mdxLoader(
...(reqOptions.beforeDefaultRemarkPlugins ?? []), ...(reqOptions.beforeDefaultRemarkPlugins ?? []),
...getAdmonitionsPlugins(reqOptions.admonitions ?? false), ...getAdmonitionsPlugins(reqOptions.admonitions ?? false),
...DEFAULT_OPTIONS.remarkPlugins, ...DEFAULT_OPTIONS.remarkPlugins,
...(reqOptions.markdownConfig.mermaid ? [mermaid] : []),
[ [
transformImage, transformImage,
{ {

View File

@ -0,0 +1,10 @@
Test nested Admonitions
::::info **Weather**
On nice days, you can enjoy skiing in the mountains.
:::danger *Storms*
Take care of snowstorms...
:::
::::

View File

@ -42,3 +42,8 @@ exports[`admonitions remark plugin interpolation 1`] = `
"<p>Test admonition with interpolated title/body</p> "<p>Test admonition with interpolated title/body</p>
<admonition type="tip"><mdxAdmonitionTitle>My <code>interpolated</code> <strong>title</strong> &#x3C;button style={{color: "red"}} onClick={() => alert("click")}>test</mdxAdmonitionTitle><p><code>body</code> <strong>interpolated</strong> content</p></admonition>" <admonition type="tip"><mdxAdmonitionTitle>My <code>interpolated</code> <strong>title</strong> &#x3C;button style={{color: "red"}} onClick={() => alert("click")}>test</mdxAdmonitionTitle><p><code>body</code> <strong>interpolated</strong> content</p></admonition>"
`; `;
exports[`admonitions remark plugin nesting 1`] = `
"<p>Test nested Admonitions</p>
<admonition type="info"><mdxAdmonitionTitle><strong>Weather</strong></mdxAdmonitionTitle><p>On nice days, you can enjoy skiing in the mountains.</p><admonition type="danger"><mdxAdmonitionTitle><em>Storms</em></mdxAdmonitionTitle><p>Take care of snowstorms...</p></admonition></admonition>"
`;

View File

@ -50,4 +50,9 @@ describe('admonitions remark plugin', () => {
const result = await processFixture('interpolation'); const result = await processFixture('interpolation');
expect(result).toMatchSnapshot(); expect(result).toMatchSnapshot();
}); });
it('nesting', async () => {
const result = await processFixture('nesting');
expect(result).toMatchSnapshot();
});
}); });

View File

@ -52,9 +52,20 @@ const plugin: Plugin = function plugin(
const options = normalizeOptions(optionsInput); const options = normalizeOptions(optionsInput);
const keywords = Object.values(options.keywords).map(escapeRegExp).join('|'); const keywords = Object.values(options.keywords).map(escapeRegExp).join('|');
const nestingChar = escapeRegExp(options.tag.slice(0, 1));
const tag = escapeRegExp(options.tag); const tag = escapeRegExp(options.tag);
const regex = new RegExp(`${tag}(${keywords})(?: *(.*))?\n`);
const escapeTag = new RegExp(escapeRegExp(`\\${options.tag}`), 'g'); // resolve th nesting level of an opening tag
// ::: -> 0, :::: -> 1, ::::: -> 2 ...
const nestingLevelRegex = new RegExp(
`^${tag}(?<nestingLevel>${nestingChar}*)`,
);
const regex = new RegExp(`${tag}${nestingChar}*(${keywords})(?: *(.*))?\n`);
const escapeTag = new RegExp(
escapeRegExp(`\\${options.tag}${options.tag.slice(0, 1)}*`),
'g',
);
// The tokenizer is called on blocks to determine if there is an admonition // The tokenizer is called on blocks to determine if there is an admonition
// present and create tags for it // present and create tags for it
@ -77,6 +88,11 @@ const plugin: Plugin = function plugin(
]; ];
const food = []; const food = [];
const content = []; const content = [];
// get the nesting level of the opening tag
const openingLevel =
nestingLevelRegex.exec(opening)!.groups!.nestingLevel!.length;
// used as a stack to keep track of nested admonitions
const nestingLevels: number[] = [openingLevel];
let newValue = value; let newValue = value;
// consume lines until a closing tag // consume lines until a closing tag
@ -88,12 +104,32 @@ const plugin: Plugin = function plugin(
next !== -1 ? newValue.slice(idx + 1, next) : newValue.slice(idx + 1); next !== -1 ? newValue.slice(idx + 1, next) : newValue.slice(idx + 1);
food.push(line); food.push(line);
newValue = newValue.slice(idx + 1); newValue = newValue.slice(idx + 1);
// the closing tag is NOT part of the content const nesting = nestingLevelRegex.exec(line);
if (line.startsWith(options.tag)) { idx = newValue.indexOf(NEWLINE);
break; if (!nesting) {
content.push(line);
continue;
}
const tagLevel = nesting.groups!.nestingLevel!.length;
// first level
if (nestingLevels.length === 0) {
nestingLevels.push(tagLevel);
content.push(line);
continue;
}
const currentLevel = nestingLevels[nestingLevels.length - 1]!;
if (tagLevel < currentLevel) {
// entering a nested admonition block
nestingLevels.push(tagLevel);
} else if (tagLevel === currentLevel) {
// closing a nested admonition block
nestingLevels.pop();
// the closing tag is NOT part of the content
if (nestingLevels.length === 0) {
break;
}
} }
content.push(line); content.push(line);
idx = newValue.indexOf(NEWLINE);
} }
// consume the processed tag and replace escape sequences // consume the processed tag and replace escape sequences

View File

@ -0,0 +1,51 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`mermaid remark plugin does nothing if there's no mermaid code block 1`] = `
"
const layoutProps = {
};
const MDXLayout = "wrapper"
export default function MDXContent({
components,
...props
}) {
return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">
<h1>{\`Heading 1\`}</h1>
<p>{\`No Mermaid diagram :(\`}</p>
<pre><code parentName="pre" {...{
"className": "language-js"
}}>{\`this is not mermaid
\`}</code></pre>
</MDXLayout>;
}
;
MDXContent.isMDXComponent = true;"
`;
exports[`mermaid remark plugin works for basic mermaid code blocks 1`] = `
"
const layoutProps = {
};
const MDXLayout = "wrapper"
export default function MDXContent({
components,
...props
}) {
return <MDXLayout {...layoutProps} {...props} components={components} mdxType="MDXLayout">
<h1>{\`Heading 1\`}</h1>
<mermaid {...{
"value": "graph TD;/n A-->B;/n A-->C;/n B-->D;/n C-->D;"
}}></mermaid>
</MDXLayout>;
}
;
MDXContent.isMDXComponent = true;"
`;

View File

@ -0,0 +1,46 @@
/**
* 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 {createCompiler} from '@mdx-js/mdx';
import mermaid from '..';
describe('mermaid remark plugin', () => {
function createTestCompiler() {
return createCompiler({
remarkPlugins: [mermaid],
});
}
it("does nothing if there's no mermaid code block", async () => {
const mdxCompiler = createTestCompiler();
const result = await mdxCompiler.process(
`# Heading 1
No Mermaid diagram :(
\`\`\`js
this is not mermaid
\`\`\`
`,
);
expect(result.contents).toMatchSnapshot();
});
it('works for basic mermaid code blocks', async () => {
const mdxCompiler = createTestCompiler();
const result = await mdxCompiler.process(`# Heading 1
\`\`\`mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
\`\`\``);
expect(result.contents).toMatchSnapshot();
});
});

View File

@ -0,0 +1,32 @@
/**
* 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 visit from 'unist-util-visit';
import type {Transformer} from 'unified';
import type {Code} from 'mdast';
// TODO: this plugin shouldn't be in the core MDX loader
// After we allow plugins to provide Remark/Rehype plugins (see
// https://github.com/facebook/docusaurus/issues/6370), this should be provided
// by theme-mermaid itself
export default function plugin(): Transformer {
return (root) => {
visit(root, 'code', (node: Code, index, parent) => {
if (node.lang === 'mermaid') {
parent!.children.splice(index, 1, {
type: 'mermaidCodeBlock',
data: {
hName: 'mermaid',
hProperties: {
value: node.value,
},
},
});
}
});
};
}

View File

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

View File

@ -120,7 +120,7 @@ exports[`migration CLI migrates complex website: write 1`] = `
] ]
} }
], ],
"copyright": "Copyright © 2022 Facebook Inc.", "copyright": "Copyright © 2023 Facebook Inc.",
"logo": { "logo": {
"src": "img/docusaurus_monochrome.svg" "src": "img/docusaurus_monochrome.svg"
} }
@ -303,7 +303,7 @@ exports[`migration CLI migrates missing versions: write 1`] = `
] ]
} }
], ],
"copyright": "Copyright © 2022 Facebook Inc.", "copyright": "Copyright © 2023 Facebook Inc.",
"logo": { "logo": {
"src": "img/docusaurus_monochrome.svg" "src": "img/docusaurus_monochrome.svg"
} }
@ -483,7 +483,7 @@ exports[`migration CLI migrates simple website: write 1`] = `
] ]
} }
], ],
"copyright": "Copyright © 2022 Facebook Inc.", "copyright": "Copyright © 2023 Facebook Inc.",
"logo": { "logo": {
"src": "img/docusaurus_monochrome.svg" "src": "img/docusaurus_monochrome.svg"
} }

View File

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

View File

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

View File

@ -1,8 +1,9 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`collectRedirects throw if plugin option redirects contain invalid to paths 1`] = ` exports[`collectRedirects throw if plugin option redirects contain invalid to paths 1`] = `
"You are trying to create client-side redirections to paths that do not exist: "You are trying to create client-side redirections to invalid paths.
- /this/path/does/not/exist2
These paths are redirected to but do not exist:
- /this/path/does/not/exist2 - /this/path/does/not/exist2
Valid paths you can redirect to: Valid paths you can redirect to:
@ -12,6 +13,22 @@ Valid paths you can redirect to:
" "
`; `;
exports[`collectRedirects throw if plugin option redirects contain to paths with mismatching trailing slash 1`] = `
"You are trying to create client-side redirections to invalid paths.
These paths do exist, but because you have explicitly set trailingSlash=false, you need to write the path without trailing slash:
- /someExistingPath/
"
`;
exports[`collectRedirects throw if plugin option redirects contain to paths with mismatching trailing slash 2`] = `
"You are trying to create client-side redirections to invalid paths.
These paths do exist, but because you have explicitly set trailingSlash=true, you need to write the path with trailing slash:
- /someExistingPath
"
`;
exports[`collectRedirects throws if redirect creator creates array of array redirect 1`] = ` exports[`collectRedirects throws if redirect creator creates array of array redirect 1`] = `
"Some created redirects are invalid: "Some created redirects are invalid:
- {"from":["/fromPath"],"to":"/"} => Validation error: "from" must be a string - {"from":["/fromPath"],"to":"/"} => Validation error: "from" must be a string

View File

@ -9,7 +9,7 @@ exports[`createRedirectPageContent encodes uri special chars 1`] = `
<link rel="canonical" href="https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/" /> <link rel="canonical" href="https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/'; window.location.href = 'https://docusaurus.io/gr/%CF%83%CE%B5%CE%BB%CE%B9%CE%B4%CE%B1%CF%82/' + window.location.search + window.location.hash;
</script> </script>
</html>" </html>"
`; `;
@ -23,7 +23,7 @@ exports[`createRedirectPageContent works 1`] = `
<link rel="canonical" href="https://docusaurus.io/" /> <link rel="canonical" href="https://docusaurus.io/" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/'; window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
</script> </script>
</html>" </html>"
`; `;

View File

@ -10,7 +10,7 @@ exports[`toRedirectFiles creates appropriate metadata for empty baseUrl: fileCon
<link rel="canonical" href="/abc" /> <link rel="canonical" href="/abc" />
</head> </head>
<script> <script>
window.location.href = '/abc'; window.location.href = '/abc' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
] ]
@ -26,7 +26,7 @@ exports[`toRedirectFiles creates appropriate metadata for root baseUrl: fileCont
<link rel="canonical" href="/abc" /> <link rel="canonical" href="/abc" />
</head> </head>
<script> <script>
window.location.href = '/abc'; window.location.href = '/abc' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
] ]
@ -42,7 +42,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
<link rel="canonical" href="https://docusaurus.io/abc" /> <link rel="canonical" href="https://docusaurus.io/abc" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/abc'; window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
"<!DOCTYPE html> "<!DOCTYPE html>
@ -53,7 +53,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
<link rel="canonical" href="https://docusaurus.io/def.html" /> <link rel="canonical" href="https://docusaurus.io/def.html" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/def.html'; window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
"<!DOCTYPE html> "<!DOCTYPE html>
@ -64,7 +64,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=false: fileC
<link rel="canonical" href="https://docusaurus.io/" /> <link rel="canonical" href="https://docusaurus.io/" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/'; window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
] ]
@ -80,7 +80,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
<link rel="canonical" href="https://docusaurus.io/abc" /> <link rel="canonical" href="https://docusaurus.io/abc" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/abc'; window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
"<!DOCTYPE html> "<!DOCTYPE html>
@ -91,7 +91,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
<link rel="canonical" href="https://docusaurus.io/def.html" /> <link rel="canonical" href="https://docusaurus.io/def.html" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/def.html'; window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
"<!DOCTYPE html> "<!DOCTYPE html>
@ -102,7 +102,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=true: fileCo
<link rel="canonical" href="https://docusaurus.io/" /> <link rel="canonical" href="https://docusaurus.io/" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/'; window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
] ]
@ -118,7 +118,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
<link rel="canonical" href="https://docusaurus.io/abc" /> <link rel="canonical" href="https://docusaurus.io/abc" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/abc'; window.location.href = 'https://docusaurus.io/abc' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
"<!DOCTYPE html> "<!DOCTYPE html>
@ -129,7 +129,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
<link rel="canonical" href="https://docusaurus.io/def.html" /> <link rel="canonical" href="https://docusaurus.io/def.html" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/def.html'; window.location.href = 'https://docusaurus.io/def.html' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
"<!DOCTYPE html> "<!DOCTYPE html>
@ -140,7 +140,7 @@ exports[`toRedirectFiles creates appropriate metadata trailingSlash=undefined: f
<link rel="canonical" href="https://docusaurus.io/" /> <link rel="canonical" href="https://docusaurus.io/" />
</head> </head>
<script> <script>
window.location.href = 'https://docusaurus.io/'; window.location.href = 'https://docusaurus.io/' + window.location.search + window.location.hash;
</script> </script>
</html>", </html>",
] ]

View File

@ -220,6 +220,69 @@ describe('collectRedirects', () => {
).toThrowErrorMatchingSnapshot(); ).toThrowErrorMatchingSnapshot();
}); });
it('tolerates mismatched trailing slash if option is undefined', () => {
expect(
collectRedirects(
createTestPluginContext(
{
redirects: [
{
from: '/someLegacyPath',
to: '/somePath',
},
],
},
['/', '/somePath/'],
{trailingSlash: undefined},
),
undefined,
),
).toEqual([
{
from: '/someLegacyPath',
to: '/somePath',
},
]);
});
it('throw if plugin option redirects contain to paths with mismatching trailing slash', () => {
expect(() =>
collectRedirects(
createTestPluginContext(
{
redirects: [
{
from: '/someLegacyPath',
to: '/someExistingPath/',
},
],
},
['/', '/someExistingPath', '/anotherExistingPath'],
{trailingSlash: false},
),
undefined,
),
).toThrowErrorMatchingSnapshot();
expect(() =>
collectRedirects(
createTestPluginContext(
{
redirects: [
{
from: '/someLegacyPath',
to: '/someExistingPath',
},
],
},
['/', '/someExistingPath/', '/anotherExistingPath/'],
{trailingSlash: true},
),
undefined,
),
).toThrowErrorMatchingSnapshot();
});
it('collects redirects with custom redirect creator', () => { it('collects redirects with custom redirect creator', () => {
expect( expect(
collectRedirects( collectRedirects(

View File

@ -7,6 +7,7 @@
import _ from 'lodash'; import _ from 'lodash';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
import {addTrailingSlash, removeTrailingSlash} from '@docusaurus/utils';
import {applyTrailingSlash} from '@docusaurus/utils-common'; import {applyTrailingSlash} from '@docusaurus/utils-common';
import { import {
createFromExtensionsRedirects, createFromExtensionsRedirects,
@ -80,16 +81,59 @@ function validateCollectedRedirects(
const allowedToPaths = pluginContext.relativeRoutesPaths; const allowedToPaths = pluginContext.relativeRoutesPaths;
const toPaths = redirects.map((redirect) => redirect.to); const toPaths = redirects.map((redirect) => redirect.to);
const illegalToPaths = _.difference(toPaths, allowedToPaths); const trailingSlashConfig = pluginContext.siteConfig.trailingSlash;
if (illegalToPaths.length > 0) { // Key is the path, value is whether a valid toPath with a different trailing
throw new Error( // slash exists; if the key doesn't exist it means it's valid
`You are trying to create client-side redirections to paths that do not exist: const differByTrailSlash = new Map(toPaths.map((path) => [path, false]));
- ${illegalToPaths.join('\n- ')} allowedToPaths.forEach((toPath) => {
if (differByTrailSlash.has(toPath)) {
differByTrailSlash.delete(toPath);
} else if (differByTrailSlash.has(removeTrailingSlash(toPath))) {
if (trailingSlashConfig === true) {
differByTrailSlash.set(removeTrailingSlash(toPath), true);
} else {
differByTrailSlash.delete(removeTrailingSlash(toPath));
}
} else if (differByTrailSlash.has(addTrailingSlash(toPath))) {
if (trailingSlashConfig === false) {
differByTrailSlash.set(addTrailingSlash(toPath), true);
} else {
differByTrailSlash.delete(addTrailingSlash(toPath));
}
}
});
if (differByTrailSlash.size > 0) {
console.log(differByTrailSlash);
const errors = Array.from(differByTrailSlash.entries());
let message =
'You are trying to create client-side redirections to invalid paths.\n';
const [trailingSlashIssues, invalidPaths] = _.partition(
errors,
([, differ]) => differ,
);
if (trailingSlashIssues.length) {
message += `
These paths do exist, but because you have explicitly set trailingSlash=${trailingSlashConfig}, you need to write the path ${
trailingSlashConfig ? 'with trailing slash' : 'without trailing slash'
}:
- ${trailingSlashIssues.map(([p]) => p).join('\n- ')}
`;
}
if (invalidPaths.length) {
message += `
These paths are redirected to but do not exist:
- ${invalidPaths.map(([p]) => p).join('\n- ')}
Valid paths you can redirect to: Valid paths you can redirect to:
- ${allowedToPaths.join('\n- ')} - ${allowedToPaths.join('\n- ')}
`, `;
); }
throw new Error(message);
} }
} }

View File

@ -14,7 +14,7 @@ export default `
<link rel="canonical" href="<%= it.toUrl %>" /> <link rel="canonical" href="<%= it.toUrl %>" />
</head> </head>
<script> <script>
window.location.href = '<%= it.toUrl %>'; window.location.href = '<%= it.toUrl %>' + window.location.search + window.location.hash;
</script> </script>
</html> </html>
`; `;

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/plugin-content-blog", "name": "@docusaurus/plugin-content-blog",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Blog plugin for Docusaurus.", "description": "Blog plugin for Docusaurus.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "src/plugin-content-blog.d.ts", "types": "src/plugin-content-blog.d.ts",
@ -18,13 +18,13 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/logger": "2.0.0-rc.1", "@docusaurus/logger": "2.3.0",
"@docusaurus/mdx-loader": "2.0.0-rc.1", "@docusaurus/mdx-loader": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils": "2.0.0-rc.1", "@docusaurus/utils": "2.3.0",
"@docusaurus/utils-common": "2.0.0-rc.1", "@docusaurus/utils-common": "2.3.0",
"@docusaurus/utils-validation": "2.0.0-rc.1", "@docusaurus/utils-validation": "2.3.0",
"cheerio": "^1.0.0-rc.12", "cheerio": "^1.0.0-rc.12",
"feed": "^4.2.2", "feed": "^4.2.2",
"fs-extra": "^10.1.0", "fs-extra": "^10.1.0",
@ -35,10 +35,6 @@
"utility-types": "^3.10.0", "utility-types": "^3.10.0",
"webpack": "^5.73.0" "webpack": "^5.73.0"
}, },
"devDependencies": {
"@docusaurus/types": "2.0.0-beta.21",
"escape-string-regexp": "^4.0.0"
},
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4 || ^17.0.0", "react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0" "react-dom": "^16.8.4 || ^17.0.0"

File diff suppressed because one or more lines are too long

View File

@ -143,4 +143,56 @@ describe.each(['atom', 'rss', 'json'])('%s', (feedType) => {
).toMatchSnapshot(); ).toMatchSnapshot();
fsMock.mockClear(); fsMock.mockClear();
}); });
it('filters to the first two entries', async () => {
const siteDir = path.join(__dirname, '__fixtures__', 'website');
const outDir = path.join(siteDir, 'build-snap');
const siteConfig = {
title: 'Hello',
baseUrl: '/myBaseUrl/',
url: 'https://docusaurus.io',
favicon: 'image/favicon.ico',
};
// Build is quite difficult to mock, so we built the blog beforehand and
// copied the output to the fixture...
await testGenerateFeeds(
{
siteDir,
siteConfig,
i18n: DefaultI18N,
outDir,
} as LoadContext,
{
path: 'blog',
routeBasePath: 'blog',
tagsBasePath: 'tags',
authorsMapPath: 'authors.yml',
include: DEFAULT_OPTIONS.include,
exclude: DEFAULT_OPTIONS.exclude,
feedOptions: {
type: [feedType],
copyright: 'Copyright',
createFeedItems: async (params) => {
const {blogPosts, defaultCreateFeedItems, ...rest} = params;
const blogPostsFiltered = blogPosts.filter(
(item, index) => index < 2,
);
return defaultCreateFeedItems({
blogPosts: blogPostsFiltered,
...rest,
});
},
},
readingTime: ({content, defaultReadingTime}) =>
defaultReadingTime({content}),
truncateMarker: /<!--\s*truncate\s*-->/,
} as PluginOptions,
);
expect(
fsMock.mock.calls.map((call) => call[1] as string),
).toMatchSnapshot();
fsMock.mockClear();
});
}); });

View File

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import escapeStringRegexp from 'escape-string-regexp'; import {escapeRegexp} from '@docusaurus/utils';
import {validateBlogPostFrontMatter} from '../frontMatter'; import {validateBlogPostFrontMatter} from '../frontMatter';
import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog'; import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog';
@ -57,7 +57,7 @@ function testField(params: {
} catch (err) { } catch (err) {
// eslint-disable-next-line jest/no-conditional-expect // eslint-disable-next-line jest/no-conditional-expect
expect((err as Error).message).toMatch( expect((err as Error).message).toMatch(
new RegExp(escapeStringRegexp(message)), new RegExp(escapeRegexp(message)),
); );
} }
}); });

View File

@ -8,7 +8,7 @@
import path from 'path'; import path from 'path';
import fs from 'fs-extra'; import fs from 'fs-extra';
import logger from '@docusaurus/logger'; import logger from '@docusaurus/logger';
import {Feed, type Author as FeedAuthor, type Item as FeedItem} from 'feed'; import {Feed, type Author as FeedAuthor} from 'feed';
import {normalizeUrl, readOutputHTMLFile} from '@docusaurus/utils'; import {normalizeUrl, readOutputHTMLFile} from '@docusaurus/utils';
import {blogPostContainerID} from '@docusaurus/utils-common'; import {blogPostContainerID} from '@docusaurus/utils-common';
import {load as cheerioLoad} from 'cheerio'; import {load as cheerioLoad} from 'cheerio';
@ -18,6 +18,7 @@ import type {
PluginOptions, PluginOptions,
Author, Author,
BlogPost, BlogPost,
BlogFeedItem,
} from '@docusaurus/plugin-content-blog'; } from '@docusaurus/plugin-content-blog';
async function generateBlogFeed({ async function generateBlogFeed({
@ -54,14 +55,39 @@ async function generateBlogFeed({
copyright: feedOptions.copyright, copyright: feedOptions.copyright,
}); });
const createFeedItems =
options.feedOptions.createFeedItems ?? defaultCreateFeedItems;
const feedItems = await createFeedItems({
blogPosts,
siteConfig,
outDir,
defaultCreateFeedItems,
});
feedItems.forEach(feed.addItem);
return feed;
}
async function defaultCreateFeedItems({
blogPosts,
siteConfig,
outDir,
}: {
blogPosts: BlogPost[];
siteConfig: DocusaurusConfig;
outDir: string;
}): Promise<BlogFeedItem[]> {
const {url: siteUrl} = siteConfig;
function toFeedAuthor(author: Author): FeedAuthor { function toFeedAuthor(author: Author): FeedAuthor {
return {name: author.name, link: author.url, email: author.email}; return {name: author.name, link: author.url, email: author.email};
} }
await Promise.all( return Promise.all(
blogPosts.map(async (post) => { blogPosts.map(async (post) => {
const { const {
id,
metadata: { metadata: {
title: metadataTitle, title: metadataTitle,
permalink, permalink,
@ -79,10 +105,11 @@ async function generateBlogFeed({
); );
const $ = cheerioLoad(content); const $ = cheerioLoad(content);
const feedItem: FeedItem = { const link = normalizeUrl([siteUrl, permalink]);
const feedItem: BlogFeedItem = {
title: metadataTitle, title: metadataTitle,
id, id: link,
link: normalizeUrl([siteUrl, permalink]), link,
date, date,
description, description,
// Atom feed demands the "term", while other feeds use "name" // Atom feed demands the "term", while other feeds use "name"
@ -99,9 +126,7 @@ async function generateBlogFeed({
return feedItem; return feedItem;
}), }),
).then((items) => items.forEach(feed.addItem)); );
return feed;
} }
async function createBlogFeedFile({ async function createBlogFeedFile({

View File

@ -455,6 +455,7 @@ export default async function pluginContentBlog(
(author) => author.imageURL, (author) => author.imageURL,
), ),
}), }),
markdownConfig: siteConfig.markdown,
}, },
}, },
{ {

View File

@ -124,6 +124,7 @@ const PluginOptionSchema = Joi.object<PluginOptions>({
.default(DEFAULT_OPTIONS.feedOptions.copyright), .default(DEFAULT_OPTIONS.feedOptions.copyright),
}), }),
language: Joi.string(), language: Joi.string(),
createFeedItems: Joi.function(),
}).default(DEFAULT_OPTIONS.feedOptions), }).default(DEFAULT_OPTIONS.feedOptions),
authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath), authorsMapPath: Joi.string().default(DEFAULT_OPTIONS.authorsMapPath),
readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime), readingTime: Joi.function().default(() => DEFAULT_OPTIONS.readingTime),

View File

@ -9,12 +9,19 @@ declare module '@docusaurus/plugin-content-blog' {
import type {LoadedMDXContent} from '@docusaurus/mdx-loader'; import type {LoadedMDXContent} from '@docusaurus/mdx-loader';
import type {MDXOptions} from '@docusaurus/mdx-loader'; import type {MDXOptions} from '@docusaurus/mdx-loader';
import type {FrontMatterTag, Tag} from '@docusaurus/utils'; import type {FrontMatterTag, Tag} from '@docusaurus/utils';
import type {Plugin, LoadContext} from '@docusaurus/types'; import type {DocusaurusConfig, Plugin, LoadContext} from '@docusaurus/types';
import type {Item as FeedItem} from 'feed';
import type {Overwrite} from 'utility-types'; import type {Overwrite} from 'utility-types';
export type Assets = { export type Assets = {
/** /**
* If `metadata.image` is a collocated image path, this entry will be the * If `metadata.yarn workspace website typecheck
4
yarn workspace v1.22.19yarn workspace website typecheck
4
yarn workspace v1.22.19yarn workspace website typecheck
4
yarn workspace v1.22.19image` is a collocated image path, this entry will be the
* bundler-generated image path. Otherwise, it's empty, and the image URL * bundler-generated image path. Otherwise, it's empty, and the image URL
* should be accessed through `frontMatter.image`. * should be accessed through `frontMatter.image`.
*/ */
@ -255,6 +262,24 @@ declare module '@docusaurus/plugin-content-blog' {
copyright: string; copyright: string;
/** Language of the feed. */ /** Language of the feed. */
language?: string; language?: string;
/** Allow control over the construction of BlogFeedItems */
createFeedItems?: CreateFeedItemsFn;
};
type DefaultCreateFeedItemsParams = {
blogPosts: BlogPost[];
siteConfig: DocusaurusConfig;
outDir: string;
};
type CreateFeedItemsFn = (
params: CreateFeedItemsParams,
) => Promise<BlogFeedItem[]>;
type CreateFeedItemsParams = DefaultCreateFeedItemsParams & {
defaultCreateFeedItems: (
params: DefaultCreateFeedItemsParams,
) => Promise<BlogFeedItem[]>;
}; };
/** /**
@ -436,6 +461,8 @@ declare module '@docusaurus/plugin-content-blog' {
content: string; content: string;
}; };
export type BlogFeedItem = FeedItem;
export type BlogPaginatedMetadata = { export type BlogPaginatedMetadata = {
/** Title of the entire blog. */ /** Title of the entire blog. */
readonly blogTitle: string; readonly blogTitle: string;

View File

@ -1,10 +1,11 @@
{ {
"name": "@docusaurus/plugin-content-docs", "name": "@docusaurus/plugin-content-docs",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Docs plugin for Docusaurus.", "description": "Docs plugin for Docusaurus.",
"main": "lib/index.js", "main": "lib/index.js",
"sideEffects": false, "sideEffects": false,
"exports": { "exports": {
"./lib/*": "./lib/*",
"./src/*": "./src/*", "./src/*": "./src/*",
"./client": { "./client": {
"type": "./lib/client/index.d.ts", "type": "./lib/client/index.d.ts",
@ -34,13 +35,13 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/logger": "2.0.0-rc.1", "@docusaurus/logger": "2.3.0",
"@docusaurus/mdx-loader": "2.0.0-rc.1", "@docusaurus/mdx-loader": "2.3.0",
"@docusaurus/module-type-aliases": "2.0.0-rc.1", "@docusaurus/module-type-aliases": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils": "2.0.0-rc.1", "@docusaurus/utils": "2.3.0",
"@docusaurus/utils-validation": "2.0.0-rc.1", "@docusaurus/utils-validation": "2.3.0",
"@types/react-router-config": "^5.0.6", "@types/react-router-config": "^5.0.6",
"combine-promises": "^1.1.0", "combine-promises": "^1.1.0",
"fs-extra": "^10.1.0", "fs-extra": "^10.1.0",
@ -52,11 +53,9 @@
"webpack": "^5.73.0" "webpack": "^5.73.0"
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/types": "2.0.0-beta.21",
"@types/js-yaml": "^4.0.5", "@types/js-yaml": "^4.0.5",
"@types/picomatch": "^2.3.0", "@types/picomatch": "^2.3.0",
"commander": "^5.1.0", "commander": "^5.1.0",
"escape-string-regexp": "^4.0.0",
"picomatch": "^2.3.1", "picomatch": "^2.3.1",
"shelljs": "^0.8.5" "shelljs": "^0.8.5"
}, },

View File

@ -901,6 +901,7 @@ exports[`simple website content: data 1`] = `
"label": "Next", "label": "Next",
"banner": null, "banner": null,
"badge": false, "badge": false,
"noIndex": false,
"className": "docs-version-current", "className": "docs-version-current",
"isLast": true, "isLast": true,
"docsSidebars": { "docsSidebars": {
@ -2608,6 +2609,7 @@ exports[`versioned website (community) content: data 1`] = `
"label": "1.0.0", "label": "1.0.0",
"banner": null, "banner": null,
"badge": true, "badge": true,
"noIndex": false,
"className": "docs-version-1.0.0", "className": "docs-version-1.0.0",
"isLast": true, "isLast": true,
"docsSidebars": { "docsSidebars": {
@ -2635,6 +2637,7 @@ exports[`versioned website (community) content: data 1`] = `
"label": "Next", "label": "Next",
"banner": "unreleased", "banner": "unreleased",
"badge": true, "badge": true,
"noIndex": false,
"className": "docs-version-current", "className": "docs-version-current",
"isLast": false, "isLast": false,
"docsSidebars": { "docsSidebars": {
@ -3477,6 +3480,7 @@ exports[`versioned website content: data 1`] = `
"label": "1.0.0", "label": "1.0.0",
"banner": "unmaintained", "banner": "unmaintained",
"badge": true, "badge": true,
"noIndex": false,
"className": "docs-version-1.0.0", "className": "docs-version-1.0.0",
"isLast": false, "isLast": false,
"docsSidebars": { "docsSidebars": {
@ -3544,6 +3548,7 @@ exports[`versioned website content: data 1`] = `
"label": "1.0.1", "label": "1.0.1",
"banner": null, "banner": null,
"badge": true, "badge": true,
"noIndex": true,
"className": "docs-version-1.0.1", "className": "docs-version-1.0.1",
"isLast": true, "isLast": true,
"docsSidebars": { "docsSidebars": {
@ -3599,6 +3604,7 @@ exports[`versioned website content: data 1`] = `
"label": "Next", "label": "Next",
"banner": "unreleased", "banner": "unreleased",
"badge": true, "badge": true,
"noIndex": false,
"className": "docs-version-current", "className": "docs-version-current",
"isLast": false, "isLast": false,
"docsSidebars": { "docsSidebars": {
@ -3674,6 +3680,7 @@ exports[`versioned website content: data 1`] = `
"label": "withSlugs", "label": "withSlugs",
"banner": "unmaintained", "banner": "unmaintained",
"badge": true, "badge": true,
"noIndex": false,
"className": "docs-version-withSlugs", "className": "docs-version-withSlugs",
"isLast": false, "isLast": false,
"docsSidebars": { "docsSidebars": {

View File

@ -93,6 +93,18 @@ function createTestUtils({
}); });
} }
// Makes it easier to assert failure cases
async function getProcessDocFileError(
docFileArg: DocFile | string,
): Promise<Error> {
try {
await processDocFile(docFileArg);
return new Error("unexpected: getProcessDocFileError didn't crash");
} catch (e) {
return e as Error;
}
}
async function testMeta( async function testMeta(
docFileSource: string, docFileSource: string,
expectedMetadata: Optional< expectedMetadata: Optional<
@ -172,7 +184,13 @@ function createTestUtils({
}; };
} }
return {processDocFile, testMeta, testSlug, generateNavigation}; return {
processDocFile,
getProcessDocFileError,
testMeta,
testSlug,
generateNavigation,
};
} }
describe('simple site', () => { describe('simple site', () => {
@ -683,16 +701,21 @@ describe('simple site', () => {
it('docs with invalid id', async () => { it('docs with invalid id', async () => {
const {defaultTestUtils} = await loadSite(); const {defaultTestUtils} = await loadSite();
await expect(async () =>
defaultTestUtils.processDocFile( const error = await defaultTestUtils.getProcessDocFileError(
createFakeDocFile({ createFakeDocFile({
source: 'some/fake/path', source: 'some/fake/path',
frontMatter: { frontMatter: {
id: 'Hello/world', id: 'Hello/world',
}, },
}), }),
), );
).rejects.toThrowErrorMatchingInlineSnapshot(
expect(error.message).toMatchInlineSnapshot(
`"Can't process doc metadata for doc at path path=some/fake/path in version name=current"`,
);
expect(error.cause).toBeDefined();
expect(error.cause!.message).toMatchInlineSnapshot(
`"Document id "Hello/world" cannot include slash."`, `"Document id "Hello/world" cannot include slash."`,
); );
}); });

View File

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import escapeStringRegexp from 'escape-string-regexp'; import {escapeRegexp} from '@docusaurus/utils';
import {validateDocFrontMatter} from '../frontMatter'; import {validateDocFrontMatter} from '../frontMatter';
import type {DocFrontMatter} from '@docusaurus/plugin-content-docs'; import type {DocFrontMatter} from '@docusaurus/plugin-content-docs';
@ -57,7 +57,7 @@ function testField(params: {
} catch (err) { } catch (err) {
// eslint-disable-next-line jest/no-conditional-expect // eslint-disable-next-line jest/no-conditional-expect
expect((err as Error).message).toMatch( expect((err as Error).message).toMatch(
new RegExp(escapeStringRegexp(message)), new RegExp(escapeRegexp(message)),
); );
} }
}); });

View File

@ -362,6 +362,11 @@ describe('versioned website', () => {
options: { options: {
routeBasePath, routeBasePath,
sidebarPath, sidebarPath,
versions: {
'1.0.1': {
noIndex: true,
},
},
}, },
}); });
const plugin = await pluginContentDocs(context, options); const plugin = await pluginContentDocs(context, options);

View File

@ -76,6 +76,7 @@ describe('normalizeDocsPluginOptions', () => {
version1: { version1: {
path: 'hello', path: 'hello',
label: 'world', label: 'world',
noIndex: true,
}, },
}, },
sidebarCollapsible: false, sidebarCollapsible: false,

View File

@ -316,7 +316,7 @@ async function doProcessDocMetadata({
}; };
} }
export function processDocMetadata(args: { export async function processDocMetadata(args: {
docFile: DocFile; docFile: DocFile;
versionMetadata: VersionMetadata; versionMetadata: VersionMetadata;
context: LoadContext; context: LoadContext;
@ -324,10 +324,12 @@ export function processDocMetadata(args: {
env: DocEnv; env: DocEnv;
}): Promise<DocMetadataBase> { }): Promise<DocMetadataBase> {
try { try {
return doProcessDocMetadata(args); return await doProcessDocMetadata(args);
} catch (err) { } catch (err) {
logger.error`Can't process doc metadata for doc at path path=${args.docFile.filePath} in version name=${args.versionMetadata.versionName}`; throw new Error(
throw err; `Can't process doc metadata for doc at path path=${args.docFile.filePath} in version name=${args.versionMetadata.versionName}`,
{cause: err as Error},
);
} }
} }

View File

@ -336,12 +336,13 @@ export default async function pluginContentDocs(
}; };
function createMDXLoaderRule(): RuleSetRule { function createMDXLoaderRule(): RuleSetRule {
const contentDirs = versionsMetadata.flatMap(getContentPathList); const contentDirs = versionsMetadata
.flatMap(getContentPathList)
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator);
return { return {
test: /\.mdx?$/i, test: /\.mdx?$/i,
include: contentDirs include: contentDirs,
// Trailing slash is important, see https://github.com/facebook/docusaurus/pull/3970
.map(addTrailingPathSeparator),
use: [ use: [
getJSLoader({isServer}), getJSLoader({isServer}),
{ {
@ -375,6 +376,7 @@ export default async function pluginContentDocs(
}) => ({ }) => ({
image: frontMatter.image, image: frontMatter.image,
}), }),
markdownConfig: siteConfig.markdown,
}, },
}, },
{ {

View File

@ -59,6 +59,7 @@ const VersionOptionsSchema = Joi.object({
banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(), banner: Joi.string().equal('none', 'unreleased', 'unmaintained').optional(),
badge: Joi.boolean().optional(), badge: Joi.boolean().optional(),
className: Joi.string().optional(), className: Joi.string().optional(),
noIndex: Joi.boolean().optional(),
}); });
const VersionsOptionsSchema = Joi.object() const VersionsOptionsSchema = Joi.object()

View File

@ -125,6 +125,25 @@ declare module '@docusaurus/plugin-content-docs' {
// TODO support custom version banner? // TODO support custom version banner?
// {type: "error", content: "html content"} // {type: "error", content: "html content"}
export type VersionBanner = 'unreleased' | 'unmaintained'; export type VersionBanner = 'unreleased' | 'unmaintained';
export type VersionOptions = {
/**
* The base path of the version, will be appended to `baseUrl` +
* `routeBasePath`.
*/
path?: string;
/** The label of the version to be used in badges, dropdowns, etc. */
label?: string;
/** The banner to show at the top of a doc of that version. */
banner?: 'none' | VersionBanner;
/** Show a badge with the version label at the top of each doc. */
badge?: boolean;
/** Prevents search engines from indexing this version */
noIndex?: boolean;
/** Add a custom class name to the <html> element of each doc. */
className?: string;
};
export type VersionsOptions = { export type VersionsOptions = {
/** /**
* The version navigated to in priority and displayed by default for docs * The version navigated to in priority and displayed by default for docs
@ -144,23 +163,7 @@ declare module '@docusaurus/plugin-content-docs' {
/** Include the current version of your docs. */ /** Include the current version of your docs. */
includeCurrentVersion: boolean; includeCurrentVersion: boolean;
/** Independent customization of each version's properties. */ /** Independent customization of each version's properties. */
versions: { versions: {[versionName: string]: VersionOptions};
[versionName: string]: {
/**
* The base path of the version, will be appended to `baseUrl` +
* `routeBasePath`.
*/
path?: string;
/** The label of the version to be used in badges, dropdowns, etc. */
label?: string;
/** The banner to show at the top of a doc of that version. */
banner?: 'none' | VersionBanner;
/** Show a badge with the version label at the top of each doc. */
badge?: boolean;
/** Add a custom class name to the <html> element of each doc. */
className?: string;
};
};
}; };
export type SidebarOptions = { export type SidebarOptions = {
/** /**
@ -263,6 +266,8 @@ declare module '@docusaurus/plugin-content-docs' {
banner: VersionBanner | null; banner: VersionBanner | null;
/** Show a badge with the version label at the top of each doc. */ /** Show a badge with the version label at the top of each doc. */
badge: boolean; badge: boolean;
/** Prevents search engines from indexing this version */
noIndex: boolean;
/** Add a custom class name to the <html> element of each doc. */ /** Add a custom class name to the <html> element of each doc. */
className: string; className: string;
/** /**
@ -500,7 +505,7 @@ declare module '@docusaurus/plugin-content-docs' {
export type PropVersionMetadata = Pick< export type PropVersionMetadata = Pick<
VersionMetadata, VersionMetadata,
'label' | 'banner' | 'badge' | 'className' | 'isLast' 'label' | 'banner' | 'badge' | 'className' | 'isLast' | 'noIndex'
> & { > & {
/** ID of the docs plugin this version belongs to. */ /** ID of the docs plugin this version belongs to. */
pluginId: string; pluginId: string;

View File

@ -142,6 +142,7 @@ export function toVersionMetadataProp(
label: loadedVersion.label, label: loadedVersion.label,
banner: loadedVersion.banner, banner: loadedVersion.banner,
badge: loadedVersion.badge, badge: loadedVersion.badge,
noIndex: loadedVersion.noIndex,
className: loadedVersion.className, className: loadedVersion.className,
isLast: loadedVersion.isLast, isLast: loadedVersion.isLast,
docsSidebars: toSidebarsProp(loadedVersion), docsSidebars: toSidebarsProp(loadedVersion),

View File

@ -44,6 +44,7 @@ export type SidebarItemLink = SidebarItemBase & {
type: 'link'; type: 'link';
href: string; href: string;
label: string; label: string;
autoAddBaseUrl?: boolean;
}; };
export type SidebarItemAutogenerated = SidebarItemBase & { export type SidebarItemAutogenerated = SidebarItemBase & {

View File

@ -59,6 +59,7 @@ const sidebarItemHtmlSchema = sidebarItemBaseSchema.append<SidebarItemHtml>({
const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({ const sidebarItemLinkSchema = sidebarItemBaseSchema.append<SidebarItemLink>({
type: 'link', type: 'link',
href: URISchema.required(), href: URISchema.required(),
autoAddBaseUrl: Joi.boolean(),
label: Joi.string() label: Joi.string()
.required() .required()
.messages({'any.unknown': '"label" must be a string'}), .messages({'any.unknown': '"label" must be a string'}),

View File

@ -56,6 +56,7 @@ describe('readVersionsMetadata', () => {
path: '/docs', path: '/docs',
banner: null, banner: null,
badge: false, badge: false,
noIndex: false,
className: 'docs-version-current', className: 'docs-version-current',
}; };
return {simpleSiteDir, defaultOptions, defaultContext, vCurrent}; return {simpleSiteDir, defaultOptions, defaultContext, vCurrent};
@ -218,6 +219,7 @@ describe('readVersionsMetadata', () => {
path: '/docs/next', path: '/docs/next',
banner: 'unreleased', banner: 'unreleased',
badge: true, badge: true,
noIndex: false,
className: 'docs-version-current', className: 'docs-version-current',
}; };
@ -242,6 +244,7 @@ describe('readVersionsMetadata', () => {
path: '/docs', path: '/docs',
banner: null, banner: null,
badge: true, badge: true,
noIndex: false,
className: 'docs-version-1.0.1', className: 'docs-version-1.0.1',
}; };
@ -266,6 +269,7 @@ describe('readVersionsMetadata', () => {
path: '/docs/1.0.0', path: '/docs/1.0.0',
banner: 'unmaintained', banner: 'unmaintained',
badge: true, badge: true,
noIndex: false,
className: 'docs-version-1.0.0', className: 'docs-version-1.0.0',
}; };
@ -290,6 +294,7 @@ describe('readVersionsMetadata', () => {
path: '/docs/withSlugs', path: '/docs/withSlugs',
banner: 'unmaintained', banner: 'unmaintained',
badge: true, badge: true,
noIndex: false,
className: 'docs-version-withSlugs', className: 'docs-version-withSlugs',
}; };
@ -657,6 +662,7 @@ describe('readVersionsMetadata', () => {
path: '/communityBasePath/next', path: '/communityBasePath/next',
banner: 'unreleased', banner: 'unreleased',
badge: true, badge: true,
noIndex: false,
className: 'docs-version-current', className: 'docs-version-current',
}; };
@ -681,6 +687,7 @@ describe('readVersionsMetadata', () => {
path: '/communityBasePath', path: '/communityBasePath',
banner: null, banner: null,
badge: true, badge: true,
noIndex: false,
className: 'docs-version-1.0.0', className: 'docs-version-1.0.0',
}; };

View File

@ -122,6 +122,13 @@ export function getVersionBadge({
return options.versions[versionName]?.badge ?? defaultVersionBadge; return options.versions[versionName]?.badge ?? defaultVersionBadge;
} }
export function getVersionNoIndex({
versionName,
options,
}: VersionContext): VersionMetadata['noIndex'] {
return options.versions[versionName]?.noIndex ?? false;
}
function getVersionClassName({ function getVersionClassName({
versionName, versionName,
options, options,
@ -179,6 +186,7 @@ async function createVersionMetadata(
label: getVersionLabel(context), label: getVersionLabel(context),
banner: getVersionBanner(context), banner: getVersionBanner(context),
badge: getVersionBadge(context), badge: getVersionBadge(context),
noIndex: getVersionNoIndex(context),
className: getVersionClassName(context), className: getVersionClassName(context),
path: routePath, path: routePath,
tagsPath: normalizeUrl([routePath, options.tagsBasePath]), tagsPath: normalizeUrl([routePath, options.tagsBasePath]),

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/plugin-content-pages", "name": "@docusaurus/plugin-content-pages",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Pages plugin for Docusaurus.", "description": "Pages plugin for Docusaurus.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "src/plugin-content-pages.d.ts", "types": "src/plugin-content-pages.d.ts",
@ -18,18 +18,15 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/mdx-loader": "2.0.0-rc.1", "@docusaurus/mdx-loader": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils": "2.0.0-rc.1", "@docusaurus/utils": "2.3.0",
"@docusaurus/utils-validation": "2.0.0-rc.1", "@docusaurus/utils-validation": "2.3.0",
"fs-extra": "^10.1.0", "fs-extra": "^10.1.0",
"tslib": "^2.4.0", "tslib": "^2.4.0",
"webpack": "^5.73.0" "webpack": "^5.73.0"
}, },
"devDependencies": {
"@docusaurus/types": "2.0.0-beta.21"
},
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4 || ^17.0.0", "react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0" "react-dom": "^16.8.4 || ^17.0.0"

View File

@ -211,6 +211,7 @@ export default function pluginContentPages(
`${docuHash(aliasedSource)}.json`, `${docuHash(aliasedSource)}.json`,
); );
}, },
markdownConfig: siteConfig.markdown,
}, },
}, },
{ {

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/plugin-debug", "name": "@docusaurus/plugin-debug",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Debug plugin for Docusaurus.", "description": "Debug plugin for Docusaurus.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "src/plugin-debug.d.ts", "types": "src/plugin-debug.d.ts",
@ -20,16 +20,13 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils": "2.0.0-rc.1", "@docusaurus/utils": "2.3.0",
"fs-extra": "^10.1.0", "fs-extra": "^10.1.0",
"react-json-view": "^1.21.3", "react-json-view": "^1.21.3",
"tslib": "^2.4.0" "tslib": "^2.4.0"
}, },
"devDependencies": {
"@docusaurus/types": "2.0.0-beta.21"
},
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4 || ^17.0.0", "react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0" "react-dom": "^16.8.4 || ^17.0.0"

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/plugin-google-analytics", "name": "@docusaurus/plugin-google-analytics",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Global analytics (analytics.js) plugin for Docusaurus.", "description": "Global analytics (analytics.js) plugin for Docusaurus.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
@ -18,14 +18,11 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils-validation": "2.0.0-rc.1", "@docusaurus/utils-validation": "2.3.0",
"tslib": "^2.4.0" "tslib": "^2.4.0"
}, },
"devDependencies": {
"@docusaurus/types": "2.0.0-beta.21"
},
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4 || ^17.0.0", "react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0" "react-dom": "^16.8.4 || ^17.0.0"

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/plugin-google-gtag", "name": "@docusaurus/plugin-google-gtag",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Global Site Tag (gtag.js) plugin for Docusaurus.", "description": "Global Site Tag (gtag.js) plugin for Docusaurus.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
@ -18,14 +18,11 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils-validation": "2.0.0-rc.1", "@docusaurus/utils-validation": "2.3.0",
"tslib": "^2.4.0" "tslib": "^2.4.0"
}, },
"devDependencies": {
"@docusaurus/types": "2.0.0-beta.21"
},
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4 || ^17.0.0", "react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0" "react-dom": "^16.8.4 || ^17.0.0"

View File

@ -0,0 +1,3 @@
.tsbuildinfo*
tsconfig*
__tests__

View File

@ -0,0 +1,7 @@
# `@docusaurus/plugin-google-tag-manager`
Google Tag Manager plugin for Docusaurus.
## Usage
See [plugin-google-tag-manager documentation](https://docusaurus.io/docs/api/plugins/@docusaurus/plugin-google-tag-manager).

View File

@ -0,0 +1,33 @@
{
"name": "@docusaurus/plugin-google-tag-manager",
"version": "2.3.0",
"description": "Google Tag Manager (gtm.js) plugin for Docusaurus.",
"main": "lib/index.js",
"types": "lib/index.d.ts",
"publishConfig": {
"access": "public"
},
"scripts": {
"build": "tsc --build",
"watch": "tsc --build --watch"
},
"repository": {
"type": "git",
"url": "https://github.com/facebook/docusaurus.git",
"directory": "packages/docusaurus-plugin-google-tag-manager"
},
"license": "MIT",
"dependencies": {
"@docusaurus/core": "2.3.0",
"@docusaurus/types": "2.3.0",
"@docusaurus/utils-validation": "2.3.0",
"tslib": "^2.4.0"
},
"peerDependencies": {
"react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0"
},
"engines": {
"node": ">=16.14"
}
}

View File

@ -0,0 +1,78 @@
/**
* 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 {Joi} from '@docusaurus/utils-validation';
import type {
LoadContext,
Plugin,
OptionValidationContext,
} from '@docusaurus/types';
import type {PluginOptions, Options} from './options';
export default function pluginGoogleAnalytics(
context: LoadContext,
options: PluginOptions,
): Plugin {
const {containerId} = options;
const isProd = process.env.NODE_ENV === 'production';
return {
name: 'docusaurus-plugin-google-tag-manager',
contentLoaded({actions}) {
actions.setGlobalData(options);
},
injectHtmlTags() {
if (!isProd) {
return {};
}
return {
preBodyTags: [
{
tagName: 'noscript',
innerHTML: `<iframe src="https://www.googletagmanager.com/ns.html?id=${containerId}" height="0" width="0" style="display:none;visibility:hidden"></iframe>`,
},
],
headTags: [
{
tagName: 'link',
attributes: {
rel: 'preconnect',
href: 'https://www.googletagmanager.com',
},
},
{
tagName: 'script',
innerHTML: `window.dataLayer = window.dataLayer || [];`,
},
{
tagName: 'script',
innerHTML: `(function(w,d,s,l,i){w[l]=w[l]||[];w[l].push({'gtm.start':
new Date().getTime(),event:'gtm.js'});var f=d.getElementsByTagName(s)[0],
j=d.createElement(s),dl=l!='dataLayer'?'&l='+l:'';j.async=true;j.src=
'https://www.googletagmanager.com/gtm.js?id='+i+dl;f.parentNode.insertBefore(j,f);
})(window,document,'script','dataLayer','${containerId}');`,
},
],
};
},
};
}
const pluginOptionsSchema = Joi.object<PluginOptions>({
containerId: Joi.string().required(),
});
export function validateOptions({
validate,
options,
}: OptionValidationContext<Options, PluginOptions>): PluginOptions {
return validate(pluginOptionsSchema, options);
}
export type {PluginOptions, Options};

View File

@ -0,0 +1,12 @@
/**
* 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.
*/
export type PluginOptions = {
containerId: string;
};
export type Options = Partial<PluginOptions>;

View File

@ -0,0 +1,8 @@
/**
* 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.
*/
/// <reference types="@docusaurus/module-type-aliases" />

View File

@ -0,0 +1,15 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"noEmit": false,
"composite": true,
"incremental": true,
"tsBuildInfoFile": "./lib/.tsbuildinfo-client",
"module": "esnext",
"target": "esnext",
"rootDir": "src",
"outDir": "lib"
},
"include": ["src/*.d.ts"],
"exclude": ["**/__tests__/**"]
}

View File

@ -0,0 +1,13 @@
{
"extends": "../../tsconfig.json",
"references": [{"path": "./tsconfig.client.json"}],
"compilerOptions": {
"noEmit": false,
"incremental": true,
"tsBuildInfoFile": "./lib/.tsbuildinfo",
"rootDir": "src",
"outDir": "lib"
},
"include": ["src"],
"exclude": ["**/__tests__/**"]
}

View File

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

View File

@ -81,25 +81,19 @@ function getMessage(icon: IconKey, state: State) {
} }
export default function IdealImage(props: Props): JSX.Element { export default function IdealImage(props: Props): JSX.Element {
const {alt, className, img} = props; const {img, ...propsRest} = props;
// In dev env just use regular img with original file // In dev env just use regular img with original file
if (typeof img === 'string' || 'default' in img) { if (typeof img === 'string' || 'default' in img) {
return ( return (
<img // eslint-disable-next-line jsx-a11y/alt-text
src={typeof img === 'string' ? img : img.default} <img src={typeof img === 'string' ? img : img.default} {...propsRest} />
className={className}
alt={alt}
{...props}
/>
); );
} }
return ( return (
<ReactIdealImage <ReactIdealImage
{...props} {...propsRest}
alt={alt}
className={className}
height={img.src.height ?? 100} height={img.src.height ?? 100}
width={img.src.width ?? 100} width={img.src.width ?? 100}
placeholder={{lqip: img.preSrc}} placeholder={{lqip: img.preSrc}}

View File

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

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/plugin-sitemap", "name": "@docusaurus/plugin-sitemap",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Simple sitemap generation plugin for Docusaurus.", "description": "Simple sitemap generation plugin for Docusaurus.",
"main": "lib/index.js", "main": "lib/index.js",
"types": "lib/index.d.ts", "types": "lib/index.d.ts",
@ -18,19 +18,16 @@
}, },
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/logger": "2.0.0-rc.1", "@docusaurus/logger": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils": "2.0.0-rc.1", "@docusaurus/utils": "2.3.0",
"@docusaurus/utils-common": "2.0.0-rc.1", "@docusaurus/utils-common": "2.3.0",
"@docusaurus/utils-validation": "2.0.0-rc.1", "@docusaurus/utils-validation": "2.3.0",
"fs-extra": "^10.1.0", "fs-extra": "^10.1.0",
"sitemap": "^7.1.1", "sitemap": "^7.1.1",
"tslib": "^2.4.0" "tslib": "^2.4.0"
}, },
"devDependencies": {
"@docusaurus/types": "2.0.0-beta.21"
},
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4 || ^17.0.0", "react": "^16.8.4 || ^17.0.0",
"react-dom": "^16.8.4 || ^17.0.0" "react-dom": "^16.8.4 || ^17.0.0"

View File

@ -158,7 +158,10 @@ describe('createSitemap', () => {
meta: { meta: {
// @ts-expect-error: bad lib def // @ts-expect-error: bad lib def
toComponent: () => [ toComponent: () => [
React.createElement('meta', {name: 'robots', content: 'noindex'}), React.createElement('meta', {
name: 'robots',
content: 'NoFolloW, NoiNDeX',
}),
], ],
}, },
}, },

View File

@ -13,6 +13,40 @@ import type {DocusaurusConfig} from '@docusaurus/types';
import type {HelmetServerState} from 'react-helmet-async'; import type {HelmetServerState} from 'react-helmet-async';
import type {PluginOptions} from './options'; import type {PluginOptions} from './options';
function isNoIndexMetaRoute({
head,
route,
}: {
head: {[location: string]: HelmetServerState};
route: string;
}) {
const isNoIndexMetaTag = ({
name,
content,
}: {
name?: string;
content?: string;
}): boolean => {
if (!name || !content) {
return false;
}
return (
// meta name is not case-sensitive
name.toLowerCase() === 'robots' &&
// Robots directives are not case-sensitive
content.toLowerCase().includes('noindex')
);
};
// https://github.com/staylor/react-helmet-async/pull/167
const meta = head[route]?.meta.toComponent() as unknown as
| ReactElement<{name?: string; content?: string}>[]
| undefined;
return meta?.some((tag) =>
isNoIndexMetaTag({name: tag.props.name, content: tag.props.content}),
);
}
export default async function createSitemap( export default async function createSitemap(
siteConfig: DocusaurusConfig, siteConfig: DocusaurusConfig,
routesPaths: string[], routesPaths: string[],
@ -27,18 +61,15 @@ export default async function createSitemap(
const ignoreMatcher = createMatcher(ignorePatterns); const ignoreMatcher = createMatcher(ignorePatterns);
const includedRoutes = routesPaths.filter((route) => { function isRouteExcluded(route: string) {
if (route.endsWith('404.html') || ignoreMatcher(route)) { return (
return false; route.endsWith('404.html') ||
} ignoreMatcher(route) ||
// https://github.com/staylor/react-helmet-async/pull/167 isNoIndexMetaRoute({head, route})
const meta = head[route]?.meta.toComponent() as unknown as
| ReactElement<{name?: string; content?: string}>[]
| undefined;
return !meta?.some(
(tag) => tag.props.name === 'robots' && tag.props.content === 'noindex',
); );
}); }
const includedRoutes = routesPaths.filter((route) => !isRouteExcluded(route));
if (includedRoutes.length === 0) { if (includedRoutes.length === 0) {
return null; return null;

View File

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

View File

@ -40,6 +40,7 @@ export default function preset(
theme, theme,
googleAnalytics, googleAnalytics,
gtag, gtag,
googleTagManager,
...rest ...rest
} = opts; } = opts;
@ -80,6 +81,11 @@ export default function preset(
if (gtag) { if (gtag) {
plugins.push(makePluginConfig('@docusaurus/plugin-google-gtag', gtag)); plugins.push(makePluginConfig('@docusaurus/plugin-google-gtag', gtag));
} }
if (googleTagManager) {
plugins.push(
makePluginConfig('@docusaurus/plugin-google-gtag', googleTagManager),
);
}
if (isProd && sitemap !== false) { if (isProd && sitemap !== false) {
plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap)); plugins.push(makePluginConfig('@docusaurus/plugin-sitemap', sitemap));
} }
@ -87,7 +93,7 @@ export default function preset(
throw new Error( throw new Error(
`Unrecognized keys ${Object.keys(rest).join( `Unrecognized keys ${Object.keys(rest).join(
', ', ', ',
)} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme, googleAnalytics, gtag. Check the documentation: https://docusaurus.io/docs/presets#docusauruspreset-classic for more information on how to configure individual plugins.`, )} found in preset-classic configuration. The allowed keys are debug, docs, blog, pages, sitemap, theme, googleAnalytics, gtag. Check the documentation: https://docusaurus.io/docs/using-plugins#docusauruspreset-classic for more information on how to configure individual plugins.`,
); );
} }

View File

@ -11,6 +11,7 @@ import type {Options as PagesPluginOptions} from '@docusaurus/plugin-content-pag
import type {Options as SitemapPluginOptions} from '@docusaurus/plugin-sitemap'; import type {Options as SitemapPluginOptions} from '@docusaurus/plugin-sitemap';
import type {Options as GAPluginOptions} from '@docusaurus/plugin-google-analytics'; import type {Options as GAPluginOptions} from '@docusaurus/plugin-google-analytics';
import type {Options as GtagPluginOptions} from '@docusaurus/plugin-google-gtag'; import type {Options as GtagPluginOptions} from '@docusaurus/plugin-google-gtag';
import type {Options as GTMPluginOptions} from '@docusaurus/plugin-google-tag-manager';
import type {Options as ThemeOptions} from '@docusaurus/theme-classic'; import type {Options as ThemeOptions} from '@docusaurus/theme-classic';
import type {ThemeConfig as BaseThemeConfig} from '@docusaurus/types'; import type {ThemeConfig as BaseThemeConfig} from '@docusaurus/types';
import type {UserThemeConfig as ClassicThemeConfig} from '@docusaurus/theme-common'; import type {UserThemeConfig as ClassicThemeConfig} from '@docusaurus/theme-common';
@ -42,6 +43,7 @@ export type Options = {
* is present. * is present.
*/ */
gtag?: GtagPluginOptions; gtag?: GtagPluginOptions;
googleTagManager?: GTMPluginOptions;
}; };
export type ThemeConfig = BaseThemeConfig & export type ThemeConfig = BaseThemeConfig &

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/remark-plugin-npm2yarn", "name": "@docusaurus/remark-plugin-npm2yarn",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Remark plugin for converting npm commands to Yarn commands as tabs.", "description": "Remark plugin for converting npm commands to Yarn commands as tabs.",
"main": "lib/index.js", "main": "lib/index.js",
"publishConfig": { "publishConfig": {

View File

@ -1,6 +1,6 @@
{ {
"name": "@docusaurus/theme-classic", "name": "@docusaurus/theme-classic",
"version": "2.0.0-rc.1", "version": "2.3.0",
"description": "Classic theme for Docusaurus", "description": "Classic theme for Docusaurus",
"main": "lib/index.js", "main": "lib/index.js",
"types": "src/theme-classic.d.ts", "types": "src/theme-classic.d.ts",
@ -20,18 +20,18 @@
"copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch" "copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-rc.1", "@docusaurus/core": "2.3.0",
"@docusaurus/mdx-loader": "2.0.0-rc.1", "@docusaurus/mdx-loader": "2.3.0",
"@docusaurus/module-type-aliases": "2.0.0-rc.1", "@docusaurus/module-type-aliases": "2.3.0",
"@docusaurus/plugin-content-blog": "2.0.0-rc.1", "@docusaurus/plugin-content-blog": "2.3.0",
"@docusaurus/plugin-content-docs": "2.0.0-rc.1", "@docusaurus/plugin-content-docs": "2.3.0",
"@docusaurus/plugin-content-pages": "2.0.0-rc.1", "@docusaurus/plugin-content-pages": "2.3.0",
"@docusaurus/theme-common": "2.0.0-rc.1", "@docusaurus/theme-common": "2.3.0",
"@docusaurus/theme-translations": "2.0.0-rc.1", "@docusaurus/theme-translations": "2.3.0",
"@docusaurus/types": "2.0.0-rc.1", "@docusaurus/types": "2.3.0",
"@docusaurus/utils": "2.0.0-rc.1", "@docusaurus/utils": "2.3.0",
"@docusaurus/utils-common": "2.0.0-rc.1", "@docusaurus/utils-common": "2.3.0",
"@docusaurus/utils-validation": "2.0.0-rc.1", "@docusaurus/utils-validation": "2.3.0",
"@mdx-js/react": "^1.6.22", "@mdx-js/react": "^1.6.22",
"clsx": "^1.2.1", "clsx": "^1.2.1",
"copy-text-to-clipboard": "^3.0.1", "copy-text-to-clipboard": "^3.0.1",
@ -47,8 +47,6 @@
"utility-types": "^3.10.0" "utility-types": "^3.10.0"
}, },
"devDependencies": { "devDependencies": {
"@docusaurus/module-type-aliases": "2.0.0-beta.21",
"@docusaurus/types": "2.0.0-beta.21",
"@types/mdx-js__react": "^1.5.5", "@types/mdx-js__react": "^1.5.5",
"@types/nprogress": "^0.2.0", "@types/nprogress": "^0.2.0",
"@types/prismjs": "^1.26.0", "@types/prismjs": "^1.26.0",

View File

@ -62,7 +62,7 @@ describe('themeConfig', () => {
textColor: '#000', textColor: '#000',
isCloseable: true, isCloseable: true,
}, },
image: 'img/docusaurus-soc.png', image: 'img/docusaurus-social-card.jpg',
navbar: { navbar: {
style: 'primary', style: 'primary',
hideOnScroll: true, hideOnScroll: true,

View File

@ -20,6 +20,14 @@ export default function getSwizzleConfig(): SwizzleConfig {
description: description:
'The component used to render multi-line code blocks, generally used in Markdown files.', 'The component used to render multi-line code blocks, generally used in Markdown files.',
}, },
'CodeBlock/Content': {
actions: {
eject: 'unsafe',
wrap: 'forbidden',
},
description:
'The folder containing components responsible for rendering different types of CodeBlock content.',
},
ColorModeToggle: { ColorModeToggle: {
actions: { actions: {
eject: 'safe', eject: 'safe',
@ -28,6 +36,33 @@ export default function getSwizzleConfig(): SwizzleConfig {
description: description:
'The color mode toggle to switch between light and dark mode.', 'The color mode toggle to switch between light and dark mode.',
}, },
'DocBreadcrumbs/Items': {
actions: {
eject: 'unsafe',
wrap: 'forbidden', // Can't wrap a folder
},
description:
'The components responsible for rendering the breadcrumb items',
},
DocCardList: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description:
'The component responsible for rendering a list of sidebar items cards.\nNotable used on the category generated-index pages.',
},
'DocItem/TOC': {
actions: {
// Forbidden because it's a parent folder, makes the CLI crash atm
// TODO the CLI should rather support --eject
// Subfolders can be swizzled
eject: 'forbidden',
wrap: 'forbidden',
},
description:
'The DocItem TOC is not directly swizzle-able, but you can swizzle its sub-components.',
},
DocSidebar: { DocSidebar: {
actions: { actions: {
eject: 'unsafe', // Too much technical code in sidebar, not very safe atm eject: 'unsafe', // Too much technical code in sidebar, not very safe atm
@ -93,6 +128,17 @@ export default function getSwizzleConfig(): SwizzleConfig {
}, },
description: 'The footer logo', description: 'The footer logo',
}, },
Icon: {
actions: {
// Forbidden because it's a parent folder, makes the CLI crash atm
// TODO the CLI should rather support --eject
// Subfolders can be swizzled
eject: 'forbidden',
wrap: 'forbidden',
},
description:
'The Icon folder is not directly swizzle-able, but you can swizzle its sub-components.',
},
'Icon/Arrow': { 'Icon/Arrow': {
actions: { actions: {
eject: 'safe', eject: 'safe',
@ -212,7 +258,7 @@ export default function getSwizzleConfig(): SwizzleConfig {
wrap: 'forbidden', wrap: 'forbidden',
}, },
description: description:
'The Navbar item components mapping. Can be ejected to add custom navbar item types. See https://github.com/facebook/docusaurus/issues/7227.', 'The Navbar item components mapping. Can be ejected to add custom navbar item types.\nSee https://github.com/facebook/docusaurus/issues/7227.',
}, },
NotFound: { NotFound: {
actions: { actions: {
@ -232,6 +278,14 @@ export default function getSwizzleConfig(): SwizzleConfig {
description: description:
'The search bar component of your site, appearing in the navbar.', 'The search bar component of your site, appearing in the navbar.',
}, },
SkipToContent: {
actions: {
eject: 'safe',
wrap: 'safe',
},
description:
'The component responsible for implementing the accessibility "skip to content" link (https://www.w3.org/TR/WCAG20-TECHS/G1.html)',
},
'prism-include-languages': { 'prism-include-languages': {
actions: { actions: {
eject: 'safe', eject: 'safe',

View File

@ -55,6 +55,22 @@ declare module '@theme/AnnouncementBar' {
export default function AnnouncementBar(): JSX.Element | null; export default function AnnouncementBar(): JSX.Element | null;
} }
declare module '@theme/AnnouncementBar/Content' {
import type {ComponentProps} from 'react';
export interface Props extends ComponentProps<'div'> {}
export default function AnnouncementBarContent(props: Props): JSX.Element;
}
declare module '@theme/AnnouncementBar/CloseButton' {
import type {ComponentProps} from 'react';
export interface Props extends ComponentProps<'button'> {}
export default function AnnouncementBarCloseButton(props: Props): JSX.Element;
}
declare module '@theme/BackToTopButton' { declare module '@theme/BackToTopButton' {
export default function BackToTopButton(): JSX.Element; export default function BackToTopButton(): JSX.Element;
} }
@ -320,7 +336,7 @@ declare module '@theme/DocCardList' {
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs'; import type {PropSidebarItem} from '@docusaurus/plugin-content-docs';
export interface Props { export interface Props {
readonly items: PropSidebarItem[]; readonly items?: PropSidebarItem[];
readonly className?: string; readonly className?: string;
} }
@ -772,6 +788,7 @@ declare module '@theme/MDXComponents' {
import type MDXUl from '@theme/MDXComponents/Ul'; import type MDXUl from '@theme/MDXComponents/Ul';
import type MDXImg from '@theme/MDXComponents/Img'; import type MDXImg from '@theme/MDXComponents/Img';
import type Admonition from '@theme/Admonition'; import type Admonition from '@theme/Admonition';
import type Mermaid from '@theme/Mermaid';
export type MDXComponentsObject = { export type MDXComponentsObject = {
readonly head: typeof MDXHead; readonly head: typeof MDXHead;
@ -788,6 +805,7 @@ declare module '@theme/MDXComponents' {
readonly h5: (props: ComponentProps<'h5'>) => JSX.Element; readonly h5: (props: ComponentProps<'h5'>) => JSX.Element;
readonly h6: (props: ComponentProps<'h6'>) => JSX.Element; readonly h6: (props: ComponentProps<'h6'>) => JSX.Element;
readonly admonition: typeof Admonition; readonly admonition: typeof Admonition;
readonly mermaid: typeof Mermaid;
// eslint-disable-next-line @typescript-eslint/no-explicit-any // eslint-disable-next-line @typescript-eslint/no-explicit-any
[tagName: string]: ComponentType<any>; [tagName: string]: ComponentType<any>;
}; };
@ -1096,39 +1114,26 @@ declare module '@theme/SearchBar' {
export default function SearchBar(): JSX.Element; export default function SearchBar(): JSX.Element;
} }
declare module '@theme/TabItem' { declare module '@theme/Mermaid' {
import type {ReactNode} from 'react';
export interface Props { export interface Props {
readonly children: ReactNode; value: string;
readonly value: string;
readonly default?: boolean;
readonly label?: string;
readonly hidden?: boolean;
readonly className?: string;
readonly attributes?: {[key: string]: unknown};
} }
export default function Mermaid(props: Props): JSX.Element;
}
declare module '@theme/TabItem' {
import type {TabItemProps} from '@docusaurus/theme-common/internal';
export interface Props extends TabItemProps {}
export default function TabItem(props: Props): JSX.Element; export default function TabItem(props: Props): JSX.Element;
} }
declare module '@theme/Tabs' { declare module '@theme/Tabs' {
import type {ReactElement} from 'react'; import type {TabsProps} from '@docusaurus/theme-common/internal';
import type {Props as TabItemProps} from '@theme/TabItem';
export interface Props { export interface Props extends TabsProps {}
readonly lazy?: boolean;
readonly block?: boolean;
readonly children: readonly ReactElement<TabItemProps>[];
readonly defaultValue?: string | null;
readonly values?: readonly {
value: string;
label?: string;
attributes?: {[key: string]: unknown};
}[];
readonly groupId?: string;
readonly className?: string;
}
export default function Tabs(props: Props): JSX.Element; export default function Tabs(props: Props): JSX.Element;
} }
@ -1366,3 +1371,7 @@ declare module '@theme/prism-include-languages' {
PrismObject: typeof PrismNamespace, PrismObject: typeof PrismNamespace,
): void; ): void;
} }
declare module '@theme/DocBreadcrumbs/Items/Home' {
export default function HomeBreadcrumbItem(): JSX.Element;
}

View File

@ -0,0 +1,31 @@
/**
* 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 from 'react';
import clsx from 'clsx';
import {translate} from '@docusaurus/Translate';
import IconClose from '@theme/Icon/Close';
import type {Props} from '@theme/AnnouncementBar/CloseButton';
import styles from './styles.module.css';
export default function AnnouncementBarCloseButton(
props: Props,
): JSX.Element | null {
return (
<button
type="button"
aria-label={translate({
id: 'theme.AnnouncementBar.closeButtonAriaLabel',
message: 'Close',
description: 'The ARIA label for close button of announcement bar',
})}
{...props}
className={clsx('clean-btn close', styles.closeButton, props.className)}>
<IconClose width={14} height={14} strokeWidth={3.1} />
</button>
);
}

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.
*/
.closeButton {
padding: 0;
line-height: 0;
}

View File

@ -0,0 +1,28 @@
/**
* 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 from 'react';
import clsx from 'clsx';
import {useThemeConfig} from '@docusaurus/theme-common';
import type {Props} from '@theme/AnnouncementBar/Content';
import styles from './styles.module.css';
export default function AnnouncementBarContent(
props: Props,
): JSX.Element | null {
const {announcementBar} = useThemeConfig();
const {content} = announcementBar!;
return (
<div
{...props}
className={clsx(styles.content, props.className)}
// Developer provided the HTML, so assume it's safe.
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: content}}
/>
);
}

View File

@ -0,0 +1,17 @@
/**
* 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.
*/
.content {
font-size: 85%;
text-align: center;
padding: 5px 0;
}
.content a {
color: inherit;
text-decoration: underline;
}

View File

@ -6,49 +6,33 @@
*/ */
import React from 'react'; import React from 'react';
import clsx from 'clsx';
import {useThemeConfig} from '@docusaurus/theme-common'; import {useThemeConfig} from '@docusaurus/theme-common';
import {useAnnouncementBar} from '@docusaurus/theme-common/internal'; import {useAnnouncementBar} from '@docusaurus/theme-common/internal';
import {translate} from '@docusaurus/Translate'; import AnnouncementBarCloseButton from '@theme/AnnouncementBar/CloseButton';
import IconClose from '@theme/Icon/Close'; import AnnouncementBarContent from '@theme/AnnouncementBar/Content';
import styles from './styles.module.css'; import styles from './styles.module.css';
export default function AnnouncementBar(): JSX.Element | null { export default function AnnouncementBar(): JSX.Element | null {
const {isActive, close} = useAnnouncementBar();
const {announcementBar} = useThemeConfig(); const {announcementBar} = useThemeConfig();
const {isActive, close} = useAnnouncementBar();
if (!isActive) { if (!isActive) {
return null; return null;
} }
const {backgroundColor, textColor, isCloseable} = announcementBar!;
const {content, backgroundColor, textColor, isCloseable} = announcementBar!;
return ( return (
<div <div
className={styles.announcementBar} className={styles.announcementBar}
style={{backgroundColor, color: textColor}} style={{backgroundColor, color: textColor}}
role="banner"> role="banner">
{isCloseable && <div className={styles.announcementBarPlaceholder} />} {isCloseable && <div className={styles.announcementBarPlaceholder} />}
<div <AnnouncementBarContent className={styles.announcementBarContent} />
className={styles.announcementBarContent} {isCloseable && (
// Developer provided the HTML, so assume it's safe. <AnnouncementBarCloseButton
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: content}}
/>
{isCloseable ? (
<button
type="button"
className={clsx('clean-btn close', styles.announcementBarClose)}
onClick={close} onClick={close}
aria-label={translate({ className={styles.announcementBarClose}
id: 'theme.AnnouncementBar.closeButtonAriaLabel', />
message: 'Close', )}
description: 'The ARIA label for close button of announcement bar',
})}>
<IconClose width={14} height={14} strokeWidth={3.1} />
</button>
) : null}
</div> </div>
); );
} }

View File

@ -15,6 +15,15 @@
height: var(--docusaurus-announcement-bar-height); height: var(--docusaurus-announcement-bar-height);
background-color: var(--ifm-color-white); background-color: var(--ifm-color-white);
color: var(--ifm-color-black); color: var(--ifm-color-black);
/*
Unfortunately we can't make announcement bar render above the navbar
IE need to use border-bottom instead of shadow
See https://github.com/facebookincubator/infima/issues/275
box-shadow: var(--ifm-global-shadow-lw);
z-index: calc(var(--ifm-z-index-fixed) + 1);
*/
border-bottom: 1px solid var(--ifm-color-emphasis-100); border-bottom: 1px solid var(--ifm-color-emphasis-100);
} }
@ -29,15 +38,10 @@ html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
.announcementBarClose { .announcementBarClose {
flex: 0 0 30px; flex: 0 0 30px;
align-self: stretch; align-self: stretch;
padding: 0;
line-height: 0;
} }
.announcementBarContent { .announcementBarContent {
flex: 1 1 auto; flex: 1 1 auto;
font-size: 85%;
text-align: center;
padding: 5px 0;
} }
@media print { @media print {
@ -46,11 +50,6 @@ html[data-announcement-bar-initially-dismissed='true'] .announcementBar {
} }
} }
.announcementBarContent a {
color: inherit;
text-decoration: underline;
}
@media (min-width: 997px) { @media (min-width: 997px) {
:root { :root {
--docusaurus-announcement-bar-height: 30px; --docusaurus-announcement-bar-height: 30px;

View File

@ -39,11 +39,9 @@ export default function CodeBlockLine({
<span className={styles.codeLineContent}>{lineTokens}</span> <span className={styles.codeLineContent}>{lineTokens}</span>
</> </>
) : ( ) : (
<> lineTokens
{lineTokens}
<br />
</>
)} )}
<br />
</span> </span>
); );
} }

View File

@ -35,6 +35,7 @@ the background in custom CSS file due bug https://github.com/facebook/docusaurus
left: 0; left: 0;
padding: 0 var(--ifm-pre-padding); padding: 0 var(--ifm-pre-padding);
background: var(--ifm-pre-background); background: var(--ifm-pre-background);
overflow-wrap: normal;
} }
.codeLineNumber::before { .codeLineNumber::before {

View File

@ -52,7 +52,8 @@ function ColorModeToggle({className, value, onChange}: Props): JSX.Element {
onClick={() => onChange(value === 'dark' ? 'light' : 'dark')} onClick={() => onChange(value === 'dark' ? 'light' : 'dark')}
disabled={!isBrowser} disabled={!isBrowser}
title={title} title={title}
aria-label={title}> aria-label={title}
aria-live="polite">
<IconLightMode <IconLightMode
className={clsx(styles.toggleIcon, styles.lightToggleIcon)} className={clsx(styles.toggleIcon, styles.lightToggleIcon)}
/> />

View File

@ -0,0 +1,33 @@
/**
* 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 from 'react';
import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import {translate} from '@docusaurus/Translate';
import IconHome from '@theme/Icon/Home';
import styles from './styles.module.css';
export default function HomeBreadcrumbItem(): JSX.Element {
const homeHref = useBaseUrl('/');
return (
<li className="breadcrumbs__item">
<Link
aria-label={translate({
id: 'theme.docs.breadcrumbs.home',
message: 'Home page',
description: 'The ARIA label for the home page in the breadcrumbs',
})}
className="breadcrumbs__link"
href={homeHref}>
<IconHome className={styles.breadcrumbHomeIcon} />
</Link>
</li>
);
}

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.
*/
.breadcrumbHomeIcon {
position: relative;
top: 1px;
vertical-align: top;
height: 1.1rem;
width: 1.1rem;
}

View File

@ -13,9 +13,8 @@ import {
useHomePageRoute, useHomePageRoute,
} from '@docusaurus/theme-common/internal'; } from '@docusaurus/theme-common/internal';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import useBaseUrl from '@docusaurus/useBaseUrl';
import {translate} from '@docusaurus/Translate'; import {translate} from '@docusaurus/Translate';
import IconHome from '@theme/Icon/Home'; import HomeBreadcrumbItem from '@theme/DocBreadcrumbs/Items/Home';
import styles from './styles.module.css'; import styles from './styles.module.css';
@ -79,24 +78,6 @@ function BreadcrumbsItem({
); );
} }
function HomeBreadcrumbItem() {
const homeHref = useBaseUrl('/');
return (
<li className="breadcrumbs__item">
<Link
aria-label={translate({
id: 'theme.docs.breadcrumbs.home',
message: 'Home page',
description: 'The ARIA label for the home page in the breadcrumbs',
})}
className={clsx('breadcrumbs__link', styles.breadcrumbsItemLink)}
href={homeHref}>
<IconHome className={styles.breadcrumbHomeIcon} />
</Link>
</li>
);
}
export default function DocBreadcrumbs(): JSX.Element | null { export default function DocBreadcrumbs(): JSX.Element | null {
const breadcrumbs = useSidebarBreadcrumbs(); const breadcrumbs = useSidebarBreadcrumbs();
const homePageRoute = useHomePageRoute(); const homePageRoute = useHomePageRoute();

View File

@ -9,11 +9,3 @@
--ifm-breadcrumb-size-multiplier: 0.8; --ifm-breadcrumb-size-multiplier: 0.8;
margin-bottom: 0.8rem; margin-bottom: 0.8rem;
} }
.breadcrumbHomeIcon {
position: relative;
top: 1px;
vertical-align: top;
height: 1.1rem;
width: 1.1rem;
}

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