From deaac19bec631362b54e2b4b2e36385ef1680fe0 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 31 Jul 2024 10:34:45 +0300 Subject: [PATCH 01/38] initial changes --- www/apps/book/app/layout.tsx | 5 +- .../src/components/Sidebar/Back/index.tsx | 26 --------- .../src/components/Sidebar/Title/index.tsx | 7 ++- .../Sidebar/Top/Separator/index.tsx | 16 ++++++ .../src/components/Sidebar/Top/index.tsx | 26 +++++++++ .../docs-ui/src/components/Sidebar/index.tsx | 46 +++++++--------- www/packages/docs-ui/src/layouts/root.tsx | 24 +++++--- www/packages/docs-ui/src/layouts/tight.tsx | 21 +++---- www/packages/tailwind/base.tailwind.config.js | 55 +++++++++++++++---- 9 files changed, 134 insertions(+), 92 deletions(-) delete mode 100644 www/packages/docs-ui/src/components/Sidebar/Back/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/index.tsx diff --git a/www/apps/book/app/layout.tsx b/www/apps/book/app/layout.tsx index 1dfd2ea4b2553..c4e31648b3073 100644 --- a/www/apps/book/app/layout.tsx +++ b/www/apps/book/app/layout.tsx @@ -40,10 +40,11 @@ export default function RootLayout({ return ( , + sidebarTopProps: { + banner: , + }, }} showPagination={true} bodyClassName={clsx(inter.variable, robotoMono.variable)} diff --git a/www/packages/docs-ui/src/components/Sidebar/Back/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Back/index.tsx deleted file mode 100644 index baa43177e3001..0000000000000 --- a/www/packages/docs-ui/src/components/Sidebar/Back/index.tsx +++ /dev/null @@ -1,26 +0,0 @@ -"use client" - -import React from "react" -import { useSidebar } from "../../../providers" -import clsx from "clsx" -import { ArrowUturnLeft } from "@medusajs/icons" - -export const SidebarBack = () => { - const { goBack } = useSidebar() - - return ( -
- - Back -
- ) -} diff --git a/www/packages/docs-ui/src/components/Sidebar/Title/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Title/index.tsx index dbcafdb740eb6..e2da2070176c1 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Title/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Title/index.tsx @@ -2,6 +2,7 @@ import React from "react" import Link from "next/link" import clsx from "clsx" import { SidebarItemType } from "types" +import { ArrowUturnLeft } from "@medusajs/icons" type SidebarTitleProps = { item: SidebarItemType @@ -11,17 +12,17 @@ export const SidebarTitle = ({ item }: SidebarTitleProps) => { return ( + {item.childSidebarTitle || item.title} - {item.additionalElms} ) } diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx new file mode 100644 index 0000000000000..0ff1bc76234e7 --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx @@ -0,0 +1,16 @@ +"use client" + +import clsx from "clsx" +import React from "react" + +export const SidebarTopSeparator = () => { + return ( + + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx new file mode 100644 index 0000000000000..5925e2cec7d77 --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx @@ -0,0 +1,26 @@ +"use client" + +import React from "react" +import { SidebarTitle } from "../Title" +import { SidebarItemType } from "types" +import { SidebarTopSeparator } from "./Separator" + +export type SidebarTopProps = { + banner?: React.ReactNode + parentItem?: SidebarItemType +} + +export const SidebarTop = ({ banner, parentItem }: SidebarTopProps) => { + return ( +
+ {banner &&
{banner}
} + {parentItem && ( + <> + + + + )} + +
+ ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/index.tsx b/www/packages/docs-ui/src/components/Sidebar/index.tsx index 389ee9db12485..ab1bede7b0452 100644 --- a/www/packages/docs-ui/src/components/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/index.tsx @@ -1,24 +1,23 @@ "use client" -import React, { useMemo, useRef } from "react" +import React, { useMemo } from "react" import { useSidebar } from "@/providers" import clsx from "clsx" import { Loading } from "@/components" import { SidebarItem } from "./Item" -import { SidebarTitle } from "./Title" -import { SidebarBack } from "./Back" import { CSSTransition, SwitchTransition } from "react-transition-group" +import { SidebarTop, SidebarTopProps } from "./Top" export type SidebarProps = { className?: string expandItems?: boolean - banner?: React.ReactNode + sidebarTopProps?: Omit } export const Sidebar = ({ className = "", expandItems = false, - banner, + sidebarTopProps, }: SidebarProps) => { const { items, @@ -42,11 +41,11 @@ export const Sidebar = ({ return ( ) } diff --git a/www/packages/docs-ui/src/layouts/root.tsx b/www/packages/docs-ui/src/layouts/root.tsx index a2ba565f77a4f..67cff43b30e2a 100644 --- a/www/packages/docs-ui/src/layouts/root.tsx +++ b/www/packages/docs-ui/src/layouts/root.tsx @@ -5,7 +5,7 @@ import { Sidebar, SidebarProps } from "@/components" export type RootLayoutProps = { children: React.ReactNode ProvidersComponent: React.FC<{ children: React.ReactNode }> - NavbarComponent: React.FC + NavbarComponent?: React.FC sidebarProps?: SidebarProps htmlClassName?: string bodyClassName?: string @@ -27,22 +27,30 @@ export const RootLayout = ({ - + {NavbarComponent && } +
-
- - {children} -
+ {children}
diff --git a/www/packages/docs-ui/src/layouts/tight.tsx b/www/packages/docs-ui/src/layouts/tight.tsx index 166a643d482c1..db1ae08d0a830 100644 --- a/www/packages/docs-ui/src/layouts/tight.tsx +++ b/www/packages/docs-ui/src/layouts/tight.tsx @@ -9,24 +9,17 @@ export const TightLayout = ({ ...props }: RootLayoutProps) => { return ( - +
-
- {children} - {showPagination && } -
+ {children} + {showPagination && }
) diff --git a/www/packages/tailwind/base.tailwind.config.js b/www/packages/tailwind/base.tailwind.config.js index de32c117ec08b..018daab1bcefa 100644 --- a/www/packages/tailwind/base.tailwind.config.js +++ b/www/packages/tailwind/base.tailwind.config.js @@ -271,31 +271,62 @@ module.exports = { "subtle-code-fade-right-to-left-dark": `linear-gradient(90deg, #30303380, #303033)`, }, screens: { - xs: "576px", - lg: "1025px", - xl: "1419px", - xxl: "1440px", + xs: "568px", + sm: "640px", + md: "768px", + lg: "1024px", + xl: "1280px", + xxl: "1536px", + xxxl: "3840px", }, transitionTimingFunction: { ease: "ease", }, + // TODO maybe remove? width: { - sidebar: "321px", + sidebar: "197px", "sidebar-hidden": "0px", - "main-content": "1140px", + "main-content": "1239px", "main-content-hidden-sidebar": "1440px", - "ref-sidebar": "280px", - "ref-main": "calc(100% - 280px)", + "ref-sidebar": "197px", + "ref-main": "calc(100% - 197px)", + // TODO check if it should be changed "ref-content": "calc(100% - 484px)", }, height: { + // TODO remove if no longer needed navbar: "57px", }, maxWidth: { - "main-content": "1140px", - "main-content-hidden-sidebar": "1440px", - xl: "1419px", - xxl: "1440px", + // sidebar + "sidebar-xs": "276px", + "sidebar-sm": "276px", + "sidebar-md": "276px", + "sidebar-lg": "197px", + "sidebar-xl": "197px", + "sidebar-xxl": "197px", + "sidebar-xxxl": "197px", + // main content + "main-content-xs": "100%", + "main-content-sm": "100%", + "main-content-md": "100%", + "main-content-lg": "751px", + "main-content-xl": "1007px", + "main-content-xxl": "1263px", + "main-content-xxxl": "3567px", + // inner content + "inner-content-xs": "272px", + "inner-content-sm": "592px", + "inner-content-md": "640px", + "inner-content-lg": "640px", + "inner-content-xl": "640px", + "inner-content-xxl": "640px", + "inner-content-xxxl": "640px", + // TODO maybe remove + // "main-content": "1239px", + // "main-content-hidden-sidebar": "1440px", + // xl: "1419px", + // xxl: "1440px", }, minWidth: { xl: "1419px", From 0d1f86d3236a2b7f89bbd62295f8677a9e06c534 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 31 Jul 2024 17:52:48 +0300 Subject: [PATCH 02/38] redesign the sidebar + nav drawer --- www/apps/book/providers/sidebar.tsx | 15 ++ .../src/components/BorderedIcon/index.tsx | 53 +++-- .../src/components/HelpButton/index.tsx | 32 +-- .../Icons/NavigationDropdown/Admin/index.tsx | 33 +++ .../Icons/NavigationDropdown/Doc/index.tsx | 37 ++++ .../NavigationDropdown/Resources/index.tsx | 37 ++++ .../Icons/NavigationDropdown/Store/index.tsx | 37 ++++ .../Icons/NavigationDropdown/Ui/index.tsx | 37 ++++ .../components/Icons/SidebarLeft/index.tsx | 42 ++++ .../docs-ui/src/components/Kbd/index.tsx | 8 +- .../src/components/MobileNavigation/index.tsx | 31 +++ .../Navbar/SearchModalOpener/index.tsx | 5 +- .../components/Search/ModalOpener/index.tsx | 49 ++--- .../Sidebar/Top/MobileClose/index.tsx | 21 ++ .../Top/NavigationDropdown/Icon/index.tsx | 13 ++ .../NavigationDropdown/Menu/Item/index.tsx | 46 +++++ .../Top/NavigationDropdown/Menu/index.tsx | 30 +++ .../Top/NavigationDropdown/Selected/index.tsx | 36 ++++ .../Sidebar/Top/NavigationDropdown/index.tsx | 48 +++++ .../Sidebar/Top/Separator/index.tsx | 14 +- .../src/components/Sidebar/Top/index.tsx | 37 ++-- .../docs-ui/src/components/Sidebar/index.tsx | 192 +++++++++++------- www/packages/docs-ui/src/constants.tsx | 96 ++++++++- www/packages/docs-ui/src/hooks/index.ts | 1 + .../src/hooks/use-click-outside/index.tsx | 37 ++++ www/packages/docs-ui/src/layouts/root.tsx | 7 +- .../docs-ui/src/providers/Mobile/index.tsx | 4 +- .../docs-ui/src/providers/Sidebar/index.tsx | 5 + .../docs-ui/src/utils/get-navbar-items.ts | 29 ++- www/packages/tailwind/base.tailwind.config.js | 14 +- www/packages/types/package.json | 3 + www/packages/types/src/index.ts | 1 + www/packages/types/src/navigation-dropdown.ts | 16 ++ www/yarn.lock | 10 + 34 files changed, 876 insertions(+), 200 deletions(-) create mode 100644 www/packages/docs-ui/src/components/Icons/NavigationDropdown/Admin/index.tsx create mode 100644 www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx create mode 100644 www/packages/docs-ui/src/components/Icons/NavigationDropdown/Resources/index.tsx create mode 100644 www/packages/docs-ui/src/components/Icons/NavigationDropdown/Store/index.tsx create mode 100644 www/packages/docs-ui/src/components/Icons/NavigationDropdown/Ui/index.tsx create mode 100644 www/packages/docs-ui/src/components/Icons/SidebarLeft/index.tsx create mode 100644 www/packages/docs-ui/src/components/MobileNavigation/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/MobileClose/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Icon/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/Item/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Selected/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/index.tsx create mode 100644 www/packages/docs-ui/src/hooks/use-click-outside/index.tsx create mode 100644 www/packages/types/src/navigation-dropdown.ts diff --git a/www/apps/book/providers/sidebar.tsx b/www/apps/book/providers/sidebar.tsx index 5c8ce3c9273fa..08cbb57ac772b 100644 --- a/www/apps/book/providers/sidebar.tsx +++ b/www/apps/book/providers/sidebar.tsx @@ -1,9 +1,13 @@ "use client" + import { + getNavDropdownItems, SidebarProvider as UiSidebarProvider, useScrollController, } from "docs-ui" import { config } from "@/config" +import { useMemo } from "react" +import { basePathUrl } from "../utils/base-path-url" type SidebarProviderProps = { children?: React.ReactNode @@ -12,6 +16,16 @@ type SidebarProviderProps = { const SidebarProvider = ({ children }: SidebarProviderProps) => { const { scrollableElement } = useScrollController() + const navigationDropdownItems = useMemo( + () => + getNavDropdownItems({ + basePath: config.baseUrl, + activePath: basePathUrl(), + version: "v2", + }), + [] + ) + return ( { staticSidebarItems={true} disableActiveTransition={true} noTitleStyling={true} + navigationDropdownItems={navigationDropdownItems} > {children} diff --git a/www/packages/docs-ui/src/components/BorderedIcon/index.tsx b/www/packages/docs-ui/src/components/BorderedIcon/index.tsx index ffd66a620f43e..00f7726cca182 100644 --- a/www/packages/docs-ui/src/components/BorderedIcon/index.tsx +++ b/www/packages/docs-ui/src/components/BorderedIcon/index.tsx @@ -1,5 +1,4 @@ import React from "react" -import { Bordered } from "@/components/Bordered" import clsx from "clsx" import { IconProps } from "@medusajs/icons/dist/types" @@ -15,37 +14,35 @@ export type BorderedIconProps = { export const BorderedIcon = ({ icon = "", IconComponent = null, - wrapperClassName, iconWrapperClassName, iconClassName, iconColorClassName = "", }: BorderedIconProps) => { return ( - - - {!IconComponent && ( - - )} - {IconComponent && ( - - )} - - + + {!IconComponent && ( + + )} + {IconComponent && ( + + )} + ) } diff --git a/www/packages/docs-ui/src/components/HelpButton/index.tsx b/www/packages/docs-ui/src/components/HelpButton/index.tsx index f75ac2385b297..a2216e657093b 100644 --- a/www/packages/docs-ui/src/components/HelpButton/index.tsx +++ b/www/packages/docs-ui/src/components/HelpButton/index.tsx @@ -1,39 +1,23 @@ "use client" -import React, { useCallback, useEffect, useRef, useState } from "react" +import React, { useEffect, useRef, useState } from "react" import { Button } from "@/components" import clsx from "clsx" import { CSSTransition } from "react-transition-group" import { HelpButtonActions } from "./Actions" -import { useIsBrowser } from "../.." +import { useClickOutside } from "../.." export const HelpButton = () => { const [showText, setShowText] = useState(false) const [showHelp, setShowHelp] = useState(false) const ref = useRef(null) - const isBrowser = useIsBrowser() - - const onClickOutside = useCallback( - (e: MouseEvent) => { - if (!ref.current?.contains(e.target as Node)) { - setShowHelp(false) - setShowText(false) - } + useClickOutside({ + elmRef: ref, + onClickOutside: () => { + setShowHelp(false) + setShowText(false) }, - [ref.current] - ) - - useEffect(() => { - if (!isBrowser) { - return - } - - window.document.addEventListener("click", onClickOutside) - - return () => { - window.document.removeEventListener("click", onClickOutside) - } - }, [isBrowser]) + }) useEffect(() => { if (showHelp) { diff --git a/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Admin/index.tsx b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Admin/index.tsx new file mode 100644 index 0000000000000..d424affdc12cf --- /dev/null +++ b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Admin/index.tsx @@ -0,0 +1,33 @@ +import { IconProps } from "@medusajs/icons/dist/types" +import React from "react" + +export const NavigationDropdownAdminIcon = (props: IconProps) => { + return ( + + + + + + + + + + + + ) +} diff --git a/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx new file mode 100644 index 0000000000000..0752bfd74d221 --- /dev/null +++ b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx @@ -0,0 +1,37 @@ +import { IconProps } from "@medusajs/icons/dist/types" +import React from "react" + +export const NavigationDropdownDocIcon = (props: IconProps) => { + return ( + + + + + + + + + + + + + ) +} diff --git a/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Resources/index.tsx b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Resources/index.tsx new file mode 100644 index 0000000000000..17ac93945794d --- /dev/null +++ b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Resources/index.tsx @@ -0,0 +1,37 @@ +import { IconProps } from "@medusajs/icons/dist/types" +import React from "react" + +export const NavigationDropdownResourcesIcon = (props: IconProps) => { + return ( + + + + + + + + + + + + + ) +} diff --git a/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Store/index.tsx b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Store/index.tsx new file mode 100644 index 0000000000000..7527cb9693a2f --- /dev/null +++ b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Store/index.tsx @@ -0,0 +1,37 @@ +import { IconProps } from "@medusajs/icons/dist/types" +import React from "react" + +export const NavigationDropdownStoreIcon = (props: IconProps) => { + return ( + + + + + + + + + + + + + ) +} diff --git a/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Ui/index.tsx b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Ui/index.tsx new file mode 100644 index 0000000000000..b19e199f4baa2 --- /dev/null +++ b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Ui/index.tsx @@ -0,0 +1,37 @@ +import { IconProps } from "@medusajs/icons/dist/types" +import React from "react" + +export const NavigationDropdownUiIcon = (props: IconProps) => { + return ( + + + + + + + + + + + + + ) +} diff --git a/www/packages/docs-ui/src/components/Icons/SidebarLeft/index.tsx b/www/packages/docs-ui/src/components/Icons/SidebarLeft/index.tsx new file mode 100644 index 0000000000000..963b08a601dbe --- /dev/null +++ b/www/packages/docs-ui/src/components/Icons/SidebarLeft/index.tsx @@ -0,0 +1,42 @@ +import { IconProps } from "@medusajs/icons/dist/types" +import React from "react" + +export const SidebarLeftIcon = (props: IconProps) => { + return ( + + + + + + + + + + + + ) +} diff --git a/www/packages/docs-ui/src/components/Kbd/index.tsx b/www/packages/docs-ui/src/components/Kbd/index.tsx index 414d9b0c75740..5d4e2a5fb08ce 100644 --- a/www/packages/docs-ui/src/components/Kbd/index.tsx +++ b/www/packages/docs-ui/src/components/Kbd/index.tsx @@ -7,11 +7,11 @@ export const Kbd = ({ children, className, ...props }: KbdProps) => { return ( { + const { setMobileSidebarOpen } = useSidebar() + + return ( +
+ + + +
+ ) +} diff --git a/www/packages/docs-ui/src/components/Navbar/SearchModalOpener/index.tsx b/www/packages/docs-ui/src/components/Navbar/SearchModalOpener/index.tsx index 5700b9ce3f711..dc9d3bbaada6b 100644 --- a/www/packages/docs-ui/src/components/Navbar/SearchModalOpener/index.tsx +++ b/www/packages/docs-ui/src/components/Navbar/SearchModalOpener/index.tsx @@ -2,7 +2,6 @@ import React from "react" import { SearchModalOpener } from "@/components" -import { useMobile } from "@/providers" export type NavbarSearchModalOpenerProps = { isLoading?: boolean @@ -11,7 +10,5 @@ export type NavbarSearchModalOpenerProps = { export const NavbarSearchModalOpener = ({ isLoading, }: NavbarSearchModalOpenerProps) => { - const { isMobile } = useMobile() - - return + return } diff --git a/www/packages/docs-ui/src/components/Search/ModalOpener/index.tsx b/www/packages/docs-ui/src/components/Search/ModalOpener/index.tsx index 3519dbdfa0337..372d32edc0cfe 100644 --- a/www/packages/docs-ui/src/components/Search/ModalOpener/index.tsx +++ b/www/packages/docs-ui/src/components/Search/ModalOpener/index.tsx @@ -2,20 +2,21 @@ import React, { MouseEvent, useMemo } from "react" import clsx from "clsx" -import { useSearch } from "@/providers" -import { Button, InputText, Kbd } from "@/components" +import { useMobile, useSearch } from "@/providers" +import { Button, Kbd } from "@/components" import { MagnifyingGlass } from "@medusajs/icons" import { useKeyboardShortcut } from "@/hooks" export type SearchModalOpenerProps = { isLoading?: boolean - isMobile?: boolean + className?: string } export const SearchModalOpener = ({ isLoading = false, - isMobile = false, + className, }: SearchModalOpenerProps) => { + const { isMobile } = useMobile() const { setIsOpen } = useSearch() const isApple = useMemo(() => { return typeof navigator !== "undefined" @@ -48,42 +49,22 @@ export const SearchModalOpener = ({ <> {isMobile && ( )} {!isMobile && (
- - e.target.blur()} - tabIndex={-1} - addGroupStyling={true} - /> - - {isApple ? "⌘" : "Ctrl"} - K - + + Ask or search... + {isApple ? "⌘" : "Ctrl"}K
)} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/MobileClose/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/MobileClose/index.tsx new file mode 100644 index 0000000000000..b12a8d4ffd1bf --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/MobileClose/index.tsx @@ -0,0 +1,21 @@ +"use client" + +import React from "react" +import { Button, useSidebar } from "../../../.." +import { XMarkMini } from "@medusajs/icons" + +export const SidebarTopMobileClose = () => { + const { setMobileSidebarOpen } = useSidebar() + + return ( +
+ +
+ ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Icon/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Icon/index.tsx new file mode 100644 index 0000000000000..e0677462f3412 --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Icon/index.tsx @@ -0,0 +1,13 @@ +import React from "react" +import { BorderedIcon } from "@/components" +import { IconProps } from "@medusajs/icons/dist/types" + +export type SidebarTopNavigationDropdownIconProps = { + icon: React.FC +} + +export const SidebarTopNavigationDropdownIcon = ({ + icon, +}: SidebarTopNavigationDropdownIconProps) => { + return +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/Item/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/Item/index.tsx new file mode 100644 index 0000000000000..cf6555e0949bb --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/Item/index.tsx @@ -0,0 +1,46 @@ +"use client" + +import React from "react" +import { NavigationDropdownItem } from "types" +import { SidebarTopSeparator } from "../../../Separator" +import Link from "next/link" +import clsx from "clsx" +import { EllipseMiniSolid } from "@medusajs/icons" +import { SidebarTopNavigationDropdownIcon } from "../../Icon" + +export type SidebarTopNavigationDropdownMenuItemProps = { + item: NavigationDropdownItem +} + +export const SidebarTopNavigationDropdownMenuItem = ({ + item, +}: SidebarTopNavigationDropdownMenuItemProps) => { + switch (item.type) { + case "divider": + return + case "link": + return ( + +
  • + + + + + {item.title} +
  • + + ) + } +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/index.tsx new file mode 100644 index 0000000000000..9a5a3d3292b92 --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Menu/index.tsx @@ -0,0 +1,30 @@ +"use client" + +import clsx from "clsx" +import React from "react" +import { NavigationDropdownItem } from "types" +import { SidebarTopNavigationDropdownMenuItem } from "./Item" + +export type SidebarTopNavigationDropdownMenuProps = { + items: NavigationDropdownItem[] + open: boolean +} + +export const SidebarTopNavigationDropdownMenu = ({ + items, + open, +}: SidebarTopNavigationDropdownMenuProps) => { + return ( +
      + {items.map((item, index) => ( + + ))} +
    + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Selected/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Selected/index.tsx new file mode 100644 index 0000000000000..e73eb3a0fc2e9 --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/Selected/index.tsx @@ -0,0 +1,36 @@ +"use client" + +import React from "react" +import { NavigationDropdownItem } from "types" +import { TrianglesMini } from "@medusajs/icons" +import clsx from "clsx" +import { SidebarTopNavigationDropdownIcon } from "../Icon" + +export type SidebarTopNavigationDropdownSelectedProps = { + item: NavigationDropdownItem + onClick: () => void +} + +export const SidebarTopNavigationDropdownSelected = ({ + item, + onClick, +}: SidebarTopNavigationDropdownSelectedProps) => { + if (item.type === "divider") { + return <> + } + + return ( +
    + + {item.title} + +
    + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/index.tsx new file mode 100644 index 0000000000000..c610c7836be63 --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Top/NavigationDropdown/index.tsx @@ -0,0 +1,48 @@ +"use client" + +import clsx from "clsx" +import React, { useMemo, useRef, useState } from "react" +import { SidebarTopNavigationDropdownSelected } from "./Selected" +import { SidebarTopNavigationDropdownMenu } from "./Menu" +import { useClickOutside, useSidebar } from "../../../.." + +export const SidebarTopNavigationDropdown = () => { + const { navigationDropdownItems: items } = useSidebar() + const navigationRef = useRef(null) + const [menuOpen, setMenuOpen] = useState(false) + useClickOutside({ + elmRef: navigationRef, + onClickOutside: () => { + setMenuOpen(false) + }, + }) + + const selectedItem = useMemo(() => { + const activeItem = items.find( + (item) => item.type === "link" && item.isActive + ) + + if (!activeItem) { + return items.length ? items[0] : undefined + } + + return activeItem + }, [items]) + return ( +
    + {selectedItem && ( + setMenuOpen((prev) => !prev)} + /> + )} + +
    + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx index 0ff1bc76234e7..5cc2ba37bfb38 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx @@ -3,13 +3,21 @@ import clsx from "clsx" import React from "react" -export const SidebarTopSeparator = () => { +export type SidebarTopSeparatorProps = { + className?: string +} + +export const SidebarTopSeparator = ({ + className, +}: SidebarTopSeparatorProps) => { return ( ) diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx index 5925e2cec7d77..adba69a691a02 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx @@ -4,23 +4,34 @@ import React from "react" import { SidebarTitle } from "../Title" import { SidebarItemType } from "types" import { SidebarTopSeparator } from "./Separator" +import { SidebarTopNavigationDropdown } from "./NavigationDropdown" +import { SearchModalOpener } from "../../.." +import { SidebarTopMobileClose } from "./MobileClose" export type SidebarTopProps = { banner?: React.ReactNode parentItem?: SidebarItemType } -export const SidebarTop = ({ banner, parentItem }: SidebarTopProps) => { - return ( -
    - {banner &&
    {banner}
    } - {parentItem && ( - <> +export const SidebarTop = React.forwardRef( + function SidebarTop({ banner, parentItem }, ref) { + return ( + <> + +
    + - - - )} - -
    - ) -} + + {/* {banner &&
    {banner}
    } */} + {parentItem && ( + <> + + + + )} + +
    + + ) + } +) diff --git a/www/packages/docs-ui/src/components/Sidebar/index.tsx b/www/packages/docs-ui/src/components/Sidebar/index.tsx index ab1bede7b0452..d360a25297758 100644 --- a/www/packages/docs-ui/src/components/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/index.tsx @@ -1,12 +1,14 @@ "use client" -import React, { useMemo } from "react" +import React, { useCallback, useMemo, useRef, useState } from "react" import { useSidebar } from "@/providers" import clsx from "clsx" import { 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 } from "../.." export type SidebarProps = { className?: string @@ -19,14 +21,25 @@ export const Sidebar = ({ expandItems = false, sidebarTopProps, }: SidebarProps) => { + const sidebarTopRef = useRef(null) + const [sidebarTopHeight, setSidebarHeight] = useState(0) const { items, currentItems, mobileSidebarOpen, + setMobileSidebarOpen, desktopSidebarOpen, staticSidebarItems, sidebarRef, } = useSidebar() + useClickOutside({ + elmRef: sidebarRef, + onClickOutside: () => { + if (mobileSidebarOpen) { + setMobileSidebarOpen(false) + } + }, + }) const sidebarItems = useMemo( () => currentItems || items, @@ -38,84 +51,111 @@ export const Sidebar = ({ [sidebarItems] ) + useResizeObserver(sidebarTopRef, () => { + setSidebarHeight(sidebarTopRef.current?.clientHeight || 0) + }) + return ( - + + + + + ) } diff --git a/www/packages/docs-ui/src/constants.tsx b/www/packages/docs-ui/src/constants.tsx index 30f6b025c3df1..c6a6f0a165980 100644 --- a/www/packages/docs-ui/src/constants.tsx +++ b/www/packages/docs-ui/src/constants.tsx @@ -1,12 +1,106 @@ import React from "react" import { Badge, NavbarItem, HelpButton } from "@/components" import { OptionType } from "@/hooks" -import { SidebarItemType } from "types" +import { NavigationDropdownItem, SidebarItemType } from "types" import { NotificationItemType } from "@/providers" +import { NavigationDropdownDocIcon } from "./components/Icons/NavigationDropdown/Doc" +import { NavigationDropdownStoreIcon } from "./components/Icons/NavigationDropdown/Store" +import { NavigationDropdownAdminIcon } from "./components/Icons/NavigationDropdown/Admin" +import { NavigationDropdownUiIcon } from "./components/Icons/NavigationDropdown/Ui" +import { NavigationDropdownResourcesIcon } from "./components/Icons/NavigationDropdown/Resources" export const GITHUB_ISSUES_PREFIX = `https://github.com/medusajs/medusa/issues/new?assignees=&labels=type%3A+docs&template=docs.yml` export const GITHUB_UI_ISSUES_PREFIX = `https://github.com/medusajs/ui/issues/new?labels=documentation` +export const navDropdownItemsV2: NavigationDropdownItem[] = [ + { + type: "link", + path: `/v2`, + icon: NavigationDropdownDocIcon, + title: "Documentation", + }, + { + type: "link", + path: `/v2/resources`, + // TODO use user guide icon + icon: NavigationDropdownResourcesIcon, + title: "Learning Resources", + }, + { + type: "link", + path: `/v2/api/store`, + icon: NavigationDropdownStoreIcon, + title: "Store API", + }, + { + type: "link", + path: `/v2/api/admin`, + icon: NavigationDropdownAdminIcon, + title: "Admin API", + }, + { + type: "link", + path: `/ui`, + icon: NavigationDropdownUiIcon, + title: "UI", + }, + { + type: "divider", + }, + { + type: "link", + path: `/`, + // TODO use docs icon + icon: NavigationDropdownDocIcon, + title: "Medusa v1", + }, +] + +export const navDropdownItemsV1: NavigationDropdownItem[] = [ + { + type: "link", + path: `/`, + icon: NavigationDropdownDocIcon, + title: "Documentation", + }, + { + type: "link", + path: `/user-guide`, + // TODO use user guide icon + icon: NavigationDropdownDocIcon, + title: "User Guide", + }, + { + type: "link", + path: `/api/store`, + icon: NavigationDropdownStoreIcon, + title: "Store API", + }, + { + type: "link", + path: `/api/admin`, + icon: NavigationDropdownAdminIcon, + title: "Admin API", + }, + { + type: "link", + path: `/ui`, + icon: NavigationDropdownUiIcon, + title: "UI", + }, + { + type: "divider", + }, + { + type: "link", + path: `/v2`, + // TODO use docs icon + icon: NavigationDropdownDocIcon, + title: "Medusa v2", + }, +] + +// TODO remove navbarItems in favor of navbar dropdown items export const navbarItemsV1: NavbarItem[] = [ { type: "link", diff --git a/www/packages/docs-ui/src/hooks/index.ts b/www/packages/docs-ui/src/hooks/index.ts index e9850717ba750..93c5d0e9df41e 100644 --- a/www/packages/docs-ui/src/hooks/index.ts +++ b/www/packages/docs-ui/src/hooks/index.ts @@ -1,3 +1,4 @@ +export * from "./use-click-outside" export * from "./use-collapsible" export * from "./use-collapsible-code-lines" export * from "./use-copy" diff --git a/www/packages/docs-ui/src/hooks/use-click-outside/index.tsx b/www/packages/docs-ui/src/hooks/use-click-outside/index.tsx new file mode 100644 index 0000000000000..821c80b871a30 --- /dev/null +++ b/www/packages/docs-ui/src/hooks/use-click-outside/index.tsx @@ -0,0 +1,37 @@ +"use client" + +import React, { useCallback, useEffect } from "react" +import { useIsBrowser } from "../.." + +export type UseClickOutsideProps = { + elmRef: React.RefObject + onClickOutside: (e: MouseEvent) => void +} + +export const useClickOutside = ({ + elmRef, + onClickOutside, +}: UseClickOutsideProps) => { + const isBrowser = useIsBrowser() + + const checkClickOutside = useCallback( + (e: MouseEvent) => { + if (!elmRef.current?.contains(e.target as Node)) { + onClickOutside(e) + } + }, + [elmRef.current, onClickOutside] + ) + + useEffect(() => { + if (!isBrowser) { + return + } + + window.document.addEventListener("click", checkClickOutside) + + return () => { + window.document.removeEventListener("click", checkClickOutside) + } + }, [isBrowser, checkClickOutside]) +} diff --git a/www/packages/docs-ui/src/layouts/root.tsx b/www/packages/docs-ui/src/layouts/root.tsx index 67cff43b30e2a..1012b7515812d 100644 --- a/www/packages/docs-ui/src/layouts/root.tsx +++ b/www/packages/docs-ui/src/layouts/root.tsx @@ -1,10 +1,12 @@ import React from "react" import clsx from "clsx" import { Sidebar, SidebarProps } from "@/components" +import { MobileNavigation } from "../components/MobileNavigation" export type RootLayoutProps = { children: React.ReactNode ProvidersComponent: React.FC<{ children: React.ReactNode }> + // todo remove NavbarComponent?: React.FC sidebarProps?: SidebarProps htmlClassName?: string @@ -15,7 +17,6 @@ export type RootLayoutProps = { export const RootLayout = ({ ProvidersComponent, - NavbarComponent, children, sidebarProps, htmlClassName, @@ -30,12 +31,12 @@ export const RootLayout = ({ "bg-medusa-bg-subtle font-base text-medium w-full", "text-medusa-fg-subtle", "h-screen overflow-hidden", - "grid grid-cols-1 lg:mx-auto lg:grid-cols-[197px_1fr]", + "grid grid-cols-1 lg:mx-auto lg:grid-cols-[221px_1fr]", bodyClassName )} > - {NavbarComponent && } +
    { const [isMobile, setIsMobile] = useState(false) const handleResize = useCallback(() => { - if (window.innerWidth < 1025 && !isMobile) { + if (window.innerWidth < 1024 && !isMobile) { setIsMobile(true) - } else if (window.innerWidth >= 1025 && isMobile) { + } else if (window.innerWidth >= 1024 && isMobile) { setIsMobile(false) } }, [isMobile]) diff --git a/www/packages/docs-ui/src/providers/Sidebar/index.tsx b/www/packages/docs-ui/src/providers/Sidebar/index.tsx index 6253e6169ea8b..f425e3bc1aab8 100644 --- a/www/packages/docs-ui/src/providers/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/providers/Sidebar/index.tsx @@ -14,6 +14,7 @@ import { usePathname, useRouter } from "next/navigation" import { getScrolledTop } from "@/utils" import { useIsBrowser } from "@/hooks" import { + NavigationDropdownItem, SidebarItemSections, SidebarItemType, SidebarSectionItemsType, @@ -61,6 +62,7 @@ export type SidebarContextType = { shouldHandleHashChange: boolean sidebarRef: React.RefObject goBack: () => void + navigationDropdownItems: NavigationDropdownItem[] } & SidebarStyleOptions export const SidebarContext = createContext(null) @@ -173,6 +175,7 @@ export type SidebarProviderProps = { shouldHandlePathChange?: boolean scrollableElement?: Element | Window staticSidebarItems?: boolean + navigationDropdownItems: NavigationDropdownItem[] } & SidebarStyleOptions export const SidebarProvider = ({ @@ -186,6 +189,7 @@ export const SidebarProvider = ({ staticSidebarItems = false, disableActiveTransition = false, noTitleStyling = false, + navigationDropdownItems, }: SidebarProviderProps) => { const [items, dispatch] = useReducer(reducer, { top: initialItems?.top || [], @@ -435,6 +439,7 @@ export const SidebarProvider = ({ shouldHandleHashChange, sidebarRef, goBack, + navigationDropdownItems, }} > {children} diff --git a/www/packages/docs-ui/src/utils/get-navbar-items.ts b/www/packages/docs-ui/src/utils/get-navbar-items.ts index 670e572c272d7..05c42a6a18b57 100644 --- a/www/packages/docs-ui/src/utils/get-navbar-items.ts +++ b/www/packages/docs-ui/src/utils/get-navbar-items.ts @@ -1,4 +1,11 @@ -import { NavbarItem, navbarItemsV1, navbarItemsV2 } from ".." +import { NavigationDropdownItem } from "types" +import { + NavbarItem, + navbarItemsV1, + navbarItemsV2, + navDropdownItemsV1, + navDropdownItemsV2, +} from ".." type Options = { basePath: string @@ -6,6 +13,7 @@ type Options = { version?: "v1" | "v2" } +// TODO remove if not used anymore export function getNavbarItems({ basePath, activePath, @@ -27,3 +35,22 @@ export function getNavbarItems({ } }) } + +export function getNavDropdownItems({ + basePath, + activePath, + version = "v1", +}: Options): NavigationDropdownItem[] { + const items = version === "v2" ? navDropdownItemsV2 : navDropdownItemsV1 + return items.map((item) => { + if (item.type === "divider") { + return item + } + + return { + ...item, + isActive: activePath === item.path, + href: `${basePath}${item.path}`, + } + }) +} diff --git a/www/packages/tailwind/base.tailwind.config.js b/www/packages/tailwind/base.tailwind.config.js index 018daab1bcefa..5988c162091e6 100644 --- a/www/packages/tailwind/base.tailwind.config.js +++ b/www/packages/tailwind/base.tailwind.config.js @@ -299,13 +299,13 @@ module.exports = { }, maxWidth: { // sidebar - "sidebar-xs": "276px", - "sidebar-sm": "276px", - "sidebar-md": "276px", - "sidebar-lg": "197px", - "sidebar-xl": "197px", - "sidebar-xxl": "197px", - "sidebar-xxxl": "197px", + "sidebar-xs": "300px", + "sidebar-sm": "300px", + "sidebar-md": "300px", + "sidebar-lg": "221px", + "sidebar-xl": "221px", + "sidebar-xxl": "221px", + "sidebar-xxxl": "221px", // main content "main-content-xs": "100%", "main-content-sm": "100%", diff --git a/www/packages/types/package.json b/www/packages/types/package.json index ee93f6bfa56bd..3f2309216703f 100644 --- a/www/packages/types/package.json +++ b/www/packages/types/package.json @@ -39,5 +39,8 @@ }, "engines": { "node": ">=18.17.0" + }, + "dependencies": { + "@medusajs/icons": "^1.2.2" } } diff --git a/www/packages/types/src/index.ts b/www/packages/types/src/index.ts index 8abc96e9631ef..070a19d2b8f4c 100644 --- a/www/packages/types/src/index.ts +++ b/www/packages/types/src/index.ts @@ -1,4 +1,5 @@ export * from "./api-testing.js" export * from "./config.js" export * from "./general.js" +export * from "./navigation-dropdown.js" export * from "./sidebar.js" diff --git a/www/packages/types/src/navigation-dropdown.ts b/www/packages/types/src/navigation-dropdown.ts new file mode 100644 index 0000000000000..c7f1a8044e0a0 --- /dev/null +++ b/www/packages/types/src/navigation-dropdown.ts @@ -0,0 +1,16 @@ +import { IconProps } from "@medusajs/icons/dist/types.js" + +export type NavigationDropdownItemLink = { + path: string + isActive?: boolean + title: string + icon: React.FC +} + +export type NavigationDropdownItem = + | ({ + type: "link" + } & NavigationDropdownItemLink) + | { + type: "divider" + } diff --git a/www/yarn.lock b/www/yarn.lock index 96e179621c393..d7ffab6371114 100644 --- a/www/yarn.lock +++ b/www/yarn.lock @@ -1302,6 +1302,15 @@ __metadata: languageName: node linkType: hard +"@medusajs/icons@npm:^1.2.2": + version: 1.2.2 + resolution: "@medusajs/icons@npm:1.2.2" + peerDependencies: + react: ^16.x || ^17.x || ^18.x + checksum: 610117b959ddbd68f927caa12e70fb5fc849e8c68a25ca38f4d137aca1363f36552455aa83669847bd42753cccf36ad57b82f9bd5be7794e5b23af1046f78967 + languageName: node + linkType: hard + "@medusajs/ui-preset@npm:^1.1.2": version: 1.1.2 resolution: "@medusajs/ui-preset@npm:1.1.2" @@ -14662,6 +14671,7 @@ turbo@latest: version: 0.0.0-use.local resolution: "types@workspace:packages/types" dependencies: + "@medusajs/icons": ^1.2.2 "@types/node": ^20.11.20 eslint-config-docs: "*" rimraf: ^5.0.5 From 5363f262be9ac8df598751628d1a749e127fa222 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Wed, 31 Jul 2024 19:04:55 +0300 Subject: [PATCH 03/38] changes to sidebar items --- www/apps/book/config/sidebar.tsx | 3 +- www/apps/book/sidebar.mjs | 2 +- www/apps/book/utils/number-sidebar-items.mjs | 5 +- .../src/components/Breadcrumbs/index.tsx | 7 +- .../src/components/ChildDocs/index.tsx | 39 +++-- .../src/components/Sidebar/Item/index.tsx | 13 +- .../src/components/Sidebar/Title/index.tsx | 18 ++- .../src/components/Sidebar/Top/index.tsx | 4 +- .../docs-ui/src/components/Sidebar/index.tsx | 25 +-- www/packages/docs-ui/src/constants.tsx | 18 ++- .../src/providers/Pagination/index.tsx | 37 +++-- .../docs-ui/src/providers/Sidebar/index.tsx | 147 ++++++++---------- .../src/providers/SiteConifg/index.tsx | 3 +- .../src/utils/get-mobile-sidebar-items.ts | 8 +- www/packages/types/src/config.ts | 4 +- www/packages/types/src/sidebar.ts | 38 +++-- 16 files changed, 188 insertions(+), 183 deletions(-) diff --git a/www/apps/book/config/sidebar.tsx b/www/apps/book/config/sidebar.tsx index 836a964ea5c80..21ddf66ee2d60 100644 --- a/www/apps/book/config/sidebar.tsx +++ b/www/apps/book/config/sidebar.tsx @@ -19,8 +19,7 @@ const normalizeSidebarItems = (items: SidebarItemType[]) => export const sidebarConfig = (baseUrl: string): SidebarConfig => { return { - top: normalizeSidebarItems(sidebar), - bottom: [], + default: normalizeSidebarItems(sidebar), mobile: getMobileSidebarItems({ baseUrl, version: "v2", diff --git a/www/apps/book/sidebar.mjs b/www/apps/book/sidebar.mjs index 3228846971a5a..9338cad3a1450 100644 --- a/www/apps/book/sidebar.mjs +++ b/www/apps/book/sidebar.mjs @@ -1,7 +1,7 @@ import numberSidebarItems from "./utils/number-sidebar-items.mjs" import { sidebarAttachHrefCommonOptions } from "./utils/sidebar-attach-common-options.mjs" -/** @type {import('@/types').SidebarItemType[]} */ +/** @type {import('@/types').SidebarItem[]} */ export const sidebar = sidebarAttachHrefCommonOptions( numberSidebarItems([ { diff --git a/www/apps/book/utils/number-sidebar-items.mjs b/www/apps/book/utils/number-sidebar-items.mjs index c1a2fcf9027c3..26881f0d1bc90 100644 --- a/www/apps/book/utils/number-sidebar-items.mjs +++ b/www/apps/book/utils/number-sidebar-items.mjs @@ -1,10 +1,11 @@ /** * - * @param {import("@/types").SidebarItemType[]} sidebarItems - The items to add numbers to their titles + * @param {import("@/types").SidebarItem[]} sidebarItems - The items to add numbers to their titles * @param {number[]} numbering - The current numbering level - * @returns {import("@/types").SidebarItemType[]} The modified sidebar items + * @returns {import("@/types").SidebarItem[]} The modified sidebar items */ export default function numberSidebarItems(sidebarItems, numbering = [1]) { + // TODO generate chapter titles if (!numbering.length) { numbering.push(1) } diff --git a/www/packages/docs-ui/src/components/Breadcrumbs/index.tsx b/www/packages/docs-ui/src/components/Breadcrumbs/index.tsx index fd6bd17d74f2f..83ad81a08f660 100644 --- a/www/packages/docs-ui/src/components/Breadcrumbs/index.tsx +++ b/www/packages/docs-ui/src/components/Breadcrumbs/index.tsx @@ -17,8 +17,13 @@ export const Breadcrumbs = () => { tempBreadcrumbItems = getBreadcrumbsOfItem(item.previousSidebar) } + const parentPath = + item.parentItem?.type === "link" ? item.parentItem.path : undefined + const firstItemPath = + item.default[0].type === "link" ? item.default[0].path : undefined + tempBreadcrumbItems.set( - item.parentItem?.path || item.top[0].path || "/", + parentPath || firstItemPath || "/", item.parentItem?.childSidebarTitle || item.parentItem?.title || "" ) diff --git a/www/packages/docs-ui/src/components/ChildDocs/index.tsx b/www/packages/docs-ui/src/components/ChildDocs/index.tsx index e237852c486b6..5e3c70edfd039 100644 --- a/www/packages/docs-ui/src/components/ChildDocs/index.tsx +++ b/www/packages/docs-ui/src/components/ChildDocs/index.tsx @@ -2,7 +2,7 @@ import React, { useMemo } from "react" import { Card, CardList, MDXComponents, useSidebar } from "../.." -import { SidebarItemType } from "types" +import { SidebarItem } from "types" type ChildDocsProps = { onlyTopLevel?: boolean @@ -28,16 +28,16 @@ export const ChildDocs = ({ : "all" }, [showItems, hideItems]) - const filterCondition = (item: SidebarItemType): boolean => { + const filterCondition = (item: SidebarItem): boolean => { switch (filterType) { case "hide": return ( - (!item.path || !hideItems.includes(item.path)) && + (item.type !== "link" || !hideItems.includes(item.path)) && !hideItems.includes(item.title) ) case "show": return ( - (item.path !== undefined && showItems!.includes(item.path)) || + (item.type === "link" && showItems!.includes(item.path)) || showItems!.includes(item.title) ) case "all": @@ -45,7 +45,7 @@ export const ChildDocs = ({ } } - const filterItems = (items: SidebarItemType[]): SidebarItemType[] => { + const filterItems = (items: SidebarItem[]): SidebarItem[] => { return items .filter(filterCondition) .map((item) => Object.assign({}, item)) @@ -65,8 +65,7 @@ export const ChildDocs = ({ ? Object.assign({}, currentItems) : undefined : { - top: [...(getActiveItem()?.children || [])], - bottom: [], + default: [...(getActiveItem()?.children || [])], } if (filterType === "all" || !targetItems) { return targetItems @@ -74,24 +73,23 @@ export const ChildDocs = ({ return { ...targetItems, - top: filterItems(targetItems.top), - bottom: filterItems(targetItems.bottom), + default: filterItems(targetItems.default), } }, [currentItems, type, getActiveItem, filterItems]) - const getTopLevelElms = (items?: SidebarItemType[]) => ( + const getTopLevelElms = (items?: SidebarItem[]) => ( ({ title: childItem.title, - href: childItem.path, + href: childItem.type === "link" ? childItem.path : "", showLinkIcon: false, })) || [] } /> ) - const getAllLevelsElms = (items?: SidebarItemType[]) => + const getAllLevelsElms = (items?: SidebarItem[]) => items?.map((item, key) => { const HeadingComponent = item.children?.length ? MDXComponents["h2"] @@ -106,7 +104,7 @@ export const ChildDocs = ({ items={ item.children?.map((childItem) => ({ title: childItem.title, - href: childItem.path, + href: childItem.type === "link" ? childItem.path : "", showLinkIcon: false, })) || [] } @@ -114,20 +112,19 @@ export const ChildDocs = ({ )} {!HeadingComponent && ( - + )} ) }) - const getElms = (items?: SidebarItemType[]) => { + const getElms = (items?: SidebarItem[]) => { return onlyTopLevel ? getTopLevelElms(items) : getAllLevelsElms(items) } - return ( - <> - {getElms(filteredItems?.top)} - {getElms(filteredItems?.bottom)} - - ) + return <>{getElms(filteredItems?.default)} } diff --git a/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx index 2276d12ae3acc..faac0409e6209 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx @@ -8,7 +8,7 @@ import clsx from "clsx" import Link from "next/link" import { checkSidebarItemVisibility } from "@/utils" import { Loading } from "@/components" -import { SidebarItemType } from "types" +import { SidebarItem as SidebarItemType } from "types" export type SidebarItemProps = { item: SidebarItemType @@ -62,12 +62,9 @@ export const SidebarItem = ({ !canHaveTitleStyling && "text-compact-small-plus text-medusa-fg-subtle", canHaveTitleStyling && "text-compact-x-small-plus text-medusa-fg-muted uppercase", - !item.path && "cursor-default", - item.path !== undefined && - active && - "text-medusa-fg-base bg-medusa-bg-component-hover" + active && "text-medusa-fg-base bg-medusa-bg-component-hover" ), - [canHaveTitleStyling, active, item.path] + [canHaveTitleStyling, active] ) /** @@ -150,13 +147,13 @@ export const SidebarItem = ({ )} ref={ref} > - {item.path === undefined && ( + {item.type === "category" && ( {item.title} {item.additionalElms} )} - {item.path !== undefined && ( + {item.type === "link" && ( { @@ -16,10 +16,16 @@ export const SidebarTitle = ({ item }: SidebarTitleProps) => { "border border-transparent", "text-medusa-fg-base text-compact-small-plus" )} - href={item.isPathHref && item.path ? item.path : `#${item.path}`} - replace={!item.isPathHref} - shallow={!item.isPathHref} - {...item.linkProps} + href={ + item.type === "link" + ? item.isPathHref && item.path + ? item.path + : `#${item.path}` + : "#" + } + replace={item.type === "link" && !item.isPathHref} + shallow={item.type === "link" && !item.isPathHref} + {...(item.type === "link" ? item.linkProps : {})} > {item.childSidebarTitle || item.title} diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx index adba69a691a02..56cd541eba624 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx @@ -2,7 +2,7 @@ import React from "react" import { SidebarTitle } from "../Title" -import { SidebarItemType } from "types" +import { SidebarItem } from "types" import { SidebarTopSeparator } from "./Separator" import { SidebarTopNavigationDropdown } from "./NavigationDropdown" import { SearchModalOpener } from "../../.." @@ -10,7 +10,7 @@ import { SidebarTopMobileClose } from "./MobileClose" export type SidebarTopProps = { banner?: React.ReactNode - parentItem?: SidebarItemType + parentItem?: SidebarItem } export const SidebarTop = React.forwardRef( diff --git a/www/packages/docs-ui/src/components/Sidebar/index.tsx b/www/packages/docs-ui/src/components/Sidebar/index.tsx index d360a25297758..dd906590ceed5 100644 --- a/www/packages/docs-ui/src/components/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/index.tsx @@ -9,6 +9,7 @@ import { CSSTransition, SwitchTransition } from "react-transition-group" import { SidebarTop, SidebarTopProps } from "./Top" import useResizeObserver from "@react-hook/resize-observer" import { useClickOutside } from "../.." +import { SidebarTopSeparator } from "./Top/Separator" export type SidebarProps = { className?: string @@ -74,6 +75,7 @@ export const Sidebar = ({ mobileSidebarOpen && [ "!left-docs_0.5 !top-docs_0.5 z-50 shadow-elevation-modal", "rounded", + "lg:!left-0 lg:!top-0 lg:shadow-none", ], !desktopSidebarOpen && "!absolute !-left-full", className @@ -105,7 +107,7 @@ export const Sidebar = ({ className="overflow-y-scroll mt-docs_0.75 clip" ref={sidebarRef} style={{ - maxHeight: `calc(100vh - ${sidebarTopHeight}px)`, + maxHeight: `calc(100vh - ${sidebarTopHeight + 40}px)`, }} > {/* MOBILE SIDEBAR */} @@ -122,27 +124,14 @@ export const Sidebar = ({ isMobile={true} /> ))} +
    {/* DESKTOP SIDEBAR */} -
    - {!sidebarItems.top.length && !staticSidebarItems && ( +
    + {!sidebarItems.default.length && !staticSidebarItems && ( )} - {sidebarItems.top.map((item, index) => ( - - ))} -
    - {/* TODO remove to only have one sidebar items */} -
    - {!sidebarItems.bottom.length && !staticSidebarItems && ( - - )} - {sidebarItems.bottom.map((item, index) => ( + {sidebarItems.default.map((item, index) => ( ( null ) -type SidebarItemWithParent = SidebarItemType & { - parent?: SidebarItemType +type SidebarItemWithParent = SidebarItem & { + parent?: SidebarItem } type SearchItemsResult = { @@ -43,20 +43,20 @@ export type PaginationProviderProps = { export const PaginationProvider = ({ children }: PaginationProviderProps) => { const { items, activePath } = useSidebar() - const combinedItems = useMemo(() => [...items.top, ...items.bottom], [items]) + const combinedItems = useMemo(() => [...items.default], [items]) const previousActivePath = usePrevious(activePath) const [nextPage, setNextPage] = useState() const [prevPage, setPrevPage] = useState() const getFirstChild = ( - item: SidebarItemType + item: SidebarItem ): SidebarItemWithParent | undefined => { const children = getChildrenWithPages(item) if (!children?.length) { return undefined } - return children[0].path + return children[0].type === "link" ? { ...children[0], parent: item, @@ -65,16 +65,16 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { } const getChildrenWithPages = ( - item: SidebarItemType + item: SidebarItem ): SidebarItemWithParent[] | undefined => { return item.children?.filter( (childItem) => - childItem.path !== undefined || getChildrenWithPages(childItem)?.length + childItem.type === "link" || getChildrenWithPages(childItem)?.length ) } const getPrevItem = ( - items: SidebarItemType[], + items: SidebarItem[], index: number ): SidebarItemWithParent | undefined => { let foundItem: SidebarItemWithParent | undefined @@ -90,7 +90,7 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { parent: item, } } - } else if (item.path) { + } else if (item.type === "link") { foundItem = item } @@ -101,12 +101,12 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { } const getNextItem = ( - items: SidebarItemType[], + items: SidebarItem[], index: number ): SidebarItemWithParent | undefined => { let foundItem: SidebarItemWithParent | undefined items.slice(index + 1).some((item) => { - if (item.path) { + if (item.type === "link") { foundItem = item } else if (item.children?.length) { const childItem = getNextItem(item.children, -1) @@ -124,13 +124,13 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { return foundItem } - const searchItems = (currentItems: SidebarItemType[]): SearchItemsResult => { + const searchItems = (currentItems: SidebarItem[]): SearchItemsResult => { const result: SearchItemsResult = { foundActive: false, } result.foundActive = currentItems.some((item, index) => { - if (item.path === activePath) { + if (item.type === "link" && item.path === activePath) { if (index !== 0) { result.prevItem = getPrevItem(currentItems, index) } @@ -152,9 +152,8 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { result.prevItem = childrenResult.prevItem result.nextItem = childrenResult.nextItem if (!result.prevItem) { - result.prevItem = item.path - ? item - : getPrevItem(currentItems, index) + result.prevItem = + item.type === "link" ? item : getPrevItem(currentItems, index) } if (!result.nextItem && index !== currentItems.length - 1) { @@ -178,7 +177,7 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { result.prevItem ? { title: result.prevItem.title, - link: result.prevItem.path || "", + link: result.prevItem.type === "link" ? result.prevItem.path : "", parentTitle: result.prevItem.parent?.title, } : undefined @@ -187,7 +186,7 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { result.nextItem ? { title: result.nextItem.title, - link: result.nextItem.path || "", + link: result.nextItem.type === "link" ? result.nextItem.path : "", parentTitle: result.nextItem.parent?.title, } : undefined diff --git a/www/packages/docs-ui/src/providers/Sidebar/index.tsx b/www/packages/docs-ui/src/providers/Sidebar/index.tsx index f425e3bc1aab8..a0a93c1fcb0d6 100644 --- a/www/packages/docs-ui/src/providers/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/providers/Sidebar/index.tsx @@ -16,11 +16,12 @@ import { useIsBrowser } from "@/hooks" import { NavigationDropdownItem, SidebarItemSections, - SidebarItemType, - SidebarSectionItemsType, + SidebarItem, + SidebarSectionItems, + SidebarItemLink, } from "types" -export type CurrentItemsState = SidebarSectionItemsType & { +export type CurrentItemsState = SidebarSectionItems & { previousSidebar?: CurrentItemsState } @@ -30,29 +31,18 @@ export type SidebarStyleOptions = { } export type SidebarContextType = { - items: SidebarSectionItemsType + items: SidebarSectionItems currentItems: CurrentItemsState | undefined activePath: string | null - getActiveItem: () => SidebarItemType | undefined + getActiveItem: () => SidebarItem | undefined setActivePath: (path: string | null) => void - isItemActive: (item: SidebarItemType, checkChildren?: boolean) => boolean - addItems: ( - item: SidebarItemType[], - options?: { - section?: SidebarItemSections - parent?: { - path: string - changeLoaded?: boolean - } - indexPosition?: number - ignoreExisting?: boolean - } - ) => void + isItemActive: (item: SidebarItem, checkChildren?: boolean) => boolean + addItems: (item: SidebarItem[], options?: ActionOptionsType) => void findItemInSection: ( - section: SidebarItemType[], - item: Partial, + section: SidebarItem[], + item: Partial, checkChildren?: boolean - ) => SidebarItemType | undefined + ) => SidebarItem | undefined mobileSidebarOpen: boolean setMobileSidebarOpen: React.Dispatch> isSidebarEmpty: () => boolean @@ -71,6 +61,7 @@ export type ActionOptionsType = { section?: SidebarItemSections parent?: { path: string + title: string changeLoaded?: boolean } indexPosition?: number @@ -79,21 +70,26 @@ export type ActionOptionsType = { export type ActionType = { type: "add" | "update" - items: SidebarItemType[] + items: SidebarItem[] options?: ActionOptionsType } +const areItemsEqual = (itemA: SidebarItem, itemB: SidebarItem) => { + const hasSameTitle = itemA.title === itemB.title + const hasSamePath = + itemA.type === "link" && itemB.type === "link" && itemA.path === itemB.path + + return hasSameTitle || hasSamePath +} + const findItem = ( - section: SidebarItemType[], - item: Partial, + section: SidebarItem[], + item: Partial, checkChildren = true -): SidebarItemType | undefined => { - let foundItem: SidebarItemType | undefined +): SidebarItem | undefined => { + let foundItem: SidebarItem | undefined section.some((i) => { - if ( - (!item.path && !i.path && i.title === item.title) || - i.path === item.path - ) { + if (areItemsEqual(item as SidebarItem, i)) { foundItem = i } else if (checkChildren && i.children) { foundItem = findItem(i.children, item) @@ -106,20 +102,15 @@ const findItem = ( } export const reducer = ( - state: SidebarSectionItemsType, + state: SidebarSectionItems, { type, items, options }: ActionType ) => { - const { - section = SidebarItemSections.TOP, - parent, - ignoreExisting = false, - indexPosition, - } = options || {} + const { parent, ignoreExisting = false, indexPosition } = options || {} + const sectionName = SidebarItemSections.DEFAULT + const sectionItems = state[sectionName] if (!ignoreExisting) { - const selectedSection = - section === SidebarItemSections.BOTTOM ? state.bottom : state.top - items = items.filter((item) => !findItem(selectedSection, item)) + items = items.filter((item) => !findItem(sectionItems, item)) } if (!items.length) { @@ -130,21 +121,21 @@ export const reducer = ( case "add": return { ...state, - [section]: + [sectionName]: indexPosition !== undefined ? [ - ...state[section].slice(0, indexPosition), + ...sectionItems.slice(0, indexPosition), ...items, - ...state[section].slice(indexPosition), + ...sectionItems.slice(indexPosition), ] - : [...state[section], ...items], + : [...sectionItems, ...items], } case "update": // find item index return { ...state, - [section]: state[section].map((i) => { - if (i.path && parent?.path && i.path === parent?.path) { + [sectionName]: sectionItems.map((i) => { + if (parent && areItemsEqual(i, parent as SidebarItem)) { return { ...i, children: @@ -155,7 +146,11 @@ export const reducer = ( ...(i.children?.slice(indexPosition) || []), ] : [...(i.children || []), ...items], - loaded: parent.changeLoaded ? true : i.loaded, + loaded: parent.changeLoaded + ? true + : i.type === "link" + ? i.loaded + : true, } } return i @@ -170,7 +165,7 @@ export type SidebarProviderProps = { children?: ReactNode isLoading?: boolean setIsLoading?: React.Dispatch> - initialItems?: SidebarSectionItemsType + initialItems?: SidebarSectionItems shouldHandleHashChange?: boolean shouldHandlePathChange?: boolean scrollableElement?: Element | Window @@ -192,8 +187,7 @@ export const SidebarProvider = ({ navigationDropdownItems, }: SidebarProviderProps) => { const [items, dispatch] = useReducer(reducer, { - top: initialItems?.top || [], - bottom: initialItems?.bottom || [], + default: initialItems?.default || [], mobile: initialItems?.mobile || [], }) const [currentItems, setCurrentItems] = useState< @@ -220,23 +214,11 @@ export const SidebarProvider = ({ return ( findItemInSection(items.mobile, { path: activePath }) || - findItemInSection(items.top, { path: activePath }) || - findItemInSection(items.bottom, { path: activePath }) + findItemInSection(items.default, { path: activePath }) ) }, [activePath, items, findItemInSection]) - const addItems = ( - newItems: SidebarItemType[], - options?: { - section?: SidebarItemSections - parent?: { - path: string - changeLoaded?: boolean - } - indexPosition?: number - ignoreExisting?: boolean - } - ) => { + const addItems = (newItems: SidebarItem[], options?: ActionOptionsType) => { dispatch({ type: options?.parent ? "update" : "add", items: newItems, @@ -245,7 +227,11 @@ export const SidebarProvider = ({ } const isItemActive = useCallback( - (item: SidebarItemType, checkChildren = false): boolean => { + (item: SidebarItem, checkChildren = false): boolean => { + if (item.type !== "link") { + return false + } + return ( item.path === activePath || (checkChildren && activePath?.split("_")[0] === item.path) @@ -272,8 +258,8 @@ export const SidebarProvider = ({ } const getCurrentSidebar = useCallback( - (searchItems: SidebarItemType[]): SidebarItemType | undefined => { - let currentSidebar: SidebarItemType | undefined + (searchItems: SidebarItem[]): SidebarItem | undefined => { + let currentSidebar: SidebarItem | undefined searchItems.some((item) => { if (item.isChildSidebar) { if (isItemActive(item)) { @@ -306,9 +292,9 @@ export const SidebarProvider = ({ const previousSidebar = currentItems.previousSidebar || items - const backItem = - previousSidebar.top.find((item) => item.path && !item.isChildSidebar) || - previousSidebar.bottom.find((item) => item.path && !item.isChildSidebar) + const backItem = previousSidebar.default.find( + (item) => item.type === "link" && !item.isChildSidebar + ) as SidebarItemLink if (!backItem) { return @@ -369,7 +355,7 @@ export const SidebarProvider = ({ }, [shouldHandleHashChange, isBrowser]) useEffect(() => { - if (isLoading && items.top.length && items.bottom.length) { + if (isLoading && items.default.length) { setIsLoading?.(false) } }, [items, isLoading, setIsLoading]) @@ -390,8 +376,7 @@ export const SidebarProvider = ({ return } - const currentSidebar = - getCurrentSidebar(items.top) || getCurrentSidebar(items.bottom) + const currentSidebar = getCurrentSidebar(items.default) if (!currentSidebar) { setCurrentItems(undefined) @@ -401,18 +386,20 @@ export const SidebarProvider = ({ if ( currentSidebar.isChildSidebar && currentSidebar.children && - currentItems?.parentItem?.path !== currentSidebar.path + currentItems?.parentItem && + !areItemsEqual(currentItems?.parentItem, currentSidebar) ) { const { children, ...parentItem } = currentSidebar + const hasPreviousSidebar = + currentItems.previousSidebar?.parentItem?.type === "link" && + parentItem.type === "link" && + currentItems.previousSidebar.parentItem.path !== parentItem.path + setCurrentItems({ - top: children, - bottom: [], + default: children, mobile: items.mobile, parentItem: parentItem, - previousSidebar: - currentItems?.previousSidebar?.parentItem?.path !== parentItem.path - ? currentItems - : undefined, + previousSidebar: hasPreviousSidebar ? currentItems : undefined, }) } }, [getCurrentSidebar, activePath]) diff --git a/www/packages/docs-ui/src/providers/SiteConifg/index.tsx b/www/packages/docs-ui/src/providers/SiteConifg/index.tsx index ee1a8ef1ebe52..f272cd604c989 100644 --- a/www/packages/docs-ui/src/providers/SiteConifg/index.tsx +++ b/www/packages/docs-ui/src/providers/SiteConifg/index.tsx @@ -23,8 +23,7 @@ export const SiteConfigProvider = ({ initConfig || { baseUrl: "", sidebar: { - top: [], - bottom: [], + default: [], mobile: [], }, } diff --git a/www/packages/docs-ui/src/utils/get-mobile-sidebar-items.ts b/www/packages/docs-ui/src/utils/get-mobile-sidebar-items.ts index eaf3761523555..2c320b63abf1e 100644 --- a/www/packages/docs-ui/src/utils/get-mobile-sidebar-items.ts +++ b/www/packages/docs-ui/src/utils/get-mobile-sidebar-items.ts @@ -1,4 +1,4 @@ -import { SidebarItemType } from "types" +import { SidebarItem } from "types" import { mobileSidebarItemsV1, mobileSidebarItemsV2 } from ".." type Options = { @@ -9,10 +9,14 @@ type Options = { export function getMobileSidebarItems({ baseUrl, version = "v1", -}: Options): SidebarItemType[] { +}: Options): SidebarItem[] { const mobileItems = version === "v2" ? mobileSidebarItemsV2 : mobileSidebarItemsV1 return mobileItems.map((item) => { + if (item.type === "category") { + return item + } + return { ...item, path: `${baseUrl}${item.path}`, diff --git a/www/packages/types/src/config.ts b/www/packages/types/src/config.ts index e912baf9e1de5..2f535e9cfebc5 100644 --- a/www/packages/types/src/config.ts +++ b/www/packages/types/src/config.ts @@ -1,10 +1,10 @@ -import { SidebarSectionItemsType } from "./sidebar.js" +import { SidebarSectionItems } from "./sidebar.js" export declare type DocsConfig = { titleSuffix?: string baseUrl: string basePath?: string - sidebar: SidebarSectionItemsType + sidebar: SidebarSectionItems filesBasePath?: string useNextLinks?: boolean } diff --git a/www/packages/types/src/sidebar.ts b/www/packages/types/src/sidebar.ts index c2ebc0d170d34..92cb709d2ac26 100644 --- a/www/packages/types/src/sidebar.ts +++ b/www/packages/types/src/sidebar.ts @@ -1,30 +1,40 @@ export enum SidebarItemSections { - TOP = "top", - BOTTOM = "bottom", + DEFAULT = "default", MOBILE = "mobile", } -export type SidebarItemType = { - path?: string +export type SidebarItemCommon = { title: string - pageTitle?: string - additionalElms?: React.ReactNode - children?: SidebarItemType[] - loaded?: boolean - isPathHref?: boolean - linkProps?: React.AllHTMLAttributes + children?: SidebarItem[] isChildSidebar?: boolean hasTitleStyling?: boolean childSidebarTitle?: string + loaded?: boolean + additionalElms?: React.ReactNode } -export type SidebarSectionItemsType = { - [k in SidebarItemSections]: SidebarItemType[] +export type SidebarItemLink = SidebarItemCommon & { + type: "link" + path: string + isPathHref?: boolean + linkProps?: React.AllHTMLAttributes + // TODO maybe remove? + pageTitle?: string +} + +export type SidebarItemCategory = SidebarItemCommon & { + type: "category" +} + +export type SidebarItem = SidebarItemLink | SidebarItemCategory + +export type SidebarSectionItems = { + [k in SidebarItemSections]: SidebarItem[] } & { - parentItem?: SidebarItemType + parentItem?: SidebarItem } -export type RawSidebarItemType = SidebarItemType & { +export type RawSidebarItemType = SidebarItem & { autogenerate_path?: string number?: string } From 8d71e98b405cd090cc419f514341a9cccdfa5dd4 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 1 Aug 2024 14:46:29 +0300 Subject: [PATCH 04/38] finish up sidebar redesign --- www/apps/book/sidebar.mjs | 74 ++++++- www/apps/book/types/index.d.ts | 9 +- www/apps/book/utils/number-sidebar-items.mjs | 33 ++- .../utils/sidebar-attach-common-options.mjs | 27 ++- .../build-scripts/src/generate-sidebar.ts | 19 +- .../Sidebar/Item/Category/index.tsx | 107 +++++++++ .../components/Sidebar/Item/Link/index.tsx | 151 +++++++++++++ .../Sidebar/Item/SubCategory/index.tsx | 135 ++++++++++++ .../src/components/Sidebar/Item/index.tsx | 208 ++---------------- .../Sidebar/{Top => }/Separator/index.tsx | 6 +- .../NavigationDropdown/Menu/Item/index.tsx | 4 +- .../src/components/Sidebar/Top/index.tsx | 12 +- .../docs-ui/src/components/Sidebar/index.tsx | 25 +-- .../src/utils/get-mobile-sidebar-items.ts | 2 +- .../remark-rehype-plugins/src/page-number.ts | 2 +- www/packages/tailwind/base.tailwind.config.js | 22 +- www/packages/types/src/sidebar.ts | 11 +- 17 files changed, 598 insertions(+), 249 deletions(-) create mode 100644 www/packages/docs-ui/src/components/Sidebar/Item/Category/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Item/SubCategory/index.tsx rename www/packages/docs-ui/src/components/Sidebar/{Top => }/Separator/index.tsx (76%) diff --git a/www/apps/book/sidebar.mjs b/www/apps/book/sidebar.mjs index 9338cad3a1450..b596b984931d1 100644 --- a/www/apps/book/sidebar.mjs +++ b/www/apps/book/sidebar.mjs @@ -2,258 +2,319 @@ import numberSidebarItems from "./utils/number-sidebar-items.mjs" import { sidebarAttachHrefCommonOptions } from "./utils/sidebar-attach-common-options.mjs" /** @type {import('@/types').SidebarItem[]} */ -export const sidebar = sidebarAttachHrefCommonOptions( - numberSidebarItems([ +export const sidebar = numberSidebarItems( + sidebarAttachHrefCommonOptions([ { + type: "link", path: "/", title: "Introduction", }, { + type: "link", path: "/first-customizations", title: "Your First Customizations", }, { + type: "link", path: "/basics", title: "The Basics", children: [ { + type: "link", path: "/basics/project-directories-files", title: "Project Directories and Files", }, { + type: "link", path: "/basics/medusa-container", title: "Medusa Container", }, { + type: "link", path: "/basics/api-routes", title: "API Routes", }, { + type: "link", path: "/basics/modules-and-services", title: "Modules and Services", }, { + type: "link", path: "/basics/commerce-modules", title: "Commerce Modules", }, { + type: "link", path: "/basics/modules-directory-structure", title: "Modules Directory Structure", }, { + type: "link", path: "/basics/data-models", title: "Data Models", }, { + type: "link", path: "/basics/loaders", title: "Loaders", }, { + type: "link", path: "/basics/events-and-subscribers", title: "Events and Subscribers", }, { + type: "link", path: "/basics/scheduled-jobs", title: "Scheduled Jobs", }, { + type: "link", path: "/basics/workflows", title: "Workflows", }, { + type: "link", path: "/basics/admin-customizations", title: "Admin Customizations", }, ], }, { + type: "link", path: "/advanced-development", title: "Advanced Development", children: [ { + type: "sub-category", title: "API Routes", children: [ { + type: "link", path: "/advanced-development/api-routes/http-methods", title: "HTTP Methods", }, { + type: "link", path: "/advanced-development/api-routes/parameters", title: "Parameters", }, { + type: "link", path: "/advanced-development/api-routes/middlewares", title: "Middlewares", }, { + type: "link", path: "/advanced-development/api-routes/protected-routes", title: "Protected Routes", }, { + type: "link", path: "/advanced-development/api-routes/cors", title: "Handling CORS", }, ], }, { + type: "sub-category", title: "Modules", children: [ { + type: "link", path: "/advanced-development/modules/container", title: "Module's Container", }, { + type: "link", path: "/advanced-development/modules/service-factory", title: "Service Factory", }, { + type: "link", path: "/advanced-development/modules/isolation", title: "Module Isolation", }, { + type: "link", path: "/advanced-development/modules/module-links", title: "Module Links", }, { + type: "link", path: "/advanced-development/modules/module-link-directions", title: "Module Link Direction", }, { + type: "link", path: "/advanced-development/modules/remote-link", title: "Remote Link", }, { + type: "link", path: "/advanced-development/modules/remote-query", title: "Remote Query", }, { + type: "link", path: "/advanced-development/modules/options", title: "Module Options", }, ], }, { + type: "link", path: "/advanced-development/data-models", title: "Data Models", children: [ { + type: "link", path: "/advanced-development/data-models/property-types", title: "Property Types", }, { + type: "link", path: "/advanced-development/data-models/primary-key", title: "Primary Key", }, { + type: "link", path: "/advanced-development/data-models/default-properties", title: "Default Properties", }, { + type: "link", path: "/advanced-development/data-models/configure-properties", title: "Configure Properties", }, { + type: "link", path: "/advanced-development/data-models/relationships", title: "Relationships", }, { + type: "link", path: "/advanced-development/data-models/manage-relationships", title: "Manage Relationships", }, { + type: "link", path: "/advanced-development/data-models/index", title: "Index", }, { + type: "link", path: "/advanced-development/data-models/searchable-property", title: "Searchable Property", }, { + type: "link", path: "/advanced-development/data-models/write-migration", title: "Write Migration", }, ], }, { + type: "sub-category", title: "Events and Subscribers", children: [ { + type: "link", path: "/advanced-development/events-and-subscribers/data-payload", title: "Events Data Payload", }, ], }, { + type: "sub-category", title: "Scheduled Jobs", children: [ { + type: "link", path: "/advanced-development/scheduled-jobs/execution-number", title: "Execution Number", }, ], }, { + type: "sub-category", title: "Workflows", children: [ { + type: "link", path: "/advanced-development/workflows/constructor-constraints", title: "Workflow Constraints", }, { + type: "link", path: "/advanced-development/workflows/conditions", title: "Conditions in Workflows", }, { + type: "link", path: "/advanced-development/workflows/compensation-function", title: "Compensation Function", }, { + type: "link", path: "/advanced-development/workflows/access-workflow-errors", title: "Access Workflow Errors", }, { + type: "link", path: "/advanced-development/workflows/retry-failed-steps", title: "Retry Failed Steps", }, { + type: "link", path: "/advanced-development/workflows/parallel-steps", title: "Run Steps in Parallel", }, { + type: "link", path: "/advanced-development/workflows/workflow-timeout", title: "Workflow Timeout", }, { + type: "link", path: "/advanced-development/workflows/long-running-workflow", title: "Long-Running Workflow", }, { + type: "link", path: "/advanced-development/workflows/execute-another-workflow", title: "Execute Another Workflow", }, { + type: "link", path: "/advanced-development/workflows/advanced-example", title: "Example: Advanced Workflow", }, ], }, { + type: "link", path: "/advanced-development/custom-cli-scripts", title: "Custom CLI Scripts", }, { + type: "link", path: "/advanced-development/admin", title: "Admin Development", children: [ { + type: "link", path: "/advanced-development/admin/widgets", title: "Admin Widgets", }, { + type: "link", path: "/advanced-development/admin/ui-routes", title: "Admin UI Routes", }, { + type: "link", path: "/advanced-development/admin/tips", title: "Tips", }, @@ -262,42 +323,51 @@ export const sidebar = sidebarAttachHrefCommonOptions( ], }, { + type: "link", path: "/storefront-development", title: "Storefront Development", children: [ { + type: "link", path: "/storefront-development/nextjs-starter", title: "Next.js Starter", }, ], }, { + type: "link", path: "/architectural-modules", title: "Architectural Modules", }, { + type: "link", path: "/debugging-and-testing", title: "Debugging and Testing", children: [ { + type: "link", path: "/debugging-and-testing/logging", title: "Logging", }, { + type: "link", path: "/debugging-and-testing/tools", title: "Tools", }, ], }, { + type: "link", path: "/deployment", title: "Deployment", }, { + type: "link", path: "/more-resources", title: "More Resources", }, { + type: "link", path: "/cheatsheet", title: "Cheat Sheet", }, diff --git a/www/apps/book/types/index.d.ts b/www/apps/book/types/index.d.ts index e7594b456ce80..3934655afd10e 100644 --- a/www/apps/book/types/index.d.ts +++ b/www/apps/book/types/index.d.ts @@ -1,11 +1,8 @@ -import { - SidebarSectionItemsType, - SidebarItemType as UiSidebarItemType, -} from "docs-ui" +import { SidebarSectionItems, SidebarItem as SidebarItemType } from "types" -export declare type SidebarItemType = UiSidebarItemType & { +export declare type SidebarItem = SidebarItemType & { isSoon: boolean number?: string } -export declare type SidebarConfig = SidebarSectionItemsType +export declare type SidebarConfig = SidebarSectionItems diff --git a/www/apps/book/utils/number-sidebar-items.mjs b/www/apps/book/utils/number-sidebar-items.mjs index 26881f0d1bc90..17c79d8d8a87e 100644 --- a/www/apps/book/utils/number-sidebar-items.mjs +++ b/www/apps/book/utils/number-sidebar-items.mjs @@ -9,7 +9,23 @@ export default function numberSidebarItems(sidebarItems, numbering = [1]) { if (!numbering.length) { numbering.push(1) } + const isTopItems = numbering.length === 1 + /** @type {import("@/types").SidebarItem[]} */ + const numberedItems = [] + /** @type {import("@/types").SidebarItem | undefined} */ + let parentItem sidebarItems.forEach((item) => { + if (isTopItems) { + // Add chapter category + numberedItems.push({ + type: "category", + title: `Chapter ${padNumber(numbering[0])}`, + children: [], + loaded: true, + }) + + parentItem = numberedItems[numberedItems.length - 1] + } // append current number to the item's title item.number = `${numbering.join(".")}.` item.title = `${item.number} ${item.title.trim()}` @@ -18,8 +34,23 @@ export default function numberSidebarItems(sidebarItems, numbering = [1]) { item.children = numberSidebarItems(item.children, [...numbering, 1]) } + if (parentItem) { + parentItem.children.push(item) + } else { + numberedItems.push(item) + } + numbering[numbering.length - 1]++ }) - return sidebarItems + return numberedItems +} + +function padNumber(number) { + number = number.toString() + if (number.length < 2) { + number = `0` + number + } + + return number } diff --git a/www/apps/book/utils/sidebar-attach-common-options.mjs b/www/apps/book/utils/sidebar-attach-common-options.mjs index e40b6dee0e61e..3654526cb42af 100644 --- a/www/apps/book/utils/sidebar-attach-common-options.mjs +++ b/www/apps/book/utils/sidebar-attach-common-options.mjs @@ -1,4 +1,4 @@ -/** @type {Partial} */ +/** @type {Partial} */ const commonOptions = { loaded: true, isPathHref: true, @@ -6,13 +6,22 @@ const commonOptions = { /** * - * @param {import("../providers").SidebarItemType[]} sidebar - * @returns {import("../providers").SidebarItemType[]} + * @param {import("@/types").SidebarItem[]} sidebar + * @param {boolean} nested + * @returns {import("@/types").SidebarItem[]} */ -export function sidebarAttachHrefCommonOptions(sidebar) { - return sidebar.map((item) => ({ - ...commonOptions, - ...item, - children: sidebarAttachHrefCommonOptions(item.children || []), - })) +export function sidebarAttachHrefCommonOptions(sidebar, nested = false) { + return sidebar.map((item) => { + const updatedItem = { + ...commonOptions, + ...item, + children: sidebarAttachHrefCommonOptions(item.children || [], true), + } + + if (updatedItem.type !== "category" && !nested) { + updatedItem.childrenSameLevel = true + } + + return updatedItem + }) } diff --git a/www/packages/build-scripts/src/generate-sidebar.ts b/www/packages/build-scripts/src/generate-sidebar.ts index 2bba5fdf9ffb4..94d0279225c32 100644 --- a/www/packages/build-scripts/src/generate-sidebar.ts +++ b/www/packages/build-scripts/src/generate-sidebar.ts @@ -35,17 +35,13 @@ async function getSidebarItems( true ) if (nested && newItems.length > 1) { - items.push( - ...sidebarAttachHrefCommonOptions([ - { - title: - fileBasename.charAt(0).toUpperCase() + - fileBasename.substring(1), - hasTitleStyling: true, - children: newItems, - }, - ]) - ) + items.push({ + type: "category", + title: + fileBasename.charAt(0).toUpperCase() + fileBasename.substring(1), + children: newItems, + loaded: true, + }) } else { items.push(...sidebarAttachHrefCommonOptions(newItems)) } @@ -63,6 +59,7 @@ async function getSidebarItems( const newItem = sidebarAttachHrefCommonOptions([ { + type: "link", path: frontmatter.slug || filePath.replace(basePath, "").replace(`/${fileBasename}`, ""), diff --git a/www/packages/docs-ui/src/components/Sidebar/Item/Category/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Item/Category/index.tsx new file mode 100644 index 0000000000000..46903df1d3f0c --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Item/Category/index.tsx @@ -0,0 +1,107 @@ +"use client" + +// @refresh reset + +import React, { useEffect, useRef, useState } from "react" +import { SidebarItemCategory as SidebarItemCategoryType } from "types" +import { Loading, SidebarItem } from "../../../.." +import clsx from "clsx" +import { MinusMini, PlusMini } from "@medusajs/icons" +import { CSSTransition } from "react-transition-group" + +export type SidebarItemCategory = { + item: SidebarItemCategoryType + expandItems?: boolean +} & React.AllHTMLAttributes + +export const SidebarItemCategory = ({ + item, + expandItems = true, + className, +}: SidebarItemCategory) => { + const [showLoading, setShowLoading] = useState(false) + const [open, setOpen] = useState(expandItems) + const childrenRef = useRef(null) + + useEffect(() => { + if (open && !item.loaded) { + setShowLoading(true) + } + }, [open]) + + useEffect(() => { + if (item.loaded && showLoading) { + setShowLoading(false) + } + }, [item]) + + return ( +
    +
    setOpen((prev) => !prev)} + > + {item.title} + {item.additionalElms} + {!item.additionalElms && ( + <> + {open && } + {!open && } + + )} +
    + { + childrenRef.current?.classList.add("overflow-hidden", "m-0", "h-0") + }} + onEnter={() => { + childrenRef.current?.classList.remove("overflow-hidden", "m-0", "h-0") + }} + > +
      + {showLoading && ( + + )} + {item.children?.map((childItem, index) => ( + + ))} +
    +
    +
    + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx new file mode 100644 index 0000000000000..c60aa0feecb2e --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx @@ -0,0 +1,151 @@ +"use client" + +// @refresh reset + +import React, { useEffect, useMemo, useRef } from "react" +import { SidebarItemLink as SidebarItemlinkType } from "types" +import { + checkSidebarItemVisibility, + SidebarItem, + useMobile, + useSidebar, +} from "../../../.." +import clsx from "clsx" +import Link from "next/link" + +export type SidebarItemLinkProps = { + item: SidebarItemlinkType + nested?: boolean +} & React.AllHTMLAttributes + +export const SidebarItemLink = ({ + item, + className, + nested = false, +}: SidebarItemLinkProps) => { + const { + isItemActive, + setMobileSidebarOpen: setSidebarOpen, + disableActiveTransition, + sidebarRef, + } = useSidebar() + const { isMobile } = useMobile() + const active = useMemo( + () => !isMobile && isItemActive(item, true), + [isItemActive, item, isMobile] + ) + const ref = useRef(null) + + /** + * Tries to place the item in the center of the sidebar + */ + const newTopCalculator = (): number => { + if (!sidebarRef.current || !ref.current) { + return 0 + } + const sidebarBoundingRect = sidebarRef.current.getBoundingClientRect() + const sidebarHalf = sidebarBoundingRect.height / 2 + const itemTop = ref.current.offsetTop + const itemBottom = + itemTop + (ref.current.children.item(0) as HTMLElement)?.clientHeight + + // try deducting half + let newTop = itemTop - sidebarHalf + let newBottom = newTop + sidebarBoundingRect.height + if (newTop <= itemTop && newBottom >= itemBottom) { + return newTop + } + + // try adding half + newTop = itemTop + sidebarHalf + newBottom = newTop + sidebarBoundingRect.height + if (newTop <= itemTop && newBottom >= itemBottom) { + return newTop + } + + //return the item's top minus some top margin + return itemTop - sidebarBoundingRect.top + } + + useEffect(() => { + if ( + active && + ref.current && + sidebarRef.current && + window.innerWidth >= 1025 + ) { + if ( + !disableActiveTransition && + !checkSidebarItemVisibility( + (ref.current.children.item(0) as HTMLElement) || ref.current, + !disableActiveTransition + ) + ) { + ref.current.scrollIntoView({ + block: "center", + }) + } else if (disableActiveTransition) { + sidebarRef.current.scrollTo({ + top: newTopCalculator(), + }) + } + } + }, [active, sidebarRef.current, disableActiveTransition]) + + const hasChildren = useMemo(() => { + return item.children?.length || 0 > 0 + }, [item.children]) + + return ( +
  • + { + if (isMobile) { + setSidebarOpen(false) + } + }} + replace={!item.isPathHref} + shallow={!item.isPathHref} + {...item.linkProps} + > + {item.title} + {item.additionalElms} + + {hasChildren && ( +
      + {item.children!.map((childItem, index) => ( + + ))} +
    + )} +
  • + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Item/SubCategory/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Item/SubCategory/index.tsx new file mode 100644 index 0000000000000..0e7ab576087a7 --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Item/SubCategory/index.tsx @@ -0,0 +1,135 @@ +"use client" + +// @refresh reset + +import React, { useEffect, useMemo, useRef } from "react" +import { SidebarItemSubCategory as SidebarItemSubCategoryType } from "types" +import { + checkSidebarItemVisibility, + SidebarItem, + useMobile, + useSidebar, +} from "../../../.." +import clsx from "clsx" + +export type SidebarItemLinkProps = { + item: SidebarItemSubCategoryType + nested?: boolean +} & React.AllHTMLAttributes + +export const SidebarItemSubCategory = ({ + item, + className, + nested = false, +}: SidebarItemLinkProps) => { + const { isItemActive, disableActiveTransition, sidebarRef } = useSidebar() + const { isMobile } = useMobile() + const active = useMemo( + () => !isMobile && isItemActive(item, true), + [isItemActive, item, isMobile] + ) + const ref = useRef(null) + + /** + * Tries to place the item in the center of the sidebar + */ + const newTopCalculator = (): number => { + if (!sidebarRef.current || !ref.current) { + return 0 + } + const sidebarBoundingRect = sidebarRef.current.getBoundingClientRect() + const sidebarHalf = sidebarBoundingRect.height / 2 + const itemTop = ref.current.offsetTop + const itemBottom = + itemTop + (ref.current.children.item(0) as HTMLElement)?.clientHeight + + // try deducting half + let newTop = itemTop - sidebarHalf + let newBottom = newTop + sidebarBoundingRect.height + if (newTop <= itemTop && newBottom >= itemBottom) { + return newTop + } + + // try adding half + newTop = itemTop + sidebarHalf + newBottom = newTop + sidebarBoundingRect.height + if (newTop <= itemTop && newBottom >= itemBottom) { + return newTop + } + + //return the item's top minus some top margin + return itemTop - sidebarBoundingRect.top + } + + useEffect(() => { + if ( + active && + ref.current && + sidebarRef.current && + window.innerWidth >= 1025 + ) { + if ( + !disableActiveTransition && + !checkSidebarItemVisibility( + (ref.current.children.item(0) as HTMLElement) || ref.current, + !disableActiveTransition + ) + ) { + ref.current.scrollIntoView({ + block: "center", + }) + } else if (disableActiveTransition) { + sidebarRef.current.scrollTo({ + top: newTopCalculator(), + }) + } + } + }, [active, sidebarRef.current, disableActiveTransition]) + + const hasChildren = useMemo(() => { + return item.children?.length || 0 > 0 + }, [item.children]) + + return ( +
  • + + {item.title} + {item.additionalElms} + + {hasChildren && ( +
      + {item.children!.map((childItem, index) => ( + + ))} +
    + )} +
  • + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx index faac0409e6209..34fbceeded686 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Item/index.tsx @@ -1,201 +1,35 @@ "use client" -// @refresh reset - -import React, { useEffect, useMemo, useRef, useState } from "react" -import { useSidebar } from "@/providers" -import clsx from "clsx" -import Link from "next/link" -import { checkSidebarItemVisibility } from "@/utils" -import { Loading } from "@/components" +import React from "react" import { SidebarItem as SidebarItemType } from "types" +import { SidebarItemCategory } from "./Category" +import { SidebarItemLink } from "./Link" +import { SidebarItemSubCategory } from "./SubCategory" +import { SidebarSeparator } from "../Separator" export type SidebarItemProps = { item: SidebarItemType nested?: boolean expandItems?: boolean - currentLevel?: number - isSidebarTitle?: boolean - sidebarHasParent?: boolean - isMobile?: boolean -} & React.AllHTMLAttributes + hasNextItems?: boolean +} & React.AllHTMLAttributes export const SidebarItem = ({ item, - nested = false, - expandItems = false, - className, - currentLevel = 1, - sidebarHasParent = false, - isMobile = false, + hasNextItems = false, + ...props }: SidebarItemProps) => { - const [showLoading, setShowLoading] = useState(false) - const { - isItemActive, - setMobileSidebarOpen: setSidebarOpen, - disableActiveTransition, - noTitleStyling, - sidebarRef, - } = useSidebar() - const active = useMemo( - () => !isMobile && isItemActive(item, nested), - [isItemActive, item, nested, isMobile] - ) - const collapsed = !expandItems && !isItemActive(item, true) - const ref = useRef(null) - - const itemChildren = useMemo(() => { - return item.isChildSidebar ? undefined : item.children - }, [item]) - const canHaveTitleStyling = useMemo( - () => - item.hasTitleStyling || - ((itemChildren?.length || !item.loaded) && !noTitleStyling && !nested), - [itemChildren, noTitleStyling, item, nested] - ) - - const classNames = useMemo( - () => - clsx( - "flex items-center justify-between gap-docs_0.5 rounded-docs_xs px-docs_0.5 py-[6px]", - "hover:no-underline hover:bg-medusa-bg-component-hover", - !canHaveTitleStyling && "text-compact-small-plus text-medusa-fg-subtle", - canHaveTitleStyling && - "text-compact-x-small-plus text-medusa-fg-muted uppercase", - active && "text-medusa-fg-base bg-medusa-bg-component-hover" - ), - [canHaveTitleStyling, active] - ) - - /** - * Tries to place the item in the center of the sidebar - */ - const newTopCalculator = (): number => { - if (!sidebarRef.current || !ref.current) { - return 0 - } - const sidebarBoundingRect = sidebarRef.current.getBoundingClientRect() - const sidebarHalf = sidebarBoundingRect.height / 2 - const itemTop = ref.current.offsetTop - const itemBottom = - itemTop + (ref.current.children.item(0) as HTMLElement)?.clientHeight - - // try deducting half - let newTop = itemTop - sidebarHalf - let newBottom = newTop + sidebarBoundingRect.height - if (newTop <= itemTop && newBottom >= itemBottom) { - return newTop - } - - // try adding half - newTop = itemTop + sidebarHalf - newBottom = newTop + sidebarBoundingRect.height - if (newTop <= itemTop && newBottom >= itemBottom) { - return newTop - } - - //return the item's top minus some top margin - return itemTop - sidebarBoundingRect.top + switch (item.type) { + case "category": + return ( + <> + + {hasNextItems && } + + ) + case "sub-category": + return + case "link": + return } - - useEffect(() => { - if ( - active && - ref.current && - sidebarRef.current && - window.innerWidth >= 1025 - ) { - if ( - !disableActiveTransition && - !checkSidebarItemVisibility( - (ref.current.children.item(0) as HTMLElement) || ref.current, - !disableActiveTransition - ) - ) { - ref.current.scrollIntoView({ - block: "center", - }) - } else if (disableActiveTransition) { - sidebarRef.current.scrollTo({ - top: newTopCalculator(), - }) - } - } - if (active) { - setShowLoading(true) - } - }, [active, sidebarRef.current, disableActiveTransition]) - - return ( -
  • - {item.type === "category" && ( - - {item.title} - {item.additionalElms} - - )} - {item.type === "link" && ( - { - if (window.innerWidth < 1025) { - setSidebarOpen(false) - } - }} - replace={!item.isPathHref} - shallow={!item.isPathHref} - {...item.linkProps} - > - {item.title} - {item.additionalElms} - - )} - {itemChildren && ( -
      - {showLoading && !item.loaded && ( - - )} - {itemChildren?.map((childItem, index) => ( - - ))} -
    - )} -
  • - ) } diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Separator/index.tsx similarity index 76% rename from www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx rename to www/packages/docs-ui/src/components/Sidebar/Separator/index.tsx index 5cc2ba37bfb38..939c3738d8c2d 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Top/Separator/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Separator/index.tsx @@ -3,13 +3,11 @@ import clsx from "clsx" import React from "react" -export type SidebarTopSeparatorProps = { +export type SidebarSeparatorProps = { className?: string } -export const SidebarTopSeparator = ({ - className, -}: SidebarTopSeparatorProps) => { +export const SidebarSeparator = ({ className }: SidebarSeparatorProps) => { return ( { switch (item.type) { case "divider": - return + return case "link": return ( ( function SidebarTop({ banner, parentItem }, ref) { return ( - <> +
    - + {/* {banner &&
    {banner}
    } */} {parentItem && ( <> - + )} - +
    - +
    ) } ) diff --git a/www/packages/docs-ui/src/components/Sidebar/index.tsx b/www/packages/docs-ui/src/components/Sidebar/index.tsx index dd906590ceed5..8954daadd0b42 100644 --- a/www/packages/docs-ui/src/components/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/index.tsx @@ -1,6 +1,6 @@ "use client" -import React, { useCallback, useMemo, useRef, useState } from "react" +import React, { useMemo, useRef, useState } from "react" import { useSidebar } from "@/providers" import clsx from "clsx" import { Loading } from "@/components" @@ -9,7 +9,7 @@ import { CSSTransition, SwitchTransition } from "react-transition-group" import { SidebarTop, SidebarTopProps } from "./Top" import useResizeObserver from "@react-hook/resize-observer" import { useClickOutside } from "../.." -import { SidebarTopSeparator } from "./Top/Separator" +import { SidebarSeparator } from "./Separator" export type SidebarProps = { className?: string @@ -19,7 +19,7 @@ export type SidebarProps = { export const Sidebar = ({ className = "", - expandItems = false, + expandItems = true, sidebarTopProps, }: SidebarProps) => { const sidebarTopRef = useRef(null) @@ -47,11 +47,6 @@ export const Sidebar = ({ [items, currentItems] ) - const sidebarHasParent = useMemo( - () => sidebarItems.parentItem !== undefined, - [sidebarItems] - ) - useResizeObserver(sidebarTopRef, () => { setSidebarHeight(sidebarTopRef.current?.clientHeight || 0) }) @@ -84,10 +79,7 @@ export const Sidebar = ({ animationFillMode: "forwards", }} > -
    ) diff --git a/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx index bfa44990c060d..1048d44bfdc23 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Top/index.tsx @@ -2,7 +2,7 @@ import React from "react" import { SidebarTitle } from "../Title" -import { SidebarItem } from "types" +import { InteractiveSidebarItem, SidebarItem } from "types" import { SidebarSeparator } from "../Separator" import { SidebarTopNavigationDropdown } from "./NavigationDropdown" import { SearchModalOpener } from "../../.." @@ -10,7 +10,7 @@ import { SidebarTopMobileClose } from "./MobileClose" export type SidebarTopProps = { banner?: React.ReactNode - parentItem?: SidebarItem + parentItem?: InteractiveSidebarItem } export const SidebarTop = React.forwardRef( @@ -21,7 +21,7 @@ export const SidebarTop = React.forwardRef(
    - + {/* {banner &&
    {banner}
    } */} {parentItem && ( <> @@ -29,7 +29,7 @@ export const SidebarTop = React.forwardRef( )} - +
    ) diff --git a/www/packages/docs-ui/src/components/Sidebar/index.tsx b/www/packages/docs-ui/src/components/Sidebar/index.tsx index 8954daadd0b42..fa89187196969 100644 --- a/www/packages/docs-ui/src/components/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/index.tsx @@ -118,7 +118,7 @@ export const Sidebar = ({ {/* DESKTOP SIDEBAR */} -
    +
    {!sidebarItems.default.length && !staticSidebarItems && ( )} diff --git a/www/packages/docs-ui/src/providers/Pagination/index.tsx b/www/packages/docs-ui/src/providers/Pagination/index.tsx index 3dbeef95bcf40..f8211b21efd31 100644 --- a/www/packages/docs-ui/src/providers/Pagination/index.tsx +++ b/www/packages/docs-ui/src/providers/Pagination/index.tsx @@ -9,7 +9,7 @@ import React, { } from "react" import { useSidebar } from "../Sidebar" import { usePrevious } from "@uidotdev/usehooks" -import { SidebarItem } from "types" +import { InteractiveSidebarItem, SidebarItem } from "types" export type Page = { title: string @@ -27,7 +27,7 @@ export const PaginationContext = createContext( null ) -type SidebarItemWithParent = SidebarItem & { +type SidebarItemWithParent = InteractiveSidebarItem & { parent?: SidebarItem } @@ -49,7 +49,7 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { const [prevPage, setPrevPage] = useState() const getFirstChild = ( - item: SidebarItem + item: InteractiveSidebarItem ): SidebarItemWithParent | undefined => { const children = getChildrenWithPages(item) if (!children?.length) { @@ -65,12 +65,14 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { } const getChildrenWithPages = ( - item: SidebarItem + item: InteractiveSidebarItem ): SidebarItemWithParent[] | undefined => { return item.children?.filter( (childItem) => - childItem.type === "link" || getChildrenWithPages(childItem)?.length - ) + childItem.type === "link" || + (childItem.type !== "separator" && + getChildrenWithPages(childItem)?.length) + ) as SidebarItemWithParent[] } const getPrevItem = ( @@ -82,6 +84,9 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { .slice(0, index) .reverse() .some((item) => { + if (item.type === "separator") { + return false + } if (item.children?.length) { const childItem = getPrevItem(item.children, item.children.length) if (childItem) { @@ -106,6 +111,10 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { ): SidebarItemWithParent | undefined => { let foundItem: SidebarItemWithParent | undefined items.slice(index + 1).some((item) => { + if (item.type === "separator") { + return false + } + if (item.type === "link") { foundItem = item } else if (item.children?.length) { @@ -145,7 +154,7 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { return true } - if (item.children?.length) { + if (item.type !== "separator" && item.children?.length) { const childrenResult = searchItems(item.children) if (childrenResult.foundActive) { @@ -178,7 +187,10 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { ? { title: result.prevItem.title, link: result.prevItem.type === "link" ? result.prevItem.path : "", - parentTitle: result.prevItem.parent?.title, + parentTitle: + result.prevItem.parent?.type !== "separator" + ? result.prevItem.parent?.title + : undefined, } : undefined ) @@ -187,7 +199,10 @@ export const PaginationProvider = ({ children }: PaginationProviderProps) => { ? { title: result.nextItem.title, link: result.nextItem.type === "link" ? result.nextItem.path : "", - parentTitle: result.nextItem.parent?.title, + parentTitle: + result.nextItem.parent?.type !== "separator" + ? result.nextItem.parent?.title + : undefined, } : undefined ) diff --git a/www/packages/docs-ui/src/providers/Sidebar/index.tsx b/www/packages/docs-ui/src/providers/Sidebar/index.tsx index a0a93c1fcb0d6..b19583366419f 100644 --- a/www/packages/docs-ui/src/providers/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/providers/Sidebar/index.tsx @@ -19,6 +19,7 @@ import { SidebarItem, SidebarSectionItems, SidebarItemLink, + InteractiveSidebarItem, } from "types" export type CurrentItemsState = SidebarSectionItems & { @@ -34,7 +35,7 @@ export type SidebarContextType = { items: SidebarSectionItems currentItems: CurrentItemsState | undefined activePath: string | null - getActiveItem: () => SidebarItem | undefined + getActiveItem: () => InteractiveSidebarItem | undefined setActivePath: (path: string | null) => void isItemActive: (item: SidebarItem, checkChildren?: boolean) => boolean addItems: (item: SidebarItem[], options?: ActionOptionsType) => void @@ -74,7 +75,10 @@ export type ActionType = { options?: ActionOptionsType } -const areItemsEqual = (itemA: SidebarItem, itemB: SidebarItem) => { +const areItemsEqual = (itemA: SidebarItem, itemB: SidebarItem): boolean => { + if (itemA.type === "separator" || itemB.type === "separator") { + return false + } const hasSameTitle = itemA.title === itemB.title const hasSamePath = itemA.type === "link" && itemB.type === "link" && itemA.path === itemB.path @@ -86,9 +90,12 @@ const findItem = ( section: SidebarItem[], item: Partial, checkChildren = true -): SidebarItem | undefined => { - let foundItem: SidebarItem | undefined +): InteractiveSidebarItem | undefined => { + let foundItem: InteractiveSidebarItem | undefined section.some((i) => { + if (i.type === "separator") { + return false + } if (areItemsEqual(item as SidebarItem, i)) { foundItem = i } else if (checkChildren && i.children) { @@ -135,6 +142,9 @@ export const reducer = ( return { ...state, [sectionName]: sectionItems.map((i) => { + if (i.type === "separator") { + return i + } if (parent && areItemsEqual(i, parent as SidebarItem)) { return { ...i, @@ -213,8 +223,8 @@ export const SidebarProvider = ({ } return ( - findItemInSection(items.mobile, { path: activePath }) || - findItemInSection(items.default, { path: activePath }) + findItemInSection(items.mobile, { path: activePath, type: "link" }) || + findItemInSection(items.default, { path: activePath, type: "link" }) ) }, [activePath, items, findItemInSection]) @@ -258,23 +268,27 @@ export const SidebarProvider = ({ } const getCurrentSidebar = useCallback( - (searchItems: SidebarItem[]): SidebarItem | undefined => { - let currentSidebar: SidebarItem | undefined + (searchItems: SidebarItem[]): InteractiveSidebarItem | undefined => { + let currentSidebar: InteractiveSidebarItem | undefined searchItems.some((item) => { - if (item.isChildSidebar) { - if (isItemActive(item)) { - currentSidebar = item - } else if (item.children?.length) { - const childSidebar = - getCurrentSidebar(item.children) || - findItem(item.children, { path: activePath || undefined }) - - if (childSidebar) { - currentSidebar = childSidebar.isChildSidebar ? childSidebar : item - } + if (item.type === "separator") { + return false + } + if (item.isChildSidebar && isItemActive(item)) { + currentSidebar = item + } + + if (!currentSidebar && item.children?.length) { + const childSidebar = + getCurrentSidebar(item.children) || + findItem(item.children, { + path: activePath || undefined, + type: "link", + }) + + if (childSidebar) { + currentSidebar = childSidebar.isChildSidebar ? childSidebar : item } - } else if (item.children?.length) { - currentSidebar = getCurrentSidebar(item.children) } return currentSidebar !== undefined @@ -386,12 +400,12 @@ export const SidebarProvider = ({ if ( currentSidebar.isChildSidebar && currentSidebar.children && - currentItems?.parentItem && - !areItemsEqual(currentItems?.parentItem, currentSidebar) + (!currentItems?.parentItem || + !areItemsEqual(currentItems?.parentItem, currentSidebar)) ) { const { children, ...parentItem } = currentSidebar const hasPreviousSidebar = - currentItems.previousSidebar?.parentItem?.type === "link" && + currentItems?.previousSidebar?.parentItem?.type === "link" && parentItem.type === "link" && currentItems.previousSidebar.parentItem.path !== parentItem.path diff --git a/www/packages/docs-ui/src/utils/sidebar-attach-href-common-options.ts b/www/packages/docs-ui/src/utils/sidebar-attach-href-common-options.ts index 363b6d6d72976..bb44f8b048b3d 100644 --- a/www/packages/docs-ui/src/utils/sidebar-attach-href-common-options.ts +++ b/www/packages/docs-ui/src/utils/sidebar-attach-href-common-options.ts @@ -1,16 +1,22 @@ -import { RawSidebarItemType } from "types" +import { RawSidebarItem } from "types" -const commonOptions: Partial = { +const commonOptions: Partial = { loaded: true, isPathHref: true, } export function sidebarAttachHrefCommonOptions( - sidebar: RawSidebarItemType[] -): RawSidebarItemType[] { - return sidebar.map((item) => ({ - ...commonOptions, - ...item, - children: sidebarAttachHrefCommonOptions(item.children || []), - })) + sidebar: RawSidebarItem[] +): RawSidebarItem[] { + return sidebar.map((item) => { + if (item.type === "separator") { + return item + } + + return { + ...commonOptions, + ...item, + children: sidebarAttachHrefCommonOptions(item.children || []), + } + }) } diff --git a/www/packages/remark-rehype-plugins/src/page-number.ts b/www/packages/remark-rehype-plugins/src/page-number.ts index b7b075b7b84a4..cc16a4d978af8 100644 --- a/www/packages/remark-rehype-plugins/src/page-number.ts +++ b/www/packages/remark-rehype-plugins/src/page-number.ts @@ -1,12 +1,12 @@ import path from "path" import type { Transformer } from "unified" -import type { RawSidebarItemType } from "types" +import type { RawSidebarItem } from "types" import type { UnistTree } from "./types/index.js" export function pageNumberRehypePlugin({ sidebar, }: { - sidebar: RawSidebarItemType[] + sidebar: RawSidebarItem[] }): Transformer { return async (tree, file) => { const { valueToEstree } = await import("estree-util-value-to-estree") @@ -66,11 +66,14 @@ export function pageNumberRehypePlugin({ } function findSidebarItem( - sidebar: RawSidebarItemType[], + sidebar: RawSidebarItem[], path: string -): RawSidebarItemType | undefined { +): RawSidebarItem | undefined { let foundItem = undefined for (const item of sidebar) { + if (item.type === "separator") { + continue + } if (item.type === "link" && path === item.path) { foundItem = item } else if (item.children) { diff --git a/www/packages/tailwind/base.tailwind.config.js b/www/packages/tailwind/base.tailwind.config.js index 8aec83abfa407..440392bdbb8dc 100644 --- a/www/packages/tailwind/base.tailwind.config.js +++ b/www/packages/tailwind/base.tailwind.config.js @@ -269,6 +269,10 @@ module.exports = { "code-fade-bottom-to-top-dark": `linear-gradient(180deg, rgba(47, 47, 50, 0.00) 0%, #2F2F32 100%)`, "base-code-fade-right-to-left-dark": `linear-gradient(90deg, #27272aa3, #27272A)`, "subtle-code-fade-right-to-left-dark": `linear-gradient(90deg, #30303380, #303033)`, + "border-dotted": + "linear-gradient(to right, #D4D4D8 33%, rgba(255,255,255,0) 0%)", + "border-dotted-dark": + "linear-gradient(to right, rgba(69, 69, 71) 33%, rgba(255,255,255,0) 0%)", }, screens: { xs: "568px", diff --git a/www/packages/types/src/sidebar.ts b/www/packages/types/src/sidebar.ts index fdab483b3f935..5abf989220883 100644 --- a/www/packages/types/src/sidebar.ts +++ b/www/packages/types/src/sidebar.ts @@ -32,18 +32,24 @@ export type SidebarItemSubCategory = SidebarItemCommon & { childrenSameLevel?: boolean } -export type SidebarItem = +export type SidebarItemSeparator = { + type: "separator" +} + +export type InteractiveSidebarItem = | SidebarItemLink | SidebarItemCategory | SidebarItemSubCategory +export type SidebarItem = InteractiveSidebarItem | SidebarItemSeparator + export type SidebarSectionItems = { [k in SidebarItemSections]: SidebarItem[] } & { - parentItem?: SidebarItem + parentItem?: InteractiveSidebarItem } -export type RawSidebarItemType = SidebarItem & { +export type RawSidebarItem = SidebarItem & { autogenerate_path?: string number?: string } From 76338be8600b84cacf88b89558d5dfbd752b1eb9 Mon Sep 17 00:00:00 2001 From: Shahed Nasser Date: Thu, 1 Aug 2024 19:31:45 +0300 Subject: [PATCH 06/38] general fixes --- .../Icons/NavigationDropdown/Doc/index.tsx | 6 +- .../docs-ui/src/components/Kbd/index.tsx | 4 +- .../Sidebar/Actions/ColorMode/index.tsx | 30 ++++++++ .../src/components/Sidebar/Actions/index.tsx | 21 ++++++ .../components/Sidebar/Item/Link/index.tsx | 69 ++++++++----------- .../docs-ui/src/components/Sidebar/index.tsx | 21 ++++-- www/packages/docs-ui/src/layouts/root.tsx | 6 +- www/packages/docs-ui/src/layouts/tight.tsx | 2 +- .../docs-ui/src/providers/Sidebar/index.tsx | 10 +++ .../utils/check-sidebar-item-visibility.ts | 25 ++++--- 10 files changed, 132 insertions(+), 62 deletions(-) create mode 100644 www/packages/docs-ui/src/components/Sidebar/Actions/ColorMode/index.tsx create mode 100644 www/packages/docs-ui/src/components/Sidebar/Actions/index.tsx diff --git a/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx index 0752bfd74d221..11ac92fc28646 100644 --- a/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx +++ b/www/packages/docs-ui/src/components/Icons/NavigationDropdown/Doc/index.tsx @@ -11,7 +11,11 @@ export const NavigationDropdownDocIcon = (props: IconProps) => { xmlns="http://www.w3.org/2000/svg" {...props} > - + { return ( { + const { colorMode, toggleColorMode } = useColorMode() + + return ( +
    toggleColorMode()} + > + <> + {colorMode === "light" && } + {colorMode === "dark" && } + + + {colorMode === "light" ? "Light" : "Dark"} Theme + +
    + ) +} diff --git a/www/packages/docs-ui/src/components/Sidebar/Actions/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Actions/index.tsx new file mode 100644 index 0000000000000..5e939faf763de --- /dev/null +++ b/www/packages/docs-ui/src/components/Sidebar/Actions/index.tsx @@ -0,0 +1,21 @@ +"use client" + +import clsx from "clsx" +import React from "react" +import { SidebarActionColorMode } from "./ColorMode" + +export const SidebarActions = React.forwardRef( + function SidebarActions(_props, ref) { + return ( +
    + +
    + ) + } +) diff --git a/www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx b/www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx index ac8df15eace0f..5b5661fdd0c12 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Item/Link/index.tsx @@ -2,7 +2,7 @@ // @refresh reset -import React, { useEffect, useMemo, useRef } from "react" +import React, { useCallback, useEffect, useMemo, useRef } from "react" import { SidebarItemLink as SidebarItemlinkType } from "types" import { checkSidebarItemVisibility, @@ -28,6 +28,7 @@ export const SidebarItemLink = ({ setMobileSidebarOpen: setSidebarOpen, disableActiveTransition, sidebarRef, + sidebarTopHeight, } = useSidebar() const { isMobile } = useMobile() const active = useMemo( @@ -36,61 +37,47 @@ export const SidebarItemLink = ({ ) const ref = useRef(null) - /** - * Tries to place the item in the center of the sidebar - */ - const newTopCalculator = (): number => { + const newTopCalculator = useCallback(() => { if (!sidebarRef.current || !ref.current) { return 0 } - const sidebarBoundingRect = sidebarRef.current.getBoundingClientRect() - const sidebarHalf = sidebarBoundingRect.height / 2 - const itemTop = ref.current.offsetTop - const itemBottom = - itemTop + (ref.current.children.item(0) as HTMLElement)?.clientHeight - - // try deducting half - let newTop = itemTop - sidebarHalf - let newBottom = newTop + sidebarBoundingRect.height - if (newTop <= itemTop && newBottom >= itemBottom) { - return newTop - } - // try adding half - newTop = itemTop + sidebarHalf - newBottom = newTop + sidebarBoundingRect.height - if (newTop <= itemTop && newBottom >= itemBottom) { - return newTop - } + const sidebarBoundingRect = sidebarRef.current.getBoundingClientRect() + const itemBoundingRect = ref.current.getBoundingClientRect() - //return the item's top minus some top margin - return itemTop - sidebarBoundingRect.top - } + return ( + itemBoundingRect.top - + (sidebarBoundingRect.top + sidebarTopHeight) + + sidebarRef.current.scrollTop + ) + }, [sidebarTopHeight, sidebarRef, ref]) useEffect(() => { - if ( - active && - ref.current && - sidebarRef.current && - window.innerWidth >= 1025 - ) { - if ( - !disableActiveTransition && - !checkSidebarItemVisibility( - (ref.current.children.item(0) as HTMLElement) || ref.current, - !disableActiveTransition - ) - ) { + if (active && ref.current && sidebarRef.current && !isMobile) { + const isVisible = checkSidebarItemVisibility( + (ref.current.children.item(0) as HTMLElement) || ref.current, + !disableActiveTransition + ) + if (isVisible) { + return + } + if (!disableActiveTransition) { ref.current.scrollIntoView({ block: "center", }) - } else if (disableActiveTransition) { + } else { sidebarRef.current.scrollTo({ top: newTopCalculator(), }) } } - }, [active, sidebarRef.current, disableActiveTransition]) + }, [ + active, + sidebarRef.current, + disableActiveTransition, + isMobile, + newTopCalculator, + ]) const hasChildren = useMemo(() => { return !item.isChildSidebar && (item.children?.length || 0) > 0 diff --git a/www/packages/docs-ui/src/components/Sidebar/index.tsx b/www/packages/docs-ui/src/components/Sidebar/index.tsx index fa89187196969..99a4ee3813d36 100644 --- a/www/packages/docs-ui/src/components/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/index.tsx @@ -10,6 +10,7 @@ import { SidebarTop, SidebarTopProps } from "./Top" import useResizeObserver from "@react-hook/resize-observer" import { useClickOutside } from "../.." import { SidebarSeparator } from "./Separator" +import { SidebarActions } from "./Actions" export type SidebarProps = { className?: string @@ -23,7 +24,7 @@ export const Sidebar = ({ sidebarTopProps, }: SidebarProps) => { const sidebarTopRef = useRef(null) - const [sidebarTopHeight, setSidebarHeight] = useState(0) + const sidebarActionsRef = useRef(null) const { items, currentItems, @@ -32,6 +33,10 @@ export const Sidebar = ({ desktopSidebarOpen, staticSidebarItems, sidebarRef, + sidebarTopHeight, + setSidebarTopHeight, + sidebarActionsHeight, + setSidebarActionsHeight, } = useSidebar() useClickOutside({ elmRef: sidebarRef, @@ -48,7 +53,11 @@ export const Sidebar = ({ ) useResizeObserver(sidebarTopRef, () => { - setSidebarHeight(sidebarTopRef.current?.clientHeight || 0) + setSidebarTopHeight(sidebarTopRef.current?.clientHeight || 0) + }) + + useResizeObserver(sidebarActionsRef, () => { + setSidebarActionsHeight(sidebarActionsRef.current?.clientHeight || 0) }) return ( @@ -79,7 +88,7 @@ export const Sidebar = ({ animationFillMode: "forwards", }} > -