fix(ui): make brand text readable across themes (#49871)

## What kind of change does this PR introduce?

Bug fix and design-system update. Resolves DEPR-316.

Follow-up rename (`text-brand` → `text-primary`) is in a dedicated PR
(https://github.com/supabase/supabase/pull/50564) stacked on this one.

## What is the current behavior?

`text-brand` resolves to the canonical bright brand green in places that
need readable text, which fails WCAG AA on light surfaces. A separate
`text-brand-display` token adds another green for large type.

## What is the new behavior?

- `text-brand` maps to accessible `--primary` (light mode darkened to
meet ~4.5:1 AA)
- `--hue` / `--primary-hue` aligned to 157.5
- `text-brand-display` removed; former display callsites use
`text-brand`
- Bright fills/borders stay on `brand-default`
- Design-system colour and typography docs updated

| Before | After |
| --- | --- |
| <img width="514" height="112" alt="CleanShot 2026-09-02 at 11 13
09@2x"
src="https://github.com/user-attachments/assets/4e0138a9-a32d-4e4c-a426-90736706e1e7"
/> | <img width="512" height="138" alt="CleanShot 2026-09-21 at 11 42
05@2x"
src="https://github.com/user-attachments/assets/164cc5b1-a0c5-4e93-95f1-80016641a114"
/> |
| <img width="864" height="266" alt="CleanShot 2026-09-02 at 11 13
53@2x"
src="https://github.com/user-attachments/assets/3c1ca53f-bf9e-431e-bc15-816b4a275b8e"
/> | <img width="882" height="248" alt="CleanShot 2026-09-21 at 11 41
37@2x"
src="https://github.com/user-attachments/assets/24828e7b-ed6b-44cb-b9dc-becc3398bdfc"
/> |
| <img width="782" height="692" alt="CleanShot 2026-09-02 at 11 16
30@2x"
src="https://github.com/user-attachments/assets/fc871977-77bc-47fb-9e0e-9284e0ecd5cc"
/> | <img width="730" height="690" alt="CleanShot 2026-09-21 at 11 42
52@2x"
src="https://github.com/user-attachments/assets/bf479515-d5f9-471e-b82d-f097c0f4b56c"
/> |
| <img width="480" height="306" alt="CleanShot 2026-09-02 at 11 18
53@2x"
src="https://github.com/user-attachments/assets/03f341f4-f02e-44f8-a2b2-8c31670d0427"
/> | <img width="470" height="300" alt="CleanShot 2026-09-21 at 11 43
19@2x"
src="https://github.com/user-attachments/assets/9df18217-d5e6-48b8-ba0b-579d2664b94b"
/> |
| <img width="960" height="300" alt="CleanShot 2026-09-02 at 11 32
04@2x"
src="https://github.com/user-attachments/assets/6b1d9373-7a71-4247-81ff-26441604b09d"
/> | <img width="980" height="306" alt="CleanShot 2026-09-21 at 11 44
13@2x"
src="https://github.com/user-attachments/assets/41ad4784-02ec-4b29-b860-32af9fa79aa8"
/> |
| <img width="924" height="214" alt="CleanShot 2026-09-02 at 11 34
44@2x"
src="https://github.com/user-attachments/assets/1de661fe-c7b6-499b-a94f-e4737436ec79"
/> | <img width="752" height="162" alt="CleanShot 2026-09-21 at 11 44
56@2x"
src="https://github.com/user-attachments/assets/1811890f-0660-4445-84e9-447720954fa1"
/> |

## To test

Test each callsite **in light mode** (dark mode is largely unchanged).

### WWW

-
[Homepage](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/):
“Scale to millions” uses readable brand text (display token is gone)
-
[Careers](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/careers):
small “Careers” eyebrow readable; green dividers stay bright
`brand-default`
-
[Contact](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/contact-us):
email / policy links use readable brand text
-
[Regions](https://zone-www-dot-com-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/regions):
“Ask about early access to BYOC” readable

### Docs

- [Docs
homepage](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs):
“DOCS” wordmark and resource links readable
- [Database
overview](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/guides/database/overview):
nav / footer brand links readable
- [JavaScript
reference](https://docs-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/reference/javascript/introduction):
active sidebar treatment readable

### Design system

-
[Typography](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/typography):
documents `text-brand` only (no display)
- [Colour
usage](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/docs/color-usage):
`text-brand` vs `bg-brand-default`
- [Design-system
homepage](https://design-system-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/):
brand text examples across themes

### Studio

- [Auth
providers](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/auth/providers):
enabled provider badge text readable; status dot stays bright
- [Database
policies](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/database/policies?new=true):
template hover text more legible
- [Database
connections](https://studio-staging-git-dnywh-depr-316-brand-text-tokens-supabase.vercel.app/dashboard/project/_/observability/connections):
“Live” status readable; animated dot stays bright green

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
This commit is contained in:
Danny WhiteandJoshen Lim authored and GitHub committed 2026-09-22 10:07:28 +10:00
1 parent e1bdcc99db
commit a31ca2bad0
166 files changed
+305 -279

No files matched your search

+4
View File
@@ -125,6 +125,10 @@ reviews:
"read more", or "learn more" when it does not describe the
destination. Skip if aria-label or wrapping context already names
where the link goes.
- Color contrast: flag non-large informative text below 4.5:1 and large informative
text (at least 24px regular or 18.5px bold) below 3:1. Skip logotypes and
decorative text. Treat expressive text at 40px or larger as advisory rather
than blocking.
# Applies our internal engineering skills (.agents/skills/) as CodeRabbit review
# guidelines. The skills are the single source of truth — they are consumed
@@ -9,10 +9,18 @@ The shorthand utility classes below simplify our full color palette by providing
Use accent text colors (e.g. text-destructive, text-warning) sparingly to avoid visual overload.
Use `text-brand` for readable branded text such as links, labels, and statuses. On light-theme
surfaces it meets the 4.5:1 WCAG AA requirement for normal text. Use `bg-brand-default` /
`border-brand-default` when you need the canonical bright Supabase green as a fill or border.
<Colors definition={'text'} />
## Background
Use `bg-brand-default` when the canonical Supabase green is required as a fill. The same
`brand-default` suffix applies to borders and other non-text utilities, such as
`border-brand-default`.
<Colors definition={'background'} />
### App backgrounds
@@ -9,7 +9,9 @@ The shorthands below are composed of core [Tailwind utility classes](../docs/tai
## Shorthands
| Value | Usage |
| ------------------ | ---------------------------------------------------------------------------- |
| `text-code-inline` | Apply to a `code` element for inline code or similar custom inline content |
| `text-brand-link` | Supabase green text that meets contrast requirements in light and dark modes |
| Value | Usage |
| ------------------ | -------------------------------------------------------------------------- |
| `text-code-inline` | Apply to a `code` element for inline code or similar custom inline content |
| `text-brand` | Accessible Supabase green for readable branded text |
`text-brand` is independent from `bg-brand-default`, `border-brand-default`, and other non-text brand utilities. Its light-mode value has at least 4.5:1 contrast against the light surfaces used by the apps, meeting WCAG AA for normal text.
@@ -23,7 +23,7 @@ export default function SuccessCheckSelected() {
className={cn(
'relative flex w-full items-center rounded-md border px-4 py-3 text-left text-sm transition-colors',
isSelected
? 'border-brand bg-brand-200/20 pr-10 dark:bg-brand-300'
? 'border-brand-default bg-brand-200/20 pr-10 dark:bg-brand-300'
: 'hover:border-default hover:bg-surface-200'
)}
>
+1 -1
View File
@@ -108,7 +108,7 @@ Use the [Write the docs](../../.agents/skills/pm-the-docs/reference/write-the-do
### Edit existing pages
Use [`edit-the-docs`](../../.agents/skills/edit-the-docs/SKILL.md) for style, structure, or brevity on an existing page when you are not changing the product story.
Use [`edit-the-docs`](../../.agents/skills/edit-the-docs/SKILL.md) for style, structure, or brevity on an existing page when you are not changing the product story.
## Document types
+2 -2
View File
@@ -330,7 +330,7 @@ const HomePage = () => (
<TextLink
label="Explore more resources"
url="/guides/resources"
className="no-underline text-brand-link text-sm"
className="no-underline text-brand text-sm"
/>
</div>
@@ -388,7 +388,7 @@ const HomePage = () => (
<TextLink
label="More on self-hosting"
url="/guides/self-hosting"
className="no-underline text-brand-link text-sm"
className="no-underline text-brand text-sm"
/>
</div>
</div>
+1 -1
View File
@@ -179,7 +179,7 @@ function Feedback({ className }: { className?: string }) {
'[transition-timing-function:cubic-bezier(.76,0,.23,1)]',
!isYes && 'hover:text-brand-600 hover:border-brand-500',
isYes &&
'bg-brand text-brand-200 border-brand! disabled:opacity-100 -translate-x-[calc(100%+var(--container-inline-flex-gap,0.5rem))]',
'bg-brand-default text-brand-200 border-brand-default! disabled:opacity-100 -translate-x-[calc(100%+var(--container-inline-flex-gap,0.5rem))]',
!showYes && 'opacity-0 invisible'
)}
onClick={() => handleVote('yes')}
@@ -94,7 +94,7 @@ function FeedbackModal({ visible, page, onCancel, onSubmit }: FeedbackModalProps
href="https://supabase.com/dashboard/support/new"
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline"
className="text-brand hover:underline"
>
support request
</a>
+1 -1
View File
@@ -14,7 +14,7 @@ const Footer = ({ className }: { className?: string }) => (
<p>{text}</p>
<Link
href={url}
className="text-brand-link hover:underline"
className="text-brand hover:underline"
target="_blank"
rel="noreferrer noopener"
>
@@ -137,7 +137,7 @@ const GlobalMobileMenu = ({ open, setOpen }: Props) => {
height={24}
alt="Supabase Logo"
/>
<span className="font-mono text-sm font-medium text-brand-link mb-px">DOCS</span>
<span className="font-mono text-sm font-medium text-brand mb-px">DOCS</span>
</Link>
<div className="flex gap-4 items-center">
<ThemeToggle contentClassName="bg-surface-200" />
@@ -22,7 +22,7 @@ const NavigationMenuCliList = ({ currentLevel, setLevel, id }) => {
<li key={id} className="function-link-item text-foreground-lighter leading-3">
<Link
href={`#${id}`}
className="cursor-pointer transition text-foreground-lighter text-sm hover:text-brand-link flex gap-3"
className="cursor-pointer transition text-foreground-lighter text-sm hover:text-brand flex gap-3"
>
{icon && <img className="w-3" src={`${BASE_PATH}${icon}`} />}
{title}
@@ -99,7 +99,7 @@ const NavigationMenuCliList = ({ currentLevel, setLevel, id }) => {
href={`${menu.parent ?? '/'}`}
className={[
'flex items-center gap-1 text-xs group mb-3',
'text-base transition-all duration-200 text-brand-link hover:text-brand-600 hover:cursor-pointer ',
'text-base transition-all duration-200 text-brand hover:text-brand-600 hover:cursor-pointer ',
].join(' ')}
>
<div className="relative w-2">
@@ -43,7 +43,7 @@ const HeaderLink = React.memo(function HeaderLink(props: {
className={[
' ',
!props.title && 'capitalize',
props.url === pathname ? 'text-brand-link' : 'hover:text-brand-link text-foreground',
props.url === pathname ? 'text-brand' : 'hover:text-brand text-foreground',
].join(' ')}
>
{props.title ?? props.id}
@@ -111,7 +111,7 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any
'cursor-pointer transition text-sm',
'focus-inset rounded-md',
activeItem
? 'text-brand-link font-medium'
? 'text-brand font-medium'
: 'hover:text-foreground text-foreground-lighter',
].join(' ')}
>
@@ -146,8 +146,8 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any
'relative block py-1.25 pl-1 -ml-1 cursor-pointer transition text-sm',
'focus-inset rounded-md',
child.url === pathname
? 'text-brand-link'
: 'hover:text-brand-link text-foreground-lighter',
? 'text-brand'
: 'hover:text-brand text-foreground-lighter',
].join(' ')}
>
{child.url === pathname && (
@@ -173,9 +173,7 @@ const ContentAccordionLink = React.memo(function ContentAccordionLink(props: any
'flex items-center gap-2',
'cursor-pointer transition text-sm',
'focus-inset rounded-md',
activeItem
? 'text-brand-link font-medium'
: 'hover:text-foreground text-foreground-lighter',
activeItem ? 'text-brand font-medium' : 'hover:text-foreground text-foreground-lighter',
].join(' ')}
parent={props.subItem.parent}
>
@@ -206,9 +204,7 @@ const ContentLink = React.memo(function ContentLink(props: any) {
className={[
'cursor-pointer transition text-sm',
'focus-inset rounded-md',
props.url === pathname
? 'text-brand-link'
: 'hover:text-foreground text-foreground-lighter',
props.url === pathname ? 'text-brand' : 'hover:text-foreground text-foreground-lighter',
].join(' ')}
>
{props.icon && (
@@ -230,7 +226,7 @@ const Content = (props) => {
return (
<div className="relative w-full flex flex-col gap-0 pb-5">
<Link href={menu.url ?? ''}>
<div className="flex items-center gap-3 my-3 text-brand-link">
<div className="flex items-center gap-3 my-3 text-brand">
<MenuIconPicker icon={menu.icon} />
<HeaderLink title={menu.title} url={menu.url} id={id} />
</div>
@@ -132,7 +132,7 @@ const HeaderLogo = memo(() => {
height={navigationLogo?.height ?? 18}
alt="Supabase wordmark"
/>
<span className="font-mono text-sm font-medium text-brand-link mb-px">DOCS</span>
<span className="font-mono text-sm font-medium text-brand mb-px">DOCS</span>
</Link>
)
})
+5 -5
View File
@@ -80,7 +80,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
'py-1.5 px-5 rounded-sm text-sm transition',
`${
item.url === pathname
? 'bg-background text-brand-link'
? 'bg-background text-brand'
: 'text-foreground-light hover:text-foreground'
}`,
].join(' ')}
@@ -105,7 +105,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
size={14}
strokeWidth={2}
/>
<span className="text-foreground text-sm group-hover:text-brand-link transition">
<span className="text-foreground text-sm group-hover:text-brand transition">
{group.label}
</span>
</Accordion.Trigger>
@@ -119,7 +119,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
'py-1.5 px-5 rounded-sm text-sm transition',
`${
section.url === pathname
? 'bg-background text-brand-link'
? 'bg-background text-brand'
: 'text-foreground-light hover:text-foreground'
}`,
].join(' ')}
@@ -144,7 +144,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
size={14}
strokeWidth={2}
/>
<span className="text-foreground text-sm group-hover:text-brand-link transition">
<span className="text-foreground text-sm group-hover:text-brand transition">
{section.name}
</span>
</Accordion.Trigger>
@@ -157,7 +157,7 @@ const SideBar = ({ menuItems = [] }: { menuItems: any }) => {
'py-1.5 ml-4 px-5 rounded-sm text-sm transition',
`${
item.url === pathname
? 'bg-background text-brand-link'
? 'bg-background text-brand'
: 'text-foreground-light hover:text-foreground'
}`,
].join(' ')}
+1 -1
View File
@@ -40,7 +40,7 @@ function ClientLibHeader({ menuData, className }: ClientLibHeaderProps) {
href={menuData.pkg.repo}
target="_blank"
rel="noreferrer noopener"
className="hover:text-brand-link focus-visible:text-brand-link transition-colors"
className="hover:text-brand focus-visible:text-brand transition-colors"
>
<span className="sr-only">View on GitHub</span>
<Github size={18} />
+8 -8
View File
@@ -18,7 +18,7 @@ function PluginInstructions({ client }: { client: PluginClient }) {
href="https://claude.com/plugins/supabase"
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline"
className="text-brand hover:underline"
>
official Anthropic marketplace
</a>
@@ -53,7 +53,7 @@ function PluginInstructions({ client }: { client: PluginClient }) {
href="https://developers.openai.com/codex/plugins#plugin-directory-in-the-codex-app"
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline"
className="text-brand hover:underline"
>
Codex desktop app plugin directory
</a>
@@ -83,7 +83,7 @@ function PluginInstructions({ client }: { client: PluginClient }) {
href="https://cursor.com/marketplace/supabase"
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline"
className="text-brand hover:underline"
>
Supabase
</a>{' '}
@@ -118,7 +118,7 @@ function PluginInstructions({ client }: { client: PluginClient }) {
href="https://geminicli.com/extensions/?name=supabase-communitysupabase-plugin"
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline"
className="text-brand hover:underline"
>
Gemini CLI extensions directory
</a>
@@ -222,7 +222,7 @@ function PluginInstructions({ client }: { client: PluginClient }) {
href="https://github.com/vercel-labs/open-plugin-spec"
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline"
className="text-brand hover:underline"
>
Open Plugin
</a>{' '}
@@ -243,7 +243,7 @@ function PluginInstructions({ client }: { client: PluginClient }) {
href="https://github.com/supabase-community/supabase-plugin"
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline"
className="text-brand hover:underline"
>
GitHub repository
</a>
@@ -290,7 +290,7 @@ export function AgentPluginsPanel() {
href={selectedClient.docsUrl}
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline inline-flex items-center"
className="text-brand hover:underline inline-flex items-center"
>
{selectedClient.docsLinkText ?? `View ${selectedClient.label} extensions docs`}
<ExternalLink className="h-3 w-3 ml-1" />
@@ -302,7 +302,7 @@ export function AgentPluginsPanel() {
href={selectedClient.repoUrl}
target="_blank"
rel="noopener noreferrer"
className="text-brand-link hover:underline inline-flex items-center"
className="text-brand hover:underline inline-flex items-center"
>
Give feedback
<ExternalLink className="h-3 w-3 ml-1" />
+1 -1
View File
@@ -23,7 +23,7 @@ function Logo() {
height={18}
alt="Supabase logo"
/>
<span className="font-mono text-sm font-medium text-brand-link mb-px">KB</span>
<span className="font-mono text-sm font-medium text-brand mb-px">KB</span>
</a>
)
}
@@ -309,7 +309,9 @@ export const Grid = memo(
<div
className={cn(
'flex flex-col items-center justify-center w-full h-full mt-9 transition',
isTableEmpty && isDraggedOver && 'border-2 border-dashed border-brand'
isTableEmpty &&
isDraggedOver &&
'border-2 border-dashed border-brand-default'
)}
>
<p className="text-sm text-light pointer-events-auto">This table is empty</p>
@@ -190,7 +190,7 @@ export const ProviderForm = ({ config, provider, isActive }: ProviderFormProps)
meta={
isActive ? (
<div className="flex items-center gap-1 rounded-full border border-brand-400 bg-brand-200 py-1 px-1 text-xs text-brand">
<span className="rounded-full bg-brand p-0.5 text-xs text-brand-200">
<span className="rounded-full bg-brand-default p-0.5 text-xs text-brand-200">
<Check strokeWidth={2} size={12} />
</span>
<span className="px-1">Enabled</span>
@@ -117,7 +117,7 @@ export const HookCard = ({ hook, onSelectEdit, onSelectDelete }: HookCardProps)
<div className="flex items-center gap-x-2">
{hook.enabled ? (
<Badge className="space-x-1" variant="success">
<div className="h-3.5 w-3.5 bg-brand rounded-full flex justify-center items-center">
<div className="h-3.5 w-3.5 bg-brand-default rounded-full flex justify-center items-center">
<Check className="h-2 w-2 text-background-overlay " strokeWidth={6} />
</div>
<span>Enabled</span>
@@ -209,7 +209,7 @@ export const IntegrationCard = ({
<div className="shrink-0">
{true ? (
<Badge className="space-x-1" variant="success">
<div className="h-3.5 w-3.5 bg-brand rounded-full flex justify-center items-center">
<div className="h-3.5 w-3.5 bg-brand-default rounded-full flex justify-center items-center">
<Check className="h-2 w-2 text-background-overlay" strokeWidth={6} />
</div>
<span>Enabled</span>
@@ -274,7 +274,7 @@ export const UserOverview = ({ user, onDeleteSuccess }: UserOverviewProps) => {
</div>
{isActive ? (
<div className="flex items-center gap-1 rounded-full border border-brand-400 bg-brand-200 py-1 px-1 text-xs text-brand">
<span className="rounded-full bg-brand p-0.5 text-xs text-brand-200">
<span className="rounded-full bg-brand-default p-0.5 text-xs text-brand-200">
<Check strokeWidth={2} size={12} />
</span>
<span className="px-1">Enabled</span>
@@ -128,7 +128,11 @@ const BUILD_STATE_META: Record<ComputeInstanceBuildState, ComputeInstanceStateMe
dotClassName: 'bg-warning',
textClassName: 'text-foreground-light',
},
active: { label: 'Active', dotClassName: 'bg-brand', textClassName: 'text-foreground-light' },
active: {
label: 'Active',
dotClassName: 'bg-brand-default',
textClassName: 'text-foreground-light',
},
failed: {
label: 'Failed',
dotClassName: 'bg-destructive',
@@ -210,7 +210,7 @@ const ConnectOrganizationButton = ({
'pointer-events-none shadow-none transition-colors',
!disabled && !selected && 'group-hover:border-default group-hover:bg-surface-200',
selected &&
'border-brand bg-brand-200/20 dark:bg-brand-300 pr-10 group-hover:border-brand group-hover:bg-brand-200/20'
'border-brand-default bg-brand-200/20 dark:bg-brand-300 pr-10 group-hover:border-brand-default group-hover:bg-brand-200/20'
)}
/>
{selected && (
@@ -183,7 +183,7 @@ export const BigQueryFields = ({
{isDraggingFile ? (
<div
aria-hidden="true"
className="pointer-events-none absolute inset-0 rounded-md ring-2 ring-brand ring-offset-2 ring-offset-background"
className="pointer-events-none absolute inset-0 rounded-md ring-2 ring-brand-default ring-offset-2 ring-offset-background"
/>
) : null}
</div>
@@ -85,7 +85,7 @@ export const ReplicationNode = ({ id }: { id: string }) => {
<div
className={cn(
'w-2 h-2 rounded-full',
statusName === 'started' ? 'bg-brand' : 'bg-destructive'
statusName === 'started' ? 'bg-brand-default' : 'bg-destructive'
)}
/>
</div>
@@ -166,7 +166,7 @@ export const RowMenu = ({
/>
{hasUpdate && (
<span
className="absolute -top-0.5 -right-0.5 h-2 w-2 bg-brand rounded-full"
className="absolute -top-0.5 -right-0.5 h-2 w-2 bg-brand-default rounded-full"
aria-hidden
/>
)}
@@ -140,8 +140,8 @@ export const RoleRow = ({ role, disabled = false, onSelectDelete }: RoleRowProps
{role.activeConnections > 0 && (
<div className="relative h-2 w-2">
<span className="flex h-2 w-2">
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-brand opacity-75"></span>
<span className="relative inline-flex h-2 w-2 rounded-full bg-brand opacity-75"></span>
<span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-brand-default opacity-75"></span>
<span className="relative inline-flex h-2 w-2 rounded-full bg-brand-default opacity-75"></span>
</span>
</div>
)}
@@ -52,7 +52,9 @@ const DefaultEdgeComponent = ({
<BaseEdge
id={id}
path={edgePath}
className={cn(selected ? 'stroke-brand!' : isDownloading ? 'stroke-black!' : undefined)}
className={cn(
selected ? 'stroke-brand-default!' : isDownloading ? 'stroke-black!' : undefined
)}
stroke="#000000"
{...props}
/>
@@ -141,7 +143,7 @@ const EdgeRelationInfo = ({
<Badge
ref={checkIfShouldBeDisplayed}
className={cn(
'absolute pointer-events-auto z-50 p-1 rounded-[4px] gap-1 outline outline-1 outline-brand',
'absolute pointer-events-auto z-50 p-1 rounded-[4px] gap-1 outline outline-1 outline-brand-default',
show ? 'opacity-100' : 'opacity-0'
)}
style={{
@@ -72,7 +72,7 @@ const TableNodeComponent = ({
<header
className={cn(
'text-[0.55rem] px-2 py-1 border-[0.5px] rounded-[4px] bg-alternative flex gap-1 items-center',
hasEdgesSelected ? 'outline outline-1 outline-brand' : undefined
hasEdgesSelected ? 'outline outline-1 outline-brand-default' : undefined
)}
>
{data.name}
@@ -89,7 +89,7 @@ const TableNodeComponent = ({
<div
className={cn(
'border-[0.5px] overflow-hidden rounded-[4px] shadow-xs',
hasEdgesSelected ? 'outline outline-1 outline-brand' : undefined
hasEdgesSelected ? 'outline outline-1 outline-brand-default' : undefined
)}
style={{ width: TABLE_NODE_WIDTH / 2 }}
>
@@ -16,7 +16,7 @@ const constraintTokenClassName = cn(
export const ConstraintToken = ({ icon, label, variant = 'default' }: ConstraintTokenProps) => {
const tokenToneClassName =
variant === 'primary'
? 'bg-brand/10 text-brand-600 border-brand-500'
? 'bg-brand-default/10 text-brand-600 border-brand-500'
: variant === 'default'
? 'bg-surface-75 text-foreground-light border-strong'
: 'bg-surface-75/50 text-foreground-light border-strong'
@@ -498,7 +498,7 @@ export const TableList = ({
(table) => table.id === x.id
) ? (
<div className="flex items-center gap-x-2">
<Check size={16} strokeWidth={2} className="text-brand-link" />
<Check size={16} strokeWidth={2} className="text-brand" />
<p className="text-foreground-light">Enabled</p>
</div>
) : (
@@ -139,8 +139,8 @@ export const DiskManagementReviewAndSubmitDialog = ({
</div>
<div className="animate-badge-pulse absolute left-1/2 top-1/2 -translate-x-1/2 -translate-y-1/2 w-9 h-9 rounded-full bg-dash-sidebar border border-brand-500 flex items-center justify-center z-10 overflow-hidden">
<span className="absolute inset-0 bg-brand/10 rounded-full" />
<span className="animate-badge-shimmer pointer-events-none absolute inset-0 bg-linear-to-br from-transparent via-brand/20 to-transparent blur-md" />
<span className="absolute inset-0 bg-brand-default/10 rounded-full" />
<span className="animate-badge-shimmer pointer-events-none absolute inset-0 bg-linear-to-br from-transparent via-brand-default/20 to-transparent blur-md" />
<ArrowRight size={16} className="text-brand-600 relative z-10" strokeWidth={2.5} />
</div>
@@ -101,7 +101,7 @@ export const DiskSpaceBar = ({ form }: DiskSpaceBarProps) => {
<div
className={cn(
'h-[35px] relative border rounded-xs w-full transition overflow-visible',
showNewSize ? 'bg-selection border border-brand' : 'bg-surface-300'
showNewSize ? 'bg-selection border border-brand-default' : 'bg-surface-300'
)}
>
<AnimatePresence>
@@ -98,7 +98,7 @@ export function ExplainHeader({ mode, onToggleMode, summary, id, rows }: Explain
<span>Seq Scan (slow)</span>
</div>
<div className="flex items-center gap-1.5">
<span className="inline-block w-1.5 h-1.5 rounded-full bg-brand" />
<span className="inline-block w-1.5 h-1.5 rounded-full bg-brand-default" />
<span>Index Scan (fast)</span>
</div>
</div>
@@ -154,7 +154,7 @@ export function getScanBarColor(operation: string): string {
op.includes('index only scan') ||
op.includes('bitmap index scan')
) {
return 'bg-brand/20'
return 'bg-brand-default/20'
}
// Sequential scans are yellow
@@ -90,7 +90,7 @@ export const EdgeFunctionRecentInvocations = ({
<div
className={cn(
'flex items-center justify-center border px-1.5 py-0.5 rounded-sm text-xs font-mono',
is2xx && 'text-brand border-brand bg-brand-300',
is2xx && 'text-brand border-brand-default bg-brand-300',
is4xx && 'text-warning border-warning bg-warning-300',
is5xx && 'text-destructive border-destructive bg-destructive-300',
!is2xx &&
@@ -26,7 +26,7 @@ export const ResourceGroupSection = ({
) : (
group.badge && (
<Badge variant="success" className="gap-x-1.5">
<span className="h-1.5 w-1.5 rounded-full bg-brand" />
<span className="h-1.5 w-1.5 rounded-full bg-brand-default" />
{group.badge}
</Badge>
)
@@ -92,8 +92,8 @@ export const IntegrationCard = ({
</div>
{isInstalled && (
<div className="flex items-center gap-x-1">
<BadgeCheck size={14} className="text-brand-link" />
<span className="text-brand-link text-xs">Installed</span>
<BadgeCheck size={14} className="text-brand" />
<span className="text-brand text-xs">Installed</span>
</div>
)}
</div>
@@ -210,7 +210,7 @@ export const ActivityRow = ({
>
<TableCell className="relative w-[70px]">
{selectedPid === activity.pid && (
<div className="absolute h-full bg-brand top-0 left-0 w-1 bg-foreground-lighter" />
<div className="absolute h-full bg-brand-default top-0 left-0 w-1" />
)}
{/* Absolute (not inline in the flex row) so top-0/bottom-0 ignore the cell's padding and touch the adjacent row */}
@@ -47,7 +47,7 @@ const colorClassMap: Record<string, string> = {
muted: 'bg-gray-500',
destructive: 'bg-destructive',
warning: 'bg-warning',
brand: 'bg-brand',
brand: 'bg-brand-default',
}
const LEVEL_CHART_CONFIG: ChartConfig = {
@@ -169,12 +169,12 @@ function ControlCard({
'px-4 py-4 flex flex-col items-start justify-between',
'border rounded-md col-span-12 md:col-span-4 bg-surface-200',
shouldHighlight &&
'ring-4 ring-brand animate-[pulse_1.5s_ease-in-out_1] motion-reduce:animate-none shadow-md shadow-brand/40'
'ring-4 ring-brand-default animate-[pulse_1.5s_ease-in-out_1] motion-reduce:animate-none shadow-md shadow-brand-default/40'
)}
>
<div className="w-full">
<div className="flex items-center space-x-2">
<p className="text-brand-link text-sm uppercase">{plan.name}</p>
<p className="text-brand text-sm uppercase">{plan.name}</p>
{isCurrentPlan ? (
<div className="text-xs bg-surface-300 text-foreground-light rounded-sm px-2 py-0.5">
Current plan
@@ -264,7 +264,7 @@ function ParityCard({
'flex flex-col items-start justify-between',
'border rounded-md col-span-12 md:col-span-4 bg-surface-200',
shouldHighlight &&
'ring-4 ring-brand animate-[pulse_1.5s_ease-in-out_1] motion-reduce:animate-none shadow-md shadow-brand/40'
'ring-4 ring-brand-default animate-[pulse_1.5s_ease-in-out_1] motion-reduce:animate-none shadow-md shadow-brand-default/40'
)}
>
<div className="w-full px-4 pt-4">
@@ -396,7 +396,7 @@ export function CustomReportSection() {
</div>
<div className="relative">
{isDraggingOver && (
<div className="absolute inset-0 rounded-sm bg-brand/10 pointer-events-none z-10" />
<div className="absolute inset-0 rounded-sm bg-brand-default/10 pointer-events-none z-10" />
)}
{layout.length === 0 ? (
<div
@@ -332,7 +332,7 @@ export const ServiceStatus = () => {
(isProjectNew && service.status !== 'ACTIVE_HEALTHY')
? 'bg-foreground-lighter animate-pulse'
: service.status === 'ACTIVE_HEALTHY'
? 'bg-brand'
? 'bg-brand-default'
: 'bg-selection'
)}
/>
@@ -139,7 +139,9 @@ export const UtilityActions = ({
size={14}
strokeWidth={2}
className={
isFavorite ? 'fill-brand stroke-none' : 'fill-none stroke-foreground-light'
isFavorite
? 'fill-brand-default stroke-none'
: 'fill-none stroke-foreground-light'
}
/>
{isFavorite ? 'Remove from' : 'Add to'} favorites
@@ -198,7 +200,7 @@ export const UtilityActions = ({
size="tiny"
onClick={() => saveFavorite(id, false)}
className="px-1"
icon={<Heart className="fill-brand stroke-none" />}
icon={<Heart className="fill-brand-default stroke-none" />}
aria-label="Remove from favorites"
/>
) : (
@@ -46,7 +46,7 @@ export const CustomDomainDelete = ({ projectRef, customDomain }: CustomDomainDel
<p className="text-xs text-foreground-light">Active custom domain:</p>
<div className="flex items-center space-x-2">
<code className="text-lg mx-0 flex items-center space-x-2">
<div className="h-2 w-2 rounded-full bg-brand" />
<div className="h-2 w-2 rounded-full bg-brand-default" />
<span>
<code className="text-code-inline">{customDomain.hostname}</code>
</span>
@@ -311,7 +311,7 @@ export const ReplicaNode = ({ data }: NodeProps<Node<ReplicaNodeData>>) => {
type="horizontal"
value={stagePercent * 100}
max={100}
barClass="bg-brand"
barClass="bg-brand-default"
/>
</div>
</TooltipTrigger>
@@ -178,7 +178,7 @@ const MapView = () => {
<circle
r={4}
className={`animate-ping ${
hasNoDatabases ? 'fill-border-stronger' : 'fill-brand'
hasNoDatabases ? 'fill-border-stronger' : 'fill-brand-default'
}`}
/>
)}
@@ -188,7 +188,7 @@ const MapView = () => {
hasNoDatabases
? 'fill-background-surface-300 stroke-border-stronger'
: hasPrimary
? 'fill-brand stroke-brand-500'
? 'fill-brand-default stroke-brand-500'
: 'fill-brand-500 stroke-brand-400'
}`}
/>
@@ -418,7 +418,7 @@ export const LogsDatePicker = ({
size="tiny"
onClick={handleCopy}
className={cn({
'text-brand-link': copied || pasted,
'text-brand': copied || pasted,
})}
>
{copied ? 'Copied!' : pasted ? 'Pasted!' : 'Copy range'}
@@ -196,7 +196,7 @@ export const PreviewFilterPanel = ({
<div className="relative">
{newCount > 0 && (
<div className="absolute -top-3 -right-3 flex items-center justify-center">
<div className="absolute h-4 w-4 animate-ping rounded-full bg-brand opacity-60"></div>
<div className="absolute h-4 w-4 animate-ping rounded-full bg-brand-default opacity-60"></div>
<div className="relative z-10 flex h-4 min-w-4 items-center justify-center rounded-full bg-brand-500 px-1 text-[10px] font-medium leading-none text-white">
{newCount > 1000 ? `${Math.floor(newCount / 100) / 10}K` : newCount}
</div>
@@ -122,7 +122,7 @@ const PolicyAllowedOperations = ({ allowedOperations = [], onToggleOperation = (
className={cn(
'text-xs font-mono leading-[1.1] px-2 py-1 rounded-full border font-normal whitespace-nowrap transition-colors duration-200',
allowedClientLibraryMethods.includes(method)
? 'bg-brand/10 text-brand-600 border-brand-500'
? 'bg-brand-default/10 text-brand-600 border-brand-500'
: 'bg-surface-75 text-foreground-lighter border-muted'
)}
>
@@ -59,7 +59,7 @@ function LinkSupportTicketSuccess() {
<div className="flex flex-col items-center gap-y-4 py-8">
<div className="relative">
<Mail strokeWidth={1.5} size={60} className="text-brand" />
<div className="h-6 w-6 rounded-full bg-brand absolute bottom-1 -right-1.5 flex items-center justify-center">
<div className="h-6 w-6 rounded-full bg-brand-default absolute bottom-1 -right-1.5 flex items-center justify-center">
<Check strokeWidth={4} size={16} className="text-contrast" />
</div>
</div>
@@ -157,7 +157,10 @@ function SupportFormHeader() {
<Loader2 className="animate-spin" />
) : (
<div
className={cn('h-2 w-2 rounded-full', isIncident ? 'bg-warning' : 'bg-brand')}
className={cn(
'h-2 w-2 rounded-full',
isIncident ? 'bg-warning' : 'bg-brand-default'
)}
/>
)
}
@@ -137,7 +137,12 @@ export function SupportFormStatusButton() {
isLoading ? (
<Loader2 className="animate-spin" />
) : (
<div className={cn('h-2 w-2 rounded-full', isIncident ? 'bg-warning' : 'bg-brand')} />
<div
className={cn(
'h-2 w-2 rounded-full',
isIncident ? 'bg-warning' : 'bg-brand-default'
)}
/>
)
}
>
@@ -76,7 +76,7 @@ export const InsertButton = () => {
<div
className={cn([
'border border-foreground-light w-[15px] h-[4px] translate-x-0.5',
'transition duration-200 group-data-highlighted:border-brand group-data-highlighted:translate-x-0',
'transition duration-200 group-data-highlighted:border-brand-default group-data-highlighted:translate-x-0',
])}
/>
</div>
@@ -97,7 +97,7 @@ export const InsertButton = () => {
<div
className={cn([
'border border-foreground-light w-[4px] h-[15px] -translate-y-0.5',
'transition duration-200 group-data-highlighted:border-brand group-data-highlighted:translate-y-0',
'transition duration-200 group-data-highlighted:border-brand-default group-data-highlighted:translate-y-0',
])}
/>
</div>
@@ -76,7 +76,7 @@ export const AddRowOperationItem = ({
/>
</CardHeader>
<CardContent className="py-2 px-3 font-mono text-xs text-brand-link">
<CardContent className="py-2 px-3 font-mono text-xs text-brand">
{previewColumns.length === 0 && (
<span className="text-foreground-light">
No data provided, default values will be used
@@ -84,7 +84,7 @@ export const AddRowOperationItem = ({
)}
{previewColumns.map(([key, value]) => (
<div key={key} className="flex gap-2 py-0.5">
<span className="text-brand-link select-none font-medium">+</span>
<span className="text-brand select-none font-medium">+</span>
<span className="shrink-0">{key}:</span>
<span className="truncate min-w-0" title={formatOperationItemValue(value)}>
{formatOperationItemValue(value)}
@@ -93,7 +93,7 @@ export const AddRowOperationItem = ({
))}
{remainingCount > 0 && (
<div className="flex gap-2 py-0.5">
<span className="text-brand-link select-none font-medium">+</span>
<span className="text-brand select-none font-medium">+</span>
<span>+{remainingCount} more column(s)</span>
</div>
)}
@@ -82,8 +82,8 @@ export const OperationItem = ({ operationId, tableId, content }: OperationItemPr
</div>
<div className="flex gap-2 py-0.5">
<span className="text-brand-link select-none font-medium">+</span>
<span className="text-brand-link truncate max-w-full" title={formattedNewValue}>
<span className="text-brand select-none font-medium">+</span>
<span className="text-brand truncate max-w-full" title={formattedNewValue}>
{formattedNewValue}
</span>
</div>
@@ -592,7 +592,7 @@ export const createTable = async ({
value={progress}
max={100}
type="horizontal"
barClass="bg-brand"
barClass="bg-brand-default"
labelBottom={`Adding ${importContent.rowCount.toLocaleString()} rows to ${table.name}`}
labelBottomClass=""
labelTop={`${progress.toFixed(2)}%`}
@@ -629,7 +629,7 @@ export const createTable = async ({
value={progress}
max={100}
type="horizontal"
barClass="bg-brand"
barClass="bg-brand-default"
labelBottom={`Adding ${importContent.rows.length.toLocaleString()} rows to ${table.name}`}
labelTop={`${progress.toFixed(2)}%`}
labelTopClass="tabular-nums"
@@ -84,7 +84,7 @@ describe('AdvisorButton', () => {
expect(container.querySelector('.bg-warning')).toBeInTheDocument()
expect(container.querySelector('.bg-destructive')).not.toBeInTheDocument()
expect(container.querySelector('.bg-brand')).not.toBeInTheDocument()
expect(container.querySelector('.bg-brand-default')).not.toBeInTheDocument()
})
it('keeps the destructive dot when a critical issue is present', () => {
@@ -151,7 +151,7 @@ describe('AdvisorButton', () => {
const { container } = render(<AdvisorButton projectRef="project-ref" />)
expect(container.querySelector('.bg-brand')).toBeInTheDocument()
expect(container.querySelector('.bg-brand-default')).toBeInTheDocument()
expect(container.querySelector('.bg-warning')).not.toBeInTheDocument()
expect(container.querySelector('.bg-destructive')).not.toBeInTheDocument()
expect(screen.getByRole('button')).toBeInTheDocument()
@@ -86,7 +86,7 @@ export const AdvisorButton = ({ projectRef }: { projectRef?: string }) => {
) : hasWarningIssues ? (
<span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-warning" />
) : hasUnreadNotifications ? (
<span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-brand" />
<span className="absolute top-1.5 right-1.5 w-1.5 h-1.5 rounded-full bg-brand-default" />
) : null}
</div>
)
@@ -73,7 +73,7 @@ export const MergeRequestButton = () => {
icon={
<div className="relative">
{hasReviewRequested && (
<span className="w-1 h-1 absolute top-0 right-0 rounded-full bg-brand" />
<span className="w-1 h-1 absolute top-0 right-0 rounded-full bg-brand-default" />
)}
<GitMerge size={16} strokeWidth={1.5} />
</div>
@@ -428,7 +428,9 @@ export const SQLEditorTreeViewItem = ({
<Heart
size={14}
className={cn(
isFavorite ? 'fill-brand stroke-none' : 'fill-none stroke-foreground-light'
isFavorite
? 'fill-brand-default stroke-none'
: 'fill-none stroke-foreground-light'
)}
/>
{isFavorite ? 'Remove from' : 'Add to'} favorites
@@ -35,9 +35,9 @@ export const BannerFreeMicroUpgrade = () => {
<ComputeBadge
infraComputeSize="nano"
icon={<ChevronsUpAnimated />}
className="text-brand-600 border-brand-500 bg-brand/10 gap-1"
className="text-brand-600 border-brand-500 bg-brand-default/10 gap-1"
/>
<span className="animate-badge-shimmer pointer-events-none absolute inset-0 bg-linear-to-br from-transparent via-brand/20 to-transparent blur-md" />
<span className="animate-badge-shimmer pointer-events-none absolute inset-0 bg-linear-to-br from-transparent via-brand-default/20 to-transparent blur-md" />
</div>
</div>
</div>
@@ -49,8 +49,8 @@ export const BannerTableEditorQueueOperations = () => {
</div>
<div className="flex gap-2 py-0.5">
<span className="text-brand-link select-none font-medium">+</span>
<span className="text-brand-link truncate max-w-full">Blue</span>
<span className="text-brand select-none font-medium">+</span>
<span className="text-brand truncate max-w-full">Blue</span>
</div>
</CardContent>
</Card>
@@ -115,12 +115,12 @@ export const ComputeBadgeWrapper = ({
infraComputeSize={computeSize}
icon={showUpgradeGlow && <ChevronsUpAnimated />}
className={cn(
showUpgradeGlow && 'text-brand-600 border-brand-500 bg-brand/10 gap-1',
showUpgradeGlow && 'text-brand-600 border-brand-500 bg-brand-default/10 gap-1',
badgeClassName
)}
/>
{showUpgradeGlow && (
<span className="animate-badge-shimmer pointer-events-none absolute inset-0 bg-linear-to-br from-transparent via-brand/20 to-transparent blur-md" />
<span className="animate-badge-shimmer pointer-events-none absolute inset-0 bg-linear-to-br from-transparent via-brand-default/20 to-transparent blur-md" />
)}
</div>
</div>
+2 -2
View File
@@ -12,7 +12,7 @@ export const DotPing = ({ animate = true, variant = 'primary' }: DotPingProps) =
className={cn(
'absolute inset-0 rounded-full',
animate && 'animate-ping',
variant === 'primary' && 'bg-brand/20',
variant === 'primary' && 'bg-brand-default/20',
variant === 'default' && 'bg-selection/20',
variant === 'warning' && 'bg-warning/20'
)}
@@ -24,7 +24,7 @@ export const DotPing = ({ animate = true, variant = 'primary' }: DotPingProps) =
<span
className={cn(
'absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 inline-block w-2 h-2 rounded-full',
variant === 'primary' && 'bg-brand',
variant === 'primary' && 'bg-brand-default',
variant === 'default' && 'bg-selection',
variant === 'warning' && 'bg-warning'
)}
@@ -95,7 +95,7 @@ export const DatabaseConnections: NextPageWithLayout = () => {
<Tooltip>
<TooltipTrigger className="flex items-center">
<Badge variant="success">
<span className="h-1.5 w-1.5 bg-brand rounded-full animate-pulse" />
<span className="h-1.5 w-1.5 bg-brand-default rounded-full animate-pulse" />
<span>Live</span>
</Badge>
</TooltipTrigger>
+2 -2
View File
@@ -60,7 +60,7 @@
.rdg-cell {
border-left-color: hsl(var(--brand-default));
color: hsl(var(--brand-link));
color: var(--primary);
}
/* First cell gets a stronger left border to indicate new row */
@@ -329,7 +329,7 @@
}
.sb-grid-column-header__inner svg {
@apply border-brand text-brand;
@apply border-brand-default text-brand;
}
/*
+2 -2
View File
@@ -29,7 +29,7 @@
.rdg-row {
&.rdg-row--focused {
@apply border-r border-brand;
@apply border-r border-brand-default;
border-right-width: 4px;
}
@@ -71,7 +71,7 @@
.rdg-row {
&.rdg-row--focused {
@apply border-r border-brand;
@apply border-r border-brand-default;
border-right-width: 4px;
}
+1 -1
View File
@@ -303,7 +303,7 @@
::-moz-selection {
/* Code for Firefox */
@apply bg-brand;
@apply bg-brand-default;
color: #333 !important;
}
@@ -38,7 +38,7 @@ const page: GoPageInput = {
<div className="flex flex-wrap gap-4 justify-center mt-6">
<a
href="https://supabase.com/dashboard"
className="inline-flex items-center justify-center rounded-md bg-brand text-white px-5 py-2.5 text-sm font-medium hover:bg-brand/90 transition-colors"
className="inline-flex items-center justify-center rounded-md bg-brand-default text-white px-5 py-2.5 text-sm font-medium hover:bg-brand-default/90 transition-colors"
>
Start building with Supabase
</a>
@@ -138,7 +138,7 @@ const page: GoPageInput = {
className="group flex h-full flex-col gap-3 rounded-lg border border-muted bg-surface-100 p-5 text-left transition-colors hover:border-brand-600 hover:bg-surface-200"
>
<span className="text-sm text-foreground-lighter">Blog</span>
<span className="text-lg font-medium text-foreground group-hover:text-brand-link">
<span className="text-lg font-medium text-foreground group-hover:text-brand">
Introducing Supabase Pipelines
</span>
<span className="text-sm leading-relaxed text-foreground-light">
@@ -151,7 +151,7 @@ const page: GoPageInput = {
className="group flex h-full flex-col gap-3 rounded-lg border border-muted bg-surface-100 p-5 text-left transition-colors hover:border-brand-600 hover:bg-surface-200"
>
<span className="text-sm text-foreground-lighter">Docs</span>
<span className="text-lg font-medium text-foreground group-hover:text-brand-link">
<span className="text-lg font-medium text-foreground group-hover:text-brand">
Set up Pipelines
</span>
<span className="text-sm leading-relaxed text-foreground-light">
@@ -164,7 +164,7 @@ const page: GoPageInput = {
className="group flex h-full flex-col gap-3 rounded-lg border border-muted bg-surface-100 p-5 text-left transition-colors hover:border-brand-600 hover:bg-surface-200"
>
<span className="text-sm text-foreground-lighter">Guide</span>
<span className="text-lg font-medium text-foreground group-hover:text-brand-link">
<span className="text-lg font-medium text-foreground group-hover:text-brand">
Realtime or Pipelines?
</span>
<span className="text-sm leading-relaxed text-foreground-light">
@@ -24,7 +24,7 @@ export function QuoteSection({ quote, highlight, author }: QuoteSectionProps) {
{highlight && (
<>
{' '}
<span className="text-brand-link">{highlight}</span>
<span className="text-brand">{highlight}</span>
</>
)}
</p>
@@ -193,7 +193,7 @@ function IntegratedSkeleton() {
<div className="rounded-xl border border-border bg-surface-100 p-4">
<div className="flex flex-col gap-3">
<div className="flex items-center gap-2.5">
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-brand/15 text-[10px] font-medium text-brand">
<div className="flex h-8 w-8 shrink-0 items-center justify-center rounded-full bg-brand-default/15 text-[10px] font-medium text-brand">
CW
</div>
<div className="flex flex-col">
@@ -244,7 +244,7 @@ function IntegratedSkeleton() {
{/* Verify email card */}
<div className="rounded-xl border border-border bg-surface-100 p-4">
<div className="flex flex-col items-center gap-2.5">
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-brand/10">
<div className="flex h-8 w-8 items-center justify-center rounded-full bg-brand-default/10">
<svg
width="14"
height="14"
@@ -395,7 +395,7 @@ function IntegratedSkeleton() {
<span className="text-[10px] text-foreground">Authenticator app</span>
<span className="text-[9px] text-foreground-muted">TOTP via auth app</span>
</div>
<div className="rounded bg-brand/15 px-1.5 py-0.5 text-[8px] font-medium text-brand">
<div className="rounded bg-brand-default/15 px-1.5 py-0.5 text-[8px] font-medium text-brand">
On
</div>
</div>
@@ -478,7 +478,9 @@ function RealtimeSkeleton() {
key={msg.id}
className={cn(
'transition-colors duration-500',
tableFlashId === msg.id ? 'bg-brand/15 dark:bg-brand/5' : 'bg-surface-75'
tableFlashId === msg.id
? 'bg-brand-default/15 dark:bg-brand-default/5'
: 'bg-surface-75'
)}
>
<td className="border-b border-r border-default px-3 py-1.5 text-foreground-muted text-xs truncate max-w-0">
@@ -546,9 +548,9 @@ function RealtimeSkeleton() {
className={cn(
'max-w-[75%] px-3 py-1.5 rounded-xl text-xs leading-snug transition-colors duration-500',
isAlice
? 'bg-brand/15 text-foreground rounded-br-sm'
? 'bg-brand-default/15 text-foreground rounded-br-sm'
: 'bg-surface-300 text-foreground rounded-bl-sm',
chatFlashId === msg.id && 'ring-1 ring-brand/30'
chatFlashId === msg.id && 'ring-1 ring-brand-default/30'
)}
>
{msg.text}
@@ -140,7 +140,7 @@ export function SpreadsheetIllustration() {
<td
key={col.name}
className={`border-b border-r last:border-r-0 border-secondary px-3 py-1.5 max-w-[200px] ${
isEdited ? 'bg-brand/10' : ''
isEdited ? 'bg-brand-default/10' : ''
}`}
>
<span
@@ -177,7 +177,9 @@ function DatabaseChangesSkeleton() {
key={msg.id}
className={cn(
'transition-colors duration-500',
tableFlashId === msg.id ? 'bg-brand/15 dark:bg-brand/5' : 'bg-surface-75'
tableFlashId === msg.id
? 'bg-brand-default/15 dark:bg-brand-default/5'
: 'bg-surface-75'
)}
>
<td className="border-b border-r border-default px-3 py-1.5 text-foreground-muted text-xs truncate max-w-0">
@@ -245,9 +247,9 @@ function DatabaseChangesSkeleton() {
className={cn(
'max-w-[75%] px-3 py-1.5 rounded-xl text-xs leading-snug transition-colors duration-500',
isAlice
? 'bg-brand/15 text-foreground rounded-br-sm'
? 'bg-brand-default/15 text-foreground rounded-br-sm'
: 'bg-surface-300 text-foreground rounded-bl-sm',
chatFlashId === msg.id && 'ring-1 ring-brand/30'
chatFlashId === msg.id && 'ring-1 ring-brand-default/30'
)}
>
{msg.text}
@@ -626,7 +628,7 @@ function BroadcastSkeleton() {
key={i}
className={cn(
'absolute bottom-6 z-10 flex h-10 w-10 -translate-x-1/2 items-center justify-center rounded-xl border bg-surface-100 shadow-xs dark:shadow-sm transition-all duration-300',
isFlashing ? 'border-brand text-brand' : 'border-border text-foreground-muted'
isFlashing ? 'border-brand-default text-brand' : 'border-border text-foreground-muted'
)}
style={{ left: `${xPercent}%` }}
>
@@ -38,7 +38,7 @@ function InteroperableSkeleton() {
{[0, 1].map((i) => (
<div
key={`left-conn-${i}`}
className="relative h-[1.5px] w-full overflow-hidden bg-brand/18 [mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)] [webkit-mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)]"
className="relative h-[1.5px] w-full overflow-hidden bg-brand-default/18 [mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)] [webkit-mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)]"
>
<div
className="absolute inset-y-0 left-0 w-24 [animation:interopLineSweep_1.05s_linear_infinite]"
@@ -55,7 +55,7 @@ function InteroperableSkeleton() {
{[0, 1].map((i) => (
<div
key={`right-conn-${i}`}
className="relative h-[1.5px] w-full overflow-hidden bg-brand/18 [mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)] [webkit-mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)]"
className="relative h-[1.5px] w-full overflow-hidden bg-brand-default/18 [mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)] [webkit-mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)]"
>
<div
className="absolute inset-y-0 left-0 w-24 [animation:interopLineSweep_1.05s_linear_infinite]"
@@ -153,7 +153,7 @@ function CDNSkeleton() {
{[-20, -10, 0, 10, 20].map((offset, i) => (
<div
key={`flash-${offset}`}
className="relative h-px w-full overflow-hidden bg-brand/15 [mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)] [webkit-mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)]"
className="relative h-px w-full overflow-hidden bg-brand-default/15 [mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)] [webkit-mask-image:linear-gradient(to_right,transparent,black_20%,black_80%,transparent)]"
style={{ transform: `translateY(${offset}px)` }}
>
<div
@@ -177,7 +177,7 @@ function CDNSkeleton() {
<div className="relative flex h-[116px] w-[116px] items-center justify-center rounded-[24px] border border-foreground/15 bg-surface-200/95 shadow-[0_8px_28px_hsl(var(--background-default)/0.24)]">
<div className="absolute inset-0 rounded-[24px] shadow-[inset_0_1px_0_hsl(var(--foreground-default)/0.06)]" />
<div className="absolute size-10 rounded-full bg-brand/15 blur-xl" />
<div className="absolute size-10 rounded-full bg-brand-default/15 blur-xl" />
<svg
width="48"
height="48"
@@ -361,7 +361,7 @@ function PartnerDetails({
<span className="text-lighter">Category</span>
<Link
href={`/partners/catalog?cat=${encodeURIComponent(category.slug)}`}
className="text-brand-link hover:underline transition-colors"
className="text-brand hover:underline transition-colors"
>
{category.name}
</Link>
@@ -379,7 +379,7 @@ function PartnerDetails({
}
target="_blank"
rel="noreferrer"
className="text-brand-link hover:underline transition-colors"
className="text-brand hover:underline transition-colors"
>
{(() => {
try {
@@ -402,7 +402,7 @@ function PartnerDetails({
href={activeListing.docsUrl}
target="_blank"
rel="noreferrer"
className="text-brand-link hover:underline transition-colors"
className="text-brand hover:underline transition-colors"
>
<span className="flex items-center space-x-1">
<span>Learn</span>
@@ -97,9 +97,8 @@ function FloatingTableOfContents({
href={`#chapter-${chapterIndex + 1}`}
onClick={() => setIsTocOpen(false)}
className={cn(
'block px-6 py-2 text-xs transition-colors font-mono uppercase tracking-wider text-center text-foreground-light hover:text-brand-link hover:bg-brand-300/25',
chapterIndex + 1 === activeChapter &&
'bg-brand-300/40 text-brand-link dark:text-brand'
'block px-6 py-2 text-xs transition-colors font-mono uppercase tracking-wider text-center text-foreground-light hover:text-brand hover:bg-brand-300/25',
chapterIndex + 1 === activeChapter && 'bg-brand-300/40 text-brand'
)}
>
{chapter.shortTitle}
@@ -227,7 +226,7 @@ export default function StateOfStartups2026Content() {
<li key={chapterIndex + 1}>
<Link
href={`#chapter-${chapterIndex + 1}`}
className="group flex flex-row gap-5 py-3 pl-7 pr-8 font-mono uppercase tracking-wide text-sm transition-all text-foreground-light hover:text-brand-link hover:bg-brand-300/25"
className="group flex flex-row gap-5 py-3 pl-7 pr-8 font-mono uppercase tracking-wide text-sm transition-all text-foreground-light hover:text-brand hover:bg-brand-300/25"
>
<span className="text-xs rounded-full bg-surface-75 border border-surface-200 group-hover:border-brand-500/40 w-5 h-5 flex items-center justify-center group-hover:bg-brand-600/5">
{chapterIndex + 1}
@@ -29,7 +29,7 @@ export function CohortToggle({ eyebrow, options, value, onValueChange }: CohortT
onClick={() => onValueChange(option.label)}
className={`px-3 py-1 text-xs font-mono uppercase tracking-wider border rounded-full transition-colors ${
isActive
? 'border-brand-500/40 bg-brand-300/40 text-brand-link dark:text-brand'
? 'border-brand-500/40 bg-brand-300/40 text-brand'
: 'border-overlay text-foreground-light hover:text-foreground hover:bg-surface-100'
}`}
>
@@ -11,7 +11,7 @@ interface ProgressBarProps {
export function ProgressBar({
className = 'h-4',
backgroundClassName = 'bg-foreground-muted/80',
foregroundClassName = 'bg-brand',
foregroundClassName = 'bg-brand-default',
animationDelay,
reverse = false,
}: ProgressBarProps) {
@@ -62,7 +62,7 @@ const PROGRESS_BARS = [
{
height: 'h-8',
bgColor: 'bg-foreground-muted/50',
fgColor: 'bg-brand',
fgColor: 'bg-brand-default',
animationDelay: '0.3s',
},
{
@@ -68,7 +68,7 @@ export function ParticipantsCarousel({ participants }: { participants: Participa
href={participant.url}
target="_blank"
rel="noopener noreferrer"
className="text-xs md:text-sm font-mono tracking-widest uppercase text-foreground-lighter hover:text-brand-link transition-colors whitespace-nowrap"
className="text-xs md:text-sm font-mono tracking-widest uppercase text-foreground-lighter hover:text-brand transition-colors whitespace-nowrap"
>
{participant.company}
</Link>
@@ -13,15 +13,13 @@ export function SectionCallout({ eyebrow, body, href, cta, external }: SectionCa
return (
<div className="border-t border-muted px-8 py-8">
<div className="bg-surface-100/60 border border-muted rounded-lg p-6 flex flex-col gap-3">
<span className="text-brand-link dark:text-brand text-xs font-mono uppercase tracking-widest">
{eyebrow}
</span>
<span className="text-brand text-xs font-mono uppercase tracking-widest">{eyebrow}</span>
<p className="text-foreground-light text-balance">{body}</p>
<Link
href={href}
target={external ? '_blank' : undefined}
rel={external ? 'noopener noreferrer' : undefined}
className="inline-flex items-center gap-1 text-brand-link dark:text-brand text-sm font-medium hover:underline w-fit"
className="inline-flex items-center gap-1 text-brand text-sm font-medium hover:underline w-fit"
>
{cta}
<ArrowUpRight size={14} strokeWidth={2} />
@@ -74,7 +74,7 @@ export function SurveyChannelMixChart({
}}
/>
<div
className={`h-full relative ${cohorts[ci].tone === 'accent' ? 'bg-brand' : 'bg-foreground-light'}`}
className={`h-full relative ${cohorts[ci].tone === 'accent' ? 'bg-brand-default' : 'bg-foreground-light'}`}
style={{ width: `${v ?? 0}%` }}
/>
</div>
@@ -56,9 +56,7 @@ export function SurveyChapter({
{/* Text content */}
<div className="max-w-240 mx-auto grid gap-y-4 sm:gap-y-8 grid-cols-1 md:grid-cols-3 text-balance pb-12">
<div className="md:col-span-2 flex flex-col gap-4 px-8">
<p
className={`text-sm uppercase font-mono text-balance tracking-wider text-brand-link`}
>
<p className={`text-sm uppercase font-mono text-balance tracking-wider text-brand`}>
{shortTitle}
</p>
<h2 className="text-4xl md:text-5xl xl:text-6xl text-balance leading-tight tracking-tight">
@@ -49,7 +49,7 @@ export function SurveyChapterSection({ section }: { section: SurveySection }) {
return { [cohortToggle.key]: option.filter }
}, [cohortToggle, cohortLabel])
const eyebrowColor = 'text-brand-link dark:text-brand'
const eyebrowColor = 'text-brand'
// A section can be compared across years only if it has any 2025 data. New-in-
// 2026 questions (share of codebase, auth, agents, MCP, the AI-codebase
@@ -25,8 +25,8 @@ interface SurveyChartProps {
maxBars?: number
}
const accentBarFg = 'bg-brand'
const accentBarText = 'text-brand-link dark:text-brand'
const accentBarFg = 'bg-brand-default'
const accentBarText = 'text-brand'
export function SurveyChart({
title,
@@ -63,7 +63,7 @@ export function ChartLegend({
<div key={item.label} className="flex items-center gap-2">
<span
className={`inline-block ${item.variant === 'line' ? 'w-4 h-[3px]' : 'w-3 h-3'} ${
item.tone === 'accent' ? 'bg-brand' : 'bg-foreground-light'
item.tone === 'accent' ? 'bg-brand-default' : 'bg-foreground-light'
}`}
/>
<span className="text-foreground-light text-xs font-mono uppercase tracking-widest">
@@ -120,7 +120,7 @@ export function SurveyPullQuoteCarousel({ quotes }: { quotes: CarouselPullQuote[
}}
>
<div
className="absolute inset-0 pointer-events-none bg-brand"
className="absolute inset-0 pointer-events-none bg-brand-default"
style={{
maskImage: 'url("/images/state-of-startups/pattern-checker.svg")',
maskSize: '4px',
@@ -24,7 +24,7 @@ export function SurveyPullQuoteGrid({ quotes }: { quotes: PullQuoteGridItem[] })
{quotes.map((q, i) => (
<div key={i} className="flex flex-col gap-4 px-8 py-12">
{q.theme && (
<span className="text-brand-link dark:text-brand text-xs font-mono uppercase tracking-widest">
<span className="text-brand text-xs font-mono uppercase tracking-widest">
{q.theme}
</span>
)}
@@ -9,7 +9,7 @@ export function SurveyRankedAnswersPair({
}) {
const accent = useAccent()
const accentBlocks = ['bg-brand', 'bg-brand-500', 'bg-brand-300']
const accentBlocks = ['bg-brand-default', 'bg-brand-500', 'bg-brand-300']
const accentRankText = 'text-brand'
@@ -27,7 +27,7 @@ export function SurveyStatCard({ label, query, value, cohortFilter }: SurveyStat
const cardRef = useRef<HTMLDivElement>(null)
const { year } = useYear()
const accentBg = 'bg-brand'
const accentBg = 'bg-brand-default'
const accentText = 'text-brand'
// A static `value` wins; otherwise resolve from the embedded dataset for the
@@ -14,7 +14,7 @@ export function SurveySummarizedAnswer({ label, answers }: { label: string; answ
const [isBlinking, setIsBlinking] = useState(false)
const accent = useAccent()
const accentBg = 'bg-brand'
const accentBg = 'bg-brand-default'
useEffect(() => {
if (answers.length <= 1) return
@@ -18,7 +18,7 @@ export function SurveyWordCloud({
const [scramblingTexts, setScramblingTexts] = useState<string[]>([])
const accent = useAccent()
const accentBg = 'bg-brand'
const accentBg = 'bg-brand-default'
// Calculate the range within the current context
const counts = answers.map((answer) => answer.count)
@@ -198,7 +198,7 @@ function PreviousResultsCta() {
<div className="w-fit bg-brand-300 px-5 py-3 text-[1.75rem] leading-8 tracking-tight text-brand md:text-[2.25rem] md:leading-10">
of
</div>
<div className="w-fit bg-brand px-5 py-3 text-[1.75rem] leading-8 tracking-tight text-background dark:text-brand-200 md:text-[2.25rem] md:leading-10">
<div className="w-fit bg-brand-default px-5 py-3 text-[1.75rem] leading-8 tracking-tight text-background dark:text-brand-200 md:text-[2.25rem] md:leading-10">
Startups
</div>
<div className="w-fit bg-brand-500 px-5 py-3 text-[1.75rem] leading-8 tracking-tight text-brand-300 md:text-[2.25rem] md:leading-10">
+1 -1
View File
@@ -4,7 +4,7 @@ import { Button } from 'ui'
export function Hero() {
return (
<header className="container relative mx-auto px-6 pt-12 pb-8 lg:pt-24 lg:px-16 xl:px-20 text-center space-y-4">
<h1 className="text-sm text-brand-link md:text-base">
<h1 className="text-sm text-brand md:text-base">
<span className="sr-only">Supabase </span>Contribute
</h1>
<h2 className="text-3xl md:text-4xl xl:text-5xl lg:max-w-2xl xl:max-w-6xl lg:mx-auto tracking-[-1px]">
@@ -19,7 +19,7 @@ export const markdownComponents: Components = {
a: ({ node, ...props }) => (
<a
{...props}
className="text-brand-link hover:underline break-all"
className="text-brand hover:underline break-all"
target="_blank"
rel="noopener noreferrer"
/>
+1 -1
View File
@@ -104,7 +104,7 @@ const EnterpriseFormQuotes = ({
<div className="relative w-full h-px bg-border-strong opacity-80 group-hover:opacity-100 rounded-full overflow-hidden">
<motion.div
className={cn(
'absolute motion-reduce:hidden inset-0 w-full right-full bg-brand h-full transition-all',
'absolute motion-reduce:hidden inset-0 w-full right-full bg-brand-default h-full transition-all',
progress! > 99.7 ? 'opacity-0' : 'opacity-100'
)}
style={{ x: `${progress! - 100}%` }}
+1 -1
View File
@@ -63,7 +63,7 @@ export function EventList() {
<div
className={cn(
'absolute top-2 left-[-59px] rounded-full size-1.5',
index === 0 ? 'bg-brand size-2 left-[-60px]' : 'bg-foreground-muted'
index === 0 ? 'bg-brand-default size-2 left-[-60px]' : 'bg-foreground-muted'
)}
/>
Loaded 100 of 166 files, more files were not shown because too many files have changed in this diff. Show more