Skip to content

Commit

Permalink
feat: add sidebar auto-collapse menus (#1832)
Browse files Browse the repository at this point in the history
Co-authored-by: Dimitri POSTOLOV <en3m@ya.ru>
Co-authored-by: Dimitri POSTOLOV <dmytropostolov@gmail.com>
  • Loading branch information
3 people authored Jun 19, 2023
1 parent bef7324 commit b43f268
Show file tree
Hide file tree
Showing 8 changed files with 52 additions and 17 deletions.
6 changes: 6 additions & 0 deletions .changeset/two-bugs-destroy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
'nextra-theme-docs': minor
---

add new option `sidebar.autoCollapse` to automatically collapse inactive folders
above `defaultMenuCollapseLevel`
10 changes: 10 additions & 0 deletions docs/pages/docs/docs-theme/theme-configuration.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,11 @@ Customize the entire navbar component.
'number',
'Specifies the folder level at which the menu on the left is collapsed by default. Defaults to 2.'
],
[
'sidebar.autoCollapse',
'boolean',
'If true, automatically collapse inactive folders above defaultMenuCollapseLevel.'
],
[
'sidebar.titleComponent',
`React.ReactNode | React.FC<{
Expand All @@ -468,6 +473,11 @@ setting `sidebar.defaultMenuCollapseLevel` to a different number. For example,
when set to `1`, every folder will be collapsed by default and when set to
`Infinity`, all nested folders will be expanded by default.

If `sidebar.autoCollapse` is set to `true`, then all folders that do not contain
an active/focused route will automatically collapse up to the level set by
`sidebar.defaultMenuCollapseLevel`. e.g. if `defaultMenuCollapseLevel` is `2`,
then top-level folders will not auto-collapse.

### Customize sidebar content

Together with the [Separators](/docs/docs-theme/page-configuration#separators)
Expand Down
4 changes: 2 additions & 2 deletions docs/pages/docs/guide/advanced/table.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ you'll get the following result:
</tbody>
</table>

<Callout emoji="⚠️" type="warning">
<Callout type="warning">
Confused by unstyled elements? We explained [here](#why-this-happens), why
this happens.
</Callout>
Expand Down Expand Up @@ -129,7 +129,7 @@ will be rendered as:
</tbody>
</table>

<Callout emoji="⚠️" type="warning">
<Callout type="warning">
Confused by unstyled elements? We explain below 👇, why it's happens.
</Callout>

Expand Down
9 changes: 5 additions & 4 deletions examples/swr-site/pages/docs/advanced/cache.en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ import { Callout } from 'nextra/components'

<Callout>Upgrade to the latest version (≥ 1.0.0) to use this feature.</Callout>

<Callout emoji="⚠️">
<Callout type="warning">
In most cases, you shouldn't directly _write_ to the cache, which might cause
undefined behaviors of SWR. If you need to manually mutate a key, please
consider using the SWR APIs.
<br />
See also: [Mutation](/docs/mutation), [Reset Cache Between Test
Cases](#reset-cache-between-test-cases).

See also: [Mutation](/docs/mutation),
[Reset Cache Between Test Cases](#reset-cache-between-test-cases).

</Callout>

By default, SWR uses a global cache to store and share data across all
Expand Down
5 changes: 3 additions & 2 deletions examples/swr-site/pages/index.en-US.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,9 @@ and finally come with the up-to-date data.
<Callout emoji="">
With SWR, components will get a stream of data updates **constantly** and
**automatically**.
<br />
And the UI will be always **fast** and **reactive**.

And the UI will be always **fast** and **reactive**.

</Callout>

<div className="mb-20 mt-16 text-center">
Expand Down
1 change: 1 addition & 0 deletions examples/swr-site/theme.config.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ const config: DocsThemeConfig = {
link: 'https://github.com/vercel/swr'
},
sidebar: {
autoCollapse: true,
defaultMenuCollapseLevel: 1,
titleComponent: ({ title, type }) =>
type === 'separator' ? (
Expand Down
33 changes: 24 additions & 9 deletions packages/nextra-theme-docs/src/components/sidebar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,9 @@ import { LocaleSwitch } from './locale-switch'
const TreeState: Record<string, boolean> = Object.create(null)

const FocusedItemContext = createContext<null | string>(null)
const OnFocuseItemContext = createContext<
null | ((item: string | null) => any)
>(null)
const OnFocusItemContext = createContext<null | ((item: string | null) => any)>(
null
)
const FolderLevelContext = createContext(0)

const Folder = memo(function FolderInner(props: FolderProps) {
Expand Down Expand Up @@ -92,10 +92,25 @@ function FolderImpl({ item, anchors }: FolderProps): ReactElement {
const rerender = useState({})[1]

useEffect(() => {
if (activeRouteInside || focusedRouteInside) {
TreeState[item.route] = true
const updateTreeState = () => {
if (activeRouteInside || focusedRouteInside) {
TreeState[item.route] = true
}
}
const updateAndPruneTreeState = () => {
if (activeRouteInside && focusedRouteInside) {
TreeState[item.route] = true
} else {
delete TreeState[item.route]
}
}
}, [activeRouteInside, focusedRouteInside, item.route])
config.sidebar.autoCollapse ? updateAndPruneTreeState() : updateTreeState()
}, [
activeRouteInside,
focusedRouteInside,
item.route,
config.sidebar.autoCollapse
])

if (item.type === 'menu') {
const menu = item as MenuItem
Expand Down Expand Up @@ -211,7 +226,7 @@ function File({
anchors: Heading[]
}): ReactElement {
const route = useFSRoute()
const onFocus = useContext(OnFocuseItemContext)
const onFocus = useContext(OnFocusItemContext)

// It is possible that the item doesn't have any route - for example an external link.
const active = item.route && [route, route + '/'].includes(item.route + '/')
Expand Down Expand Up @@ -408,7 +423,7 @@ export function Sidebar({
})}
</div>
<FocusedItemContext.Provider value={focused}>
<OnFocuseItemContext.Provider
<OnFocusItemContext.Provider
value={item => {
setFocused(item)
}}
Expand Down Expand Up @@ -443,7 +458,7 @@ export function Sidebar({
anchors={anchors}
/>
</div>
</OnFocuseItemContext.Provider>
</OnFocusItemContext.Provider>
</FocusedItemContext.Provider>

{hasMenu && (
Expand Down
1 change: 1 addition & 0 deletions packages/nextra-theme-docs/src/constants.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,7 @@ export const themeSchema = z.strictObject({
labels: z.string()
}),
sidebar: z.strictObject({
autoCollapse: z.boolean().optional(),
defaultMenuCollapseLevel: z.number().min(1).int(),
titleComponent: z.custom<
ReactNode | FC<{ title: string; type: string; route: string }>
Expand Down

1 comment on commit b43f268

@vercel
Copy link

@vercel vercel bot commented on b43f268 Jun 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.