mirror of
https://github.com/supabase/supabase.git
synced 2026-10-09 19:35:06 +03:00
## What kind of change does this PR introduce? follow-up to #50235 to reduce reference page payloads and cold rendering overhead ## What is the current behavior? reference pages ship a large rsc payload inside the html _ most of it is duplication rather than content along with shiki that writes ~30 character css variable name for every syntax token making the page heavy in some cases ## What is the new behavior? - moves repeated styles into shared css and uses compact, namespaced token classes - renders details icons inside the client trigger - follows shiki’s guidance to [reuse one highlighter](https://shiki.style/guide/best-performance#cache-the-highlighter-instance) and [load languages on demand](https://shiki.style/guide/best-performance#use-shorthands) `page size` page | before | after | change -- | -- | -- | -- javascript | 10.61 mb | 8.28 mb | -21.9% dart | 4.59 mb | 4.13 mb | -10.1% python | 4.38 mb | 3.73 mb | -14.9% swift | 2.87 mb | 2.56 mb | -10.9% server | 1.59 mb | 1.35 mb | -15.2% kotlin | 3.42 mb | 3.17 mb | -7.2% `cold initialization` language | before | after | reduction -- | -- | -- | -- bash | 2,180 ms | 23 ms | 98.95% javascript | 2,245 ms | 38 ms | 98.29% ## Additional context measured on a local production build which uses the checked in generated content _ production has larger sdk data, so absolute sizes there will be higher <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added reusable expand/collapse controls for API reference details, with updated icons, labels, and styling. * Improved code block rendering with class-based syntax highlighting, wrapped-code support, responsive layouts, and lazy language loading. * **Style** * Added theme-aware syntax-token colors, line-number styling, and configurable code-block shadows. * Consolidated expandable reference panel and item styling. * **Tests** * Added coverage for syntax highlighting, code block rendering, language support, token stability, and reference details. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
128 lines
3.8 KiB
TypeScript
128 lines
3.8 KiB
TypeScript
'use client'
|
|
|
|
import { ReferenceContentInitiallyScrolledContext } from '~/features/docs/Reference.navigation.client'
|
|
import { safeHistoryReplaceState } from '~/lib/historyUtils'
|
|
import { XCircle } from 'lucide-react'
|
|
import type { HTMLAttributes, PropsWithChildren } from 'react'
|
|
import { useContext, useEffect, useRef, useState } from 'react'
|
|
import { useInView } from 'react-intersection-observer'
|
|
import {
|
|
cn,
|
|
CollapsibleTrigger,
|
|
Select,
|
|
SelectContent,
|
|
SelectGroup,
|
|
SelectItem,
|
|
SelectTrigger,
|
|
SelectValue,
|
|
} from 'ui'
|
|
|
|
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 */
|
|
) {
|
|
safeHistoryReplaceState(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(() => {
|
|
const elements = containerRef.current?.querySelectorAll(
|
|
`[${API_REFERENCE_REQUEST_BODY_SCHEMA_DATA_ATTRIBUTES.KEY}]`
|
|
)
|
|
allSchemeDetails.current = elements ? (Array.from(elements) as HTMLUListElement[]) : []
|
|
}, [])
|
|
|
|
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
|
|
value={selectedScheme}
|
|
onValueChange={(value) =>
|
|
setSelectedScheme(value as 'application/json' | 'application/x-www-form-urlencoded')
|
|
}
|
|
>
|
|
<SelectTrigger className="w-48 [&>span]:w-full [&>span]:truncate">
|
|
<SelectValue />
|
|
</SelectTrigger>
|
|
<SelectContent>
|
|
<SelectGroup>
|
|
{availableSchemes.map((scheme) => (
|
|
<SelectItem key={scheme} value={scheme}>
|
|
{scheme}
|
|
</SelectItem>
|
|
))}
|
|
</SelectGroup>
|
|
</SelectContent>
|
|
</Select>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export function DetailsTrigger({ label, className }: { label: string; className?: string }) {
|
|
return (
|
|
<CollapsibleTrigger className={cn('group reference-details-trigger', className)}>
|
|
<XCircle size={14} aria-hidden="true" className="reference-details-trigger-icon" />
|
|
{label}
|
|
</CollapsibleTrigger>
|
|
)
|
|
}
|