mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 09:25:06 +03:00
## I have read the [CONTRIBUTING.md](https://github.com/supabase/supabase/blob/master/CONTRIBUTING.md) file. YES ## What kind of change does this PR introduce? Feature ## What is the current behavior? Region and data residency information is split across docs, `/security`, and legal pages. [MARKET-1866](https://linear.app/supabase/issue/MARKET-1866/package-and-display-available-regions-better-on-website) ## What is the new behavior? Adds `/regions`: a catalog of all 17 regions generated from `regions.ts`, plus what stays in-region, the Europe vs EU caveat, and links to the DPA, GDPR guide, sub-processor list, and security page. Regions is in the footer under Security & Compliance. The security page residency card now links here. ## Test plan - [ ] Open `/regions` in light and dark mode - [ ] Confirm the region count and list match `packages/shared-data/regions.ts` - [ ] Confirm footer Regions link and `/security` residency link go to `/regions` Made with [Cursor](https://cursor.com) <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Added a Regions page showcasing available AWS regions by geography. - Added an interactive map and region list with selection, hover states, keyboard accessibility, and residency badges. - Included data residency guidance, legal resources, and a call-to-action for next steps. - Added Regions links in the site footer and security documentation. - **Documentation** - Updated agent skill resources with expanded troubleshooting and operational guidance. <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Cursor <cursoragent@cursor.com> Co-authored-by: Francesco Sansalvadore <f.sansalvadore@gmail.com>
53 lines
1.8 KiB
TypeScript
53 lines
1.8 KiB
TypeScript
'use client'
|
|
|
|
import dynamic from 'next/dynamic'
|
|
import { parseAsStringLiteral, useQueryState } from 'nuqs'
|
|
import { NuqsAdapter } from 'nuqs/adapters/next/pages'
|
|
import { useState } from 'react'
|
|
|
|
import { REGION_CODES } from './Regions.constants'
|
|
import { RegionsList } from './RegionsList'
|
|
|
|
const RegionsMap = dynamic(() => import('./RegionsMap').then((mod) => mod.RegionsMap), {
|
|
ssr: false,
|
|
loading: () => null,
|
|
})
|
|
|
|
// Unknown values are dropped, so `?region=nonsense` renders as no selection
|
|
const regionParser = parseAsStringLiteral(REGION_CODES).withOptions({ history: 'push' })
|
|
|
|
const RegionsExplorerContent = () => {
|
|
const [selectedRegionCode, setSelectedRegionCode] = useQueryState('region', regionParser)
|
|
const [hoveredRegionCode, setHoveredRegionCode] = useState<string>()
|
|
|
|
const handleRegionSelect = (code: string) =>
|
|
setSelectedRegionCode(code === selectedRegionCode ? null : code)
|
|
|
|
return (
|
|
<div className="flex flex-col gap-8 lg:gap-12">
|
|
{/* Matches the map's viewBox ratio, so the map fills the container instead of letterboxing */}
|
|
<div className="relative aspect-800/349 w-full overflow-hidden rounded-lg border bg-alternative">
|
|
<RegionsMap
|
|
selectedRegionCode={selectedRegionCode}
|
|
hoveredRegionCode={hoveredRegionCode}
|
|
onRegionHover={setHoveredRegionCode}
|
|
onRegionSelect={handleRegionSelect}
|
|
onRegionClear={() => setSelectedRegionCode(null)}
|
|
/>
|
|
</div>
|
|
<RegionsList
|
|
selectedRegionCode={selectedRegionCode}
|
|
hoveredRegionCode={hoveredRegionCode}
|
|
onRegionHover={setHoveredRegionCode}
|
|
onRegionSelect={handleRegionSelect}
|
|
/>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
export const RegionsExplorer = () => (
|
|
<NuqsAdapter>
|
|
<RegionsExplorerContent />
|
|
</NuqsAdapter>
|
|
)
|