Files
supabase/apps/docs/features/docs/Reference.ui.client.tsx
T
Charis 33ede6f893 refactor(docs): convert management api reference to app router (#29146)
* chore(docs): preprocess management api specs

In preparation for App Router migration of Management API reference,
preprocess the Management API spec (both OpenAPI spec and common
sections), and write the processed data to file, in the style of the
other pregenerated reference data.

Details:

- Split reference section generation into separate functions for SDK, CLI, and API
- Add new function to generate API reference sections from OpenAPI spec
- Introduce mapEndpointsById function to create a map of API endpoints
- Update run function to execute all reference generation tasks in parallel
- Import necessary new dependencies and types

* refactor(docs): migrate management api reference to app router

* fix(docs): statically build management api reference page

* fix(docs): minor styling issues
2024-09-11 13:53:45 -04:00

118 lines
3.5 KiB
TypeScript

'use client'
import type { HTMLAttributes, PropsWithChildren } from 'react'
import { useContext, useEffect, useRef, useState } from 'react'
import { useInView } from 'react-intersection-observer'
import {
cn,
Select_Shadcn_,
SelectContent_Shadcn_,
SelectGroup_Shadcn_,
SelectItem_Shadcn_,
SelectTrigger_Shadcn_,
SelectValue_Shadcn_,
} from 'ui'
import { ReferenceContentInitiallyScrolledContext } from '~/features/docs/Reference.navigation.client'
import { type IApiEndPoint } from './Reference.api.utils'
import { API_REFERENCE_REQUEST_BODY_SCHEMA_DATA_ATTRIBUTES } from './Reference.ui.shared'
/**
* Wrap a reference section with client-side functionality:
*
* - Intersection observer to auto-update the URL when the user scrolls the page
* - An ID to scroll to programmatically. This is on the entire section rather
* than the heading to avoid problems with scroll-to position when the heading
* is sticky.
*/
export function ReferenceSectionWrapper({
id,
link,
children,
className,
}: PropsWithChildren<{ id: string; link: string; className?: string }> &
HTMLAttributes<HTMLElement>) {
const initialScrollHappened = useContext(ReferenceContentInitiallyScrolledContext)
const { ref } = useInView({
threshold: 0,
rootMargin: '-10% 0% -50% 0%',
onChange: (inView) => {
if (
inView &&
initialScrollHappened &&
window.scrollY > 0 /* Don't update on first navigation to introduction */
) {
window.history.replaceState(null, '', link)
}
},
})
return (
<section
ref={ref}
id={id}
className={cn('scroll-mt-[calc(var(--header-height)+4rem)]', className)}
>
{children}
</section>
)
}
export function ApiOperationBodySchemeSelector({
requestBody,
className,
}: {
requestBody: IApiEndPoint['requestBody']
className?: string
}) {
const availableSchemes = Object.keys(requestBody.content) as Array<
'application/json' | 'application/x-www-form-urlencoded'
>
const [selectedScheme, setSelectedScheme] = useState(availableSchemes[0])
const containerRef = useRef<HTMLDivElement>(null)
const allSchemeDetails = useRef<HTMLUListElement[]>([])
useEffect(() => {
allSchemeDetails.current = Array.from(
containerRef.current?.querySelectorAll(
`[${API_REFERENCE_REQUEST_BODY_SCHEMA_DATA_ATTRIBUTES.KEY}]`
)
)
}, [])
useEffect(() => {
allSchemeDetails.current?.forEach((schemeDetails) => {
schemeDetails.hidden =
schemeDetails.getAttribute(API_REFERENCE_REQUEST_BODY_SCHEMA_DATA_ATTRIBUTES.KEY) !==
selectedScheme
})
}, [selectedScheme])
return (
<div ref={containerRef} className={cn('flex items-center justify-between gap-2', className)}>
<h3 className="text-base text-foreground">Body</h3>
<Select_Shadcn_
value={selectedScheme}
onValueChange={(value) =>
setSelectedScheme(value as 'application/json' | 'application/x-www-form-urlencoded')
}
>
<SelectTrigger_Shadcn_ className="w-48 [&>span]:w-full [&>span]:truncate">
<SelectValue_Shadcn_ />
</SelectTrigger_Shadcn_>
<SelectContent_Shadcn_>
<SelectGroup_Shadcn_>
{availableSchemes.map((scheme) => (
<SelectItem_Shadcn_ key={scheme} value={scheme}>
{scheme}
</SelectItem_Shadcn_>
))}
</SelectGroup_Shadcn_>
</SelectContent_Shadcn_>
</Select_Shadcn_>
</div>
)
}