diff --git a/www/apps/api-reference/providers/sidebar.tsx b/www/apps/api-reference/providers/sidebar.tsx index 3e550ff8227c4..9df31784dc376 100644 --- a/www/apps/api-reference/providers/sidebar.tsx +++ b/www/apps/api-reference/providers/sidebar.tsx @@ -33,6 +33,8 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => { scrollableElement={scrollableElement} initialItems={config.sidebar} resetOnCondition={resetOnCondition} + persistState={false} + projectName="api" > {children} diff --git a/www/apps/book/providers/sidebar.tsx b/www/apps/book/providers/sidebar.tsx index c98ba6cb5f686..3393d7b349726 100644 --- a/www/apps/book/providers/sidebar.tsx +++ b/www/apps/book/providers/sidebar.tsx @@ -21,6 +21,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => { initialItems={config.sidebar} staticSidebarItems={true} disableActiveTransition={true} + projectName="docs" > {children} diff --git a/www/apps/book/utils/number-sidebar-items.mjs b/www/apps/book/utils/number-sidebar-items.mjs index 9bb1a3d35ef0b..b1ab601748190 100644 --- a/www/apps/book/utils/number-sidebar-items.mjs +++ b/www/apps/book/utils/number-sidebar-items.mjs @@ -14,24 +14,27 @@ export default function numberSidebarItems(sidebarItems, numbering = [1]) { const numberedItems = [] /** @type {import("@/types").SidebarItem | undefined} */ let parentItem - sidebarItems.forEach((item) => { + sidebarItems.forEach((item, index) => { if (item.type === "separator") { ;(parentItem?.children || numberedItems).push(item) } + + // append current number to the item's title + item.number = `${numbering.join(".")}.` + item.title = `${item.number} ${item.title.trim()}` + if (isTopItems) { // Add chapter category numberedItems.push({ type: "category", - title: `Chapter ${padNumber(numbering[0])}`, + title: item.title, children: [], loaded: true, + initialOpen: false, }) parentItem = numberedItems[numberedItems.length - 1] } - // append current number to the item's title - item.number = `${numbering.join(".")}.` - item.title = `${item.number} ${item.title.trim()}` if (item.children) { item.children = numberSidebarItems(item.children, [...numbering, 1]) diff --git a/www/apps/resources/providers/sidebar.tsx b/www/apps/resources/providers/sidebar.tsx index 4562e1fc8c6de..c70f148845f6d 100644 --- a/www/apps/resources/providers/sidebar.tsx +++ b/www/apps/resources/providers/sidebar.tsx @@ -20,6 +20,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => { initialItems={config.sidebar} staticSidebarItems={true} disableActiveTransition={true} + projectName="resources" > {children} diff --git a/www/apps/ui/src/providers/sidebar.tsx b/www/apps/ui/src/providers/sidebar.tsx index fa9a051ad94e0..8aec55686af98 100644 --- a/www/apps/ui/src/providers/sidebar.tsx +++ b/www/apps/ui/src/providers/sidebar.tsx @@ -17,6 +17,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => { shouldHandlePathChange={true} scrollableElement={scrollableElement} disableActiveTransition={true} + projectName="ui" > {children} diff --git a/www/apps/user-guide/providers/sidebar.tsx b/www/apps/user-guide/providers/sidebar.tsx index 4562e1fc8c6de..e170238727933 100644 --- a/www/apps/user-guide/providers/sidebar.tsx +++ b/www/apps/user-guide/providers/sidebar.tsx @@ -20,6 +20,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => { initialItems={config.sidebar} staticSidebarItems={true} disableActiveTransition={true} + projectName="user-guide" > {children} 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 index 9538c91214051..bcf2d1939dcb4 100644 --- a/www/packages/docs-ui/src/components/Sidebar/Item/Category/index.tsx +++ b/www/packages/docs-ui/src/components/Sidebar/Item/Category/index.tsx @@ -23,7 +23,12 @@ export const SidebarItemCategory = ({ item.initialOpen !== undefined ? item.initialOpen : expandItems ) const childrenRef = useRef(null) - const { isChildrenActive } = useSidebar() + const { + isChildrenActive, + updatePersistedCategoryState, + getPersistedCategoryState, + persistState, + } = useSidebar() useEffect(() => { if (open && !item.loaded) { @@ -44,6 +49,16 @@ export const SidebarItemCategory = ({ } }, [isChildrenActive]) + useEffect(() => { + if (!persistState) { + return + } + const persistedOpen = getPersistedCategoryState(item.title) + if (persistedOpen !== undefined) { + setOpen(persistedOpen) + } + }, [persistState]) + const handleOpen = () => { item.onOpen?.() } @@ -70,6 +85,9 @@ export const SidebarItemCategory = ({ if (!open) { handleOpen() } + if (persistState) { + updatePersistedCategoryState(item.title, !open) + } setOpen((prev) => !prev) }} > diff --git a/www/packages/docs-ui/src/providers/Sidebar/index.tsx b/www/packages/docs-ui/src/providers/Sidebar/index.tsx index bdc97ebe80026..4c36294748660 100644 --- a/www/packages/docs-ui/src/providers/Sidebar/index.tsx +++ b/www/packages/docs-ui/src/providers/Sidebar/index.tsx @@ -56,6 +56,9 @@ export type SidebarContextType = { setSidebarTopHeight: React.Dispatch> resetItems: () => void isItemLoaded: (path: string) => boolean + updatePersistedCategoryState: (title: string, opened: boolean) => void + getPersistedCategoryState: (title: string) => boolean | undefined + persistState: boolean } & SidebarStyleOptions export const SidebarContext = createContext(null) @@ -191,6 +194,8 @@ export type SidebarProviderProps = { scrollableElement?: Element | Window staticSidebarItems?: boolean resetOnCondition?: () => boolean + projectName: string + persistState?: boolean } & SidebarStyleOptions export const SidebarProvider = ({ @@ -204,7 +209,11 @@ export const SidebarProvider = ({ staticSidebarItems = false, disableActiveTransition = false, resetOnCondition, + projectName, + persistState = true, }: SidebarProviderProps) => { + const categoriesStorageKey = `${projectName}_categories` + const hideSidebarStorageKey = `hide_sidebar` const [items, dispatch] = useReducer(reducer, { default: initialItems?.default || [], mobile: initialItems?.mobile || [], @@ -462,6 +471,56 @@ export const SidebarProvider = ({ } }, [resetOnCondition, resetItems]) + useEffect(() => { + if (!isBrowser) { + return + } + + const storageValue = localStorage.getItem(hideSidebarStorageKey) + + if (storageValue !== null) { + setDesktopSidebarOpen(storageValue === "false") + } + }, [isBrowser]) + + useEffect(() => { + if (!isBrowser) { + return + } + + localStorage.setItem( + hideSidebarStorageKey, + `${desktopSidebarOpen === false}` + ) + }, [isBrowser, desktopSidebarOpen]) + + const updatePersistedCategoryState = (title: string, opened: boolean) => { + const storageData = JSON.parse( + localStorage.getItem(categoriesStorageKey) || "{}" + ) + if (!Object.hasOwn(storageData, projectName)) { + storageData[projectName] = {} + } + + storageData[projectName] = { + ...storageData[projectName], + [title]: opened, + } + + localStorage.setItem(categoriesStorageKey, JSON.stringify(storageData)) + } + + const getPersistedCategoryState = (title: string): boolean | undefined => { + const storageData = JSON.parse( + localStorage.getItem(categoriesStorageKey) || "{}" + ) + + return !Object.hasOwn(storageData, projectName) || + !Object.hasOwn(storageData[projectName], title) + ? undefined + : storageData[projectName][title] + } + return ( {children} diff --git a/www/packages/types/src/sidebar.ts b/www/packages/types/src/sidebar.ts index 16138c4ca5e8a..b6fdbe4e88fd6 100644 --- a/www/packages/types/src/sidebar.ts +++ b/www/packages/types/src/sidebar.ts @@ -54,3 +54,9 @@ export type RawSidebarItem = SidebarItem & { custom_autogenerate?: string number?: string } + +export type PersistedSidebarCategoryState = { + [k: string]: { + [k: string]: boolean + } +}