Skip to content

Commit

Permalink
feat: optionally allow the primary sections of the project sidebar be…
Browse files Browse the repository at this point in the history
… collapsible (#258)

* chore: cleanup imports

* feat: docs config schema to accept a `collapsible` boolean

* chore: tweak the zod schema and MenuItem type

* feat: add the collapsible menu

* refactor: correct semantic tags for the list of links

* feat: make the details collapsible by default
  • Loading branch information
SeanCassiere authored Aug 17, 2024
1 parent 19b8ce3 commit e14f12e
Show file tree
Hide file tree
Showing 3 changed files with 42 additions and 15 deletions.
43 changes: 28 additions & 15 deletions app/components/DocsLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,9 @@ import {
useMatches,
useNavigate,
useParams,
useRouterState,
} from '@tanstack/react-router'
import type { AnyOrama, SearchParamsFullText, AnyDocument } from '@orama/orama'
import { SearchBox, SearchButton } from '@orama/searchbox'
import { SearchBox } from '@orama/searchbox'
import { Carbon } from '~/components/Carbon'
import { Select } from '~/components/Select'
import { useLocalStorage } from '~/utils/useLocalStorage'
Expand All @@ -25,7 +24,7 @@ import type { SelectOption } from '~/components/Select'
import type { ConfigSchema, MenuItem } from '~/utils/config'
import { create } from 'zustand'
import { searchBoxParams, searchButtonParams } from '~/components/Orama'
import { Framework, getFrameworkOptions, getLibrary } from '~/libraries'
import { Framework, getFrameworkOptions } from '~/libraries'
import { DocsCalloutQueryGG } from '~/components/DocsCalloutQueryGG'
import { DocsCalloutBytes } from '~/components/DocsCalloutBytes'
import { ClientOnlySearchButton } from './ClientOnlySearchButton'
Expand Down Expand Up @@ -179,7 +178,7 @@ const useMenuConfig = ({
config: ConfigSchema
repo: string
frameworks: Framework[]
}) => {
}): MenuItem[] => {
const currentFramework = useCurrentFramework(frameworks)

const localMenu: MenuItem = {
Expand Down Expand Up @@ -211,7 +210,7 @@ const useMenuConfig = ({
return [
localMenu,
// Merge the two menus together based on their group labels
...config.sections.map((section) => {
...config.sections.map((section): MenuItem | undefined => {
const frameworkDocs = section.frameworks?.find(
(f) => f.label === currentFramework.framework
)
Expand All @@ -232,9 +231,11 @@ const useMenuConfig = ({
return {
label: section.label,
children,
collapsible: section.collapsible ?? false,
defaultCollapsed: section.defaultCollapsed ?? false,
}
}),
].filter(Boolean)
].filter((item) => item !== undefined)
}

const useFrameworkConfig = ({ frameworks }: { frameworks: Framework[] }) => {
Expand Down Expand Up @@ -317,8 +318,7 @@ export function DocsLayout({
children,
}: DocsLayoutProps) {
const { libraryId } = useParams({
strict: false,
experimental_returnIntersection: true,
from: '/$libraryId/$version/docs',
})
const frameworkConfig = useFrameworkConfig({ frameworks })
const versionConfig = useVersionConfig({ versions })
Expand Down Expand Up @@ -350,16 +350,29 @@ export function DocsLayout({
const [showBytes, setShowBytes] = useLocalStorage('showBytes', true)

const menuItems = menuConfig.map((group, i) => {
const WrapperComp = group.collapsible ? 'details' : 'div'
const LabelComp = group.collapsible ? 'summary' : 'div'

const isCollapsed = group.defaultCollapsed ?? false

const detailsProps = group.collapsible ? { open: !isCollapsed } : {}

return (
<div key={i}>
<div className="text-[.8em] uppercase font-black">{group?.label}</div>
<WrapperComp
key={`group-${i}`}
className="[&>summary]:before:mr-[0.4rem] [&>summary]:marker:text-[0.8em] [&>summary]:marker:-ml-[0.3rem] [&>summary]:marker:leading-4 [&>div.ts-sidebar-label]:ml-[1rem] relative select-none"
{...detailsProps}
>
<LabelComp className="text-[.8em] uppercase font-black leading-4 ts-sidebar-label">
{group?.label}
</LabelComp>
<div className="h-2" />
<div className="ml-2 text-[.85em]">
<ul className="ml-2 text-[.85em] list-none">
{group?.children?.map((child, i) => {
const linkClasses = `cursor-pointer flex gap-2 items-center justify-between group px-2 py-[.1rem] rounded-lg hover:bg-gray-500 hover:bg-opacity-10`

return (
<React.Fragment key={i}>
<li key={i}>
{child.to.startsWith('http') ? (
<a href={child.to} className={linkClasses}>
{child.label}
Expand Down Expand Up @@ -423,11 +436,11 @@ export function DocsLayout({
}}
</Link>
)}
</React.Fragment>
</li>
)
})}
</div>
</div>
</ul>
</WrapperComp>
)
})

Expand Down
4 changes: 4 additions & 0 deletions app/utils/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ export type MenuItem = {
to: string
badge?: string
}[]
collapsible?: boolean
defaultCollapsed?: boolean
}

const configSchema = z.object({
Expand Down Expand Up @@ -36,6 +38,8 @@ const configSchema = z.object({
})
)
.optional(),
collapsible: z.boolean().optional(),
defaultCollapsed: z.boolean().optional(),
})
),
users: z.array(z.string()).optional(),
Expand Down
10 changes: 10 additions & 0 deletions tanstack-docs-config.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,16 @@
"required": ["label", "children"],
"additionalProperties": false
}
},
"collapsible": {
"type": "boolean",
"default": false,
"description": "Whether the section should be collapsible."
},
"defaultCollapsed": {
"type": "boolean",
"default": false,
"description": "Whether the section should be collapsed by default."
}
}
}
Expand Down

0 comments on commit e14f12e

Please sign in to comment.