mirror of
https://github.com/supabase/supabase.git
synced 2026-10-05 01:15:03 +03:00
fix(ui): align primary colours across text, buttons, and controls (#50697)
## Problem Primary colour serves readable text and selected controls, but those uses need different shades. Light mode needs darker text, while dark mode needs a deeper button fill. Fixed brand green on interactive chrome also prevents a custom primary hue from carrying through the interface. Some slider tracks and selected text are hard to read. ## Solution - Keep `--primary` for accessible text and small selected indicators. Use `--primary-solid` for button fills, which need a deeper shade in dark mode. - Add `--primary-bright` for focus rings, selected control chrome, chart accents, and other interactive highlights. It follows `--primary-hue`; `brand-*` stays fixed for Supabase identity. - Make slider troughs clearer and text selection translucent with theme foreground text. - Document the split in the design-system colour guide. | Before | After | | --- | --- | | <img width="980" height="244" alt="Before: light mode primary controls" src="https://github.com/user-attachments/assets/dfae325d-0dfe-4231-8bcd-3f89c4b9d793" /> | <img width="982" height="204" alt="After: light mode primary controls" src="https://github.com/user-attachments/assets/5fdcb531-a6e3-4549-8a13-9d9a5ebe6e20" /> | | <img width="610" height="120" alt="Before: slider track" src="https://github.com/user-attachments/assets/04f768e0-51e8-4d06-9b97-c52f4a34f122" /> | <img width="622" height="126" alt="After: slider track" src="https://github.com/user-attachments/assets/95127f4e-13dc-4f0f-b63c-cf5d70a28b42" /> | | <img width="652" height="512" alt="Before: dark mode controls" src="https://github.com/user-attachments/assets/3f88de66-90cc-40ee-8cf1-b5f4eb87b09a" /> | <img width="658" height="498" alt="After: dark mode controls" src="https://github.com/user-attachments/assets/906bec30-6ca1-4614-9fb3-6cf5e5feec22" /> | ## Review instructions 1. Compare light and dark mode in the [colour usage guide](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/color-usage#primary-and-brand-colors). Check primary ink, primary-solid, primary-bright, and fixed brand swatches. 2. In Studio, open the ‘new table’ sheet in [Table Editor](https://studio-staging-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/dashboard/project/_/editor). Tab through the new table sheet's fields and toggles. Check the focus rings, selected controls, and the sheet's edges in both themes. You do not need to save a table. 3. Select text in Studio in both themes, including a link or primary-coloured label. The selection and text should remain legible. 4. Check the [Field](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/components/field) Price Range slider: the unused track should remain visible in both themes. The selected field card border should follow primary-bright. 5. Check the [Button](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/components/button) and [Radio Group](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/components/radio-group) previews. In dark mode, `primary` button fill should be deeper than primary [text](https://design-system-git-dnywh-fix-bright-brand-chrome-supabase.vercel.app/design-system/docs/color-usage#text); selected radios should remain readable.
This commit is contained in:
1 parent
76c4f2b739
commit
d067e81a69
68 files changed
+276
-189
No files matched your search
@@ -14,7 +14,11 @@
|
||||
--color-popover: var(--popover);
|
||||
--color-popover-foreground: var(--popover-foreground);
|
||||
--color-primary: var(--primary);
|
||||
--color-primary-hover: var(--primary-hover);
|
||||
--color-primary-bright: var(--primary-bright);
|
||||
--color-primary-foreground: var(--primary-foreground);
|
||||
--color-primary-solid: var(--primary-solid);
|
||||
--color-primary-solid-foreground: var(--primary-solid-foreground);
|
||||
--color-secondary: var(--secondary);
|
||||
--color-secondary-foreground: var(--secondary-foreground);
|
||||
--color-tertiary: var(--tertiary);
|
||||
@@ -74,7 +78,7 @@
|
||||
--color-brand-400: hsl(var(--brand-400));
|
||||
--color-brand-500: hsl(var(--brand-500));
|
||||
--color-brand-600: hsl(var(--brand-600));
|
||||
/* Alias leftover bg-brand / border-brand to the bright fill. Prefer brand-default / primary. */
|
||||
/* Brand remains the fixed Supabase palette. Functional chrome uses primary. */
|
||||
--color-brand: hsl(var(--brand-default));
|
||||
--color-brand-default: hsl(var(--brand-default));
|
||||
--color-_secondary-200: hsl(var(--secondary-200));
|
||||
@@ -334,6 +338,7 @@
|
||||
--color-border-warning: var(--border-warning);
|
||||
--color-border-info: var(--border-info);
|
||||
--color-border-brand-default: var(--border-brand-default);
|
||||
--color-border-primary-bright: var(--border-primary-bright);
|
||||
/*
|
||||
* This will generate colors only for border utilities
|
||||
* i.e. bg-muted and they'll only have border-color: var(--border-muted) rule
|
||||
|
||||
@@ -20,8 +20,8 @@ const DIMMED_FILL_OPACITY = 0.35
|
||||
const CHART_COLORS = {
|
||||
TICK: 'var(--background-overlay-hover)',
|
||||
AXIS: 'var(--background-overlay-hover)',
|
||||
BRAND: 'hsl(var(--brand-default))',
|
||||
BRAND_HOVER: 'hsl(var(--brand-500))',
|
||||
PRIMARY: 'var(--primary-bright)',
|
||||
PRIMARY_HOVER: 'var(--primary-bright-hover)',
|
||||
}
|
||||
|
||||
export type ChartBarTick =
|
||||
@@ -97,8 +97,8 @@ export const ChartBar = ({
|
||||
DateTimeFormat = 'MMM D, YYYY, hh:mma',
|
||||
isFullHeight = false,
|
||||
className,
|
||||
color = CHART_COLORS.BRAND,
|
||||
hoverColor = CHART_COLORS.BRAND_HOVER,
|
||||
color = CHART_COLORS.PRIMARY,
|
||||
hoverColor = CHART_COLORS.PRIMARY_HOVER,
|
||||
chartHighlight,
|
||||
syncId,
|
||||
showHighlightArea = true,
|
||||
|
||||
@@ -18,8 +18,8 @@ import { ChartConfig, ChartContainer, ChartTooltip, ChartTooltipContent, cn } fr
|
||||
const CHART_COLORS = {
|
||||
TICK: 'var(--background-overlay-hover)',
|
||||
AXIS: 'var(--background-overlay-hover)',
|
||||
BRAND: 'hsl(var(--brand-default))',
|
||||
BRAND_HOVER: 'hsl(var(--brand-500))',
|
||||
PRIMARY: 'var(--primary-bright)',
|
||||
PRIMARY_HOVER: 'var(--primary-bright-hover)',
|
||||
}
|
||||
|
||||
export type ChartLineTick =
|
||||
@@ -104,7 +104,7 @@ export const ChartLine = ({
|
||||
DateTimeFormat = 'MMM D, YYYY, hh:mma',
|
||||
isFullHeight = false,
|
||||
className,
|
||||
color = CHART_COLORS.BRAND,
|
||||
color = CHART_COLORS.PRIMARY,
|
||||
chartHighlight,
|
||||
syncId,
|
||||
showHighlightArea = true,
|
||||
|
||||
@@ -448,7 +448,7 @@ const ChartDisabledState = ({ icon, label, description, actions }: ChartDisabled
|
||||
{
|
||||
demo: {
|
||||
label: 'Demo',
|
||||
color: 'hsl(var(--brand-default))',
|
||||
color: 'var(--primary-bright)',
|
||||
},
|
||||
} satisfies ChartConfig
|
||||
}
|
||||
@@ -457,7 +457,7 @@ const ChartDisabledState = ({ icon, label, description, actions }: ChartDisabled
|
||||
<BarChart data={demoData}>
|
||||
<XAxis dataKey="period_start" hide />
|
||||
<YAxis hide />
|
||||
<Bar dataKey="demo" fill="hsl(var(--brand-default))" />
|
||||
<Bar dataKey="demo" fill="var(--primary-bright)" />
|
||||
</BarChart>
|
||||
</ChartContainer>
|
||||
</div>
|
||||
@@ -584,8 +584,8 @@ const ChartSparkline = React.forwardRef<HTMLDivElement, ChartSparklineProps>(
|
||||
<AreaChart data={data} margin={{ top: 5, left: 0, right: 0, bottom: 0 }}>
|
||||
<defs>
|
||||
<linearGradient id="sparklineGradient" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="hsl(var(--brand-default))" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="hsl(var(--brand-default))" stopOpacity={0} />
|
||||
<stop offset="5%" stopColor="var(--primary-bright)" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="var(--primary-bright)" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<RechartsTooltip content={<ChartSparklineTooltip />} />
|
||||
@@ -594,7 +594,7 @@ const ChartSparkline = React.forwardRef<HTMLDivElement, ChartSparklineProps>(
|
||||
dataKey={dataKey || 'value'}
|
||||
fill="url(#sparklineGradient)"
|
||||
fillOpacity={0.1}
|
||||
stroke="hsl(var(--brand-default))"
|
||||
stroke="var(--primary-bright)"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
</AreaChart>
|
||||
|
||||
@@ -265,7 +265,7 @@ export function FilterCondition({
|
||||
className={cn(
|
||||
'flex items-stretch px-0 h-[26px] bg-muted group shrink-0',
|
||||
variant === 'pill' ? 'rounded-sm border' : 'border-r',
|
||||
isHighlighted && 'ring-2 ring-primary'
|
||||
isHighlighted && 'ring-2 ring-primary-bright'
|
||||
)}
|
||||
data-testid={`filter-condition-${property.name}`}
|
||||
data-highlighted={isHighlighted}
|
||||
|
||||
@@ -263,8 +263,8 @@ const MetricCardSparkline = React.forwardRef<HTMLDivElement, MetricCardSparkline
|
||||
<AreaChart data={data} margin={{ top: 5, left: 0, right: 0, bottom: 0 }}>
|
||||
<defs>
|
||||
<linearGradient id="sparklineGradient" x1="0" y1="0" x2="0" y2="1">
|
||||
<stop offset="5%" stopColor="hsl(var(--brand-default))" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="hsl(var(--brand-default))" stopOpacity={0} />
|
||||
<stop offset="5%" stopColor="var(--primary-bright)" stopOpacity={0.8} />
|
||||
<stop offset="95%" stopColor="var(--primary-bright)" stopOpacity={0} />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
<RechartsTooltip content={<SparklineTooltip />} />
|
||||
@@ -273,7 +273,7 @@ const MetricCardSparkline = React.forwardRef<HTMLDivElement, MetricCardSparkline
|
||||
dataKey={dataKey || 'value'}
|
||||
fill="url(#sparklineGradient)"
|
||||
fillOpacity={0.1}
|
||||
stroke="hsl(var(--brand-default))"
|
||||
stroke="var(--primary-bright)"
|
||||
strokeWidth={1.5}
|
||||
/>
|
||||
</AreaChart>
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
* and the brand, so the two could never drift apart. They are now split so a
|
||||
* theme can run, say, a cool-gray surface against the green brand:
|
||||
* --surface-hue tints backgrounds, text and borders (the neutral ramp)
|
||||
* --primary-hue is the brand hue that --primary is built from
|
||||
* --primary-hue is the spot hue that functional primary colors use
|
||||
* Both default to --hue (Supabase green ≈157.5° in OKLCH), so a theme that only
|
||||
* sets --hue keeps surfaces and brand locked together as before; override
|
||||
* either one to let them diverge. */
|
||||
@@ -150,7 +150,7 @@
|
||||
);
|
||||
/* Inverse of --foreground: canvas-coloured text for use on inverted fills
|
||||
(bg-foreground, bg-black / dark:bg-white, etc). Not the same as
|
||||
--primary-foreground, which stays light for the dark primary fill. */
|
||||
--primary-solid-foreground, which stays light on the deep button plate. */
|
||||
--foreground-contrast: oklch(var(--surface) calc(var(--chroma) * 0.55) var(--surface-hue));
|
||||
|
||||
--card: oklch(from var(--background) calc(l + var(--elevation-step) * var(--elevation-1)) c h);
|
||||
@@ -159,14 +159,22 @@
|
||||
--popover-foreground: var(--foreground);
|
||||
|
||||
/*
|
||||
* Primary is the accessible functional green (text, controls). Bright
|
||||
* expressive fills use brand-default. Light theme overrides --primary for AA text.
|
||||
* Primary ink vs primary solid fill:
|
||||
* --primary Readable branded text / small indicators. Root
|
||||
* values mirror dark theme (bright). Light theme
|
||||
* overrides for AA text on light surfaces.
|
||||
* --primary-solid Deeper button plate (dark mode). Light theme
|
||||
* aliases these to --primary so ink and buttons
|
||||
* share one green there.
|
||||
* --primary-bright keeps rings and selected chrome vivid while sharing the
|
||||
* hue of --primary. It is brighter than readable ink in light mode.
|
||||
*
|
||||
* Hover shifts lightness only (preserves hue/chroma). Mixing with --foreground
|
||||
* pulls light-mode surface-hue (warm) into the green and reads as yellow.
|
||||
* Sign of --tone-span: darken in light, lighten in dark.
|
||||
*/
|
||||
--primary: oklch(0.76 0.15 var(--primary-hue));
|
||||
--primary-bright: oklch(from var(--primary) max(l, 0.7) max(c, 0.15) h);
|
||||
--button-fill-hover-delta: 0.04;
|
||||
--primary-hover: oklch(
|
||||
from var(--primary)
|
||||
@@ -176,10 +184,29 @@
|
||||
)
|
||||
c h
|
||||
);
|
||||
--primary-bright-hover: oklch(
|
||||
from var(--primary-bright)
|
||||
calc(
|
||||
l + var(--button-fill-hover-delta) * var(--tone-span) /
|
||||
max(var(--tone-span), calc(var(--tone-span) * -1))
|
||||
)
|
||||
c h
|
||||
);
|
||||
--primary-foreground: oklch(
|
||||
min(var(--surface), var(--foreground-lightness)) calc(var(--chroma) * 0.45) var(--primary-hue)
|
||||
);
|
||||
|
||||
--primary-solid: oklch(0.43627 0.11 var(--primary-hue));
|
||||
--primary-solid-hover: oklch(
|
||||
from var(--primary-solid)
|
||||
calc(
|
||||
l + var(--button-fill-hover-delta) * var(--tone-span) /
|
||||
max(var(--tone-span), calc(var(--tone-span) * -1))
|
||||
)
|
||||
c h
|
||||
);
|
||||
--primary-solid-foreground: oklch(0.95 0.00275 var(--primary-hue));
|
||||
|
||||
--secondary: oklch(
|
||||
from var(--background) calc(l + var(--elevation-step) * var(--elevation-3)) c h
|
||||
);
|
||||
@@ -274,7 +301,9 @@
|
||||
--border-destructive: oklch(from var(--destructive) l c h / 30%);
|
||||
--border-warning: oklch(from var(--warning) l c h / 30%);
|
||||
--border-info: oklch(from var(--info) l c h / 30%);
|
||||
--border-brand-default: oklch(from var(--primary) l c h / 30%);
|
||||
/* Keep the brand border for explicitly Supabase-branded surfaces. */
|
||||
--border-brand-default: oklch(from hsl(var(--brand-default)) l c h / 30%);
|
||||
--border-primary-bright: oklch(from var(--primary-bright) l c h / 30%);
|
||||
|
||||
--border: oklch(
|
||||
from var(--foreground) l calc(c * 0.54) h / calc(2% + 20% * var(--contrast-border))
|
||||
@@ -290,5 +319,6 @@
|
||||
--border-control-hover: oklch(
|
||||
from var(--foreground) l calc(c * 0.5) h / calc(12% + 58% * var(--contrast-border))
|
||||
);
|
||||
--ring: oklch(from var(--primary) l c h / 55%);
|
||||
/* Focus chrome follows the theme's primary hue without muddy light-mode ink. */
|
||||
--ring: oklch(from var(--primary-bright) l c h / 55%);
|
||||
}
|
||||
@@ -16,9 +16,14 @@
|
||||
--foreground-lightness: 0.1;
|
||||
--muted-foreground-level: 0.65;
|
||||
--tertiary-foreground-level: 0.5;
|
||||
/* Accessible primary for text/controls (~4.5:1+ on light surfaces). */
|
||||
/* Accessible primary for text and small indicators on light surfaces (~4.5:1+).
|
||||
Solid button plates alias to the same green in light mode. Focus rings and
|
||||
bright interactive chrome uses --primary-bright. */
|
||||
--primary: oklch(0.525 0.12 var(--primary-hue));
|
||||
--primary-foreground: oklch(0.99 0.00275 var(--primary-hue));
|
||||
--primary-solid: var(--primary);
|
||||
--primary-solid-foreground: var(--primary-foreground);
|
||||
--primary-solid-hover: var(--primary-hover);
|
||||
/*
|
||||
* Expressive fills run darker than the dark-theme anchors so they hold contrast
|
||||
* against the near-white surface (a light amber on white disappears). Lightness
|
||||
|
||||
@@ -32,7 +32,7 @@ describe('#Button', () => {
|
||||
const button = screen.getByRole('button', { name: 'Neutral' })
|
||||
expect(button.className).toContain('bg-card')
|
||||
expect(button.className).toContain('hover:bg-muted')
|
||||
expect(button.className).not.toContain('bg-primary')
|
||||
expect(button.className).not.toContain('bg-primary-solid')
|
||||
})
|
||||
|
||||
it('should apply tiny size classes when buttonVariants omits size', () => {
|
||||
@@ -45,7 +45,7 @@ describe('#Button', () => {
|
||||
render(<Button variant="primary">Primary</Button>)
|
||||
|
||||
const button = screen.getByRole('button', { name: 'Primary' })
|
||||
expect(button.className).toContain('bg-primary')
|
||||
expect(button.className).toContain('bg-primary-solid')
|
||||
})
|
||||
|
||||
it('should render different text', () => {
|
||||
|
||||
@@ -38,12 +38,12 @@ const buttonVariants = cva(
|
||||
variant: {
|
||||
primary: `
|
||||
border-0
|
||||
bg-primary
|
||||
bg-primary-solid
|
||||
bg-[linear-gradient(to_bottom,hsl(var(--colors-white)/0.015),hsl(var(--colors-black)/0.01))]
|
||||
text-primary-foreground
|
||||
text-primary-solid-foreground
|
||||
shadow-[var(--button-shadow-raised)]
|
||||
hover:bg-[var(--primary-hover)]
|
||||
data-[state=open]:bg-[var(--primary-hover)]
|
||||
hover:bg-[var(--primary-solid-hover)]
|
||||
data-[state=open]:bg-[var(--primary-solid-hover)]
|
||||
`,
|
||||
default: `
|
||||
text-foreground
|
||||
@@ -76,12 +76,12 @@ const buttonVariants = cva(
|
||||
data-[state=open]:border-control-hover
|
||||
`,
|
||||
link: `
|
||||
text-brand-600
|
||||
text-primary
|
||||
border
|
||||
border-transparent/0
|
||||
hover:bg-brand-400
|
||||
hover:bg-primary-bright/15
|
||||
shadow-none
|
||||
data-[state=open]:bg-brand-400
|
||||
data-[state=open]:bg-primary-bright/15
|
||||
`,
|
||||
text: `
|
||||
text-foreground
|
||||
@@ -155,13 +155,13 @@ const IconContainerVariants = cva('inline-flex items-center justify-center shrin
|
||||
xxxlarge: '[&_svg]:h-[42px] [&_svg]:w-[42px]',
|
||||
},
|
||||
variant: {
|
||||
primary: 'text-primary-foreground/50',
|
||||
primary: 'text-primary-solid-foreground/50',
|
||||
default: 'text-foreground-lighter',
|
||||
secondary: 'text-background',
|
||||
alternative: 'text-foreground-lighter',
|
||||
outline: 'text-foreground-lighter',
|
||||
dashed: 'text-foreground-lighter',
|
||||
link: 'text-brand-600',
|
||||
link: 'text-primary',
|
||||
text: 'text-foreground-lighter',
|
||||
danger: 'text-destructive-foreground/50',
|
||||
warning: 'text-warning-foreground/50',
|
||||
@@ -173,13 +173,13 @@ export type LoadingVariantProps = VariantProps<typeof loadingVariants>
|
||||
const loadingVariants = cva('', {
|
||||
variants: {
|
||||
variant: {
|
||||
primary: 'text-primary-foreground/50',
|
||||
primary: 'text-primary-solid-foreground/50',
|
||||
default: 'text-foreground-lighter',
|
||||
secondary: 'text-background',
|
||||
alternative: 'text-foreground-lighter',
|
||||
outline: 'text-foreground-lighter',
|
||||
dashed: 'text-foreground-lighter',
|
||||
link: 'text-brand-600',
|
||||
link: 'text-primary',
|
||||
text: 'text-foreground-muted',
|
||||
danger: 'text-destructive-foreground/50',
|
||||
warning: 'text-warning-foreground/50',
|
||||
|
||||
@@ -75,7 +75,7 @@ export const menuItemVariants = cva(
|
||||
type: 'border',
|
||||
active: true,
|
||||
className:
|
||||
'text-foreground-muted border-l border-brand-default group-hover:border-brand-default',
|
||||
'text-foreground-muted border-l border-primary-bright group-hover:border-primary-bright',
|
||||
},
|
||||
{
|
||||
type: 'border',
|
||||
|
||||
@@ -12,7 +12,8 @@ const buttonVariants = cva(
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground hover:bg-[var(--primary-hover)]',
|
||||
default:
|
||||
'bg-primary-solid text-primary-solid-foreground hover:bg-[var(--primary-solid-hover)]',
|
||||
destructive: 'bg-destructive text-destructive-foreground hover:bg-destructive/90',
|
||||
outline: 'border border-control bg-background hover:bg-accent hover:text-accent-foreground',
|
||||
secondary: 'bg-secondary text-secondary-foreground hover:bg-secondary/80',
|
||||
|
||||
@@ -83,7 +83,8 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
|
||||
day_button
|
||||
),
|
||||
selected: cn(
|
||||
!fullDateRangeSelected && 'bg-brand-400! dark:bg-brand-500! text-foreground rounded-md',
|
||||
!fullDateRangeSelected &&
|
||||
'bg-primary-bright/70! dark:bg-primary-bright/25! text-foreground rounded-md',
|
||||
selected
|
||||
),
|
||||
// Plain accent — range/selected fills use ! so they still win when today is in the selection
|
||||
@@ -94,15 +95,17 @@ function Calendar({ className, classNames, showOutsideDays = true, ...props }: C
|
||||
),
|
||||
disabled: cn('text-foreground-muted opacity-50', disabled),
|
||||
range_start: cn(
|
||||
fullDateRangeSelected && 'bg-brand-400! dark:bg-brand-500! text-foreground rounded-l-md',
|
||||
fullDateRangeSelected &&
|
||||
'bg-primary-bright/70! dark:bg-primary-bright/25! text-foreground rounded-l-md',
|
||||
range_start
|
||||
),
|
||||
range_middle: cn(
|
||||
'bg-brand-200! dark:bg-brand-400! text-foreground rounded-none',
|
||||
'bg-primary-bright/25! dark:bg-primary-bright/12! text-foreground rounded-none',
|
||||
range_middle
|
||||
),
|
||||
range_end: cn(
|
||||
fullDateRangeSelected && 'bg-brand-400! dark:bg-brand-500! text-foreground rounded-r-md',
|
||||
fullDateRangeSelected &&
|
||||
'bg-primary-bright/70! dark:bg-primary-bright/25! text-foreground rounded-r-md',
|
||||
range_end
|
||||
),
|
||||
hidden: cn('invisible', hidden),
|
||||
|
||||
@@ -106,7 +106,7 @@ function FieldLabel({ className, ...props }: React.ComponentProps<typeof Label>)
|
||||
className={cn(
|
||||
'group/field-label peer/field-label flex w-fit gap-2 leading-snug group-data-[disabled=true]/field:opacity-50',
|
||||
'has-[>[data-slot=field]]:w-full has-[>[data-slot=field]]:flex-col has-[>[data-slot=field]]:rounded-md has-[>[data-slot=field]]:border *:data-[slot=field]:p-4',
|
||||
'has-data-[state=checked]:bg-primary/5 has-data-[state=checked]:border-primary dark:has-data-[state=checked]:bg-primary/10',
|
||||
'has-data-[state=checked]:bg-primary-bright/5 has-data-[state=checked]:border-primary-bright dark:has-data-[state=checked]:bg-primary-bright/10',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
|
||||
@@ -30,7 +30,7 @@ function Slider({
|
||||
>
|
||||
<SliderPrimitive.Track
|
||||
data-slot="slider-track"
|
||||
className="relative h-1 w-full grow overflow-hidden rounded-full bg-surface-300"
|
||||
className="relative h-1 w-full grow overflow-hidden rounded-full bg-border-stronger"
|
||||
>
|
||||
<SliderPrimitive.Range
|
||||
data-slot="slider-range"
|
||||
|
||||
@@ -7,7 +7,7 @@ import * as React from 'react'
|
||||
import { cn } from '../../../lib/utils/cn'
|
||||
|
||||
const switchRootVariants = cva(
|
||||
'peer inline-flex shrink-0 cursor-pointer items-center rounded-full border transition-colors focus-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-brand-default data-[state=checked]:hover:bg-brand-600/90 data-[state=unchecked]:bg-control data-[state=unchecked]:hover:bg-border',
|
||||
'peer inline-flex shrink-0 cursor-pointer items-center rounded-full border transition-colors focus-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary-bright data-[state=checked]:hover:bg-[var(--primary-bright-hover)] data-[state=unchecked]:bg-control data-[state=unchecked]:hover:bg-border',
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
@@ -23,7 +23,7 @@ const switchRootVariants = cva(
|
||||
)
|
||||
|
||||
const switchThumbVariants = cva(
|
||||
'pointer-events-none block rounded-full bg-foreground-lighter data-[state=checked]:bg-white shadow-lg ring-0 transition-transform',
|
||||
'pointer-events-none block rounded-full bg-foreground-lighter data-[state=checked]:bg-black shadow-lg ring-0 transition-transform',
|
||||
{
|
||||
variants: {
|
||||
size: {
|
||||
|
||||
@@ -60,6 +60,7 @@ export default {
|
||||
'bg-brand-500',
|
||||
'bg-brand-600',
|
||||
'bg-brand-default',
|
||||
'bg-primary-bright',
|
||||
'bg-_secondary-200',
|
||||
'bg-_secondary-400',
|
||||
'bg-_secondary',
|
||||
|
||||
Reference in new issue
Block a user