@docusaurus/theme-classic 3.3.2 → 3.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.d.ts CHANGED
@@ -7,7 +7,6 @@
7
7
  /// <reference path="../src/theme-classic.d.ts" />
8
8
  import type { LoadContext, Plugin } from '@docusaurus/types';
9
9
  import type { PluginOptions } from '@docusaurus/theme-classic';
10
- export declare const AnnouncementBarDismissStorageKey = "docusaurus.announcement.dismiss";
11
10
  export default function themeClassic(context: LoadContext, options: PluginOptions): Plugin<undefined>;
12
11
  export { default as getSwizzleConfig } from './getSwizzleConfig';
13
12
  export { validateThemeConfig, validateOptions } from './options';
package/lib/index.js CHANGED
@@ -6,102 +6,21 @@
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
- exports.validateOptions = exports.validateThemeConfig = exports.getSwizzleConfig = exports.AnnouncementBarDismissStorageKey = void 0;
9
+ exports.validateOptions = exports.validateThemeConfig = exports.getSwizzleConfig = void 0;
10
10
  const tslib_1 = require("tslib");
11
11
  const path_1 = tslib_1.__importDefault(require("path"));
12
12
  const module_1 = require("module");
13
13
  const rtlcss_1 = tslib_1.__importDefault(require("rtlcss"));
14
14
  const theme_translations_1 = require("@docusaurus/theme-translations");
15
15
  const translations_1 = require("./translations");
16
+ const inlineScripts_1 = require("./inlineScripts");
16
17
  const requireFromDocusaurusCore = (0, module_1.createRequire)(require.resolve('@docusaurus/core/package.json'));
17
18
  const ContextReplacementPlugin = requireFromDocusaurusCore('webpack/lib/ContextReplacementPlugin');
18
- // Need to be inlined to prevent dark mode FOUC
19
- // Make sure the key is the same as the one in `/theme/hooks/useTheme.js`
20
- const ThemeStorageKey = 'theme';
21
- // Support for ?docusaurus-theme=dark
22
- const ThemeQueryStringKey = 'docusaurus-theme';
23
- // Support for ?docusaurus-data-mode=embed&docusaurus-data-myAttr=42
24
- const DataQueryStringPrefixKey = 'docusaurus-data-';
25
- const noFlashColorMode = ({ defaultMode, respectPrefersColorScheme, }) =>
26
- /* language=js */
27
- `(function() {
28
- var defaultMode = '${defaultMode}';
29
- var respectPrefersColorScheme = ${respectPrefersColorScheme};
30
-
31
- function setDataThemeAttribute(theme) {
32
- document.documentElement.setAttribute('data-theme', theme);
33
- }
34
-
35
- function getQueryStringTheme() {
36
- try {
37
- return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
38
- } catch(e) {}
39
- }
40
-
41
- function getStoredTheme() {
42
- try {
43
- return localStorage.getItem('${ThemeStorageKey}');
44
- } catch (err) {}
45
- }
46
-
47
- var initialTheme = getQueryStringTheme() || getStoredTheme();
48
- if (initialTheme !== null) {
49
- setDataThemeAttribute(initialTheme);
50
- } else {
51
- if (
52
- respectPrefersColorScheme &&
53
- window.matchMedia('(prefers-color-scheme: dark)').matches
54
- ) {
55
- setDataThemeAttribute('dark');
56
- } else if (
57
- respectPrefersColorScheme &&
58
- window.matchMedia('(prefers-color-scheme: light)').matches
59
- ) {
60
- setDataThemeAttribute('light');
61
- } else {
62
- setDataThemeAttribute(defaultMode === 'dark' ? 'dark' : 'light');
63
- }
64
- }
65
- })();`;
66
- /* language=js */
67
- const DataAttributeQueryStringInlineJavaScript = `
68
- (function() {
69
- try {
70
- const entries = new URLSearchParams(window.location.search).entries();
71
- for (var [searchKey, value] of entries) {
72
- if (searchKey.startsWith('${DataQueryStringPrefixKey}')) {
73
- var key = searchKey.replace('${DataQueryStringPrefixKey}',"data-")
74
- document.documentElement.setAttribute(key, value);
75
- }
76
- }
77
- } catch(e) {}
78
- })();
79
- `;
80
- // Duplicated constant. Unfortunately we can't import it from theme-common, as
81
- // we need to support older nodejs versions without ESM support
82
- // TODO: import from theme-common once we only support Node.js with ESM support
83
- // + move all those announcementBar stuff there too
84
- exports.AnnouncementBarDismissStorageKey = 'docusaurus.announcement.dismiss';
85
- const AnnouncementBarDismissDataAttribute = 'data-announcement-bar-initially-dismissed';
86
- // We always render the announcement bar html on the server, to prevent layout
87
- // shifts on React hydration. The theme can use CSS + the data attribute to hide
88
- // the announcement bar asap (before React hydration)
89
- /* language=js */
90
- const AnnouncementBarInlineJavaScript = `
91
- (function() {
92
- function isDismissed() {
93
- try {
94
- return localStorage.getItem('${exports.AnnouncementBarDismissStorageKey}') === 'true';
95
- } catch (err) {}
96
- return false;
97
- }
98
- document.documentElement.setAttribute('${AnnouncementBarDismissDataAttribute}', isDismissed());
99
- })();`;
100
19
  function getInfimaCSSFile(direction) {
101
20
  return `infima/dist/css/default/default${direction === 'rtl' ? '-rtl' : ''}.css`;
102
21
  }
103
22
  function themeClassic(context, options) {
104
- const { i18n: { currentLocale, localeConfigs }, } = context;
23
+ const { i18n: { currentLocale, localeConfigs }, siteStorage, } = context;
105
24
  const themeConfig = context.siteConfig.themeConfig;
106
25
  const { announcementBar, colorMode, prism: { additionalLanguages }, } = themeConfig;
107
26
  const { customCss } = options;
@@ -171,9 +90,9 @@ function themeClassic(context, options) {
171
90
  {
172
91
  tagName: 'script',
173
92
  innerHTML: `
174
- ${noFlashColorMode(colorMode)}
175
- ${DataAttributeQueryStringInlineJavaScript}
176
- ${announcementBar ? AnnouncementBarInlineJavaScript : ''}
93
+ ${(0, inlineScripts_1.getThemeInlineScript)({ colorMode, siteStorage })}
94
+ ${inlineScripts_1.DataAttributeQueryStringInlineJavaScript}
95
+ ${announcementBar ? (0, inlineScripts_1.getAnnouncementBarInlineScript)({ siteStorage }) : ''}
177
96
  `,
178
97
  },
179
98
  ],
@@ -0,0 +1,16 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+ import type { SiteStorage } from '@docusaurus/types';
8
+ import type { ThemeConfig } from '@docusaurus/theme-common';
9
+ export declare function getThemeInlineScript({ colorMode: { defaultMode, respectPrefersColorScheme }, siteStorage, }: {
10
+ colorMode: ThemeConfig['colorMode'];
11
+ siteStorage: SiteStorage;
12
+ }): string;
13
+ export declare const DataAttributeQueryStringInlineJavaScript = "\n(function() {\n try {\n const entries = new URLSearchParams(window.location.search).entries();\n for (var [searchKey, value] of entries) {\n if (searchKey.startsWith('docusaurus-data-')) {\n var key = searchKey.replace('docusaurus-data-',\"data-\")\n document.documentElement.setAttribute(key, value);\n }\n }\n } catch(e) {}\n})();\n";
14
+ export declare function getAnnouncementBarInlineScript({ siteStorage, }: {
15
+ siteStorage: SiteStorage;
16
+ }): string;
@@ -0,0 +1,98 @@
1
+ "use strict";
2
+ /**
3
+ * Copyright (c) Facebook, Inc. and its affiliates.
4
+ *
5
+ * This source code is licensed under the MIT license found in the
6
+ * LICENSE file in the root directory of this source tree.
7
+ */
8
+ Object.defineProperty(exports, "__esModule", { value: true });
9
+ exports.getAnnouncementBarInlineScript = exports.DataAttributeQueryStringInlineJavaScript = exports.getThemeInlineScript = void 0;
10
+ // Support for ?docusaurus-theme=dark
11
+ const ThemeQueryStringKey = 'docusaurus-theme';
12
+ // Support for ?docusaurus-data-mode=embed&docusaurus-data-myAttr=42
13
+ const DataQueryStringPrefixKey = 'docusaurus-data-';
14
+ function getThemeInlineScript({ colorMode: { defaultMode, respectPrefersColorScheme }, siteStorage, }) {
15
+ // Need to be inlined to prevent dark mode FOUC
16
+ // Make sure the key is the same as the one in the color mode React context
17
+ // Currently defined in: `docusaurus-theme-common/src/contexts/colorMode.tsx`
18
+ const themeStorageKey = `theme${siteStorage.namespace}`;
19
+ /* language=js */
20
+ return `(function() {
21
+ var defaultMode = '${defaultMode}';
22
+ var respectPrefersColorScheme = ${respectPrefersColorScheme};
23
+
24
+ function setDataThemeAttribute(theme) {
25
+ document.documentElement.setAttribute('data-theme', theme);
26
+ }
27
+
28
+ function getQueryStringTheme() {
29
+ try {
30
+ return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
31
+ } catch (e) {
32
+ }
33
+ }
34
+
35
+ function getStoredTheme() {
36
+ try {
37
+ return window['${siteStorage.type}'].getItem('${themeStorageKey}');
38
+ } catch (err) {
39
+ }
40
+ }
41
+
42
+ var initialTheme = getQueryStringTheme() || getStoredTheme();
43
+ if (initialTheme !== null) {
44
+ setDataThemeAttribute(initialTheme);
45
+ } else {
46
+ if (
47
+ respectPrefersColorScheme &&
48
+ window.matchMedia('(prefers-color-scheme: dark)').matches
49
+ ) {
50
+ setDataThemeAttribute('dark');
51
+ } else if (
52
+ respectPrefersColorScheme &&
53
+ window.matchMedia('(prefers-color-scheme: light)').matches
54
+ ) {
55
+ setDataThemeAttribute('light');
56
+ } else {
57
+ setDataThemeAttribute(defaultMode === 'dark' ? 'dark' : 'light');
58
+ }
59
+ }
60
+ })();`;
61
+ }
62
+ exports.getThemeInlineScript = getThemeInlineScript;
63
+ /* language=js */
64
+ exports.DataAttributeQueryStringInlineJavaScript = `
65
+ (function() {
66
+ try {
67
+ const entries = new URLSearchParams(window.location.search).entries();
68
+ for (var [searchKey, value] of entries) {
69
+ if (searchKey.startsWith('${DataQueryStringPrefixKey}')) {
70
+ var key = searchKey.replace('${DataQueryStringPrefixKey}',"data-")
71
+ document.documentElement.setAttribute(key, value);
72
+ }
73
+ }
74
+ } catch(e) {}
75
+ })();
76
+ `;
77
+ // We always render the announcement bar html on the server, to prevent layout
78
+ // shifts on React hydration. The theme can use CSS + the data attribute to hide
79
+ // the announcement bar asap (before React hydration)
80
+ function getAnnouncementBarInlineScript({ siteStorage, }) {
81
+ // Duplicated constant. Unfortunately we can't import it from theme-common, as
82
+ // we need to support older nodejs versions without ESM support
83
+ // TODO: import from theme-common once we support Node.js with ESM support
84
+ // + move all those announcementBar stuff there too
85
+ const AnnouncementBarDismissStorageKey = `docusaurus.announcement.dismiss${siteStorage.namespace}`;
86
+ const AnnouncementBarDismissDataAttribute = 'data-announcement-bar-initially-dismissed';
87
+ /* language=js */
88
+ return `(function() {
89
+ function isDismissed() {
90
+ try {
91
+ return localStorage.getItem('${AnnouncementBarDismissStorageKey}') === 'true';
92
+ } catch (err) {}
93
+ return false;
94
+ }
95
+ document.documentElement.setAttribute('${AnnouncementBarDismissDataAttribute}', isDismissed());
96
+ })();`;
97
+ }
98
+ exports.getAnnouncementBarInlineScript = getAnnouncementBarInlineScript;
@@ -52,7 +52,7 @@ function BlogTagsPostsPageMetadata({tag}) {
52
52
  const title = useBlogTagsPostsPageTitle(tag);
53
53
  return (
54
54
  <>
55
- <PageMetadata title={title} />
55
+ <PageMetadata title={title} description={tag.description} />
56
56
  <SearchMetadata tag="blog_tags_posts" />
57
57
  </>
58
58
  );
@@ -64,6 +64,7 @@ function BlogTagsPostsPageContent({tag, items, sidebar, listMetadata}) {
64
64
  {tag.unlisted && <Unlisted />}
65
65
  <header className="margin-bottom--xl">
66
66
  <Heading as="h1">{title}</Heading>
67
+ {tag.description && <p>{tag.description}</p>}
67
68
  <Link href={tag.allTagsPath}>
68
69
  <Translate
69
70
  id="theme.tags.tagsPageLink"
@@ -23,7 +23,7 @@ function useCategoryItemsPlural() {
23
23
  count,
24
24
  translate(
25
25
  {
26
- message: '{count} items',
26
+ message: '1 item|{count} items',
27
27
  id: 'theme.docs.DocCard.categoryDescription.plurals',
28
28
  description:
29
29
  'The default description for a category card in the generated index about how many items this category includes',
@@ -55,10 +55,10 @@ function DocItem({doc}) {
55
55
  </article>
56
56
  );
57
57
  }
58
- function DocTagDocListPageMetadata({title}) {
58
+ function DocTagDocListPageMetadata({title, tag}) {
59
59
  return (
60
60
  <>
61
- <PageMetadata title={title} />
61
+ <PageMetadata title={title} description={tag.description} />
62
62
  <SearchMetadata tag="doc_tag_doc_list" />
63
63
  </>
64
64
  );
@@ -73,6 +73,7 @@ function DocTagDocListPageContent({tag, title}) {
73
73
  {tag.unlisted && <Unlisted />}
74
74
  <header className="margin-bottom--xl">
75
75
  <Heading as="h1">{title}</Heading>
76
+ {tag.description && <p>{tag.description}</p>}
76
77
  <Link href={tag.allTagsPath}>
77
78
  <Translate
78
79
  id="theme.tags.tagsPageLink"
@@ -7,4 +7,4 @@
7
7
  /// <reference path="../../../src/theme-classic.d.ts" />
8
8
  /// <reference types="react" />
9
9
  import type { Props } from '@theme/Tag';
10
- export default function Tag({ permalink, label, count }: Props): JSX.Element;
10
+ export default function Tag({ permalink, label, count, description, }: Props): JSX.Element;
@@ -8,10 +8,11 @@ import React from 'react';
8
8
  import clsx from 'clsx';
9
9
  import Link from '@docusaurus/Link';
10
10
  import styles from './styles.module.css';
11
- export default function Tag({permalink, label, count}) {
11
+ export default function Tag({permalink, label, count, description}) {
12
12
  return (
13
13
  <Link
14
14
  href={permalink}
15
+ title={description}
15
16
  className={clsx(
16
17
  styles.tag,
17
18
  count ? styles.tagWithCount : styles.tagRegular,
@@ -20,9 +20,9 @@ export default function TagsListInline({tags}) {
20
20
  </Translate>
21
21
  </b>
22
22
  <ul className={clsx(styles.tags, 'padding--none', 'margin-left--sm')}>
23
- {tags.map(({label, permalink: tagPermalink}) => (
24
- <li key={tagPermalink} className={styles.tag}>
25
- <Tag label={label} permalink={tagPermalink} />
23
+ {tags.map((tag) => (
24
+ <li key={tag.permalink} className={styles.tag}>
25
+ <Tag {...tag} />
26
26
  </li>
27
27
  ))}
28
28
  </ul>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@docusaurus/theme-classic",
3
- "version": "3.3.2",
3
+ "version": "3.4.0",
4
4
  "description": "Classic theme for Docusaurus",
5
5
  "main": "lib/index.js",
6
6
  "types": "src/theme-classic.d.ts",
@@ -20,18 +20,18 @@
20
20
  "copy:watch": "node ../../admin/scripts/copyUntypedFiles.js --watch"
21
21
  },
22
22
  "dependencies": {
23
- "@docusaurus/core": "3.3.2",
24
- "@docusaurus/mdx-loader": "3.3.2",
25
- "@docusaurus/module-type-aliases": "3.3.2",
26
- "@docusaurus/plugin-content-blog": "3.3.2",
27
- "@docusaurus/plugin-content-docs": "3.3.2",
28
- "@docusaurus/plugin-content-pages": "3.3.2",
29
- "@docusaurus/theme-common": "3.3.2",
30
- "@docusaurus/theme-translations": "3.3.2",
31
- "@docusaurus/types": "3.3.2",
32
- "@docusaurus/utils": "3.3.2",
33
- "@docusaurus/utils-common": "3.3.2",
34
- "@docusaurus/utils-validation": "3.3.2",
23
+ "@docusaurus/core": "3.4.0",
24
+ "@docusaurus/mdx-loader": "3.4.0",
25
+ "@docusaurus/module-type-aliases": "3.4.0",
26
+ "@docusaurus/plugin-content-blog": "3.4.0",
27
+ "@docusaurus/plugin-content-docs": "3.4.0",
28
+ "@docusaurus/plugin-content-pages": "3.4.0",
29
+ "@docusaurus/theme-common": "3.4.0",
30
+ "@docusaurus/theme-translations": "3.4.0",
31
+ "@docusaurus/types": "3.4.0",
32
+ "@docusaurus/utils": "3.4.0",
33
+ "@docusaurus/utils-common": "3.4.0",
34
+ "@docusaurus/utils-validation": "3.4.0",
35
35
  "@mdx-js/react": "^3.0.0",
36
36
  "clsx": "^2.0.0",
37
37
  "copy-text-to-clipboard": "^3.2.0",
@@ -61,5 +61,5 @@
61
61
  "engines": {
62
62
  "node": ">=18.0"
63
63
  },
64
- "gitHead": "bc638d674bfbde1e254ef306697f47e764b5e107"
64
+ "gitHead": "49e9a2143274a8dd795659b417b470bc42abbd6e"
65
65
  }
package/src/index.ts CHANGED
@@ -10,6 +10,11 @@ import {createRequire} from 'module';
10
10
  import rtlcss from 'rtlcss';
11
11
  import {readDefaultCodeTranslationMessages} from '@docusaurus/theme-translations';
12
12
  import {getTranslationFiles, translateThemeConfig} from './translations';
13
+ import {
14
+ getThemeInlineScript,
15
+ getAnnouncementBarInlineScript,
16
+ DataAttributeQueryStringInlineJavaScript,
17
+ } from './inlineScripts';
13
18
  import type {LoadContext, Plugin} from '@docusaurus/types';
14
19
  import type {ThemeConfig} from '@docusaurus/theme-common';
15
20
  import type {Plugin as PostCssPlugin} from 'postcss';
@@ -23,97 +28,6 @@ const ContextReplacementPlugin = requireFromDocusaurusCore(
23
28
  'webpack/lib/ContextReplacementPlugin',
24
29
  ) as typeof webpack.ContextReplacementPlugin;
25
30
 
26
- // Need to be inlined to prevent dark mode FOUC
27
- // Make sure the key is the same as the one in `/theme/hooks/useTheme.js`
28
- const ThemeStorageKey = 'theme';
29
- // Support for ?docusaurus-theme=dark
30
- const ThemeQueryStringKey = 'docusaurus-theme';
31
- // Support for ?docusaurus-data-mode=embed&docusaurus-data-myAttr=42
32
- const DataQueryStringPrefixKey = 'docusaurus-data-';
33
-
34
- const noFlashColorMode = ({
35
- defaultMode,
36
- respectPrefersColorScheme,
37
- }: ThemeConfig['colorMode']) =>
38
- /* language=js */
39
- `(function() {
40
- var defaultMode = '${defaultMode}';
41
- var respectPrefersColorScheme = ${respectPrefersColorScheme};
42
-
43
- function setDataThemeAttribute(theme) {
44
- document.documentElement.setAttribute('data-theme', theme);
45
- }
46
-
47
- function getQueryStringTheme() {
48
- try {
49
- return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
50
- } catch(e) {}
51
- }
52
-
53
- function getStoredTheme() {
54
- try {
55
- return localStorage.getItem('${ThemeStorageKey}');
56
- } catch (err) {}
57
- }
58
-
59
- var initialTheme = getQueryStringTheme() || getStoredTheme();
60
- if (initialTheme !== null) {
61
- setDataThemeAttribute(initialTheme);
62
- } else {
63
- if (
64
- respectPrefersColorScheme &&
65
- window.matchMedia('(prefers-color-scheme: dark)').matches
66
- ) {
67
- setDataThemeAttribute('dark');
68
- } else if (
69
- respectPrefersColorScheme &&
70
- window.matchMedia('(prefers-color-scheme: light)').matches
71
- ) {
72
- setDataThemeAttribute('light');
73
- } else {
74
- setDataThemeAttribute(defaultMode === 'dark' ? 'dark' : 'light');
75
- }
76
- }
77
- })();`;
78
-
79
- /* language=js */
80
- const DataAttributeQueryStringInlineJavaScript = `
81
- (function() {
82
- try {
83
- const entries = new URLSearchParams(window.location.search).entries();
84
- for (var [searchKey, value] of entries) {
85
- if (searchKey.startsWith('${DataQueryStringPrefixKey}')) {
86
- var key = searchKey.replace('${DataQueryStringPrefixKey}',"data-")
87
- document.documentElement.setAttribute(key, value);
88
- }
89
- }
90
- } catch(e) {}
91
- })();
92
- `;
93
-
94
- // Duplicated constant. Unfortunately we can't import it from theme-common, as
95
- // we need to support older nodejs versions without ESM support
96
- // TODO: import from theme-common once we only support Node.js with ESM support
97
- // + move all those announcementBar stuff there too
98
- export const AnnouncementBarDismissStorageKey =
99
- 'docusaurus.announcement.dismiss';
100
- const AnnouncementBarDismissDataAttribute =
101
- 'data-announcement-bar-initially-dismissed';
102
- // We always render the announcement bar html on the server, to prevent layout
103
- // shifts on React hydration. The theme can use CSS + the data attribute to hide
104
- // the announcement bar asap (before React hydration)
105
- /* language=js */
106
- const AnnouncementBarInlineJavaScript = `
107
- (function() {
108
- function isDismissed() {
109
- try {
110
- return localStorage.getItem('${AnnouncementBarDismissStorageKey}') === 'true';
111
- } catch (err) {}
112
- return false;
113
- }
114
- document.documentElement.setAttribute('${AnnouncementBarDismissDataAttribute}', isDismissed());
115
- })();`;
116
-
117
31
  function getInfimaCSSFile(direction: string) {
118
32
  return `infima/dist/css/default/default${
119
33
  direction === 'rtl' ? '-rtl' : ''
@@ -126,6 +40,7 @@ export default function themeClassic(
126
40
  ): Plugin<undefined> {
127
41
  const {
128
42
  i18n: {currentLocale, localeConfigs},
43
+ siteStorage,
129
44
  } = context;
130
45
  const themeConfig = context.siteConfig.themeConfig as ThemeConfig;
131
46
  const {
@@ -218,9 +133,9 @@ export default function themeClassic(
218
133
  {
219
134
  tagName: 'script',
220
135
  innerHTML: `
221
- ${noFlashColorMode(colorMode)}
136
+ ${getThemeInlineScript({colorMode, siteStorage})}
222
137
  ${DataAttributeQueryStringInlineJavaScript}
223
- ${announcementBar ? AnnouncementBarInlineJavaScript : ''}
138
+ ${announcementBar ? getAnnouncementBarInlineScript({siteStorage}) : ''}
224
139
  `,
225
140
  },
226
141
  ],
@@ -0,0 +1,114 @@
1
+ /**
2
+ * Copyright (c) Facebook, Inc. and its affiliates.
3
+ *
4
+ * This source code is licensed under the MIT license found in the
5
+ * LICENSE file in the root directory of this source tree.
6
+ */
7
+
8
+ import type {SiteStorage} from '@docusaurus/types';
9
+ import type {ThemeConfig} from '@docusaurus/theme-common';
10
+
11
+ // Support for ?docusaurus-theme=dark
12
+ const ThemeQueryStringKey = 'docusaurus-theme';
13
+
14
+ // Support for ?docusaurus-data-mode=embed&docusaurus-data-myAttr=42
15
+ const DataQueryStringPrefixKey = 'docusaurus-data-';
16
+
17
+ export function getThemeInlineScript({
18
+ colorMode: {defaultMode, respectPrefersColorScheme},
19
+ siteStorage,
20
+ }: {
21
+ colorMode: ThemeConfig['colorMode'];
22
+ siteStorage: SiteStorage;
23
+ }): string {
24
+ // Need to be inlined to prevent dark mode FOUC
25
+ // Make sure the key is the same as the one in the color mode React context
26
+ // Currently defined in: `docusaurus-theme-common/src/contexts/colorMode.tsx`
27
+ const themeStorageKey = `theme${siteStorage.namespace}`;
28
+
29
+ /* language=js */
30
+ return `(function() {
31
+ var defaultMode = '${defaultMode}';
32
+ var respectPrefersColorScheme = ${respectPrefersColorScheme};
33
+
34
+ function setDataThemeAttribute(theme) {
35
+ document.documentElement.setAttribute('data-theme', theme);
36
+ }
37
+
38
+ function getQueryStringTheme() {
39
+ try {
40
+ return new URLSearchParams(window.location.search).get('${ThemeQueryStringKey}')
41
+ } catch (e) {
42
+ }
43
+ }
44
+
45
+ function getStoredTheme() {
46
+ try {
47
+ return window['${siteStorage.type}'].getItem('${themeStorageKey}');
48
+ } catch (err) {
49
+ }
50
+ }
51
+
52
+ var initialTheme = getQueryStringTheme() || getStoredTheme();
53
+ if (initialTheme !== null) {
54
+ setDataThemeAttribute(initialTheme);
55
+ } else {
56
+ if (
57
+ respectPrefersColorScheme &&
58
+ window.matchMedia('(prefers-color-scheme: dark)').matches
59
+ ) {
60
+ setDataThemeAttribute('dark');
61
+ } else if (
62
+ respectPrefersColorScheme &&
63
+ window.matchMedia('(prefers-color-scheme: light)').matches
64
+ ) {
65
+ setDataThemeAttribute('light');
66
+ } else {
67
+ setDataThemeAttribute(defaultMode === 'dark' ? 'dark' : 'light');
68
+ }
69
+ }
70
+ })();`;
71
+ }
72
+
73
+ /* language=js */
74
+ export const DataAttributeQueryStringInlineJavaScript = `
75
+ (function() {
76
+ try {
77
+ const entries = new URLSearchParams(window.location.search).entries();
78
+ for (var [searchKey, value] of entries) {
79
+ if (searchKey.startsWith('${DataQueryStringPrefixKey}')) {
80
+ var key = searchKey.replace('${DataQueryStringPrefixKey}',"data-")
81
+ document.documentElement.setAttribute(key, value);
82
+ }
83
+ }
84
+ } catch(e) {}
85
+ })();
86
+ `;
87
+
88
+ // We always render the announcement bar html on the server, to prevent layout
89
+ // shifts on React hydration. The theme can use CSS + the data attribute to hide
90
+ // the announcement bar asap (before React hydration)
91
+ export function getAnnouncementBarInlineScript({
92
+ siteStorage,
93
+ }: {
94
+ siteStorage: SiteStorage;
95
+ }): string {
96
+ // Duplicated constant. Unfortunately we can't import it from theme-common, as
97
+ // we need to support older nodejs versions without ESM support
98
+ // TODO: import from theme-common once we support Node.js with ESM support
99
+ // + move all those announcementBar stuff there too
100
+ const AnnouncementBarDismissStorageKey = `docusaurus.announcement.dismiss${siteStorage.namespace}`;
101
+ const AnnouncementBarDismissDataAttribute =
102
+ 'data-announcement-bar-initially-dismissed';
103
+
104
+ /* language=js */
105
+ return `(function() {
106
+ function isDismissed() {
107
+ try {
108
+ return localStorage.getItem('${AnnouncementBarDismissStorageKey}') === 'true';
109
+ } catch (err) {}
110
+ return false;
111
+ }
112
+ document.documentElement.setAttribute('${AnnouncementBarDismissDataAttribute}', isDismissed());
113
+ })();`;
114
+ }
@@ -57,7 +57,7 @@ function BlogTagsPostsPageMetadata({tag}: Props): JSX.Element {
57
57
  const title = useBlogTagsPostsPageTitle(tag);
58
58
  return (
59
59
  <>
60
- <PageMetadata title={title} />
60
+ <PageMetadata title={title} description={tag.description} />
61
61
  <SearchMetadata tag="blog_tags_posts" />
62
62
  </>
63
63
  );
@@ -75,6 +75,7 @@ function BlogTagsPostsPageContent({
75
75
  {tag.unlisted && <Unlisted />}
76
76
  <header className="margin-bottom--xl">
77
77
  <Heading as="h1">{title}</Heading>
78
+ {tag.description && <p>{tag.description}</p>}
78
79
  <Link href={tag.allTagsPath}>
79
80
  <Translate
80
81
  id="theme.tags.tagsPageLink"
@@ -32,7 +32,7 @@ function useCategoryItemsPlural() {
32
32
  count,
33
33
  translate(
34
34
  {
35
- message: '{count} items',
35
+ message: '1 item|{count} items',
36
36
  id: 'theme.docs.DocCard.categoryDescription.plurals',
37
37
  description:
38
38
  'The default description for a category card in the generated index about how many items this category includes',
@@ -63,10 +63,11 @@ function DocItem({doc}: {doc: Props['tag']['items'][number]}): JSX.Element {
63
63
 
64
64
  function DocTagDocListPageMetadata({
65
65
  title,
66
+ tag,
66
67
  }: Props & {title: string}): JSX.Element {
67
68
  return (
68
69
  <>
69
- <PageMetadata title={title} />
70
+ <PageMetadata title={title} description={tag.description} />
70
71
  <SearchMetadata tag="doc_tag_doc_list" />
71
72
  </>
72
73
  );
@@ -85,6 +86,7 @@ function DocTagDocListPageContent({
85
86
  {tag.unlisted && <Unlisted />}
86
87
  <header className="margin-bottom--xl">
87
88
  <Heading as="h1">{title}</Heading>
89
+ {tag.description && <p>{tag.description}</p>}
88
90
  <Link href={tag.allTagsPath}>
89
91
  <Translate
90
92
  id="theme.tags.tagsPageLink"
@@ -12,10 +12,16 @@ import type {Props} from '@theme/Tag';
12
12
 
13
13
  import styles from './styles.module.css';
14
14
 
15
- export default function Tag({permalink, label, count}: Props): JSX.Element {
15
+ export default function Tag({
16
+ permalink,
17
+ label,
18
+ count,
19
+ description,
20
+ }: Props): JSX.Element {
16
21
  return (
17
22
  <Link
18
23
  href={permalink}
24
+ title={description}
19
25
  className={clsx(
20
26
  styles.tag,
21
27
  count ? styles.tagWithCount : styles.tagRegular,
@@ -24,9 +24,9 @@ export default function TagsListInline({tags}: Props): JSX.Element {
24
24
  </Translate>
25
25
  </b>
26
26
  <ul className={clsx(styles.tags, 'padding--none', 'margin-left--sm')}>
27
- {tags.map(({label, permalink: tagPermalink}) => (
28
- <li key={tagPermalink} className={styles.tag}>
29
- <Tag label={label} permalink={tagPermalink} />
27
+ {tags.map((tag) => (
28
+ <li key={tag.permalink} className={styles.tag}>
29
+ <Tag {...tag} />
30
30
  </li>
31
31
  ))}
32
32
  </ul>