Skip to content

Commit

Permalink
feat(v2): ability to add/override theme html metadatas (#3406)
Browse files Browse the repository at this point in the history
* ability to add/override theme html metadatas
see #3024

* refactor/fix validateThemeConfig tests
  • Loading branch information
slorber authored Sep 4, 2020
1 parent f49d8ba commit 2185294
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 29 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,15 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

import merge from 'lodash/merge';

const {
validateThemeConfig,
DEFAULT_COLOR_MODE_CONFIG,
} = require('../validateThemeConfig');
const {ThemeConfigSchema, DEFAULT_CONFIG} = require('../validateThemeConfig');

const mergeDefault = (config) => merge({}, DEFAULT_COLOR_MODE_CONFIG, config);
const {normalizeThemeConfig} = require('@docusaurus/utils-validation');

function testValidateThemeConfig(themeConfig) {
function validate(schema, cfg) {
const {value, error} = schema.validate(cfg, {
convert: false,
});
if (error) {
throw error;
}
return value;
}

return validateThemeConfig({themeConfig, validate});
return normalizeThemeConfig(ThemeConfigSchema, themeConfig);
}

describe('themeConfig', () => {
Expand Down Expand Up @@ -88,7 +76,7 @@ describe('themeConfig', () => {
},
};
expect(testValidateThemeConfig(userConfig)).toEqual({
colorMode: DEFAULT_COLOR_MODE_CONFIG,
...DEFAULT_CONFIG,
...userConfig,
});
});
Expand All @@ -104,7 +92,7 @@ describe('themeConfig', () => {
},
};
expect(testValidateThemeConfig(altTagConfig)).toEqual({
colorMode: DEFAULT_COLOR_MODE_CONFIG,
...DEFAULT_CONFIG,
...altTagConfig,
});
});
Expand All @@ -116,20 +104,24 @@ describe('themeConfig', () => {
},
};
expect(testValidateThemeConfig(prismConfig)).toEqual({
colorMode: DEFAULT_COLOR_MODE_CONFIG,
...DEFAULT_CONFIG,
...prismConfig,
});
});

describe('color mode config', () => {
const withDefaultValues = (colorMode) =>
merge({}, DEFAULT_CONFIG.colorMode, colorMode);

test('minimal config', () => {
const colorMode = {
switchConfig: {
darkIcon: '🌙',
},
};
expect(testValidateThemeConfig({colorMode})).toEqual({
colorMode: mergeDefault(colorMode),
...DEFAULT_CONFIG,
colorMode: withDefaultValues(colorMode),
});
});

Expand All @@ -151,21 +143,27 @@ describe('themeConfig', () => {
},
};
expect(testValidateThemeConfig({colorMode})).toEqual({
colorMode: mergeDefault(colorMode),
...DEFAULT_CONFIG,
colorMode: withDefaultValues(colorMode),
});
});

test('undefined config', () => {
const colorMode = undefined;
expect(testValidateThemeConfig({colorMode})).toEqual({
colorMode: mergeDefault(colorMode),
...DEFAULT_CONFIG,
colorMode: withDefaultValues(colorMode),
});
});

test('empty config', () => {
const colorMode = {};
expect(testValidateThemeConfig({colorMode})).toEqual({
colorMode: mergeDefault(colorMode),
...DEFAULT_CONFIG,
colorMode: {
...DEFAULT_CONFIG.colorMode,
...colorMode,
},
});
});

Expand All @@ -174,7 +172,8 @@ describe('themeConfig', () => {
switchConfig: {},
};
expect(testValidateThemeConfig({colorMode})).toEqual({
colorMode: mergeDefault(colorMode),
...DEFAULT_CONFIG,
colorMode: withDefaultValues(colorMode),
});
});
});
Expand Down
19 changes: 15 additions & 4 deletions packages/docusaurus-theme-classic/src/theme/Layout/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ function Providers({children}) {
}

function Layout(props: Props): JSX.Element {
const {siteConfig = {}} = useDocusaurusContext();
const {siteConfig} = useDocusaurusContext();
const {
favicon,
title: siteTitle,
themeConfig: {image: defaultImage},
themeConfig: {image: defaultImage, metadatas},
url: siteUrl,
} = siteConfig;
const {
Expand All @@ -48,13 +48,11 @@ function Layout(props: Props): JSX.Element {
const metaImage = image || defaultImage;
const metaImageUrl = useBaseUrl(metaImage, {absolute: true});
const faviconUrl = useBaseUrl(favicon);

return (
<Providers>
<Head>
{/* TODO: Do not assume that it is in english language */}
<html lang="en" />

{metaTitle && <title>{metaTitle}</title>}
{metaTitle && <meta property="og:title" content={metaTitle} />}
{favicon && <link rel="shortcut icon" href={faviconUrl} />}
Expand All @@ -74,6 +72,19 @@ function Layout(props: Props): JSX.Element {
{permalink && <link rel="canonical" href={siteUrl + permalink} />}
<meta name="twitter:card" content="summary_large_image" />
</Head>

<Head
// it's important to have an additional <Head> element here,
// as it allows react-helmet to override values set in previous <Head>
// ie we can override default metadatas such as "twitter:card"
// In same Head, the same meta would appear twice instead of overriding
// See react-helmet doc
>
{metadatas.map((metadata, i) => (
<meta key={`metadata_${i}`} {...metadata} />
))}
</Head>

<AnnouncementBar />
<Navbar />
<div className="main-wrapper">{children}</div>
Expand Down
20 changes: 19 additions & 1 deletion packages/docusaurus-theme-classic/src/validateThemeConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,12 @@ const DEFAULT_COLOR_MODE_CONFIG = {
lightIconStyle: {},
},
};
exports.DEFAULT_COLOR_MODE_CONFIG = DEFAULT_COLOR_MODE_CONFIG;

const DEFAULT_CONFIG = {
colorMode: DEFAULT_COLOR_MODE_CONFIG,
metadatas: [],
};
exports.DEFAULT_CONFIG = DEFAULT_CONFIG;

const NavbarItemPosition = Joi.string().equal('left', 'right').default('left');

Expand Down Expand Up @@ -137,6 +142,15 @@ const ColorModeSchema = Joi.object({
}).default(DEFAULT_COLOR_MODE_CONFIG.switchConfig),
}).default(DEFAULT_COLOR_MODE_CONFIG);

// schema can probably be improved
const HtmlMetadataSchema = Joi.object({
id: Joi.string(),
name: Joi.string(),
property: Joi.string(),
content: Joi.string(),
itemprop: Joi.string(),
}).unknown();

const FooterLinkItemSchema = Joi.object({
to: Joi.string(),
href: URISchema,
Expand Down Expand Up @@ -164,6 +178,9 @@ const ThemeConfigSchema = Joi.object({
}),
colorMode: ColorModeSchema,
image: Joi.string(),
metadatas: Joi.array()
.items(HtmlMetadataSchema)
.default(DEFAULT_CONFIG.metadatas),
announcementBar: Joi.object({
id: Joi.string().default('announcement-bar'),
content: Joi.string(),
Expand Down Expand Up @@ -216,6 +233,7 @@ const ThemeConfigSchema = Joi.object({
additionalLanguages: Joi.array().items(Joi.string()),
}).unknown(),
});
exports.ThemeConfigSchema = ThemeConfigSchema;

exports.validateThemeConfig = ({validate, themeConfig}) => {
return validate(ThemeConfigSchema, themeConfig);
Expand Down
14 changes: 14 additions & 0 deletions website/docs/theme-classic.md
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,20 @@ module.exports = {
};
```

### Metadatas

You can configure additional html metadatas (and override existing ones).

```js {4-6} title="docusaurus.config.js"
module.exports = {
// ...
themeConfig: {
metadatas: [{name: 'twitter:card', content: 'summary'}],
// ...
},
};
```

### Announcement bar

Sometimes you want to announce something in your website. Just for such a case, you can add an announcement bar. This is a non-fixed and optionally dismissable panel above the navbar.
Expand Down
1 change: 1 addition & 0 deletions website/docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ module.exports = {
darkTheme: require('prism-react-renderer/themes/dracula'),
},
image: 'img/docusaurus-soc.png',
// metadatas: [{name: 'twitter:card', content: 'summary'}],
gtag: {
trackingID: 'UA-141789564-1',
},
Expand Down

0 comments on commit 2185294

Please sign in to comment.