fix: Consistency across buttons and labels

This commit is contained in:
Dries Augustyns
2026-04-24 13:35:25 +02:00
parent 517753c420
commit c1bcd358cc
40 changed files with 195 additions and 276 deletions
+3 -2
View File
@@ -8,8 +8,9 @@ const alertVariants = cva(
variants: {
variant: {
default: 'bg-white text-neutral-950',
destructive: 'border-red-500/50 text-red-900 [&>svg]:text-red-900',
warning: 'bg-amber-50 border-amber-200 text-amber-900 [&>svg]:text-amber-600',
destructive: 'border-red-200 bg-red-50 text-red-900 [&>svg]:text-red-600',
warning: 'border-amber-200 bg-amber-50 text-amber-900 [&>svg]:text-amber-600',
success: 'border-green-200 bg-green-50 text-green-900 [&>svg]:text-green-600',
},
},
defaultVariants: {
+4 -9
View File
@@ -4,22 +4,17 @@ import * as React from 'react';
import {cn} from '../../lib';
const badgeVariants = cva(
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2',
'inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-1 focus:ring-ring focus:ring-offset-2',
{
variants: {
variant: {
default: 'border-transparent bg-neutral-100 text-neutral-900',
secondary: 'border-transparent bg-neutral-100 text-neutral-900',
destructive: 'border-transparent bg-red-100 text-red-900',
outline: 'text-neutral-950',
success: 'border-transparent bg-green-100 text-green-900',
warning: 'border-transparent bg-yellow-100 text-yellow-900',
// Additional semantic variants for common use cases
info: 'border-transparent bg-blue-100 text-blue-900',
orange: 'border-transparent bg-orange-100 text-orange-800',
green: 'border-transparent bg-green-100 text-green-800',
red: 'border-transparent bg-red-100 text-red-800',
neutral: 'border-transparent bg-neutral-50 text-neutral-600',
destructive: 'border-transparent bg-red-100 text-red-900',
success: 'border-transparent bg-green-100 text-green-900',
warning: 'border-transparent bg-amber-100 text-amber-900',
},
},
defaultVariants: {
+2 -1
View File
@@ -10,10 +10,11 @@ const buttonVariants = cva(
variants: {
variant: {
default: 'bg-neutral-900 text-neutral-50 hover:bg-neutral-900/90',
destructive: 'bg-red-500 text-neutral-50 hover:bg-red-500/90',
destructive: 'bg-red-600 text-white hover:bg-red-600/90',
outline: 'border border-neutral-200 bg-white hover:bg-neutral-100 hover:text-neutral-900',
secondary: 'bg-neutral-100 text-neutral-900 hover:bg-neutral-100/80',
ghost: 'hover:bg-neutral-100 hover:text-neutral-900',
destructiveGhost: 'text-red-600 hover:text-red-700 hover:bg-red-50',
link: 'text-neutral-900 underline-offset-4 hover:underline',
},
size: {
+1 -1
View File
@@ -5,7 +5,7 @@ import {cn} from '../../lib';
const Card = React.forwardRef<HTMLDivElement, React.HTMLAttributes<HTMLDivElement>>(({className, ...props}, ref) => (
<div
ref={ref}
className={cn('rounded-xl border border-neutral-200 bg-white text-neutral-950 shadow-sm overflow-hidden', className)}
className={cn('rounded-lg border border-neutral-200 bg-white text-neutral-950 shadow-sm overflow-hidden', className)}
{...props}
/>
));
@@ -13,7 +13,7 @@ const Checkbox = React.forwardRef<
<CheckboxPrimitive.Root
ref={ref}
className={cn(
'peer h-4 w-4 shrink-0 rounded-sm border border-neutral-200 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-neutral-900 data-[state=checked]:text-neutral-50',
'peer h-4 w-4 shrink-0 rounded-sm border border-neutral-200 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-neutral-900 data-[state=checked]:text-neutral-50',
className,
)}
{...props}
+1 -1
View File
@@ -42,7 +42,7 @@ const DialogContent = React.forwardRef<
{...props}
>
{children}
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-60 ring-offset-white transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 p-1.5">
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-md opacity-60 ring-offset-white transition-opacity hover:opacity-100 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-neutral-100 data-[state=open]:text-neutral-500 p-1.5">
<X className="h-5 w-5 sm:h-5 sm:w-5" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
+1 -1
View File
@@ -122,7 +122,7 @@ const FormMessage = React.forwardRef<HTMLParagraphElement, React.HTMLAttributes<
}
return (
<p ref={ref} id={formMessageId} className={cn('text-[0.8rem] font-medium text-red-500', className)} {...props}>
<p ref={ref} id={formMessageId} className={cn('text-[0.8rem] font-medium text-red-600', className)} {...props}>
{body}
</p>
);
@@ -22,7 +22,7 @@ const RadioGroupItem = React.forwardRef<
<RadioGroupPrimitive.Item
ref={ref}
className={cn(
'aspect-square h-4 w-4 rounded-full border border-neutral-200 text-neutral-900 ring-offset-white focus:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
'aspect-square h-4 w-4 rounded-full border border-neutral-200 text-neutral-900 ring-offset-white focus:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
className,
)}
{...props}
+1 -1
View File
@@ -17,7 +17,7 @@ const SelectTrigger = React.forwardRef<
<SelectPrimitive.Trigger
ref={ref}
className={cn(
'flex h-10 w-full items-center justify-between rounded-md border border-neutral-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-neutral-500 focus:outline-none focus:ring-1 focus:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
'flex h-10 w-full items-center justify-between rounded-md border border-neutral-200 bg-white px-3 py-2 text-sm ring-offset-white placeholder:text-neutral-500 focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1',
className,
)}
{...props}
+1 -1
View File
@@ -8,7 +8,7 @@ const Switch = React.forwardRef<
>(({className, ...props}, ref) => (
<SwitchPrimitives.Root
className={cn(
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-neutral-900 data-[state=unchecked]:bg-neutral-200',
'peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-white disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-neutral-900 data-[state=unchecked]:bg-neutral-200',
className,
)}
{...props}
+2 -2
View File
@@ -29,7 +29,7 @@ const TabsTrigger = React.forwardRef<
<TabsPrimitive.Trigger
ref={ref}
className={cn(
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-white transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-neutral-950 data-[state=active]:shadow-sm',
'inline-flex items-center justify-center whitespace-nowrap rounded-sm px-3 py-1.5 text-sm font-medium ring-offset-white transition-all hover:text-neutral-900 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-white data-[state=active]:text-neutral-950 data-[state=active]:shadow-sm',
className,
)}
{...props}
@@ -44,7 +44,7 @@ const TabsContent = React.forwardRef<
<TabsPrimitive.Content
ref={ref}
className={cn(
'mt-2 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-neutral-950 focus-visible:ring-offset-2',
'mt-2 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2',
className,
)}
{...props}
@@ -1,31 +1,27 @@
import type {LucideIcon} from 'lucide-react';
import * as React from 'react';
import type {ReactNode} from 'react';
import {cn} from '../../lib';
import {Button} from '../atoms';
export interface EmptyStateProps {
icon: LucideIcon;
title: string;
description?: string;
action?: {
label: string;
onClick: () => void;
};
action?: ReactNode;
className?: string;
}
export function EmptyState({icon: Icon, title, description, action, className}: EmptyStateProps) {
return (
<div className={cn('text-center py-12', className)}>
<Icon className="h-12 w-12 mx-auto text-neutral-400 mb-4" />
<h3 className="text-lg font-medium text-neutral-900 mb-2">{title}</h3>
{description && <p className="text-sm text-neutral-500 mb-6 max-w-md mx-auto">{description}</p>}
{action && (
<Button onClick={action.onClick} variant="default">
{action.label}
</Button>
<div className={cn('text-center py-14', className)}>
<div className="inline-flex items-center justify-center w-10 h-10 rounded-md border border-neutral-200 bg-neutral-50 mb-4">
<Icon className="h-5 w-5 text-neutral-400" />
</div>
<h3 className="text-sm font-semibold text-neutral-900 mb-1">{title}</h3>
{description && (
<p className="text-sm text-neutral-500 max-w-xs mx-auto leading-relaxed mb-5">{description}</p>
)}
{action}
</div>
);
}