feat(v2): redesign mobile UX: inline TOC + doc sidebar in main menu (#4273)

* feat(v2): mobile TOC

* Bug fixes and various improvements

* Redesign

* extract TOCCollapsible component

* TS improvements

* Assign sidebar name directly to the doc route => no need for either permalinkToSidebar or GlobalData

* revert changes to useWindowSize, fix FOUC issues

* extract DocSidebarDesktop component

* remove now useless menu infima classes

* TOCHeadings => rename + remove unused onClick prop

* Extract DocSidebarItem

* minor renaming

* replace GlobalData usage by a React teleport system to render in the navbar mobile sidebar menu directly from the DocPage component

* useWindowSize => simulate SSR size in dev to make FOUC issues more obvious

* fix remaining sidebar layout shift

* update docs snapshots

* remove unused code translations

* remove unused code translations

* fix minor update-code-translations bug

* Add more build-size paths to watch

* Restyle back button

* Add  missing`menu` class

* extract useShallowMemoizedObject

* fix routes tests + better routes formatting

* use Translate api for labels

* use Translate api for labels

* Update translations

* Improve dark mode support for back button

* Merge branch 'master' into lex111/inline-color-code

# Conflicts:
#	packages/core/dist/css/default-dark/default-dark-rtl.min.css
#	packages/core/dist/css/default-dark/default-dark.min.css
#	packages/core/dist/css/default/default-rtl.min.css
#	packages/core/dist/css/default/default.min.css

* replace useCollapse by new useCollapsible

* Cleanup and use clean-btn for TOCCollapsible button

* Make TOC links clickable over full width

* Cleanup

* fix uncollapsible sidebar that can be collapsed + create <Collapsible> component

* dependency array typo

* rollback sidebars community commit typo

Co-authored-by: slorber <lorber.sebastien@gmail.com>
This commit is contained in:
Alexey Pyltsyn 2021-07-09 17:50:38 +03:00 committed by GitHub
parent f03479f69e
commit 9536ef900d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
58 changed files with 1006 additions and 633 deletions

View file

@ -26,7 +26,7 @@ jobs:
with: with:
repo-token: '${{ secrets.GITHUB_TOKEN }}' repo-token: '${{ secrets.GITHUB_TOKEN }}'
build-script: 'build:v2:en' build-script: 'build:v2:en'
pattern: '{website/build/assets/js/main*js,website/build/assets/css/styles*css,website/.docusaurus/globalData.json,website/build/index.html,website/build/blog/**/introducing-docusaurus/*,website/build/docs/index.html,website/build/docs/introduction/index.html,website/build/docs-tests/index.html,website/build/docs-tests/standalone/index.html}' pattern: '{website/build/assets/js/main*js,website/build/assets/css/styles*css,website/.docusaurus/globalData.json,website/build/index.html,website/build/blog/index.html,website/build/blog/**/introducing-docusaurus/*,website/build/docs/index.html,website/build/docs/installation/index.html,website/build/docs-tests/index.html,website/build/docs-tests/standalone/index.html}'
strip-hash: '\.([^;]\w{7})\.' strip-hash: '\.([^;]\w{7})\.'
minimum-change-threshold: 30 minimum-change-threshold: 30
compression: 'none' compression: 'none'

View file

@ -456,11 +456,6 @@ Object {
] ]
} }
] ]
},
\\"permalinkToSidebar\\": {
\\"/docs/foo/bar\\": \\"docs\\",
\\"/docs/foo/bazSlug.html\\": \\"docs\\",
\\"/docs/\\": \\"docs\\"
} }
}", }",
} }
@ -575,6 +570,7 @@ Array [
"content": "@site/docs/hello.md", "content": "@site/docs/hello.md",
}, },
"path": "/docs/", "path": "/docs/",
"sidebar": "docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -591,6 +587,7 @@ Array [
"content": "@site/docs/foo/bar.md", "content": "@site/docs/foo/bar.md",
}, },
"path": "/docs/foo/bar", "path": "/docs/foo/bar",
"sidebar": "docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -599,6 +596,7 @@ Array [
"content": "@site/docs/foo/baz.md", "content": "@site/docs/foo/baz.md",
}, },
"path": "/docs/foo/bazSlug.html", "path": "/docs/foo/bazSlug.html",
"sidebar": "docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -883,9 +881,6 @@ Object {
\\"href\\": \\"/community/team\\" \\"href\\": \\"/community/team\\"
} }
] ]
},
\\"permalinkToSidebar\\": {
\\"/community/team\\": \\"version-1.0.0/community\\"
} }
}", }",
"version-current-metadata-prop-751.json": "{ "version-current-metadata-prop-751.json": "{
@ -902,9 +897,6 @@ Object {
\\"href\\": \\"/community/next/team\\" \\"href\\": \\"/community/next/team\\"
} }
] ]
},
\\"permalinkToSidebar\\": {
\\"/community/next/team\\": \\"community\\"
} }
}", }",
} }
@ -968,6 +960,7 @@ Array [
"content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md", "content": "@site/i18n/en/docusaurus-plugin-content-docs-community/current/team.md",
}, },
"path": "/community/next/team", "path": "/community/next/team",
"sidebar": "community",
}, },
], ],
}, },
@ -987,6 +980,7 @@ Array [
"content": "@site/community_versioned_docs/version-1.0.0/team.md", "content": "@site/community_versioned_docs/version-1.0.0/team.md",
}, },
"path": "/community/team", "path": "/community/team",
"sidebar": "version-1.0.0/community",
}, },
], ],
}, },
@ -1439,11 +1433,6 @@ Object {
] ]
} }
] ]
},
\\"permalinkToSidebar\\": {
\\"/docs/1.0.0/foo/barSlug\\": \\"version-1.0.0/docs\\",
\\"/docs/1.0.0/foo/baz\\": \\"version-1.0.0/docs\\",
\\"/docs/1.0.0/\\": \\"version-1.0.0/docs\\"
} }
}", }",
"version-1-0-1-metadata-prop-e87.json": "{ "version-1-0-1-metadata-prop-e87.json": "{
@ -1479,10 +1468,6 @@ Object {
] ]
} }
] ]
},
\\"permalinkToSidebar\\": {
\\"/docs/foo/bar\\": \\"version-1.0.1/docs\\",
\\"/docs/\\": \\"version-1.0.1/docs\\"
} }
}", }",
"version-current-metadata-prop-751.json": "{ "version-current-metadata-prop-751.json": "{
@ -1518,10 +1503,6 @@ Object {
] ]
} }
] ]
},
\\"permalinkToSidebar\\": {
\\"/docs/next/foo/barSlug\\": \\"docs\\",
\\"/docs/next/\\": \\"docs\\"
} }
}", }",
"version-with-slugs-metadata-prop-2bf.json": "{ "version-with-slugs-metadata-prop-2bf.json": "{
@ -1545,9 +1526,6 @@ Object {
] ]
} }
] ]
},
\\"permalinkToSidebar\\": {
\\"/docs/withSlugs/rootAbsoluteSlug\\": \\"version-1.0.1/docs\\"
} }
}", }",
} }
@ -1714,6 +1692,7 @@ Array [
"content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md", "content": "@site/i18n/en/docusaurus-plugin-content-docs/version-1.0.0/hello.md",
}, },
"path": "/docs/1.0.0/", "path": "/docs/1.0.0/",
"sidebar": "version-1.0.0/docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -1722,6 +1701,7 @@ Array [
"content": "@site/versioned_docs/version-1.0.0/foo/bar.md", "content": "@site/versioned_docs/version-1.0.0/foo/bar.md",
}, },
"path": "/docs/1.0.0/foo/barSlug", "path": "/docs/1.0.0/foo/barSlug",
"sidebar": "version-1.0.0/docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -1730,6 +1710,7 @@ Array [
"content": "@site/versioned_docs/version-1.0.0/foo/baz.md", "content": "@site/versioned_docs/version-1.0.0/foo/baz.md",
}, },
"path": "/docs/1.0.0/foo/baz", "path": "/docs/1.0.0/foo/baz",
"sidebar": "version-1.0.0/docs",
}, },
], ],
}, },
@ -1749,6 +1730,7 @@ Array [
"content": "@site/docs/hello.md", "content": "@site/docs/hello.md",
}, },
"path": "/docs/next/", "path": "/docs/next/",
"sidebar": "docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -1765,6 +1747,7 @@ Array [
"content": "@site/docs/foo/bar.md", "content": "@site/docs/foo/bar.md",
}, },
"path": "/docs/next/foo/barSlug", "path": "/docs/next/foo/barSlug",
"sidebar": "docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -1824,6 +1807,7 @@ Array [
"content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md", "content": "@site/versioned_docs/version-withSlugs/rootAbsoluteSlug.md",
}, },
"path": "/docs/withSlugs/rootAbsoluteSlug", "path": "/docs/withSlugs/rootAbsoluteSlug",
"sidebar": "version-1.0.1/docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -1883,6 +1867,7 @@ Array [
"content": "@site/versioned_docs/version-1.0.1/hello.md", "content": "@site/versioned_docs/version-1.0.1/hello.md",
}, },
"path": "/docs/", "path": "/docs/",
"sidebar": "version-1.0.1/docs",
}, },
Object { Object {
"component": "@theme/DocItem", "component": "@theme/DocItem",
@ -1891,6 +1876,7 @@ Array [
"content": "@site/versioned_docs/version-1.0.1/foo/bar.md", "content": "@site/versioned_docs/version-1.0.1/foo/bar.md",
}, },
"path": "/docs/foo/bar", "path": "/docs/foo/bar",
"sidebar": "version-1.0.1/docs",
}, },
], ],
}, },

View file

@ -151,7 +151,6 @@ Object {
], ],
"isLast": true, "isLast": true,
"mainDocId": "", "mainDocId": "",
"permalinkToSidebar": Object {},
"routePriority": undefined, "routePriority": undefined,
"sidebarFilePath": "any", "sidebarFilePath": "any",
"sidebars": Object { "sidebars": Object {
@ -292,7 +291,6 @@ Object {
], ],
"isLast": true, "isLast": true,
"mainDocId": "", "mainDocId": "",
"permalinkToSidebar": Object {},
"routePriority": undefined, "routePriority": undefined,
"sidebarFilePath": "any", "sidebarFilePath": "any",
"sidebars": Object { "sidebars": Object {
@ -433,7 +431,6 @@ Object {
], ],
"isLast": true, "isLast": true,
"mainDocId": "", "mainDocId": "",
"permalinkToSidebar": Object {},
"routePriority": undefined, "routePriority": undefined,
"sidebarFilePath": "any", "sidebarFilePath": "any",
"sidebars": Object { "sidebars": Object {

View file

@ -105,9 +105,6 @@ Entries created:
`version-${kebabCase(version.versionName)}-metadata-prop`, `version-${kebabCase(version.versionName)}-metadata-prop`,
); );
expect(versionMetadataProp.docsSidebars).toEqual(toSidebarsProp(version)); expect(versionMetadataProp.docsSidebars).toEqual(toSidebarsProp(version));
expect(versionMetadataProp.permalinkToSidebar).toEqual(
version.permalinkToSidebar,
);
}, },
expectSnapshot: () => { expectSnapshot: () => {

View file

@ -40,7 +40,6 @@ function createSampleVersion(
versionLabel: `${version.versionName} label`, versionLabel: `${version.versionName} label`,
versionPath: '/docs/', versionPath: '/docs/',
mainDocId: '', mainDocId: '',
permalinkToSidebar: {},
routePriority: undefined, routePriority: undefined,
sidebarFilePath: 'any', sidebarFilePath: 'any',
isLast: true, isLast: true,

View file

@ -37,7 +37,6 @@ import {
DocFile, DocFile,
DocsMarkdownOption, DocsMarkdownOption,
} from './types'; } from './types';
import {PermalinkToSidebar} from '@docusaurus/plugin-content-docs-types';
import {RuleSetRule} from 'webpack'; import {RuleSetRule} from 'webpack';
import {cliDocsVersionCommand} from './cli'; import {cliDocsVersionCommand} from './cli';
import {VERSIONS_JSON_FILE} from './constants'; import {VERSIONS_JSON_FILE} from './constants';
@ -224,14 +223,6 @@ export default function pluginContentDocs(
// sort to ensure consistent output for tests // sort to ensure consistent output for tests
docs.sort((a, b) => a.id.localeCompare(b.id)); docs.sort((a, b) => a.id.localeCompare(b.id));
// TODO really useful? replace with global state logic?
const permalinkToSidebar: PermalinkToSidebar = {};
Object.values(docs).forEach((doc) => {
if (doc.sidebar) {
permalinkToSidebar[doc.permalink] = doc.sidebar;
}
});
// The "main doc" is the "version entry point" // The "main doc" is the "version entry point"
// We browse this doc by clicking on a version: // We browse this doc by clicking on a version:
// - the "home" doc (at '/docs/') // - the "home" doc (at '/docs/')
@ -256,7 +247,6 @@ export default function pluginContentDocs(
...versionMetadata, ...versionMetadata,
mainDocId: getMainDoc().unversionedId, mainDocId: getMainDoc().unversionedId,
sidebars, sidebars,
permalinkToSidebar,
docs: docs.map(addNavData), docs: docs.map(addNavData),
}; };
} }
@ -300,30 +290,36 @@ export default function pluginContentDocs(
JSON.stringify(metadataItem, null, 2), JSON.stringify(metadataItem, null, 2),
); );
return { const docRoute: RouteConfig = {
path: metadataItem.permalink, path: metadataItem.permalink,
component: docItemComponent, component: docItemComponent,
exact: true, exact: true,
modules: { modules: {
content: metadataItem.source, content: metadataItem.source,
}, },
// Because the parent (DocPage) comp need to access it easily
// This permits to render the sidebar once without unmount/remount when navigating (and preserve sidebar state)
...(metadataItem.sidebar && {
sidebar: metadataItem.sidebar,
}),
}; };
return docRoute;
}), }),
); );
return routes.sort((a, b) => a.path.localeCompare(b.path)); return routes.sort((a, b) => a.path.localeCompare(b.path));
}; };
async function doCreateVersionRoutes(loadedVersion: LoadedVersion) { async function doCreateVersionRoutes(
loadedVersion: LoadedVersion,
): Promise<void> {
const versionMetadata = toVersionMetadataProp(pluginId, loadedVersion);
const versionMetadataPropPath = await createData( const versionMetadataPropPath = await createData(
`${docuHash( `${docuHash(
`version-${loadedVersion.versionName}-metadata-prop`, `version-${loadedVersion.versionName}-metadata-prop`,
)}.json`, )}.json`,
JSON.stringify( JSON.stringify(versionMetadata, null, 2),
toVersionMetadataProp(pluginId, loadedVersion),
null,
2,
),
); );
addRoute({ addRoute({
@ -341,7 +337,9 @@ export default function pluginContentDocs(
}); });
} }
async function createVersionRoutes(loadedVersion: LoadedVersion) { async function createVersionRoutes(
loadedVersion: LoadedVersion,
): Promise<void> {
try { try {
return await doCreateVersionRoutes(loadedVersion); return await doCreateVersionRoutes(loadedVersion);
} catch (e) { } catch (e) {

View file

@ -10,10 +10,6 @@
declare module '@docusaurus/plugin-content-docs-types' { declare module '@docusaurus/plugin-content-docs-types' {
import type {VersionBanner} from './types'; import type {VersionBanner} from './types';
export type PermalinkToSidebar = {
[permalink: string]: string;
};
export type PropVersionMetadata = { export type PropVersionMetadata = {
pluginId: string; pluginId: string;
version: string; version: string;
@ -21,7 +17,6 @@ declare module '@docusaurus/plugin-content-docs-types' {
banner: VersionBanner; banner: VersionBanner;
isLast: boolean; isLast: boolean;
docsSidebars: PropSidebars; docsSidebars: PropSidebars;
permalinkToSidebar: PermalinkToSidebar;
}; };
type PropsSidebarItemBase = { type PropsSidebarItemBase = {
@ -60,6 +55,7 @@ declare module '@theme/DocItem' {
readonly component: () => JSX.Element; readonly component: () => JSX.Element;
readonly exact: boolean; readonly exact: boolean;
readonly path: string; readonly path: string;
readonly sidebar?: string;
}; };
export type FrontMatter = { export type FrontMatter = {

View file

@ -77,6 +77,5 @@ export function toVersionMetadataProp(
banner: loadedVersion.versionBanner, banner: loadedVersion.versionBanner,
isLast: loadedVersion.isLast, isLast: loadedVersion.isLast,
docsSidebars: toSidebarsProp(loadedVersion), docsSidebars: toSidebarsProp(loadedVersion),
permalinkToSidebar: loadedVersion.permalinkToSidebar,
}; };
} }

View file

@ -239,7 +239,6 @@ export type LoadedVersion = VersionMetadata & {
mainDocId: string; mainDocId: string;
docs: DocMetadata[]; docs: DocMetadata[];
sidebars: Sidebars; sidebars: Sidebars;
permalinkToSidebar: Record<string, string>;
}; };
export type LoadedContent = { export type LoadedContent = {

View file

@ -8,37 +8,25 @@
import React, {ReactNode} from 'react'; import React, {ReactNode} from 'react';
import renderRoutes from '@docusaurus/renderRoutes'; import renderRoutes from '@docusaurus/renderRoutes';
import NotFound from '@theme/NotFound'; import NotFound from '@theme/NotFound';
import DocSidebar from '@theme/DocSidebar';
import MDXComponents from '@theme/MDXComponents'; import MDXComponents from '@theme/MDXComponents';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import {MDXProvider} from '@mdx-js/react'; import {MDXProvider} from '@mdx-js/react';
import {matchPath} from '@docusaurus/router'; import {matchPath} from '@docusaurus/router';
import type {Props} from '@theme/DocPage'; import type {Props} from '@theme/DocPage';
import type {DocumentRoute} from '@theme/DocItem';
import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types'; import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types';
type DocPageContentProps = { type DocPageContentProps = {
readonly currentDocRoute: DocumentRoute;
readonly versionMetadata: PropVersionMetadata; readonly versionMetadata: PropVersionMetadata;
readonly children: ReactNode; readonly children: ReactNode;
}; };
function DocPageContent({ function DocPageContent({
currentDocRoute, versionMetadata: _versionMetadata,
versionMetadata,
children, children,
}: DocPageContentProps): JSX.Element { }: DocPageContentProps): JSX.Element {
const {permalinkToSidebar, docsSidebars} = versionMetadata;
const sidebarName = permalinkToSidebar[currentDocRoute.path];
const sidebar = docsSidebars[sidebarName];
return ( return (
<Layout title="Doc page" description="My Doc page"> <Layout title="Doc page" description="My Doc page">
<div className="d-flex vh-100"> <div className="d-flex vh-100">
{sidebar && (
<div role="complementary">
<DocSidebar key={sidebarName} sidebar={sidebar} />
</div>
)}
<main className="w-100 align-items-center overflow-auto p-5"> <main className="w-100 align-items-center overflow-auto p-5">
<MDXProvider components={MDXComponents}>{children}</MDXProvider> <MDXProvider components={MDXComponents}>{children}</MDXProvider>
</main> </main>
@ -60,9 +48,7 @@ function DocPage(props: Props): JSX.Element {
return <NotFound {...props} />; return <NotFound {...props} />;
} }
return ( return (
<DocPageContent <DocPageContent versionMetadata={versionMetadata}>
currentDocRoute={currentDocRoute}
versionMetadata={versionMetadata}>
{renderRoutes(docRoutes)} {renderRoutes(docRoutes)}
</DocPageContent> </DocPageContent>
); );

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "بحث", "theme.SearchPage.inputLabel": "بحث",
"theme.SearchPage.inputPlaceholder": "اكتب ما تبحث عنه هنا", "theme.SearchPage.inputPlaceholder": "اكتب ما تبحث عنه هنا",
"theme.SearchPage.noResultsText": "لم يتم العثور على نتائج", "theme.SearchPage.noResultsText": "لم يتم العثور على نتائج",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "التنقل في صفحة قائمة المدونة", "theme.blog.paginator.navAriaLabel": "التنقل في صفحة قائمة المدونة",
"theme.blog.paginator.newerEntries": "إدخالات أحدث", "theme.blog.paginator.newerEntries": "إدخالات أحدث",
"theme.blog.paginator.olderEntries": "إدخالات أقدم", "theme.blog.paginator.olderEntries": "إدخالات أقدم",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "طي الشريط الجانبي", "theme.docs.sidebar.collapseButtonTitle": "طي الشريط الجانبي",
"theme.docs.sidebar.expandButtonAriaLabel": "توسيع الشريط الجانبي", "theme.docs.sidebar.expandButtonAriaLabel": "توسيع الشريط الجانبي",
"theme.docs.sidebar.expandButtonTitle": "توسيع الشريط الجانبي", "theme.docs.sidebar.expandButtonTitle": "توسيع الشريط الجانبي",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "إغلاق القائمة",
"theme.docs.sidebar.responsiveOpenButtonLabel": "فتح القائمة",
"theme.docs.versions.latestVersionLinkLabel": "احدث اصدار", "theme.docs.versions.latestVersionLinkLabel": "احدث اصدار",
"theme.docs.versions.latestVersionSuggestionLabel": "للحصول على أحدث الوثائق، راجع {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "للحصول على أحدث الوثائق، راجع {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "هذه هي وثائق {siteTitle} {versionLabel}، التي لم تعد تتم صيانتها بشكل نشط.", "theme.docs.versions.unmaintainedVersionLabel": "هذه هي وثائق {siteTitle} {versionLabel}، التي لم تعد تتم صيانتها بشكل نشط.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " في {date}", "theme.lastUpdated.atDate": " في {date}",
"theme.lastUpdated.byUser": " بواسطة {user}", "theme.lastUpdated.byUser": " بواسطة {user}",
"theme.lastUpdated.lastUpdatedAtBy": "آخر تحديث{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "آخر تحديث{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "الوسوم:", "theme.tags.tagsListLabel": "الوسوم:",
"theme.tags.tagsPageLink": "عرض كل الوسوم", "theme.tags.tagsPageLink": "عرض كل الوسوم",
"theme.tags.tagsPageTitle": "الوسوم" "theme.tags.tagsPageTitle": "الوسوم"

View file

@ -41,6 +41,8 @@
"theme.SearchPage.inputPlaceholder___DESCRIPTION": "The placeholder for search page input", "theme.SearchPage.inputPlaceholder___DESCRIPTION": "The placeholder for search page input",
"theme.SearchPage.noResultsText": "No results were found", "theme.SearchPage.noResultsText": "No results were found",
"theme.SearchPage.noResultsText___DESCRIPTION": "The paragraph for empty search result", "theme.SearchPage.noResultsText___DESCRIPTION": "The paragraph for empty search result",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.TOCCollapsible.toggleButtonLabel___DESCRIPTION": "The label used by the button on the collapsible TOC component",
"theme.blog.paginator.navAriaLabel": "Blog list page navigation", "theme.blog.paginator.navAriaLabel": "Blog list page navigation",
"theme.blog.paginator.navAriaLabel___DESCRIPTION": "The ARIA label for the blog pagination", "theme.blog.paginator.navAriaLabel___DESCRIPTION": "The ARIA label for the blog pagination",
"theme.blog.paginator.newerEntries": "Newer Entries", "theme.blog.paginator.newerEntries": "Newer Entries",
@ -83,16 +85,10 @@
"theme.docs.sidebar.expandButtonAriaLabel___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar", "theme.docs.sidebar.expandButtonAriaLabel___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar",
"theme.docs.sidebar.expandButtonTitle": "Expand sidebar", "theme.docs.sidebar.expandButtonTitle": "Expand sidebar",
"theme.docs.sidebar.expandButtonTitle___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar", "theme.docs.sidebar.expandButtonTitle___DESCRIPTION": "The ARIA label and title attribute for expand button of doc sidebar",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.navAriaLabel___DESCRIPTION": "The ARIA label for documentation menu",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Close menu",
"theme.docs.sidebar.responsiveCloseButtonLabel___DESCRIPTION": "The ARIA label for close button of mobile doc sidebar",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Open menu",
"theme.docs.sidebar.responsiveOpenButtonLabel___DESCRIPTION": "The ARIA label for open button of mobile doc sidebar",
"theme.docs.versions.latestVersionLinkLabel": "latest version", "theme.docs.versions.latestVersionLinkLabel": "latest version",
"theme.docs.versions.latestVersionLinkLabel___DESCRIPTION": "The label used for the latest version suggestion link label", "theme.docs.versions.latestVersionLinkLabel___DESCRIPTION": "The label used for the latest version suggestion link label",
"theme.docs.versions.latestVersionSuggestionLabel": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.latestVersionSuggestionLabel___DESCRIPTION": "The label userd to tell the user that he's browsing an unmaintained doc version", "theme.docs.versions.latestVersionSuggestionLabel___DESCRIPTION": "The label used to tell the user to check the latest version",
"theme.docs.versions.unmaintainedVersionLabel": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.", "theme.docs.versions.unmaintainedVersionLabel": "This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.",
"theme.docs.versions.unmaintainedVersionLabel___DESCRIPTION": "The label used to tell the user that he's browsing an unmaintained doc version", "theme.docs.versions.unmaintainedVersionLabel___DESCRIPTION": "The label used to tell the user that he's browsing an unmaintained doc version",
"theme.docs.versions.unreleasedVersionLabel": "This is unreleased documentation for {siteTitle} {versionLabel} version.", "theme.docs.versions.unreleasedVersionLabel": "This is unreleased documentation for {siteTitle} {versionLabel} version.",
@ -103,6 +99,8 @@
"theme.lastUpdated.byUser___DESCRIPTION": "The words used to describe by who the page has been last updated", "theme.lastUpdated.byUser___DESCRIPTION": "The words used to describe by who the page has been last updated",
"theme.lastUpdated.lastUpdatedAtBy": "Last updated{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Last updated{atDate}{byUser}",
"theme.lastUpdated.lastUpdatedAtBy___DESCRIPTION": "The sentence used to display when a page has been last updated, and by who", "theme.lastUpdated.lastUpdatedAtBy___DESCRIPTION": "The sentence used to display when a page has been last updated, and by who",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel___DESCRIPTION": "The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)",
"theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsListLabel": "Tags:",
"theme.tags.tagsListLabel___DESCRIPTION": "The label alongside a tag list", "theme.tags.tagsListLabel___DESCRIPTION": "The label alongside a tag list",
"theme.tags.tagsPageLink": "View All Tags", "theme.tags.tagsPageLink": "View All Tags",

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "সার্চ", "theme.SearchPage.inputLabel": "সার্চ",
"theme.SearchPage.inputPlaceholder": "আপনার অনুসন্ধান এখানে টাইপ করুন", "theme.SearchPage.inputPlaceholder": "আপনার অনুসন্ধান এখানে টাইপ করুন",
"theme.SearchPage.noResultsText": "কোন ফলাফল পাওয়া যায়নি", "theme.SearchPage.noResultsText": "কোন ফলাফল পাওয়া যায়নি",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "ব্লগ তালিকা পেজ নেভিগেশন", "theme.blog.paginator.navAriaLabel": "ব্লগ তালিকা পেজ নেভিগেশন",
"theme.blog.paginator.newerEntries": "নতুন এন্ট্রি", "theme.blog.paginator.newerEntries": "নতুন এন্ট্রি",
"theme.blog.paginator.olderEntries": "পুরানো এন্ট্রি", "theme.blog.paginator.olderEntries": "পুরানো এন্ট্রি",
@ -41,8 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "সাইডবারটি সঙ্কুচিত করুন", "theme.docs.sidebar.collapseButtonTitle": "সাইডবারটি সঙ্কুচিত করুন",
"theme.docs.sidebar.expandButtonAriaLabel": "সাইডবারটি প্রসারিত করুন", "theme.docs.sidebar.expandButtonAriaLabel": "সাইডবারটি প্রসারিত করুন",
"theme.docs.sidebar.expandButtonTitle": "সাইডবারটি প্রসারিত করুন", "theme.docs.sidebar.expandButtonTitle": "সাইডবারটি প্রসারিত করুন",
"theme.docs.sidebar.responsiveCloseButtonLabel": "মেনু বন্ধ করুন",
"theme.docs.sidebar.responsiveOpenButtonLabel": "মেনু খুলুন",
"theme.docs.versions.latestVersionLinkLabel": "লেটেস্ট ভার্সন", "theme.docs.versions.latestVersionLinkLabel": "লেটেস্ট ভার্সন",
"theme.docs.versions.latestVersionSuggestionLabel": "আপ-টু-ডেট ডকুমেন্টেশনের জন্য, {latestVersionLink} ({versionLabel}) দেখুন।", "theme.docs.versions.latestVersionSuggestionLabel": "আপ-টু-ডেট ডকুমেন্টেশনের জন্য, {latestVersionLink} ({versionLabel}) দেখুন।",
"theme.docs.versions.unmaintainedVersionLabel": "এটি {siteTitle} {versionLabel} এর জন্যে ডকুমেন্টেশন, যা আর সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয় না।", "theme.docs.versions.unmaintainedVersionLabel": "এটি {siteTitle} {versionLabel} এর জন্যে ডকুমেন্টেশন, যা আর সক্রিয়ভাবে রক্ষণাবেক্ষণ করা হয় না।",
@ -50,6 +49,7 @@
"theme.lastUpdated.atDate": " {date} তারিখে", "theme.lastUpdated.atDate": " {date} তারিখে",
"theme.lastUpdated.byUser": "{user} দ্বারা", "theme.lastUpdated.byUser": "{user} দ্বারা",
"theme.lastUpdated.lastUpdatedAtBy": "সর্বশেষ সংষ্করণ{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "সর্বশেষ সংষ্করণ{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "ট্যাগ্স:", "theme.tags.tagsListLabel": "ট্যাগ্স:",
"theme.tags.tagsPageLink": "সমস্ত ট্যাগ্স দেখুন", "theme.tags.tagsPageLink": "সমস্ত ট্যাগ্স দেখুন",
"theme.tags.tagsPageTitle": "ট্যাগ্স" "theme.tags.tagsPageTitle": "ট্যাগ্স"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Søg", "theme.SearchPage.inputLabel": "Søg",
"theme.SearchPage.inputPlaceholder": "Indtast din søgning her", "theme.SearchPage.inputPlaceholder": "Indtast din søgning her",
"theme.SearchPage.noResultsText": "Ingen resultater fundet", "theme.SearchPage.noResultsText": "Ingen resultater fundet",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Blogoversigt navigation", "theme.blog.paginator.navAriaLabel": "Blogoversigt navigation",
"theme.blog.paginator.newerEntries": "Nyere indslag", "theme.blog.paginator.newerEntries": "Nyere indslag",
"theme.blog.paginator.olderEntries": "Tidligere indslag", "theme.blog.paginator.olderEntries": "Tidligere indslag",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Sammenlæg sidenavigation", "theme.docs.sidebar.collapseButtonTitle": "Sammenlæg sidenavigation",
"theme.docs.sidebar.expandButtonAriaLabel": "Udvid sidenavigation", "theme.docs.sidebar.expandButtonAriaLabel": "Udvid sidenavigation",
"theme.docs.sidebar.expandButtonTitle": "Udvid sidenavigation", "theme.docs.sidebar.expandButtonTitle": "Udvid sidenavigation",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Luk menu",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Åben menu",
"theme.docs.versions.latestVersionLinkLabel": "seneste version", "theme.docs.versions.latestVersionLinkLabel": "seneste version",
"theme.docs.versions.latestVersionSuggestionLabel": "For seneste dokumentation, se {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "For seneste dokumentation, se {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Dette er dokumentationen for {siteTitle} {versionLabel}, som ikke længere bliver aktivt vedligeholdt.", "theme.docs.versions.unmaintainedVersionLabel": "Dette er dokumentationen for {siteTitle} {versionLabel}, som ikke længere bliver aktivt vedligeholdt.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " den {date}", "theme.lastUpdated.atDate": " den {date}",
"theme.lastUpdated.byUser": " af {user}", "theme.lastUpdated.byUser": " af {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Senest opdateret{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Senest opdateret{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsListLabel": "Tags:",
"theme.tags.tagsPageLink": "Se alle Tags", "theme.tags.tagsPageLink": "Se alle Tags",
"theme.tags.tagsPageTitle": "Tags" "theme.tags.tagsPageTitle": "Tags"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Suche", "theme.SearchPage.inputLabel": "Suche",
"theme.SearchPage.inputPlaceholder": "Geben Sie hier Ihre Suche ein", "theme.SearchPage.inputPlaceholder": "Geben Sie hier Ihre Suche ein",
"theme.SearchPage.noResultsText": "Es wurden keine Ergebnisse gefunden", "theme.SearchPage.noResultsText": "Es wurden keine Ergebnisse gefunden",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Navigation der Blog-Listenseite", "theme.blog.paginator.navAriaLabel": "Navigation der Blog-Listenseite",
"theme.blog.paginator.newerEntries": "Neuere Einträge", "theme.blog.paginator.newerEntries": "Neuere Einträge",
"theme.blog.paginator.olderEntries": "Ältere Einträge", "theme.blog.paginator.olderEntries": "Ältere Einträge",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Seitenleiste einklappen", "theme.docs.sidebar.collapseButtonTitle": "Seitenleiste einklappen",
"theme.docs.sidebar.expandButtonAriaLabel": "Seitenleiste ausklappen", "theme.docs.sidebar.expandButtonAriaLabel": "Seitenleiste ausklappen",
"theme.docs.sidebar.expandButtonTitle": "Seitenleiste ausklappen", "theme.docs.sidebar.expandButtonTitle": "Seitenleiste ausklappen",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Menü schließen",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Menü öffenen",
"theme.docs.versions.latestVersionLinkLabel": "letzte Version", "theme.docs.versions.latestVersionLinkLabel": "letzte Version",
"theme.docs.versions.latestVersionSuggestionLabel": "Für die aktuellste Dokumentation bitte auf {latestVersionLink} ({versionLabel}) gehen.", "theme.docs.versions.latestVersionSuggestionLabel": "Für die aktuellste Dokumentation bitte auf {latestVersionLink} ({versionLabel}) gehen.",
"theme.docs.versions.unmaintainedVersionLabel": "Das ist die Dokumentation für {siteTitle} {versionLabel} und wird nicht weiter gewartet.", "theme.docs.versions.unmaintainedVersionLabel": "Das ist die Dokumentation für {siteTitle} {versionLabel} und wird nicht weiter gewartet.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " am {date}", "theme.lastUpdated.atDate": " am {date}",
"theme.lastUpdated.byUser": " von {user}", "theme.lastUpdated.byUser": " von {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Letztes Update{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Letztes Update{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsListLabel": "Tags:",
"theme.tags.tagsPageLink": "Alle Tags anzeigen", "theme.tags.tagsPageLink": "Alle Tags anzeigen",
"theme.tags.tagsPageTitle": "Tags" "theme.tags.tagsPageTitle": "Tags"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Buscar", "theme.SearchPage.inputLabel": "Buscar",
"theme.SearchPage.inputPlaceholder": "Escribe tu búsqueda aquí", "theme.SearchPage.inputPlaceholder": "Escribe tu búsqueda aquí",
"theme.SearchPage.noResultsText": "No se encontraron resultados", "theme.SearchPage.noResultsText": "No se encontraron resultados",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Navegación por la página de la lista de blogs ", "theme.blog.paginator.navAriaLabel": "Navegación por la página de la lista de blogs ",
"theme.blog.paginator.newerEntries": "Entradas más recientes", "theme.blog.paginator.newerEntries": "Entradas más recientes",
"theme.blog.paginator.olderEntries": "Entradas más antiguas", "theme.blog.paginator.olderEntries": "Entradas más antiguas",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral", "theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral",
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral", "theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral",
"theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral", "theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Cerrar menu",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Abrir menu",
"theme.docs.versions.latestVersionLinkLabel": "última versión", "theme.docs.versions.latestVersionLinkLabel": "última versión",
"theme.docs.versions.latestVersionSuggestionLabel": "Para documentación actualizada, ver {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Para documentación actualizada, ver {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Está es documentación para {siteTitle} {versionLabel}, que ya no se mantiene activamente.", "theme.docs.versions.unmaintainedVersionLabel": "Está es documentación para {siteTitle} {versionLabel}, que ya no se mantiene activamente.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " en {date}", "theme.lastUpdated.atDate": " en {date}",
"theme.lastUpdated.byUser": " por {user}", "theme.lastUpdated.byUser": " por {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Última actualización{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Última actualización{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Etiquetas:", "theme.tags.tagsListLabel": "Etiquetas:",
"theme.tags.tagsPageLink": "Ver Todas las Etiquetas", "theme.tags.tagsPageLink": "Ver Todas las Etiquetas",
"theme.tags.tagsPageTitle": "Etiquetas" "theme.tags.tagsPageTitle": "Etiquetas"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "جستجو", "theme.SearchPage.inputLabel": "جستجو",
"theme.SearchPage.inputPlaceholder": "عبارت مورد نظر را اینجا بنویسید", "theme.SearchPage.inputPlaceholder": "عبارت مورد نظر را اینجا بنویسید",
"theme.SearchPage.noResultsText": "هیچ نتیجه ای پیدا نشد", "theme.SearchPage.noResultsText": "هیچ نتیجه ای پیدا نشد",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "کنترل لیست صفحه وبسایت", "theme.blog.paginator.navAriaLabel": "کنترل لیست صفحه وبسایت",
"theme.blog.paginator.newerEntries": "مطالب جدیدتر", "theme.blog.paginator.newerEntries": "مطالب جدیدتر",
"theme.blog.paginator.olderEntries": "مطالب قدیمی تر", "theme.blog.paginator.olderEntries": "مطالب قدیمی تر",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "بستن نوار کناری", "theme.docs.sidebar.collapseButtonTitle": "بستن نوار کناری",
"theme.docs.sidebar.expandButtonAriaLabel": "بزرگ کردن نوار کناری", "theme.docs.sidebar.expandButtonAriaLabel": "بزرگ کردن نوار کناری",
"theme.docs.sidebar.expandButtonTitle": "بزرگ کردن نوار کناری", "theme.docs.sidebar.expandButtonTitle": "بزرگ کردن نوار کناری",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "بستن منو",
"theme.docs.sidebar.responsiveOpenButtonLabel": "باز کردن منو",
"theme.docs.versions.latestVersionLinkLabel": "آخرین نسخه", "theme.docs.versions.latestVersionLinkLabel": "آخرین نسخه",
"theme.docs.versions.latestVersionSuggestionLabel": "برای دیدن آخرین نسخه، {latestVersionLink} ({versionLabel}) را ببینید.", "theme.docs.versions.latestVersionSuggestionLabel": "برای دیدن آخرین نسخه، {latestVersionLink} ({versionLabel}) را ببینید.",
"theme.docs.versions.unmaintainedVersionLabel": "نسخه {siteTitle} {versionLabel} دیگر بروزرسانی نمی شود.", "theme.docs.versions.unmaintainedVersionLabel": "نسخه {siteTitle} {versionLabel} دیگر بروزرسانی نمی شود.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " در تاریخ {date}", "theme.lastUpdated.atDate": " در تاریخ {date}",
"theme.lastUpdated.byUser": " توسط {user}", "theme.lastUpdated.byUser": " توسط {user}",
"theme.lastUpdated.lastUpdatedAtBy": "آخرین به روزرسانی{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "آخرین به روزرسانی{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": ":برچسب ها", "theme.tags.tagsListLabel": ":برچسب ها",
"theme.tags.tagsPageLink": "مشاهده تمام برچسب ها", "theme.tags.tagsPageLink": "مشاهده تمام برچسب ها",
"theme.tags.tagsPageTitle": "برچسب ها" "theme.tags.tagsPageTitle": "برچسب ها"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Maghanap", "theme.SearchPage.inputLabel": "Maghanap",
"theme.SearchPage.inputPlaceholder": "I-type and inyong hinahanap dito", "theme.SearchPage.inputPlaceholder": "I-type and inyong hinahanap dito",
"theme.SearchPage.noResultsText": "Walang resultang nahanap", "theme.SearchPage.noResultsText": "Walang resultang nahanap",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Nabegasyón para sa pahina na listahan ng blog", "theme.blog.paginator.navAriaLabel": "Nabegasyón para sa pahina na listahan ng blog",
"theme.blog.paginator.newerEntries": "Mas bagong mga éntri", "theme.blog.paginator.newerEntries": "Mas bagong mga éntri",
"theme.blog.paginator.olderEntries": "Mas lumang mga éntri", "theme.blog.paginator.olderEntries": "Mas lumang mga éntri",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Itupî ang sidebar", "theme.docs.sidebar.collapseButtonTitle": "Itupî ang sidebar",
"theme.docs.sidebar.expandButtonAriaLabel": "Palakihin ang sidebar", "theme.docs.sidebar.expandButtonAriaLabel": "Palakihin ang sidebar",
"theme.docs.sidebar.expandButtonTitle": "Palakihin ang sidebar", "theme.docs.sidebar.expandButtonTitle": "Palakihin ang sidebar",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Isara ang menu",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Buksan ang menu",
"theme.docs.versions.latestVersionLinkLabel": "pinakahuling bersiyón", "theme.docs.versions.latestVersionLinkLabel": "pinakahuling bersiyón",
"theme.docs.versions.latestVersionSuggestionLabel": "Para sa up-to-date na dokumentasyón, tingnan ang {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Para sa up-to-date na dokumentasyón, tingnan ang {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Ito ay dokumentasyón para sa {siteTitle} {versionLabel} na hindi na aktibong mine-maintain.", "theme.docs.versions.unmaintainedVersionLabel": "Ito ay dokumentasyón para sa {siteTitle} {versionLabel} na hindi na aktibong mine-maintain.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " noong {date}", "theme.lastUpdated.atDate": " noong {date}",
"theme.lastUpdated.byUser": " ni {user}", "theme.lastUpdated.byUser": " ni {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Huling inapdeyt{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Huling inapdeyt{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Mga Tag:", "theme.tags.tagsListLabel": "Mga Tag:",
"theme.tags.tagsPageLink": "Tingnan Lahat ng mga Tag", "theme.tags.tagsPageLink": "Tingnan Lahat ng mga Tag",
"theme.tags.tagsPageTitle": "Mga Tag" "theme.tags.tagsPageTitle": "Mga Tag"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Chercher", "theme.SearchPage.inputLabel": "Chercher",
"theme.SearchPage.inputPlaceholder": "Tapez votre recherche ici", "theme.SearchPage.inputPlaceholder": "Tapez votre recherche ici",
"theme.SearchPage.noResultsText": "Aucun résultat trouvé", "theme.SearchPage.noResultsText": "Aucun résultat trouvé",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Pagination de la liste des articles du blog", "theme.blog.paginator.navAriaLabel": "Pagination de la liste des articles du blog",
"theme.blog.paginator.newerEntries": "Nouvelles entrées", "theme.blog.paginator.newerEntries": "Nouvelles entrées",
"theme.blog.paginator.olderEntries": "Anciennes entrées", "theme.blog.paginator.olderEntries": "Anciennes entrées",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Réduire le menu latéral", "theme.docs.sidebar.collapseButtonTitle": "Réduire le menu latéral",
"theme.docs.sidebar.expandButtonAriaLabel": "Déplier le menu latéral", "theme.docs.sidebar.expandButtonAriaLabel": "Déplier le menu latéral",
"theme.docs.sidebar.expandButtonTitle": "Déplier le menu latéral", "theme.docs.sidebar.expandButtonTitle": "Déplier le menu latéral",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Fermer le menu latéral",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Ouvrir le menu latéral",
"theme.docs.versions.latestVersionLinkLabel": "dernière version", "theme.docs.versions.latestVersionLinkLabel": "dernière version",
"theme.docs.versions.latestVersionSuggestionLabel": "Pour une documentation à jour, consultez la {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Pour une documentation à jour, consultez la {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Ceci est la documentation de {siteTitle} {versionLabel}, qui n'est plus activement maintenue.", "theme.docs.versions.unmaintainedVersionLabel": "Ceci est la documentation de {siteTitle} {versionLabel}, qui n'est plus activement maintenue.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " le {date}", "theme.lastUpdated.atDate": " le {date}",
"theme.lastUpdated.byUser": " par {user}", "theme.lastUpdated.byUser": " par {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Dernière mise à jour{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Dernière mise à jour{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Tags :", "theme.tags.tagsListLabel": "Tags :",
"theme.tags.tagsPageLink": "Voir tous les tags", "theme.tags.tagsPageLink": "Voir tous les tags",
"theme.tags.tagsPageTitle": "Tags" "theme.tags.tagsPageTitle": "Tags"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "חיפוש", "theme.SearchPage.inputLabel": "חיפוש",
"theme.SearchPage.inputPlaceholder": "הקלד כאן לחיפוש", "theme.SearchPage.inputPlaceholder": "הקלד כאן לחיפוש",
"theme.SearchPage.noResultsText": "לא נמצאו תוצאות", "theme.SearchPage.noResultsText": "לא נמצאו תוצאות",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "רשימת דפי הבלוג", "theme.blog.paginator.navAriaLabel": "רשימת דפי הבלוג",
"theme.blog.paginator.newerEntries": "הכי חדש", "theme.blog.paginator.newerEntries": "הכי חדש",
"theme.blog.paginator.olderEntries": "ישן יותר", "theme.blog.paginator.olderEntries": "ישן יותר",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "סגור", "theme.docs.sidebar.collapseButtonTitle": "סגור",
"theme.docs.sidebar.expandButtonAriaLabel": "פתח", "theme.docs.sidebar.expandButtonAriaLabel": "פתח",
"theme.docs.sidebar.expandButtonTitle": "פתח", "theme.docs.sidebar.expandButtonTitle": "פתח",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "סגור תפריט",
"theme.docs.sidebar.responsiveOpenButtonLabel": "פתח תפריט",
"theme.docs.versions.latestVersionLinkLabel": "גרסא אחרונה", "theme.docs.versions.latestVersionLinkLabel": "גרסא אחרונה",
"theme.docs.versions.latestVersionSuggestionLabel": "לדוקומנטאציה עדכנית, ראה {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "לדוקומנטאציה עדכנית, ראה {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "דוקומנטאציה זו {siteTitle} {versionLabel}, כבר לא נתמכת.", "theme.docs.versions.unmaintainedVersionLabel": "דוקומנטאציה זו {siteTitle} {versionLabel}, כבר לא נתמכת.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " בתאריך {date}", "theme.lastUpdated.atDate": " בתאריך {date}",
"theme.lastUpdated.byUser": " על ידי {user}", "theme.lastUpdated.byUser": " על ידי {user}",
"theme.lastUpdated.lastUpdatedAtBy": "עודכן{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "עודכן{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "תגיות:", "theme.tags.tagsListLabel": "תגיות:",
"theme.tags.tagsPageLink": "כל התגיות", "theme.tags.tagsPageLink": "כל התגיות",
"theme.tags.tagsPageTitle": "תגיות" "theme.tags.tagsPageTitle": "תגיות"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "खोज करें", "theme.SearchPage.inputLabel": "खोज करें",
"theme.SearchPage.inputPlaceholder": "अपनी खोज यहाँ टाइप करें", "theme.SearchPage.inputPlaceholder": "अपनी खोज यहाँ टाइप करें",
"theme.SearchPage.noResultsText": "कोई परिणाम नहीं मिलें", "theme.SearchPage.noResultsText": "कोई परिणाम नहीं मिलें",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "ब्लॉग सूची पेज नेविगेशन", "theme.blog.paginator.navAriaLabel": "ब्लॉग सूची पेज नेविगेशन",
"theme.blog.paginator.newerEntries": "नए एंट्रीज़", "theme.blog.paginator.newerEntries": "नए एंट्रीज़",
"theme.blog.paginator.olderEntries": "पुराने एंट्रीज़", "theme.blog.paginator.olderEntries": "पुराने एंट्रीज़",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "साइडबार बंद करें", "theme.docs.sidebar.collapseButtonTitle": "साइडबार बंद करें",
"theme.docs.sidebar.expandButtonAriaLabel": "साइडबार खोलें", "theme.docs.sidebar.expandButtonAriaLabel": "साइडबार खोलें",
"theme.docs.sidebar.expandButtonTitle": "साइडबार खोलें", "theme.docs.sidebar.expandButtonTitle": "साइडबार खोलें",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "मेन्यू बंद करें",
"theme.docs.sidebar.responsiveOpenButtonLabel": "मेन्यू खोलें",
"theme.docs.versions.latestVersionLinkLabel": "सबसे नया वर्जन", "theme.docs.versions.latestVersionLinkLabel": "सबसे नया वर्जन",
"theme.docs.versions.latestVersionSuggestionLabel": "अप-टू-डेट डॉक्यूमेंटेशन के लिए {latestVersionLink} ({versionLabel}) देखें।", "theme.docs.versions.latestVersionSuggestionLabel": "अप-टू-डेट डॉक्यूमेंटेशन के लिए {latestVersionLink} ({versionLabel}) देखें।",
"theme.docs.versions.unmaintainedVersionLabel": "यह {siteTitle} {versionLabel} के लिए डॉक्यूमेंटेशन है, जिसे अब सक्रिय रूप से नहीं बनाए रखा गया है।", "theme.docs.versions.unmaintainedVersionLabel": "यह {siteTitle} {versionLabel} के लिए डॉक्यूमेंटेशन है, जिसे अब सक्रिय रूप से नहीं बनाए रखा गया है।",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " {date} पर", "theme.lastUpdated.atDate": " {date} पर",
"theme.lastUpdated.byUser": " {user} द्वारा", "theme.lastUpdated.byUser": " {user} द्वारा",
"theme.lastUpdated.lastUpdatedAtBy": "आखरी अपडेट{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "आखरी अपडेट{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "टैग:", "theme.tags.tagsListLabel": "टैग:",
"theme.tags.tagsPageLink": "सारे टैग देखें", "theme.tags.tagsPageLink": "सारे टैग देखें",
"theme.tags.tagsPageTitle": "टैग" "theme.tags.tagsPageTitle": "टैग"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "検索", "theme.SearchPage.inputLabel": "検索",
"theme.SearchPage.inputPlaceholder": "ここに検索するキーワードを入力してください", "theme.SearchPage.inputPlaceholder": "ここに検索するキーワードを入力してください",
"theme.SearchPage.noResultsText": "検索結果が見つかりませんでした", "theme.SearchPage.noResultsText": "検索結果が見つかりませんでした",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "ブログ記事一覧のナビゲーション", "theme.blog.paginator.navAriaLabel": "ブログ記事一覧のナビゲーション",
"theme.blog.paginator.newerEntries": "新しい記事", "theme.blog.paginator.newerEntries": "新しい記事",
"theme.blog.paginator.olderEntries": "過去の記事", "theme.blog.paginator.olderEntries": "過去の記事",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "サイドバーを隠す", "theme.docs.sidebar.collapseButtonTitle": "サイドバーを隠す",
"theme.docs.sidebar.expandButtonAriaLabel": "サイドバーを開く", "theme.docs.sidebar.expandButtonAriaLabel": "サイドバーを開く",
"theme.docs.sidebar.expandButtonTitle": "サイドバーを開く", "theme.docs.sidebar.expandButtonTitle": "サイドバーを開く",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "メニューを閉じる",
"theme.docs.sidebar.responsiveOpenButtonLabel": "メニューを開く",
"theme.docs.versions.latestVersionLinkLabel": "最新バージョン", "theme.docs.versions.latestVersionLinkLabel": "最新バージョン",
"theme.docs.versions.latestVersionSuggestionLabel": "最新のドキュメントは{latestVersionLink} ({versionLabel}) を見てください。", "theme.docs.versions.latestVersionSuggestionLabel": "最新のドキュメントは{latestVersionLink} ({versionLabel}) を見てください。",
"theme.docs.versions.unmaintainedVersionLabel": "これは{siteTitle} {versionLabel}のドキュメントで現在はアクティブにメンテナンスされていません。", "theme.docs.versions.unmaintainedVersionLabel": "これは{siteTitle} {versionLabel}のドキュメントで現在はアクティブにメンテナンスされていません。",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": "{date}に", "theme.lastUpdated.atDate": "{date}に",
"theme.lastUpdated.byUser": "{user}が", "theme.lastUpdated.byUser": "{user}が",
"theme.lastUpdated.lastUpdatedAtBy": "{atDate}{byUser}最終更新", "theme.lastUpdated.lastUpdatedAtBy": "{atDate}{byUser}最終更新",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "タグ:", "theme.tags.tagsListLabel": "タグ:",
"theme.tags.tagsPageLink": "全てのタグを見る", "theme.tags.tagsPageLink": "全てのタグを見る",
"theme.tags.tagsPageTitle": "タグ" "theme.tags.tagsPageTitle": "タグ"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "검색", "theme.SearchPage.inputLabel": "검색",
"theme.SearchPage.inputPlaceholder": "여기에 검색할 키워드를 입력하세요.", "theme.SearchPage.inputPlaceholder": "여기에 검색할 키워드를 입력하세요.",
"theme.SearchPage.noResultsText": "검색 결과가 없습니다.", "theme.SearchPage.noResultsText": "검색 결과가 없습니다.",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "블로그 게시물 목록 탐색", "theme.blog.paginator.navAriaLabel": "블로그 게시물 목록 탐색",
"theme.blog.paginator.newerEntries": "이전 페이지", "theme.blog.paginator.newerEntries": "이전 페이지",
"theme.blog.paginator.olderEntries": "다음 페이지", "theme.blog.paginator.olderEntries": "다음 페이지",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "사이드바 숨기기", "theme.docs.sidebar.collapseButtonTitle": "사이드바 숨기기",
"theme.docs.sidebar.expandButtonAriaLabel": "사이드바 열기", "theme.docs.sidebar.expandButtonAriaLabel": "사이드바 열기",
"theme.docs.sidebar.expandButtonTitle": "사이드바 열기", "theme.docs.sidebar.expandButtonTitle": "사이드바 열기",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "메뉴 닫기",
"theme.docs.sidebar.responsiveOpenButtonLabel": "메뉴 열기",
"theme.docs.versions.latestVersionLinkLabel": "최신 버전", "theme.docs.versions.latestVersionLinkLabel": "최신 버전",
"theme.docs.versions.latestVersionSuggestionLabel": "최신 문서는 {latestVersionLink} ({versionLabel})을 확인하세요.", "theme.docs.versions.latestVersionSuggestionLabel": "최신 문서는 {latestVersionLink} ({versionLabel})을 확인하세요.",
"theme.docs.versions.unmaintainedVersionLabel": "{siteTitle} {versionLabel} 문서는 업데이트되지 않습니다.", "theme.docs.versions.unmaintainedVersionLabel": "{siteTitle} {versionLabel} 문서는 업데이트되지 않습니다.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " {date}에", "theme.lastUpdated.atDate": " {date}에",
"theme.lastUpdated.byUser": " {user}가", "theme.lastUpdated.byUser": " {user}가",
"theme.lastUpdated.lastUpdatedAtBy": "{atDate}{byUser} 마지막으로 업데이트했습니다.", "theme.lastUpdated.lastUpdatedAtBy": "{atDate}{byUser} 마지막으로 업데이트했습니다.",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "태그:", "theme.tags.tagsListLabel": "태그:",
"theme.tags.tagsPageLink": "모든 태그 보기", "theme.tags.tagsPageLink": "모든 태그 보기",
"theme.tags.tagsPageTitle": "태그" "theme.tags.tagsPageTitle": "태그"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Szukaj", "theme.SearchPage.inputLabel": "Szukaj",
"theme.SearchPage.inputPlaceholder": "wpisz szukaną frazę tutaj…", "theme.SearchPage.inputPlaceholder": "wpisz szukaną frazę tutaj…",
"theme.SearchPage.noResultsText": "Nie znaleziono żadnych wyników", "theme.SearchPage.noResultsText": "Nie znaleziono żadnych wyników",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Nawigacja na stronie listy wpisów na blogu", "theme.blog.paginator.navAriaLabel": "Nawigacja na stronie listy wpisów na blogu",
"theme.blog.paginator.newerEntries": "Nowsze wpisy", "theme.blog.paginator.newerEntries": "Nowsze wpisy",
"theme.blog.paginator.olderEntries": "Starsze wpisy", "theme.blog.paginator.olderEntries": "Starsze wpisy",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Zwiń boczny panel", "theme.docs.sidebar.collapseButtonTitle": "Zwiń boczny panel",
"theme.docs.sidebar.expandButtonAriaLabel": "Rozszerz boczny panel", "theme.docs.sidebar.expandButtonAriaLabel": "Rozszerz boczny panel",
"theme.docs.sidebar.expandButtonTitle": "Rozszerz boczny panel", "theme.docs.sidebar.expandButtonTitle": "Rozszerz boczny panel",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Zamknij menu",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Otwórz menu",
"theme.docs.versions.latestVersionLinkLabel": "bieżącej wersji", "theme.docs.versions.latestVersionLinkLabel": "bieżącej wersji",
"theme.docs.versions.latestVersionSuggestionLabel": "Aby zobaczyć bieżącą dokumentację, przejdź do wersji {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Aby zobaczyć bieżącą dokumentację, przejdź do wersji {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Ta dokumentacja dotyczy {siteTitle} w wersji {versionLabel} i nie jest już aktywnie aktualizowana.", "theme.docs.versions.unmaintainedVersionLabel": "Ta dokumentacja dotyczy {siteTitle} w wersji {versionLabel} i nie jest już aktywnie aktualizowana.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " dnia {date}", "theme.lastUpdated.atDate": " dnia {date}",
"theme.lastUpdated.byUser": " przez {user}", "theme.lastUpdated.byUser": " przez {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Ostatnia aktualizacja{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Ostatnia aktualizacja{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Tagi:", "theme.tags.tagsListLabel": "Tagi:",
"theme.tags.tagsPageLink": "Wyświetl wszystkie tagi", "theme.tags.tagsPageLink": "Wyświetl wszystkie tagi",
"theme.tags.tagsPageTitle": "Tagi" "theme.tags.tagsPageTitle": "Tagi"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Buscar", "theme.SearchPage.inputLabel": "Buscar",
"theme.SearchPage.inputPlaceholder": "Digite sua busca aqui", "theme.SearchPage.inputPlaceholder": "Digite sua busca aqui",
"theme.SearchPage.noResultsText": "Nenhum resultado foi encontrado", "theme.SearchPage.noResultsText": "Nenhum resultado foi encontrado",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Navegação da página de listagem do blog", "theme.blog.paginator.navAriaLabel": "Navegação da página de listagem do blog",
"theme.blog.paginator.newerEntries": "Conteúdo mais novo", "theme.blog.paginator.newerEntries": "Conteúdo mais novo",
"theme.blog.paginator.olderEntries": "Conteúdo mais antigo", "theme.blog.paginator.olderEntries": "Conteúdo mais antigo",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Fechar painel lateral", "theme.docs.sidebar.collapseButtonTitle": "Fechar painel lateral",
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir painel lateral", "theme.docs.sidebar.expandButtonAriaLabel": "Expandir painel lateral",
"theme.docs.sidebar.expandButtonTitle": "Expandir painel lateral", "theme.docs.sidebar.expandButtonTitle": "Expandir painel lateral",
"theme.docs.sidebar.navAriaLabel": "Navegação do painel lateral",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Fechar menu",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Abrir menu",
"theme.docs.versions.latestVersionLinkLabel": "última versão", "theme.docs.versions.latestVersionLinkLabel": "última versão",
"theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que não é mais mantida ativamente.", "theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que não é mais mantida ativamente.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " em {date}", "theme.lastUpdated.atDate": " em {date}",
"theme.lastUpdated.byUser": " por {user}", "theme.lastUpdated.byUser": " por {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Última atualização {atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Última atualização {atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Marcadores:", "theme.tags.tagsListLabel": "Marcadores:",
"theme.tags.tagsPageLink": "Ver todas os Marcadores", "theme.tags.tagsPageLink": "Ver todas os Marcadores",
"theme.tags.tagsPageTitle": "Marcadores" "theme.tags.tagsPageTitle": "Marcadores"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Pesquisar", "theme.SearchPage.inputLabel": "Pesquisar",
"theme.SearchPage.inputPlaceholder": "Escreva aqui a sua pesquisa", "theme.SearchPage.inputPlaceholder": "Escreva aqui a sua pesquisa",
"theme.SearchPage.noResultsText": "Nenhum resultado encontrado", "theme.SearchPage.noResultsText": "Nenhum resultado encontrado",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Navegação da página de listagem do blog", "theme.blog.paginator.navAriaLabel": "Navegação da página de listagem do blog",
"theme.blog.paginator.newerEntries": "Publicações mais recentes", "theme.blog.paginator.newerEntries": "Publicações mais recentes",
"theme.blog.paginator.olderEntries": "Publicações mais antigas", "theme.blog.paginator.olderEntries": "Publicações mais antigas",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral", "theme.docs.sidebar.collapseButtonTitle": "Colapsar barra lateral",
"theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral", "theme.docs.sidebar.expandButtonAriaLabel": "Expandir barra lateral",
"theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral", "theme.docs.sidebar.expandButtonTitle": "Expandir barra lateral",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Fechar menu",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Abrir menu",
"theme.docs.versions.latestVersionLinkLabel": "última versão", "theme.docs.versions.latestVersionLinkLabel": "última versão",
"theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Para a documentação atualizada, veja: {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que já não é mantida ativamente.", "theme.docs.versions.unmaintainedVersionLabel": "Esta é a documentação para {siteTitle} {versionLabel}, que já não é mantida ativamente.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " a {date}", "theme.lastUpdated.atDate": " a {date}",
"theme.lastUpdated.byUser": " por {user}", "theme.lastUpdated.byUser": " por {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Última atualização{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Última atualização{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Tags:", "theme.tags.tagsListLabel": "Tags:",
"theme.tags.tagsPageLink": "Ver todas as Tags", "theme.tags.tagsPageLink": "Ver todas as Tags",
"theme.tags.tagsPageTitle": "Tags" "theme.tags.tagsPageTitle": "Tags"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Поиск", "theme.SearchPage.inputLabel": "Поиск",
"theme.SearchPage.inputPlaceholder": "Введите фразу для поиска", "theme.SearchPage.inputPlaceholder": "Введите фразу для поиска",
"theme.SearchPage.noResultsText": "По запросу ничего не найдено", "theme.SearchPage.noResultsText": "По запросу ничего не найдено",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Навигация по странице списка блогов", "theme.blog.paginator.navAriaLabel": "Навигация по странице списка блогов",
"theme.blog.paginator.newerEntries": "Следующие записи", "theme.blog.paginator.newerEntries": "Следующие записи",
"theme.blog.paginator.olderEntries": "Предыдущие записи", "theme.blog.paginator.olderEntries": "Предыдущие записи",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Свернуть сайдбар", "theme.docs.sidebar.collapseButtonTitle": "Свернуть сайдбар",
"theme.docs.sidebar.expandButtonAriaLabel": "Развернуть сайдбар", "theme.docs.sidebar.expandButtonAriaLabel": "Развернуть сайдбар",
"theme.docs.sidebar.expandButtonTitle": "Развернуть сайдбар", "theme.docs.sidebar.expandButtonTitle": "Развернуть сайдбар",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Закрыть меню",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Открыть меню",
"theme.docs.versions.latestVersionLinkLabel": "последней версии", "theme.docs.versions.latestVersionLinkLabel": "последней версии",
"theme.docs.versions.latestVersionSuggestionLabel": "Актуальная документация находится на странице {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Актуальная документация находится на странице {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Это документация {siteTitle} для версии {versionLabel}, которая уже не поддерживается.", "theme.docs.versions.unmaintainedVersionLabel": "Это документация {siteTitle} для версии {versionLabel}, которая уже не поддерживается.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " {date}", "theme.lastUpdated.atDate": " {date}",
"theme.lastUpdated.byUser": " от {user}", "theme.lastUpdated.byUser": " от {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Последнее обновление{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Последнее обновление{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Теги:", "theme.tags.tagsListLabel": "Теги:",
"theme.tags.tagsPageLink": "Посмотреть все теги", "theme.tags.tagsPageLink": "Посмотреть все теги",
"theme.tags.tagsPageTitle": "Теги" "theme.tags.tagsPageTitle": "Теги"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Ara", "theme.SearchPage.inputLabel": "Ara",
"theme.SearchPage.inputPlaceholder": "Aramanızı buraya yazın", "theme.SearchPage.inputPlaceholder": "Aramanızı buraya yazın",
"theme.SearchPage.noResultsText": "Hiçbir sonuç bulunamadı", "theme.SearchPage.noResultsText": "Hiçbir sonuç bulunamadı",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Blog gönderi sayfası navigasyonu", "theme.blog.paginator.navAriaLabel": "Blog gönderi sayfası navigasyonu",
"theme.blog.paginator.newerEntries": "Yeni Girdiler", "theme.blog.paginator.newerEntries": "Yeni Girdiler",
"theme.blog.paginator.olderEntries": "Eski Girdiler", "theme.blog.paginator.olderEntries": "Eski Girdiler",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Kenar çubuğunu daralt", "theme.docs.sidebar.collapseButtonTitle": "Kenar çubuğunu daralt",
"theme.docs.sidebar.expandButtonAriaLabel": "Kenar çubuğunu genişlet", "theme.docs.sidebar.expandButtonAriaLabel": "Kenar çubuğunu genişlet",
"theme.docs.sidebar.expandButtonTitle": "Kenar çubuğunu genişlet", "theme.docs.sidebar.expandButtonTitle": "Kenar çubuğunu genişlet",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Menüyü kapat",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Menüyü aç",
"theme.docs.versions.latestVersionLinkLabel": "en son sürüm", "theme.docs.versions.latestVersionLinkLabel": "en son sürüm",
"theme.docs.versions.latestVersionSuggestionLabel": "Güncel belgeler için bkz. {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Güncel belgeler için bkz. {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Bu, {siteTitle} {versionLabel} dokümantasyonudur ve bakımı sonlanmıştır.", "theme.docs.versions.unmaintainedVersionLabel": "Bu, {siteTitle} {versionLabel} dokümantasyonudur ve bakımı sonlanmıştır.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " {date} tarihinde", "theme.lastUpdated.atDate": " {date} tarihinde",
"theme.lastUpdated.byUser": " {user} tarafından", "theme.lastUpdated.byUser": " {user} tarafından",
"theme.lastUpdated.lastUpdatedAtBy": "En son{atDate}{byUser} güncellendi", "theme.lastUpdated.lastUpdatedAtBy": "En son{atDate}{byUser} güncellendi",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Etiketler:", "theme.tags.tagsListLabel": "Etiketler:",
"theme.tags.tagsPageLink": "Tüm Etiketleri Görüntüle", "theme.tags.tagsPageLink": "Tüm Etiketleri Görüntüle",
"theme.tags.tagsPageTitle": "Etiketler" "theme.tags.tagsPageTitle": "Etiketler"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "Tìm kiếm", "theme.SearchPage.inputLabel": "Tìm kiếm",
"theme.SearchPage.inputPlaceholder": "Nhập từ khóa cần tìm vào đây", "theme.SearchPage.inputPlaceholder": "Nhập từ khóa cần tìm vào đây",
"theme.SearchPage.noResultsText": "Không tìm thấy kết quả nào", "theme.SearchPage.noResultsText": "Không tìm thấy kết quả nào",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "Thanh điều hướng của trang danh sách bài viết", "theme.blog.paginator.navAriaLabel": "Thanh điều hướng của trang danh sách bài viết",
"theme.blog.paginator.newerEntries": "Các bài mới hơn", "theme.blog.paginator.newerEntries": "Các bài mới hơn",
"theme.blog.paginator.olderEntries": "Các bài cũ hơn", "theme.blog.paginator.olderEntries": "Các bài cũ hơn",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "Thu gọn thanh bên", "theme.docs.sidebar.collapseButtonTitle": "Thu gọn thanh bên",
"theme.docs.sidebar.expandButtonAriaLabel": "Mở rộng thanh bên", "theme.docs.sidebar.expandButtonAriaLabel": "Mở rộng thanh bên",
"theme.docs.sidebar.expandButtonTitle": "Mở rộng thanh bên", "theme.docs.sidebar.expandButtonTitle": "Mở rộng thanh bên",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "Đóng menu",
"theme.docs.sidebar.responsiveOpenButtonLabel": "Mở menu",
"theme.docs.versions.latestVersionLinkLabel": "phiên bản mới nhất", "theme.docs.versions.latestVersionLinkLabel": "phiên bản mới nhất",
"theme.docs.versions.latestVersionSuggestionLabel": "Để xem các cập nhật mới nhất, vui lòng xem phiên bản {latestVersionLink} ({versionLabel}).", "theme.docs.versions.latestVersionSuggestionLabel": "Để xem các cập nhật mới nhất, vui lòng xem phiên bản {latestVersionLink} ({versionLabel}).",
"theme.docs.versions.unmaintainedVersionLabel": "Đây là tài liệu của {siteTitle} {versionLabel}, hiện không còn được bảo trì.", "theme.docs.versions.unmaintainedVersionLabel": "Đây là tài liệu của {siteTitle} {versionLabel}, hiện không còn được bảo trì.",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": " vào {date}", "theme.lastUpdated.atDate": " vào {date}",
"theme.lastUpdated.byUser": " bởi {user}", "theme.lastUpdated.byUser": " bởi {user}",
"theme.lastUpdated.lastUpdatedAtBy": "Cập nhật lần cuối{atDate}{byUser}", "theme.lastUpdated.lastUpdatedAtBy": "Cập nhật lần cuối{atDate}{byUser}",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "Thẻ:", "theme.tags.tagsListLabel": "Thẻ:",
"theme.tags.tagsPageLink": "Xem tất cả Thẻ", "theme.tags.tagsPageLink": "Xem tất cả Thẻ",
"theme.tags.tagsPageTitle": "Thẻ" "theme.tags.tagsPageTitle": "Thẻ"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "搜索", "theme.SearchPage.inputLabel": "搜索",
"theme.SearchPage.inputPlaceholder": "在此输入搜索字词", "theme.SearchPage.inputPlaceholder": "在此输入搜索字词",
"theme.SearchPage.noResultsText": "未找到任何结果", "theme.SearchPage.noResultsText": "未找到任何结果",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "博文列表分页导航", "theme.blog.paginator.navAriaLabel": "博文列表分页导航",
"theme.blog.paginator.newerEntries": "较新的博文", "theme.blog.paginator.newerEntries": "较新的博文",
"theme.blog.paginator.olderEntries": "较旧的博文", "theme.blog.paginator.olderEntries": "较旧的博文",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "收起侧边栏", "theme.docs.sidebar.collapseButtonTitle": "收起侧边栏",
"theme.docs.sidebar.expandButtonAriaLabel": "展开侧边栏", "theme.docs.sidebar.expandButtonAriaLabel": "展开侧边栏",
"theme.docs.sidebar.expandButtonTitle": "展开侧边栏", "theme.docs.sidebar.expandButtonTitle": "展开侧边栏",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "关闭菜单",
"theme.docs.sidebar.responsiveOpenButtonLabel": "打开菜单",
"theme.docs.versions.latestVersionLinkLabel": "最新版本", "theme.docs.versions.latestVersionLinkLabel": "最新版本",
"theme.docs.versions.latestVersionSuggestionLabel": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。", "theme.docs.versions.latestVersionSuggestionLabel": "最新的文档请参阅 {latestVersionLink} ({versionLabel})。",
"theme.docs.versions.unmaintainedVersionLabel": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。", "theme.docs.versions.unmaintainedVersionLabel": "此为 {siteTitle} {versionLabel} 版的文档,现已不再积极维护。",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": "于 {date} ", "theme.lastUpdated.atDate": "于 {date} ",
"theme.lastUpdated.byUser": "由 {user} ", "theme.lastUpdated.byUser": "由 {user} ",
"theme.lastUpdated.lastUpdatedAtBy": "最后{byUser}{atDate}更新", "theme.lastUpdated.lastUpdatedAtBy": "最后{byUser}{atDate}更新",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "标签:", "theme.tags.tagsListLabel": "标签:",
"theme.tags.tagsPageLink": "查看所有标签", "theme.tags.tagsPageLink": "查看所有标签",
"theme.tags.tagsPageTitle": "标签" "theme.tags.tagsPageTitle": "标签"

View file

@ -20,6 +20,7 @@
"theme.SearchPage.inputLabel": "搜尋", "theme.SearchPage.inputLabel": "搜尋",
"theme.SearchPage.inputPlaceholder": "在此輸入搜尋字詞", "theme.SearchPage.inputPlaceholder": "在此輸入搜尋字詞",
"theme.SearchPage.noResultsText": "未找到任何結果", "theme.SearchPage.noResultsText": "未找到任何結果",
"theme.TOCCollapsible.toggleButtonLabel": "On this page",
"theme.blog.paginator.navAriaLabel": "部落格文章列表分頁導覽", "theme.blog.paginator.navAriaLabel": "部落格文章列表分頁導覽",
"theme.blog.paginator.newerEntries": "較新的文章", "theme.blog.paginator.newerEntries": "較新的文章",
"theme.blog.paginator.olderEntries": "較舊的文章", "theme.blog.paginator.olderEntries": "較舊的文章",
@ -41,9 +42,6 @@
"theme.docs.sidebar.collapseButtonTitle": "收起側邊欄", "theme.docs.sidebar.collapseButtonTitle": "收起側邊欄",
"theme.docs.sidebar.expandButtonAriaLabel": "展開側邊欄", "theme.docs.sidebar.expandButtonAriaLabel": "展開側邊欄",
"theme.docs.sidebar.expandButtonTitle": "展開側邊欄", "theme.docs.sidebar.expandButtonTitle": "展開側邊欄",
"theme.docs.sidebar.navAriaLabel": "Sidebar navigation",
"theme.docs.sidebar.responsiveCloseButtonLabel": "關閉選單",
"theme.docs.sidebar.responsiveOpenButtonLabel": "打開選單",
"theme.docs.versions.latestVersionLinkLabel": "最新版本", "theme.docs.versions.latestVersionLinkLabel": "最新版本",
"theme.docs.versions.latestVersionSuggestionLabel": "最新的文件請參閱 {latestVersionLink} ({versionLabel})。", "theme.docs.versions.latestVersionSuggestionLabel": "最新的文件請參閱 {latestVersionLink} ({versionLabel})。",
"theme.docs.versions.unmaintainedVersionLabel": "此為 {siteTitle} {versionLabel} 版的文件,現已不再積極維護。", "theme.docs.versions.unmaintainedVersionLabel": "此為 {siteTitle} {versionLabel} 版的文件,現已不再積極維護。",
@ -51,6 +49,7 @@
"theme.lastUpdated.atDate": "於 {date} ", "theme.lastUpdated.atDate": "於 {date} ",
"theme.lastUpdated.byUser": "由 {user} ", "theme.lastUpdated.byUser": "由 {user} ",
"theme.lastUpdated.lastUpdatedAtBy": "最後{byUser}{atDate}更新", "theme.lastUpdated.lastUpdatedAtBy": "最後{byUser}{atDate}更新",
"theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel": "← Back to main menu",
"theme.tags.tagsListLabel": "標籤:", "theme.tags.tagsListLabel": "標籤:",
"theme.tags.tagsPageLink": "查看所有標籤", "theme.tags.tagsPageLink": "查看所有標籤",
"theme.tags.tagsPageTitle": "標籤" "theme.tags.tagsPageTitle": "標籤"

View file

@ -6,18 +6,21 @@
*/ */
import React from 'react'; import React from 'react';
import clsx from 'clsx';
import {useActivePlugin, useVersions} from '@theme/hooks/useDocs';
import useWindowSize from '@theme/hooks/useWindowSize';
import DocPaginator from '@theme/DocPaginator'; import DocPaginator from '@theme/DocPaginator';
import DocVersionBanner from '@theme/DocVersionBanner'; import DocVersionBanner from '@theme/DocVersionBanner';
import Seo from '@theme/Seo'; import Seo from '@theme/Seo';
import LastUpdated from '@theme/LastUpdated'; import LastUpdated from '@theme/LastUpdated';
import type {Props} from '@theme/DocItem'; import type {Props} from '@theme/DocItem';
import TOC from '@theme/TOC'; import TOC from '@theme/TOC';
import TOCCollapsible from '@theme/TOCCollapsible';
import EditThisPage from '@theme/EditThisPage'; import EditThisPage from '@theme/EditThisPage';
import {MainHeading} from '@theme/Heading'; import {MainHeading} from '@theme/Heading';
import clsx from 'clsx';
import styles from './styles.module.css'; import styles from './styles.module.css';
import {useActivePlugin, useVersions} from '@theme/hooks/useDocs';
function DocItem(props: Props): JSX.Element { function DocItem(props: Props): JSX.Element {
const {content: DocContent, versionMetadata} = props; const {content: DocContent, versionMetadata} = props;
@ -51,6 +54,18 @@ function DocItem(props: Props): JSX.Element {
const shouldAddTitle = const shouldAddTitle =
!hideTitle && typeof DocContent.contentTitle === 'undefined'; !hideTitle && typeof DocContent.contentTitle === 'undefined';
const windowSize = useWindowSize();
const renderTocMobile =
!hideTableOfContents &&
DocContent.toc &&
(windowSize === 'mobile' || windowSize === 'ssr');
const renderTocDesktop =
!hideTableOfContents &&
DocContent.toc &&
(windowSize === 'desktop' || windowSize === 'ssr');
return ( return (
<> <>
<Seo {...{title, description, keywords, image}} /> <Seo {...{title, description, keywords, image}} />
@ -69,6 +84,13 @@ function DocItem(props: Props): JSX.Element {
</span> </span>
)} )}
{renderTocMobile && (
<TOCCollapsible
toc={DocContent.toc}
className={styles.tocMobile}
/>
)}
<div className="markdown"> <div className="markdown">
{/* {/*
Title can be declared inside md content or declared through frontmatter and added manually Title can be declared inside md content or declared through frontmatter and added manually
@ -102,7 +124,7 @@ function DocItem(props: Props): JSX.Element {
<DocPaginator metadata={metadata} /> <DocPaginator metadata={metadata} />
</div> </div>
</div> </div>
{!hideTableOfContents && DocContent.toc && ( {renderTocDesktop && (
<div className="col col--3"> <div className="col col--3">
<TOC toc={DocContent.toc} /> <TOC toc={DocContent.toc} />
</div> </div>

View file

@ -23,4 +23,9 @@
.lastUpdated { .lastUpdated {
text-align: right; text-align: right;
} }
/* Prevent hydration FOUC, as the mobile TOC needs to be server-rendered */
.tocMobile {
display: none;
}
} }

View file

@ -31,28 +31,6 @@ type DocPageContentProps = {
readonly children: ReactNode; readonly children: ReactNode;
}; };
function getSidebar({versionMetadata, currentDocRoute}) {
function addTrailingSlash(str: string): string {
return str.endsWith('/') ? str : `${str}/`;
}
function removeTrailingSlash(str: string): string {
return str.endsWith('/') ? str.slice(0, -1) : str;
}
const {permalinkToSidebar, docsSidebars} = versionMetadata;
// With/without trailingSlash, we should always be able to get the appropriate sidebar
// note: docs plugin permalinks currently never have trailing slashes
// trailingSlash is handled globally at the framework level, not plugin level
const sidebarName =
permalinkToSidebar[currentDocRoute.path] ||
permalinkToSidebar[addTrailingSlash(currentDocRoute.path)] ||
permalinkToSidebar[removeTrailingSlash(currentDocRoute.path)];
const sidebar = docsSidebars[sidebarName];
return {sidebar, sidebarName};
}
function DocPageContent({ function DocPageContent({
currentDocRoute, currentDocRoute,
versionMetadata, versionMetadata,
@ -60,7 +38,11 @@ function DocPageContent({
}: DocPageContentProps): JSX.Element { }: DocPageContentProps): JSX.Element {
const {siteConfig, isClient} = useDocusaurusContext(); const {siteConfig, isClient} = useDocusaurusContext();
const {pluginId, version} = versionMetadata; const {pluginId, version} = versionMetadata;
const {sidebarName, sidebar} = getSidebar({versionMetadata, currentDocRoute});
const sidebarName = currentDocRoute.sidebar;
const sidebar = sidebarName
? versionMetadata.docsSidebars[sidebarName]
: undefined;
const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false); const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false);
const [hiddenSidebar, setHiddenSidebar] = useState(false); const [hiddenSidebar, setHiddenSidebar] = useState(false);
@ -106,9 +88,7 @@ function DocPageContent({
} }
sidebar={sidebar} sidebar={sidebar}
path={currentDocRoute.path} path={currentDocRoute.path}
sidebarCollapsible={ sidebarCollapsible={siteConfig.themeConfig.sidebarCollapsible}
siteConfig.themeConfig?.sidebarCollapsible ?? true
}
onCollapse={toggleSidebar} onCollapse={toggleSidebar}
isHidden={hiddenSidebar} isHidden={hiddenSidebar}
/> />

View file

@ -20,6 +20,10 @@
width: 100%; width: 100%;
} }
.docSidebarContainer {
display: none;
}
@media (min-width: 997px) { @media (min-width: 997px) {
.docMainContainer { .docMainContainer {
flex-grow: 1; flex-grow: 1;
@ -31,6 +35,7 @@
} }
.docSidebarContainer { .docSidebarContainer {
display: block;
width: var(--doc-sidebar-width); width: var(--doc-sidebar-width);
margin-top: calc(-1 * var(--ifm-navbar-height)); margin-top: calc(-1 * var(--ifm-navbar-height));
border-right: 1px solid var(--ifm-toc-border-color); border-right: 1px solid var(--ifm-toc-border-color);

View file

@ -5,175 +5,24 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import React, {useState, useCallback, useEffect, memo} from 'react'; import React, {useState} from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import { import {
useThemeConfig, useThemeConfig,
isSamePath,
usePrevious,
useAnnouncementBar, useAnnouncementBar,
useCollapsible, MobileSecondaryMenuFiller,
MobileSecondaryMenuComponent,
} from '@docusaurus/theme-common'; } from '@docusaurus/theme-common';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll'; import useWindowSize from '@theme/hooks/useWindowSize';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize';
import useScrollPosition from '@theme/hooks/useScrollPosition'; import useScrollPosition from '@theme/hooks/useScrollPosition';
import Link from '@docusaurus/Link';
import isInternalUrl from '@docusaurus/isInternalUrl';
import type {Props} from '@theme/DocSidebar';
import Logo from '@theme/Logo'; import Logo from '@theme/Logo';
import IconArrow from '@theme/IconArrow'; import IconArrow from '@theme/IconArrow';
import IconMenu from '@theme/IconMenu';
import IconExternalLink from '@theme/IconExternalLink';
import {translate} from '@docusaurus/Translate'; import {translate} from '@docusaurus/Translate';
import {DocSidebarItems} from '@theme/DocSidebarItem';
import type {Props} from '@theme/DocSidebar';
import styles from './styles.module.css'; import styles from './styles.module.css';
const MOBILE_TOGGLE_SIZE = 24;
const isActiveSidebarItem = (item, activePath) => {
if (item.type === 'link') {
return isSamePath(item.href, activePath);
}
if (item.type === 'category') {
return item.items.some((subItem) =>
isActiveSidebarItem(subItem, activePath),
);
}
return false;
};
// Optimize sidebar at each "level"
// TODO this item should probably not receive the "activePath" props
// TODO this triggers whole sidebar re-renders on navigation
const DocSidebarItems = memo(function DocSidebarItems({
items,
...props
}: any): JSX.Element {
return items.map((item, index) => (
<DocSidebarItem
key={index} // sidebar is static, the index does not change
item={item}
{...props}
/>
));
});
function DocSidebarItem(props): JSX.Element | null {
switch (props.item.type) {
case 'category':
// Never render empty categories
if (props.item.items.length === 0) {
return null;
}
return <DocSidebarItemCategory {...props} />;
case 'link':
default:
return <DocSidebarItemLink {...props} />;
}
}
function DocSidebarItemCategory({
item,
onItemClick,
collapsible,
activePath,
...props
}) {
const {items, label} = item;
const isActive = isActiveSidebarItem(item, activePath);
const wasActive = usePrevious(isActive);
const {
collapsed,
setCollapsed,
getToggleProps,
getCollapsibleProps,
} = useCollapsible({
// active categories are always initialized as expanded
// the default (item.collapsed) is only used for non-active categories
initialState: () => {
if (!collapsible) {
return false;
}
return isActive ? false : item.collapsed;
},
});
// If we navigate to a category, it should automatically expand itself
useEffect(() => {
const justBecameActive = isActive && !wasActive;
if (justBecameActive && collapsed) {
setCollapsed(false);
}
}, [isActive, wasActive, collapsed]);
return (
<li
className={clsx('menu__list-item', {
'menu__list-item--collapsed': collapsed,
})}>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a
className={clsx('menu__link', {
'menu__link--sublist': collapsible,
'menu__link--active': collapsible && isActive,
[styles.menuLinkText]: !collapsible,
})}
href={collapsible ? '#' : undefined}
{...getToggleProps()}
{...props}>
{label}
</a>
<ul className="menu__list" {...getCollapsibleProps()}>
<DocSidebarItems
items={items}
tabIndex={collapsed ? '-1' : '0'}
onItemClick={onItemClick}
collapsible={collapsible}
activePath={activePath}
/>
</ul>
</li>
);
}
function DocSidebarItemLink({
item,
onItemClick,
activePath,
collapsible: _collapsible,
...props
}) {
const {href, label} = item;
const isActive = isActiveSidebarItem(item, activePath);
return (
<li className="menu__list-item" key={label}>
<Link
className={clsx('menu__link', {
'menu__link--active': isActive,
})}
to={href}
{...(isInternalUrl(href) && {
isNavLink: true,
exact: true,
onClick: onItemClick,
})}
{...props}>
{isInternalUrl(href) ? (
label
) : (
<span>
{label}
<IconExternalLink />
</span>
)}
</Link>
</li>
);
}
function useShowAnnouncementBar() { function useShowAnnouncementBar() {
const {isClosed} = useAnnouncementBar(); const {isClosed} = useAnnouncementBar();
const [showAnnouncementBar, setShowAnnouncementBar] = useState(!isClosed); const [showAnnouncementBar, setShowAnnouncementBar] = useState(!isClosed);
@ -185,36 +34,6 @@ function useShowAnnouncementBar() {
return showAnnouncementBar; return showAnnouncementBar;
} }
function useResponsiveSidebar() {
const [showResponsiveSidebar, setShowResponsiveSidebar] = useState(false);
useLockBodyScroll(showResponsiveSidebar);
const windowSize = useWindowSize();
useEffect(() => {
if (windowSize === windowSizes.desktop) {
setShowResponsiveSidebar(false);
}
}, [windowSize]);
const closeResponsiveSidebar = useCallback(
(e) => {
e.target.blur();
setShowResponsiveSidebar(false);
},
[setShowResponsiveSidebar],
);
const toggleResponsiveSidebar = useCallback(() => {
setShowResponsiveSidebar((value) => !value);
}, [setShowResponsiveSidebar]);
return {
showResponsiveSidebar,
closeResponsiveSidebar,
toggleResponsiveSidebar,
};
}
function HideableSidebarButton({onClick}) { function HideableSidebarButton({onClick}) {
return ( return (
<button <button
@ -239,51 +58,13 @@ function HideableSidebarButton({onClick}) {
); );
} }
function ResponsiveSidebarButton({responsiveSidebarOpened, onClick}) { function DocSidebarDesktop({
return (
<button
aria-label={
responsiveSidebarOpened
? translate({
id: 'theme.docs.sidebar.responsiveCloseButtonLabel',
message: 'Close menu',
description:
'The ARIA label for close button of mobile doc sidebar',
})
: translate({
id: 'theme.docs.sidebar.responsiveOpenButtonLabel',
message: 'Open menu',
description:
'The ARIA label for open button of mobile doc sidebar',
})
}
aria-haspopup="true"
className="button button--secondary button--sm menu__button"
type="button"
onClick={onClick}>
{responsiveSidebarOpened ? (
<span
className={clsx(styles.sidebarMenuIcon, styles.sidebarMenuCloseIcon)}>
&times;
</span>
) : (
<IconMenu
className={styles.sidebarMenuIcon}
height={MOBILE_TOGGLE_SIZE}
width={MOBILE_TOGGLE_SIZE}
/>
)}
</button>
);
}
function DocSidebar({
path, path,
sidebar, sidebar,
sidebarCollapsible = true, sidebarCollapsible,
onCollapse, onCollapse,
isHidden, isHidden,
}: Props): JSX.Element | null { }: Props) {
const showAnnouncementBar = useShowAnnouncementBar(); const showAnnouncementBar = useShowAnnouncementBar();
const { const {
navbar: {hideOnScroll}, navbar: {hideOnScroll},
@ -291,12 +72,6 @@ function DocSidebar({
} = useThemeConfig(); } = useThemeConfig();
const {isClosed: isAnnouncementBarClosed} = useAnnouncementBar(); const {isClosed: isAnnouncementBarClosed} = useAnnouncementBar();
const {
showResponsiveSidebar,
closeResponsiveSidebar,
toggleResponsiveSidebar,
} = useResponsiveSidebar();
return ( return (
<div <div
className={clsx(styles.sidebar, { className={clsx(styles.sidebar, {
@ -305,31 +80,13 @@ function DocSidebar({
})}> })}>
{hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />} {hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />}
<nav <nav
className={clsx( className={clsx('menu thin-scrollbar', styles.menu, {
'menu', [styles.menuWithAnnouncementBar]:
'menu--responsive', !isAnnouncementBarClosed && showAnnouncementBar,
'thin-scrollbar',
styles.menu,
{
'menu--show': showResponsiveSidebar,
[styles.menuWithAnnouncementBar]:
!isAnnouncementBarClosed && showAnnouncementBar,
},
)}
aria-label={translate({
id: 'theme.docs.sidebar.navAriaLabel',
message: 'Sidebar navigation',
description: 'The ARIA label for documentation menu',
})}> })}>
<ResponsiveSidebarButton
responsiveSidebarOpened={showResponsiveSidebar}
onClick={toggleResponsiveSidebar}
/>
<ul className="menu__list"> <ul className="menu__list">
<DocSidebarItems <DocSidebarItems
items={sidebar} items={sidebar}
onItemClick={closeResponsiveSidebar}
collapsible={sidebarCollapsible} collapsible={sidebarCollapsible}
activePath={path} activePath={path}
/> />
@ -340,4 +97,50 @@ function DocSidebar({
); );
} }
export default DocSidebar; const DocSidebarMobileSecondaryMenu: MobileSecondaryMenuComponent<Props> = ({
toggleSidebar,
sidebar,
sidebarCollapsible,
path,
}) => {
return (
<ul className="menu__list">
<DocSidebarItems
items={sidebar}
collapsible={sidebarCollapsible}
activePath={path}
onItemClick={() => toggleSidebar()}
/>
</ul>
);
};
function DocSidebarMobile(props: Props) {
return (
<MobileSecondaryMenuFiller
component={DocSidebarMobileSecondaryMenu}
props={props}
/>
);
}
const DocSidebarDesktopMemo = React.memo(DocSidebarDesktop);
const DocSidebarMobileMemo = React.memo(DocSidebarMobile);
export default function DocSidebar(props: Props): JSX.Element {
const windowSize = useWindowSize();
// Desktop sidebar visible on hydration: need SSR rendering
const shouldRenderSidebarDesktop =
windowSize === 'desktop' || windowSize === 'ssr';
// Mobile sidebar not visible on hydration: can avoid SSR rendering
const shouldRenderSidebarMobile = windowSize === 'mobile';
return (
<>
{shouldRenderSidebarDesktop && <DocSidebarDesktopMemo {...props} />}
{shouldRenderSidebarMobile && <DocSidebarMobileMemo {...props} />}
</>
);
}

View file

@ -53,14 +53,6 @@
padding: 0.5rem; padding: 0.5rem;
} }
.menuLinkText {
cursor: initial;
}
.menuLinkText:hover {
background: none;
}
.menuWithAnnouncementBar { .menuWithAnnouncementBar {
margin-bottom: var(--docusaurus-announcement-bar-height); margin-bottom: var(--docusaurus-announcement-bar-height);
} }

View file

@ -0,0 +1,183 @@
/**
* 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, {useEffect, memo} from 'react';
import clsx from 'clsx';
import {
isSamePath,
usePrevious,
Collapsible,
useCollapsible,
} from '@docusaurus/theme-common';
import Link from '@docusaurus/Link';
import isInternalUrl from '@docusaurus/isInternalUrl';
import IconExternalLink from '@theme/IconExternalLink';
import type {Props, DocSidebarItemsProps} from '@theme/DocSidebarItem';
import type {
PropSidebarItemCategory,
PropSidebarItemLink,
} from '@docusaurus/plugin-content-docs-types';
import styles from './styles.module.css';
const isActiveSidebarItem = (item: Props['item'], activePath: string) => {
if (item.type === 'link') {
return isSamePath(item.href, activePath);
}
if (item.type === 'category') {
return item.items.some((subItem) =>
isActiveSidebarItem(subItem, activePath),
);
}
return false;
};
// Optimize sidebar at each "level"
// TODO this item should probably not receive the "activePath" props
// TODO this triggers whole sidebar re-renders on navigation
export const DocSidebarItems = memo(function DocSidebarItems({
items,
...props
}: DocSidebarItemsProps): JSX.Element {
return (
<>
{items.map((item, index) => (
<DocSidebarItem
key={index} // sidebar is static, the index does not change
item={item}
{...props}
/>
))}
</>
);
});
export default function DocSidebarItem({
item,
...props
}: Props): JSX.Element | null {
switch (item.type) {
case 'category':
if (item.items.length === 0) {
return null;
}
return <DocSidebarItemCategory item={item} {...props} />;
case 'link':
default:
return <DocSidebarItemLink item={item} {...props} />;
}
}
// If we navigate to a category and it becomes active, it should automatically expand itself
function useAutoExpandActiveCategory({
isActive,
collapsed,
setCollapsed,
}: {
isActive: boolean;
collapsed: boolean;
setCollapsed: (b: boolean) => void;
}) {
const wasActive = usePrevious(isActive);
useEffect(() => {
const justBecameActive = isActive && !wasActive;
if (justBecameActive && collapsed) {
setCollapsed(false);
}
}, [isActive, wasActive, collapsed]);
}
function DocSidebarItemCategory({
item,
onItemClick,
collapsible = true,
activePath,
...props
}: Props & {item: PropSidebarItemCategory}) {
const {items, label} = item;
const isActive = isActiveSidebarItem(item, activePath);
const {collapsed, setCollapsed, toggleCollapsed} = useCollapsible({
// active categories are always initialized as expanded
// the default (item.collapsed) is only used for non-active categories
initialState: () => {
if (!collapsible) {
return false;
}
return isActive ? false : item.collapsed ?? true;
},
});
useAutoExpandActiveCategory({isActive, collapsed, setCollapsed});
return (
<li
className={clsx('menu__list-item', {
'menu__list-item--collapsed': collapsed,
})}>
{/* eslint-disable-next-line jsx-a11y/anchor-is-valid */}
<a
className={clsx('menu__link', {
'menu__link--sublist': collapsible,
'menu__link--active': collapsible && isActive,
[styles.menuLinkText]: !collapsible,
})}
onClick={collapsible ? toggleCollapsed : undefined}
href={collapsible ? '#' : undefined}
{...props}>
{label}
</a>
<Collapsible as="ul" className="menu__list" collapsed={collapsed}>
<DocSidebarItems
items={items}
tabIndex={collapsed ? -1 : 0}
onItemClick={onItemClick}
collapsible={collapsible}
activePath={activePath}
/>
</Collapsible>
</li>
);
}
function DocSidebarItemLink({
item,
onItemClick,
activePath,
collapsible: _collapsible,
...props
}: Props & {item: PropSidebarItemLink}) {
const {href, label} = item;
const isActive = isActiveSidebarItem(item, activePath);
return (
<li className="menu__list-item" key={label}>
<Link
className={clsx('menu__link', {
'menu__link--active': isActive,
})}
to={href}
{...(isInternalUrl(href) && {
isNavLink: true,
exact: true,
onClick: onItemClick,
})}
{...props}>
{isInternalUrl(href) ? (
label
) : (
<span>
{label}
<IconExternalLink />
</span>
)}
</Link>
</li>
);
}

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.
*/
@media (min-width: 997px) {
.menuLinkText {
cursor: initial;
}
.menuLinkText:hover {
background: none;
}
}

View file

@ -11,6 +11,7 @@ import UserPreferencesProvider from '@theme/UserPreferencesProvider';
import { import {
AnnouncementBarProvider, AnnouncementBarProvider,
DocsPreferredVersionContextProvider, DocsPreferredVersionContextProvider,
MobileSecondaryMenuProvider,
} from '@docusaurus/theme-common'; } from '@docusaurus/theme-common';
import type {Props} from '@theme/LayoutProviders'; import type {Props} from '@theme/LayoutProviders';
@ -20,7 +21,9 @@ export default function LayoutProviders({children}: Props): JSX.Element {
<AnnouncementBarProvider> <AnnouncementBarProvider>
<UserPreferencesProvider> <UserPreferencesProvider>
<DocsPreferredVersionContextProvider> <DocsPreferredVersionContextProvider>
{children} <MobileSecondaryMenuProvider>
{children}
</MobileSecondaryMenuProvider>
</DocsPreferredVersionContextProvider> </DocsPreferredVersionContextProvider>
</UserPreferencesProvider> </UserPreferencesProvider>
</AnnouncementBarProvider> </AnnouncementBarProvider>

View file

@ -7,14 +7,17 @@
import React, {useCallback, useState, useEffect} from 'react'; import React, {useCallback, useState, useEffect} from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import Translate from '@docusaurus/Translate';
import SearchBar from '@theme/SearchBar'; import SearchBar from '@theme/SearchBar';
import Toggle from '@theme/Toggle'; import Toggle from '@theme/Toggle';
import useThemeContext from '@theme/hooks/useThemeContext'; import useThemeContext from '@theme/hooks/useThemeContext';
import {useThemeConfig} from '@docusaurus/theme-common'; import {
useThemeConfig,
useMobileSecondaryMenuRenderer,
} from '@docusaurus/theme-common';
import useHideableNavbar from '@theme/hooks/useHideableNavbar'; import useHideableNavbar from '@theme/hooks/useHideableNavbar';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll'; import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import useWindowSize, {windowSizes} from '@theme/hooks/useWindowSize'; import useWindowSize from '@theme/hooks/useWindowSize';
import NavbarItem from '@theme/NavbarItem'; import NavbarItem from '@theme/NavbarItem';
import Logo from '@theme/Logo'; import Logo from '@theme/Logo';
import IconMenu from '@theme/IconMenu'; import IconMenu from '@theme/IconMenu';
@ -39,37 +42,120 @@ function splitNavItemsByPosition(items) {
}; };
} }
function Navbar(): JSX.Element { function NavbarMobileSidebar({
sidebarShown,
toggleSidebar,
}: {
sidebarShown: boolean;
toggleSidebar: () => void;
}) {
useLockBodyScroll(sidebarShown);
const { const {
navbar: {items, hideOnScroll, style}, navbar: {items},
colorMode: {disableSwitch: disableColorModeSwitch}, colorMode: {disableSwitch: disableColorModeSwitch},
} = useThemeConfig(); } = useThemeConfig();
const [sidebarShown, setSidebarShown] = useState(false);
const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext(); const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
useLockBodyScroll(sidebarShown);
const showSidebar = useCallback(() => {
setSidebarShown(true);
}, [setSidebarShown]);
const hideSidebar = useCallback(() => {
setSidebarShown(false);
}, [setSidebarShown]);
const onToggleChange = useCallback( const onToggleChange = useCallback(
(e) => (e.target.checked ? setDarkTheme() : setLightTheme()), (e) => (e.target.checked ? setDarkTheme() : setLightTheme()),
[setLightTheme, setDarkTheme], [setLightTheme, setDarkTheme],
); );
const mobileSecondaryMenuContent = useMobileSecondaryMenuRenderer()?.({
toggleSidebar,
});
const hasMobileSecondaryMenu = !!mobileSecondaryMenuContent;
const [mainMenuShown, setMainMenuShown] = useState(true);
// On sidebar close, reset the sidebar to secondary menu (if any)
useEffect(() => {
if (!hasMobileSecondaryMenu) {
setMainMenuShown(true);
return;
}
if (!sidebarShown) {
setMainMenuShown(false);
}
}, [sidebarShown, hasMobileSecondaryMenu]);
return (
<div className="navbar-sidebar">
<div className="navbar-sidebar__brand">
<Logo
className="navbar__brand"
imageClassName="navbar__logo"
titleClassName="navbar__title"
/>
{!disableColorModeSwitch && sidebarShown && (
<Toggle checked={isDarkTheme} onChange={onToggleChange} />
)}
</div>
<div
className={clsx('navbar-sidebar__items', styles.menuWrapper, {
[styles.menuWrapperDocShown]: !mainMenuShown,
})}>
<div className="menu">
<ul className="menu__list">
{items.map((item, i) => (
<NavbarItem
mobile
{...(item as any)} // TODO fix typing
onClick={toggleSidebar}
key={i}
/>
))}
</ul>
</div>
<div className={styles.docSidebarSecondaryMenu}>
<button
type="button"
className={clsx('clean-btn', styles.backButton)}
onClick={() => setMainMenuShown(true)}>
<Translate
id="theme.navbar.mobileSidebarSecondaryMenu.backButtonLabel"
description="The label of the back button to return to main menu, inside the mobile navbar sidebar secondary menu (notably used to display the docs sidebar)">
Back to main menu
</Translate>
</button>
{mobileSecondaryMenuContent}
</div>
</div>
</div>
);
}
function Navbar(): JSX.Element {
const {
navbar: {items, hideOnScroll, style},
colorMode: {disableSwitch: disableColorModeSwitch},
} = useThemeConfig();
const windowSize = useWindowSize(); const windowSize = useWindowSize();
// Mobile sidebar not visible on hydration: can avoid SSR rendering
const shouldRenderSidebarMobile = windowSize === 'mobile'; // || windowSize === 'ssr';
const [sidebarShown, setSidebarShown] = useState(false);
const toggleSidebar = useCallback(() => {
setSidebarShown(!sidebarShown);
}, [sidebarShown]);
useEffect(() => { useEffect(() => {
if (windowSize === windowSizes.desktop) { if (windowSize === 'desktop') {
setSidebarShown(false); setSidebarShown(false);
} }
}, [windowSize]); }, [windowSize]);
const {isDarkTheme, setLightTheme, setDarkTheme} = useThemeContext();
const onToggleChange = useCallback(
(e) => (e.target.checked ? setDarkTheme() : setLightTheme()),
[setLightTheme, setDarkTheme],
);
const {navbarRef, isNavbarVisible} = useHideableNavbar(hideOnScroll);
const hasSearchNavbarItem = items.some((item) => item.type === 'search'); const hasSearchNavbarItem = items.some((item) => item.type === 'search');
const {leftItems, rightItems} = splitNavItemsByPosition(items); const {leftItems, rightItems} = splitNavItemsByPosition(items);
@ -85,14 +171,14 @@ function Navbar(): JSX.Element {
})}> })}>
<div className="navbar__inner"> <div className="navbar__inner">
<div className="navbar__items"> <div className="navbar__items">
{items != null && items.length !== 0 && ( {items?.length > 0 && (
<button <button
aria-label="Navigation bar toggle" aria-label="Navigation bar toggle"
className="navbar__toggle clean-btn" className="navbar__toggle clean-btn"
type="button" type="button"
tabIndex={0} tabIndex={0}
onClick={showSidebar} onClick={toggleSidebar}
onKeyDown={showSidebar}> onKeyDown={toggleSidebar}>
<IconMenu /> <IconMenu />
</button> </button>
)} )}
@ -119,38 +205,19 @@ function Navbar(): JSX.Element {
{!hasSearchNavbarItem && <SearchBar />} {!hasSearchNavbarItem && <SearchBar />}
</div> </div>
</div> </div>
<div <div
role="presentation" role="presentation"
className="navbar-sidebar__backdrop" className="navbar-sidebar__backdrop"
onClick={hideSidebar} onClick={toggleSidebar}
/> />
<div className="navbar-sidebar">
<div className="navbar-sidebar__brand"> {shouldRenderSidebarMobile && (
<Logo <NavbarMobileSidebar
className="navbar__brand" sidebarShown={sidebarShown}
imageClassName="navbar__logo" toggleSidebar={toggleSidebar}
titleClassName="navbar__title" />
onClick={hideSidebar} )}
/>
{!disableColorModeSwitch && sidebarShown && (
<Toggle checked={isDarkTheme} onChange={onToggleChange} />
)}
</div>
<div className="navbar-sidebar__items">
<div className="menu">
<ul className="menu__list">
{items.map((item, i) => (
<NavbarItem
mobile
{...(item as any)} // TODO fix typing
onClick={hideSidebar}
key={i}
/>
))}
</ul>
</div>
</div>
</div>
</nav> </nav>
); );
} }

View file

@ -18,3 +18,47 @@
.navbarHidden { .navbarHidden {
transform: translate3d(0, calc(-100% - 2px), 0); transform: translate3d(0, calc(-100% - 2px), 0);
} }
:global(.navbar-sidebar__items) {
padding: 0;
}
:global(.navbar-sidebar) {
overflow-x: hidden;
}
.menuWrapper {
display: flex;
width: calc(var(--ifm-navbar-sidebar-width));
transition: transform 0.2s cubic-bezier(0.4, 0, 0.2, 1);
transform: translateZ(0) !important;
}
.menuWrapperDocShown {
transform: translate3d(
calc((var(--ifm-navbar-sidebar-width)) * -1),
0,
0
) !important;
}
.menuWrapper > div {
flex-shrink: 0;
width: calc(var(--ifm-navbar-sidebar-width));
font-weight: var(--ifm-font-weight-semibold);
padding: 0.5rem;
}
.backButton {
width: calc(100% + 1rem);
margin: 0 0 0.7rem -0.5rem;
text-align: left;
font-size: 15px;
padding: 0.6rem 1.5rem;
background: var(--ifm-menu-color-background-active);
font-weight: var(--ifm-button-font-weight);
}
.docSidebarSecondaryMenu {
padding-top: 0 !important;
}

View file

@ -8,22 +8,15 @@
import React from 'react'; import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import useTOCHighlight from '@theme/hooks/useTOCHighlight'; import useTOCHighlight from '@theme/hooks/useTOCHighlight';
import type {TOCProps} from '@theme/TOC'; import type {TOCProps, TOCHeadingsProps} from '@theme/TOC';
import styles from './styles.module.css'; import styles from './styles.module.css';
import {TOCItem} from '@docusaurus/types';
const LINK_CLASS_NAME = 'table-of-contents__link'; const LINK_CLASS_NAME = 'table-of-contents__link';
const ACTIVE_LINK_CLASS_NAME = 'table-of-contents__link--active'; const ACTIVE_LINK_CLASS_NAME = 'table-of-contents__link--active';
const TOP_OFFSET = 100; const TOP_OFFSET = 100;
/* eslint-disable jsx-a11y/control-has-associated-label */ /* eslint-disable jsx-a11y/control-has-associated-label */
function Headings({ export function TOCHeadings({toc, isChild}: TOCHeadingsProps) {
toc,
isChild,
}: {
toc: readonly TOCItem[];
isChild?: boolean;
}) {
if (!toc.length) { if (!toc.length) {
return null; return null;
} }
@ -41,7 +34,7 @@ function Headings({
// eslint-disable-next-line react/no-danger // eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML={{__html: heading.value}} dangerouslySetInnerHTML={{__html: heading.value}}
/> />
<Headings isChild toc={heading.children} /> <TOCHeadings isChild toc={heading.children} />
</li> </li>
))} ))}
</ul> </ul>
@ -52,7 +45,7 @@ function TOC({toc}: TOCProps): JSX.Element {
useTOCHighlight(LINK_CLASS_NAME, ACTIVE_LINK_CLASS_NAME, TOP_OFFSET); useTOCHighlight(LINK_CLASS_NAME, ACTIVE_LINK_CLASS_NAME, TOP_OFFSET);
return ( return (
<div className={clsx(styles.tableOfContents, 'thin-scrollbar')}> <div className={clsx(styles.tableOfContents, 'thin-scrollbar')}>
<Headings toc={toc} /> <TOCHeadings toc={toc} />
</div> </div>
); );
} }

View file

@ -0,0 +1,49 @@
/**
* 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 clsx from 'clsx';
import Translate from '@docusaurus/Translate';
import {useCollapsible, Collapsible} from '@docusaurus/theme-common';
import styles from './styles.module.css';
import {TOCHeadings} from '@theme/TOC';
import type {TOCCollapsibleProps} from '@theme/TOCCollapsible';
export default function TOCCollapsible({toc, className}: TOCCollapsibleProps) {
const {collapsed, toggleCollapsed} = useCollapsible({
initialState: true,
});
return (
<div
className={clsx(
'margin-vert--md',
styles.tocCollapsible,
{
[styles.tocCollapsibleExpanded]: !collapsed,
},
className,
)}>
<button
type="button"
className={clsx('clean-btn', styles.tocCollapsibleButton)}
onClick={toggleCollapsed}>
<Translate
id="theme.TOCCollapsible.toggleButtonLabel"
description="The label used by the button on the collapsible TOC component">
On this page
</Translate>
</button>
<Collapsible
className={styles.tocCollapsibleContent}
collapsed={collapsed}>
<TOCHeadings toc={toc} />
</Collapsible>
</div>
);
}

View file

@ -0,0 +1,49 @@
/**
* 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.
*/
.tocCollapsible {
background-color: var(--ifm-menu-color-background-active);
border-radius: var(--ifm-global-radius);
}
.tocCollapsibleButton {
font-size: inherit;
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.4rem 0.8rem;
width: 100%;
}
.tocCollapsibleButton:after {
content: '';
background: var(--ifm-menu-link-sublist-icon) 50% 50% / 2rem 2rem no-repeat;
filter: var(--ifm-menu-link-sublist-icon-filter);
height: 1.25rem;
width: 1.25rem;
transform: rotate(180deg);
transition: transform var(--ifm-transition-fast);
}
.tocCollapsibleContent > ul {
border-left: none;
border-top: 1px solid var(--ifm-color-emphasis-300);
padding: 0.2rem 0;
font-size: 15px;
}
.tocCollapsibleContent ul li {
margin: 0.4rem 0.8rem;
}
.tocCollapsibleContent a {
display: block;
}
.tocCollapsibleExpanded .tocCollapsibleButton:after {
transform: none;
}

View file

@ -10,42 +10,65 @@ import {useEffect, useState} from 'react';
import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment'; import ExecutionEnvironment from '@docusaurus/ExecutionEnvironment';
import type {WindowSize} from '@theme/hooks/useWindowSize'; import type {WindowSize} from '@theme/hooks/useWindowSize';
const desktopThresholdWidth = 996;
const windowSizes = { const windowSizes = {
desktop: 'desktop', desktop: 'desktop',
mobile: 'mobile', mobile: 'mobile',
// This "ssr" value is very important to handle hydration FOUC / layout shifts
// You have to handle server-rendering explicitly on the call-site
// On the server, you may need to render BOTH the mobile/desktop elements (and hide one of them with mediaquery)
// We don't return "undefined" on purpose, to make it more explicit
ssr: 'ssr',
} as const; } as const;
function useWindowSize(): WindowSize | undefined { const DesktopThresholdWidth = 996;
const isClient = ExecutionEnvironment.canUseDOM;
function getSize() { function getWindowSize() {
if (!isClient) { if (!ExecutionEnvironment.canUseDOM) {
return undefined; return windowSizes.ssr;
}
return window.innerWidth > desktopThresholdWidth
? windowSizes.desktop
: windowSizes.mobile;
} }
return window.innerWidth > DesktopThresholdWidth
? windowSizes.desktop
: windowSizes.mobile;
}
const [windowSize, setWindowSize] = useState(getSize); // Simulate the SSR window size in dev, so that potential hydration FOUC/layout shift problems can be seen in dev too!
const DevSimulateSSR = process.env.NODE_ENV === 'development' && true;
// This hook returns an enum value on purpose!
// We don't want it to return the actual width value, for resize perf reasons
// We only want to re-render once a breakpoint is crossed
function useWindowSize(): WindowSize {
const [windowSize, setWindowSize] = useState<WindowSize>(() => {
if (DevSimulateSSR) {
return 'ssr';
}
return getWindowSize();
});
useEffect(() => { useEffect(() => {
if (!isClient) { if (!ExecutionEnvironment.canUseDOM) {
return undefined; return undefined;
} }
function handleResize() { function updateWindowSize() {
setWindowSize(getSize()); setWindowSize(getWindowSize());
} }
window.addEventListener('resize', handleResize); // @ts-expect-error: annoying TS setTimeout typing...
return () => window.removeEventListener('resize', handleResize); const timeout: number | undefined = DevSimulateSSR
? setTimeout(updateWindowSize, 1000)
: undefined;
window.addEventListener('resize', updateWindowSize);
return () => {
window.removeEventListener('resize', updateWindowSize);
clearTimeout(timeout);
};
}, []); }, []);
return windowSize; return windowSize;
} }
export {windowSizes};
export default useWindowSize; export default useWindowSize;

View file

@ -88,6 +88,28 @@ declare module '@theme/DocSidebar' {
export default DocSidebar; export default DocSidebar;
} }
declare module '@theme/DocSidebarItem' {
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs-types';
type DocSidebarPropsBase = {
readonly activePath: string;
readonly collapsible?: boolean;
readonly onItemClick?: () => void;
readonly tabIndex?: number;
};
export type Props = DocSidebarPropsBase & {
readonly item: PropSidebarItem;
};
const DocSidebarItem: (props: Props) => JSX.Element;
export default DocSidebarItem;
export type DocSidebarItemsProps = DocSidebarPropsBase & {
readonly items: readonly PropSidebarItem[];
};
export const DocSidebarItems: (props: DocSidebarItemsProps) => JSX.Element;
}
declare module '@theme/DocVersionSuggestions' { declare module '@theme/DocVersionSuggestions' {
const DocVersionSuggestions: () => JSX.Element; const DocVersionSuggestions: () => JSX.Element;
export default DocVersionSuggestions; export default DocVersionSuggestions;
@ -213,11 +235,12 @@ declare module '@theme/hooks/useWindowSize' {
export const windowSizes: { export const windowSizes: {
desktop: 'desktop'; desktop: 'desktop';
mobile: 'mobile'; mobile: 'mobile';
ssr: 'ssr';
}; };
export type WindowSize = keyof typeof windowSizes; export type WindowSize = keyof typeof windowSizes;
export default function useWindowSize(): WindowSize | undefined; export default function useWindowSize(): WindowSize;
} }
declare module '@theme/hooks/useKeyboardNavigation' { declare module '@theme/hooks/useKeyboardNavigation' {
@ -476,6 +499,13 @@ declare module '@theme/TOC' {
readonly toc: readonly TOCItem[]; readonly toc: readonly TOCItem[];
}; };
export type TOCHeadingsProps = {
readonly toc: readonly TOCItem[];
readonly isChild?: boolean;
};
export const TOCHeadings: (props: HeadingsProps) => JSX.Element;
const TOC: (props: TOCProps) => JSX.Element; const TOC: (props: TOCProps) => JSX.Element;
export default TOC; export default TOC;
} }
@ -491,6 +521,18 @@ declare module '@theme/TOCInline' {
export default TOCInline; export default TOCInline;
} }
declare module '@theme/TOCCollapsible' {
import type {TOCItem} from '@docusaurus/types';
export type TOCCollapsibleProps = {
readonly className?: string;
readonly toc: readonly TOCItem[];
};
const TOCCollapsible: (props: TOCCollapsibleProps) => JSX.Element;
export default TOCCollapsible;
}
declare module '@theme/Toggle' { declare module '@theme/Toggle' {
import type {SyntheticEvent} from 'react'; import type {SyntheticEvent} from 'react';

View file

@ -40,6 +40,7 @@ const DEFAULT_CONFIG = {
items: [], items: [],
}, },
hideableSidebar: false, hideableSidebar: false,
sidebarCollapsible: true,
}; };
exports.DEFAULT_CONFIG = DEFAULT_CONFIG; exports.DEFAULT_CONFIG = DEFAULT_CONFIG;
@ -309,6 +310,7 @@ const ThemeConfigSchema = Joi.object({
.default(DEFAULT_CONFIG.prism) .default(DEFAULT_CONFIG.prism)
.unknown(), .unknown(),
hideableSidebar: Joi.bool().default(DEFAULT_CONFIG.hideableSidebar), hideableSidebar: Joi.bool().default(DEFAULT_CONFIG.hideableSidebar),
sidebarCollapsible: Joi.bool().default(DEFAULT_CONFIG.sidebarCollapsible),
}); });
exports.ThemeConfigSchema = ThemeConfigSchema; exports.ThemeConfigSchema = ThemeConfigSchema;

View file

@ -149,10 +149,12 @@ ${logKeys(unknownMessages)}`),
const newBaseMessagesDescriptions = Object.entries(newBaseMessages).reduce( const newBaseMessagesDescriptions = Object.entries(newBaseMessages).reduce(
(acc, [key]) => { (acc, [key]) => {
const codeTranslation = codeExtractedTranslations[key];
return { return {
...acc, ...acc,
[`${key}${DescriptionSuffix}`]: codeExtractedTranslations[key] [`${key}${DescriptionSuffix}`]: codeTranslation
.description, ? codeTranslation.description
: undefined,
}; };
}, },
{}, {},

View file

@ -37,12 +37,19 @@ export {useLocationChange} from './utils/useLocationChange';
export {usePrevious} from './utils/usePrevious'; export {usePrevious} from './utils/usePrevious';
export {useCollapsible} from './utils/useCollapsible'; export {useCollapsible, Collapsible} from './utils/useCollapsible';
export type { export type {
UseCollapsibleConfig, UseCollapsibleConfig,
UseCollapsibleReturns, UseCollapsibleReturns,
} from './utils/useCollapsible'; } from './utils/useCollapsible';
export {
MobileSecondaryMenuProvider,
MobileSecondaryMenuFiller,
useMobileSecondaryMenuRenderer,
} from './utils/mobileSecondaryMenu';
export type {MobileSecondaryMenuComponent} from './utils/mobileSecondaryMenu';
export { export {
useDocsPreferredVersion, useDocsPreferredVersion,
useDocsPreferredVersionByPluginId, useDocsPreferredVersionByPluginId,

View file

@ -0,0 +1,111 @@
/**
* 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, {
useState,
ReactNode,
useContext,
createContext,
useEffect,
ComponentType,
useMemo,
} from 'react';
/*
The idea behind all this is that a specific component must be able to fill a placeholder in the generic layout
The doc page should be able to fill the secondary menu of the main mobile navbar.
This permits to reduce coupling between the main layout and the specific page.
This kind of feature is often called portal/teleport/gateway... various unmaintained React libs exist
Most up-to-date one: https://github.com/gregberge/react-teleporter
Not sure any of those is safe regarding concurrent mode.
*/
type ExtraProps = {
toggleSidebar: () => void;
};
export type MobileSecondaryMenuComponent<Props extends unknown> = ComponentType<
Props & ExtraProps
>;
type State = {
component: MobileSecondaryMenuComponent<unknown>;
props: unknown;
} | null;
function useContextValue() {
return useState<State>(null);
}
type ContextValue = ReturnType<typeof useContextValue>;
const Context = createContext<ContextValue | null>(null);
export function MobileSecondaryMenuProvider({children}: {children: ReactNode}) {
return (
<Context.Provider value={useContextValue()}>{children}</Context.Provider>
);
}
function useMobileSecondaryMenuContext(): ContextValue {
const value = useContext(Context);
if (value === null) {
throw new Error(
'MobileSecondaryMenuProvider was not used correctly, context value is null',
);
}
return value;
}
export function useMobileSecondaryMenuRenderer(): (
extraProps: ExtraProps,
) => ReactNode | undefined {
const [state] = useMobileSecondaryMenuContext();
if (state) {
const Comp = state.component;
return function render(extraProps) {
return <Comp {...state.props} {...extraProps} />;
};
}
return () => undefined;
}
function useShallowMemoizedObject<O extends Record<string, unknown>>(obj: O) {
return useMemo(
() => obj,
// Is this safe?
[...Object.keys(obj), ...Object.values(obj)],
);
}
// Fill the secondary menu placeholder with some real content
export function MobileSecondaryMenuFiller<
Props extends Record<string, unknown>
>({
component,
props,
}: {
component: MobileSecondaryMenuComponent<Props & ExtraProps>;
props: Props;
}): JSX.Element | null {
const [, setState] = useMobileSecondaryMenuContext();
// To avoid useless context re-renders, props are memoized shallowly
const memoizedProps = useShallowMemoizedObject(props);
useEffect(() => {
// @ts-expect-error: context is not 100% typesafe but it's ok
setState({component, props: memoizedProps});
}, [setState, component, memoizedProps]);
useEffect(() => {
return () => setState(null);
}, [setState]);
return null;
}

View file

@ -5,7 +5,7 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import { import React, {
useState, useState,
useEffect, useEffect,
useRef, useRef,
@ -13,46 +13,38 @@ import {
RefObject, RefObject,
Dispatch, Dispatch,
SetStateAction, SetStateAction,
TransitionEvent, ReactNode,
} from 'react'; } from 'react';
/*
Lex111: Dynamic transition duration is used in Material deisign, this technique is good for a large number of items.
https://material.io/archive/guidelines/motion/duration-easing.html#duration-easing-dynamic-durations
https://github.com/mui-org/material-ui/blob/e724d98eba018e55e1a684236a2037e24bcf050c/packages/material-ui/src/styles/createTransitions.js#L40-L43
*/
function getAutoHeightDuration(height: number) {
const constant = height / 36;
return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10);
}
type CollapsibleAnimationConfig = {
duration?: number;
easing?: string;
};
const DefaultAnimationEasing = 'ease-in-out'; const DefaultAnimationEasing = 'ease-in-out';
export type UseCollapsibleConfig = { export type UseCollapsibleConfig = {
initialState: boolean | (() => boolean); initialState: boolean | (() => boolean);
animation?: CollapsibleAnimationConfig;
}; };
export type UseCollapsibleReturns = { export type UseCollapsibleReturns = {
collapsed: boolean; collapsed: boolean;
setCollapsed: Dispatch<SetStateAction<boolean>>; setCollapsed: Dispatch<SetStateAction<boolean>>;
toggleCollapsed: () => void; toggleCollapsed: () => void;
getToggleProps(): {
onClick?: () => void;
};
getCollapsibleProps(): {
ref: RefObject<any>; // any because TS is a pain for HTML element refs, see https://twitter.com/sebastienlorber/status/1412784677795110914
onTransitionEnd: (e: TransitionEvent) => void;
};
}; };
// This hook just define the state
export function useCollapsible({
initialState,
}: UseCollapsibleConfig): UseCollapsibleReturns {
const [collapsed, setCollapsed] = useState(initialState ?? false);
const toggleCollapsed = useCallback(() => {
setCollapsed((expanded) => !expanded);
}, []);
return {
collapsed,
setCollapsed,
toggleCollapsed,
};
}
const CollapsedStyles = { const CollapsedStyles = {
display: 'none', display: 'none',
overflow: 'hidden', overflow: 'hidden',
@ -72,6 +64,21 @@ function applyCollapsedStyle(el: HTMLElement, collapsed: boolean) {
el.style.height = collapsedStyles.height; el.style.height = collapsedStyles.height;
} }
/*
Lex111: Dynamic transition duration is used in Material design, this technique is good for a large number of items.
https://material.io/archive/guidelines/motion/duration-easing.html#duration-easing-dynamic-durations
https://github.com/mui-org/material-ui/blob/e724d98eba018e55e1a684236a2037e24bcf050c/packages/material-ui/src/styles/createTransitions.js#L40-L43
*/
function getAutoHeightDuration(height: number) {
const constant = height / 36;
return Math.round((4 + 15 * constant ** 0.25 + constant / 5) * 10);
}
type CollapsibleAnimationConfig = {
duration?: number;
easing?: string;
};
function useCollapseAnimation({ function useCollapseAnimation({
collapsibleRef, collapsibleRef,
collapsed, collapsed,
@ -135,41 +142,39 @@ function useCollapseAnimation({
}, [collapsibleRef, collapsed, animation]); }, [collapsibleRef, collapsed, animation]);
} }
/* type CollapsibleElementType = React.ElementType<
This hook encapsulate the animated collapsible behavior Pick<React.HTMLAttributes<unknown>, 'className' | 'onTransitionEnd'>
You have to apply the getToggleProps + getCollapsibleProps wire everything >;
Similar to other solutions in the React ecosystem, like Downshift for Selects
*/ export function Collapsible({
export function useCollapsible({ as: As = 'div',
initialState, collapsed,
children,
animation, animation,
}: UseCollapsibleConfig): UseCollapsibleReturns { className,
const collapsibleRef = useRef<HTMLElement>(null); }: {
as?: CollapsibleElementType; // TODO better typing, allow any html element (keyof JSX.IntrinsicElement => not working)
const [collapsed, setCollapsed] = useState(initialState ?? false); collapsed: boolean;
children: ReactNode;
const toggleCollapsed = useCallback(() => { animation?: CollapsibleAnimationConfig;
setCollapsed((expanded) => !expanded); className?: string;
}, []); }) {
// any because TS is a pain for HTML element refs, see https://twitter.com/sebastienlorber/status/1412784677795110914
const collapsibleRef = useRef<any>(null);
useCollapseAnimation({collapsibleRef, collapsed, animation}); useCollapseAnimation({collapsibleRef, collapsed, animation});
return { return (
collapsed, <As
setCollapsed, // @ts-expect-error: see https://twitter.com/sebastienlorber/status/1412784677795110914
toggleCollapsed, ref={collapsibleRef}
onTransitionEnd={(e) => {
getToggleProps: () => ({
onClick: toggleCollapsed,
}),
getCollapsibleProps: () => ({
ref: collapsibleRef,
onTransitionEnd: (e) => {
if (e.propertyName === 'height') { if (e.propertyName === 'height') {
applyCollapsedStyle(collapsibleRef.current!, collapsed); applyCollapsedStyle(collapsibleRef.current!, collapsed);
} }
}, }}
}), className={className}>
}; {children}
</As>
);
} }

View file

@ -103,6 +103,7 @@ export type ThemeConfig = {
hideableSidebar: boolean; hideableSidebar: boolean;
image: string; image: string;
metadatas: Array<Record<string, string>>; metadatas: Array<Record<string, string>>;
sidebarCollapsible: boolean;
}; };
export function useThemeConfig(): ThemeConfig { export function useThemeConfig(): ThemeConfig {

View file

@ -346,6 +346,7 @@ export interface RouteConfig {
routes?: RouteConfig[]; routes?: RouteConfig[];
exact?: boolean; exact?: boolean;
priority?: number; priority?: number;
[propName: string]: any;
} }
// Aliases used for Webpack resolution (when using docusaurus swizzle) // Aliases used for Webpack resolution (when using docusaurus swizzle)

View file

@ -38,16 +38,17 @@ Object {
"routesConfig": " "routesConfig": "
import React from 'react'; import React from 'react';
import ComponentCreator from '@docusaurus/ComponentCreator'; import ComponentCreator from '@docusaurus/ComponentCreator';
export default [ export default [
{ {
path: '/blog', path: '/blog',
component: ComponentCreator('/blog','94e'), component: ComponentCreator('/blog','94e'),
exact: true, exact: true
}, },
{ {
path: '*', path: '*',
component: ComponentCreator('*') component: ComponentCreator('*')
} }
]; ];
", ",
"routesPaths": Array [ "routesPaths": Array [
@ -90,16 +91,16 @@ Object {
}, },
}, },
"routesChunkNames": Object { "routesChunkNames": Object {
"/docs/hello-f94": Object { "/docs/hello-44b": Object {
"component": "component---theme-doc-item-178-a40", "component": "component---theme-doc-item-178-a40",
"content": "content---docs-helloaff-811", "content": "content---docs-helloaff-811",
"metadata": "metadata---docs-hello-956-741", "metadata": "metadata---docs-hello-956-741",
}, },
"/docs:route-838": Object { "/docs:route-63b": Object {
"component": "component---theme-doc-page-1-be-9be", "component": "component---theme-doc-page-1-be-9be",
"docsMetadata": "docsMetadata---docs-routef-34-881", "docsMetadata": "docsMetadata---docs-routef-34-881",
}, },
"docs/foo/baz-f88": Object { "docs/foo/baz-ac2": Object {
"component": "component---theme-doc-item-178-a40", "component": "component---theme-doc-item-178-a40",
"content": "content---docs-foo-baz-8-ce-61e", "content": "content---docs-foo-baz-8-ce-61e",
"metadata": "metadata---docs-foo-baz-2-cf-fa7", "metadata": "metadata---docs-foo-baz-2-cf-fa7",
@ -108,28 +109,29 @@ Object {
"routesConfig": " "routesConfig": "
import React from 'react'; import React from 'react';
import ComponentCreator from '@docusaurus/ComponentCreator'; import ComponentCreator from '@docusaurus/ComponentCreator';
export default [ export default [
{ {
path: '/docs:route', path: '/docs:route',
component: ComponentCreator('/docs:route','838'), component: ComponentCreator('/docs:route','63b'),
routes: [
routes: [ {
{ path: '/docs/hello',
path: '/docs/hello', component: ComponentCreator('/docs/hello','44b'),
component: ComponentCreator('/docs/hello','f94'), exact: true,
exact: true, 'sidebar': \\"main\\"
}, },
{ {
path: 'docs/foo/baz', path: 'docs/foo/baz',
component: ComponentCreator('docs/foo/baz','f88'), component: ComponentCreator('docs/foo/baz','ac2'),
'sidebar': \\"secondary\\"
}, }
] ]
}, },
{ {
path: '*', path: '*',
component: ComponentCreator('*') component: ComponentCreator('*')
} }
]; ];
", ",
"routesPaths": Array [ "routesPaths": Array [
@ -156,16 +158,16 @@ Object {
"routesConfig": " "routesConfig": "
import React from 'react'; import React from 'react';
import ComponentCreator from '@docusaurus/ComponentCreator'; import ComponentCreator from '@docusaurus/ComponentCreator';
export default [
{
path: '',
component: ComponentCreator('','b2a'),
}, export default [
{ {
path: '*', path: '',
component: ComponentCreator('*') component: ComponentCreator('','b2a')
} },
{
path: '*',
component: ComponentCreator('*')
}
]; ];
", ",
"routesPaths": Array [ "routesPaths": Array [

View file

@ -25,6 +25,7 @@ describe('loadRoutes', () => {
content: 'docs/hello.md', content: 'docs/hello.md',
metadata: 'docs-hello-da2.json', metadata: 'docs-hello-da2.json',
}, },
sidebar: 'main',
}, },
{ {
path: 'docs/foo/baz', path: 'docs/foo/baz',
@ -33,6 +34,7 @@ describe('loadRoutes', () => {
content: 'docs/foo/baz.md', content: 'docs/foo/baz.md',
metadata: 'docs-foo-baz-dd9.json', metadata: 'docs-foo-baz-dd9.json',
}, },
sidebar: 'secondary',
}, },
], ],
}; };

View file

@ -21,30 +21,52 @@ import {
ChunkNames, ChunkNames,
} from '@docusaurus/types'; } from '@docusaurus/types';
function indent(str: string) {
const spaces = ' ';
return `${spaces}${str.replace(/(\n)/g, `\n${spaces}`)}`;
}
const createRouteCodeString = ({ const createRouteCodeString = ({
routePath, routePath,
routeHash, routeHash,
exact, exact,
subroutesCodeStrings, subroutesCodeStrings,
props,
}: { }: {
routePath: string; routePath: string;
routeHash: string; routeHash: string;
exact?: boolean; exact?: boolean;
subroutesCodeStrings?: string[]; subroutesCodeStrings?: string[];
props: {[propName: string]: any};
}) => { }) => {
const str = `{ const parts = [
path: '${routePath}', `path: '${routePath}'`,
component: ComponentCreator('${routePath}','${routeHash}'), `component: ComponentCreator('${routePath}','${routeHash}')`,
${exact ? `exact: true,` : ''} ];
${
subroutesCodeStrings if (exact) {
? ` routes: [ parts.push(`exact: true`);
${removeSuffix(subroutesCodeStrings.join(',\n'), ',\n')}, }
]
` if (subroutesCodeStrings) {
: '' parts.push(
}}`; `routes: [
return str; ${indent(removeSuffix(subroutesCodeStrings.join(',\n'), ',\n'))}
]`,
);
}
Object.entries(props).forEach(([propName, propValue]) => {
// Figure out how to "unquote" JS attributes that don't need to be quoted
// Is this lib reliable? https://github.com/armanozak/should-quote
const shouldQuote = true; // TODO
const key = shouldQuote ? `'${propName}'` : propName;
parts.push(`${key}: ${JSON.stringify(propValue)}`);
});
return `{
${indent(parts.join(',\n'))}
}`;
}; };
const NotFoundRouteCode = `{ const NotFoundRouteCode = `{
@ -106,6 +128,9 @@ export default async function loadRoutes(
modules = {}, modules = {},
routes: subroutes, routes: subroutes,
exact, exact,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
priority,
...props
} = routeConfig; } = routeConfig;
if (!isString(routePath) || !component) { if (!isString(routePath) || !component) {
@ -138,15 +163,18 @@ export default async function loadRoutes(
routeHash, routeHash,
exact, exact,
subroutesCodeStrings: subroutes?.map(generateRouteCode), subroutesCodeStrings: subroutes?.map(generateRouteCode),
props,
}); });
} }
const routesConfig = ` const routesConfig = `
${RoutesImportsCode} ${RoutesImportsCode}
export default [ export default [
${pluginsRouteConfigs.map(generateRouteCode).join(',\n')}, ${indent(`${pluginsRouteConfigs.map(generateRouteCode).join(',\n')},`)}
${NotFoundRouteCode} ${indent(NotFoundRouteCode)}
];\n`; ];
`;
return { return {
registry, registry,

View file

@ -310,6 +310,7 @@ const isVersioningDisabled = !!process.env.DISABLE_VERSIONING || isI18nStaging;
liveCodeBlock: { liveCodeBlock: {
playgroundPosition: 'bottom', playgroundPosition: 'bottom',
}, },
sidebarCollapsible: true,
hideableSidebar: true, hideableSidebar: true,
colorMode: { colorMode: {
defaultMode: 'light', defaultMode: 'light',