You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pulsar.apache.org by ur...@apache.org on 2022/03/31 05:24:14 UTC

[pulsar-site] branch feature/versions-in-docs-sidebar created (now a7b5933)

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

urfree pushed a change to branch feature/versions-in-docs-sidebar
in repository https://gitbox.apache.org/repos/asf/pulsar-site.git.


      at a7b5933  feat: add versions dropdown menu in docs page

This branch includes the following new commits:

     new a7b5933  feat: add versions dropdown menu in docs page

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


[pulsar-site] 01/01: feat: add versions dropdown menu in docs page

Posted by ur...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

urfree pushed a commit to branch feature/versions-in-docs-sidebar
in repository https://gitbox.apache.org/repos/asf/pulsar-site.git

commit a7b593365034ddfa6685b5eaaae49a9e233d69b8
Author: Li Li <ur...@apache.org>
AuthorDate: Thu Mar 31 13:23:50 2022 +0800

    feat: add versions dropdown menu in docs page
    
    Signed-off-by: Li Li <ur...@apache.org>
---
 site2/website-next/src/css/custom.css              |   4 +
 .../src/theme/DocSidebar/Desktop/index.js          |  59 +++++++++
 .../src/theme/DocSidebar/Desktop/styles.module.css |  68 ++++++++++
 .../src/theme/DocSidebar/Mobile/index.js           |  68 ++++++++++
 .../src/theme/DocSidebar/Mobile/styles.module.css  |  23 ++++
 site2/website-next/src/theme/DocSidebar/index.js   |  24 ++++
 .../src/theme/DocVersionBanner/index.js            | 144 +++++++++++++++++++++
 .../src/theme/DocsVersionDropdownNavbarItem.js     |  97 ++++++++++++++
 8 files changed, 487 insertions(+)

diff --git a/site2/website-next/src/css/custom.css b/site2/website-next/src/css/custom.css
index 39730db..1b80c5d 100644
--- a/site2/website-next/src/css/custom.css
+++ b/site2/website-next/src/css/custom.css
@@ -899,4 +899,8 @@ footer .row.footer__links {
 }
 @media (max-width: 400px){
   .row.footer__links .footer__col:first-child  .footer-items .footer__item a { font-size: 14px;}
+}
+
+.sidebarVersionSwitch_src-theme-DocSidebar-Desktop-styles-module .dropdown__menu {
+  min-width: 165px !important;
 }
\ No newline at end of file
diff --git a/site2/website-next/src/theme/DocSidebar/Desktop/index.js b/site2/website-next/src/theme/DocSidebar/Desktop/index.js
new file mode 100644
index 0000000..166bfe4
--- /dev/null
+++ b/site2/website-next/src/theme/DocSidebar/Desktop/index.js
@@ -0,0 +1,59 @@
+/**
+ * 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 { useThemeConfig } from "@docusaurus/theme-common";
+import Logo from "@theme/Logo";
+import CollapseButton from "@theme/DocSidebar/Desktop/CollapseButton";
+import Content from "@theme/DocSidebar/Desktop/Content";
+import styles from "./styles.module.css";
+import DocsVersionDropdownNavbarItem from "@theme/NavbarItem/DocsVersionDropdownNavbarItem";
+
+function DocSidebarDesktop({
+  path,
+  sidebar,
+  onCollapse,
+  isHidden,
+  docsPluginId,
+}) {
+  const {
+    navbar: { hideOnScroll },
+    hideableSidebar,
+  } = useThemeConfig();
+  return (
+    <div
+      className={clsx(
+        styles.sidebar,
+        hideOnScroll && styles.sidebarWithHideableNavbar,
+        isHidden && styles.sidebarHidden
+      )}
+    >
+      {hideOnScroll && <Logo tabIndex={-1} className={styles.sidebarLogo} />}
+      <DocsVersionWrapperMemo docsPluginId={docsPluginId} />
+      <Content path={path} sidebar={sidebar} />
+      {hideableSidebar && <CollapseButton onClick={onCollapse} />}
+    </div>
+  );
+}
+
+function DocsVersionWrapper(props) {
+  return (
+    <div className={styles.sidebarVersionSwitch}>
+      Version:
+      <DocsVersionDropdownNavbarItem
+        docsPluginId={props.docsPluginId}
+        dropdownItemsBefore={[]}
+        dropdownItemsAfter={[]}
+        items={['Master', 'Legacy']}
+      />
+    </div>
+  );
+}
+
+const DocsVersionWrapperMemo = React.memo(DocsVersionWrapper);
+
+export default React.memo(DocSidebarDesktop);
diff --git a/site2/website-next/src/theme/DocSidebar/Desktop/styles.module.css b/site2/website-next/src/theme/DocSidebar/Desktop/styles.module.css
new file mode 100644
index 0000000..16d3c38
--- /dev/null
+++ b/site2/website-next/src/theme/DocSidebar/Desktop/styles.module.css
@@ -0,0 +1,68 @@
+/**
+ * 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) {
+  .sidebar {
+    display: flex;
+    flex-direction: column;
+    max-height: 100vh;
+    height: 100%;
+    position: sticky;
+    top: 0;
+    padding-top: var(--ifm-navbar-height);
+    width: var(--doc-sidebar-width);
+    transition: opacity 50ms ease;
+  }
+
+  .sidebarWithHideableNavbar {
+    padding-top: 0;
+  }
+
+  .sidebarHidden {
+    opacity: 0;
+    height: 0;
+    overflow: hidden;
+    visibility: hidden;
+  }
+
+  .sidebarLogo {
+    display: flex !important;
+    align-items: center;
+    margin: 0 var(--ifm-navbar-padding-horizontal);
+    min-height: var(--ifm-navbar-height);
+    max-height: var(--ifm-navbar-height);
+    color: inherit !important;
+    text-decoration: none !important;
+  }
+
+  .sidebarLogo img {
+    margin-right: 0.5rem;
+    height: 2rem;
+  }
+}
+
+.sidebarLogo {
+  display: none;
+}
+
+.sidebarVersionSwitch {
+  display: flex;
+  align-items: center;
+  padding: 4px 1rem;
+  margin: 1rem;
+  border-radius: 0.5rem;
+  border: 1px solid #198fff;
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
+}
+
+.sidebarVersionSwitch a {
+  display: inline-block;
+}
+
+.sidebarVersionSwitch div {
+  display: inline-block !important;
+}
diff --git a/site2/website-next/src/theme/DocSidebar/Mobile/index.js b/site2/website-next/src/theme/DocSidebar/Mobile/index.js
new file mode 100644
index 0000000..c4d1d4e
--- /dev/null
+++ b/site2/website-next/src/theme/DocSidebar/Mobile/index.js
@@ -0,0 +1,68 @@
+/**
+ * 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 {
+  NavbarSecondaryMenuFiller,
+  ThemeClassNames,
+  useNavbarMobileSidebar,
+} from "@docusaurus/theme-common";
+import DocSidebarItems from "@theme/DocSidebarItems";
+import styles from "./styles.module.css";
+import DocsVersionDropdownNavbarItem from "@theme/NavbarItem/DocsVersionDropdownNavbarItem";
+
+// eslint-disable-next-line react/function-component-definition
+const DocSidebarMobileSecondaryMenu = ({ sidebar, path, docsPluginId }) => {
+  const mobileSidebar = useNavbarMobileSidebar();
+  return (
+    <ul className={clsx(ThemeClassNames.docs.docSidebarMenu, "menu__list")}>
+      <DocsVersionWrapperMemo docsPluginId={docsPluginId} />
+      <DocSidebarItems
+        items={sidebar}
+        activePath={path}
+        onItemClick={(item) => {
+          // Mobile sidebar should only be closed if the category has a link
+          if (item.type === "category" && item.href) {
+            mobileSidebar.toggle();
+          }
+
+          if (item.type === "link") {
+            mobileSidebar.toggle();
+          }
+        }}
+        level={1}
+      />
+    </ul>
+  );
+};
+
+function DocSidebarMobile(props) {
+  return (
+    <NavbarSecondaryMenuFiller
+      component={DocSidebarMobileSecondaryMenu}
+      props={props}
+    />
+  );
+}
+
+function DocsVersionWrapper(props) {
+  return (
+    <div className={styles.sidebarVersionSwitch}>
+      Version:
+      <DocsVersionDropdownNavbarItem
+        docsPluginId={props.docsPluginId}
+        dropdownItemsBefore={[]}
+        dropdownItemsAfter={[]}
+        items={["Master", "Legacy"]}
+      />
+    </div>
+  );
+}
+
+const DocsVersionWrapperMemo = React.memo(DocsVersionWrapper);
+
+export default React.memo(DocSidebarMobile);
diff --git a/site2/website-next/src/theme/DocSidebar/Mobile/styles.module.css b/site2/website-next/src/theme/DocSidebar/Mobile/styles.module.css
new file mode 100644
index 0000000..9527b6e
--- /dev/null
+++ b/site2/website-next/src/theme/DocSidebar/Mobile/styles.module.css
@@ -0,0 +1,23 @@
+/**
+ * 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.
+ */
+.sidebarVersionSwitch {
+  display: flex;
+  align-items: center;
+  padding: 4px 1rem;
+  margin: 1rem;
+  border-radius: 0.5rem;
+  border: 1px solid #198fff;
+  box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.03);
+}
+
+.sidebarVersionSwitch a {
+  display: inline-block;
+}
+
+.sidebarVersionSwitch div {
+  display: inline-block !important;
+}
diff --git a/site2/website-next/src/theme/DocSidebar/index.js b/site2/website-next/src/theme/DocSidebar/index.js
new file mode 100644
index 0000000..a84c73a
--- /dev/null
+++ b/site2/website-next/src/theme/DocSidebar/index.js
@@ -0,0 +1,24 @@
+/**
+ * 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 {useWindowSize} from '@docusaurus/theme-common';
+import DocSidebarDesktop from '@theme/DocSidebar/Desktop';
+import DocSidebarMobile from '@theme/DocSidebar/Mobile';
+export default function DocSidebar(props) {
+  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 && <DocSidebarDesktop {...props} />}
+      {shouldRenderSidebarMobile && <DocSidebarMobile {...props} />}
+    </>
+  );
+}
diff --git a/site2/website-next/src/theme/DocVersionBanner/index.js b/site2/website-next/src/theme/DocVersionBanner/index.js
new file mode 100644
index 0000000..733d144
--- /dev/null
+++ b/site2/website-next/src/theme/DocVersionBanner/index.js
@@ -0,0 +1,144 @@
+/**
+ * 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 useDocusaurusContext from '@docusaurus/useDocusaurusContext';
+import Link from '@docusaurus/Link';
+import Translate from '@docusaurus/Translate';
+import {
+  useActivePlugin,
+  useDocVersionSuggestions,
+} from '@docusaurus/plugin-content-docs/client';
+import {
+  ThemeClassNames,
+  useDocsPreferredVersion,
+  useDocsVersion,
+} from '@docusaurus/theme-common';
+import clsx from 'clsx';
+
+function UnreleasedVersionLabel({siteTitle, versionMetadata}) {
+  return (
+    <Translate
+      id="theme.docs.versions.unreleasedVersionLabel"
+      description="The label used to tell the user that he's browsing an unreleased doc version"
+      values={{
+        siteTitle,
+        versionLabel: <b>{versionMetadata.label}</b>,
+      }}>
+      {
+        'This is unreleased documentation for {siteTitle} {versionLabel} version.'
+      }
+    </Translate>
+  );
+}
+
+function UnmaintainedVersionLabel({siteTitle, versionMetadata}) {
+  return (
+    <Translate
+      id="theme.docs.versions.unmaintainedVersionLabel"
+      description="The label used to tell the user that he's browsing an unmaintained doc version"
+      values={{
+        siteTitle,
+        versionLabel: <b>{versionMetadata.label}</b>,
+      }}>
+      {
+        'This is documentation for {siteTitle} {versionLabel}, which is no longer actively maintained.'
+      }
+    </Translate>
+  );
+}
+
+const BannerLabelComponents = {
+  unreleased: UnreleasedVersionLabel,
+  unmaintained: UnmaintainedVersionLabel,
+};
+
+function BannerLabel(props) {
+  const BannerLabelComponent =
+    BannerLabelComponents[props.versionMetadata.banner];
+  return <BannerLabelComponent {...props} />;
+}
+
+function LatestVersionSuggestionLabel({versionLabel, to, onClick}) {
+  return (
+    <Translate
+      id="theme.docs.versions.latestVersionSuggestionLabel"
+      description="The label used to tell the user to check the latest version"
+      values={{
+        versionLabel,
+        latestVersionLink: (
+          <b>
+            <Link to={to} onClick={onClick}>
+              <Translate
+                id="theme.docs.versions.latestVersionLinkLabel"
+                description="The label used for the latest version suggestion link label">
+                latest version
+              </Translate>
+            </Link>
+          </b>
+        ),
+      }}>
+      {
+        'For up-to-date documentation, see the {latestVersionLink} ({versionLabel}).'
+      }
+    </Translate>
+  );
+}
+
+function DocVersionBannerEnabled({className, versionMetadata}) {
+  const {
+    siteConfig: {title: siteTitle},
+  } = useDocusaurusContext();
+  const {pluginId} = useActivePlugin({
+    failfast: true,
+  });
+
+  const getVersionMainDoc = (version) =>
+    version.docs.find((doc) => doc.id === version.mainDocId);
+
+  const {savePreferredVersionName} = useDocsPreferredVersion(pluginId);
+  const {latestDocSuggestion, latestVersionSuggestion} =
+    useDocVersionSuggestions(pluginId); // try to link to same doc in latest version (not always possible)
+  // fallback to main doc of latest version
+
+  const latestVersionSuggestedDoc =
+    latestDocSuggestion ?? getVersionMainDoc(latestVersionSuggestion);
+  return (
+    <div
+      className={clsx(
+        className,
+        ThemeClassNames.docs.docVersionBanner,
+        'alert alert--warning margin-bottom--md',
+      )}
+      role="alert">
+      <div>
+        <BannerLabel siteTitle={siteTitle} versionMetadata={versionMetadata} />
+      </div>
+      <div className="margin-top--md">
+        <LatestVersionSuggestionLabel
+          versionLabel={latestVersionSuggestion.label}
+          to={latestVersionSuggestedDoc.path}
+          onClick={() => savePreferredVersionName(latestVersionSuggestion.name)}
+        />
+      </div>
+    </div>
+  );
+}
+
+export default function DocVersionBanner({className}) {
+  const versionMetadata = useDocsVersion();
+
+  if (versionMetadata.banner) {
+    return (
+      <DocVersionBannerEnabled
+        className={className}
+        versionMetadata={versionMetadata}
+      />
+    );
+  }
+
+  return null;
+}
diff --git a/site2/website-next/src/theme/DocsVersionDropdownNavbarItem.js b/site2/website-next/src/theme/DocsVersionDropdownNavbarItem.js
new file mode 100644
index 0000000..9d7a178
--- /dev/null
+++ b/site2/website-next/src/theme/DocsVersionDropdownNavbarItem.js
@@ -0,0 +1,97 @@
+/**
+ * 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 DefaultNavbarItem from '@theme/NavbarItem/DefaultNavbarItem';
+import DropdownNavbarItem from '@theme/NavbarItem/DropdownNavbarItem';
+import {
+  useVersions,
+  useLatestVersion,
+  useActiveDocContext,
+} from '@docusaurus/plugin-content-docs/client';
+import {useDocsPreferredVersion} from '@docusaurus/theme-common';
+import {translate} from '@docusaurus/Translate';
+
+const getVersionMainDoc = (version) =>
+  version.docs.find((doc) => doc.id === version.mainDocId);
+
+export default function DocsVersionDropdownNavbarItem({
+  mobile,
+  docsPluginId,
+  dropdownActiveClassDisabled,
+  dropdownItemsBefore,
+  dropdownItemsAfter,
+  ...props
+}) {
+  const activeDocContext = useActiveDocContext(docsPluginId);
+  const versions = useVersions(docsPluginId);
+  const latestVersion = useLatestVersion(docsPluginId);
+  const {preferredVersion, savePreferredVersionName} =
+    useDocsPreferredVersion(docsPluginId);
+
+  function getItems() {
+    const versionLinks = versions.map((version) => {
+      // We try to link to the same doc, in another version
+      // When not possible, fallback to the "main doc" of the version
+      const versionDoc =
+        activeDocContext?.alternateDocVersions[version.name] ||
+        getVersionMainDoc(version);
+      return {
+        isNavLink: true,
+        label: version.label,
+        to: versionDoc.path,
+        isActive: () => version === activeDocContext?.activeVersion,
+        onClick: () => {
+          savePreferredVersionName(version.name);
+        },
+      };
+    });
+    return [...dropdownItemsBefore, ...versionLinks, ...dropdownItemsAfter];
+  }
+
+  const items = getItems();
+  const dropdownVersion =
+    activeDocContext.activeVersion ?? preferredVersion ?? latestVersion; // Mobile dropdown is handled a bit differently
+
+  const dropdownLabel =
+    mobile && items.length > 1
+      ? translate({
+          id: 'theme.navbar.mobileVersionsDropdown.label',
+          message: 'Versions',
+          description:
+            'The label for the navbar versions dropdown on mobile view',
+        })
+      : dropdownVersion.label;
+  const dropdownTo =
+    mobile && items.length > 1
+      ? undefined
+      : getVersionMainDoc(dropdownVersion).path; // We don't want to render a version dropdown with 0 or 1 item. If we build
+  // the site with a single docs version (onlyIncludeVersions: ['1.0.0']),
+  // We'd rather render a button instead of a dropdown
+
+  if (items.length <= 1) {
+    return (
+      <DefaultNavbarItem
+        {...props}
+        mobile={mobile}
+        label={dropdownLabel}
+        to={dropdownTo}
+        isActive={dropdownActiveClassDisabled ? () => false : undefined}
+      />
+    );
+  }
+
+  return (
+    <DropdownNavbarItem
+      {...props}
+      mobile={mobile}
+      label={dropdownLabel}
+      to={dropdownTo}
+      items={items}
+      isActive={dropdownActiveClassDisabled ? () => false : undefined}
+    />
+  );
+}