From e0acbd036393982e14a4866faf199b6bb8a7c089 Mon Sep 17 00:00:00 2001 From: Jody Heavener Date: Wed, 24 Aug 2022 01:08:30 -0300 Subject: [PATCH 01/50] Exclude unlisted docs --- .../simple-site/docs/doc-unlisted.md | 5 + .../__tests__/__snapshots__/docs.test.ts.snap | 19 +- .../__snapshots__/globalData.test.ts.snap | 2 + .../__snapshots__/index.test.ts.snap | 227 ++++++++++++++++-- .../src/__tests__/docs.test.ts | 61 +++++ .../src/__tests__/frontMatter.test.ts | 16 ++ .../src/client/index.ts | 1 + .../src/docs.ts | 21 +- .../src/frontMatter.ts | 1 + .../src/globalData.ts | 1 + .../src/index.ts | 7 + .../src/plugin-content-docs.d.ts | 7 + .../src/props.ts | 3 + .../src/sidebars/__tests__/utils.test.ts | 20 +- .../src/sidebars/types.ts | 1 + .../src/sidebars/utils.ts | 8 +- .../src/theme/DocItem/Metadata/index.tsx | 7 +- .../theme/DocSidebarItem/Category/index.tsx | 22 +- .../src/theme/DocSidebarItem/Link/index.tsx | 9 +- .../src/theme/NavbarItem/DocNavbarItem.tsx | 7 +- website/_dogfooding/_docs tests/test-draft.md | 6 +- .../_dogfooding/_docs tests/test-unlisted.md | 7 + website/_dogfooding/docs-tests-sidebars.js | 12 + .../docs/api/plugins/plugin-content-docs.md | 1 + website/docusaurus.config.js | 10 +- 25 files changed, 432 insertions(+), 49 deletions(-) create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/doc-unlisted.md create mode 100644 website/_dogfooding/_docs tests/test-unlisted.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/doc-unlisted.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/doc-unlisted.md new file mode 100644 index 000000000000..54090b5a48b0 --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/doc-unlisted.md @@ -0,0 +1,5 @@ +--- +unlisted: true +--- + +This is an unlisted document diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap index 69401a06a04c..89a894cbdd70 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap @@ -25,14 +25,25 @@ exports[`simple site custom pagination 1`] = ` { "id": "doc-draft", "next": { - "permalink": "/docs/foo/bar", - "title": "Bar", + "permalink": "/docs/doc-unlisted", + "title": "doc-unlisted", }, "prev": { "permalink": "/docs/doc with space", "title": "Hoo hoo, if this path tricks you...", }, }, + { + "id": "doc-unlisted", + "next": { + "permalink": "/docs/foo/bar", + "title": "Bar", + }, + "prev": { + "permalink": "/docs/doc-draft", + "title": "doc-draft", + }, + }, { "id": "foo/bar", "next": undefined, @@ -215,6 +226,10 @@ exports[`simple site custom pagination 1`] = ` "id": "doc-draft", "type": "doc", }, + { + "id": "doc-unlisted", + "type": "doc", + }, { "collapsed": false, "collapsible": true, diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap index 0bd0862b0f8d..5e80d835e738 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap @@ -7,11 +7,13 @@ exports[`toGlobalDataVersion generates the right docs, sidebars, and metadata 1` "id": "main", "path": "/current/main", "sidebar": "tutorial", + "unlisted": undefined, }, { "id": "doc", "path": "/current/doc", "sidebar": "tutorial", + "unlisted": undefined, }, { "id": "/current/generated", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 244c608c1c0b..8bd3e0da512b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -25,6 +25,7 @@ Available document ids are: - customLastUpdate - doc with space - doc-draft +- doc-unlisted - foo/bar - foo/baz - headingAsTitle @@ -91,6 +92,7 @@ exports[`simple website content 1`] = ` }, ], "title": "baz", + "unlisted": false, "unversionedId": "foo/baz", "version": "current", } @@ -137,6 +139,7 @@ exports[`simple website content 2`] = ` }, ], "title": "Hello, World !", + "unlisted": false, "unversionedId": "hello", "version": "current", } @@ -168,6 +171,7 @@ exports[`simple website content 3`] = ` "sourceDirName": "foo", "tags": [], "title": "Bar", + "unlisted": false, "unversionedId": "foo/bar", "version": "current", } @@ -274,96 +278,121 @@ exports[`simple website content 5`] = ` "id": "customLastUpdate", "path": "/docs/customLastUpdate", "sidebar": undefined, + "unlisted": false, }, { "id": "doc with space", "path": "/docs/doc with space", "sidebar": undefined, + "unlisted": false, }, { "id": "doc-draft", "path": "/docs/doc-draft", "sidebar": undefined, + "unlisted": false, + }, + { + "id": "doc-unlisted", + "path": "/docs/doc-unlisted", + "sidebar": undefined, + "unlisted": false, }, { "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "docs", + "unlisted": false, }, { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", "sidebar": "docs", + "unlisted": false, }, { "id": "headingAsTitle", "path": "/docs/headingAsTitle", "sidebar": "docs", + "unlisted": false, }, { "id": "hello", "path": "/docs/", "sidebar": "docs", + "unlisted": false, }, { "id": "ipsum", "path": "/docs/ipsum", "sidebar": undefined, + "unlisted": false, }, { "id": "lastUpdateAuthorOnly", "path": "/docs/lastUpdateAuthorOnly", "sidebar": undefined, + "unlisted": false, }, { "id": "lastUpdateDateOnly", "path": "/docs/lastUpdateDateOnly", "sidebar": undefined, + "unlisted": false, }, { "id": "lorem", "path": "/docs/lorem", "sidebar": undefined, + "unlisted": false, }, { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "/category/slugs", @@ -419,6 +448,7 @@ exports[`simple website content: data 1`] = ` "slug": "/customLastUpdate", "permalink": "/docs/customLastUpdate", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -439,11 +469,29 @@ exports[`simple website content: data 1`] = ` "slug": "/doc-draft", "permalink": "/docs/doc-draft", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { "draft": true } +}", + "site-docs-doc-unlisted-md-80b.json": "{ + "unversionedId": "doc-unlisted", + "id": "doc-unlisted", + "title": "doc-unlisted", + "description": "This is an unlisted document", + "source": "@site/docs/doc-unlisted.md", + "sourceDirName": ".", + "slug": "/doc-unlisted", + "permalink": "/docs/doc-unlisted", + "draft": false, + "unlisted": false, + "tags": [], + "version": "current", + "frontMatter": { + "unlisted": true + } }", "site-docs-doc-with-space-md-e90.json": "{ "unversionedId": "doc with space", @@ -455,6 +503,7 @@ exports[`simple website content: data 1`] = ` "slug": "/doc with space", "permalink": "/docs/doc with space", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": {} @@ -469,6 +518,7 @@ exports[`simple website content: data 1`] = ` "slug": "/foo/bar", "permalink": "/docs/foo/bar", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -490,6 +540,7 @@ exports[`simple website content: data 1`] = ` "slug": "/foo/bazSlug.html", "permalink": "/docs/foo/bazSlug.html", "draft": false, + "unlisted": false, "tags": [ { "label": "tag 1", @@ -535,6 +586,7 @@ exports[`simple website content: data 1`] = ` "slug": "/headingAsTitle", "permalink": "/docs/headingAsTitle", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": {}, @@ -558,6 +610,7 @@ exports[`simple website content: data 1`] = ` "slug": "/", "permalink": "/docs/", "draft": false, + "unlisted": false, "tags": [ { "label": "tag-1", @@ -595,6 +648,7 @@ exports[`simple website content: data 1`] = ` "slug": "/ipsum", "permalink": "/docs/ipsum", "draft": false, + "unlisted": false, "editUrl": null, "tags": [], "version": "current", @@ -612,6 +666,7 @@ exports[`simple website content: data 1`] = ` "slug": "/lastUpdateAuthorOnly", "permalink": "/docs/lastUpdateAuthorOnly", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -631,6 +686,7 @@ exports[`simple website content: data 1`] = ` "slug": "/lastUpdateDateOnly", "permalink": "/docs/lastUpdateDateOnly", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -650,6 +706,7 @@ exports[`simple website content: data 1`] = ` "slug": "/lorem", "permalink": "/docs/lorem", "draft": false, + "unlisted": false, "editUrl": "https://github.com/customUrl/docs/lorem.md", "tags": [], "version": "current", @@ -668,6 +725,7 @@ exports[`simple website content: data 1`] = ` "slug": "/rootAbsoluteSlug", "permalink": "/docs/rootAbsoluteSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -695,6 +753,7 @@ exports[`simple website content: data 1`] = ` "slug": "/rootRelativeSlug", "permalink": "/docs/rootRelativeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -722,6 +781,7 @@ exports[`simple website content: data 1`] = ` "slug": "/hey/rootResolvedSlug", "permalink": "/docs/hey/rootResolvedSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -749,6 +809,7 @@ exports[`simple website content: data 1`] = ` "slug": "/rootTryToEscapeSlug", "permalink": "/docs/rootTryToEscapeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -776,6 +837,7 @@ exports[`simple website content: data 1`] = ` "slug": "/absoluteSlug", "permalink": "/docs/absoluteSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -792,6 +854,7 @@ exports[`simple website content: data 1`] = ` "slug": "/slugs/relativeSlug", "permalink": "/docs/slugs/relativeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -808,6 +871,7 @@ exports[`simple website content: data 1`] = ` "slug": "/slugs/hey/resolvedSlug", "permalink": "/docs/slugs/hey/resolvedSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -824,6 +888,7 @@ exports[`simple website content: data 1`] = ` "slug": "/tryToEscapeSlug", "permalink": "/docs/tryToEscapeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -918,13 +983,15 @@ exports[`simple website content: data 1`] = ` "type": "link", "label": "Bar", "href": "/docs/foo/bar", - "docId": "foo/bar" + "docId": "foo/bar", + "unlisted": false }, { "type": "link", "label": "baz", "href": "/docs/foo/bazSlug.html", - "docId": "foo/baz" + "docId": "foo/baz", + "unlisted": false } ], "collapsed": true, @@ -938,25 +1005,29 @@ exports[`simple website content: data 1`] = ` "type": "link", "label": "rootAbsoluteSlug", "href": "/docs/rootAbsoluteSlug", - "docId": "rootAbsoluteSlug" + "docId": "rootAbsoluteSlug", + "unlisted": false }, { "type": "link", "label": "rootRelativeSlug", "href": "/docs/rootRelativeSlug", - "docId": "rootRelativeSlug" + "docId": "rootRelativeSlug", + "unlisted": false }, { "type": "link", "label": "rootResolvedSlug", "href": "/docs/hey/rootResolvedSlug", - "docId": "rootResolvedSlug" + "docId": "rootResolvedSlug", + "unlisted": false }, { "type": "link", "label": "rootTryToEscapeSlug", "href": "/docs/rootTryToEscapeSlug", - "docId": "rootTryToEscapeSlug" + "docId": "rootTryToEscapeSlug", + "unlisted": false } ], "collapsed": true, @@ -967,7 +1038,8 @@ exports[`simple website content: data 1`] = ` "type": "link", "label": "My heading as title", "href": "/docs/headingAsTitle", - "docId": "headingAsTitle" + "docId": "headingAsTitle", + "unlisted": false }, { "type": "link", @@ -978,7 +1050,8 @@ exports[`simple website content: data 1`] = ` "type": "link", "label": "Hello sidebar_label", "href": "/docs/", - "docId": "hello" + "docId": "hello", + "unlisted": false } ], "collapsed": true, @@ -992,7 +1065,8 @@ exports[`simple website content: data 1`] = ` "type": "link", "label": "Hello sidebar_label", "href": "/docs/", - "docId": "hello" + "docId": "hello", + "unlisted": false } ], "collapsed": true, @@ -1016,6 +1090,11 @@ exports[`simple website content: data 1`] = ` "title": "doc-draft", "description": "This is a draft document" }, + "doc-unlisted": { + "id": "doc-unlisted", + "title": "doc-unlisted", + "description": "This is an unlisted document" + }, "foo/bar": { "id": "foo/bar", "title": "Bar", @@ -1122,96 +1201,121 @@ exports[`simple website content: global data 1`] = ` "id": "customLastUpdate", "path": "/docs/customLastUpdate", "sidebar": undefined, + "unlisted": false, }, { "id": "doc with space", "path": "/docs/doc with space", "sidebar": undefined, + "unlisted": false, }, { "id": "doc-draft", "path": "/docs/doc-draft", "sidebar": undefined, + "unlisted": false, + }, + { + "id": "doc-unlisted", + "path": "/docs/doc-unlisted", + "sidebar": undefined, + "unlisted": false, }, { "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "docs", + "unlisted": false, }, { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", "sidebar": "docs", + "unlisted": false, }, { "id": "headingAsTitle", "path": "/docs/headingAsTitle", "sidebar": "docs", + "unlisted": false, }, { "id": "hello", "path": "/docs/", "sidebar": "docs", + "unlisted": false, }, { "id": "ipsum", "path": "/docs/ipsum", "sidebar": undefined, + "unlisted": false, }, { "id": "lastUpdateAuthorOnly", "path": "/docs/lastUpdateAuthorOnly", "sidebar": undefined, + "unlisted": false, }, { "id": "lastUpdateDateOnly", "path": "/docs/lastUpdateDateOnly", "sidebar": undefined, + "unlisted": false, }, { "id": "lorem", "path": "/docs/lorem", "sidebar": undefined, + "unlisted": false, }, { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "/category/slugs", @@ -1343,6 +1447,14 @@ exports[`simple website content: route config 1`] = ` }, "path": "/docs/doc-draft", }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/doc-unlisted.md", + }, + "path": "/docs/doc-unlisted", + }, { "component": "@theme/DocItem", "exact": true, @@ -1787,6 +1899,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": ".", "tags": [], "title": "Getting Started", + "unlisted": false, "unversionedId": "getting-started", "version": "current", } @@ -1818,6 +1931,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": ".", "tags": [], "title": "Installation", + "unlisted": false, "unversionedId": "installation", "version": "current", } @@ -1852,6 +1966,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "Guides", "tags": [], "title": "Guide 1", + "unlisted": false, "unversionedId": "Guides/guide1", "version": "current", } @@ -1885,6 +2000,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "Guides", "tags": [], "title": "Guide 2", + "unlisted": false, "unversionedId": "Guides/guide2", "version": "current", } @@ -1919,6 +2035,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "Guides", "tags": [], "title": "Guide 2.5", + "unlisted": false, "unversionedId": "Guides/guide2.5", "version": "current", } @@ -1953,6 +2070,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "Guides", "tags": [], "title": "Guide 3", + "unlisted": false, "unversionedId": "Guides/guide3", "version": "current", } @@ -1986,6 +2104,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "Guides", "tags": [], "title": "Guide 4", + "unlisted": false, "unversionedId": "Guides/guide4", "version": "current", } @@ -2019,6 +2138,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "Guides", "tags": [], "title": "Guide 5", + "unlisted": false, "unversionedId": "Guides/guide5", "version": "current", } @@ -2050,6 +2170,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "3-API", "tags": [], "title": "API Overview", + "unlisted": false, "unversionedId": "API/api-overview", "version": "current", } @@ -2081,6 +2202,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "3-API/01_Core APIs", "tags": [], "title": "Client API", + "unlisted": false, "unversionedId": "API/Core APIs/Client API", "version": "current", } @@ -2112,6 +2234,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "3-API/01_Core APIs", "tags": [], "title": "Server API", + "unlisted": false, "unversionedId": "API/Core APIs/Server API", "version": "current", } @@ -2143,6 +2266,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "3-API/02_Extension APIs", "tags": [], "title": "Plugin API", + "unlisted": false, "unversionedId": "API/Extension APIs/Plugin API", "version": "current", } @@ -2174,6 +2298,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "3-API/02_Extension APIs", "tags": [], "title": "Theme API", + "unlisted": false, "unversionedId": "API/Extension APIs/Theme API", "version": "current", } @@ -2202,6 +2327,7 @@ exports[`site with full autogenerated sidebar docs in fully generated sidebar ha "sourceDirName": "3-API", "tags": [], "title": "API End", + "unlisted": false, "unversionedId": "API/api-end", "version": "current", } @@ -2382,6 +2508,7 @@ exports[`site with partial autogenerated sidebars docs in partially generated si "sourceDirName": "3-API", "tags": [], "title": "API End", + "unlisted": false, "unversionedId": "API/api-end", "version": "current", } @@ -2413,6 +2540,7 @@ exports[`site with partial autogenerated sidebars docs in partially generated si "sourceDirName": "3-API", "tags": [], "title": "API Overview", + "unlisted": false, "unversionedId": "API/api-overview", "version": "current", } @@ -2444,6 +2572,7 @@ exports[`site with partial autogenerated sidebars docs in partially generated si "sourceDirName": "3-API/02_Extension APIs", "tags": [], "title": "Plugin API", + "unlisted": false, "unversionedId": "API/Extension APIs/Plugin API", "version": "current", } @@ -2472,6 +2601,7 @@ exports[`site with partial autogenerated sidebars docs in partially generated si "sourceDirName": "3-API/02_Extension APIs", "tags": [], "title": "Theme API", + "unlisted": false, "unversionedId": "API/Extension APIs/Theme API", "version": "current", } @@ -2531,6 +2661,7 @@ exports[`versioned website (community) content 1`] = ` "sourceDirName": ".", "tags": [], "title": "Team title translated", + "unlisted": false, "unversionedId": "team", "version": "current", } @@ -2556,6 +2687,7 @@ exports[`versioned website (community) content 2`] = ` "sourceDirName": ".", "tags": [], "title": "team", + "unlisted": false, "unversionedId": "team", "version": "1.0.0", } @@ -2595,6 +2727,7 @@ exports[`versioned website (community) content: data 1`] = ` "slug": "/team", "permalink": "/community/team", "draft": false, + "unlisted": false, "tags": [], "version": "1.0.0", "frontMatter": {}, @@ -2610,6 +2743,7 @@ exports[`versioned website (community) content: data 1`] = ` "slug": "/team", "permalink": "/community/next/team", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -2632,7 +2766,8 @@ exports[`versioned website (community) content: data 1`] = ` "type": "link", "label": "team", "href": "/community/team", - "docId": "team" + "docId": "team", + "unlisted": false } ] }, @@ -2660,7 +2795,8 @@ exports[`versioned website (community) content: data 1`] = ` "type": "link", "label": "Team title translated", "href": "/community/next/team", - "docId": "team" + "docId": "team", + "unlisted": false } ] }, @@ -2689,6 +2825,7 @@ exports[`versioned website (community) content: global data 1`] = ` "id": "team", "path": "/community/next/team", "sidebar": "community", + "unlisted": false, }, ], "draftIds": [], @@ -2712,6 +2849,7 @@ exports[`versioned website (community) content: global data 1`] = ` "id": "team", "path": "/community/team", "sidebar": "version-1.0.0/community", + "unlisted": false, }, ], "draftIds": [], @@ -2860,6 +2998,7 @@ exports[`versioned website content 1`] = ` }, ], "title": "bar", + "unlisted": false, "unversionedId": "foo/bar", "version": "current", } @@ -2888,6 +3027,7 @@ exports[`versioned website content 2`] = ` "sourceDirName": "foo", "tags": [], "title": "bar", + "unlisted": false, "unversionedId": "foo/bar", "version": "1.0.1", } @@ -2918,6 +3058,7 @@ exports[`versioned website content 3`] = ` "sourceDirName": ".", "tags": [], "title": "hello", + "unlisted": false, "unversionedId": "hello", "version": "current", } @@ -2948,6 +3089,7 @@ exports[`versioned website content 4`] = ` "sourceDirName": ".", "tags": [], "title": "hello", + "unlisted": false, "unversionedId": "hello", "version": "1.0.1", } @@ -2979,6 +3121,7 @@ exports[`versioned website content 5`] = ` "sourceDirName": "foo", "tags": [], "title": "baz", + "unlisted": false, "unversionedId": "foo/baz", "version": "1.0.0", } @@ -3099,6 +3242,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/foo/barSlug", "permalink": "/docs/next/foo/barSlug", "draft": false, + "unlisted": false, "tags": [ { "label": "barTag 1", @@ -3141,6 +3285,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/", "permalink": "/docs/next/", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -3162,6 +3307,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/absoluteSlug", "permalink": "/docs/next/absoluteSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -3178,6 +3324,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/slugs/relativeSlug", "permalink": "/docs/next/slugs/relativeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -3194,6 +3341,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/slugs/hey/resolvedSlug", "permalink": "/docs/next/slugs/hey/resolvedSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -3210,6 +3358,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/tryToEscapeSlug", "permalink": "/docs/next/tryToEscapeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "current", "frontMatter": { @@ -3226,6 +3375,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/", "permalink": "/docs/1.0.0/", "draft": false, + "unlisted": false, "tags": [], "version": "1.0.0", "frontMatter": { @@ -3247,6 +3397,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/foo/barSlug", "permalink": "/docs/1.0.0/foo/barSlug", "draft": false, + "unlisted": false, "tags": [], "version": "1.0.0", "frontMatter": { @@ -3268,6 +3419,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/foo/baz", "permalink": "/docs/1.0.0/foo/baz", "draft": false, + "unlisted": false, "tags": [], "version": "1.0.0", "frontMatter": {}, @@ -3291,6 +3443,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/foo/bar", "permalink": "/docs/foo/bar", "draft": false, + "unlisted": false, "tags": [], "version": "1.0.1", "frontMatter": {}, @@ -3310,6 +3463,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/", "permalink": "/docs/", "draft": false, + "unlisted": false, "tags": [], "version": "1.0.1", "frontMatter": { @@ -3331,6 +3485,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/rootAbsoluteSlug", "permalink": "/docs/withSlugs/rootAbsoluteSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3348,6 +3503,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/rootRelativeSlug", "permalink": "/docs/withSlugs/rootRelativeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3364,6 +3520,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/hey/rootResolvedSlug", "permalink": "/docs/withSlugs/hey/rootResolvedSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3380,6 +3537,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/rootTryToEscapeSlug", "permalink": "/docs/withSlugs/rootTryToEscapeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3396,6 +3554,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/absoluteSlug", "permalink": "/docs/withSlugs/absoluteSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3412,6 +3571,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/slugs/relativeSlug", "permalink": "/docs/withSlugs/slugs/relativeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3428,6 +3588,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/slugs/hey/resolvedSlug", "permalink": "/docs/withSlugs/slugs/hey/resolvedSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3444,6 +3605,7 @@ exports[`versioned website content: data 1`] = ` "slug": "/tryToEscapeSlug", "permalink": "/docs/withSlugs/tryToEscapeSlug", "draft": false, + "unlisted": false, "tags": [], "version": "withSlugs", "frontMatter": { @@ -3528,13 +3690,15 @@ exports[`versioned website content: data 1`] = ` "type": "link", "label": "bar", "href": "/docs/1.0.0/foo/barSlug", - "docId": "foo/bar" + "docId": "foo/bar", + "unlisted": false }, { "type": "link", "label": "baz", "href": "/docs/1.0.0/foo/baz", - "docId": "foo/baz" + "docId": "foo/baz", + "unlisted": false } ], "collapsed": true, @@ -3548,7 +3712,8 @@ exports[`versioned website content: data 1`] = ` "type": "link", "label": "hello", "href": "/docs/1.0.0/", - "docId": "hello" + "docId": "hello", + "unlisted": false } ], "collapsed": true, @@ -3596,7 +3761,8 @@ exports[`versioned website content: data 1`] = ` "type": "link", "label": "bar", "href": "/docs/foo/bar", - "docId": "foo/bar" + "docId": "foo/bar", + "unlisted": false } ], "collapsed": true, @@ -3610,7 +3776,8 @@ exports[`versioned website content: data 1`] = ` "type": "link", "label": "hello", "href": "/docs/", - "docId": "hello" + "docId": "hello", + "unlisted": false } ], "collapsed": true, @@ -3652,7 +3819,8 @@ exports[`versioned website content: data 1`] = ` "type": "link", "label": "bar", "href": "/docs/next/foo/barSlug", - "docId": "foo/bar" + "docId": "foo/bar", + "unlisted": false } ], "collapsed": true, @@ -3666,7 +3834,8 @@ exports[`versioned website content: data 1`] = ` "type": "link", "label": "hello", "href": "/docs/next/", - "docId": "hello" + "docId": "hello", + "unlisted": false } ], "collapsed": true, @@ -3728,7 +3897,8 @@ exports[`versioned website content: data 1`] = ` "type": "link", "label": "rootAbsoluteSlug", "href": "/docs/withSlugs/rootAbsoluteSlug", - "docId": "rootAbsoluteSlug" + "docId": "rootAbsoluteSlug", + "unlisted": false } ], "collapsed": true, @@ -3796,31 +3966,37 @@ exports[`versioned website content: global data 1`] = ` "id": "foo/bar", "path": "/docs/next/foo/barSlug", "sidebar": "docs", + "unlisted": false, }, { "id": "hello", "path": "/docs/next/", "sidebar": "docs", + "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/next/absoluteSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/next/slugs/relativeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/next/slugs/hey/resolvedSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/next/tryToEscapeSlug", "sidebar": undefined, + "unlisted": false, }, ], "draftIds": [], @@ -3844,11 +4020,13 @@ exports[`versioned website content: global data 1`] = ` "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "unlisted": false, }, { "id": "hello", "path": "/docs/", "sidebar": "VersionedSideBarNameDoesNotMatter/docs", + "unlisted": false, }, ], "draftIds": [], @@ -3872,16 +4050,19 @@ exports[`versioned website content: global data 1`] = ` "id": "foo/bar", "path": "/docs/1.0.0/foo/barSlug", "sidebar": "version-1.0.0/docs", + "unlisted": false, }, { "id": "foo/baz", "path": "/docs/1.0.0/foo/baz", "sidebar": "version-1.0.0/docs", + "unlisted": false, }, { "id": "hello", "path": "/docs/1.0.0/", "sidebar": "version-1.0.0/docs", + "unlisted": false, }, ], "draftIds": [], @@ -3905,41 +4086,49 @@ exports[`versioned website content: global data 1`] = ` "id": "rootAbsoluteSlug", "path": "/docs/withSlugs/rootAbsoluteSlug", "sidebar": "version-1.0.1/docs", + "unlisted": false, }, { "id": "rootRelativeSlug", "path": "/docs/withSlugs/rootRelativeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "rootResolvedSlug", "path": "/docs/withSlugs/hey/rootResolvedSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "rootTryToEscapeSlug", "path": "/docs/withSlugs/rootTryToEscapeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/withSlugs/absoluteSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/withSlugs/slugs/relativeSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/withSlugs/slugs/hey/resolvedSlug", "sidebar": undefined, + "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/withSlugs/tryToEscapeSlug", "sidebar": undefined, + "unlisted": false, }, ], "draftIds": [], diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 4ccff773817c..b835f2a23b27 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -167,6 +167,7 @@ function createTestUtils({ rawDocs, sidebarsUtils, versionMetadata.sidebarFilePath as string, + [], ).map((doc) => ({prev: doc.previous, next: doc.next, id: doc.id})), sidebars, }; @@ -231,6 +232,7 @@ describe('simple site', () => { 'headingAsTitle.md', 'doc with space.md', 'doc-draft.md', + 'doc-unlisted.md', 'customLastUpdate.md', 'lastUpdateAuthorOnly.md', 'lastUpdateDateOnly.md', @@ -263,6 +265,7 @@ describe('simple site', () => { pagination_prev: null, }, tags: [], + unlisted: false, }); await defaultTestUtils.testMeta(path.join('hello.md'), { version: 'current', @@ -290,6 +293,7 @@ describe('simple site', () => { permalink: '/docs/tags/tag-3', }, ], + unlisted: false, }); }); @@ -340,6 +344,7 @@ describe('simple site', () => { permalink: '/docs/tags/tag2-custom-permalink', }, ], + unlisted: false, }); }); @@ -361,6 +366,7 @@ describe('simple site', () => { unrelated_front_matter: "won't be part of metadata", }, tags: [], + unlisted: false, }); }); @@ -414,6 +420,7 @@ describe('simple site', () => { permalink: '/docs/tags/tag2-custom-permalink', }, ], + unlisted: false, }); expect(editUrlFunction).toHaveBeenCalledTimes(1); @@ -460,6 +467,7 @@ describe('simple site', () => { formattedLastUpdatedAt: 'Oct 14, 2018', lastUpdatedBy: 'Author', tags: [], + unlisted: false, }); }); @@ -485,6 +493,44 @@ describe('simple site', () => { }); }); + it('docs with unlisted frontmatter', async () => { + const {createTestUtilsPartial} = await loadSite(); + + const baseMeta = { + version: 'current', + id: 'doc-unlisted', + unversionedId: 'doc-unlisted', + sourceDirName: '.', + permalink: '/docs/doc-unlisted', + slug: '/doc-unlisted', + title: 'doc-unlisted', + description: 'This is an unlisted document', + frontMatter: { + unlisted: true, + }, + sidebarPosition: undefined, + tags: [], + }; + + const testUtilsProd = createTestUtilsPartial({ + env: 'production', + }); + + await testUtilsProd.testMeta('doc-unlisted.md', { + ...baseMeta, + unlisted: true, + }); + + const testUtilsDev = createTestUtilsPartial({ + env: 'development', + }); + + await testUtilsDev.testMeta('doc-unlisted.md', { + ...baseMeta, + unlisted: false, + }); + }); + it('docs with last_update front matter', async () => { const {siteDir, context, options, currentVersion, createTestUtilsPartial} = await loadSite({ @@ -522,6 +568,7 @@ describe('simple site', () => { lastUpdatedBy: 'Custom Author', sidebarPosition: undefined, tags: [], + unlisted: false, }); }); @@ -561,6 +608,7 @@ describe('simple site', () => { lastUpdatedBy: 'Custom Author', sidebarPosition: undefined, tags: [], + unlisted: false, }); }); @@ -600,6 +648,7 @@ describe('simple site', () => { lastUpdatedBy: 'Author', sidebarPosition: undefined, tags: [], + unlisted: false, }); }); @@ -640,6 +689,7 @@ describe('simple site', () => { lastUpdatedBy: undefined, sidebarPosition: undefined, tags: [], + unlisted: false, }); }); @@ -826,6 +876,7 @@ describe('versioned site', () => { permalink: '/docs/next/tags/barTag-3-permalink', }, ], + unlisted: false, }); await currentVersionTestUtils.testMeta(path.join('hello.md'), { id: 'hello', @@ -840,6 +891,7 @@ describe('versioned site', () => { slug: '/', }, tags: [], + unlisted: false, }); }); @@ -857,6 +909,7 @@ describe('versioned site', () => { frontMatter: {slug: 'barSlug'}, version: '1.0.0', tags: [], + unlisted: false, }); await version100TestUtils.testMeta(path.join('hello.md'), { id: 'version-1.0.0/hello', @@ -873,6 +926,7 @@ describe('versioned site', () => { source: '@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md', tags: [], + unlisted: false, }); await version101TestUtils.testMeta(path.join('foo', 'bar.md'), { id: 'version-1.0.1/foo/bar', @@ -885,6 +939,7 @@ describe('versioned site', () => { version: '1.0.1', frontMatter: {}, tags: [], + unlisted: false, }); await version101TestUtils.testMeta(path.join('hello.md'), { id: 'version-1.0.1/hello', @@ -899,6 +954,7 @@ describe('versioned site', () => { slug: '/', }, tags: [], + unlisted: false, }); }); @@ -995,6 +1051,7 @@ describe('versioned site', () => { '@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md', editUrl: hardcodedEditUrl, tags: [], + unlisted: false, }); expect(editUrlFunction).toHaveBeenCalledTimes(1); @@ -1038,6 +1095,7 @@ describe('versioned site', () => { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/versioned_docs/version-1.0.0/hello.md', tags: [], + unlisted: false, }); }); @@ -1073,6 +1131,7 @@ describe('versioned site', () => { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/docs/hello.md', tags: [], + unlisted: false, }); }); @@ -1109,6 +1168,7 @@ describe('versioned site', () => { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/fr/docusaurus-plugin-content-docs/version-1.0.0/hello.md', tags: [], + unlisted: false, }); }); @@ -1146,6 +1206,7 @@ describe('versioned site', () => { editUrl: 'https://github.com/facebook/docusaurus/edit/main/website/i18n/fr/docusaurus-plugin-content-docs/current/hello.md', tags: [], + unlisted: false, }); }); }); diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts index 55da1682c725..d549155b4336 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts @@ -397,6 +397,22 @@ describe('validateDocFrontMatter draft', () => { }); }); +describe('validateDocFrontMatter unlisted', () => { + testField({ + prefix: 'unlisted', + validFrontMatters: [{unlisted: true}, {unlisted: false}], + convertibleFrontMatter: [ + [{unlisted: 'true'}, {unlisted: true}], + [{unlisted: 'false'}, {unlisted: false}], + ], + invalidFrontMatters: [ + [{unlisted: 'yes'}, 'must be a boolean'], + [{unlisted: 'no'}, 'must be a boolean'], + [{unlisted: ''}, 'must be a boolean'], + ], + }); +}); + describe('validateDocFrontMatter last_update', () => { testField({ prefix: 'last_update', diff --git a/packages/docusaurus-plugin-content-docs/src/client/index.ts b/packages/docusaurus-plugin-content-docs/src/client/index.ts index bf475ee00e9d..824daed1816b 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/index.ts @@ -38,6 +38,7 @@ export type GlobalDoc = { id: string; path: string; sidebar: string | undefined; + unlisted?: boolean; }; export type GlobalVersion = { diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index 7d13e40eb8cd..c7349fa030df 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -125,15 +125,20 @@ export async function readVersionDocs( export type DocEnv = 'production' | 'development'; -/** Docs with draft front matter are only considered draft in production. */ -function isDraftForEnvironment({ +/** + * Docs with draft or unlisted front matter are only + * considered to be so in production. + */ +function isHiddenForEnvironment({ + type, env, frontMatter, }: { + type: 'draft' | 'unlisted'; frontMatter: DocFrontMatter; env: DocEnv; }): boolean { - return (env === 'production' && frontMatter.draft) ?? false; + return (env === 'production' && frontMatter[type]) ?? false; } async function doProcessDocMetadata({ @@ -268,7 +273,8 @@ async function doProcessDocMetadata({ return undefined; } - const draft = isDraftForEnvironment({env, frontMatter}); + const draft = isHiddenForEnvironment({type: 'draft', env, frontMatter}); + const unlisted = isHiddenForEnvironment({type: 'unlisted', env, frontMatter}); const formatDate = (locale: string, date: Date, calendar: string): string => { try { @@ -299,6 +305,7 @@ async function doProcessDocMetadata({ slug: docSlug, permalink, draft, + unlisted, editUrl: customEditURL !== undefined ? customEditURL : getDocEditUrl(), tags: normalizeFrontMatterTags(versionMetadata.tagsPath, frontMatter.tags), version: versionMetadata.versionName, @@ -335,6 +342,7 @@ export function addDocNavigation( docsBase: DocMetadataBase[], sidebarsUtils: SidebarsUtils, sidebarFilePath: string, + unlistedIds: string[], ): LoadedVersion['docs'] { const docsById = createDocsByIdIndex(docsBase); @@ -349,6 +357,7 @@ export function addDocNavigation( doc.unversionedId, doc.id, doc.frontMatter.displayed_sidebar, + unlistedIds, ); const toNavigationLinkByDocId = ( @@ -365,6 +374,10 @@ export function addDocNavigation( `Error when loading ${doc.id} in ${doc.sourceDirName}: the pagination_${type} front matter points to a non-existent ID ${docId}.`, ); } + // Gracefully handle explicitly providing an unlisted doc ID in production + if (process.env.NODE_ENV === 'production' && navDoc.unlisted) { + return undefined; + } return toDocNavigationLink(navDoc); }; diff --git a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts index 9d210a831b25..ce29dbf2ac39 100644 --- a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts @@ -44,6 +44,7 @@ const DocFrontMatterSchema = Joi.object({ pagination_next: Joi.string().allow(null), pagination_prev: Joi.string().allow(null), draft: Joi.boolean(), + unlisted: Joi.boolean(), ...FrontMatterTOCHeadingLevels, last_update: Joi.object({ author: Joi.string(), diff --git a/packages/docusaurus-plugin-content-docs/src/globalData.ts b/packages/docusaurus-plugin-content-docs/src/globalData.ts index 594e14c0f200..ab39b83abc3b 100644 --- a/packages/docusaurus-plugin-content-docs/src/globalData.ts +++ b/packages/docusaurus-plugin-content-docs/src/globalData.ts @@ -24,6 +24,7 @@ function toGlobalDataDoc(doc: DocMetadata): GlobalDoc { id: doc.unversionedId, path: doc.permalink, sidebar: doc.sidebar, + unlisted: doc.unlisted, }; } diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 69bb8077aa7d..369bec583507 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -157,6 +157,12 @@ export default async function pluginContentDocs( ); const [drafts, docs] = _.partition(docsBase, (doc) => doc.draft); + const unlistedIds = docs.reduce((acc, doc) => { + if (doc.unlisted) { + acc.push(doc.id); + } + return acc; + }, []); const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, { sidebarItemsGenerator: options.sidebarItemsGenerator, @@ -179,6 +185,7 @@ export default async function pluginContentDocs( docs, sidebarsUtils, versionMetadata.sidebarFilePath as string, + unlistedIds, ), drafts, sidebars, diff --git a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts index 3ae1e0fb7acc..9462c9c92a8a 100644 --- a/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts +++ b/packages/docusaurus-plugin-content-docs/src/plugin-content-docs.d.ts @@ -398,6 +398,8 @@ declare module '@docusaurus/plugin-content-docs' { pagination_prev?: string | null; /** Should this doc be excluded from production builds? */ draft?: boolean; + /** Should this doc be accessible but hidden in production builds? */ + unlisted?: boolean; /** Allows overriding the last updated author and/or date. */ last_update?: FileChange; }; @@ -448,6 +450,11 @@ declare module '@docusaurus/plugin-content-docs' { * Draft docs will be excluded for production environment. */ draft: boolean; + /** + * Unlisted docs are accessible when directly visible, but will be hidden + * from the sidebar and pagination in production. + */ + unlisted: boolean; /** * Position in an autogenerated sidebar slice, acquired through front matter * or number prefix. diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index c9f58096ac50..0fe508bc865e 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -58,6 +58,9 @@ Available document ids are: customProps: item.customProps ?? docMetadata.frontMatter.sidebar_custom_props, docId: docMetadata.unversionedId, + unlisted: + process.env.NODE_ENV === 'production' && + docMetadata.frontMatter.unlisted === true, }; }; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index 60c30b96a889..d7c03faa43bf 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -153,7 +153,7 @@ describe('createSidebarsUtils', () => { }); it('getDocNavigation', () => { - expect(getDocNavigation('doc1', 'doc1', undefined)).toEqual({ + expect(getDocNavigation('doc1', 'doc1', undefined, [])).toEqual({ sidebarName: 'sidebar1', previous: undefined, next: { @@ -161,7 +161,7 @@ describe('createSidebarsUtils', () => { id: 'doc2', }, }); - expect(getDocNavigation('doc2', 'doc2', undefined)).toEqual({ + expect(getDocNavigation('doc2', 'doc2', undefined, [])).toEqual({ sidebarName: 'sidebar1', previous: { type: 'doc', @@ -170,7 +170,7 @@ describe('createSidebarsUtils', () => { next: undefined, }); - expect(getDocNavigation('doc3', 'doc3', undefined)).toEqual({ + expect(getDocNavigation('doc3', 'doc3', undefined, [])).toEqual({ sidebarName: 'sidebar2', previous: undefined, next: { @@ -178,7 +178,7 @@ describe('createSidebarsUtils', () => { id: 'doc4', }, }); - expect(getDocNavigation('doc4', 'doc4', undefined)).toEqual({ + expect(getDocNavigation('doc4', 'doc4', undefined, [])).toEqual({ sidebarName: 'sidebar2', previous: { type: 'doc', @@ -188,7 +188,7 @@ describe('createSidebarsUtils', () => { next: undefined, }); - expect(getDocNavigation('doc5', 'doc5', undefined)).toMatchObject({ + expect(getDocNavigation('doc5', 'doc5', undefined, [])).toMatchObject({ sidebarName: 'sidebar3', previous: undefined, next: { @@ -196,7 +196,7 @@ describe('createSidebarsUtils', () => { label: 'S3 SubCategory', }, }); - expect(getDocNavigation('doc6', 'doc6', undefined)).toMatchObject({ + expect(getDocNavigation('doc6', 'doc6', undefined, [])).toMatchObject({ sidebarName: 'sidebar3', previous: { type: 'category', @@ -207,7 +207,7 @@ describe('createSidebarsUtils', () => { id: 'doc7', }, }); - expect(getDocNavigation('doc7', 'doc7', undefined)).toEqual({ + expect(getDocNavigation('doc7', 'doc7', undefined, [])).toEqual({ sidebarName: 'sidebar3', previous: { type: 'doc', @@ -215,17 +215,17 @@ describe('createSidebarsUtils', () => { }, next: undefined, }); - expect(getDocNavigation('doc3', 'doc3', null)).toEqual({ + expect(getDocNavigation('doc3', 'doc3', null, [])).toEqual({ sidebarName: undefined, previous: undefined, next: undefined, }); expect(() => - getDocNavigation('doc3', 'doc3', 'foo'), + getDocNavigation('doc3', 'doc3', 'foo', []), ).toThrowErrorMatchingInlineSnapshot( `"Doc with ID doc3 wants to display sidebar foo but a sidebar with this name doesn't exist"`, ); - expect(getDocNavigation('doc3', 'doc3', 'sidebar1')).toEqual({ + expect(getDocNavigation('doc3', 'doc3', 'sidebar1', [])).toEqual({ sidebarName: 'sidebar1', previous: undefined, next: undefined, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts index 555004846ea4..16eabbcf91f2 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts @@ -188,6 +188,7 @@ export type PropSidebarItemCategory = Expand< export type PropSidebarItemLink = SidebarItemLink & { docId?: string; + unlisted?: boolean; }; export type PropSidebarItemHtml = SidebarItemHtml; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index 1ac140cd627b..2ef5c1b2a72f 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -139,6 +139,7 @@ export type SidebarsUtils = { unversionedId: string, versionedId: string, displayedSidebar: string | null | undefined, + unlistedIds: string[], ) => SidebarNavigation; getCategoryGeneratedIndexList: () => SidebarItemCategoryWithGeneratedIndex[]; getCategoryGeneratedIndexNavigation: ( @@ -196,6 +197,7 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils { unversionedId: string, versionedId: string, displayedSidebar: string | null | undefined, + unlistedIds: string[], ): SidebarNavigation { // TODO legacy id retro-compatibility! let docId = unversionedId; @@ -211,12 +213,16 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils { if (!sidebarName) { return emptySidebarNavigation(); } - const navigationItems = sidebarNameToNavigationItems[sidebarName]; + let navigationItems = sidebarNameToNavigationItems[sidebarName]; if (!navigationItems) { throw new Error( `Doc with ID ${docId} wants to display sidebar ${sidebarName} but a sidebar with this name doesn't exist`, ); } + navigationItems = navigationItems.filter( + (item) => !(item.type === 'doc' && unlistedIds.includes(item.id)), + ); + const currentItemIndex = navigationItems.findIndex((item) => { if (item.type === 'doc') { return item.id === docId; diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx index 3e75ee053a0d..5eb81fc67f36 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx @@ -16,7 +16,10 @@ export default function DocItemMetadata(): JSX.Element { title={metadata.title} description={metadata.description} keywords={frontMatter.keywords} - image={assets.image ?? frontMatter.image} - /> + image={assets.image ?? frontMatter.image}> + {process.env.NODE_ENV === 'production' && frontMatter.unlisted && ( + + )} + ); } diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx index 700c4a52bef3..5ac76f0bef08 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx @@ -46,6 +46,22 @@ function useAutoExpandActiveCategory({ }, [isActive, wasActive, collapsed, updateCollapsed]); } +function onlyInactiveUnlistedLinks( + activePath: string, + items: Props['item']['items'], +): boolean { + return items.every((item) => { + switch (item.type) { + case 'category': + return onlyInactiveUnlistedLinks(activePath, item.items); + case 'link': + return item.unlisted === true && !isActiveSidebarItem(item, activePath); + default: + return false; + } + }); +} + /** * When a collapsible category has no link, we still link it to its first child * during SSR as a temporary fallback. This allows to be able to navigate inside @@ -103,7 +119,7 @@ export default function DocSidebarItemCategory({ level, index, ...props -}: Props): JSX.Element { +}: Props): JSX.Element | null { const {items, label, collapsible, className, href} = item; const { docs: { @@ -144,6 +160,10 @@ export default function DocSidebarItemCategory({ } }, [collapsible, expandedItem, index, setCollapsed, autoCollapseCategories]); + if (onlyInactiveUnlistedLinks(activePath, items)) { + return null; + } + return (
  • - activeDoc?.path === doc.path || + pageActive || (!!activeDoc?.sidebar && activeDoc.sidebar === doc.sidebar) } label={staticLabel ?? doc.id} diff --git a/website/_dogfooding/_docs tests/test-draft.md b/website/_dogfooding/_docs tests/test-draft.md index 2aa775b6e801..7c63da823d84 100644 --- a/website/_dogfooding/_docs tests/test-draft.md +++ b/website/_dogfooding/_docs tests/test-draft.md @@ -2,8 +2,6 @@ draft: true --- -# Test section +# Draft doc -Welcome to the docs plugin test section - -Note: this draft doc (and the navbar link) should only be visible in local development +This draft doc (and the navbar link) should only be visible in local development diff --git a/website/_dogfooding/_docs tests/test-unlisted.md b/website/_dogfooding/_docs tests/test-unlisted.md new file mode 100644 index 000000000000..ebf623201a89 --- /dev/null +++ b/website/_dogfooding/_docs tests/test-unlisted.md @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted doc + +This unlisted doc should always be directly accessible in any environment, but in production the navbar link and pagination should only be visible when on the page itself diff --git a/website/_dogfooding/docs-tests-sidebars.js b/website/_dogfooding/docs-tests-sidebars.js index d458e7eb517d..b705e1192145 100644 --- a/website/_dogfooding/docs-tests-sidebars.js +++ b/website/_dogfooding/docs-tests-sidebars.js @@ -20,6 +20,7 @@ const sidebars = { label: 'Index', }, 'test-draft', + 'test-unlisted', 'doc-without-sidebar', 'doc-with-another-sidebar', 'doc-with-last-update', @@ -47,6 +48,17 @@ const sidebars = { collapsible: false, items: ['index', 'more-test'], }, + { + type: 'category', + label: 'Category with only unlisted doc', + items: [ + { + type: 'category', + label: 'Sub-category with only unlisted doc', + items: ['test-unlisted'], + }, + ], + }, { type: 'category', label: 'Another category with index', diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index 9b9a124e0c47..9adb5d8338ce 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -292,6 +292,7 @@ Accepted fields: | `slug` | `string` | File path | Allows to customize the document URL (`//`). Support multiple patterns: `slug: my-doc`, `slug: /my/path/myDoc`, `slug: /`. | | `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your docs. | | `draft` | `boolean` | `false` | A boolean flag to indicate that a document is a work-in-progress. Draft documents will only be displayed during development. | +| `unlisted` | `boolean` | `false` | A boolean flag to indicate that the document should be accessible if linked to directly, but visibly hidden on the site otherwise and ignored by search engines. Unlisted documents are fully visible in development. | | `last_update` | `FileChange` | `undefined` | Allows overriding the last updated author and/or date. Date can be any [parsable date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse). | ```mdx-code-block diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 2377c40d679e..5ef4b93df442 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -444,7 +444,15 @@ const config = { { type: 'doc', docId: 'test-draft', - label: 'Tests', + label: 'Draft', + docsPluginId: 'docs-tests', + }, + // This item links to an unlisted doc: only displayed + // in dev or when directly access + { + type: 'doc', + docId: 'test-unlisted', + label: 'Unlisted', docsPluginId: 'docs-tests', }, // Custom item for dogfooding: only displayed in /tests/ routes From 9e19e0fec6e6bb53a21f80a8209fa8851e9960ce Mon Sep 17 00:00:00 2001 From: Jody Heavener Date: Wed, 24 Aug 2022 13:50:58 -0300 Subject: [PATCH 02/50] Exclude unlisted pages --- .../src/frontMatter.ts | 1 + .../src/plugin-content-pages.d.ts | 1 + .../src/theme/MDXPage/index.tsx | 13 ++++++++++--- website/_dogfooding/_pages tests/index.md | 1 + website/_dogfooding/_pages tests/test-unlisted.mdx | 7 +++++++ 5 files changed, 20 insertions(+), 3 deletions(-) create mode 100644 website/_dogfooding/_pages tests/test-unlisted.mdx diff --git a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts index 8c9247da710a..6996517e98e8 100644 --- a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts @@ -17,6 +17,7 @@ const PageFrontMatterSchema = Joi.object({ description: Joi.string(), wrapperClassName: Joi.string(), hide_table_of_contents: Joi.boolean(), + unlisted: Joi.boolean(), ...FrontMatterTOCHeadingLevels, }); diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index f60623c7de65..0de96fe42965 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -27,6 +27,7 @@ declare module '@docusaurus/plugin-content-pages' { readonly hide_table_of_contents?: string; readonly toc_min_heading_level?: number; readonly toc_max_heading_level?: number; + readonly unlisted?: boolean; }; export type JSXPageMetadata = { diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index a8090301129c..1090b182b485 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -24,8 +24,11 @@ export default function MDXPage(props: Props): JSX.Element { const { metadata: {title, description, frontMatter}, } = MDXPageContent; - const {wrapperClassName, hide_table_of_contents: hideTableOfContents} = - frontMatter; + const { + wrapperClassName, + hide_table_of_contents: hideTableOfContents, + unlisted, + } = frontMatter; return ( - + + {process.env.NODE_ENV === 'production' && unlisted && ( + + )} +
    diff --git a/website/_dogfooding/_pages tests/index.md b/website/_dogfooding/_pages tests/index.md index e8bb7fdc7df4..af08ab2a242f 100644 --- a/website/_dogfooding/_pages tests/index.md +++ b/website/_dogfooding/_pages tests/index.md @@ -30,3 +30,4 @@ import Readme from "../README.md" - [Tabs tests](/tests/pages/tabs-tests) - [z-index tests](/tests/pages/z-index-tests) - [Head metadata tests](/tests/pages/head-metadata) +- [Unlisted page test](/tests/pages/test-unlisted) diff --git a/website/_dogfooding/_pages tests/test-unlisted.mdx b/website/_dogfooding/_pages tests/test-unlisted.mdx new file mode 100644 index 000000000000..0e3439149638 --- /dev/null +++ b/website/_dogfooding/_pages tests/test-unlisted.mdx @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted page + +This unlisted page should always be directly accessible, but hidden from search engines From 760dca9c26b2ddc5fdeea452d02c0e0a4d29d678 Mon Sep 17 00:00:00 2001 From: Jody Heavener Date: Wed, 24 Aug 2022 16:58:07 -0300 Subject: [PATCH 03/50] Exclude unlisted blog posts --- .../__fixtures__/website/blog/unlisted.md | 6 ++++ .../build-snap/blog/unlisted/index.html | 18 ++++++++++ .../__tests__/__snapshots__/feed.test.ts.snap | 25 ++++++++++++++ .../src/__tests__/frontMatter.test.ts | 15 +++++++++ .../src/__tests__/index.test.ts | 16 ++++++--- .../src/blogUtils.ts | 17 +++++++++- .../src/frontMatter.ts | 1 + .../src/index.ts | 16 ++++++--- .../src/plugin-content-blog.d.ts | 10 +++++- .../src/theme/BlogPostPage/Metadata/index.tsx | 4 ++- .../src/theme/BlogSidebar/Desktop/index.tsx | 33 ++++++++++++------- .../src/theme/BlogSidebar/Mobile/index.tsx | 33 ++++++++++++------- .../_blog tests/2022-08-24-post-unlisted.md | 7 ++++ website/_dogfooding/dogfooding.config.js | 3 +- .../docs/api/plugins/plugin-content-blog.md | 1 + 15 files changed, 169 insertions(+), 36 deletions(-) create mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/blog/unlisted.md create mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/unlisted/index.html create mode 100644 website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/blog/unlisted.md b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/blog/unlisted.md new file mode 100644 index 000000000000..0c5ca5d55022 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/blog/unlisted.md @@ -0,0 +1,6 @@ +--- +date: 2020-02-27 +unlisted: true +--- + +this post is unlisted diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/unlisted/index.html b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/unlisted/index.html new file mode 100644 index 000000000000..7167942e8fff --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website/build-snap/blog/unlisted/index.html @@ -0,0 +1,18 @@ + + + + + + + +Unlisted | My Site + + + + +
    +
    + + + + diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap index bf7d608e30c6..748019d4a423 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap @@ -50,6 +50,14 @@ exports[`atom has feed item for each post 1`] = ` https://sebastienlorber.com + + <![CDATA[unlisted]]> + /unlisted + + 2020-02-27T00:00:00.000Z + + this post is unlisted

    ]]>
    +
    <![CDATA[some heading]]> /heading-as-title @@ -135,6 +143,15 @@ exports[`json has feed item for each post 1`] = ` }, "tags": [] }, + { + "id": "/unlisted", + "content_html": "

    this post is unlisted

    ", + "url": "https://docusaurus.io/myBaseUrl/blog/unlisted", + "title": "unlisted", + "summary": "this post is unlisted", + "date_modified": "2020-02-27T00:00:00.000Z", + "tags": [] + }, { "id": "/heading-as-title", "content_html": "", @@ -218,6 +235,14 @@ exports[`rss has feed item for each post 1`] = ` simple url slug

    ]]>
    + + <![CDATA[unlisted]]> + https://docusaurus.io/myBaseUrl/blog/unlisted + /unlisted + Thu, 27 Feb 2020 00:00:00 GMT + + this post is unlisted

    ]]>
    +
    <![CDATA[some heading]]> https://docusaurus.io/myBaseUrl/blog/heading-as-title diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts index 7d769afe3f69..083e3ca95ff9 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts @@ -365,6 +365,21 @@ describe('validateBlogPostFrontMatter draft', () => { }); }); +describe('validateBlogPostFrontMatter unlisted', () => { + testField({ + fieldName: 'unlisted', + validFrontMatters: [{unlisted: true}, {unlisted: false}], + convertibleFrontMatter: [ + [{unlisted: 'true'}, {unlisted: true}], + [{unlisted: 'false'}, {unlisted: false}], + ], + invalidFrontMatters: [ + [{unlisted: 'yes'}, 'must be a boolean'], + [{unlisted: 'no'}, 'must be a boolean'], + ], + }); +}); + describe('validateBlogPostFrontMatter hide_table_of_contents', () => { testField({ fieldName: 'hide_table_of_contents', diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 64998082ff53..4e767a138b6a 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -172,6 +172,7 @@ describe('blog plugin', () => { title: 'Happy 1st Birthday Slash! (translated)', }, hasTruncateMarker: false, + unlisted: false, }); expect( @@ -215,6 +216,7 @@ describe('blog plugin', () => { title: 'date-matter', }, hasTruncateMarker: false, + unlisted: false, }); expect({ @@ -252,6 +254,7 @@ describe('blog plugin', () => { }, ], hasTruncateMarker: false, + unlisted: false, }); expect({ @@ -289,6 +292,7 @@ describe('blog plugin', () => { }, tags: [], hasTruncateMarker: false, + unlisted: false, }); expect({ @@ -314,13 +318,14 @@ describe('blog plugin', () => { title: 'date-matter', }, hasTruncateMarker: false, + unlisted: false, }); }); it('builds simple website blog with localized dates', async () => { const siteDir = path.join(__dirname, '__fixtures__', 'website'); const blogPostsFrench = await getBlogPosts(siteDir, {}, getI18n('fr')); - expect(blogPostsFrench).toHaveLength(8); + expect(blogPostsFrench).toHaveLength(9); expect(blogPostsFrench[0]!.metadata.formattedDate).toMatchInlineSnapshot( `"6 mars 2021"`, ); @@ -337,13 +342,13 @@ describe('blog plugin', () => { `"27 février 2020"`, ); expect(blogPostsFrench[5]!.metadata.formattedDate).toMatchInlineSnapshot( - `"2 janvier 2019"`, + `"27 février 2020"`, ); expect(blogPostsFrench[6]!.metadata.formattedDate).toMatchInlineSnapshot( - `"1 janvier 2019"`, + `"2 janvier 2019"`, ); expect(blogPostsFrench[7]!.metadata.formattedDate).toMatchInlineSnapshot( - `"14 décembre 2018"`, + `"1 janvier 2019"`, ); }); @@ -372,7 +377,7 @@ describe('blog plugin', () => { expect(blogPost.metadata.editUrl).toEqual(hardcodedEditUrl); }); - expect(editUrlFunction).toHaveBeenCalledTimes(8); + expect(editUrlFunction).toHaveBeenCalledTimes(9); expect(editUrlFunction).toHaveBeenCalledWith({ blogDirPath: 'blog', @@ -471,6 +476,7 @@ describe('blog plugin', () => { prevItem: undefined, nextItem: undefined, hasTruncateMarker: false, + unlisted: false, }); }); diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 17e0dbb0bffc..eb7144ffee68 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -33,6 +33,7 @@ import type { BlogPost, BlogTags, BlogPaginated, + BlogPostFrontMatter, } from '@docusaurus/plugin-content-blog'; import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types'; @@ -186,6 +187,16 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute: string) { const defaultReadingTime: ReadingTimeFunction = ({content, options}) => readingTime(content, options).minutes; +function isHiddenForProduction({ + type, + frontMatter, +}: { + type: 'draft' | 'unlisted'; + frontMatter: BlogPostFrontMatter; +}): boolean { + return (process.env.NODE_ENV === 'production' && frontMatter[type]) ?? false; +} + async function processBlogSourceFile( blogSourceRelative: string, contentPaths: BlogContentPaths, @@ -219,7 +230,10 @@ async function processBlogSourceFile( const aliasedSource = aliasedSitePath(blogSourceAbsolute, siteDir); - if (frontMatter.draft && process.env.NODE_ENV === 'production') { + const draft = isHiddenForProduction({type: 'draft', frontMatter}); + const unlisted = isHiddenForProduction({type: 'unlisted', frontMatter}); + + if (draft) { return undefined; } @@ -326,6 +340,7 @@ async function processBlogSourceFile( hasTruncateMarker: truncateMarker.test(content), authors, frontMatter, + unlisted, }, content, }; diff --git a/packages/docusaurus-plugin-content-blog/src/frontMatter.ts b/packages/docusaurus-plugin-content-blog/src/frontMatter.ts index 417bf1df00fb..393bd79e2118 100644 --- a/packages/docusaurus-plugin-content-blog/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-blog/src/frontMatter.ts @@ -33,6 +33,7 @@ const BlogFrontMatterSchema = Joi.object({ description: Joi.string().allow(''), tags: FrontMatterTagsSchema, draft: Joi.boolean(), + unlisted: Joi.boolean(), date: Joi.date().raw(), // New multi-authors front matter: diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 315c87e6a792..4e28ccc853bc 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -112,6 +112,9 @@ export default async function pluginContentBlog( const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]); const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]); const blogPosts = await generateBlogPosts(contentPaths, context, options); + const listedBlogPosts = blogPosts.filter( + (blogPost) => !blogPost.metadata.unlisted, + ); if (!blogPosts.length) { return { @@ -125,8 +128,8 @@ export default async function pluginContentBlog( } // Colocate next and prev metadata. - blogPosts.forEach((blogPost, index) => { - const prevItem = index > 0 ? blogPosts[index - 1] : null; + listedBlogPosts.forEach((blogPost, index) => { + const prevItem = index > 0 ? listedBlogPosts[index - 1] : null; if (prevItem) { blogPost.metadata.prevItem = { title: prevItem.metadata.title, @@ -135,7 +138,9 @@ export default async function pluginContentBlog( } const nextItem = - index < blogPosts.length - 1 ? blogPosts[index + 1] : null; + index < listedBlogPosts.length - 1 + ? listedBlogPosts[index + 1] + : null; if (nextItem) { blogPost.metadata.nextItem = { title: nextItem.metadata.title, @@ -145,7 +150,7 @@ export default async function pluginContentBlog( }); const blogListPaginated: BlogPaginated[] = paginateBlogPosts({ - blogPosts, + blogPosts: listedBlogPosts, blogTitle, blogDescription, postsPerPageOption, @@ -153,7 +158,7 @@ export default async function pluginContentBlog( }); const blogTags: BlogTags = getBlogTags({ - blogPosts, + blogPosts: listedBlogPosts, postsPerPageOption, blogDescription, blogTitle, @@ -242,6 +247,7 @@ export default async function pluginContentBlog( items: sidebarBlogPosts.map((blogPost) => ({ title: blogPost.metadata.title, permalink: blogPost.metadata.permalink, + unlisted: blogPost.metadata.unlisted, })), }, null, diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index 63d31d5f58c7..1459a5cf8599 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -90,6 +90,10 @@ declare module '@docusaurus/plugin-content-blog' { * Marks the post as draft and excludes it from the production build. */ draft?: boolean; + /** + * Marks the post as unlisted and visibly hides it unless directly accessed. + */ + unlisted?: boolean; /** * Will override the default publish date inferred from git/filename. Yaml * only converts standard yyyy-MM-dd format to dates, so this may stay as a @@ -222,6 +226,10 @@ declare module '@docusaurus/plugin-content-blog' { readonly frontMatter: BlogPostFrontMatter & {[key: string]: unknown}; /** Tags, normalized. */ readonly tags: Tag[]; + /** + * Marks the post as unlisted and visibly hides it unless directly accessed. + */ + readonly unlisted?: boolean; }; /** * @returns The edit URL that's directly plugged into metadata. @@ -409,7 +417,7 @@ declare module '@docusaurus/plugin-content-blog' { export type BlogSidebar = { title: string; - items: {title: string; permalink: string}[]; + items: {title: string; permalink: string; unlisted: boolean}[]; }; export type BlogContent = { diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx index 515e104baa8e..ce420f793c29 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx @@ -11,7 +11,8 @@ import {useBlogPost} from '@docusaurus/theme-common/internal'; export default function BlogPostPageMetadata(): JSX.Element { const {assets, metadata} = useBlogPost(); - const {title, description, date, tags, authors, frontMatter} = metadata; + const {title, description, date, tags, authors, frontMatter, unlisted} = + metadata; const {keywords} = frontMatter; const image = assets.image ?? frontMatter.image; @@ -39,6 +40,7 @@ export default function BlogPostPageMetadata(): JSX.Element { content={tags.map((tag) => tag.label).join(',')} /> )} + {unlisted && } ); } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx index f010d2144836..d9a2ee6b8d25 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx @@ -9,11 +9,14 @@ import React from 'react'; import clsx from 'clsx'; import Link from '@docusaurus/Link'; import {translate} from '@docusaurus/Translate'; +import {useLocation} from '@docusaurus/router'; +import {isSamePath} from '@docusaurus/theme-common/internal'; import type {Props} from '@theme/BlogSidebar/Desktop'; import styles from './styles.module.css'; export default function BlogSidebarDesktop({sidebar}: Props): JSX.Element { + const {pathname} = useLocation(); return ( diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx index a07967840419..a2c0433fd2ae 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx @@ -7,23 +7,34 @@ import React from 'react'; import Link from '@docusaurus/Link'; +import {useLocation} from '@docusaurus/router'; +import {isSamePath} from '@docusaurus/theme-common/internal'; import {NavbarSecondaryMenuFiller} from '@docusaurus/theme-common'; import type {Props} from '@theme/BlogSidebar/Mobile'; function BlogSidebarMobileSecondaryMenu({sidebar}: Props): JSX.Element { + const {pathname} = useLocation(); return (
      - {sidebar.items.map((item) => ( -
    • - - {item.title} - -
    • - ))} + {sidebar.items + .filter((item) => { + if (item.unlisted && !isSamePath(item.permalink, pathname)) { + return false; + } + + return true; + }) + .map((item) => ( +
    • + + {item.title} + +
    • + ))}
    ); } diff --git a/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md new file mode 100644 index 000000000000..5620b9c99da5 --- /dev/null +++ b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md @@ -0,0 +1,7 @@ +--- +title: Unlisted blog post +unlisted: true +tags: [blog] +--- + +This unlisted blog post should always be directly accessible in any environment, but in production the sidebar link and pagination should only be visible when on the page itself diff --git a/website/_dogfooding/dogfooding.config.js b/website/_dogfooding/dogfooding.config.js index e961bca132a5..027447e97ef2 100644 --- a/website/_dogfooding/dogfooding.config.js +++ b/website/_dogfooding/dogfooding.config.js @@ -72,7 +72,8 @@ const dogfoodingPluginInstances = [ frontMatter.hide_reading_time ? undefined : defaultReadingTime({content, options: {wordsPerMinute: 5}}), - sortPosts: 'ascending', + // TODO: undo this + sortPosts: 'descending', }), ], diff --git a/website/docs/api/plugins/plugin-content-blog.md b/website/docs/api/plugins/plugin-content-blog.md index 696b4102858d..6e55adf6c242 100644 --- a/website/docs/api/plugins/plugin-content-blog.md +++ b/website/docs/api/plugins/plugin-content-blog.md @@ -193,6 +193,7 @@ Accepted fields: | `date` | `string` | File name or file creation time | The blog post creation date. If not specified, this can be extracted from the file or folder name, e.g, `2021-04-15-blog-post.mdx`, `2021-04-15-blog-post/index.mdx`, `2021/04/15/blog-post.mdx`. Otherwise, it is the Markdown file creation time. | | `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your post. | | `draft` | `boolean` | `false` | A boolean flag to indicate that the blog post is work-in-progress. Draft blog posts will only be displayed during development. | +| `unlisted` | `boolean` | `false` | A boolean flag to indicate that the blog post should be accessible if linked to directly, but visibly hidden on the site otherwise and ignored by search engines. Unlisted blog posts are fully visible in development. | | `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. | | `toc_min_heading_level` | `number` | `2` | The minimum heading level shown in the table of contents. Must be between 2 and 6 and lower or equal to the max value. | | `toc_max_heading_level` | `number` | `3` | The max heading level shown in the table of contents. Must be between 2 and 6. | From d03283d2114e48bdf66386db0b5aa3e64e7e6635 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 15:53:02 +0200 Subject: [PATCH 04/50] dedup unlisted/draft logic --- .../src/blogUtils.ts | 17 ++----- .../src/docs.ts | 23 ++-------- .../src/theme/DocItem/Metadata/index.tsx | 4 +- .../src/contentVisibilityUtils.ts | 44 +++++++++++++++++++ packages/docusaurus-utils/src/index.ts | 1 + 5 files changed, 54 insertions(+), 35 deletions(-) create mode 100644 packages/docusaurus-utils/src/contentVisibilityUtils.ts diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index eb7144ffee68..10abe3af877c 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -23,6 +23,8 @@ import { groupTaggedItems, getFileCommitDate, getContentPathList, + isUnlisted, + isDraft, } from '@docusaurus/utils'; import {validateBlogPostFrontMatter} from './frontMatter'; import {type AuthorsMap, getAuthorsMap, getBlogPostAuthors} from './authors'; @@ -33,7 +35,6 @@ import type { BlogPost, BlogTags, BlogPaginated, - BlogPostFrontMatter, } from '@docusaurus/plugin-content-blog'; import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types'; @@ -187,16 +188,6 @@ async function parseBlogPostMarkdownFile(blogSourceAbsolute: string) { const defaultReadingTime: ReadingTimeFunction = ({content, options}) => readingTime(content, options).minutes; -function isHiddenForProduction({ - type, - frontMatter, -}: { - type: 'draft' | 'unlisted'; - frontMatter: BlogPostFrontMatter; -}): boolean { - return (process.env.NODE_ENV === 'production' && frontMatter[type]) ?? false; -} - async function processBlogSourceFile( blogSourceRelative: string, contentPaths: BlogContentPaths, @@ -230,8 +221,8 @@ async function processBlogSourceFile( const aliasedSource = aliasedSitePath(blogSourceAbsolute, siteDir); - const draft = isHiddenForProduction({type: 'draft', frontMatter}); - const unlisted = isHiddenForProduction({type: 'unlisted', frontMatter}); + const draft = isDraft({frontMatter}); + const unlisted = isUnlisted({frontMatter}); if (draft) { return undefined; diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index c7349fa030df..e6aad8d338a7 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -18,6 +18,8 @@ import { posixPath, Globby, normalizeFrontMatterTags, + isUnlisted, + isDraft, } from '@docusaurus/utils'; import {getFileLastUpdate} from './lastUpdate'; @@ -35,7 +37,6 @@ import type { PropNavigationLink, LastUpdateData, VersionMetadata, - DocFrontMatter, LoadedVersion, FileChange, } from '@docusaurus/plugin-content-docs'; @@ -125,22 +126,6 @@ export async function readVersionDocs( export type DocEnv = 'production' | 'development'; -/** - * Docs with draft or unlisted front matter are only - * considered to be so in production. - */ -function isHiddenForEnvironment({ - type, - env, - frontMatter, -}: { - type: 'draft' | 'unlisted'; - frontMatter: DocFrontMatter; - env: DocEnv; -}): boolean { - return (env === 'production' && frontMatter[type]) ?? false; -} - async function doProcessDocMetadata({ docFile, versionMetadata, @@ -273,8 +258,8 @@ async function doProcessDocMetadata({ return undefined; } - const draft = isHiddenForEnvironment({type: 'draft', env, frontMatter}); - const unlisted = isHiddenForEnvironment({type: 'unlisted', env, frontMatter}); + const draft = isDraft({env, frontMatter}); + const unlisted = isUnlisted({env, frontMatter}); const formatDate = (locale: string, date: Date, calendar: string): string => { try { diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx index 5eb81fc67f36..1ee9cb506420 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx @@ -17,9 +17,7 @@ export default function DocItemMetadata(): JSX.Element { description={metadata.description} keywords={frontMatter.keywords} image={assets.image ?? frontMatter.image}> - {process.env.NODE_ENV === 'production' && frontMatter.unlisted && ( - - )} + {metadata.unlisted && } ); } diff --git a/packages/docusaurus-utils/src/contentVisibilityUtils.ts b/packages/docusaurus-utils/src/contentVisibilityUtils.ts new file mode 100644 index 000000000000..0385b3634191 --- /dev/null +++ b/packages/docusaurus-utils/src/contentVisibilityUtils.ts @@ -0,0 +1,44 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +type Env = 'production' | 'development'; + +/** + * draft/unlisted is a production-only concept + * In dev it is ignored and all content files are included + */ +function isProduction(env: Env | undefined): boolean { + return (env ?? process.env.NODE_ENV) === 'production'; +} + +/** + * A draft content will not be included in the production build + */ +export function isDraft({ + frontMatter, + env, +}: { + frontMatter: {draft?: boolean}; + env?: Env; +}): boolean { + return (isProduction(env) && frontMatter.draft) ?? false; +} + +/** + * An unlisted content will be included in the production build, but hidden. + * It is excluded from sitemap, has noIndex, does not appear in lists etc... + * Only users having the link can find it. + */ +export function isUnlisted({ + frontMatter, + env, +}: { + frontMatter: {unlisted?: boolean}; + env?: Env; +}): boolean { + return (isProduction(env) && frontMatter.unlisted) ?? false; +} diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index 06f553c43f1c..a555dfd341a5 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -103,3 +103,4 @@ export { findFolderContainingFile, getFolderContainingFile, } from './dataFileUtils'; +export {isDraft, isUnlisted} from './contentVisibilityUtils'; From f25969adec56b61ec1e315f319ece30fccca69cc Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 15:59:01 +0200 Subject: [PATCH 05/50] add page unlisted metadata --- .../src/__tests__/__snapshots__/index.test.ts.snap | 6 ++++++ packages/docusaurus-plugin-content-pages/src/index.ts | 6 ++++++ .../src/plugin-content-pages.d.ts | 1 + 3 files changed, 13 insertions(+) diff --git a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap index c4c22e849260..56028498771e 100644 --- a/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-pages/src/__tests__/__snapshots__/index.test.ts.snap @@ -19,6 +19,7 @@ exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` "source": "@site/src/pages/hello/index.md", "title": "Index", "type": "mdx", + "unlisted": false, }, { "description": "my MDX page", @@ -30,6 +31,7 @@ exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` "source": "@site/src/pages/hello/mdxPage.mdx", "title": "MDX page", "type": "mdx", + "unlisted": false, }, { "permalink": "/hello/translatedJs", @@ -43,6 +45,7 @@ exports[`docusaurus-plugin-content-pages loads simple pages 1`] = ` "source": "@site/src/pages/hello/translatedMd.md", "title": undefined, "type": "mdx", + "unlisted": false, }, { "permalink": "/hello/world", @@ -71,6 +74,7 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat "source": "@site/src/pages/hello/index.md", "title": "Index", "type": "mdx", + "unlisted": false, }, { "description": "my MDX page", @@ -82,6 +86,7 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat "source": "@site/src/pages/hello/mdxPage.mdx", "title": "MDX page", "type": "mdx", + "unlisted": false, }, { "permalink": "/fr/hello/translatedJs", @@ -95,6 +100,7 @@ exports[`docusaurus-plugin-content-pages loads simple pages with french translat "source": "@site/i18n/fr/docusaurus-plugin-content-pages/hello/translatedMd.md", "title": undefined, "type": "mdx", + "unlisted": false, }, { "permalink": "/fr/hello/world", diff --git a/packages/docusaurus-plugin-content-pages/src/index.ts b/packages/docusaurus-plugin-content-pages/src/index.ts index c3c51b883283..b983a96ccf44 100644 --- a/packages/docusaurus-plugin-content-pages/src/index.ts +++ b/packages/docusaurus-plugin-content-pages/src/index.ts @@ -20,6 +20,7 @@ import { normalizeUrl, DEFAULT_PLUGIN_ID, parseMarkdownString, + isUnlisted, } from '@docusaurus/utils'; import {validatePageFrontMatter} from './frontMatter'; @@ -110,6 +111,10 @@ export default function pluginContentPages( excerpt, } = parseMarkdownString(content); const frontMatter = validatePageFrontMatter(unsafeFrontMatter); + + // TODO draft support is missing + const unlisted = isUnlisted({frontMatter}); + return { type: 'mdx', permalink, @@ -117,6 +122,7 @@ export default function pluginContentPages( title: frontMatter.title ?? contentTitle, description: frontMatter.description ?? excerpt, frontMatter, + unlisted, }; } diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index 0de96fe42965..d71f073090b1 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -43,6 +43,7 @@ declare module '@docusaurus/plugin-content-pages' { frontMatter: FrontMatter & {[key: string]: unknown}; title?: string; description?: string; + unlisted: boolean; }; export type Metadata = JSXPageMetadata | MDXPageMetadata; From 62b1ecf684cae2257177bc05e7ffab5de47980b8 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 17:33:23 +0200 Subject: [PATCH 06/50] use unlisted metadata in mdx page --- .../src/theme/MDXPage/index.tsx | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index 1090b182b485..637e6f7e56a0 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -22,13 +22,10 @@ import styles from './styles.module.css'; export default function MDXPage(props: Props): JSX.Element { const {content: MDXPageContent} = props; const { - metadata: {title, description, frontMatter}, + metadata: {title, description, frontMatter, unlisted}, } = MDXPageContent; - const { - wrapperClassName, - hide_table_of_contents: hideTableOfContents, - unlisted, - } = frontMatter; + const {wrapperClassName, hide_table_of_contents: hideTableOfContents} = + frontMatter; return ( - {process.env.NODE_ENV === 'production' && unlisted && ( - - )} + {unlisted && }
    From bda2d10ff98fa49e5a444bab9f6a3081eba3c4dd Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 17:42:58 +0200 Subject: [PATCH 07/50] optimize unlisted global data size: no attribute if unlisted false/undefined --- .../__snapshots__/globalData.test.ts.snap | 8 ++- .../__snapshots__/index.test.ts.snap | 61 ------------------- .../src/__tests__/globalData.test.ts | 9 +++ .../src/client/index.ts | 2 +- .../src/globalData.ts | 6 +- 5 files changed, 21 insertions(+), 65 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap index 5e80d835e738..b8bcdf05873b 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/globalData.test.ts.snap @@ -7,13 +7,17 @@ exports[`toGlobalDataVersion generates the right docs, sidebars, and metadata 1` "id": "main", "path": "/current/main", "sidebar": "tutorial", - "unlisted": undefined, }, { "id": "doc", "path": "/current/doc", "sidebar": "tutorial", - "unlisted": undefined, + }, + { + "id": "docNoSidebarUnlisted", + "path": "/current/docNoSidebarUnlisted", + "sidebar": undefined, + "unlisted": true, }, { "id": "/current/generated", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 8bd3e0da512b..bdf9abaefd34 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -278,121 +278,101 @@ exports[`simple website content 5`] = ` "id": "customLastUpdate", "path": "/docs/customLastUpdate", "sidebar": undefined, - "unlisted": false, }, { "id": "doc with space", "path": "/docs/doc with space", "sidebar": undefined, - "unlisted": false, }, { "id": "doc-draft", "path": "/docs/doc-draft", "sidebar": undefined, - "unlisted": false, }, { "id": "doc-unlisted", "path": "/docs/doc-unlisted", "sidebar": undefined, - "unlisted": false, }, { "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "docs", - "unlisted": false, }, { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", "sidebar": "docs", - "unlisted": false, }, { "id": "headingAsTitle", "path": "/docs/headingAsTitle", "sidebar": "docs", - "unlisted": false, }, { "id": "hello", "path": "/docs/", "sidebar": "docs", - "unlisted": false, }, { "id": "ipsum", "path": "/docs/ipsum", "sidebar": undefined, - "unlisted": false, }, { "id": "lastUpdateAuthorOnly", "path": "/docs/lastUpdateAuthorOnly", "sidebar": undefined, - "unlisted": false, }, { "id": "lastUpdateDateOnly", "path": "/docs/lastUpdateDateOnly", "sidebar": undefined, - "unlisted": false, }, { "id": "lorem", "path": "/docs/lorem", "sidebar": undefined, - "unlisted": false, }, { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "/category/slugs", @@ -1201,121 +1181,101 @@ exports[`simple website content: global data 1`] = ` "id": "customLastUpdate", "path": "/docs/customLastUpdate", "sidebar": undefined, - "unlisted": false, }, { "id": "doc with space", "path": "/docs/doc with space", "sidebar": undefined, - "unlisted": false, }, { "id": "doc-draft", "path": "/docs/doc-draft", "sidebar": undefined, - "unlisted": false, }, { "id": "doc-unlisted", "path": "/docs/doc-unlisted", "sidebar": undefined, - "unlisted": false, }, { "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "docs", - "unlisted": false, }, { "id": "foo/baz", "path": "/docs/foo/bazSlug.html", "sidebar": "docs", - "unlisted": false, }, { "id": "headingAsTitle", "path": "/docs/headingAsTitle", "sidebar": "docs", - "unlisted": false, }, { "id": "hello", "path": "/docs/", "sidebar": "docs", - "unlisted": false, }, { "id": "ipsum", "path": "/docs/ipsum", "sidebar": undefined, - "unlisted": false, }, { "id": "lastUpdateAuthorOnly", "path": "/docs/lastUpdateAuthorOnly", "sidebar": undefined, - "unlisted": false, }, { "id": "lastUpdateDateOnly", "path": "/docs/lastUpdateDateOnly", "sidebar": undefined, - "unlisted": false, }, { "id": "lorem", "path": "/docs/lorem", "sidebar": undefined, - "unlisted": false, }, { "id": "rootAbsoluteSlug", "path": "/docs/rootAbsoluteSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "rootRelativeSlug", "path": "/docs/rootRelativeSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "rootResolvedSlug", "path": "/docs/hey/rootResolvedSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "rootTryToEscapeSlug", "path": "/docs/rootTryToEscapeSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/absoluteSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/slugs/relativeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/slugs/hey/resolvedSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/tryToEscapeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "/category/slugs", @@ -2825,7 +2785,6 @@ exports[`versioned website (community) content: global data 1`] = ` "id": "team", "path": "/community/next/team", "sidebar": "community", - "unlisted": false, }, ], "draftIds": [], @@ -2849,7 +2808,6 @@ exports[`versioned website (community) content: global data 1`] = ` "id": "team", "path": "/community/team", "sidebar": "version-1.0.0/community", - "unlisted": false, }, ], "draftIds": [], @@ -3966,37 +3924,31 @@ exports[`versioned website content: global data 1`] = ` "id": "foo/bar", "path": "/docs/next/foo/barSlug", "sidebar": "docs", - "unlisted": false, }, { "id": "hello", "path": "/docs/next/", "sidebar": "docs", - "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/next/absoluteSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/next/slugs/relativeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/next/slugs/hey/resolvedSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/next/tryToEscapeSlug", "sidebar": undefined, - "unlisted": false, }, ], "draftIds": [], @@ -4020,13 +3972,11 @@ exports[`versioned website content: global data 1`] = ` "id": "foo/bar", "path": "/docs/foo/bar", "sidebar": "VersionedSideBarNameDoesNotMatter/docs", - "unlisted": false, }, { "id": "hello", "path": "/docs/", "sidebar": "VersionedSideBarNameDoesNotMatter/docs", - "unlisted": false, }, ], "draftIds": [], @@ -4050,19 +4000,16 @@ exports[`versioned website content: global data 1`] = ` "id": "foo/bar", "path": "/docs/1.0.0/foo/barSlug", "sidebar": "version-1.0.0/docs", - "unlisted": false, }, { "id": "foo/baz", "path": "/docs/1.0.0/foo/baz", "sidebar": "version-1.0.0/docs", - "unlisted": false, }, { "id": "hello", "path": "/docs/1.0.0/", "sidebar": "version-1.0.0/docs", - "unlisted": false, }, ], "draftIds": [], @@ -4086,49 +4033,41 @@ exports[`versioned website content: global data 1`] = ` "id": "rootAbsoluteSlug", "path": "/docs/withSlugs/rootAbsoluteSlug", "sidebar": "version-1.0.1/docs", - "unlisted": false, }, { "id": "rootRelativeSlug", "path": "/docs/withSlugs/rootRelativeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "rootResolvedSlug", "path": "/docs/withSlugs/hey/rootResolvedSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "rootTryToEscapeSlug", "path": "/docs/withSlugs/rootTryToEscapeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/absoluteSlug", "path": "/docs/withSlugs/absoluteSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/relativeSlug", "path": "/docs/withSlugs/slugs/relativeSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/resolvedSlug", "path": "/docs/withSlugs/slugs/hey/resolvedSlug", "sidebar": undefined, - "unlisted": false, }, { "id": "slugs/tryToEscapeSlug", "path": "/docs/withSlugs/tryToEscapeSlug", "sidebar": undefined, - "unlisted": false, }, ], "draftIds": [], diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts index 35663e48b7aa..062c02404003 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/globalData.test.ts @@ -19,12 +19,21 @@ describe('toGlobalDataVersion', () => { permalink: '/current/main', sidebar: 'tutorial', frontMatter: {}, + unlisted: false, }, { unversionedId: 'doc', permalink: '/current/doc', sidebar: 'tutorial', frontMatter: {}, + unlisted: undefined, + }, + { + unversionedId: 'docNoSidebarUnlisted', + permalink: '/current/docNoSidebarUnlisted', + sidebar: undefined, + frontMatter: {}, + unlisted: true, }, ] as DocMetadata[]; const sidebars: Sidebars = { diff --git a/packages/docusaurus-plugin-content-docs/src/client/index.ts b/packages/docusaurus-plugin-content-docs/src/client/index.ts index 824daed1816b..335729b898fd 100644 --- a/packages/docusaurus-plugin-content-docs/src/client/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/client/index.ts @@ -37,7 +37,7 @@ export type GlobalDoc = { */ id: string; path: string; - sidebar: string | undefined; + sidebar?: string; unlisted?: boolean; }; diff --git a/packages/docusaurus-plugin-content-docs/src/globalData.ts b/packages/docusaurus-plugin-content-docs/src/globalData.ts index ab39b83abc3b..5679e2f68e52 100644 --- a/packages/docusaurus-plugin-content-docs/src/globalData.ts +++ b/packages/docusaurus-plugin-content-docs/src/globalData.ts @@ -23,8 +23,12 @@ function toGlobalDataDoc(doc: DocMetadata): GlobalDoc { return { id: doc.unversionedId, path: doc.permalink, + + // optimize global data size: do not add unlisted: false/undefined + ...(doc.unlisted && {unlisted: doc.unlisted}), + + // TODO optimize size? remove attribute when no sidebar (breaking change?) sidebar: doc.sidebar, - unlisted: doc.unlisted, }; } From 8b84d30827a2999e0a1450c48a969f15a43134b3 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 18:03:02 +0200 Subject: [PATCH 08/50] deduplicate blog sidebar item filtering --- .../src/plugin-content-blog.d.ts | 8 +++- .../src/theme/BlogSidebar/Desktop/index.tsx | 35 ++++++---------- .../src/theme/BlogSidebar/Mobile/index.tsx | 35 ++++++---------- .../docusaurus-theme-common/src/internal.ts | 2 + .../src/utils/blogUtils.ts | 40 +++++++++++++++++++ 5 files changed, 75 insertions(+), 45 deletions(-) create mode 100644 packages/docusaurus-theme-common/src/utils/blogUtils.ts diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index 1459a5cf8599..b30a1c6015b8 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -415,9 +415,15 @@ declare module '@docusaurus/plugin-content-blog' { } >; + export type BlogSidebarItem = { + title: string; + permalink: string; + unlisted: boolean; + }; + export type BlogSidebar = { title: string; - items: {title: string; permalink: string; unlisted: boolean}[]; + items: BlogSidebarItem[]; }; export type BlogContent = { diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx index d9a2ee6b8d25..8488a49e3116 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Desktop/index.tsx @@ -9,14 +9,13 @@ import React from 'react'; import clsx from 'clsx'; import Link from '@docusaurus/Link'; import {translate} from '@docusaurus/Translate'; -import {useLocation} from '@docusaurus/router'; -import {isSamePath} from '@docusaurus/theme-common/internal'; +import {useVisibleBlogSidebarItems} from '@docusaurus/theme-common/internal'; import type {Props} from '@theme/BlogSidebar/Desktop'; import styles from './styles.module.css'; export default function BlogSidebarDesktop({sidebar}: Props): JSX.Element { - const {pathname} = useLocation(); + const items = useVisibleBlogSidebarItems(sidebar.items); return ( diff --git a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx index a2c0433fd2ae..7b021d7f39b7 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogSidebar/Mobile/index.tsx @@ -7,34 +7,25 @@ import React from 'react'; import Link from '@docusaurus/Link'; -import {useLocation} from '@docusaurus/router'; -import {isSamePath} from '@docusaurus/theme-common/internal'; +import {useVisibleBlogSidebarItems} from '@docusaurus/theme-common/internal'; import {NavbarSecondaryMenuFiller} from '@docusaurus/theme-common'; import type {Props} from '@theme/BlogSidebar/Mobile'; function BlogSidebarMobileSecondaryMenu({sidebar}: Props): JSX.Element { - const {pathname} = useLocation(); + const items = useVisibleBlogSidebarItems(sidebar.items); return (
      - {sidebar.items - .filter((item) => { - if (item.unlisted && !isSamePath(item.permalink, pathname)) { - return false; - } - - return true; - }) - .map((item) => ( -
    • - - {item.title} - -
    • - ))} + {items.map((item) => ( +
    • + + {item.title} + +
    • + ))}
    ); } diff --git a/packages/docusaurus-theme-common/src/internal.ts b/packages/docusaurus-theme-common/src/internal.ts index aefaa2ddbabf..3fcf164c8e88 100644 --- a/packages/docusaurus-theme-common/src/internal.ts +++ b/packages/docusaurus-theme-common/src/internal.ts @@ -109,6 +109,8 @@ export { type TOCHighlightConfig, } from './hooks/useTOCHighlight'; +export {useVisibleBlogSidebarItems} from './utils/blogUtils'; + export {useHideableNavbar} from './hooks/useHideableNavbar'; export { useKeyboardNavigation, diff --git a/packages/docusaurus-theme-common/src/utils/blogUtils.ts b/packages/docusaurus-theme-common/src/utils/blogUtils.ts new file mode 100644 index 000000000000..b8dc04ca04cb --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/blogUtils.ts @@ -0,0 +1,40 @@ +/** + * 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 {useMemo} from 'react'; +import {useLocation} from '@docusaurus/router'; +import {isSamePath} from './routesUtils'; +import type {BlogSidebarItem} from '@docusaurus/plugin-content-blog'; + +function filterUnlistedBlogSidebarItems( + items: BlogSidebarItem[], + pathname: string, +): BlogSidebarItem[] { + return items.filter((item) => { + if (item.unlisted && !isSamePath(item.permalink, pathname)) { + return false; + } + return true; + }); +} + +/** + * Return the visible blog sidebar items to display. + * Unlisted items are filtered. + */ +export function useVisibleBlogSidebarItems( + // TODO put blog sidebar in a React context + // We should make it accessible to the whole blog layout subtree + // This hook could have no param + items: BlogSidebarItem[], +): BlogSidebarItem[] { + const {pathname} = useLocation(); + return useMemo( + () => filterUnlistedBlogSidebarItems(items, pathname), + [items, pathname], + ); +} From de872c2c9cddeb6a26b62f2de743cd08da32f3dc Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 19:10:31 +0200 Subject: [PATCH 09/50] improve project draft/unlisted dogfood --- website/_dogfooding/_docs tests/test-draft.md | 7 ------ .../_dogfooding/_docs tests/test-unlisted.md | 7 ------ .../_docs tests/tests/visibility/index.md | 22 +++++++++++++++++++ .../only-drafts/draft-subcategory/draft3.md | 7 ++++++ .../tests/visibility/only-drafts/draft1.md | 7 ++++++ .../tests/visibility/only-drafts/draft2.md | 7 ++++++ .../unlisted-subcategory/unlisted3.md | 7 ++++++ .../visibility/only-unlisteds/unlisted1.md | 7 ++++++ .../visibility/only-unlisteds/unlisted2.md | 7 ++++++ .../some-drafts/draft-subcategory/draft3.md | 7 ++++++ .../some-drafts/draft-subcategory/listed1.md | 3 +++ .../tests/visibility/some-drafts/draft1.md | 7 ++++++ .../tests/visibility/some-drafts/draft2.md | 7 ++++++ .../unlisted-subcategory/listed1.md | 3 +++ .../unlisted-subcategory/unlisted3.md | 7 ++++++ .../visibility/some-unlisteds/unlisted1.md | 7 ++++++ .../visibility/some-unlisteds/unlisted2.md | 7 ++++++ website/_dogfooding/_pages tests/index.md | 2 +- .../{test-unlisted.mdx => unlisted.mdx} | 0 website/_dogfooding/docs-tests-sidebars.js | 13 ----------- website/docusaurus.config.js | 4 ++-- 21 files changed, 115 insertions(+), 30 deletions(-) delete mode 100644 website/_dogfooding/_docs tests/test-draft.md delete mode 100644 website/_dogfooding/_docs tests/test-unlisted.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/index.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md rename website/_dogfooding/_pages tests/{test-unlisted.mdx => unlisted.mdx} (100%) diff --git a/website/_dogfooding/_docs tests/test-draft.md b/website/_dogfooding/_docs tests/test-draft.md deleted file mode 100644 index 7c63da823d84..000000000000 --- a/website/_dogfooding/_docs tests/test-draft.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -draft: true ---- - -# Draft doc - -This draft doc (and the navbar link) should only be visible in local development diff --git a/website/_dogfooding/_docs tests/test-unlisted.md b/website/_dogfooding/_docs tests/test-unlisted.md deleted file mode 100644 index ebf623201a89..000000000000 --- a/website/_dogfooding/_docs tests/test-unlisted.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -unlisted: true ---- - -# Unlisted doc - -This unlisted doc should always be directly accessible in any environment, but in production the navbar link and pagination should only be visible when on the page itself diff --git a/website/_dogfooding/_docs tests/tests/visibility/index.md b/website/_dogfooding/_docs tests/tests/visibility/index.md new file mode 100644 index 000000000000..5d7a60b17e8b --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/index.md @@ -0,0 +1,22 @@ +# Visibility + +A category to play with draft/unlisted front matter. + +In dev, both draft/unlisted items are displayed. + +--- + +In production, draft items shouldn't be accessible: + +- [/tests/docs/tests/visibility/only-drafts/draft1](pathname:///tests/docs/tests/visibility/only-drafts/draft1) + +--- + +In production, unlisted items should remain accessible, but be hidden in the sidebar (unless currently browsed): + +- [./only-unlisteds/unlisted1.md](./only-unlisteds/unlisted1.md) +- [./only-unlisteds/unlisted2.md](./only-unlisteds/unlisted2.md) +- [./only-unlisteds/unlisted-subcategory/unlisted3.md](./only-unlisteds/unlisted-subcategory/unlisted3.md) +- [./some-unlisteds/unlisted1.md](./some-unlisteds/unlisted1.md) +- [./some-unlisteds/unlisted2.md](./some-unlisteds/unlisted2.md) +- [./some-unlisteds/unlisted-subcategory/unlisted3.md](./some-unlisteds/unlisted-subcategory/unlisted3.md) diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md new file mode 100644 index 000000000000..655423590453 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md @@ -0,0 +1,7 @@ +--- +draft: true +--- + +# Draft 2 + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md new file mode 100644 index 000000000000..298b96438405 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md @@ -0,0 +1,7 @@ +--- +draft: true +--- + +# Draft 1 + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md new file mode 100644 index 000000000000..655423590453 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md @@ -0,0 +1,7 @@ +--- +draft: true +--- + +# Draft 2 + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md new file mode 100644 index 000000000000..0217ed207114 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted 3 + +Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md new file mode 100644 index 000000000000..e62f23348cfc --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted 1 + +Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md new file mode 100644 index 000000000000..62b3571d1eaa --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted 2 + +Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md new file mode 100644 index 000000000000..655423590453 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md @@ -0,0 +1,7 @@ +--- +draft: true +--- + +# Draft 2 + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md new file mode 100644 index 000000000000..7af342c269bb --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md @@ -0,0 +1,3 @@ +# Listed 1 + +Regular doc diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md new file mode 100644 index 000000000000..298b96438405 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md @@ -0,0 +1,7 @@ +--- +draft: true +--- + +# Draft 1 + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md new file mode 100644 index 000000000000..655423590453 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md @@ -0,0 +1,7 @@ +--- +draft: true +--- + +# Draft 2 + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md new file mode 100644 index 000000000000..7af342c269bb --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md @@ -0,0 +1,3 @@ +# Listed 1 + +Regular doc diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md new file mode 100644 index 000000000000..0217ed207114 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted 3 + +Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md new file mode 100644 index 000000000000..e62f23348cfc --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted 1 + +Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md new file mode 100644 index 000000000000..62b3571d1eaa --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md @@ -0,0 +1,7 @@ +--- +unlisted: true +--- + +# Unlisted 2 + +Doc with unlisted front matter diff --git a/website/_dogfooding/_pages tests/index.md b/website/_dogfooding/_pages tests/index.md index d71e441ce3dd..50ac433cc7af 100644 --- a/website/_dogfooding/_pages tests/index.md +++ b/website/_dogfooding/_pages tests/index.md @@ -31,5 +31,5 @@ import Readme from "../README.md" - [Tabs tests](/tests/pages/tabs-tests) - [z-index tests](/tests/pages/z-index-tests) - [Head metadata tests](/tests/pages/head-metadata) -- [Unlisted page test](/tests/pages/test-unlisted +- [Unlisted page](/tests/pages/unlisted) - [Analytics](/tests/pages/analytics) diff --git a/website/_dogfooding/_pages tests/test-unlisted.mdx b/website/_dogfooding/_pages tests/unlisted.mdx similarity index 100% rename from website/_dogfooding/_pages tests/test-unlisted.mdx rename to website/_dogfooding/_pages tests/unlisted.mdx diff --git a/website/_dogfooding/docs-tests-sidebars.js b/website/_dogfooding/docs-tests-sidebars.js index b705e1192145..8b9f4d76d6f6 100644 --- a/website/_dogfooding/docs-tests-sidebars.js +++ b/website/_dogfooding/docs-tests-sidebars.js @@ -19,8 +19,6 @@ const sidebars = { className: 'red', label: 'Index', }, - 'test-draft', - 'test-unlisted', 'doc-without-sidebar', 'doc-with-another-sidebar', 'doc-with-last-update', @@ -48,17 +46,6 @@ const sidebars = { collapsible: false, items: ['index', 'more-test'], }, - { - type: 'category', - label: 'Category with only unlisted doc', - items: [ - { - type: 'category', - label: 'Sub-category with only unlisted doc', - items: ['test-unlisted'], - }, - ], - }, { type: 'category', label: 'Another category with index', diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index 9d79dddbf2ea..ad5e54b7d7ae 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -444,7 +444,7 @@ const config = { // This item links to a draft doc: only displayed in dev { type: 'doc', - docId: 'test-draft', + docId: 'tests/visibility/only-drafts/draft1', label: 'Draft', docsPluginId: 'docs-tests', }, @@ -452,7 +452,7 @@ const config = { // in dev or when directly access { type: 'doc', - docId: 'test-unlisted', + docId: 'tests/visibility/some-unlisteds/unlisted1', label: 'Unlisted', docsPluginId: 'docs-tests', }, From 0aa11e1713950cca378839033a1c42214a90d96c Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 19:11:33 +0200 Subject: [PATCH 10/50] extract theme visibility filtering logic to theme-common --- .../theme/DocSidebarItem/Category/index.tsx | 20 ---- .../src/theme/DocSidebarItems/index.tsx | 11 ++- .../docusaurus-theme-common/src/internal.ts | 1 + .../src/utils/__tests__/docsUtils.test.tsx | 93 +++++++++++++++++++ .../src/utils/blogUtils.ts | 20 ++-- .../src/utils/docsUtils.tsx | 18 ++++ project-words.txt | 1 + 7 files changed, 128 insertions(+), 36 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx index 5ac76f0bef08..67f8d91bb41b 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx @@ -46,22 +46,6 @@ function useAutoExpandActiveCategory({ }, [isActive, wasActive, collapsed, updateCollapsed]); } -function onlyInactiveUnlistedLinks( - activePath: string, - items: Props['item']['items'], -): boolean { - return items.every((item) => { - switch (item.type) { - case 'category': - return onlyInactiveUnlistedLinks(activePath, item.items); - case 'link': - return item.unlisted === true && !isActiveSidebarItem(item, activePath); - default: - return false; - } - }); -} - /** * When a collapsible category has no link, we still link it to its first child * during SSR as a temporary fallback. This allows to be able to navigate inside @@ -160,10 +144,6 @@ export default function DocSidebarItemCategory({ } }, [collapsible, expandedItem, index, setCollapsed, autoCollapseCategories]); - if (onlyInactiveUnlistedLinks(activePath, items)) { - return null; - } - return (
  • + isVisibleSidebarItem(item, props.activePath), + ); + return ( - {items.map((item, index) => ( + {visibleItems.map((item, index) => ( ))} diff --git a/packages/docusaurus-theme-common/src/internal.ts b/packages/docusaurus-theme-common/src/internal.ts index 3fcf164c8e88..4a4b78cb914c 100644 --- a/packages/docusaurus-theme-common/src/internal.ts +++ b/packages/docusaurus-theme-common/src/internal.ts @@ -69,6 +69,7 @@ export { findSidebarCategory, findFirstCategoryLink, isActiveSidebarItem, + isVisibleSidebarItem, useSidebarBreadcrumbs, useDocsVersionCandidates, useLayoutDoc, diff --git a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx index 45724b2b2ec5..30ff811d827d 100644 --- a/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx +++ b/packages/docusaurus-theme-common/src/utils/__tests__/docsUtils.test.tsx @@ -16,6 +16,7 @@ import { findSidebarCategory, useCurrentSidebarCategory, useSidebarBreadcrumbs, + isVisibleSidebarItem, } from '../docsUtils'; import {DocsSidebarProvider} from '../../contexts/docsSidebar'; import {DocsVersionProvider} from '../../contexts/docsVersion'; @@ -293,6 +294,98 @@ describe('isActiveSidebarItem', () => { }); }); +describe('isVisibleSidebarItem', () => { + it('works with item', () => { + const item: PropSidebarItem = { + type: 'link', + href: '/itemPath', + label: 'Label', + }; + + expect(isVisibleSidebarItem(item, item.href)).toBe(true); + expect(isVisibleSidebarItem(item, '/nonexistentPath/')).toBe(true); + + expect(isVisibleSidebarItem({...item, unlisted: false}, item.href)).toBe( + true, + ); + expect( + isVisibleSidebarItem({...item, unlisted: undefined}, item.href), + ).toBe(true); + + expect(isVisibleSidebarItem({...item, unlisted: true}, item.href)).toBe( + true, + ); + expect( + isVisibleSidebarItem({...item, unlisted: true}, '/nonexistentPath/'), + ).toBe(false); + }); + + it('works with category', () => { + const subCategoryAllUnlisted = testCategory({ + href: '/sub-category-path', + items: [ + { + type: 'link', + href: '/sub-sub-link-path', + label: 'Label', + unlisted: true, + }, + { + type: 'link', + href: '/sub-sub-link-path', + label: 'Label', + unlisted: true, + }, + testCategory({ + href: '/sub-sub-category-path', + items: [ + { + type: 'link', + href: '/sub-sub-sub-link-path', + label: 'Label', + unlisted: true, + }, + ], + }), + ], + }); + + expect( + isVisibleSidebarItem(subCategoryAllUnlisted, '/nonexistentPath'), + ).toBe(false); + expect( + isVisibleSidebarItem( + subCategoryAllUnlisted, + subCategoryAllUnlisted.href!, + ), + ).toBe(true); + expect( + isVisibleSidebarItem(subCategoryAllUnlisted, '/sub-sub-link-path'), + ).toBe(true); + expect( + isVisibleSidebarItem(subCategoryAllUnlisted, '/sub-sub-sub-link-path'), + ).toBe(true); + + const categorySomeUnlisted = testCategory({ + href: '/category-path', + items: [ + { + type: 'link', + href: '/sub-link-path', + label: 'Label', + }, + subCategoryAllUnlisted, + ], + }); + expect(isVisibleSidebarItem(categorySomeUnlisted, '/nonexistentPath')).toBe( + true, + ); + expect( + isVisibleSidebarItem(categorySomeUnlisted, categorySomeUnlisted.href!), + ).toBe(true); + }); +}); + describe('useSidebarBreadcrumbs', () => { const createUseSidebarBreadcrumbsMock = (sidebar: PropSidebar | undefined, breadcrumbsOption?: boolean) => diff --git a/packages/docusaurus-theme-common/src/utils/blogUtils.ts b/packages/docusaurus-theme-common/src/utils/blogUtils.ts index b8dc04ca04cb..d50a2ffac67e 100644 --- a/packages/docusaurus-theme-common/src/utils/blogUtils.ts +++ b/packages/docusaurus-theme-common/src/utils/blogUtils.ts @@ -10,16 +10,11 @@ import {useLocation} from '@docusaurus/router'; import {isSamePath} from './routesUtils'; import type {BlogSidebarItem} from '@docusaurus/plugin-content-blog'; -function filterUnlistedBlogSidebarItems( - items: BlogSidebarItem[], - pathname: string, -): BlogSidebarItem[] { - return items.filter((item) => { - if (item.unlisted && !isSamePath(item.permalink, pathname)) { - return false; - } - return true; - }); +function isVisible(item: BlogSidebarItem, pathname: string): boolean { + if (item.unlisted && !isSamePath(item.permalink, pathname)) { + return false; + } + return true; } /** @@ -27,14 +22,11 @@ function filterUnlistedBlogSidebarItems( * Unlisted items are filtered. */ export function useVisibleBlogSidebarItems( - // TODO put blog sidebar in a React context - // We should make it accessible to the whole blog layout subtree - // This hook could have no param items: BlogSidebarItem[], ): BlogSidebarItem[] { const {pathname} = useLocation(); return useMemo( - () => filterUnlistedBlogSidebarItems(items, pathname), + () => items.filter((item) => isVisible(item, pathname)), [items, pathname], ); } diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index 3c476d16231d..f4d5e56bc0fd 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -152,6 +152,24 @@ export function isActiveSidebarItem( return false; } +export function isVisibleSidebarItem( + item: PropSidebarItem, + activePath: string, +): boolean { + switch (item.type) { + case 'category': + return ( + isActiveSidebarItem(item, activePath) || + item.items.some((subItem) => isVisibleSidebarItem(subItem, activePath)) + ); + case 'link': + // An unlisted item remains visible if it is active + return !item.unlisted || isActiveSidebarItem(item, activePath); + default: + return false; + } +} + function getSidebarBreadcrumbs(param: { sidebarItems: PropSidebar; pathname: string; diff --git a/project-words.txt b/project-words.txt index 094e9896a651..254609dce57f 100644 --- a/project-words.txt +++ b/project-words.txt @@ -359,6 +359,7 @@ typesense unflat unist unlinkable +unlisteds unlocalized unmatch unnormalized From c92b5aba2ca96cd3b95682354e59c4f8a59ee511 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 19:20:28 +0200 Subject: [PATCH 11/50] refactor DocSidebarItems --- .../src/theme/DocSidebarItems/index.tsx | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx index c877cac10b4f..1d0435b1c5f3 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import React, {memo} from 'react'; +import React, {memo, useMemo} from 'react'; import { DocSidebarItemsExpandedStateProvider, isVisibleSidebarItem, @@ -14,13 +14,20 @@ import DocSidebarItem from '@theme/DocSidebarItem'; import type {Props} from '@theme/DocSidebarItems'; -// TODO this item should probably not receive the "activePath" props -// TODO this triggers whole sidebar re-renders on navigation -function DocSidebarItems({items, ...props}: Props): JSX.Element { - const visibleItems = items.filter((item) => - isVisibleSidebarItem(item, props.activePath), +// TODO "technical" component: move it to theme-common later + +function useVisibleItems( + items: Props['items'], + activePath: string, +): Props['items'] { + return useMemo( + () => items.filter((item) => isVisibleSidebarItem(item, activePath)), + [items, activePath], ); +} +function DocSidebarItems({items, ...props}: Props): JSX.Element { + const visibleItems = useVisibleItems(items, props.activePath); return ( {visibleItems.map((item, index) => ( From 149382d4972d53d936ce27348d7aa0c89f18f975 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 19:21:25 +0200 Subject: [PATCH 12/50] revert category return null --- .../src/theme/DocSidebarItem/Category/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx index 67f8d91bb41b..700c4a52bef3 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx @@ -103,7 +103,7 @@ export default function DocSidebarItemCategory({ level, index, ...props -}: Props): JSX.Element | null { +}: Props): JSX.Element { const {items, label, collapsible, className, href} = item; const { docs: { From 66e1d8f6d3c88e1e510f2fea7a8f1a5e362953f1 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 19:22:36 +0200 Subject: [PATCH 13/50] revert useless Link changes --- .../src/theme/DocSidebarItem/Link/index.tsx | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx index 6d7b7e581208..3d4cb181b9d4 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx @@ -23,15 +23,11 @@ export default function DocSidebarItemLink({ level, index, ...props -}: Props): JSX.Element | null { - const {href, label, className, autoAddBaseUrl, unlisted} = item; +}: Props): JSX.Element { + const {href, label, className, autoAddBaseUrl} = item; const isActive = isActiveSidebarItem(item, activePath); const isInternalLink = isInternalUrl(href); - if (unlisted && !isActive) { - return null; - } - return (
  • Date: Fri, 21 Oct 2022 19:25:24 +0200 Subject: [PATCH 14/50] blog post metadata is required --- .../docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index b30a1c6015b8..ee1c21a365a2 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -229,7 +229,7 @@ declare module '@docusaurus/plugin-content-blog' { /** * Marks the post as unlisted and visibly hides it unless directly accessed. */ - readonly unlisted?: boolean; + readonly unlisted: boolean; }; /** * @returns The edit URL that's directly plugged into metadata. From 82a93f156efd20c5aad9e5f1d386eab0ad305d91 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 19:29:29 +0200 Subject: [PATCH 15/50] revert weird sortPosts dogfood --- website/_dogfooding/dogfooding.config.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/website/_dogfooding/dogfooding.config.js b/website/_dogfooding/dogfooding.config.js index 027447e97ef2..5e0cf41f6459 100644 --- a/website/_dogfooding/dogfooding.config.js +++ b/website/_dogfooding/dogfooding.config.js @@ -72,8 +72,6 @@ const dogfoodingPluginInstances = [ frontMatter.hide_reading_time ? undefined : defaultReadingTime({content, options: {wordsPerMinute: 5}}), - // TODO: undo this - sortPosts: 'descending', }), ], From f488c50122a53492e66563c82d072353a9944fbf Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 21 Oct 2022 19:29:59 +0200 Subject: [PATCH 16/50] remove linebreak --- .../src/theme/DocSidebarItem/Link/index.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx index 3d4cb181b9d4..ffa8b0e89602 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Link/index.tsx @@ -27,7 +27,6 @@ export default function DocSidebarItemLink({ const {href, label, className, autoAddBaseUrl} = item; const isActive = isActiveSidebarItem(item, activePath); const isInternalLink = isInternalUrl(href); - return (
  • Date: Thu, 27 Oct 2022 14:52:48 +0200 Subject: [PATCH 17/50] exclude unlisted blog posts from feed --- .../__tests__/__snapshots__/feed.test.ts.snap | 25 ------------------- .../src/__tests__/feed.test.ts | 2 +- .../src/feed.ts | 11 +++++++- 3 files changed, 11 insertions(+), 27 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap index 748019d4a423..bf7d608e30c6 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/feed.test.ts.snap @@ -50,14 +50,6 @@ exports[`atom has feed item for each post 1`] = ` https://sebastienlorber.com - - <![CDATA[unlisted]]> - /unlisted - - 2020-02-27T00:00:00.000Z - - this post is unlisted

    ]]>
    -
    <![CDATA[some heading]]> /heading-as-title @@ -143,15 +135,6 @@ exports[`json has feed item for each post 1`] = ` }, "tags": [] }, - { - "id": "/unlisted", - "content_html": "

    this post is unlisted

    ", - "url": "https://docusaurus.io/myBaseUrl/blog/unlisted", - "title": "unlisted", - "summary": "this post is unlisted", - "date_modified": "2020-02-27T00:00:00.000Z", - "tags": [] - }, { "id": "/heading-as-title", "content_html": "", @@ -235,14 +218,6 @@ exports[`rss has feed item for each post 1`] = ` simple url slug

    ]]>
    - - <![CDATA[unlisted]]> - https://docusaurus.io/myBaseUrl/blog/unlisted - /unlisted - Thu, 27 Feb 2020 00:00:00 GMT - - this post is unlisted

    ]]>
    -
    <![CDATA[some heading]]> https://docusaurus.io/myBaseUrl/blog/heading-as-title diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts index e56e35d17620..83d0af77157c 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/feed.test.ts @@ -54,7 +54,7 @@ async function testGenerateFeeds( ); await createBlogFeedFiles({ - blogPosts: blogPosts.filter((post) => !post.metadata.frontMatter.draft), + blogPosts, options, siteConfig: context.siteConfig, outDir: context.outDir, diff --git a/packages/docusaurus-plugin-content-blog/src/feed.ts b/packages/docusaurus-plugin-content-blog/src/feed.ts index 222fcb84b2b5..81d7d45fe99f 100644 --- a/packages/docusaurus-plugin-content-blog/src/feed.ts +++ b/packages/docusaurus-plugin-content-blog/src/feed.ts @@ -133,8 +133,15 @@ async function createBlogFeedFile({ } } +function shouldBeInFeed(blogPost: BlogPost): boolean { + const excluded = + blogPost.metadata.frontMatter.draft || + blogPost.metadata.frontMatter.unlisted; + return !excluded; +} + export async function createBlogFeedFiles({ - blogPosts, + blogPosts: allBlogPosts, options, siteConfig, outDir, @@ -146,6 +153,8 @@ export async function createBlogFeedFiles({ outDir: string; locale: string; }): Promise { + const blogPosts = allBlogPosts.filter(shouldBeInFeed); + const feed = await generateBlogFeed({ blogPosts, options, From 55dd5013a845a1e0c6205c35f987fd27bb29d07f Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 14:54:02 +0200 Subject: [PATCH 18/50] Add unlisted tag dogfooding --- website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md index 5620b9c99da5..2eed972dd449 100644 --- a/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md +++ b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md @@ -1,7 +1,7 @@ --- title: Unlisted blog post unlisted: true -tags: [blog] +tags: [blog, unlisted-tag] --- This unlisted blog post should always be directly accessible in any environment, but in production the sidebar link and pagination should only be visible when on the page itself From 80a110a86fcdd6b0c34d0a51ecfe7b033aaa34aa Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 15:14:04 +0200 Subject: [PATCH 19/50] add better visibility dogfooding + ability to simulate prod content visibility in dev with env variable (convenient to work) --- .../docusaurus-utils/src/contentVisibilityUtils.ts | 12 +++++++++++- website/_dogfooding/_docs tests/index.md | 7 +++++++ website/_dogfooding/docs-tests-sidebars.js | 6 ------ website/docusaurus.config.js | 4 ++-- 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/packages/docusaurus-utils/src/contentVisibilityUtils.ts b/packages/docusaurus-utils/src/contentVisibilityUtils.ts index 0385b3634191..5cc97ae0d77c 100644 --- a/packages/docusaurus-utils/src/contentVisibilityUtils.ts +++ b/packages/docusaurus-utils/src/contentVisibilityUtils.ts @@ -7,12 +7,22 @@ type Env = 'production' | 'development'; +/** + * To easily work on draft/unlisted in dev mode, use this env variable! + * SIMULATE_PRODUCTION_VISIBILITY=true yarn start:website + */ +const simulateProductionVisibility = + process.env.SIMULATE_PRODUCTION_VISIBILITY === 'true'; + /** * draft/unlisted is a production-only concept * In dev it is ignored and all content files are included */ function isProduction(env: Env | undefined): boolean { - return (env ?? process.env.NODE_ENV) === 'production'; + return ( + simulateProductionVisibility || + (env ?? process.env.NODE_ENV) === 'production' + ); } /** diff --git a/website/_dogfooding/_docs tests/index.md b/website/_dogfooding/_docs tests/index.md index f8a07cac85d7..64fcfb7eddbf 100644 --- a/website/_dogfooding/_docs tests/index.md +++ b/website/_dogfooding/_docs tests/index.md @@ -1,8 +1,15 @@ --- slug: / tags: [a, b, c, some tag] +unlisted: true # Makes the navbar link disappear in prod +id: index +sidebar_label: Docs tests # TODO why is this required? --- # Docs tests This Docusaurus docs plugin instance is meant to test fancy edge-cases that regular unit tests don't really cover. + +- [/tests/docs](/tests/docs) +- [/tests/blog](/tests/blog) +- [/tests/pages](/tests/pages) diff --git a/website/_dogfooding/docs-tests-sidebars.js b/website/_dogfooding/docs-tests-sidebars.js index 8b9f4d76d6f6..add2433e77b8 100644 --- a/website/_dogfooding/docs-tests-sidebars.js +++ b/website/_dogfooding/docs-tests-sidebars.js @@ -40,12 +40,6 @@ const sidebars = { }, ], }, - { - type: 'category', - label: 'section', - collapsible: false, - items: ['index', 'more-test'], - }, { type: 'category', label: 'Another category with index', diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js index ad5e54b7d7ae..7c6489f62cf8 100644 --- a/website/docusaurus.config.js +++ b/website/docusaurus.config.js @@ -444,8 +444,8 @@ const config = { // This item links to a draft doc: only displayed in dev { type: 'doc', - docId: 'tests/visibility/only-drafts/draft1', - label: 'Draft', + docId: 'index', + label: 'Tests', docsPluginId: 'docs-tests', }, // This item links to an unlisted doc: only displayed From 1da33a360e18fae418b546410700541a8670882f Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 15:32:27 +0200 Subject: [PATCH 20/50] extract toSidebarDocItemLinkProp, fix edge case + add test to prevent future possible issues --- .../src/__tests__/props.test.ts | 73 ++++++++++++++++++- .../src/props.ts | 51 ++++++++----- 2 files changed, 105 insertions(+), 19 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts index 7103e3908d59..6a2f0f70d63f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/props.test.ts @@ -5,7 +5,7 @@ * LICENSE file in the root directory of this source tree. */ -import {toTagDocListProp} from '../props'; +import {toSidebarDocItemLinkProp, toTagDocListProp} from '../props'; describe('toTagDocListProp', () => { type Params = Parameters[0]; @@ -61,3 +61,74 @@ describe('toTagDocListProp', () => { }); }); }); + +describe('toSidebarDocItemLinkProp', () => { + type Params = Parameters[0]; + type Result = ReturnType; + type DocSidebarItem = Params['item']; + type Doc = Params['doc']; + + const id = 'some-doc-id'; + const unversionedId = 'some-unversioned-doc-id'; + + const item: DocSidebarItem = { + type: 'doc', + id, + label: 'doc sidebar item label', + }; + + const doc: Doc = { + id, + unversionedId, + title: 'doc title', + permalink: '/docPermalink', + frontMatter: {}, + unlisted: false, + }; + + it('works', () => { + const result = toSidebarDocItemLinkProp({ + item, + doc, + }); + + expect(result).toEqual({ + type: 'link', + docId: unversionedId, + unlisted: false, + label: item.label, + autoAddBaseUrl: undefined, + className: undefined, + href: doc.permalink, + customProps: undefined, + } as Result); + }); + + it('uses unlisted from metadata and ignores frontMatter', () => { + expect( + toSidebarDocItemLinkProp({ + item, + doc: { + ...doc, + unlisted: true, + frontMatter: { + unlisted: false, + }, + }, + }).unlisted, + ).toBe(true); + + expect( + toSidebarDocItemLinkProp({ + item, + doc: { + ...doc, + unlisted: false, + frontMatter: { + unlisted: true, + }, + }, + }).unlisted, + ).toBe(false); + }); +}); diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index 0fe508bc865e..5fc757beba0d 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -28,6 +28,37 @@ import type { LoadedVersion, } from '@docusaurus/plugin-content-docs'; +export function toSidebarDocItemLinkProp({ + item, + doc, +}: { + item: SidebarItemDoc; + doc: Pick< + DocMetadata, + 'id' | 'title' | 'permalink' | 'unlisted' | 'frontMatter' | 'unversionedId' + >; +}): PropSidebarItemLink { + const { + title, + permalink, + frontMatter: { + sidebar_label: sidebarLabel, + sidebar_custom_props: customProps, + }, + unlisted, + unversionedId, + } = doc; + return { + type: 'link', + label: sidebarLabel ?? item.label ?? title, + href: permalink, + className: item.className, + customProps: item.customProps ?? customProps, + docId: unversionedId, + unlisted, + }; +} + export function toSidebarsProp(loadedVersion: LoadedVersion): PropSidebars { const docsById = createDocsByIdIndex(loadedVersion.docs); @@ -44,24 +75,8 @@ Available document ids are: } const convertDocLink = (item: SidebarItemDoc): PropSidebarItemLink => { - const docMetadata = getDocById(item.id); - const { - title, - permalink, - frontMatter: {sidebar_label: sidebarLabel}, - } = docMetadata; - return { - type: 'link', - label: sidebarLabel ?? item.label ?? title, - href: permalink, - className: item.className, - customProps: - item.customProps ?? docMetadata.frontMatter.sidebar_custom_props, - docId: docMetadata.unversionedId, - unlisted: - process.env.NODE_ENV === 'production' && - docMetadata.frontMatter.unlisted === true, - }; + const doc = getDocById(item.id); + return toSidebarDocItemLinkProp({item, doc}); }; function getCategoryLinkHref( From bb1b17b876cfe3c0e9d294dc0efcb03895589c6f Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 16:59:13 +0200 Subject: [PATCH 21/50] Add support for unlisted blog tags --- website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md index 2eed972dd449..df5afc08f9d4 100644 --- a/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md +++ b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md @@ -1,7 +1,8 @@ --- title: Unlisted blog post unlisted: true -tags: [blog, unlisted-tag] +tags: [blog, unlisted] +slug: /unlisted-blog-post-test --- This unlisted blog post should always be directly accessible in any environment, but in production the sidebar link and pagination should only be visible when on the page itself From 0266f6d0855732c4e9b028e91764877ec0eb573f Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 16:59:26 +0200 Subject: [PATCH 22/50] Add support for unlisted blog tags --- .../src/__tests__/props.test.ts | 68 +++++++++++++++++++ .../src/blogUtils.ts | 48 ++++++++++--- .../src/index.ts | 27 ++------ .../src/plugin-content-blog.d.ts | 1 + .../src/props.ts | 34 ++++++++++ .../src/theme/BlogTagsPostsPage/index.tsx | 1 - packages/docusaurus-utils/src/tags.ts | 2 + 7 files changed, 149 insertions(+), 32 deletions(-) create mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts create mode 100644 packages/docusaurus-plugin-content-blog/src/props.ts diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts new file mode 100644 index 000000000000..3b2d2c39b418 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts @@ -0,0 +1,68 @@ +/** + * 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 {toTagsProp} from '../props'; + +describe('toTagsProp', () => { + type Tags = Parameters[0]; + type Tag = Tags[number]; + + const tag1: Tag = { + label: 'Tag 1', + permalink: '/tag1', + items: ['item1', 'item2'], + pages: [], + }; + + const tag2: Tag = { + label: 'Tag 2', + permalink: '/tag2', + items: ['item3'], + pages: [], + }; + + function testTags(...tags: Tag[]) { + const tagsObject: Tags = {}; + tags.forEach((tag) => { + tagsObject[tag.permalink] = tag; + }); + return toTagsProp(tagsObject); + } + + it('works', () => { + expect(testTags(tag1, tag2)).toEqual([ + { + count: tag1.items.length, + label: tag1.label, + permalink: tag1.permalink, + }, + { + count: tag2.items.length, + label: tag2.label, + permalink: tag2.permalink, + }, + ]); + }); + + it('filters unlisted tags', () => { + expect(testTags(tag1, {...tag2, unlisted: true})).toEqual([ + { + count: tag1.items.length, + label: tag1.label, + permalink: tag1.permalink, + }, + ]); + + expect(testTags({...tag1, unlisted: true}, tag2)).toEqual([ + { + count: tag2.items.length, + label: tag2.label, + permalink: tag2.permalink, + }, + ]); + }); +}); diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 10abe3af877c..ed0170040067 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -98,6 +98,30 @@ export function paginateBlogPosts({ return pages; } +export function shouldBeListed(blogPost: BlogPost): boolean { + return !blogPost.metadata.unlisted; +} + +function getTagListing(tagsBlogPosts: BlogPost[]): { + unlisted: boolean; + listedBlogPosts: BlogPost[]; +} { + const allPostsAreUnlisted = tagsBlogPosts.every( + (blogPost) => blogPost.metadata.unlisted, + ); + // When a tag is full of unlisted blog posts, we display all the blog posts + // on that tag but we mark the tag as unlisted + if (allPostsAreUnlisted) { + return {unlisted: true, listedBlogPosts: tagsBlogPosts}; + } + // When a tag has some listed blog posts, the tag remains listed + // but we filter its unlisted blog posts + return { + unlisted: false, + listedBlogPosts: tagsBlogPosts.filter(shouldBeListed), + }; +} + export function getBlogTags({ blogPosts, ...params @@ -112,16 +136,20 @@ export function getBlogTags({ (blogPost) => blogPost.metadata.tags, ); - return _.mapValues(groups, ({tag, items: tagBlogPosts}) => ({ - label: tag.label, - items: tagBlogPosts.map((item) => item.id), - permalink: tag.permalink, - pages: paginateBlogPosts({ - blogPosts: tagBlogPosts, - basePageUrl: tag.permalink, - ...params, - }), - })); + return _.mapValues(groups, ({tag, items: tagBlogPosts}) => { + const {unlisted, listedBlogPosts} = getTagListing(tagBlogPosts); + return { + label: tag.label, + items: listedBlogPosts.map((item) => item.id), + permalink: tag.permalink, + pages: paginateBlogPosts({ + blogPosts: listedBlogPosts, + basePageUrl: tag.permalink, + ...params, + }), + unlisted, + }; + }); } const DATE_FILENAME_REGEX = diff --git a/packages/docusaurus-plugin-content-blog/src/index.ts b/packages/docusaurus-plugin-content-blog/src/index.ts index 699863cbdab5..a86b835e0556 100644 --- a/packages/docusaurus-plugin-content-blog/src/index.ts +++ b/packages/docusaurus-plugin-content-blog/src/index.ts @@ -18,19 +18,19 @@ import { getContentPathList, getDataFilePath, DEFAULT_PLUGIN_ID, - type TagsListItem, - type TagModule, } from '@docusaurus/utils'; import { generateBlogPosts, getSourceToPermalink, getBlogTags, paginateBlogPosts, + shouldBeListed, } from './blogUtils'; import footnoteIDFixer from './remark/footnoteIDFixer'; import {translateContent, getTranslationFiles} from './translations'; import {createBlogFeedFiles} from './feed'; +import {toTagProp, toTagsProp} from './props'; import type {BlogContentPaths, BlogMarkdownLoaderOptions} from './types'; import type {LoadContext, Plugin, HtmlTags} from '@docusaurus/types'; import type { @@ -112,9 +112,7 @@ export default async function pluginContentBlog( const baseBlogUrl = normalizeUrl([baseUrl, routeBasePath]); const blogTagsListPath = normalizeUrl([baseBlogUrl, tagsBasePath]); const blogPosts = await generateBlogPosts(contentPaths, context, options); - const listedBlogPosts = blogPosts.filter( - (blogPost) => !blogPost.metadata.unlisted, - ); + const listedBlogPosts = blogPosts.filter(shouldBeListed); if (!blogPosts.length) { return { @@ -158,7 +156,7 @@ export default async function pluginContentBlog( }); const blogTags: BlogTags = getBlogTags({ - blogPosts: listedBlogPosts, + blogPosts, postsPerPageOption, blogDescription, blogTitle, @@ -309,17 +307,10 @@ export default async function pluginContentBlog( } async function createTagsListPage() { - const tagsProp: TagsListItem[] = Object.values(blogTags).map((tag) => ({ - label: tag.label, - permalink: tag.permalink, - count: tag.items.length, - })); - const tagsPropPath = await createData( `${docuHash(`${blogTagsListPath}-tags`)}.json`, - JSON.stringify(tagsProp, null, 2), + JSON.stringify(toTagsProp({blogTags}), null, 2), ); - addRoute({ path: blogTagsListPath, component: blogTagsListComponent, @@ -335,15 +326,9 @@ export default async function pluginContentBlog( await Promise.all( tag.pages.map(async (blogPaginated) => { const {metadata, items} = blogPaginated; - const tagProp: TagModule = { - label: tag.label, - permalink: tag.permalink, - allTagsPath: blogTagsListPath, - count: tag.items.length, - }; const tagPropPath = await createData( `${docuHash(metadata.permalink)}.json`, - JSON.stringify(tagProp, null, 2), + JSON.stringify(toTagProp({tag, blogTagsListPath}), null, 2), ); const listMetadataPath = await createData( diff --git a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts index ee1c21a365a2..96c288d335f4 100644 --- a/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts +++ b/packages/docusaurus-plugin-content-blog/src/plugin-content-blog.d.ts @@ -442,6 +442,7 @@ declare module '@docusaurus/plugin-content-blog' { /** Blog post permalinks. */ items: string[]; pages: BlogPaginated[]; + unlisted: boolean; }; export type BlogPost = { diff --git a/packages/docusaurus-plugin-content-blog/src/props.ts b/packages/docusaurus-plugin-content-blog/src/props.ts new file mode 100644 index 000000000000..8946bc15d580 --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/props.ts @@ -0,0 +1,34 @@ +/** + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +import type {TagsListItem, TagModule} from '@docusaurus/utils'; +import type {BlogTag, BlogTags} from '@docusaurus/plugin-content-blog'; + +export function toTagsProp({blogTags}: {blogTags: BlogTags}): TagsListItem[] { + return Object.values(blogTags) + .filter((tag) => !tag.unlisted) + .map((tag) => ({ + label: tag.label, + permalink: tag.permalink, + count: tag.items.length, + })); +} + +export function toTagProp({ + blogTagsListPath, + tag, +}: { + blogTagsListPath: string; + tag: BlogTag; +}): TagModule { + return { + label: tag.label, + permalink: tag.permalink, + allTagsPath: blogTagsListPath, + count: tag.items.length, + unlisted: tag.unlisted, + }; +} diff --git a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx index 1ace6a9b3c3c..340f06abe79e 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx @@ -72,7 +72,6 @@ function BlogTagsPostsPageContent({

    {title}

    - Date: Thu, 27 Oct 2022 17:44:10 +0200 Subject: [PATCH 23/50] Add theme banner/metadata component --- .../src/theme-classic.d.ts | 8 ++++ .../src/theme/BlogPostPage/Metadata/index.tsx | 4 +- .../src/theme/BlogPostPage/index.tsx | 4 +- .../src/theme/BlogTagsPostsPage/index.tsx | 2 + .../src/theme/DocItem/Layout/index.tsx | 5 +++ .../src/theme/DocItem/Metadata/index.tsx | 5 +-- .../src/theme/MDXPage/index.tsx | 6 +-- .../src/theme/Unlisted/index.tsx | 42 +++++++++++++++++++ packages/docusaurus-theme-common/src/index.ts | 6 +++ .../src/utils/ThemeClassNames.ts | 2 + .../src/utils/unlistedUtils.tsx | 38 +++++++++++++++++ 11 files changed, 112 insertions(+), 10 deletions(-) create mode 100644 packages/docusaurus-theme-classic/src/theme/Unlisted/index.tsx create mode 100644 packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx diff --git a/packages/docusaurus-theme-classic/src/theme-classic.d.ts b/packages/docusaurus-theme-classic/src/theme-classic.d.ts index 2e89d14c8ddd..be4cf3fa94e2 100644 --- a/packages/docusaurus-theme-classic/src/theme-classic.d.ts +++ b/packages/docusaurus-theme-classic/src/theme-classic.d.ts @@ -1494,6 +1494,14 @@ declare module '@theme/Tag' { export default function Tag(props: Props): JSX.Element; } +declare module '@theme/Unlisted' { + export interface Props { + className?: string; + } + + export default function Unlisted(props: Props): JSX.Element; +} + declare module '@theme/prism-include-languages' { import type * as PrismNamespace from 'prismjs'; diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx index ce420f793c29..515e104baa8e 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/Metadata/index.tsx @@ -11,8 +11,7 @@ import {useBlogPost} from '@docusaurus/theme-common/internal'; export default function BlogPostPageMetadata(): JSX.Element { const {assets, metadata} = useBlogPost(); - const {title, description, date, tags, authors, frontMatter, unlisted} = - metadata; + const {title, description, date, tags, authors, frontMatter} = metadata; const {keywords} = frontMatter; const image = assets.image ?? frontMatter.image; @@ -40,7 +39,6 @@ export default function BlogPostPageMetadata(): JSX.Element { content={tags.map((tag) => tag.label).join(',')} /> )} - {unlisted && } ); } diff --git a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx index 2dec817ef470..f640f603347b 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogPostPage/index.tsx @@ -15,6 +15,7 @@ import BlogPostPaginator from '@theme/BlogPostPaginator'; import BlogPostPageMetadata from '@theme/BlogPostPage/Metadata'; import TOC from '@theme/TOC'; import type {Props} from '@theme/BlogPostPage'; +import Unlisted from '@theme/Unlisted'; import type {BlogSidebar} from '@docusaurus/plugin-content-blog'; function BlogPostPageContent({ @@ -25,7 +26,7 @@ function BlogPostPageContent({ children: ReactNode; }): JSX.Element { const {metadata, toc} = useBlogPost(); - const {nextItem, prevItem, frontMatter} = metadata; + const {nextItem, prevItem, frontMatter, unlisted} = metadata; const { hide_table_of_contents: hideTableOfContents, toc_min_heading_level: tocMinHeadingLevel, @@ -43,6 +44,7 @@ function BlogPostPageContent({ /> ) : undefined }> + {unlisted && } {children} {(nextItem || prevItem) && ( diff --git a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx index 340f06abe79e..27b1c658f685 100644 --- a/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/BlogTagsPostsPage/index.tsx @@ -20,6 +20,7 @@ import BlogListPaginator from '@theme/BlogListPaginator'; import SearchMetadata from '@theme/SearchMetadata'; import type {Props} from '@theme/BlogTagsPostsPage'; import BlogPostItems from '@theme/BlogPostItems'; +import Unlisted from '@theme/Unlisted'; // Very simple pluralization: probably good enough for now function useBlogPostsPlural() { @@ -70,6 +71,7 @@ function BlogTagsPostsPageContent({ const title = useBlogTagsPostsPageTitle(tag); return ( + {tag.unlisted && }

    {title}

    diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/index.tsx index ff5ab6d1a39a..9c46677c7135 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/Layout/index.tsx @@ -17,6 +17,7 @@ import DocItemTOCMobile from '@theme/DocItem/TOC/Mobile'; import DocItemTOCDesktop from '@theme/DocItem/TOC/Desktop'; import DocItemContent from '@theme/DocItem/Content'; import DocBreadcrumbs from '@theme/DocBreadcrumbs'; +import Unlisted from '@theme/Unlisted'; import type {Props} from '@theme/DocItem/Layout'; import styles from './styles.module.css'; @@ -47,9 +48,13 @@ function useDocTOC() { export default function DocItemLayout({children}: Props): JSX.Element { const docTOC = useDocTOC(); + const { + metadata: {unlisted}, + } = useDoc(); return (
    + {unlisted && }
    diff --git a/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx index 1ee9cb506420..3e75ee053a0d 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocItem/Metadata/index.tsx @@ -16,8 +16,7 @@ export default function DocItemMetadata(): JSX.Element { title={metadata.title} description={metadata.description} keywords={frontMatter.keywords} - image={assets.image ?? frontMatter.image}> - {metadata.unlisted && } - + image={assets.image ?? frontMatter.image} + /> ); } diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index 637e6f7e56a0..245e107a2407 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -15,6 +15,7 @@ import { import Layout from '@theme/Layout'; import MDXContent from '@theme/MDXContent'; import TOC from '@theme/TOC'; +import Unlisted from '@theme/Unlisted'; import type {Props} from '@theme/MDXPage'; import styles from './styles.module.css'; @@ -33,10 +34,9 @@ export default function MDXPage(props: Props): JSX.Element { wrapperClassName ?? ThemeClassNames.wrapper.mdxPages, ThemeClassNames.page.mdxPage, )}> - - {unlisted && } - + + {unlisted && }
    diff --git a/packages/docusaurus-theme-classic/src/theme/Unlisted/index.tsx b/packages/docusaurus-theme-classic/src/theme/Unlisted/index.tsx new file mode 100644 index 000000000000..302456e5bf12 --- /dev/null +++ b/packages/docusaurus-theme-classic/src/theme/Unlisted/index.tsx @@ -0,0 +1,42 @@ +/** + * 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 { + ThemeClassNames, + UnlistedBannerTitle, + UnlistedBannerMessage, + UnlistedMetadata, +} from '@docusaurus/theme-common'; +import Admonition from '@theme/Admonition'; +import type {Props} from '@theme/Unlisted'; + +function UnlistedBanner({className}: Props) { + return ( + } + className={clsx(className, ThemeClassNames.common.unlistedBanner)}> + + + ); +} + +export default function Unlisted(props: Props): JSX.Element | null { + return ( + <> + {/* + Unlisted metadata declared here for simplicity. + Ensures we never forget to add the correct noindex metadata. + Also gives a central place for user to swizzle override default metadata. + */} + + + + ); +} diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index 03503ddfc155..c58eb5be14d7 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -86,4 +86,10 @@ export { SkipToContentLink, } from './utils/skipToContentUtils'; +export { + UnlistedBannerTitle, + UnlistedBannerMessage, + UnlistedMetadata, +} from './utils/unlistedContentUtils'; + export {ErrorBoundaryTryAgainButton} from './utils/errorBoundaryUtils'; diff --git a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts index e5f859f42890..5c43408b3890 100644 --- a/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts +++ b/packages/docusaurus-theme-common/src/utils/ThemeClassNames.ts @@ -40,6 +40,8 @@ export const ThemeClassNames = { backToTopButton: 'theme-back-to-top-button', codeBlock: 'theme-code-block', admonition: 'theme-admonition', + unlistedBanner: 'theme-unlisted-banner', + admonitionType: (type: string) => `theme-admonition-${type}`, }, layout: { diff --git a/packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx b/packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx new file mode 100644 index 000000000000..b08d97f9f08a --- /dev/null +++ b/packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx @@ -0,0 +1,38 @@ +/** + * 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 Translate from '@docusaurus/Translate'; +import Head from '@docusaurus/Head'; + +export function UnlistedBannerTitle(): JSX.Element { + return ( + + Unlisted content + + ); +} + +export function UnlistedBannerMessage(): JSX.Element { + return ( + + This page is unlisted and can only be accessed directly. + + ); +} + +export function UnlistedMetadata(): JSX.Element { + return ( + + + + ); +} From 6fef19e7deeb2b6c6a0b1270159f0eaee79acaa1 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 17:45:56 +0200 Subject: [PATCH 24/50] fix test --- .../src/__tests__/props.test.ts | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts index 3b2d2c39b418..3446a3601468 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/props.test.ts @@ -8,7 +8,7 @@ import {toTagsProp} from '../props'; describe('toTagsProp', () => { - type Tags = Parameters[0]; + type Tags = Parameters[0]['blogTags']; type Tag = Tags[number]; const tag1: Tag = { @@ -16,6 +16,7 @@ describe('toTagsProp', () => { permalink: '/tag1', items: ['item1', 'item2'], pages: [], + unlisted: false, }; const tag2: Tag = { @@ -23,14 +24,15 @@ describe('toTagsProp', () => { permalink: '/tag2', items: ['item3'], pages: [], + unlisted: false, }; function testTags(...tags: Tag[]) { - const tagsObject: Tags = {}; + const blogTags: Tags = {}; tags.forEach((tag) => { - tagsObject[tag.permalink] = tag; + blogTags[tag.permalink] = tag; }); - return toTagsProp(tagsObject); + return toTagsProp({blogTags}); } it('works', () => { From ebbf832a4ac364234aed1bd93e4026eaf06682fb Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 18:23:32 +0200 Subject: [PATCH 25/50] improve dogfooding for visibility --- .../_dogfooding/_blog tests/2022-08-24-post-unlisted.md | 8 +++++--- website/_dogfooding/_blog tests/2022-08-25-post-draft.md | 8 ++++++++ website/_dogfooding/_docs tests/tests/visibility/index.md | 4 ++++ .../visibility/only-drafts/draft-subcategory/draft3.md | 3 ++- .../_docs tests/tests/visibility/only-drafts/draft1.md | 3 ++- .../_docs tests/tests/visibility/only-drafts/draft2.md | 3 ++- .../only-unlisteds/unlisted-subcategory/unlisted3.md | 3 ++- .../tests/visibility/only-unlisteds/unlisted1.md | 3 ++- .../tests/visibility/only-unlisteds/unlisted2.md | 3 ++- .../visibility/some-drafts/draft-subcategory/draft3.md | 3 ++- .../visibility/some-drafts/draft-subcategory/listed1.md | 6 +++++- .../_docs tests/tests/visibility/some-drafts/draft1.md | 3 ++- .../_docs tests/tests/visibility/some-drafts/draft2.md | 3 ++- .../some-unlisteds/unlisted-subcategory/listed1.md | 6 +++++- .../some-unlisteds/unlisted-subcategory/unlisted3.md | 3 ++- .../tests/visibility/some-unlisteds/unlisted1.md | 3 ++- .../tests/visibility/some-unlisteds/unlisted2.md | 3 ++- website/_dogfooding/_pages tests/draft.md | 7 +++++++ 18 files changed, 58 insertions(+), 17 deletions(-) create mode 100644 website/_dogfooding/_blog tests/2022-08-25-post-draft.md create mode 100644 website/_dogfooding/_pages tests/draft.md diff --git a/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md index df5afc08f9d4..41b1bcbfd68b 100644 --- a/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md +++ b/website/_dogfooding/_blog tests/2022-08-24-post-unlisted.md @@ -1,8 +1,10 @@ --- title: Unlisted blog post unlisted: true -tags: [blog, unlisted] -slug: /unlisted-blog-post-test +tags: [blog, visibility, unlisted] +slug: /unlisted-post --- -This unlisted blog post should always be directly accessible in any environment, but in production the sidebar link and pagination should only be visible when on the page itself +This unlisted blog post should be "hidden" in production, but remain accessible. + +It is filtered from the sidebar, sitemap, SEO indexation... diff --git a/website/_dogfooding/_blog tests/2022-08-25-post-draft.md b/website/_dogfooding/_blog tests/2022-08-25-post-draft.md new file mode 100644 index 000000000000..a8e7b075b52f --- /dev/null +++ b/website/_dogfooding/_blog tests/2022-08-25-post-draft.md @@ -0,0 +1,8 @@ +--- +title: Draft blog post +unlisted: true +tags: [blog, visibility, draft] +slug: /draft-post +--- + +This draft blog post should not be accessible in production, only in dev! diff --git a/website/_dogfooding/_docs tests/tests/visibility/index.md b/website/_dogfooding/_docs tests/tests/visibility/index.md index 5d7a60b17e8b..a0b92f20cc8b 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/index.md +++ b/website/_dogfooding/_docs tests/tests/visibility/index.md @@ -1,3 +1,7 @@ +--- +tags: [visibility] +--- + # Visibility A category to play with draft/unlisted front matter. diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md index 655423590453..e813252bb2e7 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md +++ b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/draft3.md @@ -1,7 +1,8 @@ --- draft: true +tags: [visibility, draft] --- -# Draft 2 +# Only Drafts - Draft 3 Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md index 298b96438405..d6f6a0d96438 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md +++ b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft1.md @@ -1,7 +1,8 @@ --- draft: true +tags: [visibility, draft] --- -# Draft 1 +# Only Drafts - Draft 1 Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md index 655423590453..e366234ce4c6 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md +++ b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft2.md @@ -1,7 +1,8 @@ --- draft: true +tags: [draft] --- -# Draft 2 +# Only Drafts - Draft 2 Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md index 0217ed207114..26aeedd58f3d 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md +++ b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/unlisted3.md @@ -1,7 +1,8 @@ --- unlisted: true +tags: [visibility, unlisted] --- -# Unlisted 3 +# Only Unlisteds - Unlisted 3 Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md index e62f23348cfc..342ebf1694e9 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md +++ b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted1.md @@ -1,7 +1,8 @@ --- unlisted: true +tags: [visibility, unlisted] --- -# Unlisted 1 +# Only Unlisteds - Unlisted 1 Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md index 62b3571d1eaa..e0adb46f500b 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md +++ b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted2.md @@ -1,7 +1,8 @@ --- unlisted: true +tags: [visibility, unlisted] --- -# Unlisted 2 +# Only Unlisteds - Unlisted 2 Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md index 655423590453..e7cd4405b710 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/draft3.md @@ -1,7 +1,8 @@ --- draft: true +tags: [visibility, draft] --- -# Draft 2 +# Some Drafts - Draft 3 Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md index 7af342c269bb..23272c0b3128 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/listed1.md @@ -1,3 +1,7 @@ -# Listed 1 +--- +tags: [visibility, listed] +--- + +# Some Drafts - Listed 1 Regular doc diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md index 298b96438405..9656436aec3f 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft1.md @@ -1,7 +1,8 @@ --- draft: true +tags: [visibility, draft] --- -# Draft 1 +# Some Drafts - Draft 1 Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md index 655423590453..5acf2f3b5113 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft2.md @@ -1,7 +1,8 @@ --- draft: true +tags: [visibility, draft] --- -# Draft 2 +# Some Drafts - Draft 2 Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md index 7af342c269bb..5bf8fd7a2756 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/listed1.md @@ -1,3 +1,7 @@ -# Listed 1 +--- +tags: [visibility, listed] +--- + +# Some Unlisteds - Listed 1 Regular doc diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md index 0217ed207114..2d3b503aa516 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/unlisted3.md @@ -1,7 +1,8 @@ --- unlisted: true +tags: [visibility, unlisted] --- -# Unlisted 3 +# Some Unlisteds - Unlisted 3 Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md index e62f23348cfc..aafb3f3136cc 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted1.md @@ -1,7 +1,8 @@ --- unlisted: true +tags: [visibility, unlisted] --- -# Unlisted 1 +# Some Unlisteds - Unlisted 1 Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md index 62b3571d1eaa..d7702e5ddef7 100644 --- a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted2.md @@ -1,7 +1,8 @@ --- unlisted: true +tags: [visibility, unlisted] --- -# Unlisted 2 +# Some Unlisteds - Unlisted 2 Doc with unlisted front matter diff --git a/website/_dogfooding/_pages tests/draft.md b/website/_dogfooding/_pages tests/draft.md new file mode 100644 index 000000000000..a16a0e097378 --- /dev/null +++ b/website/_dogfooding/_pages tests/draft.md @@ -0,0 +1,7 @@ +--- +draft: true +--- + +# Draft page + +This draft page should not be accessible in prod From 56006ae10a0d76bfa879bf6ec9310e3e028d6ecc Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 18:57:30 +0200 Subject: [PATCH 26/50] replicate unlisted tag logic to docs, extract getTagVisibility --- .../src/blogUtils.ts | 33 +++++-------------- .../src/props.ts | 1 + .../src/tags.ts | 19 +++++++---- .../src/types.ts | 1 + .../src/theme/DocTagDocListPage/index.tsx | 2 ++ packages/docusaurus-theme-common/src/index.ts | 2 +- packages/docusaurus-utils/src/index.ts | 1 + packages/docusaurus-utils/src/tags.ts | 29 ++++++++++++++++ 8 files changed, 56 insertions(+), 32 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index ed0170040067..72ba63260446 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -21,6 +21,7 @@ import { Globby, normalizeFrontMatterTags, groupTaggedItems, + getTagVisibility, getFileCommitDate, getContentPathList, isUnlisted, @@ -102,26 +103,6 @@ export function shouldBeListed(blogPost: BlogPost): boolean { return !blogPost.metadata.unlisted; } -function getTagListing(tagsBlogPosts: BlogPost[]): { - unlisted: boolean; - listedBlogPosts: BlogPost[]; -} { - const allPostsAreUnlisted = tagsBlogPosts.every( - (blogPost) => blogPost.metadata.unlisted, - ); - // When a tag is full of unlisted blog posts, we display all the blog posts - // on that tag but we mark the tag as unlisted - if (allPostsAreUnlisted) { - return {unlisted: true, listedBlogPosts: tagsBlogPosts}; - } - // When a tag has some listed blog posts, the tag remains listed - // but we filter its unlisted blog posts - return { - unlisted: false, - listedBlogPosts: tagsBlogPosts.filter(shouldBeListed), - }; -} - export function getBlogTags({ blogPosts, ...params @@ -135,19 +116,21 @@ export function getBlogTags({ blogPosts, (blogPost) => blogPost.metadata.tags, ); - return _.mapValues(groups, ({tag, items: tagBlogPosts}) => { - const {unlisted, listedBlogPosts} = getTagListing(tagBlogPosts); + const tagVisibility = getTagVisibility({ + items: tagBlogPosts, + isUnlisted: (item) => item.metadata.unlisted, + }); return { label: tag.label, - items: listedBlogPosts.map((item) => item.id), + items: tagVisibility.listedItems.map((item) => item.id), permalink: tag.permalink, pages: paginateBlogPosts({ - blogPosts: listedBlogPosts, + blogPosts: tagVisibility.listedItems, basePageUrl: tag.permalink, ...params, }), - unlisted, + unlisted: tagVisibility.unlisted, }; }); } diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index 5fc757beba0d..9f46a0e5b08d 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -198,6 +198,7 @@ export function toTagDocListProp({ allTagsPath, count: tag.docIds.length, items: toDocListProp(), + unlisted: tag.unlisted, }; } diff --git a/packages/docusaurus-plugin-content-docs/src/tags.ts b/packages/docusaurus-plugin-content-docs/src/tags.ts index dfa0e3284587..1fd784c213fa 100644 --- a/packages/docusaurus-plugin-content-docs/src/tags.ts +++ b/packages/docusaurus-plugin-content-docs/src/tags.ts @@ -6,15 +6,22 @@ */ import _ from 'lodash'; -import {groupTaggedItems} from '@docusaurus/utils'; +import {getTagVisibility, groupTaggedItems} from '@docusaurus/utils'; import type {VersionTags} from './types'; import type {DocMetadata} from '@docusaurus/plugin-content-docs'; export function getVersionTags(docs: DocMetadata[]): VersionTags { const groups = groupTaggedItems(docs, (doc) => doc.tags); - return _.mapValues(groups, (group) => ({ - label: group.tag.label, - docIds: group.items.map((item) => item.id), - permalink: group.tag.permalink, - })); + return _.mapValues(groups, ({tag, items: tagDocs}) => { + const tagVisibility = getTagVisibility({ + items: tagDocs, + isUnlisted: (item) => item.unlisted, + }); + return { + label: tag.label, + docIds: tagVisibility.listedItems.map((item) => item.id), + permalink: tag.permalink, + unlisted: tagVisibility.unlisted, + }; + }); } diff --git a/packages/docusaurus-plugin-content-docs/src/types.ts b/packages/docusaurus-plugin-content-docs/src/types.ts index 4c4568517fbb..d78521c71684 100644 --- a/packages/docusaurus-plugin-content-docs/src/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/types.ts @@ -27,6 +27,7 @@ export type SourceToPermalink = { export type VersionTag = Tag & { /** All doc ids having this tag. */ docIds: string[]; + unlisted: boolean; }; export type VersionTags = { [permalink: string]: VersionTag; diff --git a/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx index f32b32ffdba4..b341b55c7263 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocTagDocListPage/index.tsx @@ -17,6 +17,7 @@ import { import Translate, {translate} from '@docusaurus/Translate'; import SearchMetadata from '@theme/SearchMetadata'; import type {Props} from '@theme/DocTagDocListPage'; +import Unlisted from '@theme/Unlisted'; // Very simple pluralization: probably good enough for now function useNDocsTaggedPlural() { @@ -80,6 +81,7 @@ function DocTagDocListPageContent({
    + {tag.unlisted && }

    {title}

    diff --git a/packages/docusaurus-theme-common/src/index.ts b/packages/docusaurus-theme-common/src/index.ts index c58eb5be14d7..b736244ca618 100644 --- a/packages/docusaurus-theme-common/src/index.ts +++ b/packages/docusaurus-theme-common/src/index.ts @@ -90,6 +90,6 @@ export { UnlistedBannerTitle, UnlistedBannerMessage, UnlistedMetadata, -} from './utils/unlistedContentUtils'; +} from './utils/unlistedUtils'; export {ErrorBoundaryTryAgainButton} from './utils/errorBoundaryUtils'; diff --git a/packages/docusaurus-utils/src/index.ts b/packages/docusaurus-utils/src/index.ts index a555dfd341a5..ba74f8d3d134 100644 --- a/packages/docusaurus-utils/src/index.ts +++ b/packages/docusaurus-utils/src/index.ts @@ -62,6 +62,7 @@ export { type FrontMatterTag, normalizeFrontMatterTags, groupTaggedItems, + getTagVisibility, } from './tags'; export { parseMarkdownHeadingId, diff --git a/packages/docusaurus-utils/src/tags.ts b/packages/docusaurus-utils/src/tags.ts index b622b206df28..fdadc1bed327 100644 --- a/packages/docusaurus-utils/src/tags.ts +++ b/packages/docusaurus-utils/src/tags.ts @@ -130,3 +130,32 @@ export function groupTaggedItems( return result; } + +/** + * Permits to get the "tag visibility" (hard to find a better name) + * IE, is this tag listed or unlisted + * And which items should be listed when this tag is browsed + */ +export function getTagVisibility({ + items, + isUnlisted, +}: { + items: Item[]; + isUnlisted: (item: Item) => boolean; +}): { + unlisted: boolean; + listedItems: Item[]; +} { + const allTagItemsUnlisted = items.every(isUnlisted); + // When a tag is full of unlisted items, we display all the items + // when tag is browsed, but we mark the tag as unlisted + if (allTagItemsUnlisted) { + return {unlisted: true, listedItems: items}; + } + // When a tag has some listed items, the tag remains listed + // but we filter its unlisted items + return { + unlisted: false, + listedItems: items.filter(isUnlisted), + }; +} From 1b1bb834c842f6adef23a2ae04ba2a3c510d0161 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 19:07:01 +0200 Subject: [PATCH 27/50] add getTagVisibility test + fix bug --- .../src/__tests__/tags.test.ts | 56 ++++++++++++++++++- packages/docusaurus-utils/src/tags.ts | 6 +- 2 files changed, 58 insertions(+), 4 deletions(-) diff --git a/packages/docusaurus-utils/src/__tests__/tags.test.ts b/packages/docusaurus-utils/src/__tests__/tags.test.ts index a78053b5d76b..cf8c52ec5335 100644 --- a/packages/docusaurus-utils/src/__tests__/tags.test.ts +++ b/packages/docusaurus-utils/src/__tests__/tags.test.ts @@ -5,7 +5,12 @@ * LICENSE file in the root directory of this source tree. */ -import {normalizeFrontMatterTags, groupTaggedItems, type Tag} from '../tags'; +import { + normalizeFrontMatterTags, + groupTaggedItems, + type Tag, + getTagVisibility, +} from '../tags'; describe('normalizeFrontMatterTags', () => { it('normalizes simple string tag', () => { @@ -183,3 +188,52 @@ describe('groupTaggedItems', () => { expect(groupItems(input)).toEqual(expectedOutput); }); }); + +describe('getTagVisibility', () => { + type Item = {id: string; unlisted: boolean}; + + function isUnlisted(item: Item): boolean { + return item.unlisted; + } + + const item1: Item = {id: '1', unlisted: false}; + const item2: Item = {id: '2', unlisted: true}; + const item3: Item = {id: '3', unlisted: false}; + const item4: Item = {id: '4', unlisted: true}; + + it('works for some unlisted', () => { + expect( + getTagVisibility({ + items: [item1, item2, item3, item4], + isUnlisted, + }), + ).toEqual({ + listedItems: [item1, item3], + unlisted: false, + }); + }); + + it('works for all unlisted', () => { + expect( + getTagVisibility({ + items: [item2, item4], + isUnlisted, + }), + ).toEqual({ + listedItems: [item2, item4], + unlisted: true, + }); + }); + + it('works for all listed', () => { + expect( + getTagVisibility({ + items: [item1, item3], + isUnlisted, + }), + ).toEqual({ + listedItems: [item1, item3], + unlisted: false, + }); + }); +}); diff --git a/packages/docusaurus-utils/src/tags.ts b/packages/docusaurus-utils/src/tags.ts index fdadc1bed327..3560bde25e62 100644 --- a/packages/docusaurus-utils/src/tags.ts +++ b/packages/docusaurus-utils/src/tags.ts @@ -146,16 +146,16 @@ export function getTagVisibility({ unlisted: boolean; listedItems: Item[]; } { - const allTagItemsUnlisted = items.every(isUnlisted); + const allItemsUnlisted = items.every(isUnlisted); // When a tag is full of unlisted items, we display all the items // when tag is browsed, but we mark the tag as unlisted - if (allTagItemsUnlisted) { + if (allItemsUnlisted) { return {unlisted: true, listedItems: items}; } // When a tag has some listed items, the tag remains listed // but we filter its unlisted items return { unlisted: false, - listedItems: items.filter(isUnlisted), + listedItems: items.filter((item) => !isUnlisted(item)), }; } From b24a2a0540d85439e3e689095cc15ca4493d69c7 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 19:13:50 +0200 Subject: [PATCH 28/50] filter unlisted tags from the docs tags index --- packages/docusaurus-plugin-content-docs/src/props.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index 9f46a0e5b08d..9b7ef2007a79 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -205,9 +205,11 @@ export function toTagDocListProp({ export function toTagsListTagsProp( versionTags: VersionTags, ): PropTagsListPage['tags'] { - return Object.values(versionTags).map((tagValue) => ({ - label: tagValue.label, - permalink: tagValue.permalink, - count: tagValue.docIds.length, - })); + return Object.values(versionTags) + .filter((tagValue) => !tagValue.unlisted) + .map((tagValue) => ({ + label: tagValue.label, + permalink: tagValue.permalink, + count: tagValue.docIds.length, + })); } From 73e28be5431071b424eea46a7196bec74358d1b9 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 19:24:03 +0200 Subject: [PATCH 29/50] fix blog test snapshots --- .../blog/another-with-tags-unlisted.md | 9 +++ .../__snapshots__/index.test.ts.snap | 56 +++++++++++++++++++ .../src/__tests__/index.test.ts | 2 +- 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website-blog-with-tags/blog/another-with-tags-unlisted.md diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website-blog-with-tags/blog/another-with-tags-unlisted.md b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website-blog-with-tags/blog/another-with-tags-unlisted.md new file mode 100644 index 000000000000..36e186ceca2e --- /dev/null +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__fixtures__/website-blog-with-tags/blog/another-with-tags-unlisted.md @@ -0,0 +1,9 @@ +--- +slug: /another/blog-with-tags-unlisted +title: Another Blog With Tag - unlisted +date: 2020-08-19 +tags: [unlisted] +unlisted: true +--- + +with tag diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap index c19351278b5f..b884dddfc605 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/__snapshots__/index.test.ts.snap @@ -30,6 +30,7 @@ exports[`blog plugin works on blog tags without pagination 1`] = ` }, ], "permalink": "/blog/tags/tag-1", + "unlisted": false, }, "/blog/tags/tag-2": { "items": [ @@ -57,6 +58,33 @@ exports[`blog plugin works on blog tags without pagination 1`] = ` }, ], "permalink": "/blog/tags/tag-2", + "unlisted": false, + }, + "/blog/tags/unlisted": { + "items": [ + "/another/blog-with-tags-unlisted", + ], + "label": "unlisted", + "pages": [ + { + "items": [ + "/another/blog-with-tags-unlisted", + ], + "metadata": { + "blogDescription": "Blog", + "blogTitle": "Blog", + "nextPage": undefined, + "page": 1, + "permalink": "/blog/tags/unlisted", + "postsPerPage": 1, + "previousPage": undefined, + "totalCount": 1, + "totalPages": 1, + }, + }, + ], + "permalink": "/blog/tags/unlisted", + "unlisted": false, }, } `; @@ -106,6 +134,7 @@ exports[`blog plugin works with blog tags 1`] = ` }, ], "permalink": "/blog/tags/tag-1", + "unlisted": false, }, "/blog/tags/tag-2": { "items": [ @@ -133,6 +162,33 @@ exports[`blog plugin works with blog tags 1`] = ` }, ], "permalink": "/blog/tags/tag-2", + "unlisted": false, + }, + "/blog/tags/unlisted": { + "items": [ + "/another/blog-with-tags-unlisted", + ], + "label": "unlisted", + "pages": [ + { + "items": [ + "/another/blog-with-tags-unlisted", + ], + "metadata": { + "blogDescription": "Blog", + "blogTitle": "Blog", + "nextPage": undefined, + "page": 1, + "permalink": "/blog/tags/unlisted", + "postsPerPage": 2, + "previousPage": undefined, + "totalCount": 1, + "totalPages": 1, + }, + }, + ], + "permalink": "/blog/tags/unlisted", + "unlisted": false, }, } `; diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts index 4e767a138b6a..ee7c68680cb5 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/index.test.ts @@ -501,7 +501,7 @@ describe('blog plugin', () => { postsPerPage: 2, }); - expect(Object.keys(blogTags)).toHaveLength(2); + expect(Object.keys(blogTags)).toHaveLength(3); expect(blogTags).toMatchSnapshot(); }); From 6bf9f894466139644b9fa4b42de4542873152371 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 27 Oct 2022 19:25:02 +0200 Subject: [PATCH 30/50] fix docs tests snapshots --- .../__tests__/__snapshots__/index.test.ts.snap | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index bdf9abaefd34..8c323af1a692 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -893,7 +893,8 @@ exports[`simple website content: data 1`] = ` "description": "Hi, Endilie here :)", "permalink": "/docs/" } - ] + ], + "unlisted": false }", "tag-docs-tags-tag-2-custom-permalink-825.json": "{ "label": "tag 2", @@ -907,7 +908,8 @@ exports[`simple website content: data 1`] = ` "description": "Images", "permalink": "/docs/foo/bazSlug.html" } - ] + ], + "unlisted": false }", "tag-docs-tags-tag-3-ab5.json": "{ "label": "tag 3", @@ -921,7 +923,8 @@ exports[`simple website content: data 1`] = ` "description": "Hi, Endilie here :)", "permalink": "/docs/" } - ] + ], + "unlisted": false }", "tags-list-current-prop-15a.json": "[ { @@ -3582,7 +3585,8 @@ exports[`versioned website content: data 1`] = ` "description": "This is next version of bar.", "permalink": "/docs/next/foo/barSlug" } - ] + ], + "unlisted": false }", "tag-docs-next-tags-bar-tag-2-216.json": "{ "label": "barTag-2", @@ -3596,7 +3600,8 @@ exports[`versioned website content: data 1`] = ` "description": "This is next version of bar.", "permalink": "/docs/next/foo/barSlug" } - ] + ], + "unlisted": false }", "tag-docs-next-tags-bar-tag-3-permalink-94a.json": "{ "label": "barTag 3", @@ -3610,7 +3615,8 @@ exports[`versioned website content: data 1`] = ` "description": "This is next version of bar.", "permalink": "/docs/next/foo/barSlug" } - ] + ], + "unlisted": false }", "tags-list-current-prop-15a.json": "[ { From b750f1243d7ffc9d5a6de7342ccb313dd68c799f Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 12:18:24 +0200 Subject: [PATCH 31/50] fix addDocNavigation => unlistedIds should be computed inside --- .../src/__tests__/__snapshots__/docs.test.ts.snap | 14 ++++---------- .../docusaurus-plugin-content-docs/src/docs.ts | 5 ++++- .../docusaurus-plugin-content-docs/src/index.ts | 7 ------- 3 files changed, 8 insertions(+), 18 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap index 89a894cbdd70..34d27ff34f39 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap @@ -25,8 +25,8 @@ exports[`simple site custom pagination 1`] = ` { "id": "doc-draft", "next": { - "permalink": "/docs/doc-unlisted", - "title": "doc-unlisted", + "permalink": "/docs/foo/bar", + "title": "Bar", }, "prev": { "permalink": "/docs/doc with space", @@ -35,14 +35,8 @@ exports[`simple site custom pagination 1`] = ` }, { "id": "doc-unlisted", - "next": { - "permalink": "/docs/foo/bar", - "title": "Bar", - }, - "prev": { - "permalink": "/docs/doc-draft", - "title": "doc-draft", - }, + "next": undefined, + "prev": undefined, }, { "id": "foo/bar", diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index ae90018e17e8..995a5e6dc29a 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -329,10 +329,13 @@ export function addDocNavigation( docsBase: DocMetadataBase[], sidebarsUtils: SidebarsUtils, sidebarFilePath: string, - unlistedIds: string[], ): LoadedVersion['docs'] { const docsById = createDocsByIdIndex(docsBase); + const unlistedIds = docsBase + .filter((doc) => doc.unlisted) + .map((doc) => doc.id); + sidebarsUtils.checkSidebarsDocIds( docsBase.flatMap(getDocIds), sidebarFilePath, diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index d28302e1ca4f..74eac5d38afe 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -157,12 +157,6 @@ export default async function pluginContentDocs( ); const [drafts, docs] = _.partition(docsBase, (doc) => doc.draft); - const unlistedIds = docs.reduce((acc, doc) => { - if (doc.unlisted) { - acc.push(doc.id); - } - return acc; - }, []); const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, { sidebarItemsGenerator: options.sidebarItemsGenerator, @@ -185,7 +179,6 @@ export default async function pluginContentDocs( docs, sidebarsUtils, versionMetadata.sidebarFilePath as string, - unlistedIds, ), drafts, sidebars, From 0746def25543e59249adae5bb9def9d6dc7094bb Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 12:36:15 +0200 Subject: [PATCH 32/50] refactor method with 4 params to take 1 object param, use Set instead of Array for unlistedIds --- .../src/__tests__/docs.test.ts | 9 +- .../src/docs.ts | 44 +++++----- .../src/index.ts | 6 +- .../src/sidebars/__tests__/utils.test.ts | 88 ++++++++++++++++--- .../src/sidebars/utils.ts | 31 ++++--- 5 files changed, 126 insertions(+), 52 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 4ad2be926864..43d49170c1a1 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -173,12 +173,11 @@ function createTestUtils({ const sidebarsUtils = createSidebarsUtils(sidebars); return { - pagination: addDocNavigation( - rawDocs, + pagination: addDocNavigation({ + docs: rawDocs, sidebarsUtils, - versionMetadata.sidebarFilePath as string, - [], - ).map((doc) => ({prev: doc.previous, next: doc.next, id: doc.id})), + sidebarFilePath: versionMetadata.sidebarFilePath as string, + }).map((doc) => ({prev: doc.previous, next: doc.next, id: doc.id})), sidebars, }; } diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index 995a5e6dc29a..3abbafc8027e 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -325,30 +325,32 @@ export async function processDocMetadata(args: { } } -export function addDocNavigation( - docsBase: DocMetadataBase[], - sidebarsUtils: SidebarsUtils, - sidebarFilePath: string, -): LoadedVersion['docs'] { - const docsById = createDocsByIdIndex(docsBase); - - const unlistedIds = docsBase - .filter((doc) => doc.unlisted) - .map((doc) => doc.id); - - sidebarsUtils.checkSidebarsDocIds( - docsBase.flatMap(getDocIds), - sidebarFilePath, - ); +function getUnlistedIds(docs: DocMetadataBase[]): Set { + return new Set(docs.filter((doc) => doc.unlisted).map((doc) => doc.id)); +} + +export function addDocNavigation({ + docs, + sidebarsUtils, + sidebarFilePath, +}: { + docs: DocMetadataBase[]; + sidebarsUtils: SidebarsUtils; + sidebarFilePath: string; +}): LoadedVersion['docs'] { + const docsById = createDocsByIdIndex(docs); + const unlistedIds = getUnlistedIds(docs); + + sidebarsUtils.checkSidebarsDocIds(docs.flatMap(getDocIds), sidebarFilePath); // Add sidebar/next/previous to the docs function addNavData(doc: DocMetadataBase): DocMetadata { - const navigation = sidebarsUtils.getDocNavigation( - doc.unversionedId, - doc.id, - doc.frontMatter.displayed_sidebar, + const navigation = sidebarsUtils.getDocNavigation({ + unversionedId: doc.unversionedId, + versionedId: doc.id, + displayedSidebar: doc.frontMatter.displayed_sidebar, unlistedIds, - ); + }); const toNavigationLinkByDocId = ( docId: string | null | undefined, @@ -383,7 +385,7 @@ export function addDocNavigation( return {...doc, sidebar: navigation.sidebarName, previous, next}; } - const docsWithNavigation = docsBase.map(addNavData); + const docsWithNavigation = docs.map(addNavData); // Sort to ensure consistent output for tests docsWithNavigation.sort((a, b) => a.id.localeCompare(b.id)); return docsWithNavigation; diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 74eac5d38afe..9dcd7f030ad0 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -175,11 +175,11 @@ export default async function pluginContentDocs( return { ...versionMetadata, - docs: addDocNavigation( + docs: addDocNavigation({ docs, sidebarsUtils, - versionMetadata.sidebarFilePath as string, - ), + sidebarFilePath: versionMetadata.sidebarFilePath as string, + }), drafts, sidebars, }; diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts index d7c03faa43bf..bc6c50b74c86 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/__tests__/utils.test.ts @@ -153,7 +153,14 @@ describe('createSidebarsUtils', () => { }); it('getDocNavigation', () => { - expect(getDocNavigation('doc1', 'doc1', undefined, [])).toEqual({ + expect( + getDocNavigation({ + unversionedId: 'doc1', + versionedId: 'doc1', + displayedSidebar: undefined, + unlistedIds: new Set(), + }), + ).toEqual({ sidebarName: 'sidebar1', previous: undefined, next: { @@ -161,7 +168,14 @@ describe('createSidebarsUtils', () => { id: 'doc2', }, }); - expect(getDocNavigation('doc2', 'doc2', undefined, [])).toEqual({ + expect( + getDocNavigation({ + unversionedId: 'doc2', + versionedId: 'doc2', + displayedSidebar: undefined, + unlistedIds: new Set(), + }), + ).toEqual({ sidebarName: 'sidebar1', previous: { type: 'doc', @@ -170,7 +184,14 @@ describe('createSidebarsUtils', () => { next: undefined, }); - expect(getDocNavigation('doc3', 'doc3', undefined, [])).toEqual({ + expect( + getDocNavigation({ + unversionedId: 'doc3', + versionedId: 'doc3', + displayedSidebar: undefined, + unlistedIds: new Set(), + }), + ).toEqual({ sidebarName: 'sidebar2', previous: undefined, next: { @@ -178,7 +199,14 @@ describe('createSidebarsUtils', () => { id: 'doc4', }, }); - expect(getDocNavigation('doc4', 'doc4', undefined, [])).toEqual({ + expect( + getDocNavigation({ + unversionedId: 'doc4', + versionedId: 'doc4', + displayedSidebar: undefined, + unlistedIds: new Set(), + }), + ).toEqual({ sidebarName: 'sidebar2', previous: { type: 'doc', @@ -188,7 +216,14 @@ describe('createSidebarsUtils', () => { next: undefined, }); - expect(getDocNavigation('doc5', 'doc5', undefined, [])).toMatchObject({ + expect( + getDocNavigation({ + unversionedId: 'doc5', + versionedId: 'doc5', + displayedSidebar: undefined, + unlistedIds: new Set(), + }), + ).toMatchObject({ sidebarName: 'sidebar3', previous: undefined, next: { @@ -196,7 +231,14 @@ describe('createSidebarsUtils', () => { label: 'S3 SubCategory', }, }); - expect(getDocNavigation('doc6', 'doc6', undefined, [])).toMatchObject({ + expect( + getDocNavigation({ + unversionedId: 'doc6', + versionedId: 'doc6', + displayedSidebar: undefined, + unlistedIds: new Set(), + }), + ).toMatchObject({ sidebarName: 'sidebar3', previous: { type: 'category', @@ -207,7 +249,14 @@ describe('createSidebarsUtils', () => { id: 'doc7', }, }); - expect(getDocNavigation('doc7', 'doc7', undefined, [])).toEqual({ + expect( + getDocNavigation({ + unversionedId: 'doc7', + versionedId: 'doc7', + displayedSidebar: undefined, + unlistedIds: new Set(), + }), + ).toEqual({ sidebarName: 'sidebar3', previous: { type: 'doc', @@ -215,17 +264,36 @@ describe('createSidebarsUtils', () => { }, next: undefined, }); - expect(getDocNavigation('doc3', 'doc3', null, [])).toEqual({ + expect( + getDocNavigation({ + unversionedId: 'doc3', + versionedId: 'doc3', + displayedSidebar: null, + unlistedIds: new Set(), + }), + ).toEqual({ sidebarName: undefined, previous: undefined, next: undefined, }); expect(() => - getDocNavigation('doc3', 'doc3', 'foo', []), + getDocNavigation({ + unversionedId: 'doc3', + versionedId: 'doc3', + displayedSidebar: 'foo', + unlistedIds: new Set(), + }), ).toThrowErrorMatchingInlineSnapshot( `"Doc with ID doc3 wants to display sidebar foo but a sidebar with this name doesn't exist"`, ); - expect(getDocNavigation('doc3', 'doc3', 'sidebar1', [])).toEqual({ + expect( + getDocNavigation({ + unversionedId: 'doc3', + versionedId: 'doc3', + displayedSidebar: 'sidebar1', + unlistedIds: new Set(), + }), + ).toEqual({ sidebarName: 'sidebar1', previous: undefined, next: undefined, diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index 2ef5c1b2a72f..cb186182f4b5 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -135,12 +135,12 @@ export type SidebarsUtils = { sidebars: Sidebars; getFirstDocIdOfFirstSidebar: () => string | undefined; getSidebarNameByDocId: (docId: string) => string | undefined; - getDocNavigation: ( - unversionedId: string, - versionedId: string, - displayedSidebar: string | null | undefined, - unlistedIds: string[], - ) => SidebarNavigation; + getDocNavigation: (params: { + unversionedId: string; + versionedId: string; + displayedSidebar: string | null | undefined; + unlistedIds: Set; + }) => SidebarNavigation; getCategoryGeneratedIndexList: () => SidebarItemCategoryWithGeneratedIndex[]; getCategoryGeneratedIndexNavigation: ( categoryGeneratedIndexPermalink: string, @@ -193,12 +193,17 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils { }; } - function getDocNavigation( - unversionedId: string, - versionedId: string, - displayedSidebar: string | null | undefined, - unlistedIds: string[], - ): SidebarNavigation { + function getDocNavigation({ + unversionedId, + versionedId, + displayedSidebar, + unlistedIds, + }: { + unversionedId: string; + versionedId: string; + displayedSidebar: string | null | undefined; + unlistedIds: Set; + }): SidebarNavigation { // TODO legacy id retro-compatibility! let docId = unversionedId; let sidebarName = @@ -220,7 +225,7 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils { ); } navigationItems = navigationItems.filter( - (item) => !(item.type === 'doc' && unlistedIds.includes(item.id)), + (item) => !(item.type === 'doc' && unlistedIds.has(item.id)), ); const currentItemIndex = navigationItems.findIndex((item) => { From b8d802a68c3749e924f721f2a0df7dc0d1b5ed92 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 12:43:04 +0200 Subject: [PATCH 33/50] fix MDX page unlisted position --- packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx index 245e107a2407..6d865b91ea6f 100644 --- a/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/MDXPage/index.tsx @@ -36,10 +36,10 @@ export default function MDXPage(props: Props): JSX.Element { )}> - {unlisted && }
    + {unlisted && }
    From fa5823f79c59d0c17de661f78f5020b8b71efeae Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 13:13:50 +0200 Subject: [PATCH 34/50] draftIds comment --- packages/docusaurus-plugin-content-docs/src/index.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index 9dcd7f030ad0..c270084608f8 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -156,6 +156,9 @@ export default async function pluginContentDocs( versionMetadata, ); + // TODO we only ever need draftIds in further code, not full draft items + // To simplify and prevent mistakes, avoid exposing draft + // replace draft=>draftIds in content loaded const [drafts, docs] = _.partition(docsBase, (doc) => doc.draft); const sidebars = await loadSidebars(versionMetadata.sidebarFilePath, { From 810ad5dc94f47e1e99fb13628557eac0652c8a67 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 13:36:36 +0200 Subject: [PATCH 35/50] blog processing: make it use Error Cause like docs --- .../src/blogUtils.ts | 34 ++++++++++--------- 1 file changed, 18 insertions(+), 16 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts index 72ba63260446..36028495381c 100644 --- a/packages/docusaurus-plugin-content-blog/src/blogUtils.ts +++ b/packages/docusaurus-plugin-content-blog/src/blogUtils.ts @@ -369,23 +369,25 @@ export async function generateBlogPosts( authorsMapPath: options.authorsMapPath, }); + async function doProcessBlogSourceFile(blogSourceFile: string) { + try { + return await processBlogSourceFile( + blogSourceFile, + contentPaths, + context, + options, + authorsMap, + ); + } catch (err) { + throw new Error( + `Processing of blog source file path=${blogSourceFile} failed.`, + {cause: err as Error}, + ); + } + } + const blogPosts = ( - await Promise.all( - blogSourceFiles.map(async (blogSourceFile: string) => { - try { - return await processBlogSourceFile( - blogSourceFile, - contentPaths, - context, - options, - authorsMap, - ); - } catch (err) { - logger.error`Processing of blog source file path=${blogSourceFile} failed.`; - throw err; - } - }), - ) + await Promise.all(blogSourceFiles.map(doProcessBlogSourceFile)) ).filter(Boolean) as BlogPost[]; blogPosts.sort( From c9744735ff507554a53aca211c4a4179edf71321 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 13:39:21 +0200 Subject: [PATCH 36/50] add error cause for page source file processing --- .../src/index.ts | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus-plugin-content-pages/src/index.ts b/packages/docusaurus-plugin-content-pages/src/index.ts index b983a96ccf44..790c89466cf8 100644 --- a/packages/docusaurus-plugin-content-pages/src/index.ts +++ b/packages/docusaurus-plugin-content-pages/src/index.ts @@ -83,7 +83,9 @@ export default function pluginContentPages( ignore: options.exclude, }); - async function toMetadata(relativeSource: string): Promise { + async function processPageSourceFile( + relativeSource: string, + ): Promise { // Lookup in localized folder in priority const contentPath = await getFolderContainingFile( getContentPathList(contentPaths), @@ -126,7 +128,20 @@ export default function pluginContentPages( }; } - return Promise.all(pagesFiles.map(toMetadata)); + async function doProcessPageSourceFile(relativeSource: string) { + try { + return await processPageSourceFile(relativeSource); + } catch (err) { + throw new Error( + `Processing of page source file path=${relativeSource} failed.`, + {cause: err as Error}, + ); + } + } + + return ( + await Promise.all(pagesFiles.map(doProcessPageSourceFile)) + ).filter(Boolean) as Metadata[]; }, async contentLoaded({content, actions}) { From b56ba7f555d86f1ba0d199e3a53fd1dbcabac430 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 14:43:11 +0200 Subject: [PATCH 37/50] add page draft support --- packages/docusaurus-plugin-content-pages/src/frontMatter.ts | 1 + packages/docusaurus-plugin-content-pages/src/index.ts | 5 ++++- .../src/plugin-content-pages.d.ts | 1 + 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts index 6996517e98e8..7e27ab2c9cce 100644 --- a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts @@ -17,6 +17,7 @@ const PageFrontMatterSchema = Joi.object({ description: Joi.string(), wrapperClassName: Joi.string(), hide_table_of_contents: Joi.boolean(), + draft: Joi.boolean(), unlisted: Joi.boolean(), ...FrontMatterTOCHeadingLevels, }); diff --git a/packages/docusaurus-plugin-content-pages/src/index.ts b/packages/docusaurus-plugin-content-pages/src/index.ts index 790c89466cf8..ab1b3c70ccf3 100644 --- a/packages/docusaurus-plugin-content-pages/src/index.ts +++ b/packages/docusaurus-plugin-content-pages/src/index.ts @@ -21,6 +21,7 @@ import { DEFAULT_PLUGIN_ID, parseMarkdownString, isUnlisted, + isDraft, } from '@docusaurus/utils'; import {validatePageFrontMatter} from './frontMatter'; @@ -114,7 +115,9 @@ export default function pluginContentPages( } = parseMarkdownString(content); const frontMatter = validatePageFrontMatter(unsafeFrontMatter); - // TODO draft support is missing + if (isDraft({frontMatter})) { + return undefined; + } const unlisted = isUnlisted({frontMatter}); return { diff --git a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts index d71f073090b1..09279828392a 100644 --- a/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts +++ b/packages/docusaurus-plugin-content-pages/src/plugin-content-pages.d.ts @@ -27,6 +27,7 @@ declare module '@docusaurus/plugin-content-pages' { readonly hide_table_of_contents?: string; readonly toc_min_heading_level?: number; readonly toc_max_heading_level?: number; + readonly draft?: boolean; readonly unlisted?: boolean; }; From 27303657a9f69f8fb0b7a1a8cd14d189a820be0d Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Fri, 28 Oct 2022 16:35:54 +0200 Subject: [PATCH 38/50] add "unlisted" doc + missing FrontMatter doc section for pages plugin --- .../docs/api/plugins/plugin-content-blog.md | 4 +- .../docs/api/plugins/plugin-content-docs.md | 4 +- .../docs/api/plugins/plugin-content-pages.md | 39 +++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) diff --git a/website/docs/api/plugins/plugin-content-blog.md b/website/docs/api/plugins/plugin-content-blog.md index 6e55adf6c242..77dfd3ab284c 100644 --- a/website/docs/api/plugins/plugin-content-blog.md +++ b/website/docs/api/plugins/plugin-content-blog.md @@ -192,8 +192,8 @@ Accepted fields: | `title` | `string` | Markdown title | The blog post title. | | `date` | `string` | File name or file creation time | The blog post creation date. If not specified, this can be extracted from the file or folder name, e.g, `2021-04-15-blog-post.mdx`, `2021-04-15-blog-post/index.mdx`, `2021/04/15/blog-post.mdx`. Otherwise, it is the Markdown file creation time. | | `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your post. | -| `draft` | `boolean` | `false` | A boolean flag to indicate that the blog post is work-in-progress. Draft blog posts will only be displayed during development. | -| `unlisted` | `boolean` | `false` | A boolean flag to indicate that the blog post should be accessible if linked to directly, but visibly hidden on the site otherwise and ignored by search engines. Unlisted blog posts are fully visible in development. | +| `draft` | `boolean` | `false` | Draft blog posts will only be available during development. | +| `unlisted` | `boolean` | `false` | Unlisted blog posts will be available in both development and production. They will be "hidden" in production and can only be accessed if the url is known. | | `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. | | `toc_min_heading_level` | `number` | `2` | The minimum heading level shown in the table of contents. Must be between 2 and 6 and lower or equal to the max value. | | `toc_max_heading_level` | `number` | `3` | The max heading level shown in the table of contents. Must be between 2 and 6. | diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index d0aa3017dff5..9c6f666c1a58 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -292,8 +292,8 @@ Accepted fields: | `image` | `string` | `undefined` | Cover or thumbnail image that will be used when displaying the link to your post. | | `slug` | `string` | File path | Allows to customize the document URL (`//`). Support multiple patterns: `slug: my-doc`, `slug: /my/path/myDoc`, `slug: /`. | | `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your docs. | -| `draft` | `boolean` | `false` | A boolean flag to indicate that a document is a work-in-progress. Draft documents will only be displayed during development. | -| `unlisted` | `boolean` | `false` | A boolean flag to indicate that the document should be accessible if linked to directly, but visibly hidden on the site otherwise and ignored by search engines. Unlisted documents are fully visible in development. | +| `draft` | `boolean` | `false` | Draft documents will only be available during development. | +| `unlisted` | `boolean` | `false` | Unlisted documents will be available in both development and production. They will be "hidden" in production and can only be accessed if the url is known. | | `last_update` | `FileChange` | `undefined` | Allows overriding the last updated author and/or date. Date can be any [parsable date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse). | ```mdx-code-block diff --git a/website/docs/api/plugins/plugin-content-pages.md b/website/docs/api/plugins/plugin-content-pages.md index b6334f5af7ca..2432669d40d0 100644 --- a/website/docs/api/plugins/plugin-content-pages.md +++ b/website/docs/api/plugins/plugin-content-pages.md @@ -79,6 +79,41 @@ const config = { }; ``` +## Markdown front matter {#markdown-front-matter} + +Markdown pages can use the following Markdown front matter metadata fields, enclosed by a line `---` on either side. + +Accepted fields: + +```mdx-code-block + +``` + +| Name | Type | Default | Description | +| --- | --- | --- | --- | +| `title` | `string` | Markdown title | The blog post title. | +| `description` | `string` | The first line of Markdown content | The description of your page, which will become the `` and `` in ``, used by search engines. | +| `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. | +| `draft` | `boolean` | `false` | Draft pages will only be available during development. | +| `unlisted` | `boolean` | `false` | Unlisted pages will be available in both development and production. They will be "hidden" in production and can only be accessed if the url is known. | + +```mdx-code-block + +``` + +Example: + +```md +--- +title: Markdown Page +description: Markdown page SEO description +hide_table_of_contents: false +draft: true +--- + +Markdown page content +``` + ## i18n {#i18n} Read the [i18n introduction](../../i18n/i18n-introduction.md) first. @@ -99,3 +134,7 @@ website/i18n/[locale]/docusaurus-plugin-content-pages ├── first-markdown-page.md └── second-markdown-page.md ``` + +``` + +``` From 7ad04e00930bbcac698b2bd9632b52392055fc97 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Wed, 2 Nov 2022 17:44:53 +0100 Subject: [PATCH 39/50] improve unlisted default messages --- .../docusaurus-theme-common/src/utils/unlistedUtils.tsx | 5 +++-- .../locales/ar/theme-common.json | 4 +++- .../locales/base/theme-common.json | 8 ++++++-- .../locales/bn/theme-common.json | 4 +++- .../locales/cs/theme-common.json | 4 +++- .../locales/da/theme-common.json | 4 +++- .../locales/de/theme-common.json | 4 +++- .../locales/es/theme-common.json | 4 +++- .../locales/fa/theme-common.json | 4 +++- .../locales/fil/theme-common.json | 4 +++- .../locales/fr/theme-common.json | 4 +++- .../locales/he/theme-common.json | 4 +++- .../locales/hi/theme-common.json | 4 +++- .../locales/it/theme-common.json | 4 +++- .../locales/ja/theme-common.json | 4 +++- .../locales/ko/theme-common.json | 4 +++- .../locales/nl/theme-common.json | 4 +++- .../locales/pl/theme-common.json | 4 +++- .../locales/pt-BR/theme-common.json | 4 +++- .../locales/pt-PT/theme-common.json | 4 +++- .../locales/ru/theme-common.json | 4 +++- .../locales/sr/theme-common.json | 4 +++- .../locales/sv/theme-common.json | 4 +++- .../locales/tr/theme-common.json | 4 +++- .../locales/uk/theme-common.json | 4 +++- .../locales/vi/theme-common.json | 4 +++- .../locales/zh-Hans/theme-common.json | 4 +++- .../locales/zh-Hant/theme-common.json | 4 +++- 28 files changed, 87 insertions(+), 30 deletions(-) diff --git a/packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx b/packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx index b08d97f9f08a..8147e5987275 100644 --- a/packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx @@ -14,7 +14,7 @@ export function UnlistedBannerTitle(): JSX.Element { - Unlisted content + Unlisted page ); } @@ -24,7 +24,8 @@ export function UnlistedBannerMessage(): JSX.Element { - This page is unlisted and can only be accessed directly. + This page is unlisted. Search engines will not index it, and only users + having a direct link can access it. ); } diff --git a/packages/docusaurus-theme-translations/locales/ar/theme-common.json b/packages/docusaurus-theme-translations/locales/ar/theme-common.json index af8ccb27bb4c..0dfce9d3cd72 100644 --- a/packages/docusaurus-theme-translations/locales/ar/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ar/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "إصدارات", "theme.tags.tagsListLabel": "الوسوم:", "theme.tags.tagsPageLink": "عرض كل الوسوم", - "theme.tags.tagsPageTitle": "الوسوم" + "theme.tags.tagsPageTitle": "الوسوم", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/base/theme-common.json b/packages/docusaurus-theme-translations/locales/base/theme-common.json index 695c5fff430e..1f7d4b9dac1e 100644 --- a/packages/docusaurus-theme-translations/locales/base/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/base/theme-common.json @@ -16,7 +16,7 @@ "theme.ErrorPageContent.title": "This page crashed.", "theme.ErrorPageContent.title___DESCRIPTION": "The title of the fallback page when the page crashed", "theme.ErrorPageContent.tryAgain": "Try again", - "theme.ErrorPageContent.tryAgain___DESCRIPTION": "The label of the button to try again when the page crashed", + "theme.ErrorPageContent.tryAgain___DESCRIPTION": "The label of the button to try again rendering when the React error boundary captures an error", "theme.NotFound.p1": "We could not find what you were looking for.", "theme.NotFound.p1___DESCRIPTION": "The first paragraph of the 404 page", "theme.NotFound.p2": "Please contact the owner of the site that linked you to the original URL and let them know their link is broken.", @@ -129,5 +129,9 @@ "theme.tags.tagsPageLink": "View All Tags", "theme.tags.tagsPageLink___DESCRIPTION": "The label of the link targeting the tag list page", "theme.tags.tagsPageTitle": "Tags", - "theme.tags.tagsPageTitle___DESCRIPTION": "The title of the tag list page" + "theme.tags.tagsPageTitle___DESCRIPTION": "The title of the tag list page", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.message___DESCRIPTION": "The unlisted content banner message", + "theme.unlistedContent.title": "Unlisted page", + "theme.unlistedContent.title___DESCRIPTION": "The unlisted content banner title" } diff --git a/packages/docusaurus-theme-translations/locales/bn/theme-common.json b/packages/docusaurus-theme-translations/locales/bn/theme-common.json index f77d613d1788..be6d2f9afb39 100644 --- a/packages/docusaurus-theme-translations/locales/bn/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/bn/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "ট্যাগ্স:", "theme.tags.tagsPageLink": "সমস্ত ট্যাগ্স দেখুন", - "theme.tags.tagsPageTitle": "ট্যাগ্স" + "theme.tags.tagsPageTitle": "ট্যাগ্স", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/cs/theme-common.json b/packages/docusaurus-theme-translations/locales/cs/theme-common.json index c5e85314faad..954a450f49cd 100644 --- a/packages/docusaurus-theme-translations/locales/cs/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/cs/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "Tagy:", "theme.tags.tagsPageLink": "Zobrazit všechny tagy", - "theme.tags.tagsPageTitle": "Tagy" + "theme.tags.tagsPageTitle": "Tagy", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/da/theme-common.json b/packages/docusaurus-theme-translations/locales/da/theme-common.json index adbe3e6eace9..2d8cee8306ac 100644 --- a/packages/docusaurus-theme-translations/locales/da/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/da/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsPageLink": "Se alle Tags", - "theme.tags.tagsPageTitle": "Tags" + "theme.tags.tagsPageTitle": "Tags", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/de/theme-common.json b/packages/docusaurus-theme-translations/locales/de/theme-common.json index ada97df4c8af..9d9acac01bcf 100644 --- a/packages/docusaurus-theme-translations/locales/de/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/de/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versionen", "theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsPageLink": "Alle Tags anzeigen", - "theme.tags.tagsPageTitle": "Tags" + "theme.tags.tagsPageTitle": "Tags", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/es/theme-common.json b/packages/docusaurus-theme-translations/locales/es/theme-common.json index a8662c60ec2a..d65fa164a4bc 100644 --- a/packages/docusaurus-theme-translations/locales/es/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/es/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versiones", "theme.tags.tagsListLabel": "Etiquetas:", "theme.tags.tagsPageLink": "Ver Todas las Etiquetas", - "theme.tags.tagsPageTitle": "Etiquetas" + "theme.tags.tagsPageTitle": "Etiquetas", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/fa/theme-common.json b/packages/docusaurus-theme-translations/locales/fa/theme-common.json index 38aa636cd480..26b0faf1b5c5 100644 --- a/packages/docusaurus-theme-translations/locales/fa/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fa/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "نسخه‌ها", "theme.tags.tagsListLabel": "برچسب‌ها:", "theme.tags.tagsPageLink": "مشاهده تمام برچسب‌ها", - "theme.tags.tagsPageTitle": "برچسب‌ها" + "theme.tags.tagsPageTitle": "برچسب‌ها", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/fil/theme-common.json b/packages/docusaurus-theme-translations/locales/fil/theme-common.json index 11aa9d25f4f6..5ba6439e4105 100644 --- a/packages/docusaurus-theme-translations/locales/fil/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fil/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "Mga Tag:", "theme.tags.tagsPageLink": "Tingnan Lahat ng mga Tag", - "theme.tags.tagsPageTitle": "Mga Tag" + "theme.tags.tagsPageTitle": "Mga Tag", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/fr/theme-common.json b/packages/docusaurus-theme-translations/locales/fr/theme-common.json index a4dceac65713..bed999daf11d 100644 --- a/packages/docusaurus-theme-translations/locales/fr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/fr/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "Tags :", "theme.tags.tagsPageLink": "Voir tous les tags", - "theme.tags.tagsPageTitle": "Tags" + "theme.tags.tagsPageTitle": "Tags", + "theme.unlistedContent.message": "Cette page n'est pas répertoriée. Les moteurs de recherche ne l'indexeront pas, et seuls les utilisateurs ayant un lien direct peuvent y accéder.", + "theme.unlistedContent.title": "Page non répertoriée" } diff --git a/packages/docusaurus-theme-translations/locales/he/theme-common.json b/packages/docusaurus-theme-translations/locales/he/theme-common.json index 4082c802805b..33c74d90b762 100644 --- a/packages/docusaurus-theme-translations/locales/he/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/he/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "תגיות:", "theme.tags.tagsPageLink": "כל התגיות", - "theme.tags.tagsPageTitle": "תגיות" + "theme.tags.tagsPageTitle": "תגיות", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/hi/theme-common.json b/packages/docusaurus-theme-translations/locales/hi/theme-common.json index 3113ac239e2b..f4ba995e490f 100644 --- a/packages/docusaurus-theme-translations/locales/hi/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/hi/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "टैग:", "theme.tags.tagsPageLink": "सारे टैग देखें", - "theme.tags.tagsPageTitle": "टैग" + "theme.tags.tagsPageTitle": "टैग", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/it/theme-common.json b/packages/docusaurus-theme-translations/locales/it/theme-common.json index f3ca7df138b1..39f32c9923d3 100644 --- a/packages/docusaurus-theme-translations/locales/it/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/it/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versioni", "theme.tags.tagsListLabel": "Etichette:", "theme.tags.tagsPageLink": "Guarda tutte le etichette", - "theme.tags.tagsPageTitle": "Etichette" + "theme.tags.tagsPageTitle": "Etichette", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/ja/theme-common.json b/packages/docusaurus-theme-translations/locales/ja/theme-common.json index 4ae84260dc9e..f578e82f798b 100644 --- a/packages/docusaurus-theme-translations/locales/ja/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ja/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "他のバージョン", "theme.tags.tagsListLabel": "タグ:", "theme.tags.tagsPageLink": "全てのタグを見る", - "theme.tags.tagsPageTitle": "タグ" + "theme.tags.tagsPageTitle": "タグ", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/ko/theme-common.json b/packages/docusaurus-theme-translations/locales/ko/theme-common.json index 18567774be7f..a7d29e2a6325 100644 --- a/packages/docusaurus-theme-translations/locales/ko/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ko/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "버전", "theme.tags.tagsListLabel": "태그:", "theme.tags.tagsPageLink": "모든 태그 보기", - "theme.tags.tagsPageTitle": "태그" + "theme.tags.tagsPageTitle": "태그", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/nl/theme-common.json b/packages/docusaurus-theme-translations/locales/nl/theme-common.json index 9970dcb85cbd..e00d710e95a8 100644 --- a/packages/docusaurus-theme-translations/locales/nl/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/nl/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versies", "theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsPageLink": "Laat alle tags zien", - "theme.tags.tagsPageTitle": "Tags" + "theme.tags.tagsPageTitle": "Tags", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/pl/theme-common.json b/packages/docusaurus-theme-translations/locales/pl/theme-common.json index 9cd009cd3e18..012e48d9adcd 100644 --- a/packages/docusaurus-theme-translations/locales/pl/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pl/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Wersje", "theme.tags.tagsListLabel": "Tagi:", "theme.tags.tagsPageLink": "Wyświetl wszystkie tagi", - "theme.tags.tagsPageTitle": "Tagi" + "theme.tags.tagsPageTitle": "Tagi", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json b/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json index 65ad133049ea..c8100bf24287 100644 --- a/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pt-BR/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "Marcadores:", "theme.tags.tagsPageLink": "Ver todas os Marcadores", - "theme.tags.tagsPageTitle": "Marcadores" + "theme.tags.tagsPageTitle": "Marcadores", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json b/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json index 81a2e2fc142d..a08cc6bb2f1a 100644 --- a/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/pt-PT/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versions", "theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsPageLink": "Ver todas as Tags", - "theme.tags.tagsPageTitle": "Tags" + "theme.tags.tagsPageTitle": "Tags", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/ru/theme-common.json b/packages/docusaurus-theme-translations/locales/ru/theme-common.json index 6a2feed11ad7..2aaabbb1916a 100644 --- a/packages/docusaurus-theme-translations/locales/ru/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/ru/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Версии", "theme.tags.tagsListLabel": "Теги:", "theme.tags.tagsPageLink": "Посмотреть все теги", - "theme.tags.tagsPageTitle": "Теги" + "theme.tags.tagsPageTitle": "Теги", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/sr/theme-common.json b/packages/docusaurus-theme-translations/locales/sr/theme-common.json index 8d9931f67d17..6e746a38db7b 100644 --- a/packages/docusaurus-theme-translations/locales/sr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/sr/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Верзије", "theme.tags.tagsListLabel": "Ознаке:", "theme.tags.tagsPageLink": "Погледај све ознаке", - "theme.tags.tagsPageTitle": "Ознаке" + "theme.tags.tagsPageTitle": "Ознаке", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/sv/theme-common.json b/packages/docusaurus-theme-translations/locales/sv/theme-common.json index b8e1a8df50b5..ed2be7a16e39 100644 --- a/packages/docusaurus-theme-translations/locales/sv/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/sv/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versioner", "theme.tags.tagsListLabel": "Taggar:", "theme.tags.tagsPageLink": "Visa Alla Taggar", - "theme.tags.tagsPageTitle": "Taggar" + "theme.tags.tagsPageTitle": "Taggar", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/tr/theme-common.json b/packages/docusaurus-theme-translations/locales/tr/theme-common.json index 69c5647f151d..c41bb5280df3 100644 --- a/packages/docusaurus-theme-translations/locales/tr/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/tr/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Versiyonlar", "theme.tags.tagsListLabel": "Etiketler:", "theme.tags.tagsPageLink": "Tüm Etiketleri Görüntüle", - "theme.tags.tagsPageTitle": "Etiketler" + "theme.tags.tagsPageTitle": "Etiketler", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/uk/theme-common.json b/packages/docusaurus-theme-translations/locales/uk/theme-common.json index 0a838bd2682f..5b7bb70691f6 100644 --- a/packages/docusaurus-theme-translations/locales/uk/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/uk/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Версії", "theme.tags.tagsListLabel": "Теги:", "theme.tags.tagsPageLink": "Переглянути всі теги", - "theme.tags.tagsPageTitle": "Теги" + "theme.tags.tagsPageTitle": "Теги", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/vi/theme-common.json b/packages/docusaurus-theme-translations/locales/vi/theme-common.json index 4784d3e47b77..d28849af7ffd 100644 --- a/packages/docusaurus-theme-translations/locales/vi/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/vi/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "Phiên bản", "theme.tags.tagsListLabel": "Thẻ:", "theme.tags.tagsPageLink": "Xem tất cả Thẻ", - "theme.tags.tagsPageTitle": "Thẻ" + "theme.tags.tagsPageTitle": "Thẻ", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json b/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json index 6aebc6c4ac6c..e2081fada05e 100644 --- a/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/zh-Hans/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "选择版本", "theme.tags.tagsListLabel": "标签:", "theme.tags.tagsPageLink": "查看所有标签", - "theme.tags.tagsPageTitle": "标签" + "theme.tags.tagsPageTitle": "标签", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } diff --git a/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json b/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json index 84a509608978..8193911a9dc4 100644 --- a/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json +++ b/packages/docusaurus-theme-translations/locales/zh-Hant/theme-common.json @@ -64,5 +64,7 @@ "theme.navbar.mobileVersionsDropdown.label": "選擇版本", "theme.tags.tagsListLabel": "標籤:", "theme.tags.tagsPageLink": "檢視所有標籤", - "theme.tags.tagsPageTitle": "標籤" + "theme.tags.tagsPageTitle": "標籤", + "theme.unlistedContent.message": "This page is unlisted. Search engines will not index it, and only users having a direct link can access it.", + "theme.unlistedContent.title": "Unlisted page" } From 86801b37ede50db6bbe3f386a6c2762826f7f858 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Wed, 2 Nov 2022 17:53:45 +0100 Subject: [PATCH 40/50] improve unlisted frontMatter docs --- website/docs/api/plugins/plugin-content-blog.md | 2 +- website/docs/api/plugins/plugin-content-docs.md | 2 +- website/docs/api/plugins/plugin-content-pages.md | 6 +----- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/website/docs/api/plugins/plugin-content-blog.md b/website/docs/api/plugins/plugin-content-blog.md index 77dfd3ab284c..d31d00c00b3b 100644 --- a/website/docs/api/plugins/plugin-content-blog.md +++ b/website/docs/api/plugins/plugin-content-blog.md @@ -193,7 +193,7 @@ Accepted fields: | `date` | `string` | File name or file creation time | The blog post creation date. If not specified, this can be extracted from the file or folder name, e.g, `2021-04-15-blog-post.mdx`, `2021-04-15-blog-post/index.mdx`, `2021/04/15/blog-post.mdx`. Otherwise, it is the Markdown file creation time. | | `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your post. | | `draft` | `boolean` | `false` | Draft blog posts will only be available during development. | -| `unlisted` | `boolean` | `false` | Unlisted blog posts will be available in both development and production. They will be "hidden" in production and can only be accessed if the url is known. | +| `unlisted` | `boolean` | `false` | Unlisted blog posts will be available in both development and production. They will be "hidden" in production, not indexed, excluded from sitemaps, and can only be accessed by users having a direct link. | | `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. | | `toc_min_heading_level` | `number` | `2` | The minimum heading level shown in the table of contents. Must be between 2 and 6 and lower or equal to the max value. | | `toc_max_heading_level` | `number` | `3` | The max heading level shown in the table of contents. Must be between 2 and 6. | diff --git a/website/docs/api/plugins/plugin-content-docs.md b/website/docs/api/plugins/plugin-content-docs.md index 9c6f666c1a58..bc9dadc73615 100644 --- a/website/docs/api/plugins/plugin-content-docs.md +++ b/website/docs/api/plugins/plugin-content-docs.md @@ -293,7 +293,7 @@ Accepted fields: | `slug` | `string` | File path | Allows to customize the document URL (`//`). Support multiple patterns: `slug: my-doc`, `slug: /my/path/myDoc`, `slug: /`. | | `tags` | `Tag[]` | `undefined` | A list of strings or objects of two string fields `label` and `permalink` to tag to your docs. | | `draft` | `boolean` | `false` | Draft documents will only be available during development. | -| `unlisted` | `boolean` | `false` | Unlisted documents will be available in both development and production. They will be "hidden" in production and can only be accessed if the url is known. | +| `unlisted` | `boolean` | `false` | Unlisted documents will be available in both development and production. They will be "hidden" in production, not indexed, excluded from sitemaps, and can only be accessed by users having a direct link. | | `last_update` | `FileChange` | `undefined` | Allows overriding the last updated author and/or date. Date can be any [parsable date string](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/parse). | ```mdx-code-block diff --git a/website/docs/api/plugins/plugin-content-pages.md b/website/docs/api/plugins/plugin-content-pages.md index 2432669d40d0..b161bee889e1 100644 --- a/website/docs/api/plugins/plugin-content-pages.md +++ b/website/docs/api/plugins/plugin-content-pages.md @@ -95,7 +95,7 @@ Accepted fields: | `description` | `string` | The first line of Markdown content | The description of your page, which will become the `` and `` in ``, used by search engines. | | `hide_table_of_contents` | `boolean` | `false` | Whether to hide the table of contents to the right. | | `draft` | `boolean` | `false` | Draft pages will only be available during development. | -| `unlisted` | `boolean` | `false` | Unlisted pages will be available in both development and production. They will be "hidden" in production and can only be accessed if the url is known. | +| `unlisted` | `boolean` | `false` | Unlisted pages will be available in both development and production. They will be "hidden" in production, not indexed, excluded from sitemaps, and can only be accessed by users having a direct link. | ```mdx-code-block @@ -134,7 +134,3 @@ website/i18n/[locale]/docusaurus-plugin-content-pages ├── first-markdown-page.md └── second-markdown-page.md ``` - -``` - -``` From 3bf18c5656ea474f4e1a06242fa5f205290279bf Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Wed, 2 Nov 2022 18:23:28 +0100 Subject: [PATCH 41/50] shared validation of draft/unlisted + add "draft XOR unlisted" rule --- .../src/__tests__/frontMatter.test.ts | 76 +++++++++++-------- .../src/frontMatter.ts | 13 ++-- .../src/__tests__/frontMatter.test.ts | 34 ++++++--- .../src/frontMatter.ts | 7 +- .../src/frontMatter.ts | 5 +- .../validationSchemas.test.ts.snap | 10 +++ .../src/__tests__/validationSchemas.test.ts | 25 ++++++ .../docusaurus-utils-validation/src/index.ts | 1 + .../src/validationSchemas.ts | 23 ++++++ 9 files changed, 143 insertions(+), 51 deletions(-) diff --git a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts index 083e3ca95ff9..3e3580d92c5c 100644 --- a/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-blog/src/__tests__/frontMatter.test.ts @@ -12,7 +12,7 @@ import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog'; // TODO this abstraction reduce verbosity but it makes it harder to debug // It would be preferable to just expose helper methods function testField(params: { - fieldName: keyof BlogPostFrontMatter; + prefix: string; validFrontMatters: BlogPostFrontMatter[]; convertibleFrontMatter?: [ ConvertibleFrontMatter: {[key: string]: unknown}, @@ -23,7 +23,7 @@ function testField(params: { ErrorMessage: string, ][]; }) { - describe(`"${params.fieldName}" field`, () => { + describe(`"${params.prefix}" field`, () => { it('accept valid values', () => { params.validFrontMatters.forEach((frontMatter) => { expect(validateBlogPostFrontMatter(frontMatter)).toEqual(frontMatter); @@ -44,15 +44,12 @@ function testField(params: { params.invalidFrontMatters?.forEach(([frontMatter, message]) => { try { validateBlogPostFrontMatter(frontMatter); - // eslint-disable-next-line jest/no-jasmine-globals - fail( - new Error( - `Blog front matter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify( - frontMatter, - null, - 2, - )}`, - ), + throw new Error( + `Blog front matter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify( + frontMatter, + null, + 2, + )}`, ); } catch (err) { // eslint-disable-next-line jest/no-conditional-expect @@ -79,7 +76,7 @@ describe('validateBlogPostFrontMatter', () => { describe('validateBlogPostFrontMatter description', () => { testField({ - fieldName: 'description', + prefix: 'description', validFrontMatters: [ // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 {description: ''}, @@ -90,7 +87,7 @@ describe('validateBlogPostFrontMatter description', () => { describe('validateBlogPostFrontMatter title', () => { testField({ - fieldName: 'title', + prefix: 'title', validFrontMatters: [ // See https://github.com/facebook/docusaurus/issues/4591#issuecomment-822372398 {title: ''}, @@ -101,7 +98,7 @@ describe('validateBlogPostFrontMatter title', () => { describe('validateBlogPostFrontMatter id', () => { testField({ - fieldName: 'id', + prefix: 'id', validFrontMatters: [{id: '123'}, {id: 'id'}], invalidFrontMatters: [[{id: ''}, 'not allowed to be empty']], }); @@ -132,7 +129,7 @@ describe('validateBlogPostFrontMatter handles legacy/new author front matter', ( describe('validateBlogPostFrontMatter author', () => { testField({ - fieldName: 'author', + prefix: 'author', validFrontMatters: [{author: '123'}, {author: 'author'}], invalidFrontMatters: [[{author: ''}, 'not allowed to be empty']], }); @@ -140,7 +137,7 @@ describe('validateBlogPostFrontMatter author', () => { describe('validateBlogPostFrontMatter author_title', () => { testField({ - fieldName: 'author_title', + prefix: 'author_title', validFrontMatters: [ {author: '123', author_title: '123'}, {author: '123', author_title: 'author_title'}, @@ -149,7 +146,7 @@ describe('validateBlogPostFrontMatter author_title', () => { }); testField({ - fieldName: 'authorTitle', + prefix: 'authorTitle', validFrontMatters: [{authorTitle: '123'}, {authorTitle: 'authorTitle'}], invalidFrontMatters: [[{authorTitle: ''}, 'not allowed to be empty']], }); @@ -157,7 +154,7 @@ describe('validateBlogPostFrontMatter author_title', () => { describe('validateBlogPostFrontMatter author_url', () => { testField({ - fieldName: 'author_url', + prefix: 'author_url', validFrontMatters: [ {author_url: 'https://docusaurus.io'}, {author_url: '../../relative'}, @@ -172,7 +169,7 @@ describe('validateBlogPostFrontMatter author_url', () => { }); testField({ - fieldName: 'authorURL', + prefix: 'authorURL', validFrontMatters: [ {authorURL: 'https://docusaurus.io'}, {authorURL: '../../relative'}, @@ -190,7 +187,7 @@ describe('validateBlogPostFrontMatter author_url', () => { describe('validateBlogPostFrontMatter author_image_url', () => { testField({ - fieldName: 'author_image_url', + prefix: 'author_image_url', validFrontMatters: [ {author_image_url: 'https://docusaurus.io/asset/image.png'}, {author_image_url: '../../relative'}, @@ -205,7 +202,7 @@ describe('validateBlogPostFrontMatter author_image_url', () => { }); testField({ - fieldName: 'authorImageURL', + prefix: 'authorImageURL', validFrontMatters: [ {authorImageURL: 'https://docusaurus.io/asset/image.png'}, {authorImageURL: '../../relative'}, @@ -222,7 +219,7 @@ describe('validateBlogPostFrontMatter author_image_url', () => { describe('validateBlogPostFrontMatter authors', () => { testField({ - fieldName: 'author', + prefix: 'author', validFrontMatters: [ {authors: []}, {authors: 'authorKey'}, @@ -270,7 +267,7 @@ describe('validateBlogPostFrontMatter authors', () => { describe('validateBlogPostFrontMatter slug', () => { testField({ - fieldName: 'slug', + prefix: 'slug', validFrontMatters: [ {slug: 'blog/'}, {slug: '/blog'}, @@ -287,7 +284,7 @@ describe('validateBlogPostFrontMatter slug', () => { describe('validateBlogPostFrontMatter image', () => { testField({ - fieldName: 'image', + prefix: 'image', validFrontMatters: [ {image: 'https://docusaurus.io/image.png'}, {image: 'blog/'}, @@ -307,7 +304,7 @@ describe('validateBlogPostFrontMatter image', () => { describe('validateBlogPostFrontMatter tags', () => { testField({ - fieldName: 'tags', + prefix: 'tags', validFrontMatters: [ {tags: []}, {tags: ['hello']}, @@ -335,7 +332,7 @@ describe('validateBlogPostFrontMatter tags', () => { describe('validateBlogPostFrontMatter keywords', () => { testField({ - fieldName: 'keywords', + prefix: 'keywords', validFrontMatters: [ {keywords: ['hello']}, {keywords: ['hello', 'world']}, @@ -352,7 +349,7 @@ describe('validateBlogPostFrontMatter keywords', () => { describe('validateBlogPostFrontMatter draft', () => { testField({ - fieldName: 'draft', + prefix: 'draft', validFrontMatters: [{draft: true}, {draft: false}], convertibleFrontMatter: [ [{draft: 'true'}, {draft: true}], @@ -367,7 +364,7 @@ describe('validateBlogPostFrontMatter draft', () => { describe('validateBlogPostFrontMatter unlisted', () => { testField({ - fieldName: 'unlisted', + prefix: 'unlisted', validFrontMatters: [{unlisted: true}, {unlisted: false}], convertibleFrontMatter: [ [{unlisted: 'true'}, {unlisted: true}], @@ -380,9 +377,28 @@ describe('validateBlogPostFrontMatter unlisted', () => { }); }); +describe('validateDocFrontMatter draft XOR unlisted', () => { + testField({ + prefix: 'draft XOR unlisted', + validFrontMatters: [ + {draft: false}, + {unlisted: false}, + {draft: false, unlisted: false}, + {draft: true, unlisted: false}, + {draft: false, unlisted: true}, + ], + invalidFrontMatters: [ + [ + {draft: true, unlisted: true}, + "Can't be draft and unlisted at the same time.", + ], + ], + }); +}); + describe('validateBlogPostFrontMatter hide_table_of_contents', () => { testField({ - fieldName: 'hide_table_of_contents', + prefix: 'hide_table_of_contents', validFrontMatters: [ {hide_table_of_contents: true}, {hide_table_of_contents: false}, @@ -400,7 +416,7 @@ describe('validateBlogPostFrontMatter hide_table_of_contents', () => { describe('validateBlogPostFrontMatter date', () => { testField({ - fieldName: 'date', + prefix: 'date', validFrontMatters: [ {date: new Date('2020-01-01')}, {date: '2020-01-01'}, diff --git a/packages/docusaurus-plugin-content-blog/src/frontMatter.ts b/packages/docusaurus-plugin-content-blog/src/frontMatter.ts index 393bd79e2118..73b4d37d25ee 100644 --- a/packages/docusaurus-plugin-content-blog/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-blog/src/frontMatter.ts @@ -11,6 +11,7 @@ import { validateFrontMatter, FrontMatterTagsSchema, FrontMatterTOCHeadingLevels, + ContentVisibilitySchema, } from '@docusaurus/utils-validation'; import type {BlogPostFrontMatter} from '@docusaurus/plugin-content-blog'; @@ -32,8 +33,6 @@ const BlogFrontMatterSchema = Joi.object({ title: Joi.string().allow(''), description: Joi.string().allow(''), tags: FrontMatterTagsSchema, - draft: Joi.boolean(), - unlisted: Joi.boolean(), date: Joi.date().raw(), // New multi-authors front matter: @@ -70,10 +69,12 @@ const BlogFrontMatterSchema = Joi.object({ hide_table_of_contents: Joi.boolean(), ...FrontMatterTOCHeadingLevels, -}).messages({ - 'deprecate.error': - '{#label} blog frontMatter field is deprecated. Please use {#alternative} instead.', -}); +}) + .messages({ + 'deprecate.error': + '{#label} blog frontMatter field is deprecated. Please use {#alternative} instead.', + }) + .concat(ContentVisibilitySchema); export function validateBlogPostFrontMatter(frontMatter: { [key: string]: unknown; diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts index d549155b4336..7aeada8201b8 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/frontMatter.test.ts @@ -44,15 +44,12 @@ function testField(params: { params.invalidFrontMatters?.forEach(([frontMatter, message]) => { try { validateDocFrontMatter(frontMatter); - // eslint-disable-next-line jest/no-jasmine-globals - fail( - new Error( - `Doc front matter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify( - frontMatter, - null, - 2, - )}`, - ), + throw new Error( + `Doc front matter is expected to be rejected, but was accepted successfully:\n ${JSON.stringify( + frontMatter, + null, + 2, + )}`, ); } catch (err) { // eslint-disable-next-line jest/no-conditional-expect @@ -413,6 +410,25 @@ describe('validateDocFrontMatter unlisted', () => { }); }); +describe('validateDocFrontMatter draft XOR unlisted', () => { + testField({ + prefix: 'draft XOR unlisted', + validFrontMatters: [ + {draft: false}, + {unlisted: false}, + {draft: false, unlisted: false}, + {draft: true, unlisted: false}, + {draft: false, unlisted: true}, + ], + invalidFrontMatters: [ + [ + {draft: true, unlisted: true}, + "Can't be draft and unlisted at the same time.", + ], + ], + }); +}); + describe('validateDocFrontMatter last_update', () => { testField({ prefix: 'last_update', diff --git a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts index ce29dbf2ac39..1cffac35f32c 100644 --- a/packages/docusaurus-plugin-content-docs/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-docs/src/frontMatter.ts @@ -11,6 +11,7 @@ import { FrontMatterTagsSchema, FrontMatterTOCHeadingLevels, validateFrontMatter, + ContentVisibilitySchema, } from '@docusaurus/utils-validation'; import type {DocFrontMatter} from '@docusaurus/plugin-content-docs'; @@ -43,8 +44,6 @@ const DocFrontMatterSchema = Joi.object({ parse_number_prefixes: Joi.boolean(), pagination_next: Joi.string().allow(null), pagination_prev: Joi.string().allow(null), - draft: Joi.boolean(), - unlisted: Joi.boolean(), ...FrontMatterTOCHeadingLevels, last_update: Joi.object({ author: Joi.string(), @@ -55,7 +54,9 @@ const DocFrontMatterSchema = Joi.object({ 'object.missing': FrontMatterLastUpdateErrorMessage, 'object.base': FrontMatterLastUpdateErrorMessage, }), -}).unknown(); +}) + .unknown() + .concat(ContentVisibilitySchema); export function validateDocFrontMatter(frontMatter: { [key: string]: unknown; diff --git a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts index 7e27ab2c9cce..87562de53e34 100644 --- a/packages/docusaurus-plugin-content-pages/src/frontMatter.ts +++ b/packages/docusaurus-plugin-content-pages/src/frontMatter.ts @@ -9,6 +9,7 @@ import { Joi, validateFrontMatter, FrontMatterTOCHeadingLevels, + ContentVisibilitySchema, } from '@docusaurus/utils-validation'; import type {FrontMatter} from '@docusaurus/plugin-content-pages'; @@ -17,10 +18,8 @@ const PageFrontMatterSchema = Joi.object({ description: Joi.string(), wrapperClassName: Joi.string(), hide_table_of_contents: Joi.boolean(), - draft: Joi.boolean(), - unlisted: Joi.boolean(), ...FrontMatterTOCHeadingLevels, -}); +}).concat(ContentVisibilitySchema); export function validatePageFrontMatter(frontMatter: { [key: string]: unknown; diff --git a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap index b2ef0a4a2588..4488ab4bdb41 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap +++ b/packages/docusaurus-utils-validation/src/__tests__/__snapshots__/validationSchemas.test.ts.snap @@ -28,6 +28,16 @@ exports[`validation schemas admonitionsSchema: for value={"unknownAttribute":"va exports[`validation schemas admonitionsSchema: for value=3 1`] = `""value" does not look like a valid admonitions config"`; +exports[`validation schemas contentVisibilitySchema: for value={"draft":"bad string"} 1`] = `""draft" must be a boolean"`; + +exports[`validation schemas contentVisibilitySchema: for value={"draft":42} 1`] = `""draft" must be a boolean"`; + +exports[`validation schemas contentVisibilitySchema: for value={"draft":true,"unlisted":true} 1`] = `"Can't be draft and unlisted at the same time."`; + +exports[`validation schemas contentVisibilitySchema: for value={"unlisted":"bad string"} 1`] = `""unlisted" must be a boolean"`; + +exports[`validation schemas contentVisibilitySchema: for value={"unlisted":42} 1`] = `""unlisted" must be a boolean"`; + exports[`validation schemas pathnameSchema: for value="foo" 1`] = `""value" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; exports[`validation schemas pathnameSchema: for value="https://github.com/foo" 1`] = `""value" is not a valid pathname. Pathname should start with slash and not contain any domain or query string."`; diff --git a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts index 46515774bb3f..7c8d3e42a12f 100644 --- a/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts +++ b/packages/docusaurus-utils-validation/src/__tests__/validationSchemas.test.ts @@ -14,6 +14,7 @@ import { PluginIdSchema, URISchema, PathnameSchema, + ContentVisibilitySchema, } from '../validationSchemas'; function createTestHelpers({ @@ -166,4 +167,28 @@ describe('validation schemas', () => { testFail('foo'); testFail('https://github.com/foo'); }); + + it('contentVisibilitySchema', () => { + const {testFail, testOK} = createTestHelpers({ + schema: ContentVisibilitySchema, + }); + + testOK({}); + testOK({draft: false}); + testOK({draft: true}); + testOK({unlisted: false}); + testOK({unlisted: true}); + + testOK({draft: false, unlisted: false}); + testOK({draft: true, unlisted: false}); + testOK({draft: false, unlisted: true}); + testOK({draft: true, unlisted: undefined}); + testOK({draft: undefined, unlisted: true}); + + testFail({draft: 'bad string'}); + testFail({draft: 42}); + testFail({unlisted: 'bad string'}); + testFail({unlisted: 42}); + testFail({draft: true, unlisted: true}); + }); }); diff --git a/packages/docusaurus-utils-validation/src/index.ts b/packages/docusaurus-utils-validation/src/index.ts index 40924a6da012..8d3fd6566ca6 100644 --- a/packages/docusaurus-utils-validation/src/index.ts +++ b/packages/docusaurus-utils-validation/src/index.ts @@ -24,4 +24,5 @@ export { PathnameSchema, FrontMatterTagsSchema, FrontMatterTOCHeadingLevels, + ContentVisibilitySchema, } from './validationSchemas'; diff --git a/packages/docusaurus-utils-validation/src/validationSchemas.ts b/packages/docusaurus-utils-validation/src/validationSchemas.ts index 15c87d777632..f5e29cf82e2a 100644 --- a/packages/docusaurus-utils-validation/src/validationSchemas.ts +++ b/packages/docusaurus-utils-validation/src/validationSchemas.ts @@ -126,3 +126,26 @@ export const FrontMatterTOCHeadingLevels = { }), toc_max_heading_level: JoiFrontMatter.number().min(2).max(6), }; + +export type ContentVisibility = { + draft: boolean; + unlisted: boolean; +}; + +export const ContentVisibilitySchema = JoiFrontMatter.object( + { + draft: JoiFrontMatter.boolean(), + unlisted: JoiFrontMatter.boolean(), + }, +) + .custom((frontMatter: ContentVisibility, helpers) => { + if (frontMatter.draft && frontMatter.unlisted) { + return helpers.error('frontMatter.draftAndUnlistedError'); + } + return frontMatter; + }) + .messages({ + 'frontMatter.draftAndUnlistedError': + "Can't be draft and unlisted at the same time.", + }) + .unknown(); From 7dde1eb81a6e7531053be4bc6756b9007a8b905b Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 11:56:45 +0100 Subject: [PATCH 42/50] add more dogfood cases for unlisted/draft category indexes --- .../visibility/only-drafts/draft-subcategory/index.md | 8 ++++++++ .../only-unlisteds/unlisted-subcategory/index.md | 8 ++++++++ .../visibility/some-drafts/draft-subcategory/index.md | 8 ++++++++ .../some-unlisteds/unlisted-subcategory/index.md | 8 ++++++++ 4 files changed, 32 insertions(+) create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/index.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/index.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/index.md create mode 100644 website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/index.md diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/index.md b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/index.md new file mode 100644 index 000000000000..d22fe8149241 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-drafts/draft-subcategory/index.md @@ -0,0 +1,8 @@ +--- +draft: true +tags: [visibility, draft] +--- + +# Only Drafts - Subcategory index draft + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/index.md b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/index.md new file mode 100644 index 000000000000..f179ed324ada --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/only-unlisteds/unlisted-subcategory/index.md @@ -0,0 +1,8 @@ +--- +unlisted: true +tags: [visibility, unlisted] +--- + +# Only Unlisteds - Subcategory index unlisted + +Doc with unlisted front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/index.md b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/index.md new file mode 100644 index 000000000000..8ead97125412 --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-drafts/draft-subcategory/index.md @@ -0,0 +1,8 @@ +--- +draft: true +tags: [visibility, draft] +--- + +# Some Drafts - Subcategory index draft + +Doc with draft front matter diff --git a/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/index.md b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/index.md new file mode 100644 index 000000000000..ea122bdc09fd --- /dev/null +++ b/website/_dogfooding/_docs tests/tests/visibility/some-unlisteds/unlisted-subcategory/index.md @@ -0,0 +1,8 @@ +--- +unlisted: true +tags: [visibility, unlisted] +--- + +# Some Unlisteds - Subcategory index unlisted + +Doc with unlisted front matter From d81b518e27ace859c759350f5bc46742e2242141 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 12:15:49 +0100 Subject: [PATCH 43/50] filter unlisted category index from navigation --- .../src/sidebars/utils.ts | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts index cb186182f4b5..59d10f4a1430 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/utils.ts @@ -224,9 +224,21 @@ export function createSidebarsUtils(sidebars: Sidebars): SidebarsUtils { `Doc with ID ${docId} wants to display sidebar ${sidebarName} but a sidebar with this name doesn't exist`, ); } - navigationItems = navigationItems.filter( - (item) => !(item.type === 'doc' && unlistedIds.has(item.id)), - ); + + // Filter unlisted items from navigation + navigationItems = navigationItems.filter((item) => { + if (item.type === 'doc' && unlistedIds.has(item.id)) { + return false; + } + if ( + item.type === 'category' && + item.link.type === 'doc' && + unlistedIds.has(item.link.id) + ) { + return false; + } + return true; + }); const currentItemIndex = navigationItems.findIndex((item) => { if (item.type === 'doc') { From d720989a150340f815759960f061672f0cbdf2ea Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 12:39:04 +0100 Subject: [PATCH 44/50] better unlisted tests covering more edge cases --- .../__fixtures__/simple-site/docs/ipsum.md | 1 + .../docs/unlisted-category/index.md | 6 + .../unlisted-category-doc.md | 6 + .../__fixtures__/simple-site/sidebars.json | 11 +- .../__tests__/__snapshots__/cli.test.ts.snap | 1 + .../__tests__/__snapshots__/docs.test.ts.snap | 389 +++++++++++++++++- .../__snapshots__/index.test.ts.snap | 43 +- .../src/__tests__/docs.test.ts | 23 +- .../src/docs.ts | 4 +- .../src/index.ts | 6 +- 10 files changed, 468 insertions(+), 22 deletions(-) create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/index.md create mode 100644 packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/unlisted-category-doc.md diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/ipsum.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/ipsum.md index 706687dbc53b..6bac3bd5a49a 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/ipsum.md +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/ipsum.md @@ -1,5 +1,6 @@ --- custom_edit_url: null +pagination_next: doc-unlisted --- Lorem ipsum. diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/index.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/index.md new file mode 100644 index 000000000000..440e184ebcca --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/index.md @@ -0,0 +1,6 @@ +--- +id: unlisted-category-index +unlisted: true +--- + +This is an unlisted category index diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/unlisted-category-doc.md b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/unlisted-category-doc.md new file mode 100644 index 000000000000..9f91c9baaf5f --- /dev/null +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/docs/unlisted-category/unlisted-category-doc.md @@ -0,0 +1,6 @@ +--- +id: unlisted-category-doc +unlisted: true +--- + +This is an unlisted category doc diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json index 7f74d2280b67..19ff4b802bf7 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__fixtures__/simple-site/sidebars.json @@ -4,7 +4,16 @@ { "type": "category", "label": "foo", - "items": ["foo/bar", "foo/baz"] + "items": ["foo/bar", "doc-unlisted", "foo/baz"] + }, + { + "type": "category", + "label": "Unlisted category", + "link": { + "type": "doc", + "id": "unlisted-category/unlisted-category-index" + }, + "items": ["unlisted-category/unlisted-category-doc"] }, { "type": "category", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap index edff61da5b8b..35a74e2404a5 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap @@ -10,6 +10,7 @@ exports[`docsVersion first time versioning 1`] = ` { "items": [ "foo/bar", + "doc-unlisted", "foo/baz", ], "label": "foo", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap index 34d27ff34f39..a9c3c1d46336 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/docs.test.ts.snap @@ -1,6 +1,6 @@ // Jest Snapshot v1, https://goo.gl/fbAQLP -exports[`simple site custom pagination 1`] = ` +exports[`simple site custom pagination - development 1`] = ` { "pagination": [ { @@ -25,8 +25,8 @@ exports[`simple site custom pagination 1`] = ` { "id": "doc-draft", "next": { - "permalink": "/docs/foo/bar", - "title": "Bar", + "permalink": "/docs/doc-unlisted", + "title": "doc-unlisted", }, "prev": { "permalink": "/docs/doc with space", @@ -35,8 +35,14 @@ exports[`simple site custom pagination 1`] = ` }, { "id": "doc-unlisted", - "next": undefined, - "prev": undefined, + "next": { + "permalink": "/docs/foo/bar", + "title": "Bar", + }, + "prev": { + "permalink": "/docs/doc-draft", + "title": "doc-draft", + }, }, { "id": "foo/bar", @@ -79,9 +85,356 @@ exports[`simple site custom pagination 1`] = ` { "id": "ipsum", "next": { + "permalink": "/docs/doc-unlisted", + "title": "doc-unlisted", + }, + "prev": { + "permalink": "/docs/", + "title": "Hello sidebar_label", + }, + }, + { + "id": "lastUpdateAuthorOnly", + "next": { + "permalink": "/docs/lastUpdateDateOnly", + "title": "Last Update Date Only", + }, + "prev": { + "permalink": "/docs/ipsum", + "title": "ipsum", + }, + }, + { + "id": "lastUpdateDateOnly", + "next": { + "permalink": "/docs/lorem", + "title": "lorem", + }, + "prev": { "permalink": "/docs/lastUpdateAuthorOnly", "title": "Last Update Author Only", }, + }, + { + "id": "lorem", + "next": { + "permalink": "/docs/rootAbsoluteSlug", + "title": "rootAbsoluteSlug", + }, + "prev": { + "permalink": "/docs/lastUpdateDateOnly", + "title": "Last Update Date Only", + }, + }, + { + "id": "rootAbsoluteSlug", + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "prev": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + }, + { + "id": "rootRelativeSlug", + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "prev": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + }, + { + "id": "rootResolvedSlug", + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "prev": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + }, + { + "id": "rootTryToEscapeSlug", + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "prev": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + }, + { + "id": "slugs/absoluteSlug", + "next": { + "permalink": "/docs/slugs/relativeSlug", + "title": "relativeSlug", + }, + "prev": { + "permalink": "/docs/rootTryToEscapeSlug", + "title": "rootTryToEscapeSlug", + }, + }, + { + "id": "slugs/relativeSlug", + "next": { + "permalink": "/docs/slugs/hey/resolvedSlug", + "title": "resolvedSlug", + }, + "prev": { + "permalink": "/docs/absoluteSlug", + "title": "absoluteSlug", + }, + }, + { + "id": "slugs/resolvedSlug", + "next": { + "permalink": "/docs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + }, + "prev": { + "permalink": "/docs/slugs/relativeSlug", + "title": "relativeSlug", + }, + }, + { + "id": "slugs/tryToEscapeSlug", + "next": { + "permalink": "/docs/unlisted-category/", + "title": "unlisted-category-index", + }, + "prev": { + "permalink": "/docs/slugs/hey/resolvedSlug", + "title": "resolvedSlug", + }, + }, + { + "id": "unlisted-category/unlisted-category-doc", + "next": undefined, + "prev": { + "permalink": "/docs/unlisted-category/", + "title": "unlisted-category-index", + }, + }, + { + "id": "unlisted-category/unlisted-category-index", + "next": { + "permalink": "/docs/unlisted-category/unlisted-category-doc", + "title": "unlisted-category-doc", + }, + "prev": { + "permalink": "/docs/tryToEscapeSlug", + "title": "tryToEscapeSlug", + }, + }, + ], + "sidebars": { + "defaultSidebar": [ + { + "id": "customLastUpdate", + "type": "doc", + }, + { + "id": "doc with space", + "type": "doc", + }, + { + "id": "doc-draft", + "type": "doc", + }, + { + "id": "doc-unlisted", + "type": "doc", + }, + { + "collapsed": false, + "collapsible": true, + "items": [ + { + "id": "foo/bar", + "type": "doc", + }, + { + "id": "foo/baz", + "type": "doc", + }, + ], + "label": "foo", + "link": undefined, + "type": "category", + }, + { + "id": "headingAsTitle", + "type": "doc", + }, + { + "id": "hello", + "label": "Hello sidebar_label", + "type": "doc", + }, + { + "id": "ipsum", + "type": "doc", + }, + { + "id": "lastUpdateAuthorOnly", + "type": "doc", + }, + { + "id": "lastUpdateDateOnly", + "type": "doc", + }, + { + "id": "lorem", + "type": "doc", + }, + { + "id": "rootAbsoluteSlug", + "type": "doc", + }, + { + "id": "rootRelativeSlug", + "type": "doc", + }, + { + "id": "rootResolvedSlug", + "type": "doc", + }, + { + "id": "rootTryToEscapeSlug", + "type": "doc", + }, + { + "collapsed": false, + "collapsible": true, + "items": [ + { + "id": "slugs/absoluteSlug", + "type": "doc", + }, + { + "id": "slugs/relativeSlug", + "type": "doc", + }, + { + "id": "slugs/resolvedSlug", + "type": "doc", + }, + { + "id": "slugs/tryToEscapeSlug", + "type": "doc", + }, + ], + "label": "slugs", + "link": undefined, + "type": "category", + }, + { + "collapsed": false, + "collapsible": true, + "items": [ + { + "id": "unlisted-category/unlisted-category-doc", + "type": "doc", + }, + ], + "label": "unlisted-category-index", + "link": { + "id": "unlisted-category/unlisted-category-index", + "type": "doc", + }, + "type": "category", + }, + ], + }, +} +`; + +exports[`simple site custom pagination - production 1`] = ` +{ + "pagination": [ + { + "id": "customLastUpdate", + "next": { + "permalink": "/docs/doc with space", + "title": "Hoo hoo, if this path tricks you...", + }, + "prev": undefined, + }, + { + "id": "doc with space", + "next": { + "permalink": "/docs/doc-draft", + "title": "doc-draft", + }, + "prev": { + "permalink": "/docs/customLastUpdate", + "title": "Custom Last Update", + }, + }, + { + "id": "doc-draft", + "next": { + "permalink": "/docs/foo/bar", + "title": "Bar", + }, + "prev": { + "permalink": "/docs/doc with space", + "title": "Hoo hoo, if this path tricks you...", + }, + }, + { + "id": "doc-unlisted", + "next": undefined, + "prev": undefined, + }, + { + "id": "foo/bar", + "next": undefined, + "prev": undefined, + }, + { + "id": "foo/baz", + "next": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + "prev": { + "permalink": "/docs/foo/bar", + "title": "Bar", + }, + }, + { + "id": "headingAsTitle", + "next": { + "permalink": "/docs/", + "title": "Hello sidebar_label", + }, + "prev": { + "permalink": "/docs/foo/bazSlug.html", + "title": "baz pagination_label", + }, + }, + { + "id": "hello", + "next": { + "permalink": "/docs/ipsum", + "title": "ipsum", + }, + "prev": { + "permalink": "/docs/headingAsTitle", + "title": "My heading as title", + }, + }, + { + "id": "ipsum", + "next": undefined, "prev": { "permalink": "/docs/", "title": "Hello sidebar_label", @@ -205,6 +558,16 @@ exports[`simple site custom pagination 1`] = ` "title": "resolvedSlug", }, }, + { + "id": "unlisted-category/unlisted-category-doc", + "next": undefined, + "prev": undefined, + }, + { + "id": "unlisted-category/unlisted-category-index", + "next": undefined, + "prev": undefined, + }, ], "sidebars": { "defaultSidebar": [ @@ -307,6 +670,22 @@ exports[`simple site custom pagination 1`] = ` "link": undefined, "type": "category", }, + { + "collapsed": false, + "collapsible": true, + "items": [ + { + "id": "unlisted-category/unlisted-category-doc", + "type": "doc", + }, + ], + "label": "unlisted-category-index", + "link": { + "id": "unlisted-category/unlisted-category-index", + "type": "doc", + }, + "type": "category", + }, ], }, } diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 8c323af1a692..298ff590f688 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -73,8 +73,8 @@ exports[`simple website content 1`] = ` }, "permalink": "/docs/foo/bazSlug.html", "previous": { - "permalink": "/docs/foo/bar", - "title": "Bar", + "permalink": "/docs/doc-unlisted", + "title": "doc-unlisted", }, "sidebar": "docs", "sidebarPosition": undefined, @@ -192,6 +192,10 @@ exports[`simple website content 4`] = ` "id": "foo/bar", "type": "doc", }, + { + "id": "doc-unlisted", + "type": "doc", + }, { "id": "foo/baz", "type": "doc", @@ -292,7 +296,7 @@ exports[`simple website content 5`] = ` { "id": "doc-unlisted", "path": "/docs/doc-unlisted", - "sidebar": undefined, + "sidebar": "docs", }, { "id": "foo/bar", @@ -471,6 +475,15 @@ exports[`simple website content: data 1`] = ` "version": "current", "frontMatter": { "unlisted": true + }, + "sidebar": "docs", + "previous": { + "title": "Bar", + "permalink": "/docs/foo/bar" + }, + "next": { + "title": "baz pagination_label", + "permalink": "/docs/foo/bazSlug.html" } }", "site-docs-doc-with-space-md-e90.json": "{ @@ -548,8 +561,8 @@ exports[`simple website content: data 1`] = ` }, "sidebar": "docs", "previous": { - "title": "Bar", - "permalink": "/docs/foo/bar" + "title": "doc-unlisted", + "permalink": "/docs/doc-unlisted" }, "next": { "title": "Slugs", @@ -633,7 +646,12 @@ exports[`simple website content: data 1`] = ` "tags": [], "version": "current", "frontMatter": { - "custom_edit_url": null + "custom_edit_url": null, + "pagination_next": "doc-unlisted" + }, + "next": { + "title": "doc-unlisted", + "permalink": "/docs/doc-unlisted" } }", "site-docs-last-update-author-only-md-352.json": "{ @@ -969,6 +987,13 @@ exports[`simple website content: data 1`] = ` "docId": "foo/bar", "unlisted": false }, + { + "type": "link", + "label": "doc-unlisted", + "href": "/docs/doc-unlisted", + "docId": "doc-unlisted", + "unlisted": false + }, { "type": "link", "label": "baz", @@ -1076,7 +1101,8 @@ exports[`simple website content: data 1`] = ` "doc-unlisted": { "id": "doc-unlisted", "title": "doc-unlisted", - "description": "This is an unlisted document" + "description": "This is an unlisted document", + "sidebar": "docs" }, "foo/bar": { "id": "foo/bar", @@ -1198,7 +1224,7 @@ exports[`simple website content: global data 1`] = ` { "id": "doc-unlisted", "path": "/docs/doc-unlisted", - "sidebar": undefined, + "sidebar": "docs", }, { "id": "foo/bar", @@ -1417,6 +1443,7 @@ exports[`simple website content: route config 1`] = ` "content": "@site/docs/doc-unlisted.md", }, "path": "/docs/doc-unlisted", + "sidebar": "docs", }, { "component": "@theme/DocItem", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index 43d49170c1a1..d440846987bf 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -153,7 +153,7 @@ function createTestUtils({ versionMetadata, context, options, - env: 'production', + env, }), ), ); @@ -177,6 +177,7 @@ function createTestUtils({ docs: rawDocs, sidebarsUtils, sidebarFilePath: versionMetadata.sidebarFilePath as string, + env, }).map((doc) => ({prev: doc.previous, next: doc.next, id: doc.id})), sidebars, }; @@ -257,6 +258,8 @@ describe('simple site', () => { 'slugs/relativeSlug.md', 'slugs/resolvedSlug.md', 'slugs/tryToEscapeSlug.md', + 'unlisted-category/index.md', + 'unlisted-category/unlisted-category-doc.md', ].sort(), ); }); @@ -767,12 +770,20 @@ describe('simple site', () => { ); }); - it('custom pagination', async () => { - const {defaultTestUtils, options, versionsMetadata} = await loadSite(); + it('custom pagination - production', async () => { + const {createTestUtilsPartial, options, versionsMetadata} = + await loadSite(); + const testUtils = createTestUtilsPartial({env: 'production'}); const docs = await readVersionDocs(versionsMetadata[0]!, options); - await expect( - defaultTestUtils.generateNavigation(docs), - ).resolves.toMatchSnapshot(); + await expect(testUtils.generateNavigation(docs)).resolves.toMatchSnapshot(); + }); + + it('custom pagination - development', async () => { + const {createTestUtilsPartial, options, versionsMetadata} = + await loadSite(); + const testUtils = createTestUtilsPartial({env: 'development'}); + const docs = await readVersionDocs(versionsMetadata[0]!, options); + await expect(testUtils.generateNavigation(docs)).resolves.toMatchSnapshot(); }); it('bad pagination', async () => { diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index 3abbafc8027e..88638ad37455 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -333,10 +333,12 @@ export function addDocNavigation({ docs, sidebarsUtils, sidebarFilePath, + env, }: { docs: DocMetadataBase[]; sidebarsUtils: SidebarsUtils; sidebarFilePath: string; + env: DocEnv; }): LoadedVersion['docs'] { const docsById = createDocsByIdIndex(docs); const unlistedIds = getUnlistedIds(docs); @@ -367,7 +369,7 @@ export function addDocNavigation({ ); } // Gracefully handle explicitly providing an unlisted doc ID in production - if (process.env.NODE_ENV === 'production' && navDoc.unlisted) { + if (env === 'production' && navDoc.unlisted) { return undefined; } return toDocNavigationLink(navDoc); diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index c270084608f8..bff2640c9df7 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -75,6 +75,9 @@ export default async function pluginContentDocs( const aliasedSource = (source: string) => `~docs/${posixPath(path.relative(pluginDataDirRoot, source))}`; + // TODO env should be injected into all plugins + const env = process.env.NODE_ENV as DocEnv; + return { name: 'docusaurus-plugin-content-docs', @@ -143,7 +146,7 @@ export default async function pluginContentDocs( versionMetadata, context, options, - env: process.env.NODE_ENV as DocEnv, + env, }); } return Promise.all(docFiles.map(processVersionDoc)); @@ -182,6 +185,7 @@ export default async function pluginContentDocs( docs, sidebarsUtils, sidebarFilePath: versionMetadata.sidebarFilePath as string, + env, }), drafts, sidebars, From cddd5ec3ea86141f2e971bdb69c6133a094eb97e Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 12:42:59 +0100 Subject: [PATCH 45/50] remove useless extra env param --- .../__tests__/__snapshots__/cli.test.ts.snap | 11 ++ .../__snapshots__/index.test.ts.snap | 152 +++++++++++++++++- .../src/__tests__/docs.test.ts | 1 - .../src/docs.ts | 4 +- .../src/index.ts | 1 - 5 files changed, 157 insertions(+), 12 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap index 35a74e2404a5..1aa0e1d12474 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/cli.test.ts.snap @@ -16,6 +16,17 @@ exports[`docsVersion first time versioning 1`] = ` "label": "foo", "type": "category", }, + { + "items": [ + "unlisted-category/unlisted-category-doc", + ], + "label": "Unlisted category", + "link": { + "id": "unlisted-category/unlisted-category-index", + "type": "doc", + }, + "type": "category", + }, { "items": [ "rootAbsoluteSlug", diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap index 298ff590f688..0e1e7a59263f 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/__snapshots__/index.test.ts.snap @@ -41,7 +41,9 @@ Available document ids are: - slugs/absoluteSlug - slugs/relativeSlug - slugs/resolvedSlug -- slugs/tryToEscapeSlug" +- slugs/tryToEscapeSlug +- unlisted-category/unlisted-category-doc +- unlisted-category/unlisted-category-index" `; exports[`simple website content 1`] = ` @@ -68,8 +70,8 @@ exports[`simple website content 1`] = ` "lastUpdatedAt": undefined, "lastUpdatedBy": undefined, "next": { - "permalink": "/docs/category/slugs", - "title": "Slugs", + "permalink": "/docs/unlisted-category/", + "title": "unlisted-category-index", }, "permalink": "/docs/foo/bazSlug.html", "previous": { @@ -205,6 +207,22 @@ exports[`simple website content 4`] = ` "link": undefined, "type": "category", }, + { + "collapsed": true, + "collapsible": true, + "items": [ + { + "id": "unlisted-category/unlisted-category-doc", + "type": "doc", + }, + ], + "label": "Unlisted category", + "link": { + "id": "unlisted-category/unlisted-category-index", + "type": "doc", + }, + "type": "category", + }, { "collapsed": true, "collapsible": true, @@ -378,6 +396,16 @@ exports[`simple website content 5`] = ` "path": "/docs/tryToEscapeSlug", "sidebar": undefined, }, + { + "id": "unlisted-category/unlisted-category-doc", + "path": "/docs/unlisted-category/unlisted-category-doc", + "sidebar": "docs", + }, + { + "id": "unlisted-category/unlisted-category-index", + "path": "/docs/unlisted-category/", + "sidebar": "docs", + }, { "id": "/category/slugs", "path": "/docs/category/slugs", @@ -413,8 +441,8 @@ exports[`simple website content: data 1`] = ` "permalink": "/docs/category/slugs", "navigation": { "previous": { - "title": "baz pagination_label", - "permalink": "/docs/foo/bazSlug.html" + "title": "unlisted-category-doc", + "permalink": "/docs/unlisted-category/unlisted-category-doc" }, "next": { "title": "rootAbsoluteSlug", @@ -565,8 +593,8 @@ exports[`simple website content: data 1`] = ` "permalink": "/docs/doc-unlisted" }, "next": { - "title": "Slugs", - "permalink": "/docs/category/slugs" + "title": "unlisted-category-index", + "permalink": "/docs/unlisted-category/" } }", "site-docs-heading-as-title-md-c6d.json": "{ @@ -892,6 +920,60 @@ exports[`simple website content: data 1`] = ` "frontMatter": { "slug": "../../../../../../../../tryToEscapeSlug" } +}", + "site-docs-unlisted-category-index-md-efa.json": "{ + "unversionedId": "unlisted-category/unlisted-category-index", + "id": "unlisted-category/unlisted-category-index", + "title": "unlisted-category-index", + "description": "This is an unlisted category index", + "source": "@site/docs/unlisted-category/index.md", + "sourceDirName": "unlisted-category", + "slug": "/unlisted-category/", + "permalink": "/docs/unlisted-category/", + "draft": false, + "unlisted": false, + "tags": [], + "version": "current", + "frontMatter": { + "id": "unlisted-category-index", + "unlisted": true + }, + "sidebar": "docs", + "previous": { + "title": "baz pagination_label", + "permalink": "/docs/foo/bazSlug.html" + }, + "next": { + "title": "unlisted-category-doc", + "permalink": "/docs/unlisted-category/unlisted-category-doc" + } +}", + "site-docs-unlisted-category-unlisted-category-doc-md-bd6.json": "{ + "unversionedId": "unlisted-category/unlisted-category-doc", + "id": "unlisted-category/unlisted-category-doc", + "title": "unlisted-category-doc", + "description": "This is an unlisted category doc", + "source": "@site/docs/unlisted-category/unlisted-category-doc.md", + "sourceDirName": "unlisted-category", + "slug": "/unlisted-category/unlisted-category-doc", + "permalink": "/docs/unlisted-category/unlisted-category-doc", + "draft": false, + "unlisted": false, + "tags": [], + "version": "current", + "frontMatter": { + "id": "unlisted-category-doc", + "unlisted": true + }, + "sidebar": "docs", + "previous": { + "title": "unlisted-category-index", + "permalink": "/docs/unlisted-category/" + }, + "next": { + "title": "Slugs", + "permalink": "/docs/category/slugs" + } }", "tag-docs-tags-tag-1-b3f.json": "{ "label": "tag 1", @@ -1005,6 +1087,22 @@ exports[`simple website content: data 1`] = ` "collapsed": true, "collapsible": true }, + { + "type": "category", + "label": "Unlisted category", + "items": [ + { + "type": "link", + "label": "unlisted-category-doc", + "href": "/docs/unlisted-category/unlisted-category-doc", + "docId": "unlisted-category/unlisted-category-doc", + "unlisted": false + } + ], + "collapsed": true, + "collapsible": true, + "href": "/docs/unlisted-category/" + }, { "type": "category", "label": "Slugs", @@ -1191,6 +1289,18 @@ exports[`simple website content: data 1`] = ` "id": "slugs/tryToEscapeSlug", "title": "tryToEscapeSlug", "description": "Lorem" + }, + "unlisted-category/unlisted-category-doc": { + "id": "unlisted-category/unlisted-category-doc", + "title": "unlisted-category-doc", + "description": "This is an unlisted category doc", + "sidebar": "docs" + }, + "unlisted-category/unlisted-category-index": { + "id": "unlisted-category/unlisted-category-index", + "title": "unlisted-category-index", + "description": "This is an unlisted category index", + "sidebar": "docs" } } }", @@ -1306,6 +1416,16 @@ exports[`simple website content: global data 1`] = ` "path": "/docs/tryToEscapeSlug", "sidebar": undefined, }, + { + "id": "unlisted-category/unlisted-category-doc", + "path": "/docs/unlisted-category/unlisted-category-doc", + "sidebar": "docs", + }, + { + "id": "unlisted-category/unlisted-category-index", + "path": "/docs/unlisted-category/", + "sidebar": "docs", + }, { "id": "/category/slugs", "path": "/docs/category/slugs", @@ -1564,6 +1684,24 @@ exports[`simple website content: route config 1`] = ` }, "path": "/docs/tryToEscapeSlug", }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/unlisted-category/index.md", + }, + "path": "/docs/unlisted-category/", + "sidebar": "docs", + }, + { + "component": "@theme/DocItem", + "exact": true, + "modules": { + "content": "@site/docs/unlisted-category/unlisted-category-doc.md", + }, + "path": "/docs/unlisted-category/unlisted-category-doc", + "sidebar": "docs", + }, ], }, ], diff --git a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts index d440846987bf..831b655a2721 100644 --- a/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts +++ b/packages/docusaurus-plugin-content-docs/src/__tests__/docs.test.ts @@ -177,7 +177,6 @@ function createTestUtils({ docs: rawDocs, sidebarsUtils, sidebarFilePath: versionMetadata.sidebarFilePath as string, - env, }).map((doc) => ({prev: doc.previous, next: doc.next, id: doc.id})), sidebars, }; diff --git a/packages/docusaurus-plugin-content-docs/src/docs.ts b/packages/docusaurus-plugin-content-docs/src/docs.ts index 88638ad37455..da620f2876c4 100644 --- a/packages/docusaurus-plugin-content-docs/src/docs.ts +++ b/packages/docusaurus-plugin-content-docs/src/docs.ts @@ -333,12 +333,10 @@ export function addDocNavigation({ docs, sidebarsUtils, sidebarFilePath, - env, }: { docs: DocMetadataBase[]; sidebarsUtils: SidebarsUtils; sidebarFilePath: string; - env: DocEnv; }): LoadedVersion['docs'] { const docsById = createDocsByIdIndex(docs); const unlistedIds = getUnlistedIds(docs); @@ -369,7 +367,7 @@ export function addDocNavigation({ ); } // Gracefully handle explicitly providing an unlisted doc ID in production - if (env === 'production' && navDoc.unlisted) { + if (navDoc.unlisted) { return undefined; } return toDocNavigationLink(navDoc); diff --git a/packages/docusaurus-plugin-content-docs/src/index.ts b/packages/docusaurus-plugin-content-docs/src/index.ts index bff2640c9df7..cb34f5249a82 100644 --- a/packages/docusaurus-plugin-content-docs/src/index.ts +++ b/packages/docusaurus-plugin-content-docs/src/index.ts @@ -185,7 +185,6 @@ export default async function pluginContentDocs( docs, sidebarsUtils, sidebarFilePath: versionMetadata.sidebarFilePath as string, - env, }), drafts, sidebars, From 638dbe3b4318889e1c31d4aa8fc7f3586d7b776b Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 12:56:10 +0100 Subject: [PATCH 46/50] extract useVisibleSidebarItems --- .../src/theme/DocSidebarItems/index.tsx | 18 +++--------------- .../docusaurus-theme-common/src/internal.ts | 1 + .../src/utils/docsUtils.tsx | 10 ++++++++++ 3 files changed, 14 insertions(+), 15 deletions(-) diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx index 1d0435b1c5f3..cf59b208d337 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItems/index.tsx @@ -5,29 +5,17 @@ * LICENSE file in the root directory of this source tree. */ -import React, {memo, useMemo} from 'react'; +import React, {memo} from 'react'; import { DocSidebarItemsExpandedStateProvider, - isVisibleSidebarItem, + useVisibleSidebarItems, } from '@docusaurus/theme-common/internal'; import DocSidebarItem from '@theme/DocSidebarItem'; import type {Props} from '@theme/DocSidebarItems'; -// TODO "technical" component: move it to theme-common later - -function useVisibleItems( - items: Props['items'], - activePath: string, -): Props['items'] { - return useMemo( - () => items.filter((item) => isVisibleSidebarItem(item, activePath)), - [items, activePath], - ); -} - function DocSidebarItems({items, ...props}: Props): JSX.Element { - const visibleItems = useVisibleItems(items, props.activePath); + const visibleItems = useVisibleSidebarItems(items, props.activePath); return ( {visibleItems.map((item, index) => ( diff --git a/packages/docusaurus-theme-common/src/internal.ts b/packages/docusaurus-theme-common/src/internal.ts index 4a4b78cb914c..7e3c4a73b4f7 100644 --- a/packages/docusaurus-theme-common/src/internal.ts +++ b/packages/docusaurus-theme-common/src/internal.ts @@ -70,6 +70,7 @@ export { findFirstCategoryLink, isActiveSidebarItem, isVisibleSidebarItem, + useVisibleSidebarItems, useSidebarBreadcrumbs, useDocsVersionCandidates, useLayoutDoc, diff --git a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx index f4d5e56bc0fd..0a628b257ab8 100644 --- a/packages/docusaurus-theme-common/src/utils/docsUtils.tsx +++ b/packages/docusaurus-theme-common/src/utils/docsUtils.tsx @@ -170,6 +170,16 @@ export function isVisibleSidebarItem( } } +export function useVisibleSidebarItems( + items: readonly PropSidebarItem[], + activePath: string, +): PropSidebarItem[] { + return useMemo( + () => items.filter((item) => isVisibleSidebarItem(item, activePath)), + [items, activePath], + ); +} + function getSidebarBreadcrumbs(param: { sidebarItems: PropSidebar; pathname: string; From 54f1dc7b569940a7b23fd5690280e03ee32ae6ec Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 12:58:15 +0100 Subject: [PATCH 47/50] category doc link should be removed if linking to an unlisted doc --- packages/docusaurus-plugin-content-docs/src/props.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index 9b7ef2007a79..a4dd9fcaef68 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -83,8 +83,13 @@ Available document ids are: link: SidebarItemCategoryLink | undefined, ): string | undefined { switch (link?.type) { - case 'doc': - return getDocById(link.id).permalink; + case 'doc': { + const doc = getDocById(link.id); + if (doc.unlisted) { + return undefined; + } + return doc.permalink; + } case 'generated-index': return link.permalink; default: From 5a2726d3e7cce02f72ee3673bf2317b455c9ac56 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 13:01:41 +0100 Subject: [PATCH 48/50] add limitation comment --- packages/docusaurus-plugin-content-docs/src/props.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index a4dd9fcaef68..534137ae85a4 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -86,6 +86,8 @@ Available document ids are: case 'doc': { const doc = getDocById(link.id); if (doc.unlisted) { + // TODO, not ideal solution because an unlisted category link + // can't be displayed/highlighted in sidebar when browsed return undefined; } return doc.permalink; From 6840195005d77d9374bf59f1350192f98f64da1e Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 13:22:27 +0100 Subject: [PATCH 49/50] fix draft dogfood typo --- website/_dogfooding/_blog tests/2022-08-25-post-draft.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/_dogfooding/_blog tests/2022-08-25-post-draft.md b/website/_dogfooding/_blog tests/2022-08-25-post-draft.md index a8e7b075b52f..da77f657aa8a 100644 --- a/website/_dogfooding/_blog tests/2022-08-25-post-draft.md +++ b/website/_dogfooding/_blog tests/2022-08-25-post-draft.md @@ -1,6 +1,6 @@ --- title: Draft blog post -unlisted: true +draft: true tags: [blog, visibility, draft] slug: /draft-post --- From 3c81af887a11ac892e87ca7c1c938ffb688b5640 Mon Sep 17 00:00:00 2001 From: sebastienlorber Date: Thu, 3 Nov 2022 13:53:03 +0100 Subject: [PATCH 50/50] breadcrumb of unlisted category index shouldn't be clickable --- .../src/props.ts | 22 +++++++++++-------- .../src/sidebars/types.ts | 6 +++++ .../src/theme/DocBreadcrumbs/index.tsx | 8 +++++-- .../theme/DocSidebarItem/Category/index.tsx | 2 +- 4 files changed, 26 insertions(+), 12 deletions(-) diff --git a/packages/docusaurus-plugin-content-docs/src/props.ts b/packages/docusaurus-plugin-content-docs/src/props.ts index 534137ae85a4..c53329564a49 100644 --- a/packages/docusaurus-plugin-content-docs/src/props.ts +++ b/packages/docusaurus-plugin-content-docs/src/props.ts @@ -83,15 +83,8 @@ Available document ids are: link: SidebarItemCategoryLink | undefined, ): string | undefined { switch (link?.type) { - case 'doc': { - const doc = getDocById(link.id); - if (doc.unlisted) { - // TODO, not ideal solution because an unlisted category link - // can't be displayed/highlighted in sidebar when browsed - return undefined; - } - return doc.permalink; - } + case 'doc': + return getDocById(link.id).permalink; case 'generated-index': return link.permalink; default: @@ -99,6 +92,15 @@ Available document ids are: } } + function getCategoryLinkUnlisted( + link: SidebarItemCategoryLink | undefined, + ): boolean { + if (link?.type === 'doc') { + return getDocById(link.id).unlisted; + } + return false; + } + function getCategoryLinkCustomProps( link: SidebarItemCategoryLink | undefined, ) { @@ -113,12 +115,14 @@ Available document ids are: function convertCategory(item: SidebarItemCategory): PropSidebarItemCategory { const {link, ...rest} = item; const href = getCategoryLinkHref(link); + const linkUnlisted = getCategoryLinkUnlisted(link); const customProps = item.customProps ?? getCategoryLinkCustomProps(link); return { ...rest, items: item.items.map(normalizeItem), ...(href && {href}), + ...(linkUnlisted && {linkUnlisted}), ...(customProps && {customProps}), }; } diff --git a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts index 16eabbcf91f2..d6d7f07a7587 100644 --- a/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts +++ b/packages/docusaurus-plugin-content-docs/src/sidebars/types.ts @@ -183,6 +183,12 @@ export type PropSidebarItemCategory = Expand< SidebarItemCategoryBase & { items: PropSidebarItem[]; href?: string; + + // Weird name => it would have been more convenient to have link.unlisted + // Note it is the category link that is unlisted, not the category itself + // We want to prevent users from clicking on an unlisted category link + // We can't use "href: undefined" otherwise sidebar item is not highlighted + linkUnlisted?: boolean; } >; diff --git a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx index 1e296be0bded..9d011bc6bc90 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocBreadcrumbs/index.tsx @@ -123,13 +123,17 @@ export default function DocBreadcrumbs(): JSX.Element | null { {homePageRoute && } {breadcrumbs.map((item, idx) => { const isLast = idx === breadcrumbs.length - 1; + const href = + item.type === 'category' && item.linkUnlisted + ? undefined + : item.href; return ( - + addMicrodata={!!href}> + {item.label} diff --git a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx index 700c4a52bef3..996720e70941 100644 --- a/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx +++ b/packages/docusaurus-theme-classic/src/theme/DocSidebarItem/Category/index.tsx @@ -59,7 +59,7 @@ function useCategoryHrefWithSSRFallback( ): string | undefined { const isBrowser = useIsBrowser(); return useMemo(() => { - if (item.href) { + if (item.href && !item.linkUnlisted) { return item.href; } // In these cases, it's not necessary to render a fallback