docs: collapse sidebar by default in main docs + persist state (#8608)
* docs: collapse sidebar by default in main docs + persist state * persist sidebar hidden
This commit is contained in:
@@ -33,6 +33,8 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||
scrollableElement={scrollableElement}
|
||||
initialItems={config.sidebar}
|
||||
resetOnCondition={resetOnCondition}
|
||||
persistState={false}
|
||||
projectName="api"
|
||||
>
|
||||
{children}
|
||||
</UiSidebarProvider>
|
||||
|
||||
@@ -21,6 +21,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||
initialItems={config.sidebar}
|
||||
staticSidebarItems={true}
|
||||
disableActiveTransition={true}
|
||||
projectName="docs"
|
||||
>
|
||||
{children}
|
||||
</UiSidebarProvider>
|
||||
|
||||
@@ -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])
|
||||
|
||||
@@ -20,6 +20,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||
initialItems={config.sidebar}
|
||||
staticSidebarItems={true}
|
||||
disableActiveTransition={true}
|
||||
projectName="resources"
|
||||
>
|
||||
{children}
|
||||
</UiSidebarProvider>
|
||||
|
||||
@@ -17,6 +17,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||
shouldHandlePathChange={true}
|
||||
scrollableElement={scrollableElement}
|
||||
disableActiveTransition={true}
|
||||
projectName="ui"
|
||||
>
|
||||
{children}
|
||||
</UiSidebarProvider>
|
||||
|
||||
@@ -20,6 +20,7 @@ const SidebarProvider = ({ children }: SidebarProviderProps) => {
|
||||
initialItems={config.sidebar}
|
||||
staticSidebarItems={true}
|
||||
disableActiveTransition={true}
|
||||
projectName="user-guide"
|
||||
>
|
||||
{children}
|
||||
</UiSidebarProvider>
|
||||
|
||||
@@ -23,7 +23,12 @@ export const SidebarItemCategory = ({
|
||||
item.initialOpen !== undefined ? item.initialOpen : expandItems
|
||||
)
|
||||
const childrenRef = useRef<HTMLUListElement>(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)
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -56,6 +56,9 @@ export type SidebarContextType = {
|
||||
setSidebarTopHeight: React.Dispatch<React.SetStateAction<number>>
|
||||
resetItems: () => void
|
||||
isItemLoaded: (path: string) => boolean
|
||||
updatePersistedCategoryState: (title: string, opened: boolean) => void
|
||||
getPersistedCategoryState: (title: string) => boolean | undefined
|
||||
persistState: boolean
|
||||
} & SidebarStyleOptions
|
||||
|
||||
export const SidebarContext = createContext<SidebarContextType | null>(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 (
|
||||
<SidebarContext.Provider
|
||||
value={{
|
||||
@@ -487,6 +546,9 @@ export const SidebarProvider = ({
|
||||
setSidebarTopHeight,
|
||||
resetItems,
|
||||
isItemLoaded,
|
||||
updatePersistedCategoryState,
|
||||
getPersistedCategoryState,
|
||||
persistState,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -54,3 +54,9 @@ export type RawSidebarItem = SidebarItem & {
|
||||
custom_autogenerate?: string
|
||||
number?: string
|
||||
}
|
||||
|
||||
export type PersistedSidebarCategoryState = {
|
||||
[k: string]: {
|
||||
[k: string]: boolean
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user