feat(docs,blog,pages): add support for "unlisted" front matter - hide md content in production (#8004)

Co-authored-by: sebastienlorber <lorber.sebastien@gmail.com>
This commit is contained in:
Jody Heavener 2022-11-03 06:31:41 -07:00 committed by GitHub
parent 7a023a2c41
commit 683ba3d2a0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
131 changed files with 2449 additions and 303 deletions

View file

@ -86,4 +86,10 @@ export {
SkipToContentLink,
} from './utils/skipToContentUtils';
export {
UnlistedBannerTitle,
UnlistedBannerMessage,
UnlistedMetadata,
} from './utils/unlistedUtils';
export {ErrorBoundaryTryAgainButton} from './utils/errorBoundaryUtils';

View file

@ -69,6 +69,8 @@ export {
findSidebarCategory,
findFirstCategoryLink,
isActiveSidebarItem,
isVisibleSidebarItem,
useVisibleSidebarItems,
useSidebarBreadcrumbs,
useDocsVersionCandidates,
useLayoutDoc,
@ -109,6 +111,8 @@ export {
type TOCHighlightConfig,
} from './hooks/useTOCHighlight';
export {useVisibleBlogSidebarItems} from './utils/blogUtils';
export {useHideableNavbar} from './hooks/useHideableNavbar';
export {
useKeyboardNavigation,

View file

@ -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: {

View file

@ -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) =>

View file

@ -0,0 +1,32 @@
/**
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
import {useMemo} from 'react';
import {useLocation} from '@docusaurus/router';
import {isSamePath} from './routesUtils';
import type {BlogSidebarItem} from '@docusaurus/plugin-content-blog';
function isVisible(item: BlogSidebarItem, pathname: string): boolean {
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(
items: BlogSidebarItem[],
): BlogSidebarItem[] {
const {pathname} = useLocation();
return useMemo(
() => items.filter((item) => isVisible(item, pathname)),
[items, pathname],
);
}

View file

@ -152,6 +152,34 @@ 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;
}
}
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;

View file

@ -0,0 +1,39 @@
/**
* 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 (
<Translate
id="theme.unlistedContent.title"
description="The unlisted content banner title">
Unlisted page
</Translate>
);
}
export function UnlistedBannerMessage(): JSX.Element {
return (
<Translate
id="theme.unlistedContent.message"
description="The unlisted content banner message">
This page is unlisted. Search engines will not index it, and only users
having a direct link can access it.
</Translate>
);
}
export function UnlistedMetadata(): JSX.Element {
return (
<Head>
<meta name="robots" content="noindex, nofollow" />
</Head>
);
}