diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx
index 301d357c16..9ddc7fea17 100644
--- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DefaultNavbarItem.tsx
@@ -82,12 +82,18 @@ function NavItemDesktop({items, position, className, ...props}) {
e.preventDefault()}
+ onClick={props.to ? undefined : (e) => e.preventDefault()}
onKeyDown={(e) => {
- if (e.key === 'Enter') {
+ function toggle() {
((e.target as HTMLElement)
.parentNode as HTMLElement).classList.toggle('dropdown--show');
}
+ if (e.key === 'Enter' && !props.to) {
+ toggle();
+ }
+ if (e.key === 'Tab') {
+ toggle();
+ }
}}>
{props.label}
diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
index cd3e924bea..275d6cfe9c 100644
--- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionDropdownNavbarItem.tsx
@@ -13,14 +13,16 @@ import {
useActiveDocContext,
} from '@theme/hooks/useDocs';
-const versionLabel = (version) =>
- version.name === 'next' ? 'Next/Master' : version.name;
+const versionLabel = (version, nextVersionLabel) =>
+ version.name === 'next' ? nextVersionLabel : version.name;
const getVersionMainDoc = (version) =>
version.docs.find((doc) => doc.id === version.mainDocId);
export default function DocsVersionDropdownNavbarItem({
+ mobile,
docsPluginId,
+ nextVersionLabel,
...props
}) {
const activeDocContext = useActiveDocContext(docsPluginId);
@@ -35,7 +37,7 @@ export default function DocsVersionDropdownNavbarItem({
getVersionMainDoc(version);
return {
isNavLink: true,
- label: versionLabel(version),
+ label: versionLabel(version, nextVersionLabel),
to: versionDoc.path,
isActive: () => version === activeDocContext?.activeVersion,
};
@@ -43,11 +45,20 @@ export default function DocsVersionDropdownNavbarItem({
const dropdownVersion = activeDocContext.activeVersion ?? latestVersion;
+ // Mobile is handled a bit differently
+ const dropdownLabel = mobile
+ ? 'Versions'
+ : versionLabel(dropdownVersion, nextVersionLabel);
+ const dropdownTo = mobile
+ ? undefined
+ : getVersionMainDoc(dropdownVersion).path;
+
return (
);
diff --git a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
index 39a71b63de..11bd3e037f 100644
--- a/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
+++ b/packages/docusaurus-theme-classic/src/theme/NavbarItem/DocsVersionNavbarItem.tsx
@@ -12,16 +12,20 @@ import {useActiveVersion, useLatestVersion} from '@theme/hooks/useDocs';
const getVersionMainDoc = (version) =>
version.docs.find((doc) => doc.id === version.mainDocId);
+const versionLabel = (version, nextVersionLabel) =>
+ version.name === 'next' ? nextVersionLabel : version.name;
+
export default function DocsVersionNavbarItem({
label: staticLabel,
to: staticTo,
docsPluginId,
+ nextVersionLabel,
...props
}) {
const activeVersion = useActiveVersion(docsPluginId);
const latestVersion = useLatestVersion(docsPluginId);
const version = activeVersion ?? latestVersion;
- const label = staticLabel ?? version.name;
+ const label = staticLabel ?? versionLabel(version, nextVersionLabel);
const path = staticTo ?? getVersionMainDoc(version).path;
return ;
}
diff --git a/packages/docusaurus-theme-classic/src/themeConfigSchema.js b/packages/docusaurus-theme-classic/src/themeConfigSchema.js
index 76a62ac274..ec1b90ce89 100644
--- a/packages/docusaurus-theme-classic/src/themeConfigSchema.js
+++ b/packages/docusaurus-theme-classic/src/themeConfigSchema.js
@@ -13,7 +13,6 @@ const DefaultNavbarItemSchema = Joi.object({
items: Joi.array().optional().items(Joi.link('...')),
to: Joi.string(),
href: Joi.string().uri(),
- prependBaseUrlToHref: Joi.bool().default(true),
label: Joi.string(),
position: NavbarItemPosition,
activeBasePath: Joi.string(),
@@ -28,12 +27,14 @@ const DocsVersionNavbarItemSchema = Joi.object({
label: Joi.string(),
to: Joi.string(),
docsPluginId: Joi.string(),
+ nextVersionLabel: Joi.string().default('Next'),
});
const DocsVersionDropdownNavbarItemSchema = Joi.object({
type: Joi.string().equal('docsVersionDropdown').required(),
position: NavbarItemPosition,
docsPluginId: Joi.string(),
+ nextVersionLabel: Joi.string().default('Next'),
});
// Can this be made easier? :/
diff --git a/packages/docusaurus/src/client/exports/Link.tsx b/packages/docusaurus/src/client/exports/Link.tsx
index b8f3a6e592..a523eb4c88 100644
--- a/packages/docusaurus/src/client/exports/Link.tsx
+++ b/packages/docusaurus/src/client/exports/Link.tsx
@@ -22,7 +22,7 @@ interface Props {
readonly isNavLink?: boolean;
readonly to?: string;
readonly activeClassName?: string;
- readonly href: string;
+ readonly href?: string;
readonly children?: ReactNode;
}
@@ -89,14 +89,16 @@ function Link({isNavLink, activeClassName, ...props}: Props): JSX.Element {
const isAnchorLink = targetLink?.startsWith('#') ?? false;
const isRegularHtmlLink = !targetLink || !isInternal || isAnchorLink;
- if (isInternal && !isAnchorLink) {
+ if (targetLink && isInternal && !isAnchorLink) {
+ if (targetLink && targetLink.startsWith('/http')) {
+ console.log('collectLink', props);
+ }
linksCollector.collectLink(targetLink);
}
return isRegularHtmlLink ? (
// eslint-disable-next-line jsx-a11y/anchor-has-content
{
+ test('should be true for empty links', () => {
+ expect(isInternalUrl('')).toBeTruthy();
+ });
+
test('should be true for root relative links', () => {
expect(isInternalUrl('/foo/bar')).toBeTruthy();
});
@@ -35,4 +39,12 @@ describe('isInternalUrl', () => {
test('should be false for mailto links', () => {
expect(isInternalUrl('mailto:someone@example.com')).toBeFalsy();
});
+
+ test('should be false for undefined links', () => {
+ expect(isInternalUrl(undefined)).toBeFalsy();
+ });
+
+ test('should be true for root relative links', () => {
+ expect(isInternalUrl('//reactjs.org')).toBeFalsy();
+ });
});
diff --git a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.ts b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.ts
index 96b08f718e..797da6a655 100644
--- a/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.ts
+++ b/packages/docusaurus/src/client/exports/__tests__/useBaseUrl.ts
@@ -12,6 +12,8 @@ jest.mock('../useDocusaurusContext', () => jest.fn(), {virtual: true});
const mockedContext = useDocusaurusContext;
+const forcePrepend = {forcePrependBaseUrl: true};
+
describe('useBaseUrl', () => {
test('empty base URL', () => {
mockedContext.mockImplementation(() => ({
@@ -31,8 +33,9 @@ describe('useBaseUrl', () => {
expect(useBaseUrl('/hello/byebye/')).toEqual('/hello/byebye/');
expect(useBaseUrl('https://github.com')).toEqual('https://github.com');
expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
- expect(useBaseUrl('https://site.com', {forcePrependBaseUrl: true})).toEqual(
- '/https://site.com',
+ expect(useBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org');
+ expect(useBaseUrl('https://site.com', forcePrepend)).toEqual(
+ 'https://site.com',
);
expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/hello/byebye',
@@ -57,8 +60,9 @@ describe('useBaseUrl', () => {
expect(useBaseUrl('/hello/byebye/')).toEqual('/docusaurus/hello/byebye/');
expect(useBaseUrl('https://github.com')).toEqual('https://github.com');
expect(useBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
- expect(useBaseUrl('https://site.com', {forcePrependBaseUrl: true})).toEqual(
- '/docusaurus/https://site.com',
+ expect(useBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org');
+ expect(useBaseUrl('https://site.com', forcePrepend)).toEqual(
+ 'https://site.com',
);
expect(useBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/docusaurus/hello/byebye',
@@ -86,9 +90,10 @@ describe('useBaseUrlUtils().withBaseUrl()', () => {
expect(withBaseUrl('/hello/byebye/')).toEqual('/hello/byebye/');
expect(withBaseUrl('https://github.com')).toEqual('https://github.com');
expect(withBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
- expect(
- withBaseUrl('https://site.com', {forcePrependBaseUrl: true}),
- ).toEqual('/https://site.com');
+ expect(withBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org');
+ expect(withBaseUrl('https://site.com', forcePrepend)).toEqual(
+ 'https://site.com',
+ );
expect(withBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/hello/byebye',
);
@@ -113,9 +118,10 @@ describe('useBaseUrlUtils().withBaseUrl()', () => {
expect(withBaseUrl('/hello/byebye/')).toEqual('/docusaurus/hello/byebye/');
expect(withBaseUrl('https://github.com')).toEqual('https://github.com');
expect(withBaseUrl('//reactjs.org')).toEqual('//reactjs.org');
- expect(
- withBaseUrl('https://site.com', {forcePrependBaseUrl: true}),
- ).toEqual('/docusaurus/https://site.com');
+ expect(withBaseUrl('//reactjs.org', forcePrepend)).toEqual('//reactjs.org');
+ expect(withBaseUrl('https://site.com', forcePrepend)).toEqual(
+ 'https://site.com',
+ );
expect(withBaseUrl('/hello/byebye', {absolute: true})).toEqual(
'https://v2.docusaurus.io/docusaurus/hello/byebye',
);
diff --git a/packages/docusaurus/src/client/exports/isInternalUrl.ts b/packages/docusaurus/src/client/exports/isInternalUrl.ts
index 134f0336a3..d4755e658a 100644
--- a/packages/docusaurus/src/client/exports/isInternalUrl.ts
+++ b/packages/docusaurus/src/client/exports/isInternalUrl.ts
@@ -5,6 +5,10 @@
* LICENSE file in the root directory of this source tree.
*/
-export default function isInternalUrl(url: string): boolean {
- return /^(\w*:|\/\/)/.test(url) === false;
+export function hasProtocol(url: string) {
+ return /^(\w*:|\/\/)/.test(url) === true;
+}
+
+export default function isInternalUrl(url?: string): boolean {
+ return typeof url !== 'undefined' && !hasProtocol(url);
}
diff --git a/packages/docusaurus/src/client/exports/useBaseUrl.ts b/packages/docusaurus/src/client/exports/useBaseUrl.ts
index 622bca7090..116fa2ab9e 100644
--- a/packages/docusaurus/src/client/exports/useBaseUrl.ts
+++ b/packages/docusaurus/src/client/exports/useBaseUrl.ts
@@ -9,6 +9,8 @@ import useDocusaurusContext from './useDocusaurusContext';
import isInternalUrl from './isInternalUrl';
type BaseUrlOptions = Partial<{
+ // note: if the url has a protocol, we never prepend it
+ // (it never makes any sense to do so)
forcePrependBaseUrl: boolean;
absolute: boolean;
}>;
@@ -23,21 +25,21 @@ function addBaseUrl(
return url;
}
- if (forcePrependBaseUrl) {
- return baseUrl + url;
- }
-
if (!isInternalUrl(url)) {
return url;
}
+ if (forcePrependBaseUrl) {
+ return baseUrl + url;
+ }
+
const basePath = baseUrl + url.replace(/^\//, '');
return absolute ? siteUrl + basePath : basePath;
}
export type BaseUrlUtils = {
- withBaseUrl: (url: string, options: BaseUrlOptions) => string;
+ withBaseUrl: (url: string, options?: BaseUrlOptions) => string;
};
export function useBaseUrlUtils(): BaseUrlUtils {
@@ -53,7 +55,7 @@ export function useBaseUrlUtils(): BaseUrlUtils {
export default function useBaseUrl(
url: string,
- options: BaseUrlOptions,
+ options: BaseUrlOptions = {},
): string {
const {withBaseUrl} = useBaseUrlUtils();
return withBaseUrl(url, options);
diff --git a/packages/docusaurus/src/server/index.ts b/packages/docusaurus/src/server/index.ts
index 72b3bfd64b..f00056a3b6 100644
--- a/packages/docusaurus/src/server/index.ts
+++ b/packages/docusaurus/src/server/index.ts
@@ -71,11 +71,6 @@ export async function load(
// Context.
const context: LoadContext = loadContext(siteDir, customOutDir);
const {generatedFilesDir, siteConfig, outDir, baseUrl} = context;
- const genSiteConfig = generate(
- generatedFilesDir,
- CONFIG_FILE_NAME,
- `export default ${JSON.stringify(siteConfig, null, 2)};`,
- );
// Plugins.
const pluginConfigs: PluginConfig[] = loadPluginConfigs(context);
@@ -84,6 +79,14 @@ export async function load(
context,
});
+ // Site config must be generated after plugins
+ // We want the generated config to have been normalized by the plugins!
+ const genSiteConfig = generate(
+ generatedFilesDir,
+ CONFIG_FILE_NAME,
+ `export default ${JSON.stringify(siteConfig, null, 2)};`,
+ );
+
// Themes.
const fallbackTheme = path.resolve(__dirname, '../client/theme-fallback');
const pluginThemes: string[] = plugins
diff --git a/website/docusaurus.config.js b/website/docusaurus.config.js
index 2bf3315688..7974d9e139 100644
--- a/website/docusaurus.config.js
+++ b/website/docusaurus.config.js
@@ -178,6 +178,7 @@ module.exports = {
{
type: 'docsVersionDropdown',
position: 'left',
+ nextVersionLabel: '2.0.0-next',
},
{to: 'blog', label: 'Blog', position: 'left'},
{to: 'showcase', label: 'Showcase', position: 'left'},
@@ -188,8 +189,8 @@ module.exports = {
activeBaseRegex: `docs/next/(support|team|resources)`,
},
{
- type: 'docsVersion',
to: 'versions',
+ label: 'All versions',
position: 'right',
},
{
diff --git a/website/src/css/custom.css b/website/src/css/custom.css
index 92272191ee..fc157bc6a2 100644
--- a/website/src/css/custom.css
+++ b/website/src/css/custom.css
@@ -48,3 +48,11 @@ html[data-theme='dark'] .header-github-link:before {
background: url("data:image/svg+xml,%3Csvg viewBox='0 0 24 24' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath fill='white' d='M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61C4.422 18.07 3.633 17.7 3.633 17.7c-1.087-.744.084-.729.084-.729 1.205.084 1.838 1.236 1.838 1.236 1.07 1.835 2.809 1.305 3.495.998.108-.776.417-1.305.76-1.605-2.665-.3-5.466-1.332-5.466-5.93 0-1.31.465-2.38 1.235-3.22-.135-.303-.54-1.523.105-3.176 0 0 1.005-.322 3.3 1.23.96-.267 1.98-.399 3-.405 1.02.006 2.04.138 3 .405 2.28-1.552 3.285-1.23 3.285-1.23.645 1.653.24 2.873.12 3.176.765.84 1.23 1.91 1.23 3.22 0 4.61-2.805 5.625-5.475 5.92.42.36.81 1.096.81 2.22 0 1.606-.015 2.896-.015 3.286 0 .315.21.69.825.57C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12'/%3E%3C/svg%3E")
no-repeat;
}
+
+/*
+TODO temporary, should be handled by infima next release
+https://github.com/facebookincubator/infima/commit/7820399af53c182b1879aa6d7fceb4d296f78ce0
+ */
+.navbar__item.dropdown .navbar__link[href] {
+ pointer-events: all;
+}