Skip to content

Commit ff599ed

Browse files
SaxonFCopilotdnywhjoshenlimcharislam
authored
Page components (supabase#40289)
* change database to pagelayout * page components * design system documentation * reduce preview width * revert studio * functions apply page * layout * interfaces * remove demos * pckage * format * format * Apply suggestion from @Copilot Co-authored-by: Copilot <[email protected]> * build registry * pckg * build script to allow index files * switch exports * fixes * gen exports * remove invalid prop * fix typecheck * fix prettier * Revert "remove invalid prop" This reverts commit 118ecd4. * Revert "fix typecheck" This reverts commit 0e1ec8f. * Revert "fix prettier" This reverts commit 2f25ed6. * pretter * fresh pnpm i * Update pnpm lock * fix import * revert * Update packages/ui-patterns/src/PageContainer/index.tsx Co-authored-by: Charis <[email protected]> * Update packages/ui-patterns/src/PageHeader/index.tsx Co-authored-by: Charis <[email protected]> * Update packages/ui-patterns/src/PageSection/index.tsx Co-authored-by: Charis <[email protected]> * ts fix * Update apps/design-system/content/docs/ui-patterns/page.mdx Co-authored-by: Danny White <[email protected]> * change to layouts and examples --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: Danny White <[email protected]> Co-authored-by: Joshen Lim <[email protected]> Co-authored-by: Charis <[email protected]>
1 parent 40f7abc commit ff599ed

File tree

34 files changed

+2660
-636
lines changed

34 files changed

+2660
-636
lines changed

apps/design-system/__registry__/index.tsx

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,39 @@ export const Index: Record<string, any> = {
3838
subcategory: "undefined",
3939
chunks: []
4040
},
41+
"PageContainer": {
42+
name: "PageContainer",
43+
type: "components:fragment",
44+
registryDependencies: undefined,
45+
component: React.lazy(() => import("@/../../packages/ui-patterns/src/PageContainer")),
46+
source: "",
47+
files: ["registry/default//PageContainer/index.tsx"],
48+
category: "undefined",
49+
subcategory: "undefined",
50+
chunks: []
51+
},
52+
"PageHeader": {
53+
name: "PageHeader",
54+
type: "components:fragment",
55+
registryDependencies: undefined,
56+
component: React.lazy(() => import("@/../../packages/ui-patterns/src/PageHeader")),
57+
source: "",
58+
files: ["registry/default//PageHeader/index.tsx"],
59+
category: "undefined",
60+
subcategory: "undefined",
61+
chunks: []
62+
},
63+
"PageSection": {
64+
name: "PageSection",
65+
type: "components:fragment",
66+
registryDependencies: undefined,
67+
component: React.lazy(() => import("@/../../packages/ui-patterns/src/PageSection")),
68+
source: "",
69+
files: ["registry/default//PageSection/index.tsx"],
70+
category: "undefined",
71+
subcategory: "undefined",
72+
chunks: []
73+
},
4174
"accordion-demo": {
4275
name: "accordion-demo",
4376
type: "components:example",
@@ -1886,6 +1919,105 @@ export const Index: Record<string, any> = {
18861919
subcategory: "undefined",
18871920
chunks: []
18881921
},
1922+
"page-container-demo": {
1923+
name: "page-container-demo",
1924+
type: "components:example",
1925+
registryDependencies: undefined,
1926+
component: React.lazy(() => import("@/registry/default/example/page-container-demo")),
1927+
source: "",
1928+
files: ["registry/default/example/page-container-demo.tsx"],
1929+
category: "undefined",
1930+
subcategory: "undefined",
1931+
chunks: []
1932+
},
1933+
"page-layout-detail": {
1934+
name: "page-layout-detail",
1935+
type: "components:example",
1936+
registryDependencies: undefined,
1937+
component: React.lazy(() => import("@/registry/default/example/page-layout-detail")),
1938+
source: "",
1939+
files: ["registry/default/example/page-layout-detail.tsx"],
1940+
category: "undefined",
1941+
subcategory: "undefined",
1942+
chunks: []
1943+
},
1944+
"page-layout-list": {
1945+
name: "page-layout-list",
1946+
type: "components:example",
1947+
registryDependencies: undefined,
1948+
component: React.lazy(() => import("@/registry/default/example/page-layout-list")),
1949+
source: "",
1950+
files: ["registry/default/example/page-layout-list.tsx"],
1951+
category: "undefined",
1952+
subcategory: "undefined",
1953+
chunks: []
1954+
},
1955+
"page-layout-list-simple": {
1956+
name: "page-layout-list-simple",
1957+
type: "components:example",
1958+
registryDependencies: undefined,
1959+
component: React.lazy(() => import("@/registry/default/example/page-layout-list-simple")),
1960+
source: "",
1961+
files: ["registry/default/example/page-layout-list-simple.tsx"],
1962+
category: "undefined",
1963+
subcategory: "undefined",
1964+
chunks: []
1965+
},
1966+
"page-layout-settings": {
1967+
name: "page-layout-settings",
1968+
type: "components:example",
1969+
registryDependencies: undefined,
1970+
component: React.lazy(() => import("@/registry/default/example/page-layout-settings")),
1971+
source: "",
1972+
files: ["registry/default/example/page-layout-settings.tsx"],
1973+
category: "undefined",
1974+
subcategory: "undefined",
1975+
chunks: []
1976+
},
1977+
"page-header-demo": {
1978+
name: "page-header-demo",
1979+
type: "components:example",
1980+
registryDependencies: undefined,
1981+
component: React.lazy(() => import("@/registry/default/example/page-header-demo")),
1982+
source: "",
1983+
files: ["registry/default/example/page-header-demo.tsx"],
1984+
category: "undefined",
1985+
subcategory: "undefined",
1986+
chunks: []
1987+
},
1988+
"page-section-demo": {
1989+
name: "page-section-demo",
1990+
type: "components:example",
1991+
registryDependencies: undefined,
1992+
component: React.lazy(() => import("@/registry/default/example/page-section-demo")),
1993+
source: "",
1994+
files: ["registry/default/example/page-section-demo.tsx"],
1995+
category: "undefined",
1996+
subcategory: "undefined",
1997+
chunks: []
1998+
},
1999+
"page-section-horizontal": {
2000+
name: "page-section-horizontal",
2001+
type: "components:example",
2002+
registryDependencies: undefined,
2003+
component: React.lazy(() => import("@/registry/default/example/page-section-horizontal")),
2004+
source: "",
2005+
files: ["registry/default/example/page-section-horizontal.tsx"],
2006+
category: "undefined",
2007+
subcategory: "undefined",
2008+
chunks: []
2009+
},
2010+
"page-section-with-aside": {
2011+
name: "page-section-with-aside",
2012+
type: "components:example",
2013+
registryDependencies: undefined,
2014+
component: React.lazy(() => import("@/registry/default/example/page-section-with-aside")),
2015+
source: "",
2016+
files: ["registry/default/example/page-section-with-aside.tsx"],
2017+
category: "undefined",
2018+
subcategory: "undefined",
2019+
chunks: []
2020+
},
18892021
"inner-side-menu-demo": {
18902022
name: "inner-side-menu-demo",
18912023
type: "components:example",

apps/design-system/app/layout.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import '@/styles/globals.css'
2+
import '../../studio/styles/typography.scss'
23
import type { Metadata } from 'next'
34
import { ThemeProvider } from './Providers'
45
import { SonnerToaster } from './SonnerToast'

apps/design-system/components/component-preview.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,11 @@ export function ComponentPreview({
120120
)
121121
}, [Preview, align])
122122

123-
const wideClasses = wide ? '2xl:-ml-12 2xl:-mr-12' : ''
123+
const wideClasses = wide ? '2xl:-ml-20 2xl:-mr-20' : ''
124124

125125
if (peekCode) {
126126
return (
127-
<div className={cn('mt-4 mb-12', wideClasses)}>
127+
<div className={cn('@container mt-4 mb-12', wideClasses)}>
128128
<div
129129
className={cn(
130130
'relative rounded-tl-md rounded-tr-md border-t border-l border-r bg-studio'

apps/design-system/config/docs.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,11 @@ export const docsConfig: DocsConfig = {
4545
href: '/docs/ui-patterns/navigation',
4646
items: [],
4747
},
48+
{
49+
title: 'Layout',
50+
href: '/docs/ui-patterns/layout',
51+
items: [],
52+
},
4853
{
4954
title: 'Empty States',
5055
href: '/docs/ui-patterns/empty-states',
@@ -75,6 +80,21 @@ export const docsConfig: DocsConfig = {
7580
href: '/docs/fragments/modal',
7681
items: [],
7782
},
83+
{
84+
title: 'Page Container',
85+
href: '/docs/fragments/page-container',
86+
items: [],
87+
},
88+
{
89+
title: 'Page Header',
90+
href: '/docs/fragments/page-header',
91+
items: [],
92+
},
93+
{
94+
title: 'Page Section',
95+
href: '/docs/fragments/page-section',
96+
items: [],
97+
},
7898
{
7999
title: 'Text Confirm Dialog',
80100
href: '/docs/fragments/text-confirm-dialog',
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
---
2+
title: Page Container
3+
description: A container component that provides consistent max-width and padding based on size variants.
4+
fragment: true
5+
---
6+
7+
<ComponentPreview
8+
name="page-container-demo"
9+
description="Container with default size (1200px max-width)"
10+
peekCode
11+
wide
12+
/>
13+
14+
## Usage
15+
16+
```tsx
17+
import { PageContainer } from 'ui-patterns/PageContainer'
18+
```
19+
20+
```tsx
21+
<PageContainer size="default">{/* Page content */}</PageContainer>
22+
```
23+
24+
## Size Variants
25+
26+
The `PageContainer` supports four size variants:
27+
28+
- `small` - max-width: 768px
29+
- `default` - max-width: 1200px
30+
- `large` - max-width: 1600px
31+
- `full` - no max-width constraint
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
title: Page Header
3+
description: A compound component for building page headers with consistent structure.
4+
fragment: true
5+
---
6+
7+
<ComponentPreview
8+
name="page-header-demo"
9+
description="Basic page header with title, description, and actions"
10+
peekCode
11+
wide
12+
/>
13+
14+
## Sub-components
15+
16+
- `PageHeader` - Root container with size variants (`default`, `small`, `large`, `full`)
17+
- `PageHeaderBreadcrumb` - Breadcrumb navigation wrapper (should be first child)
18+
- `PageHeaderMeta` - Meta wrapper for icon, summary, and aside (groups icon and summary together, places aside on the right)
19+
- `PageHeaderIcon` - Icon container positioned left of title (should be inside PageHeaderMeta, has `shrink-0`)
20+
- `PageHeaderSummary` - Container for title and description (should be inside PageHeaderMeta, has `flex-1`)
21+
- `PageHeaderTitle` - Primary page heading (h1)
22+
- `PageHeaderDescription` - Supporting text below title
23+
- `PageHeaderAside` - Container for action buttons (should be inside PageHeaderMeta, has `shrink-0`)
24+
- `PageHeaderFooter` - Container for tab navigation (NavMenu, should be last child)
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
---
2+
title: Page Section
3+
description: A compound component for organizing page content into distinct sections.
4+
fragment: true
5+
---
6+
7+
<ComponentPreview
8+
name="page-section-demo"
9+
description="Basic page section with title, description, and content"
10+
peekCode
11+
wide
12+
/>
13+
14+
## Sub-components
15+
16+
- `PageSection` - Root container with orientation variants (`horizontal` or `vertical`)
17+
- `PageSectionMeta` - Meta wrapper for summary and aside (groups summary and aside together)
18+
- `PageSectionSummary` - Container for section title and description (should be inside PageSectionMeta, has `flex-1`)
19+
- `PageSectionTitle` - Section heading (h2)
20+
- `PageSectionDescription` - Supporting text below section title
21+
- `PageSectionAside` - Container for section-level actions (should be inside PageSectionMeta, has `shrink-0`)
22+
- `PageSectionContent` - Container for the main section content
23+
24+
## Orientation Variants
25+
26+
- `vertical` - Content stacks vertically (default)
27+
- `horizontal` - Summary and content arranged horizontally on larger screens
28+
29+
## Examples
30+
31+
### Horizontal Orientation
32+
33+
<ComponentPreview
34+
name="page-section-horizontal"
35+
description="PageSection with horizontal layout - summary on left, content on right"
36+
peekCode
37+
wide
38+
/>
39+
40+
### With Aside Actions
41+
42+
<ComponentPreview
43+
name="page-section-with-aside"
44+
description="PageSection with multiple action buttons in the Aside component"
45+
peekCode
46+
wide
47+
/>
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
---
2+
title: Layout
3+
description: Guidelines to create consistent layouts across Studio pages using a set of page components.
4+
---
5+
6+
The Page pattern consists of three main components that work together to create consistent page layouts: [PageContainer](../fragments/page-container), [PageHeader](../fragments/page-header), and [PageSection](../fragments/page-section). These components provide a structured approach to building pages with consistent spacing, max-widths, and content organization.
7+
8+
## Layout Types
9+
10+
### Settings
11+
12+
Settings pages are used for configuration and preference management. They follow a single-column layout with default widths to keep content focused and readable. Examples include project settings or auth sessions.
13+
14+
- Use `PageHeader` with `size="default"`
15+
- Use `PageContainer` with `size="default"`
16+
- Use `PageSection` for organizing settings into logical groups
17+
18+
<ComponentPreview
19+
name="page-layout-settings"
20+
description="Settings page layout with default widths"
21+
peekCode
22+
wide
23+
/>
24+
25+
### List
26+
27+
List pages display collections of objects like tables, triggers, or functions. These pages use larger widths to accommodate wide content like data tables. Examples include database triggers, database functions or org team members.
28+
29+
- Use `PageHeader` with `size="large"`
30+
- Use `PageContainer` with `size="large"`
31+
- Use `PageSection` to wrap list content
32+
33+
**Table and List Actions:**
34+
35+
- **With filters or search:** If the table has filters or search, place table actions aligned with the filters on the right side. Do not use `PageSectionAside` or `PageHeaderAside` for table actions when filters are present.
36+
- **Without filters:** For simple lists without filters or search, add primary list actions to `PageHeaderAside` or `PageSectionAside` as appropriate.
37+
38+
<ComponentPreview
39+
name="page-layout-list"
40+
description="List page layout with search and filters - actions aligned with search"
41+
peekCode
42+
wide
43+
/>
44+
45+
<ComponentPreview
46+
name="page-layout-list-simple"
47+
description="Simple list page layout without filters - actions in PageHeaderAside"
48+
peekCode
49+
wide
50+
/>
51+
52+
### Data and Full Page Experiences
53+
54+
Full-page experiences like the table editor, cron jobs, and edge functions require maximum screen real-estate and so make use of "full" size containers.
55+
56+
- Use `PageHeader` with `size="full"`
57+
- Use `PageContainer` with `size="full"`
58+
- Content spans the full width of the viewport
59+
60+
### Detail Pages
61+
62+
Detail pages display dense or lengthy content split into multiple sections. The horizontal orientation allows for better information hierarchy and context. Examples include organisation billing or project infrastructure.
63+
64+
- Use `PageHeader` with `size="large"`
65+
- Use `PageContainer` with `size="large"`
66+
- Use `PageSection` with `orientation="horizontal"` to show summary alongside content
67+
- Multiple sections can stack vertically with horizontal layouts within each
68+
69+
<ComponentPreview
70+
name="page-layout-detail"
71+
description="Detail page layout with horizontal sections for dense content"
72+
peekCode
73+
wide
74+
/>
75+
76+
## Components
77+
78+
- **[PageContainer](/docs/fragments/page-container)** - Container component providing consistent max-width and padding based on size variants
79+
- **[PageHeader](/docs/fragments/page-header)** - Compound component for building page headers with breadcrumbs, icons, titles, descriptions, actions, and navigation
80+
- **[PageSection](/docs/fragments/page-section)** - Compound component for organizing page content into distinct sections with title, description, and action areas

apps/design-system/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
},
5353
"devDependencies": {
5454
"@shikijs/compat": "^1.1.7",
55+
"@tailwindcss/container-queries": "^0.1.1",
5556
"@types/lodash.template": "4.5.0",
5657
"@types/react": "catalog:",
5758
"@types/react-dom": "catalog:",

0 commit comments

Comments
 (0)