mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 17:35:10 +03:00
fix: move reference pages to hash navigation and apply redirect rules (#46501)
This commit is contained in:
1 parent
3260660daa
commit
92dfbac899
9 files changed
+54
-40
No files matched your search
@@ -9,7 +9,7 @@ import { SidebarSkeleton } from '~/layouts/MainSkeleton'
|
||||
|
||||
export async function ApiReferencePage() {
|
||||
return (
|
||||
<ReferenceContentScrollHandler libPath="api" version="latest" isLatestVersion={true}>
|
||||
<ReferenceContentScrollHandler>
|
||||
<SidebarSkeleton
|
||||
menuId={MenuId.RefApi}
|
||||
NavigationMenu={
|
||||
|
||||
@@ -9,7 +9,7 @@ import { SidebarSkeleton } from '~/layouts/MainSkeleton'
|
||||
|
||||
export async function CliReferencePage() {
|
||||
return (
|
||||
<ReferenceContentScrollHandler libPath="cli" version="latest" isLatestVersion={true}>
|
||||
<ReferenceContentScrollHandler>
|
||||
<SidebarSkeleton
|
||||
menuId={MenuId.RefCli}
|
||||
NavigationMenu={
|
||||
|
||||
@@ -42,7 +42,7 @@ export async function ClientLibIntroduction({
|
||||
return (
|
||||
<ReferenceSectionWrapper
|
||||
id="introduction"
|
||||
link={`/docs/reference/${libPath}/${isLatestVersion ? '' : `${version}/`}introduction`}
|
||||
link={`/docs/reference/${libPath}${isLatestVersion ? '' : `/${version}`}#introduction`}
|
||||
className={cn('prose', className)}
|
||||
>
|
||||
<MDXRemoteRefs source={content} />
|
||||
|
||||
@@ -6,7 +6,6 @@ import { BASE_PATH } from '~/lib/constants'
|
||||
import { debounce } from 'lodash-es'
|
||||
import { ChevronUp } from 'lucide-react'
|
||||
import Link from 'next/link'
|
||||
import { usePathname } from 'next/navigation'
|
||||
import { Collapsible } from 'radix-ui'
|
||||
import type { HTMLAttributes, MouseEvent, PropsWithChildren } from 'react'
|
||||
import {
|
||||
@@ -37,6 +36,7 @@ function subscribeToPathname(callback: () => void) {
|
||||
|
||||
if (patchCount === 0) {
|
||||
window.addEventListener('popstate', notifyPathnameListeners)
|
||||
window.addEventListener('hashchange', notifyPathnameListeners)
|
||||
|
||||
originalPushState = history.pushState.bind(history)
|
||||
history.pushState = (...args) => {
|
||||
@@ -58,6 +58,7 @@ function subscribeToPathname(callback: () => void) {
|
||||
|
||||
if (patchCount === 0) {
|
||||
window.removeEventListener('popstate', notifyPathnameListeners)
|
||||
window.removeEventListener('hashchange', notifyPathnameListeners)
|
||||
history.pushState = originalPushState!
|
||||
history.replaceState = originalReplaceState!
|
||||
originalPushState = null
|
||||
@@ -66,40 +67,29 @@ function subscribeToPathname(callback: () => void) {
|
||||
}
|
||||
}
|
||||
|
||||
function getPathname() {
|
||||
function getLocation() {
|
||||
if (typeof window === 'undefined') return ''
|
||||
const pathname = window.location.pathname
|
||||
return pathname.startsWith(BASE_PATH) ? pathname.slice(BASE_PATH.length) : pathname
|
||||
const strippedPathname = pathname.startsWith(BASE_PATH)
|
||||
? pathname.slice(BASE_PATH.length)
|
||||
: pathname
|
||||
return `${strippedPathname}${window.location.hash}`
|
||||
}
|
||||
|
||||
function getServerPathname() {
|
||||
function getServerLocation() {
|
||||
return ''
|
||||
}
|
||||
|
||||
function useCurrentPathname() {
|
||||
return useSyncExternalStore(subscribeToPathname, getPathname, getServerPathname)
|
||||
function useCurrentLocation() {
|
||||
return useSyncExternalStore(subscribeToPathname, getLocation, getServerLocation)
|
||||
}
|
||||
|
||||
export function ReferenceContentScrollHandler({
|
||||
libPath,
|
||||
version,
|
||||
isLatestVersion,
|
||||
children,
|
||||
}: PropsWithChildren<{
|
||||
libPath: string
|
||||
version: string
|
||||
isLatestVersion: boolean
|
||||
}>) {
|
||||
export function ReferenceContentScrollHandler({ children }: PropsWithChildren) {
|
||||
const [initiallyScrolled, setInitiallyScrolled] = useState(false)
|
||||
|
||||
const pathname = usePathname()
|
||||
|
||||
useEffect(() => {
|
||||
if (!initiallyScrolled) {
|
||||
const initialSelectedSection = pathname.replace(
|
||||
`/reference/${libPath}/${isLatestVersion ? '' : `${version}/`}`,
|
||||
''
|
||||
)
|
||||
const initialSelectedSection = window.location.hash.replace(/^#/, '')
|
||||
if (initialSelectedSection) {
|
||||
const section = document.getElementById(initialSelectedSection)
|
||||
if (section) {
|
||||
@@ -110,7 +100,7 @@ export function ReferenceContentScrollHandler({
|
||||
|
||||
setInitiallyScrolled(true)
|
||||
}
|
||||
}, [pathname, libPath, version, isLatestVersion, initiallyScrolled])
|
||||
}, [initiallyScrolled])
|
||||
|
||||
return (
|
||||
<ReferenceContentInitiallyScrolledContext.Provider value={initiallyScrolled}>
|
||||
@@ -177,7 +167,7 @@ export function ReferenceNavigationScrollHandler({
|
||||
}
|
||||
|
||||
function deriveHref(basePath: string, section: AbbrevApiReferenceSection) {
|
||||
return 'slug' in section ? `${basePath}/${section.slug}` : ''
|
||||
return 'slug' in section ? `${basePath}#${section.slug}` : ''
|
||||
}
|
||||
|
||||
function getLinkStyles(isActive: boolean, className?: string) {
|
||||
@@ -247,10 +237,10 @@ export function RefLink({
|
||||
}) {
|
||||
const ref = useRef<HTMLAnchorElement>(null)
|
||||
|
||||
const pathname = useCurrentPathname()
|
||||
const location = useCurrentLocation()
|
||||
const href = deriveHref(basePath, section)
|
||||
const isActive =
|
||||
pathname === href || (pathname === basePath && href.replace(basePath, '') === '/introduction')
|
||||
location === href || (location === basePath && href.replace(basePath, '') === '#introduction')
|
||||
|
||||
useEffect(() => {
|
||||
if (ref.current) {
|
||||
@@ -293,15 +283,15 @@ export function RefLink({
|
||||
function useCompoundRefLinkActive(basePath: string, section: AbbrevApiReferenceSection) {
|
||||
const [open, _setOpen] = useState(false)
|
||||
|
||||
const pathname = useCurrentPathname()
|
||||
const location = useCurrentLocation()
|
||||
const parentHref = deriveHref(basePath, section)
|
||||
const isParentActive = pathname === parentHref
|
||||
const isParentActive = location === parentHref
|
||||
|
||||
const childHrefs = useMemo(
|
||||
() => new Set((section.items || []).map((item) => deriveHref(basePath, item))),
|
||||
[basePath, section]
|
||||
)
|
||||
const isChildActive = childHrefs.has(pathname)
|
||||
const isChildActive = childHrefs.has(location)
|
||||
|
||||
const isActive = isParentActive || isChildActive
|
||||
|
||||
|
||||
@@ -21,11 +21,7 @@ export async function ClientSdkReferencePage({ sdkId, libVersion }: ClientSdkRef
|
||||
const menuData = NavItems[libraryMeta.meta[libVersion].libId]
|
||||
|
||||
return (
|
||||
<ReferenceContentScrollHandler
|
||||
libPath={libraryMeta.libPath}
|
||||
version={libVersion}
|
||||
isLatestVersion={isLatestVersion}
|
||||
>
|
||||
<ReferenceContentScrollHandler>
|
||||
<SidebarSkeleton
|
||||
menuId={libraryMeta.meta[libVersion].libId}
|
||||
NavigationMenu={
|
||||
|
||||
@@ -94,7 +94,7 @@ export function SectionSwitch({ libraryId, version, section }: SectionSwitchProp
|
||||
const allAvailableVersions = REFERENCES[libraryId.replaceAll('-', '_')].versions
|
||||
const isLatestVersion = allAvailableVersions.length === 0 || version === allAvailableVersions[0]
|
||||
|
||||
const sectionLink = `/docs/reference/${libPath}/${isLatestVersion ? '' : `${version}/`}${section.slug}`
|
||||
const sectionLink = `/docs/reference/${libPath}${isLatestVersion ? '' : `/${version}`}#${section.slug}`
|
||||
|
||||
switch (section.type) {
|
||||
case 'markdown':
|
||||
@@ -192,7 +192,7 @@ async function CliCommandSection({ link, section }: CliCommandSectionProps) {
|
||||
return (
|
||||
<li key={index} className="ml-4">
|
||||
<RefInternalLink
|
||||
href={`/reference/cli/${subcommandDetails.id}`}
|
||||
href={`/reference/cli#${subcommandDetails.id}`}
|
||||
sectionSlug={subcommandDetails.id}
|
||||
>
|
||||
{subcommandDetails.title}
|
||||
|
||||
@@ -48,7 +48,7 @@ export async function SelfHostingReferencePage({
|
||||
const name = REFERENCES[servicePath.replaceAll('-', '_')].name
|
||||
|
||||
return (
|
||||
<ReferenceContentScrollHandler libPath={servicePath} version="latest" isLatestVersion={true}>
|
||||
<ReferenceContentScrollHandler>
|
||||
<SidebarSkeleton
|
||||
menuId={menuId}
|
||||
NavigationMenu={
|
||||
|
||||
@@ -171,6 +171,20 @@ const nextConfig = {
|
||||
source: '/guides/database/replication/replication-faq',
|
||||
destination: '/guides/database/replication/external-replication-faq',
|
||||
permanent: true,
|
||||
},
|
||||
// Reference pages use hash anchors for sections; redirect the legacy
|
||||
// path-style /reference/<lib>/introduction (and versioned variants)
|
||||
// back to the base reference URL. Order matters: introduction first so
|
||||
// it strips to a bare URL, then the section rules add a hash anchor.
|
||||
{
|
||||
source: '/reference/:lib/:version(v\\d+)/:section',
|
||||
destination: '/reference/:lib/:version#:section',
|
||||
permanent: true,
|
||||
},
|
||||
{
|
||||
source: '/reference/:lib/:section((?!v\\d+$)[^/]+)',
|
||||
destination: '/reference/:lib#:section',
|
||||
permanent: true,
|
||||
},
|
||||
]
|
||||
},
|
||||
|
||||
@@ -3203,6 +3203,20 @@ module.exports = [
|
||||
destination: '/dashboard/redeem?code=:code',
|
||||
permanent: false,
|
||||
},
|
||||
// Reference pages use hash anchors for sections; redirect the legacy
|
||||
// path-style /docs/reference/<lib>/introduction (and versioned variants)
|
||||
// back to the base reference URL. Order matters: introduction first so it
|
||||
// strips to a bare URL, then the section rules add a hash anchor.
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/reference/:lib/:version(v\\d+)/:section',
|
||||
destination: '/docs/reference/:lib/:version#:section',
|
||||
},
|
||||
{
|
||||
permanent: true,
|
||||
source: '/docs/reference/:lib/:section((?!v\\d+$)[^/]+)',
|
||||
destination: '/docs/reference/:lib#:section',
|
||||
},
|
||||
// Legacy product .txt URLs → new .md routes
|
||||
{ permanent: true, source: '/llms/homepage.txt', destination: '/homepage.md' },
|
||||
{ permanent: true, source: '/llms/auth.txt', destination: '/auth.md' },
|
||||
|
||||
Reference in new issue
Block a user