Files
medusa-store/www/packages/docs-ui/src/components/Sidebar/index.tsx
T
Shahed Nasser c63a08fb03 docs: second round of polishing (#8724)
* docs: second round of polishing

* fix overflowing width
2024-08-23 10:42:23 +03:00

158 lines
4.8 KiB
TypeScript

"use client"
import React, { useMemo, useRef } from "react"
import { useSidebar } from "@/providers"
import clsx from "clsx"
import { DottedSeparator, Loading } from "@/components"
import { SidebarItem } from "./Item"
import { CSSTransition, SwitchTransition } from "react-transition-group"
import { SidebarTop, SidebarTopProps } from "./Top"
import useResizeObserver from "@react-hook/resize-observer"
import { useClickOutside, useKeyboardShortcut } from "@/hooks"
export type SidebarProps = {
className?: string
expandItems?: boolean
sidebarTopProps?: Omit<SidebarTopProps, "parentItem">
}
export const Sidebar = ({
className = "",
expandItems = true,
sidebarTopProps,
}: SidebarProps) => {
const sidebarWrapperRef = useRef(null)
const sidebarTopRef = useRef<HTMLDivElement>(null)
const {
items,
currentItems,
mobileSidebarOpen,
setMobileSidebarOpen,
staticSidebarItems,
sidebarRef,
sidebarTopHeight,
setSidebarTopHeight,
desktopSidebarOpen,
setDesktopSidebarOpen,
} = useSidebar()
useClickOutside({
elmRef: sidebarWrapperRef,
onClickOutside: () => {
if (mobileSidebarOpen) {
setMobileSidebarOpen(false)
}
},
})
useKeyboardShortcut({
metakey: true,
shortcutKeys: ["\\"],
action: () => {
setDesktopSidebarOpen((prev) => !prev)
},
})
const sidebarItems = useMemo(
() => currentItems || items,
[items, currentItems]
)
useResizeObserver(sidebarTopRef, () => {
setSidebarTopHeight(sidebarTopRef.current?.clientHeight || 0)
})
return (
<>
{mobileSidebarOpen && (
<div
className={clsx(
"lg:hidden bg-medusa-bg-overlay opacity-70",
"fixed top-0 left-0 w-full h-full z-[45]"
)}
></div>
)}
<aside
className={clsx(
"bg-medusa-bg-base lg:bg-transparent block",
"fixed -left-full top-0 h-[calc(100%-16px)] transition-[left] lg:relative lg:h-auto",
"max-w-sidebar-xs sm:max-w-sidebar-sm md:max-w-sidebar-md lg:max-w-sidebar-lg",
"xl:max-w-sidebar-xl xxl:max-w-sidebar-xxl xxxl:max-w-sidebar-xxxl",
"w-sidebar-xs sm:w-auto",
mobileSidebarOpen && [
"!left-docs_0.5 !top-docs_0.5 z-50 shadow-elevation-modal dark:shadow-elevation-modal-dark",
"rounded",
"lg:!left-0 lg:!top-0 lg:shadow-none",
],
desktopSidebarOpen && "lg:left-0",
!desktopSidebarOpen && "lg:!absolute lg:!-left-full",
className
)}
style={{
animationFillMode: "forwards",
}}
ref={sidebarWrapperRef}
>
<ul className={clsx("h-full w-full", "flex flex-col")}>
<SidebarTop
{...sidebarTopProps}
parentItem={sidebarItems.parentItem}
ref={sidebarTopRef}
/>
<SwitchTransition>
<CSSTransition
key={sidebarItems.parentItem?.title || "home"}
nodeRef={sidebarRef}
classNames={{
enter: "animate-fadeInLeft animate-fast",
exit: "animate-fadeOutLeft animate-fast",
}}
timeout={200}
>
<div
className={clsx(
"overflow-y-scroll clip",
"py-docs_0.75 flex-1"
)}
ref={sidebarRef}
style={{
maxHeight: `calc(100vh - ${sidebarTopHeight}px)`,
}}
id="sidebar"
>
{/* MOBILE SIDEBAR */}
<div className={clsx("lg:hidden")}>
{!sidebarItems.mobile.length && !staticSidebarItems && (
<Loading className="px-0" />
)}
{sidebarItems.mobile.map((item, index) => (
<SidebarItem
item={item}
key={index}
expandItems={expandItems}
hasNextItems={index !== sidebarItems.default.length - 1}
/>
))}
<DottedSeparator />
</div>
{/* DESKTOP SIDEBAR */}
<div className="mt-docs_0.75 lg:mt-0">
{!sidebarItems.default.length && !staticSidebarItems && (
<Loading className="px-0" />
)}
{sidebarItems.default.map((item, index) => (
<SidebarItem
item={item}
key={index}
expandItems={expandItems}
hasNextItems={index !== sidebarItems.default.length - 1}
/>
))}
</div>
</div>
</CSSTransition>
</SwitchTransition>
</ul>
</aside>
</>
)
}