feat(v2): migrate bootstrap components to ts (#3496)

* feat(v2): Migrate bootstrap theme to typescript

* chore(v2): Add eslint rule to avoid delete import of modules

* chore(v2): Add lib to gitignore

* chore(v2): Add prettier script

* chore(v2): change hooks to ts

* fix(v2): Fix Navbar and Layout problems

* fix(v2): scroll

* fix(v2): navbar metadata

* refactor(v2): improve css styles

* chore(v2): Restore debug layout

* feat(v2): Remove console.log

Co-authored-by: fanny <fanny.vieira@ccc.ufcg.edu.br>
This commit is contained in:
Sébastien Lorber 2020-09-29 13:16:39 +02:00 committed by GitHub
parent 1c251bca2e
commit f343450e85
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
33 changed files with 417 additions and 99 deletions

View file

@ -24,6 +24,7 @@ packages/docusaurus-plugin-sitemap/lib/
packages/docusaurus-plugin-ideal-image/lib/ packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-plugin-ideal-image/copyUntypedFiles.js packages/docusaurus-plugin-ideal-image/copyUntypedFiles.js
packages/docusaurus-theme-classic/lib/ packages/docusaurus-theme-classic/lib/
packages/docusaurus-theme-bootstrap/lib/
packages/docusaurus-migrate/lib/ packages/docusaurus-migrate/lib/
packages/docusaurus-1.x/.eslintrc.js packages/docusaurus-1.x/.eslintrc.js

1
.gitignore vendored
View file

@ -28,6 +28,7 @@ packages/docusaurus-plugin-debug/lib/
packages/docusaurus-plugin-sitemap/lib/ packages/docusaurus-plugin-sitemap/lib/
packages/docusaurus-plugin-ideal-image/lib/ packages/docusaurus-plugin-ideal-image/lib/
packages/docusaurus-theme-classic/lib/ packages/docusaurus-theme-classic/lib/
packages/docusaurus-theme-bootstrap/lib/
packages/docusaurus-migrate/lib/ packages/docusaurus-migrate/lib/
website/netlifyDeployPreview website/netlifyDeployPreview

View file

@ -20,7 +20,7 @@
> **We are working hard on Docusaurus v2. If you are new to Docusaurus, try using the new version instead of v1. See the [Docusaurus v2 website](https://v2.docusaurus.io/) for more details.** > **We are working hard on Docusaurus v2. If you are new to Docusaurus, try using the new version instead of v1. See the [Docusaurus v2 website](https://v2.docusaurus.io/) for more details.**
> >
> You can see the clean live demo with classic theme by clicking this badge [![Runme](https://runme.io/static/button.svg)](https://runme.io/run?app_id=0dd80306-47bb-4e80-95dc-dc95eb05d3fd) > You can see the clean live demo with classic theme by clicking this badge [![Runme](https://runme.io/static/button.svg)](https://runme.io/run?app_id=0dd80306-47bb-4e80-95dc-dc95eb05d3fd)
## Introduction ## Introduction
@ -28,11 +28,12 @@ Docusaurus is a project for building, deploying, and maintaining open source pro
- **Simple to Start** - **Simple to Start**
>Docusaurus is built in a way so that it can [get running](https://docusaurus.io/docs/en/installation/) in as little time as possible. We've built Docusaurus to handle the website build process so you can focus on your project. > Docusaurus is built in a way so that it can [get running](https://docusaurus.io/docs/en/installation/) in as little time as possible. We've built Docusaurus to handle the website build process so you can focus on your project.
- **Localizable** - **Localizable**
>Docusaurus ships with [localization support](https://docusaurus.io/docs/en/translation/) via CrowdIn. Empower and grow your international community by translating your documentation. > Docusaurus ships with [localization support](https://docusaurus.io/docs/en/translation/) via CrowdIn. Empower and grow your international community by translating your documentation.
- **Customizable** - **Customizable**
>While Docusaurus ships with the key pages and sections you need to get started, including a home page, a docs section, a [blog](https://docusaurus.io/docs/en/adding-blog/), and additional support pages, it is also [customizable](https://docusaurus.io/docs/en/custom-pages/) as well to ensure you have a site that is [uniquely yours](https://docusaurus.io/docs/en/api-pages/). > While Docusaurus ships with the key pages and sections you need to get started, including a home page, a docs section, a [blog](https://docusaurus.io/docs/en/adding-blog/), and additional support pages, it is also [customizable](https://docusaurus.io/docs/en/custom-pages/) as well to ensure you have a site that is [uniquely yours](https://docusaurus.io/docs/en/api-pages/).
## Installation ## Installation

View file

@ -58,6 +58,7 @@ function Feature({imageUrl, title, description}) {
function Home() { function Home() {
const context = useDocusaurusContext(); const context = useDocusaurusContext();
const {siteConfig = {}} = context; const {siteConfig = {}} = context;
return ( return (
<Layout <Layout
title={`Hello from ${siteConfig.title}`} title={`Hello from ${siteConfig.title}`}

View file

@ -0,0 +1,10 @@
/**
* 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.
*/
module.exports = {
presets: [['@babel/preset-typescript', {isTSX: true, allExtensions: true}]],
};

View file

@ -3,12 +3,17 @@
"version": "2.0.0-alpha.64", "version": "2.0.0-alpha.64",
"description": "Bootstrap theme for docusaurus", "description": "Bootstrap theme for docusaurus",
"main": "src/index.js", "main": "src/index.js",
"types": "src/types.d.ts",
"license": "MIT", "license": "MIT",
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
}, },
"dependencies": { "dependencies": {
"@docusaurus/core": "2.0.0-alpha.64", "@docusaurus/core": "2.0.0-alpha.64",
"@docusaurus/types": "2.0.0-alpha.64",
"@docusaurus/plugin-content-blog": "2.0.0-alpha.64",
"@docusaurus/plugin-content-docs": "2.0.0-alpha.64",
"@docusaurus/plugin-content-pages": "2.0.0-alpha.64",
"@mdx-js/react": "^1.5.8", "@mdx-js/react": "^1.5.8",
"bootstrap": "^4.4.1", "bootstrap": "^4.4.1",
"classnames": "^2.2.6", "classnames": "^2.2.6",
@ -16,6 +21,15 @@
"prism-react-renderer": "^1.1.0", "prism-react-renderer": "^1.1.0",
"reactstrap": "^8.4.1" "reactstrap": "^8.4.1"
}, },
"devDependencies": {
"@docusaurus/module-type-aliases": "2.0.0-alpha.64"
},
"scripts": {
"build": "tsc --noEmit && yarn babel && yarn prettier",
"watch": "yarn babel --watch",
"babel": "babel src -d lib --extensions \".tsx,.ts\" --ignore \"**/*.d.ts\" --copy-files",
"prettier": "prettier --config ../../.prettierrc --write \"**/*.{js,ts}\""
},
"peerDependencies": { "peerDependencies": {
"react": "^16.8.4", "react": "^16.8.4",
"react-dom": "^16.8.4" "react-dom": "^16.8.4"

View file

@ -11,6 +11,9 @@ module.exports = function () {
return { return {
name: 'docusaurus-theme-bootstrap', name: 'docusaurus-theme-bootstrap',
getThemePath() { getThemePath() {
return path.resolve(__dirname, '..', 'lib', 'theme');
},
getTypeScriptThemePath() {
return path.resolve(__dirname, './theme'); return path.resolve(__dirname, './theme');
}, },
getClientModules() { getClientModules() {

View file

@ -10,8 +10,9 @@ import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import BlogPostCard from '@theme/BlogPostItem'; import BlogPostCard from '@theme/BlogPostItem';
import BlogListPaginator from '@theme/BlogListPaginator'; import BlogListPaginator from '@theme/BlogListPaginator';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import type {Props} from '@theme/BlogListPage';
function BlogListPage(props) { function BlogListPage(props: Props): JSX.Element {
const {items, metadata} = props; const {items, metadata} = props;
const { const {
siteConfig: {title: siteTitle}, siteConfig: {title: siteTitle},

View file

@ -7,8 +7,9 @@
import React from 'react'; import React from 'react';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import type {Props} from '@theme/BlogListPaginator';
function BlogListPaginator(props) { function BlogListPaginator(props: Props): JSX.Element {
const {previousPage, nextPage} = props.metadata; const {previousPage, nextPage} = props.metadata;
return ( return (

View file

@ -9,6 +9,7 @@ import React from 'react';
import {MDXProvider} from '@mdx-js/react'; import {MDXProvider} from '@mdx-js/react';
import MDXComponents from '@theme/MDXComponents'; import MDXComponents from '@theme/MDXComponents';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import type {Props} from '@theme/BlogPostItem';
const MONTHS = [ const MONTHS = [
'January', 'January',
@ -29,7 +30,7 @@ const getReadingTime = (readingTime) => {
return Math.ceil(readingTime); return Math.ceil(readingTime);
}; };
function BlogPostItem(props) { function BlogPostItem(props: Props): JSX.Element {
const { const {
children, children,
frontMatter, frontMatter,
@ -61,7 +62,7 @@ function BlogPostItem(props) {
<div className="col"> <div className="col">
{author && ( {author && (
<h5> <h5>
<a href={authorURL} alt={author}> <a href={authorURL} rel={author}>
{author} {author}
</a> </a>
</h5> </h5>

View file

@ -9,11 +9,12 @@ import React from 'react';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import BlogPostItem from '@theme/BlogPostItem'; import BlogPostItem from '@theme/BlogPostItem';
import BlogPostPaginator from '@theme/BlogPostPaginator'; import BlogPostPaginator from '@theme/BlogPostPaginator';
import type {Props} from '@theme/BlogPostPage';
function BlogPostPage(props) { function BlogPostPage(props: Props): JSX.Element {
const {content: BlogPostContents} = props; const {content: BlogPostContents} = props;
const {title, description, frontMatter, metadata} = BlogPostContents; const {frontMatter, metadata} = BlogPostContents;
const {nextItem, prevItem} = metadata; const {title, description, nextItem, prevItem} = metadata;
return ( return (
<Layout title={title} description={description}> <Layout title={title} description={description}>

View file

@ -7,8 +7,9 @@
import React from 'react'; import React from 'react';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import type {Props} from '@theme/BlogPostPaginator';
function BlogPostPaginator(props) { function BlogPostPaginator(props: Props): JSX.Element {
const {nextItem, prevItem} = props; const {nextItem, prevItem} = props;
return ( return (

View file

@ -8,8 +8,9 @@
import React from 'react'; import React from 'react';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import type {Props} from '@theme/BlogTagsListPage';
function BlogTagsListPage(props) { function BlogTagsListPage(props: Props): JSX.Element {
const {tags} = props; const {tags} = props;
const renderAllTags = () => ( const renderAllTags = () => (
<> <>

View file

@ -9,12 +9,13 @@ import React from 'react';
import BlogPostItem from '@theme/BlogPostItem'; import BlogPostItem from '@theme/BlogPostItem';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import type {Props} from '@theme/BlogTagsPostsPage';
function pluralize(count, word) { function pluralize(count, word) {
return count > 1 ? `${word}s` : word; return count > 1 ? `${word}s` : word;
} }
function BlogTagsPostPage(props) { function BlogTagsPostPage(props: Props): JSX.Element {
const {metadata, items} = props; const {metadata, items} = props;
const {allTagsPath, name, count} = metadata; const {allTagsPath, name, count} = metadata;

View file

@ -9,7 +9,7 @@ import React from 'react';
import Highlight, {defaultProps} from 'prism-react-renderer'; import Highlight, {defaultProps} from 'prism-react-renderer';
import theme from 'prism-react-renderer/themes/nightOwl'; import theme from 'prism-react-renderer/themes/nightOwl';
export default ({children, className}) => { export default ({children, className}): JSX.Element => {
const language = className && className.replace(/language-/, ''); const language = className && className.replace(/language-/, '');
return ( return (

View file

@ -14,13 +14,14 @@ import useBaseUrl from '@docusaurus/useBaseUrl';
import Navbar from '@theme/Navbar'; import Navbar from '@theme/Navbar';
import Footer from '@theme/Footer'; import Footer from '@theme/Footer';
import type {Props} from '@theme/Layout';
function Layout(props) { function Layout(props: Props): JSX.Element {
const {siteConfig = {}} = useDocusaurusContext(); const {siteConfig = {}} = useDocusaurusContext();
const { const {
favicon, favicon,
title: siteTitle, title: siteTitle,
themeConfig: {image: defaultImage}, themeConfig: {image: defaultImage, metadatas},
url: siteUrl, url: siteUrl,
titleDelimiter, titleDelimiter,
} = siteConfig; } = siteConfig;
@ -32,7 +33,6 @@ function Layout(props) {
image, image,
keywords, keywords,
permalink, permalink,
version,
} = props; } = props;
const metaTitle = title const metaTitle = title
? `${title} ${titleDelimiter} ${siteTitle}` ? `${title} ${titleDelimiter} ${siteTitle}`
@ -57,7 +57,6 @@ function Layout(props) {
{description && ( {description && (
<meta property="og:description" content={description} /> <meta property="og:description" content={description} />
)} )}
{version && <meta name="docsearch:version" content={version} />}
{keywords && keywords.length && ( {keywords && keywords.length && (
<meta name="keywords" content={keywords.join(',')} /> <meta name="keywords" content={keywords.join(',')} />
)} )}
@ -69,6 +68,18 @@ function Layout(props) {
{permalink && <meta property="og:url" content={siteUrl + permalink} />} {permalink && <meta property="og:url" content={siteUrl + permalink} />}
<meta name="twitter:card" content="summary_large_image" /> <meta name="twitter:card" content="summary_large_image" />
</Head> </Head>
<Head
// it's important to have an additional <Head> element here,
// as it allows react-helmet to override values set in previous <Head>
// ie we can override default metadatas such as "twitter:card"
// In same Head, the same meta would appear twice instead of overriding
// See react-helmet doc
>
{metadatas?.length > 0 &&
metadatas.map((metadata, i) => (
<meta key={`metadata_${i}`} {...metadata} />
))}
</Head>
<Navbar /> <Navbar />
<div className="container-fluid px-0 d-inline-flex flex-row"> <div className="container-fluid px-0 d-inline-flex flex-row">
{children} {children}

View file

@ -11,10 +11,11 @@ import Head from '@docusaurus/Head';
import DocPaginator from '@theme/DocPaginator'; import DocPaginator from '@theme/DocPaginator';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import {Props} from '@theme/DocItem';
function DocItem(props) { function DocItem(props: Props): JSX.Element {
const {siteConfig = {}} = useDocusaurusContext(); const {siteConfig = {}} = useDocusaurusContext();
const {url: siteUrl, title: siteTitle, titleDelimiter} = siteConfig; const {url: siteUrl, title: siteTitle, titleDelimiter = ' | '} = siteConfig;
const {content: DocContent} = props; const {content: DocContent} = props;
const {metadata} = DocContent; const {metadata} = DocContent;
const {description, title, permalink} = metadata; const {description, title, permalink} = metadata;
@ -25,7 +26,8 @@ function DocItem(props) {
const metaTitle = title const metaTitle = title
? `${title} ${titleDelimiter} ${siteTitle}` ? `${title} ${titleDelimiter} ${siteTitle}`
: siteTitle; : siteTitle;
let metaImageUrl = siteUrl + useBaseUrl(metaImage); let metaImageUrl: string | undefined = siteUrl + useBaseUrl(metaImage);
if (!isInternalUrl(metaImage)) { if (!isInternalUrl(metaImage)) {
metaImageUrl = metaImage; metaImageUrl = metaImage;
} }

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 React 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 DocSidebar from '@theme/DocSidebar';
@ -13,24 +13,33 @@ 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 {DocumentRoute} from '@theme/DocItem';
import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types';
function DocPageContent({currentDocRoute, versionMetadata, children}) { type DocPageContentProps = {
readonly currentDocRoute: DocumentRoute;
readonly versionMetadata: PropVersionMetadata;
readonly children: ReactNode;
};
function DocPageContent({
currentDocRoute,
versionMetadata,
children,
}: DocPageContentProps): JSX.Element {
const {permalinkToSidebar, docsSidebars} = versionMetadata; const {permalinkToSidebar, docsSidebars} = versionMetadata;
const sidebarName = permalinkToSidebar[currentDocRoute.path]; const sidebarName = permalinkToSidebar[currentDocRoute.path];
const sidebar = docsSidebars[sidebarName]; 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 overflow-hidden"> <div className="d-flex vh-100">
{sidebar && ( {sidebar && (
<div className="vh-100" role="complementary"> <div role="complementary">
<DocSidebar <DocSidebar key={sidebarName} sidebar={sidebar} />
key={sidebarName}
path={currentDocRoute.path}
sidebar={sidebar}
/>
</div> </div>
)} )}
<main className="vh-100 w-100 d-flex flex-column 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>
</div> </div>
@ -38,7 +47,7 @@ function DocPageContent({currentDocRoute, versionMetadata, children}) {
); );
} }
function DocPage(props) { function DocPage(props: Props): JSX.Element {
const { const {
route: {routes: docRoutes}, route: {routes: docRoutes},
versionMetadata, versionMetadata,

View file

@ -7,8 +7,9 @@
import React from 'react'; import React from 'react';
import Link from '@docusaurus/Link'; import Link from '@docusaurus/Link';
import {Props} from '@theme/DocPaginator';
function DocPaginator(props) { function DocPaginator(props: Props): JSX.Element {
const {previous, next} = props.metadata; const {previous, next} = props.metadata;
return ( return (

View file

@ -11,57 +11,63 @@ import isInternalUrl from '@docusaurus/isInternalUrl';
import {NavItem, Nav, Button} from 'reactstrap'; import {NavItem, Nav, Button} from 'reactstrap';
import useLockBodyScroll from '@theme/hooks/useLockBodyScroll'; import useLockBodyScroll from '@theme/hooks/useLockBodyScroll';
import classNames from 'classnames'; import classNames from 'classnames';
import {Props} from '@theme/DocSidebar';
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs-types';
import styles from './styles.module.css'; import styles from './styles.module.css';
const DocSidebarItem = ({item, onItemClick, ...props}) => { type DocSidebarItemProps = {
const {items, href, label, type} = item; item: PropSidebarItem;
onItemClick: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
};
switch (type) { const DocSidebarItem = ({
case 'category': item,
return ( onItemClick,
items.length > 0 && ( }: DocSidebarItemProps): JSX.Element => {
<div> if (item.type === 'category') {
<h4 className="ml-2">{label}</h4> return item.items.length > 0 ? (
{items.map((childItem) => ( <div>
<DocSidebarItem <h4 className="ml-2">{item.label}</h4>
key={childItem.label} {item.items.map((childItem) => (
item={childItem} <DocSidebarItem
onItemClick={onItemClick} key={childItem.label}
/> item={childItem}
))} onItemClick={onItemClick}
</div> />
) ))}
); </div>
) : (
case 'link': <></>
default: );
return ( } else if (item.type === 'link') {
<NavItem> return (
<Link <NavItem>
key={label} <Link
className="sidebar-item m-4 text-white" key={item.label}
to={href} className="sidebar-item m-4 text-white"
{...(isInternalUrl(href) to={item.href}
? { {...(isInternalUrl(item.href)
isNavLink: true, ? {
activeClassName: 'active', isNavLink: true,
exact: true, activeClassName: 'active',
onClick: onItemClick, exact: true,
} onClick: onItemClick,
: { }
target: '_blank', : {
rel: 'noreferrer noopener', target: '_blank',
})} rel: 'noreferrer noopener',
{...props}> })}>
{label} {item.label}
</Link> </Link>
</NavItem> </NavItem>
); );
} else {
return <></>;
} }
}; };
const DocSidebar = ({sidebar, path}) => { const DocSidebar = ({sidebar}: Props): JSX.Element => {
const [sidebarShown, setSidebarShown] = useState(false); const [sidebarShown, setSidebarShown] = useState(false);
const handleSidebarToggle = useCallback(() => { const handleSidebarToggle = useCallback(() => {
setSidebarShown(!sidebarShown); setSidebarShown(!sidebarShown);
@ -106,7 +112,7 @@ const DocSidebar = ({sidebar, path}) => {
key={item.label} key={item.label}
item={item} item={item}
onItemClick={(e) => { onItemClick={(e) => {
e.target.blur(); e.currentTarget.blur();
setSidebarShown(false); setSidebarShown(false);
}} }}
/> />

View file

@ -0,0 +1,90 @@
/**
* 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 Head from '@docusaurus/Head';
import isInternalUrl from '@docusaurus/isInternalUrl';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl';
import Navbar from '@theme/Navbar';
import Footer from '@theme/Footer';
import type {Props} from '@theme/Layout';
function Layout(props: Props): JSX.Element {
const {siteConfig} = useDocusaurusContext();
const {
favicon,
title: siteTitle,
themeConfig: {image: defaultImage, metadatas},
url: siteUrl,
} = siteConfig;
const {
children,
title,
noFooter,
description,
image,
keywords,
permalink,
} = props;
const metaTitle = title ? `${title} | ${siteTitle}` : siteTitle;
const metaImage = image || defaultImage;
let metaImageUrl = siteUrl + useBaseUrl(metaImage);
if (!isInternalUrl(metaImage)) {
metaImageUrl = metaImage;
}
const faviconUrl = useBaseUrl(favicon);
return (
<div className="container-fluid vh-100 vw-100 row m-0 p-0">
<Head>
{/* TODO: Do not assume that it is in english language */}
<html lang="en" />
{metaTitle && <title>{metaTitle}</title>}
{metaTitle && <meta property="og:title" content={metaTitle} />}
{favicon && <link rel="shortcut icon" href={faviconUrl} />}
{description && <meta name="description" content={description} />}
{description && (
<meta property="og:description" content={description} />
)}
{keywords && keywords.length && (
<meta name="keywords" content={keywords.join(',')} />
)}
{metaImage && <meta property="og:image" content={metaImageUrl} />}
{metaImage && <meta property="twitter:image" content={metaImageUrl} />}
{metaImage && (
<meta name="twitter:image:alt" content={`Image for ${metaTitle}`} />
)}
{permalink && <meta property="og:url" content={siteUrl + permalink} />}
<meta name="twitter:card" content="summary_large_image" />
</Head>
<Head
// it's important to have an additional <Head> element here,
// as it allows react-helmet to override values set in previous <Head>
// ie we can override default metadatas such as "twitter:card"
// In same Head, the same meta would appear twice instead of overriding
// See react-helmet doc
>
{metadatas?.length > 0 &&
metadatas.map((metadata, i) => (
<meta key={`metadata_${i}`} {...metadata} />
))}
</Head>
<Navbar />
<div className="container-fluid px-0 d-inline-flex flex-row">
{children}
</div>
{!noFooter && <Footer />}
</div>
);
}
export default Layout;

View file

@ -5,11 +5,11 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import React from 'react'; import React, {ReactNode} from 'react';
import CodeBlock from '@theme/CodeBlock'; import CodeBlock from '@theme/CodeBlock';
import {Table} from 'reactstrap'; import {Table} from 'reactstrap';
const Heading = (tag) => { const Heading = (tag: string): ReactNode => {
return function (props) { return function (props) {
return React.createElement(tag, {className: `${tag} my-3`, ...props}); return React.createElement(tag, {className: `${tag} my-3`, ...props});
}; };

View file

@ -30,7 +30,7 @@ function NavItem({
}) { }) {
const toUrl = useBaseUrl(to); const toUrl = useBaseUrl(to);
const activeBaseUrl = useBaseUrl(activeBasePath); const activeBaseUrl = useBaseUrl(activeBasePath);
const normalizedHref = useBaseUrl(href, true); const normalizedHref = useBaseUrl(href, {forcePrependBaseUrl: true});
return ( return (
<NavItemBase> <NavItemBase>
@ -65,7 +65,7 @@ function NavItem({
function Navbar() { function Navbar() {
const { const {
siteConfig: { siteConfig: {
themeConfig: {navbar: {title, links = []} = {}}, themeConfig: {navbar: {title = '', items: links = []} = {}},
}, },
isClient, isClient,
} = useDocusaurusContext(); } = useDocusaurusContext();

View file

@ -8,7 +8,7 @@
import React from 'react'; import React from 'react';
import Layout from '@theme/Layout'; import Layout from '@theme/Layout';
function NotFound() { function NotFound(): JSX.Element {
return ( return (
<Layout title="Page Not Found"> <Layout title="Page Not Found">
<div className="container my-xl-3"> <div className="container my-xl-3">

View file

@ -6,8 +6,9 @@
*/ */
import React from 'react'; import React from 'react';
import type {Props} from '@theme/TabItem';
function TabItem(props) { function TabItem(props: Props): JSX.Element {
return <div>{props.children}</div>; return <div>{props.children}</div>;
} }

View file

@ -5,7 +5,8 @@
* LICENSE file in the root directory of this source tree. * LICENSE file in the root directory of this source tree.
*/ */
import React, {useState, Children, useEffect} from 'react'; import React, {useState, ReactElement, Children, useEffect} from 'react';
import type {Props} from '@theme/Tabs';
import clsx from 'clsx'; import clsx from 'clsx';
@ -29,7 +30,7 @@ function useUserPreferencesContext() {
}; };
} }
function Tabs(props) { function Tabs(props: Props): JSX.Element {
const {block, children, defaultValue, values, groupId} = props; const {block, children, defaultValue, values, groupId} = props;
const {tabGroupChoices, setTabGroupChoices} = useUserPreferencesContext(); const {tabGroupChoices, setTabGroupChoices} = useUserPreferencesContext();
@ -55,7 +56,7 @@ function Tabs(props) {
} }
}; };
const tabRefs = []; const tabRefs: (HTMLLIElement | null)[] = [];
const focusNextTab = (tabs, target) => { const focusNextTab = (tabs, target) => {
const next = tabs.indexOf(target) + 1; const next = tabs.indexOf(target) + 1;
@ -143,7 +144,9 @@ function Tabs(props) {
<div role="tabpanel" className="margin-vert--md"> <div role="tabpanel" className="margin-vert--md">
{ {
Children.toArray(children).filter( Children.toArray(children).filter(
(child) => child.props.value === selectedValue, (child) =>
(child as ReactElement<{value: string}>).props.value ===
selectedValue,
)[0] )[0]
} }
</div> </div>

View file

@ -7,10 +7,11 @@
import {useEffect} from 'react'; import {useEffect} from 'react';
function useLockBodyScroll(lock = true) { function useLockBodyScroll(lock: boolean = true): void {
useEffect(() => { useEffect(() => {
document.body.style.overflow = lock ? 'hidden' : 'visible'; document.body.style.overflow = lock ? 'hidden' : 'visible';
window.scrollTo(0, 0); window.scrollTo(0, 0);
return () => { return () => {
document.body.style.overflow = 'visible'; document.body.style.overflow = 'visible';
}; };

View file

@ -8,13 +8,14 @@
import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import useBaseUrl from '@docusaurus/useBaseUrl'; import useBaseUrl from '@docusaurus/useBaseUrl';
import isInternalUrl from '@docusaurus/isInternalUrl'; import isInternalUrl from '@docusaurus/isInternalUrl';
import type {LogoLinkProps, useLogoReturns} from '@theme/hooks/useLogo';
const useLogo = () => { const useLogo = (): useLogoReturns => {
const { const {
siteConfig: {baseUrl, themeConfig: {navbar: {logo = {}} = {}}} = {}, siteConfig: {themeConfig: {navbar: {logo = {}} = {}} = {}} = {},
} = useDocusaurusContext(); } = useDocusaurusContext();
const logoLink = logo.href || baseUrl; const logoLink = useBaseUrl(logo.href || '/');
let logoLinkProps = {}; let logoLinkProps: LogoLinkProps = {};
if (logo.target) { if (logo.target) {
logoLinkProps = {target: logo.target}; logoLinkProps = {target: logo.target};
@ -24,7 +25,6 @@ const useLogo = () => {
target: '_blank', target: '_blank',
}; };
} }
const logoImageUrl = useBaseUrl(logo.src); const logoImageUrl = useBaseUrl(logo.src);
return { return {

View file

@ -6,8 +6,9 @@
*/ */
import defaultTheme from 'prism-react-renderer/themes/palenight'; import defaultTheme from 'prism-react-renderer/themes/palenight';
import type {PrismTheme} from 'prism-react-renderer';
const usePrismTheme = () => { const usePrismTheme = (): PrismTheme => {
return defaultTheme; return defaultTheme;
}; };

View file

@ -0,0 +1,143 @@
/**
* 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.
*/
/* eslint-disable import/no-duplicates */
/* eslint-disable spaced-comment */
/// <reference types="@docusaurus/module-type-aliases" />
/// <reference types="@docusaurus/plugin-content-blog" />
/// <reference types="@docusaurus/plugin-content-docs" />
/// <reference types="@docusaurus/plugin-content-pages" />
declare module '@theme/BlogListPaginator' {
import type {Metadata} from '@theme/BlogListPage';
export type Props = {readonly metadata: Metadata};
const BlogListPaginator: (props: Props) => JSX.Element;
export default BlogListPaginator;
}
declare module '@theme/BlogPostItem' {
import type {FrontMatter, Metadata} from '@theme/BlogPostPage';
export type Props = {
readonly frontMatter: FrontMatter;
readonly metadata: Metadata;
readonly truncated?: string | boolean;
readonly isBlogPostPage?: boolean;
readonly children: JSX.Element;
};
const BlogPostItem: (props: Props) => JSX.Element;
export default BlogPostItem;
}
declare module '@theme/BlogPostPaginator' {
type Item = {readonly title: string; readonly permalink: string};
export type Props = {readonly nextItem?: Item; readonly prevItem?: Item};
const BlogPostPaginator: (props: Props) => JSX.Element;
export default BlogPostPaginator;
}
declare module '@theme/CodeBlock' {
export type Props = {
readonly children: string;
readonly className: string;
};
const CodeBlock: (props: Props) => JSX.Element;
export default CodeBlock;
}
declare module '@theme/DocPaginator' {
type PageInfo = {readonly permalink: string; readonly title: string};
export type Props = {
readonly metadata: {readonly previous?: PageInfo; readonly next?: PageInfo};
};
const DocPaginator: (props: Props) => JSX.Element;
export default DocPaginator;
}
declare module '@theme/DocSidebar' {
import type {PropSidebarItem} from '@docusaurus/plugin-content-docs-types';
export type Props = {
readonly sidebar: readonly PropSidebarItem[];
};
const DocSidebar: (props: Props) => JSX.Element;
export default DocSidebar;
}
declare module '@theme/Tabs' {
import type {ReactElement, ReactNode} from 'react';
export type Props = {
readonly block?: boolean;
readonly children: readonly ReactElement<{value: string}>[];
readonly defaultValue?: string;
readonly values: readonly {value: string; label: string}[];
readonly groupId?: string;
};
const Tabs: () => JSX.Element;
export default Tabs;
}
declare module '@theme/Footer' {
const Footer: () => JSX.Element | null;
export default Footer;
}
declare module '@theme/Navbar' {
const Navbar: () => JSX.Element;
export default Navbar;
}
declare module '@theme/TabItem' {
import type {ReactNode} from 'react';
export type Props = {readonly children: ReactNode};
const TabItem: (props: Props) => JSX.Element;
export default TabItem;
}
declare module '@theme/hooks/useLogo' {
export type LogoLinkProps = {target?: string; rel?: string};
export type useLogoReturns = {
readonly logoLink: string;
readonly logoLinkProps: LogoLinkProps;
readonly logoImageUrl: string;
readonly logoAlt: string;
};
const useLogo: () => useLogoReturns;
export default useLogo;
}
declare module '@theme/Layout' {
import type {ReactNode} from 'react';
export type Props = {
children: ReactNode;
title?: string;
noFooter?: boolean;
description?: string;
image?: string;
keywords?: string[];
permalink?: string;
};
const Layout: (props: Props) => JSX.Element;
export default Layout;
}

View file

@ -0,0 +1,12 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"lib": ["DOM"],
"module": "esnext",
"noEmit": true,
"noImplicitAny": false,
"jsx": "react",
"baseUrl": "src"
},
"include": ["src/"]
}