refactor(theme-classic): DocPage theme refactors polish (#7268)

This commit is contained in:
Sébastien Lorber 2022-04-29 19:34:40 +02:00 committed by GitHub
parent 41f53718c1
commit 2a0f105434
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 219 additions and 164 deletions

View file

@ -268,7 +268,7 @@ declare module '@theme/DocPage/Layout' {
export default function DocPageLayout(props: Props): JSX.Element;
}
declare module '@theme/DocPage/Layout/Aside' {
declare module '@theme/DocPage/Layout/Sidebar' {
import type {Dispatch, SetStateAction} from 'react';
import type {PropSidebar} from '@docusaurus/plugin-content-docs';
@ -278,7 +278,17 @@ declare module '@theme/DocPage/Layout/Aside' {
readonly setHiddenSidebarContainer: Dispatch<SetStateAction<boolean>>;
}
export default function DocPageLayoutAside(props: Props): JSX.Element;
export default function DocPageLayoutSidebar(props: Props): JSX.Element;
}
declare module '@theme/DocPage/Layout/Sidebar/ExpandButton' {
export interface Props {
toggleSidebar: () => void;
}
export default function DocPageLayoutSidebarExpandButton(
props: Props,
): JSX.Element;
}
declare module '@theme/DocPage/Layout/Main' {

View file

@ -0,0 +1,28 @@
/**
* 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.
*/
.docMainContainer {
display: flex;
width: 100%;
}
@media (min-width: 997px) {
.docMainContainer {
flex-grow: 1;
max-width: calc(100% - var(--doc-sidebar-width));
}
.docMainContainerEnhanced {
max-width: calc(100% - var(--doc-sidebar-hidden-width));
}
.docItemWrapperEnhanced {
max-width: calc(
var(--ifm-container-width) + var(--doc-sidebar-width)
) !important;
}
}

View file

@ -10,7 +10,7 @@ import React from 'react';
import {useDocsSidebar} from '@docusaurus/theme-common';
import clsx from 'clsx';
import styles from './styles.module.css';
import styles from './Main.module.css';
import type {Props} from '@theme/DocPage/Layout/Main';
export default function DocPageLayoutMain({

View file

@ -0,0 +1,37 @@
/**
* 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.
*/
@media (min-width: 997px) {
.expandButton {
position: sticky;
top: 0;
height: 100%;
max-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
transition: background-color var(--ifm-transition-fast) ease;
}
.expandButton:hover,
.expandButton:focus {
background-color: var(--ifm-color-emphasis-200);
}
.expandButtonIcon {
transform: rotate(0);
}
[dir='rtl'] .expandButtonIcon {
transform: rotate(180deg);
}
[data-theme='dark'] .expandButton:hover,
[data-theme='dark'] .expandButton:focus {
background-color: var(--collapse-button-bg-color-dark);
}
}

View file

@ -0,0 +1,40 @@
/**
* 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 IconArrow from '@theme/IconArrow';
import {translate} from '@docusaurus/Translate';
import type {Props} from '@theme/DocPage/Layout/Sidebar/ExpandButton';
import styles from './ExpandButton.module.css';
export default function DocPageLayoutSidebarExpandButton({
toggleSidebar,
}: Props): JSX.Element {
return (
<div
className={styles.expandButton}
title={translate({
id: 'theme.docs.sidebar.expandButtonTitle',
message: 'Expand sidebar',
description:
'The ARIA label and title attribute for expand button of doc sidebar',
})}
aria-label={translate({
id: 'theme.docs.sidebar.expandButtonAriaLabel',
message: 'Expand sidebar',
description:
'The ARIA label and title attribute for expand button of doc sidebar',
})}
tabIndex={0}
role="button"
onKeyDown={toggleSidebar}
onClick={toggleSidebar}>
<IconArrow className={styles.expandButtonIcon} />
</div>
);
}

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.
*/
:root {
--doc-sidebar-width: 300px;
--doc-sidebar-hidden-width: 30px;
}
.docSidebarContainer {
display: none;
}
@media (min-width: 997px) {
.docSidebarContainer {
display: block;
width: var(--doc-sidebar-width);
margin-top: calc(-1 * var(--ifm-navbar-height));
border-right: 1px solid var(--ifm-toc-border-color);
will-change: width;
transition: width var(--ifm-transition-fast) ease;
clip-path: inset(0);
}
.docSidebarContainerHidden {
width: var(--doc-sidebar-hidden-width);
cursor: pointer;
}
}

View file

@ -7,41 +7,15 @@
import React, {type ReactNode, useState, useCallback} from 'react';
import DocSidebar from '@theme/DocSidebar';
import IconArrow from '@theme/IconArrow';
import {translate} from '@docusaurus/Translate';
import {useLocation} from '@docusaurus/router';
import type {Props} from '@theme/DocPage/Layout/Aside';
import type {Props} from '@theme/DocPage/Layout/Sidebar';
import ExpandButton from '@theme/DocPage/Layout/Sidebar/ExpandButton';
import clsx from 'clsx';
import styles from './styles.module.css';
import styles from './index.module.css';
import {ThemeClassNames, useDocsSidebar} from '@docusaurus/theme-common';
function SidebarExpandButton({toggleSidebar}: {toggleSidebar: () => void}) {
return (
<div
className={styles.collapsedDocSidebar}
title={translate({
id: 'theme.docs.sidebar.expandButtonTitle',
message: 'Expand sidebar',
description:
'The ARIA label and title attribute for expand button of doc sidebar',
})}
aria-label={translate({
id: 'theme.docs.sidebar.expandButtonAriaLabel',
message: 'Expand sidebar',
description:
'The ARIA label and title attribute for expand button of doc sidebar',
})}
tabIndex={0}
role="button"
onKeyDown={toggleSidebar}
onClick={toggleSidebar}>
<IconArrow className={styles.expandSidebarButtonIcon} />
</div>
);
}
// Reset sidebar state when sidebar changes
// Use React key to unmount/remount the children
// See https://github.com/facebook/docusaurus/issues/3414
@ -54,7 +28,7 @@ function ResetOnSidebarChange({children}: {children: ReactNode}) {
);
}
export default function DocPageLayoutAside({
export default function DocPageLayoutSidebar({
sidebar,
hiddenSidebarContainer,
setHiddenSidebarContainer,
@ -94,7 +68,7 @@ export default function DocPageLayoutAside({
/>
</ResetOnSidebarChange>
{hiddenSidebar && <SidebarExpandButton toggleSidebar={toggleSidebar} />}
{hiddenSidebar && <ExpandButton toggleSidebar={toggleSidebar} />}
</aside>
);
}

View file

@ -0,0 +1,15 @@
/**
* 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.
*/
.docPage {
display: flex;
width: 100%;
}
.docsWrapper {
display: flex;
}

View file

@ -9,10 +9,10 @@ import React, {useState} from 'react';
import Layout from '@theme/Layout';
import BackToTopButton from '@theme/BackToTopButton';
import type {Props} from '@theme/DocPage/Layout';
import DocPageLayoutAside from '@theme/DocPage/Layout/Aside';
import DocPageLayoutSidebar from '@theme/DocPage/Layout/Sidebar';
import DocPageLayoutMain from '@theme/DocPage/Layout/Main';
import styles from './styles.module.css';
import styles from './index.module.css';
import {useDocsSidebar} from '@docusaurus/theme-common';
@ -24,7 +24,7 @@ export default function DocPageLayout({children}: Props): JSX.Element {
<BackToTopButton />
<div className={styles.docPage}>
{sidebar && (
<DocPageLayoutAside
<DocPageLayoutSidebar
sidebar={sidebar.items}
hiddenSidebarContainer={hiddenSidebarContainer}
setHiddenSidebarContainer={setHiddenSidebarContainer}

View file

@ -1,87 +0,0 @@
/**
* 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.
*/
:root {
--doc-sidebar-width: 300px;
--doc-sidebar-hidden-width: 30px;
}
.docPage,
.docMainContainer {
width: 100%;
}
.docsWrapper,
.docPage,
.docMainContainer {
display: flex;
}
.docSidebarContainer {
display: none;
}
@media (min-width: 997px) {
.docMainContainer {
flex-grow: 1;
max-width: calc(100% - var(--doc-sidebar-width));
}
.docMainContainerEnhanced {
max-width: calc(100% - var(--doc-sidebar-hidden-width));
}
.docSidebarContainer {
display: block;
width: var(--doc-sidebar-width);
margin-top: calc(-1 * var(--ifm-navbar-height));
border-right: 1px solid var(--ifm-toc-border-color);
will-change: width;
transition: width var(--ifm-transition-fast) ease;
clip-path: inset(0);
}
.docSidebarContainerHidden {
width: var(--doc-sidebar-hidden-width);
cursor: pointer;
}
.collapsedDocSidebar {
position: sticky;
top: 0;
height: 100%;
max-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
transition: background-color var(--ifm-transition-fast) ease;
}
.collapsedDocSidebar:hover,
.collapsedDocSidebar:focus {
background-color: var(--ifm-color-emphasis-200);
}
.expandSidebarButtonIcon {
transform: rotate(0);
}
[dir='rtl'] .expandSidebarButtonIcon {
transform: rotate(180deg);
}
[data-theme='dark'] .collapsedDocSidebar:hover,
[data-theme='dark'] .collapsedDocSidebar:focus {
background-color: var(--collapse-button-bg-color-dark);
}
.docItemWrapperEnhanced {
max-width: calc(
var(--ifm-container-width) + var(--doc-sidebar-width)
) !important;
}
}

View file

@ -6,12 +6,9 @@
*/
import React from 'react';
import renderRoutes from '@docusaurus/renderRoutes';
import type {PropSidebar} from '@docusaurus/plugin-content-docs';
import NotFound from '@theme/NotFound';
import type {Props} from '@theme/DocPage';
import DocPageLayout from '@theme/DocPage/Layout';
import {matchPath} from '@docusaurus/router';
import clsx from 'clsx';
@ -21,47 +18,13 @@ import {
docVersionSearchTag,
DocsSidebarProvider,
DocsVersionProvider,
useDocRouteMetadata,
} from '@docusaurus/theme-common';
import SearchMetadata from '@theme/SearchMetadata';
function extractDocRouteMetadata(props: Props): null | {
docElement: JSX.Element;
sidebarName: string | undefined;
sidebarItems: PropSidebar | undefined;
} {
const {
route: {routes: docRoutes},
versionMetadata,
location,
} = props;
const currentDocRoute = docRoutes!.find((docRoute) =>
matchPath(location.pathname, docRoute),
);
if (!currentDocRoute) {
return null;
}
// For now, the sidebarName is added as route config: not ideal!
const sidebarName = currentDocRoute.sidebar;
const sidebarItems = sidebarName
? versionMetadata.docsSidebars[sidebarName]
: undefined;
const docElement = renderRoutes(props.route.routes, {
versionMetadata,
});
return {
docElement,
sidebarName,
sidebarItems,
};
}
export default function DocPage(props: Props): JSX.Element {
const {versionMetadata} = props;
const currentDocRouteMetadata = extractDocRouteMetadata(props);
const currentDocRouteMetadata = useDocRouteMetadata(props);
if (!currentDocRouteMetadata) {
return <NotFound />;
}

View file

@ -55,6 +55,7 @@ export {
useDocsVersionCandidates,
useLayoutDoc,
useLayoutDocsSidebar,
useDocRouteMetadata,
} from './utils/docsUtils';
export {useSkipToContent} from './utils/a11yUtils';

View file

@ -20,6 +20,7 @@ import type {
PropSidebarItem,
PropSidebarItemCategory,
PropVersionDoc,
PropVersionMetadata,
PropSidebarBreadcrumbsItem,
} from '@docusaurus/plugin-content-docs';
import {useDocsPreferredVersion} from '../contexts/docsPreferredVersion';
@ -27,7 +28,9 @@ import {useDocsVersion} from '../contexts/docsVersion';
import {useDocsSidebar} from '../contexts/docsSidebar';
import {uniq} from './jsUtils';
import {isSamePath} from './routesUtils';
import {useLocation} from '@docusaurus/router';
import {matchPath, useLocation} from '@docusaurus/router';
import renderRoutes from '@docusaurus/renderRoutes';
import type {RouteConfig} from 'react-router-config';
// TODO not ideal, see also "useDocs"
export const isDocsPluginEnabled: boolean = !!useAllDocsData;
@ -281,3 +284,42 @@ Available doc ids are:
return doc;
}, [docId, versions]);
}
// TODO later read version/route directly from context
export function useDocRouteMetadata({
route,
versionMetadata,
}: {
route: RouteConfig;
versionMetadata: PropVersionMetadata;
}): null | {
docElement: JSX.Element;
sidebarName: string | undefined;
sidebarItems: PropSidebar | undefined;
} {
const location = useLocation();
const docRoutes = route.routes;
const currentDocRoute = docRoutes!.find((docRoute) =>
matchPath(location.pathname, docRoute),
);
if (!currentDocRoute) {
return null;
}
// For now, the sidebarName is added as route config: not ideal!
const sidebarName = currentDocRoute.sidebar;
const sidebarItems = sidebarName
? versionMetadata.docsSidebars[sidebarName]
: undefined;
const docElement = renderRoutes(route.routes!, {
versionMetadata,
});
return {
docElement,
sidebarName,
sidebarItems,
};
}