Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
0b53a18
fix(studio): wire up siwc-enabled query param opt-in on sign-in/sign-…
cemalkilic Jul 21, 2026
fe5aff6
feat: Add deployment/ci federated content and data (#48041)
jeremenichelli Jul 21, 2026
b90c84d
feat: Add ai-skills federated content and data (#48045)
jeremenichelli Jul 21, 2026
7ce1291
feat: Add ai/python federated content and data (#48043)
jeremenichelli Jul 21, 2026
3d1d34b
chore(studio): add valtio and react-hook-form ESLint ratchet rules (#…
ivasilov Jul 21, 2026
da7a10b
chore: simplify CPU messaging for compute sizes (#48109)
awaseem Jul 21, 2026
3a085f9
fix(docs): guard federated-content schema reads when artifact is abse…
claude[bot] Jul 21, 2026
d0abc7a
fix: cron job has no default for timeout input (#48103)
djhi Jul 21, 2026
0324f34
chore(studio): polish vercel deploy-button new project interstitial (…
dnywh Jul 21, 2026
8a0b324
docs(design-system): add connect interstitials pattern (#45356)
dnywh Jul 21, 2026
d5c5a95
feat(www): add "Supabase Pipelines is now in Public Alpha" blog post …
ana1337x Jul 21, 2026
6928a01
fix(www): correct Supabase Pipelines public alpha post date to July 2…
ana1337x Jul 21, 2026
9f5e751
chore(studio): add bullet-point to integration uninstall modal (#48139)
fsansalvadore Jul 21, 2026
b883b10
fix(studio): gate user logs tab behind feature flag (#48122)
luizfelmach Jul 21, 2026
2e12cdc
fix: empty search_path (#48151)
7ttp Jul 21, 2026
c13cb81
chore: remove noisy dashboard PR-reminder workflow (#48142)
claude[bot] Jul 21, 2026
94f2f5a
feat(pipelines): Adjust blog post naming (#48154)
iambriccardo Jul 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 0 additions & 45 deletions .github/workflows/dashboard-pr-reminder.yml

This file was deleted.

33 changes: 33 additions & 0 deletions apps/design-system/__registry__/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2601,6 +2601,39 @@ export const Index: Record<string, any> = {
subcategory: "undefined",
chunks: []
},
"connect-interstitial-demo": {
name: "connect-interstitial-demo",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/connect-interstitial-demo")),
source: "",
files: ["registry/default/example/connect-interstitial-demo.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"connect-interstitial-logo-pair": {
name: "connect-interstitial-logo-pair",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/connect-interstitial-logo-pair")),
source: "",
files: ["registry/default/example/connect-interstitial-logo-pair.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"connect-interstitial-logo-single": {
name: "connect-interstitial-logo-single",
type: "components:example",
registryDependencies: undefined,
component: React.lazy(() => import("@/registry/default/example/connect-interstitial-logo-single")),
source: "",
files: ["registry/default/example/connect-interstitial-logo-single.tsx"],
category: "undefined",
subcategory: "undefined",
chunks: []
},
"page-layout-auth-emails": {
name: "page-layout-auth-emails",
type: "components:example",
Expand Down
5 changes: 5 additions & 0 deletions apps/design-system/config/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ export const docsConfig: DocsConfig = {
href: '/docs/ui-patterns/charts',
items: [],
},
{
title: 'Connect Interstitials',
href: '/docs/ui-patterns/connect-interstitials',
items: [],
},
{
title: 'Empty States',
href: '/docs/ui-patterns/empty-states',
Expand Down
161 changes: 161 additions & 0 deletions apps/design-system/content/docs/ui-patterns/connect-interstitials.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
---
title: Connect Interstitials
description: Shared layout guidance for focused authorisation, invite, marketplace, CLI, and credit redemption flows.
---

Connect interstitials are focused, single-card flows that sit outside the main
Studio shell. Use the shared `InterstitialLayout` family instead of building
bespoke centered cards, logos, account rows, or organisation selectors.

<ComponentPreview
name="connect-interstitial-demo"
description="Centered 400px card with partner branding, account row, and a single primary action"
align="start"
className="p-0"
padded={false}
peekCode
wide
/>

## Use this pattern for

This pattern fits short-lived connect flows: partner authorisation and consent
(OAuth, MCP, Stripe Projects), organisation invites, marketplace and billing
connections (AWS Marketplace, Vercel install, credit redemption), and CLI or
device-code sign-in. Use the same shell for their loading, error, success, and
wrong-account states.

Do not use it for normal authenticated Studio pages. Those should use the
standard [page layout](./layout) patterns.

## Source of truth

```tsx
import { OrganizationSelector } from '@/components/interfaces/Connect/OrganizationSelector'
import {
InterstitialAccountRow,
InterstitialLayout,
LogoBox,
LogoPair,
PartnerLogo,
SupabaseLogo,
} from '@/components/layouts/InterstitialLayout'
```

## Basic shape

Use `InterstitialLayout` for the outer card, then put route-specific content in
`px-6 pb-6`. Widen the card only when the flow embeds a real tool, such as
project linking.

```tsx
<InterstitialLayout
logo={
<LogoPair
left={<PartnerLogo src={`${BASE_PATH}/img/icons/stripe-icon.svg`} alt="Stripe" />}
right={<SupabaseLogo />}
/>
}
title="Authorize Stripe Projects"
description="This will create an organization on your behalf in Supabase"
>
<div className="px-6 pb-6">
<InterstitialAccountRow displayName={displayName} />
<Button variant="primary" block>
Continue
</Button>
</div>
</InterstitialLayout>
```

```tsx
<InterstitialLayout
logo={<LogoPair left={<VercelLogo />} right={<SupabaseLogo />} />}
title="Connect Vercel project"
containerClassName="items-start"
cardClassName="max-w-[900px]"
>
<div className="px-6 pb-6">{projectLinker}</div>
</InterstitialLayout>
```

## Logos

Use `LogoPair` when the user is connecting two services, and `SupabaseLogo`
alone for first-party flows. `PartnerLogo` fills the 48px box edge-to-edge;
`LogoBox` is for custom inset marks or logos that need their own background.
Store new partner icons in `apps/studio/public/img/icons`.

<ComponentPreview
name="connect-interstitial-logo-pair"
description="LogoPair when the user is connecting two services"
align="start"
className="p-0"
padded={false}
peekCode
wide
/>

<ComponentPreview
name="connect-interstitial-logo-single"
description="SupabaseLogo alone for first-party flows"
align="start"
className="p-0"
padded={false}
peekCode
wide
/>

```tsx
const AwsLogo = () => (
<LogoBox className="border-[#232f3e] bg-[#232f3e]">
<img alt="AWS" src={`${BASE_PATH}/img/icons/aws-icon.svg`} className="w-8" />
</LogoBox>
)

<LogoPair left={<AwsLogo />} right={<SupabaseLogo />} />
```

## Account row

Use `InterstitialAccountRow` for signed-in context. Do not recreate it locally.

```tsx
<InterstitialAccountRow avatarUrl={avatarUrl} displayName={displayName} action={signOutButton} />
```

## Organisation selection

Use `OrganizationSelector` when the flow needs an organisation pick. Extend it
for new states instead of inventing a parallel card style.

```tsx
<OrganizationSelector
organizations={linkableOrganizations}
selectedSlug={selectedOrgSlug}
onSelect={setSelectedOrgSlug}
createLabel="Create new organization"
onCreate={() => setShowOrgCreationDialog(true)}
/>
```

## Actions

Prefer one full-width primary action. A full-width text button is fine for a
secondary action that still belongs in the flow.

## States

Keep loading, invalid, error, and success states inside the same card when the
route can explain them. Use `ShimmeringLoader` for loading, and `Admonition`
for warning, error, note, and success copy.

## Copy

Use sentence case. Prefer `sign in` over `login`. Titles and primary actions
should follow `Verb -> Thing`, for example `Authorize Stripe Projects` or
`Install Vercel`.

Keep the layout title static across states and put state-specific copy in the
body. Header descriptions should stay short and should not end with a full
stop.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Button } from 'ui'

import {
AccountRow,
InterstitialShell,
LogoPair,
SignOutButton,
StripeLogo,
SupabaseLogo,
} from './connect-interstitial-shared'

export default function ConnectInterstitialDemo() {
return (
<InterstitialShell
logo={<LogoPair left={<StripeLogo />} right={<SupabaseLogo />} />}
title="Authorize Stripe Projects"
description="This will create an organization on your behalf in Supabase"
>
<div className="flex flex-col gap-4">
<AccountRow displayName="alex@example.com" action={<SignOutButton />} />
<Button variant="primary" block>
Authorize Stripe Projects
</Button>
<Button variant="text" block>
Cancel
</Button>
</div>
</InterstitialShell>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { Button } from 'ui'

import {
AccountRow,
InterstitialShell,
LogoPair,
SignOutButton,
StripeLogo,
SupabaseLogo,
} from './connect-interstitial-shared'

export default function ConnectInterstitialLogoPair() {
return (
<InterstitialShell
logo={<LogoPair left={<StripeLogo />} right={<SupabaseLogo />} />}
title="Authorize Stripe Projects"
description="This will create an organization on your behalf in Supabase"
>
<div className="flex flex-col gap-4">
<AccountRow displayName="alex@example.com" action={<SignOutButton />} />
<Button variant="primary" block>
Authorize Stripe Projects
</Button>
</div>
</InterstitialShell>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { Button } from 'ui'
import { Admonition } from 'ui-patterns/admonition'

import { AccountRow, InterstitialShell, SupabaseLogo } from './connect-interstitial-shared'

export default function ConnectInterstitialLogoSingle() {
return (
<InterstitialShell
logo={<SupabaseLogo />}
title="Join organization"
description="You have been invited to Acme Labs"
>
<div className="flex flex-col gap-4">
<Admonition
type="warning"
title="Wrong account"
description="Sign in with the Supabase account that received this invite, then open the link again."
/>
<AccountRow displayName="alex@example.com" />
<Button variant="primary" block>
Sign out and continue
</Button>
</div>
</InterstitialShell>
)
}
Loading
Loading