mirror of
https://github.com/facebook/docusaurus.git
synced 2025-07-23 11:38:48 +02:00
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:
parent
7a023a2c41
commit
683ba3d2a0
131 changed files with 2449 additions and 303 deletions
|
@ -86,4 +86,10 @@ export {
|
|||
SkipToContentLink,
|
||||
} from './utils/skipToContentUtils';
|
||||
|
||||
export {
|
||||
UnlistedBannerTitle,
|
||||
UnlistedBannerMessage,
|
||||
UnlistedMetadata,
|
||||
} from './utils/unlistedUtils';
|
||||
|
||||
export {ErrorBoundaryTryAgainButton} from './utils/errorBoundaryUtils';
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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: {
|
||||
|
|
|
@ -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) =>
|
||||
|
|
32
packages/docusaurus-theme-common/src/utils/blogUtils.ts
Normal file
32
packages/docusaurus-theme-common/src/utils/blogUtils.ts
Normal 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],
|
||||
);
|
||||
}
|
|
@ -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;
|
||||
|
|
39
packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx
Normal file
39
packages/docusaurus-theme-common/src/utils/unlistedUtils.tsx
Normal 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>
|
||||
);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue