docs: enhanced sidebar context (#4165)
This commit is contained in:
1 parent
0a35f21af7
commit
e281469eb8
8 files changed
+124
-77
No files matched your search
@@ -3,6 +3,7 @@ import BorderedIcon from "../BorderedIcon"
|
|||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import Badge from "../Badge"
|
import Badge from "../Badge"
|
||||||
import { IconProps } from "@site/src/theme/Icon/index"
|
import { IconProps } from "@site/src/theme/Icon/index"
|
||||||
|
import Link from "@docusaurus/Link"
|
||||||
|
|
||||||
type LargeCardProps = {
|
type LargeCardProps = {
|
||||||
Icon: React.FC<IconProps>
|
Icon: React.FC<IconProps>
|
||||||
@@ -78,13 +79,13 @@ const LargeCard: React.FC<LargeCardProps> = ({
|
|||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<a
|
<Link
|
||||||
href={href}
|
href={href}
|
||||||
className={clsx(
|
className={clsx(
|
||||||
"tw-absolute tw-top-0 tw-left-0 tw-w-full tw-h-full tw-z-[4] tw-rounded",
|
"tw-absolute tw-top-0 tw-left-0 tw-w-full tw-h-full tw-z-[4] tw-rounded",
|
||||||
isSoon && "group-hover:tw-pointer-events-none"
|
isSoon && "group-hover:tw-pointer-events-none"
|
||||||
)}
|
)}
|
||||||
></a>
|
></Link>
|
||||||
</article>
|
</article>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,103 @@
|
|||||||
|
import React, {
|
||||||
|
createContext,
|
||||||
|
useCallback,
|
||||||
|
useContext,
|
||||||
|
useEffect,
|
||||||
|
useState,
|
||||||
|
} from "react"
|
||||||
|
import { prefersReducedMotion } from "@docusaurus/theme-common"
|
||||||
|
import useIsBrowser from "@docusaurus/useIsBrowser"
|
||||||
|
|
||||||
|
type SidebarContextType = {
|
||||||
|
hasSidebar: boolean
|
||||||
|
hiddenSidebar: boolean
|
||||||
|
setHiddenSidebar: (value: boolean) => void
|
||||||
|
hiddenSidebarContainer: boolean
|
||||||
|
setHiddenSidebarContainer: (value: boolean) => void
|
||||||
|
floatingSidebar: boolean
|
||||||
|
setFloatingSidebar: (value: boolean) => void
|
||||||
|
onCollapse: () => void
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidebarContext = createContext<SidebarContextType | null>(null)
|
||||||
|
|
||||||
|
type SidebarProviderProps = {
|
||||||
|
sidebarName?: string
|
||||||
|
children?: React.ReactNode
|
||||||
|
}
|
||||||
|
|
||||||
|
const SidebarProvider: React.FC<SidebarProviderProps> = ({
|
||||||
|
sidebarName,
|
||||||
|
children,
|
||||||
|
}) => {
|
||||||
|
const [hiddenSidebar, setHiddenSidebar] = useState(false)
|
||||||
|
const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false)
|
||||||
|
const [floatingSidebar, setFloatingSidebar] = useState(false)
|
||||||
|
|
||||||
|
const toggleSidebar = useCallback(() => {
|
||||||
|
if (hiddenSidebar) {
|
||||||
|
setHiddenSidebar(false)
|
||||||
|
}
|
||||||
|
// onTransitionEnd won't fire when sidebar animation is disabled
|
||||||
|
// fixes https://github.com/facebook/docusaurus/issues/8918
|
||||||
|
if (!hiddenSidebar && prefersReducedMotion()) {
|
||||||
|
setHiddenSidebar(true)
|
||||||
|
}
|
||||||
|
setHiddenSidebarContainer((value) => !value)
|
||||||
|
}, [setHiddenSidebarContainer, hiddenSidebar])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
function isEditingContent(event: KeyboardEvent) {
|
||||||
|
const element = event.target as HTMLElement
|
||||||
|
const tagName = element.tagName
|
||||||
|
return (
|
||||||
|
element.isContentEditable ||
|
||||||
|
tagName === "INPUT" ||
|
||||||
|
tagName === "SELECT" ||
|
||||||
|
tagName === "TEXTAREA"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function sidebarShortcut(e: KeyboardEvent) {
|
||||||
|
if (
|
||||||
|
(e.metaKey || e.ctrlKey) &&
|
||||||
|
e.key.toLowerCase() === "i" &&
|
||||||
|
!isEditingContent(e)
|
||||||
|
) {
|
||||||
|
e.preventDefault()
|
||||||
|
toggleSidebar()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addEventListener("keydown", sidebarShortcut)
|
||||||
|
|
||||||
|
return () => {
|
||||||
|
window.removeEventListener("keydown", sidebarShortcut)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SidebarContext.Provider
|
||||||
|
value={{
|
||||||
|
hasSidebar: sidebarName !== undefined,
|
||||||
|
hiddenSidebar,
|
||||||
|
setHiddenSidebar,
|
||||||
|
hiddenSidebarContainer,
|
||||||
|
setHiddenSidebarContainer,
|
||||||
|
floatingSidebar,
|
||||||
|
setFloatingSidebar,
|
||||||
|
onCollapse: toggleSidebar,
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</SidebarContext.Provider>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SidebarProvider
|
||||||
|
|
||||||
|
export const useSidebar = () => {
|
||||||
|
const context = useContext(SidebarContext)
|
||||||
|
|
||||||
|
return context
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useContext } from "react"
|
import React from "react"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { useWindowSize } from "@docusaurus/theme-common"
|
import { useWindowSize } from "@docusaurus/theme-common"
|
||||||
import { useDoc } from "@docusaurus/theme-common/internal"
|
import { useDoc } from "@docusaurus/theme-common/internal"
|
||||||
@@ -12,7 +12,7 @@ import DocItemContent from "@theme/DocItem/Content"
|
|||||||
import DocBreadcrumbs from "@theme/DocBreadcrumbs"
|
import DocBreadcrumbs from "@theme/DocBreadcrumbs"
|
||||||
import type { Props } from "@theme/DocItem/Layout"
|
import type { Props } from "@theme/DocItem/Layout"
|
||||||
import Footer from "@theme/Footer"
|
import Footer from "@theme/Footer"
|
||||||
import { SidebarContext } from "@site/src/context/sidebar"
|
import { useSidebar } from "@site/src/providers/Sidebar"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decide if the toc should be rendered, on mobile or desktop viewports
|
* Decide if the toc should be rendered, on mobile or desktop viewports
|
||||||
@@ -40,7 +40,7 @@ function useDocTOC() {
|
|||||||
|
|
||||||
export default function DocItemLayout({ children }: Props): JSX.Element {
|
export default function DocItemLayout({ children }: Props): JSX.Element {
|
||||||
const docTOC = useDocTOC()
|
const docTOC = useDocTOC()
|
||||||
const sidebarContext = useContext(SidebarContext)
|
const sidebarContext = useSidebar()
|
||||||
return (
|
return (
|
||||||
<div className="row tw-m-0">
|
<div className="row tw-m-0">
|
||||||
<div
|
<div
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
import React, { useContext } from "react"
|
import React from "react"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { useDocsSidebar } from "@docusaurus/theme-common/internal"
|
import { useDocsSidebar } from "@docusaurus/theme-common/internal"
|
||||||
import type { Props } from "@theme/DocPage/Layout/Main"
|
import type { Props } from "@theme/DocPage/Layout/Main"
|
||||||
import { SidebarContext } from "@site/src/context/sidebar"
|
import { useSidebar } from "@site/src/providers/Sidebar"
|
||||||
|
|
||||||
export default function DocPageLayoutMain({ children }: Props): JSX.Element {
|
export default function DocPageLayoutMain({ children }: Props): JSX.Element {
|
||||||
const sidebar = useDocsSidebar()
|
const sidebar = useDocsSidebar()
|
||||||
const sidebarContext = useContext(SidebarContext)
|
const sidebarContext = useSidebar()
|
||||||
return (
|
return (
|
||||||
<main
|
<main
|
||||||
className={clsx(
|
className={clsx(
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { type ReactNode, useRef, useContext } from "react"
|
import React, { type ReactNode, useRef } from "react"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { ThemeClassNames } from "@docusaurus/theme-common"
|
import { ThemeClassNames } from "@docusaurus/theme-common"
|
||||||
import { useDocsSidebar } from "@docusaurus/theme-common/internal"
|
import { useDocsSidebar } from "@docusaurus/theme-common/internal"
|
||||||
@@ -6,7 +6,7 @@ import { useLocation } from "@docusaurus/router"
|
|||||||
import DocSidebar from "@theme/DocSidebar"
|
import DocSidebar from "@theme/DocSidebar"
|
||||||
import type { Props } from "@theme/DocPage/Layout/Sidebar"
|
import type { Props } from "@theme/DocPage/Layout/Sidebar"
|
||||||
import { SwitchTransition, CSSTransition } from "react-transition-group"
|
import { SwitchTransition, CSSTransition } from "react-transition-group"
|
||||||
import { SidebarContext } from "@site/src/context/sidebar"
|
import { useSidebar } from "@site/src/providers/Sidebar"
|
||||||
|
|
||||||
// Reset sidebar state when sidebar changes
|
// Reset sidebar state when sidebar changes
|
||||||
// Use React key to unmount/remount the children
|
// Use React key to unmount/remount the children
|
||||||
@@ -25,7 +25,7 @@ export default function DocPageLayoutSidebar({
|
|||||||
hiddenSidebarContainer,
|
hiddenSidebarContainer,
|
||||||
}: Props): JSX.Element {
|
}: Props): JSX.Element {
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const sidebarContext = useContext(SidebarContext)
|
const sidebarContext = useSidebar()
|
||||||
const { name } = useDocsSidebar()
|
const { name } = useDocsSidebar()
|
||||||
const sidebarRef = useRef(null)
|
const sidebarRef = useRef(null)
|
||||||
|
|
||||||
|
|||||||
@@ -1,16 +1,16 @@
|
|||||||
import React, { useContext } from "react"
|
import React from "react"
|
||||||
import { useDocsSidebar } from "@docusaurus/theme-common/internal"
|
import { useDocsSidebar } from "@docusaurus/theme-common/internal"
|
||||||
import Layout from "@theme/Layout"
|
import Layout from "@theme/Layout"
|
||||||
import BackToTopButton from "@theme/BackToTopButton"
|
import BackToTopButton from "@theme/BackToTopButton"
|
||||||
import DocPageLayoutSidebar from "@theme/DocPage/Layout/Sidebar"
|
import DocPageLayoutSidebar from "@theme/DocPage/Layout/Sidebar"
|
||||||
import DocPageLayoutMain from "@theme/DocPage/Layout/Main"
|
import DocPageLayoutMain from "@theme/DocPage/Layout/Main"
|
||||||
import type { Props } from "@theme/DocPage/Layout"
|
import type { Props } from "@theme/DocPage/Layout"
|
||||||
import { SidebarContext } from "@site/src/context/sidebar"
|
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
|
import { useSidebar } from "@site/src/providers/Sidebar"
|
||||||
|
|
||||||
export default function DocPageLayout({ children }: Props): JSX.Element {
|
export default function DocPageLayout({ children }: Props): JSX.Element {
|
||||||
const sidebar = useDocsSidebar()
|
const sidebar = useDocsSidebar()
|
||||||
const sidebarContext = useContext(SidebarContext)
|
const sidebarContext = useSidebar()
|
||||||
return (
|
return (
|
||||||
<Layout wrapperClassName={clsx("tw-flex tw-flex-[1_0_auto]")}>
|
<Layout wrapperClassName={clsx("tw-flex tw-flex-[1_0_auto]")}>
|
||||||
<BackToTopButton />
|
<BackToTopButton />
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import NotFound from "@theme/NotFound"
|
|||||||
import SearchMetadata from "@theme/SearchMetadata"
|
import SearchMetadata from "@theme/SearchMetadata"
|
||||||
import type { Props } from "@theme/DocPage"
|
import type { Props } from "@theme/DocPage"
|
||||||
import { SidebarContext } from "@site/src/context/sidebar"
|
import { SidebarContext } from "@site/src/context/sidebar"
|
||||||
|
import SidebarProvider from "@site/src/providers/Sidebar"
|
||||||
|
|
||||||
function DocPageMetadata(props: Props): JSX.Element {
|
function DocPageMetadata(props: Props): JSX.Element {
|
||||||
const { versionMetadata } = props
|
const { versionMetadata } = props
|
||||||
@@ -46,53 +47,6 @@ export default function DocPage(props: Props): JSX.Element {
|
|||||||
}
|
}
|
||||||
const { docElement, sidebarName, sidebarItems } = currentDocRouteMetadata
|
const { docElement, sidebarName, sidebarItems } = currentDocRouteMetadata
|
||||||
|
|
||||||
const [hiddenSidebar, setHiddenSidebar] = useState(false)
|
|
||||||
const [hiddenSidebarContainer, setHiddenSidebarContainer] = useState(false)
|
|
||||||
const [floatingSidebar, setFloatingSidebar] = useState(false)
|
|
||||||
const toggleSidebar = useCallback(() => {
|
|
||||||
if (hiddenSidebar) {
|
|
||||||
setHiddenSidebar(false)
|
|
||||||
}
|
|
||||||
// onTransitionEnd won't fire when sidebar animation is disabled
|
|
||||||
// fixes https://github.com/facebook/docusaurus/issues/8918
|
|
||||||
if (!hiddenSidebar && prefersReducedMotion()) {
|
|
||||||
setHiddenSidebar(true)
|
|
||||||
}
|
|
||||||
setHiddenSidebarContainer((value) => !value)
|
|
||||||
}, [setHiddenSidebarContainer, hiddenSidebar])
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
function isEditingContent(event: KeyboardEvent) {
|
|
||||||
const element = event.target as HTMLElement
|
|
||||||
const tagName = element.tagName
|
|
||||||
return (
|
|
||||||
element.isContentEditable ||
|
|
||||||
tagName === "INPUT" ||
|
|
||||||
tagName === "SELECT" ||
|
|
||||||
tagName === "TEXTAREA"
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
function sidebarShortcut(e: KeyboardEvent) {
|
|
||||||
if (
|
|
||||||
(e.metaKey || e.ctrlKey) &&
|
|
||||||
e.key.toLowerCase() === "i" &&
|
|
||||||
!isEditingContent(e)
|
|
||||||
) {
|
|
||||||
e.preventDefault()
|
|
||||||
toggleSidebar()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener("keydown", sidebarShortcut)
|
|
||||||
|
|
||||||
return () => {
|
|
||||||
window.removeEventListener("keydown", sidebarShortcut)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
console.log(sidebarName)
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<DocPageMetadata {...props} />
|
<DocPageMetadata {...props} />
|
||||||
@@ -107,20 +61,9 @@ export default function DocPage(props: Props): JSX.Element {
|
|||||||
>
|
>
|
||||||
<DocsVersionProvider version={versionMetadata}>
|
<DocsVersionProvider version={versionMetadata}>
|
||||||
<DocsSidebarProvider name={sidebarName} items={sidebarItems}>
|
<DocsSidebarProvider name={sidebarName} items={sidebarItems}>
|
||||||
<SidebarContext.Provider
|
<SidebarProvider sidebarName={sidebarName}>
|
||||||
value={{
|
|
||||||
hasSidebar: sidebarName !== undefined,
|
|
||||||
hiddenSidebar,
|
|
||||||
setHiddenSidebar,
|
|
||||||
hiddenSidebarContainer,
|
|
||||||
setHiddenSidebarContainer,
|
|
||||||
floatingSidebar,
|
|
||||||
setFloatingSidebar,
|
|
||||||
onCollapse: toggleSidebar,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<DocPageLayout>{docElement}</DocPageLayout>
|
<DocPageLayout>{docElement}</DocPageLayout>
|
||||||
</SidebarContext.Provider>
|
</SidebarProvider>
|
||||||
</DocsSidebarProvider>
|
</DocsSidebarProvider>
|
||||||
</DocsVersionProvider>
|
</DocsVersionProvider>
|
||||||
</HtmlClassNameProvider>
|
</HtmlClassNameProvider>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React, { useContext, type ReactNode } from "react"
|
import React, { type ReactNode } from "react"
|
||||||
import { useThemeConfig } from "@docusaurus/theme-common"
|
import { useThemeConfig } from "@docusaurus/theme-common"
|
||||||
import {
|
import {
|
||||||
splitNavbarItems,
|
splitNavbarItems,
|
||||||
@@ -13,7 +13,7 @@ import Tooltip from "@site/src/components/Tooltip"
|
|||||||
import { ThemeConfig } from "@medusajs/docs"
|
import { ThemeConfig } from "@medusajs/docs"
|
||||||
import useIsBrowser from "@docusaurus/useIsBrowser"
|
import useIsBrowser from "@docusaurus/useIsBrowser"
|
||||||
import clsx from "clsx"
|
import clsx from "clsx"
|
||||||
import { SidebarContext } from "@site/src/context/sidebar"
|
import { useSidebar } from "@site/src/providers/Sidebar"
|
||||||
|
|
||||||
function useNavbarItems() {
|
function useNavbarItems() {
|
||||||
// TODO temporary casting until ThemeConfig type is improved
|
// TODO temporary casting until ThemeConfig type is improved
|
||||||
@@ -70,7 +70,7 @@ export default function NavbarContent(): JSX.Element {
|
|||||||
sidebar: { hideable },
|
sidebar: { hideable },
|
||||||
},
|
},
|
||||||
} = useThemeConfig() as ThemeConfig
|
} = useThemeConfig() as ThemeConfig
|
||||||
const sidebarContext = useContext(SidebarContext)
|
const sidebarContext = useSidebar()
|
||||||
const isBrowser = useIsBrowser()
|
const isBrowser = useIsBrowser()
|
||||||
|
|
||||||
const isApple = isBrowser
|
const isApple = isBrowser
|
||||||
|
|||||||
Reference in new issue
Block a user