You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@apisix.apache.org by ju...@apache.org on 2022/04/12 07:43:45 UTC

[apisix-website] branch master updated: refactor(hooks, theme): to ts (#1014)

This is an automated email from the ASF dual-hosted git repository.

juzhiyuan pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/apisix-website.git


The following commit(s) were added to refs/heads/master by this push:
     new de1b36ad0be refactor(hooks, theme): to ts (#1014)
de1b36ad0be is described below

commit de1b36ad0be8fea5fbecc42ff9897e5cbf049b5d
Author: SkyeYoung <is...@outlook.com>
AuthorDate: Tue Apr 12 15:43:37 2022 +0800

    refactor(hooks, theme): to ts (#1014)
    
    Co-authored-by: 琚致远 <ju...@apache.org>
---
 package.json                           |   4 +-
 website/src/hooks/useOutsideClick.js   |  19 ---
 website/src/hooks/useOutsideClick.ts   |  20 +++
 website/src/theme/DocPage/index.tsx    | 239 +++++++++++++++++----------------
 website/src/theme/DocSidebar/index.tsx | 176 ++++++++++++------------
 5 files changed, 234 insertions(+), 224 deletions(-)

diff --git a/package.json b/package.json
index dd7ffa2ef85..13e5ba0a2cf 100644
--- a/package.json
+++ b/package.json
@@ -32,8 +32,8 @@
     "stylelint-config-standard": "^25.0.0"
   },
   "lint-staged": {
-    "*.{js, jsx, ts, tsx}": "eslint --cache --fix",
-    "*.{yml, yaml}": "eslint --cache --fix",
+    "*.{js,jsx,ts,tsx}": "eslint --cache --fix",
+    "*.{yml,yaml}": "eslint --cache --fix",
     "*.css": "stylelint --cache --fix"
   }
 }
diff --git a/website/src/hooks/useOutsideClick.js b/website/src/hooks/useOutsideClick.js
deleted file mode 100644
index 690f8ebf8c7..00000000000
--- a/website/src/hooks/useOutsideClick.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import { useEffect } from "react";
-
-const useOutsideClick = (ref, callback) => {
-  const handleClick = (e) => {
-    if (ref.current && !ref.current.contains(e.target)) {
-      callback();
-    }
-  };
-
-  useEffect(() => {
-    document.addEventListener("click", handleClick);
-
-    return () => {
-      document.removeEventListener("click", handleClick);
-    };
-  });
-};
-
-export default useOutsideClick;
diff --git a/website/src/hooks/useOutsideClick.ts b/website/src/hooks/useOutsideClick.ts
new file mode 100644
index 00000000000..c11566aa578
--- /dev/null
+++ b/website/src/hooks/useOutsideClick.ts
@@ -0,0 +1,20 @@
+import type { MutableRefObject } from 'react';
+import { useEffect } from 'react';
+
+const useOutsideClick = (ref: MutableRefObject<HTMLDivElement>, callback: () => void): void => {
+  const handleClick = (e: MouseEvent & { target: HTMLDivElement }) => {
+    if (ref.current && !ref.current.contains(e.target)) {
+      callback();
+    }
+  };
+
+  useEffect(() => {
+    document.addEventListener('click', handleClick);
+
+    return () => {
+      document.removeEventListener('click', handleClick);
+    };
+  });
+};
+
+export default useOutsideClick;
diff --git a/website/src/theme/DocPage/index.tsx b/website/src/theme/DocPage/index.tsx
index 9c895afdb60..ff90ceec8ed 100644
--- a/website/src/theme/DocPage/index.tsx
+++ b/website/src/theme/DocPage/index.tsx
@@ -5,40 +5,53 @@
  * LICENSE file in the root directory of this source tree.
  */
 
-import React, {ReactNode, useState, useCallback, useEffect} from 'react';
-import {MDXProvider} from '@mdx-js/react';
+import type { ReactNode } from 'react';
+import React, { useState, useCallback, useEffect } from 'react';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { MDXProvider } from '@mdx-js/react';
 
 import renderRoutes from '@docusaurus/renderRoutes';
-import type {PropVersionMetadata} from '@docusaurus/plugin-content-docs-types';
+import type { PropVersionMetadata } from '@docusaurus/plugin-content-docs-types';
 import Layout from '@theme/Layout';
 import DocSidebar from '@theme/DocSidebar';
 import MDXComponents from '@theme/MDXComponents';
 import NotFound from '@theme/NotFound';
-import type {DocumentRoute} from '@theme/DocItem';
-import type {Props} from '@theme/DocPage';
+import type { DocumentRoute } from '@theme/DocItem';
+import type { Props } from '@theme/DocPage';
 import IconArrow from '@theme/IconArrow';
 import BackToTopButton from '@theme/BackToTopButton';
-import {matchPath} from '@docusaurus/router';
-import {translate} from '@docusaurus/Translate';
-
+import { matchPath } from '@docusaurus/router';
+import { translate } from '@docusaurus/Translate';
 import clsx from 'clsx';
-import styles from './styles.module.css';
-import {ThemeClassNames, docVersionSearchTag} from '@docusaurus/theme-common';
+// eslint-disable-next-line import/no-extraneous-dependencies
+import { ThemeClassNames, docVersionSearchTag } from '@docusaurus/theme-common';
 import Head from '@docusaurus/Head';
-import useDocusaurusContext from "@docusaurus/useDocusaurusContext";
 
-type DocPageContentProps = {
-  readonly currentDocRoute: DocumentRoute;
-  readonly versionMetadata: PropVersionMetadata;
-  readonly children: ReactNode;
+import styles from './styles.module.css';
+
+ type DocPageContentProps = {
+   readonly currentDocRoute: DocumentRoute;
+   readonly versionMetadata: PropVersionMetadata;
+   readonly children: ReactNode;
+ };
+
+const navbarLinkMap = {
+  general: 'General',
+  apisix: 'Apache APISIX®',
+  dashboard: 'Apache APISIX® Dashboard',
+  'ingress-controller': 'Apache APISIX® Ingress Controller',
+  'helm-chart': 'Apache APISIX® Helm Chart',
+  docker: 'Apache APISIX® Docker',
+  'java-plugin-runner': 'Apache APISIX® Java Plugin Runner',
+  'go-plugin-runner': 'Apache APISIX® Go Plugin Runner',
 };
 
-function DocPageContent({
+const DocPageContent = ({
   currentDocRoute,
   versionMetadata,
   children,
-}: DocPageContentProps): JSX.Element {
-  const {pluginId, version} = versionMetadata;
+}: DocPageContentProps): JSX.Element => {
+  const { pluginId, version } = versionMetadata;
   const sidebarName = currentDocRoute.sidebar;
   const sidebar = sidebarName
     ? versionMetadata.docsSidebars[sidebarName]
@@ -46,45 +59,23 @@ function DocPageContent({
 
   const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false);
   const [hiddenSidebar, setHiddenSidebar] = useState(false);
-  
+
   useEffect(() => {
-    const children = document.querySelector(".navbar__items--right").childElementCount;
-    if(window.innerWidth > 745) {
-      document.querySelector(".navbar__items--right").childNodes[children-2].style.display = "block";
-    }
-    else {
-      document.querySelector(".navbar__items--right").childNodes[children-2].style.display = "none";
-    }
-    const currentPage = currentDocRoute.path.split("/")[2] || "";
-    switch (currentPage) {
-      case "general":
-        document.querySelectorAll(".navbar__link")[0].innerText = "General";
-        break;
-      case "apisix":
-        document.querySelectorAll(".navbar__link")[0].innerText = "Apache APISIX®";
-        break;
-      case "dashboard":
-        document.querySelectorAll(".navbar__link")[0].innerText = "Apache APISIX® Dashboard";
-        break;
-      case "ingress-controller":
-        document.querySelectorAll(".navbar__link")[0].innerText = "Apache APISIX® Ingress Controller";
-        break;
-      case "helm-chart":
-        document.querySelectorAll(".navbar__link")[0].innerText = "Apache APISIX® Helm Chart";
-        break;
-      case "docker":
-        document.querySelectorAll(".navbar__link")[0].innerText = "Apache APISIX® Docker";
-        break;
-      case "java-plugin-runner":
-        document.querySelectorAll(".navbar__link")[0].innerText = "Apache APISIX® Java Plugin Runner";
-        break;
-      case "go-plugin-runner":
-        document.querySelectorAll(".navbar__link")[0].innerText = "Apache APISIX® Go Plugin Runner";
-        break;
+    const childrenCount = document.querySelector('.navbar__items--right').childElementCount;
+    const el = document.querySelector('.navbar__items--right').childNodes[childrenCount - 2] as HTMLDivElement;
+    if (window.innerWidth > 745) {
+      el.style.display = 'block';
+    } else {
+      el.style.display = 'none';
     }
+
+    const currentPage = currentDocRoute.path.split('/')[2] || '';
+    const navbarLink = document.querySelectorAll('.navbar__link')[0] as HTMLAnchorElement;
+    navbarLink.innerText = navbarLinkMap[currentPage];
+
     return () => {
-      document.querySelector(".navbar__items--right").childNodes[children-2].style.display = "none"
-    }
+      el.style.display = 'none';
+    };
   }, []);
 
   const toggleSidebar = useCallback(() => {
@@ -94,77 +85,84 @@ function DocPageContent({
 
     setHiddenSidebarContainer(!hiddenSidebarContainer);
   }, [hiddenSidebar]);
-  
+
   return (
     <Layout
+       // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+       // @ts-ignore
       wrapperClassName={ThemeClassNames.wrapper.docsPages}
       pageClassName={ThemeClassNames.page.docsDocPage}
       searchMetadatas={{
         version,
         tag: docVersionSearchTag(pluginId, version),
-      }}>
+      }}
+    >
       <div className={styles.docPage}>
         <BackToTopButton />
 
         {sidebar && (
-          <aside
-            className={clsx(styles.docSidebarContainer, {
-              [styles.docSidebarContainerHidden]: hiddenSidebarContainer,
+        <aside
+          className={clsx(styles.docSidebarContainer, {
+            [styles.docSidebarContainerHidden]: hiddenSidebarContainer,
+          })}
+          onTransitionEnd={(e) => {
+            if (
+              !e.currentTarget.classList.contains(styles.docSidebarContainer)
+            ) {
+              return;
+            }
+
+            if (hiddenSidebarContainer) {
+              setHiddenSidebar(true);
+            }
+          }}
+        >
+          <DocSidebar
+            key={
+                 // Reset sidebar state on sidebar changes
+                 // See https://github.com/facebook/docusaurus/issues/3414
+                 sidebarName
+               }
+            sidebar={sidebar}
+            path={currentDocRoute.path}
+            onCollapse={toggleSidebar}
+            isHidden={hiddenSidebar}
+               // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+               // @ts-ignore
+            docsPluginId={pluginId}
+          />
+
+          {hiddenSidebar && (
+          <div
+            className={styles.collapsedDocSidebar}
+            title={translate({
+              id: 'theme.docs.sidebar.expandButtonTitle',
+              message: 'Expand sidebar',
+              description:
+                     'The ARIA label and title attribute for expand button of doc sidebar',
             })}
-            onTransitionEnd={(e) => {
-              if (
-                !e.currentTarget.classList.contains(styles.docSidebarContainer)
-              ) {
-                return;
-              }
-
-              if (hiddenSidebarContainer) {
-                setHiddenSidebar(true);
-              }
-            }}>
-            <DocSidebar
-              key={
-                // Reset sidebar state on sidebar changes
-                // See https://github.com/facebook/docusaurus/issues/3414
-                sidebarName
-              }
-              sidebar={sidebar}
-              path={currentDocRoute.path}
-              onCollapse={toggleSidebar}
-              isHidden={hiddenSidebar}
-              // @ts-ignore
-              docsPluginId={pluginId}
-            />
-
-            {hiddenSidebar && (
-              <div
-                className={styles.collapsedDocSidebar}
-                title={translate({
-                  id: 'theme.docs.sidebar.expandButtonTitle',
-                  message: 'Expand sidebar',
-                  description:
-                    'The ARIA label and title attribute for expand button of doc sidebar',
-                })}
-                aria-label={translate({
-                  id: 'theme.docs.sidebar.expandButtonAriaLabel',
-                  message: 'Expand sidebar',
-                  description:
-                    'The ARIA label and title attribute for expand button of doc sidebar',
-                })}
-                tabIndex={0}
-                role="button"
-                onKeyDown={toggleSidebar}
-                onClick={toggleSidebar}>
-                <IconArrow className={styles.expandSidebarButtonIcon} />
-              </div>
-            )}
-          </aside>
+            aria-label={translate({
+              id: 'theme.docs.sidebar.expandButtonAriaLabel',
+              message: 'Expand sidebar',
+              description:
+                     'The ARIA label and title attribute for expand button of doc sidebar',
+            })}
+            tabIndex={0}
+            role="button"
+            onKeyDown={toggleSidebar}
+            onClick={toggleSidebar}
+          >
+            <IconArrow className={styles.expandSidebarButtonIcon} />
+          </div>
+          )}
+        </aside>
         )}
         <main
           className={clsx(styles.docMainContainer, {
             [styles.docMainContainerEnhanced]:
-              hiddenSidebarContainer || !sidebar,
-          })}>
+               hiddenSidebarContainer || !sidebar,
+          })}
+        >
           <div
             className={clsx(
               'container padding-top--md padding-bottom--lg',
@@ -172,40 +170,43 @@ function DocPageContent({
               {
                 [styles.docItemWrapperEnhanced]: hiddenSidebarContainer,
               },
-            )}>
+            )}
+          >
             <MDXProvider components={MDXComponents}>{children}</MDXProvider>
           </div>
         </main>
       </div>
     </Layout>
   );
-}
+};
 
-function DocPage(props: Props): JSX.Element {
+const DocPage = (props: Props): JSX.Element => {
   const {
-    route: {routes: docRoutes},
+    route: { routes: docRoutes },
     versionMetadata,
     location,
   } = props;
-  const currentDocRoute = docRoutes.find((docRoute) =>
-    matchPath(location.pathname, docRoute),
-  );
+  const currentDocRoute = docRoutes.find((docRoute) => matchPath(location.pathname, docRoute));
   if (!currentDocRoute) {
+    // eslint-disable-next-line @typescript-eslint/ban-ts-comment
+    // @ts-ignore
     return <NotFound {...props} />;
   }
   return (
     <>
       <Head>
         {/* TODO we should add a core addRoute({htmlClassName}) generic plugin option */}
+        {/* eslint-disable-next-line jsx-a11y/html-has-lang */}
         <html className={versionMetadata.className} />
       </Head>
       <DocPageContent
         currentDocRoute={currentDocRoute}
-        versionMetadata={versionMetadata}>
-        {renderRoutes(docRoutes, {versionMetadata})}
+        versionMetadata={versionMetadata}
+      >
+        {renderRoutes(docRoutes, { versionMetadata })}
       </DocPageContent>
     </>
   );
-}
+};
 
 export default DocPage;
diff --git a/website/src/theme/DocSidebar/index.tsx b/website/src/theme/DocSidebar/index.tsx
index 37318f57335..127ce92528f 100644
--- a/website/src/theme/DocSidebar/index.tsx
+++ b/website/src/theme/DocSidebar/index.tsx
@@ -5,30 +5,31 @@
  * LICENSE file in the root directory of this source tree.
  */
 
-import React, {useState} from 'react';
+import type { FC } from 'react';
+import React, { useState } from 'react';
 import clsx from 'clsx';
+// eslint-disable-next-line import/no-extraneous-dependencies
 import {
   useThemeConfig,
   useAnnouncementBar,
   MobileSecondaryMenuFiller,
-  MobileSecondaryMenuComponent,
   ThemeClassNames,
 } from '@docusaurus/theme-common';
 import useWindowSize from '@theme/hooks/useWindowSize';
 import useScrollPosition from '@theme/hooks/useScrollPosition';
 import Logo from '@theme/Logo';
 import IconArrow from '@theme/IconArrow';
-import {translate} from '@docusaurus/Translate';
-import {DocSidebarItems} from '@theme/DocSidebarItem';
-import DocsVersionDropdownNavbarItem from "@theme/NavbarItem/DocsVersionDropdownNavbarItem";
-import type {Props} from '@theme/DocSidebar';
+import { translate } from '@docusaurus/Translate';
+import { DocSidebarItems } from '@theme/DocSidebarItem';
+import DocsVersionDropdownNavbarItem from '@theme/NavbarItem/DocsVersionDropdownNavbarItem';
+import type { Props } from '@theme/DocSidebar';
 
 import styles from './styles.module.css';
 
 function useShowAnnouncementBar() {
-  const {isClosed} = useAnnouncementBar();
+  const { isClosed } = useAnnouncementBar();
   const [showAnnouncementBar, setShowAnnouncementBar] = useState(!isClosed);
-  useScrollPosition(({scrollY}) => {
+  useScrollPosition(({ scrollY }) => {
     if (!isClosed) {
       setShowAnnouncementBar(scrollY === 0);
     }
@@ -36,51 +37,101 @@ function useShowAnnouncementBar() {
   return showAnnouncementBar;
 }
 
-function HideableSidebarButton({onClick}: {onClick: React.MouseEventHandler}) {
+const HideableSidebarButton = ({ onClick }: {onClick: React.MouseEventHandler}) => (
+  <button
+    type="button"
+    title={translate({
+      id: 'theme.docs.sidebar.collapseButtonTitle',
+      message: 'Collapse sidebar',
+      description: 'The title attribute for collapse button of doc sidebar',
+    })}
+    aria-label={translate({
+      id: 'theme.docs.sidebar.collapseButtonAriaLabel',
+      message: 'Collapse sidebar',
+      description: 'The title attribute for collapse button of doc sidebar',
+    })}
+    className={clsx(
+      'button button--secondary button--outline',
+      styles.collapseSidebarButton,
+    )}
+    onClick={onClick}
+  >
+    <IconArrow className={styles.collapseSidebarButtonIcon} />
+  </button>
+);
+
+const DocsVersionWrapper = (props: {docsPluginId: string}) => {
+  const { docsPluginId } = props;
   return (
-    <button
-      type="button"
-      title={translate({
-        id: 'theme.docs.sidebar.collapseButtonTitle',
-        message: 'Collapse sidebar',
-        description: 'The title attribute for collapse button of doc sidebar',
-      })}
-      aria-label={translate({
-        id: 'theme.docs.sidebar.collapseButtonAriaLabel',
-        message: 'Collapse sidebar',
-        description: 'The title attribute for collapse button of doc sidebar',
-      })}
-      className={clsx(
-        'button button--secondary button--outline',
-        styles.collapseSidebarButton,
-      )}
-      onClick={onClick}>
-      <IconArrow className={styles.collapseSidebarButtonIcon} />
-    </button>
+    <div className={styles.sidebarVersionSwitch}>
+      Version:
+      <DocsVersionDropdownNavbarItem
+        docsPluginId={docsPluginId}
+        dropdownItemsBefore={[]}
+        dropdownItemsAfter={[]}
+        items={[]}
+      />
+    </div>
   );
-}
+};
+
+const DocsVersionWrapperMemo = React.memo(DocsVersionWrapper);
+
+ interface DocSidebarMobileSecondaryMenuProps extends Props {
+   docsPluginId: string,
+   toggleSidebar: () => void
+ }
 
-function DocSidebarDesktop({path, sidebar, onCollapse, isHidden, docsPluginId}: Props & {docsPluginId: string}) {
+const DocSidebarMobileSecondaryMenu: FC<DocSidebarMobileSecondaryMenuProps> = ({
+  toggleSidebar,
+  sidebar,
+  path,
+  docsPluginId,
+}) => (
+  <>
+    <DocsVersionWrapperMemo docsPluginId={docsPluginId} />
+    <ul className={clsx(ThemeClassNames.docs.docSidebarMenu, 'menu__list')}>
+      <DocSidebarItems
+        items={sidebar}
+        activePath={path}
+        onItemClick={() => toggleSidebar()}
+      />
+    </ul>
+  </>
+);
+
+const DocSidebarMobile = (props: Props) => (
+  <MobileSecondaryMenuFiller
+    component={DocSidebarMobileSecondaryMenu}
+    props={props}
+  />
+);
+
+const DocSidebarDesktop = ({
+  path, sidebar, onCollapse, isHidden, docsPluginId,
+}: Props & {docsPluginId: string}) => {
   const showAnnouncementBar = useShowAnnouncementBar();
   const {
-    navbar: {hideOnScroll},
+    navbar: { hideOnScroll },
     hideableSidebar,
   } = useThemeConfig();
-  const {isClosed: isAnnouncementBarClosed} = useAnnouncementBar();
+  const { isClosed: isAnnouncementBarClosed } = useAnnouncementBar();
 
   return (
     <div
       className={clsx(styles.sidebar, {
         [styles.sidebarWithHideableNavbar]: hideOnScroll,
         [styles.sidebarHidden]: isHidden,
-      })}>
+      })}
+    >
       {hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />}
       <DocsVersionWrapperMemo docsPluginId={docsPluginId} />
       <nav
         className={clsx('menu thin-scrollbar', styles.menu, {
           [styles.menuWithAnnouncementBar]:
-            !isAnnouncementBarClosed && showAnnouncementBar,
-        })}>
+             !isAnnouncementBarClosed && showAnnouncementBar,
+        })}
+      >
         <ul className={clsx(ThemeClassNames.docs.docSidebarMenu, 'menu__list')}>
           <DocSidebarItems items={sidebar} activePath={path} />
         </ul>
@@ -88,61 +139,16 @@ function DocSidebarDesktop({path, sidebar, onCollapse, isHidden, docsPluginId}:
       {hideableSidebar && <HideableSidebarButton onClick={onCollapse} />}
     </div>
   );
-}
-
-const DocSidebarMobileSecondaryMenu: MobileSecondaryMenuComponent<Props & {docsPluginId: string}> = ({
-  toggleSidebar,
-  sidebar,
-  path,
-  docsPluginId
-}) => {
-  return (
-    <>
-      <DocsVersionWrapperMemo docsPluginId={docsPluginId} />
-      <ul className={clsx(ThemeClassNames.docs.docSidebarMenu, 'menu__list')}>
-        <DocSidebarItems
-            items={sidebar}
-            activePath={path}
-            onItemClick={() => toggleSidebar()}
-        />
-      </ul>
-    </>
-  );
 };
 
-function DocSidebarMobile(props: Props) {
-  return (
-    <MobileSecondaryMenuFiller
-      component={DocSidebarMobileSecondaryMenu}
-      props={props}
-    />
-  );
-}
-
-function DocsVersionWrapper(props: {docsPluginId: string}) {
-  return (
-    <div className={styles.sidebarVersionSwitch}>
-      Version:
-      <DocsVersionDropdownNavbarItem
-          docsPluginId={props.docsPluginId}
-          dropdownItemsBefore={[]}
-          dropdownItemsAfter={[]}
-          items={[]}
-      />
-    </div>
-  );
-}
-
-const DocSidebarDesktopMemo = React.memo(DocSidebarDesktop);
 const DocSidebarMobileMemo = React.memo(DocSidebarMobile);
-const DocsVersionWrapperMemo = React.memo(DocsVersionWrapper);
+const DocSidebarDesktopMemo = React.memo(DocSidebarDesktop);
 
-export default function DocSidebar(props: Props & {docsPluginId: string}): JSX.Element {
+const DocSidebar: FC<Props & {docsPluginId: string}> = (props) => {
   const windowSize = useWindowSize();
 
   // Desktop sidebar visible on hydration: need SSR rendering
-  const shouldRenderSidebarDesktop =
-    windowSize === 'desktop' || windowSize === 'ssr';
+  const shouldRenderSidebarDesktop = windowSize === 'desktop' || windowSize === 'ssr';
 
   // Mobile sidebar not visible on hydration: can avoid SSR rendering
   const shouldRenderSidebarMobile = windowSize === 'mobile';
@@ -153,4 +159,6 @@ export default function DocSidebar(props: Props & {docsPluginId: string}): JSX.E
       {shouldRenderSidebarMobile && <DocSidebarMobileMemo {...props} />}
     </>
   );
-}
+};
+
+export default DocSidebar;