refactor(ui): switch surfaces to shared shadow tokens

This commit is contained in:
2026-04-21 21:43:17 -04:00
parent e0b6120cd3
commit a2d9782d8f
20 changed files with 63 additions and 52 deletions

View File

@@ -283,7 +283,7 @@ export const AIToolbar = ({
) : isAuthenticated ? (
<div className="grid gap-3 lg:grid-cols-[minmax(0,1fr)_minmax(0,1fr)]">
<div className="space-y-3">
<div className="rounded-[10px] bg-card shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_2px_2px_rgba(0,0,0,0.04),0_0_0_1px_#fafafa] focus-within:ring-[3px] focus-within:ring-ring/20">
<div className="rounded-[10px] bg-card shadow focus-within:ring-[3px] focus-within:ring-ring/20">
<Textarea
id="ai-event-prompt"
className="wrap-anywhere field-sizing-content min-h-48 w-full resize-none rounded-none border-0 bg-transparent px-4 py-3 text-sm shadow-none placeholder:text-muted-foreground/50 focus-visible:ring-0 focus-visible:ring-offset-0"
@@ -416,18 +416,20 @@ export const AIToolbar = ({
</div>
</div>
<div className="rounded-[10px] bg-card p-3 shadow-[0_0_0_1px_rgba(0,0,0,0.08)]">
<div className="rounded-[10px] bg-card p-3 shadow-sm">
<div className="mb-3 flex items-start justify-between gap-3">
<div>
<p className="text-xs font-medium uppercase tracking-[0.18em] text-muted-foreground">
Attachments
</p>
<p className="mt-1 text-sm leading-6 text-muted-foreground">
Add screenshots, flyers, or pasted images alongside the prompt.
Add screenshots, flyers, or pasted images alongside the
prompt.
</p>
</div>
<span className="rounded-full bg-muted px-2.5 py-1 text-xs font-medium text-muted-foreground">
{imagePreviews.length} file{imagePreviews.length === 1 ? "" : "s"}
{imagePreviews.length} file
{imagePreviews.length === 1 ? "" : "s"}
</span>
</div>

View File

@@ -29,7 +29,7 @@ interface EventCardProps {
}
export const EVENT_CARD_SURFACE_CLASSES =
"group cursor-pointer rounded-[10px] bg-card p-4 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_2px_2px_rgba(0,0,0,0.04),0_0_0_1px_#fafafa] transition-[background-color,transform,box-shadow] duration-150 hover:-translate-y-0.5 hover:bg-accent/20";
"group cursor-pointer rounded-[10px] bg-card p-4 shadow transition-[background-color,transform,box-shadow] duration-150 hover:-translate-y-0.5 hover:bg-accent/20";
export const EventCard = ({ event, onEdit, onDelete }: EventCardProps) => {
const validationIssues = getEventValidationIssues(event);

View File

@@ -147,8 +147,8 @@ export const EventDialog = ({
return (
<Dialog open={open} onOpenChange={handleOpenChange}>
<DialogContent className="max-w-2xl rounded-[10px] bg-card p-0 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_12px_40px_rgba(0,0,0,0.12)]">
<DialogHeader className="border-b border-foreground/10 px-6 py-5">
<DialogContent className="max-w-2xl rounded-[10px] bg-card p-0 shadow-xl">
<DialogHeader className="px-6 py-5 shadow-[inset_0_-1px_0_0_var(--color-border)]">
<DialogTitle className="text-[28px] tracking-[-0.06em]">
{titleText}
</DialogTitle>
@@ -176,7 +176,9 @@ export const EventDialog = ({
{...register("title")}
/>
{errors.title && (
<p className="text-xs text-destructive">{errors.title.message}</p>
<p className="text-xs text-destructive">
{errors.title.message}
</p>
)}
</div>
@@ -209,7 +211,9 @@ export const EventDialog = ({
<Label htmlFor="event-url">URL</Label>
<Input id="event-url" placeholder="URL" {...register("url")} />
{errors.url && (
<p className="text-xs text-destructive">{errors.url.message}</p>
<p className="text-xs text-destructive">
{errors.url.message}
</p>
)}
</div>
</div>
@@ -293,7 +297,9 @@ export const EventDialog = ({
)}
/>
{errors.start && (
<p className="text-xs text-destructive">{errors.start.message}</p>
<p className="text-xs text-destructive">
{errors.start.message}
</p>
)}
{errors.end && (
<p className="text-xs text-destructive">{errors.end.message}</p>

View File

@@ -189,7 +189,7 @@ const ServerLocationInput = ({
value={value}
/>
{showSuggestions ? (
<div className="absolute left-0 right-0 top-[calc(100%+0.375rem)] z-20 rounded-[10px] bg-popover p-1.5 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_8px_24px_rgba(0,0,0,0.08)]">
<div className="absolute left-0 right-0 top-[calc(100%+0.375rem)] z-20 rounded-[10px] bg-popover p-1.5 shadow-lg">
<div className="space-y-1" role="listbox">
{suggestions.map((suggestion) => {
const suggestionKey =

View File

@@ -13,8 +13,7 @@ interface SettingsPanelProps {
settings: UserSettings;
}
const settingRowClasses =
"rounded-[10px] bg-card p-4 shadow-[0_0_0_1px_rgba(0,0,0,0.08)]";
const settingRowClasses = "rounded-[10px] bg-card p-4 shadow-sm";
export function SettingsPanel({
adminAiEnabled,
@@ -74,7 +73,7 @@ export function SettingsPanel({
</div>
<Label
htmlFor="settings-skip-ai-review"
className="min-h-11 cursor-pointer justify-between rounded-[8px] bg-muted px-3 py-2 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]"
className="min-h-11 cursor-pointer justify-between rounded-[8px] bg-secondary px-3 py-2 shadow-[inset_0_0_0_1px_var(--color-border)]"
>
<span className="text-sm font-medium text-foreground">
{settings.skipAiReview
@@ -115,7 +114,7 @@ export function SettingsPanel({
</div>
<Label
htmlFor="settings-ai-enabled"
className="min-h-11 cursor-pointer justify-between rounded-[8px] bg-muted px-3 py-2 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]"
className="min-h-11 cursor-pointer justify-between rounded-[8px] bg-secondary px-3 py-2 shadow-[inset_0_0_0_1px_var(--color-border)]"
>
<span className="text-sm font-medium text-foreground">
{settings.aiEnabled
@@ -151,7 +150,7 @@ export function SettingsPanel({
</p>
</div>
<dl className="grid gap-3 sm:grid-cols-2 lg:grid-cols-1">
<div className="rounded-[8px] bg-muted p-3 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]">
<div className="rounded-[8px] bg-secondary p-3 shadow-[inset_0_0_0_1px_var(--color-border)]">
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
Direct create preference
</dt>
@@ -161,7 +160,7 @@ export function SettingsPanel({
: `${valuePrefix}: off`}
</dd>
</div>
<div className="rounded-[8px] bg-muted p-3 shadow-[inset_0_0_0_1px_rgba(0,0,0,0.05)]">
<div className="rounded-[8px] bg-secondary p-3 shadow-[inset_0_0_0_1px_var(--color-border)]">
<dt className="text-xs font-semibold uppercase tracking-[0.18em] text-muted-foreground">
AI integrations
</dt>

View File

@@ -10,13 +10,12 @@ const badgeVariants = cva(
variants: {
variant: {
default:
"bg-secondary text-secondary-foreground shadow-[0_0_0_1px_rgba(0,0,0,0.08)] [a&]:hover:bg-accent",
"bg-secondary text-secondary-foreground shadow-sm [a&]:hover:bg-accent",
secondary:
"bg-[#ebf5ff] text-[#0068d6] shadow-[0_0_0_1px_rgba(0,0,0,0.08)] [a&]:hover:opacity-90",
"bg-[#ebf5ff] text-[#0068d6] shadow-sm [a&]:hover:opacity-90",
destructive:
"bg-destructive/12 text-destructive shadow-[0_0_0_1px_rgba(255,91,79,0.2)] [a&]:hover:bg-destructive/18 focus-visible:ring-destructive/25",
outline:
"bg-background text-foreground shadow-[0_0_0_1px_rgba(0,0,0,0.08)] [a&]:hover:bg-accent",
outline: "bg-background text-foreground shadow-sm [a&]:hover:bg-accent",
},
},
defaultVariants: {

View File

@@ -12,10 +12,9 @@ const buttonVariants = cva(
default: "bg-primary text-primary-foreground hover:opacity-92",
destructive:
"bg-destructive text-destructive-foreground hover:opacity-92 focus-visible:ring-destructive/25 dark:focus-visible:ring-destructive/35",
outline:
"bg-background text-foreground shadow-[0_0_0_1px_rgba(0,0,0,0.08)] hover:bg-accent",
outline: "bg-background text-foreground shadow-xs hover:bg-accent",
secondary:
"bg-secondary text-secondary-foreground shadow-[0_0_0_1px_rgba(0,0,0,0.05)] hover:bg-accent",
"bg-secondary text-secondary-foreground shadow-sm hover:bg-accent",
ghost: "text-muted-foreground hover:bg-accent hover:text-foreground",
link: "text-[#0072f5] underline-offset-4 hover:underline",
},

View File

@@ -7,7 +7,7 @@ function Card({ className, ...props }: React.ComponentProps<"div">) {
<div
data-slot="card"
className={cn(
"bg-card text-card-foreground flex flex-col gap-6 rounded-[10px] py-6 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_2px_2px_rgba(0,0,0,0.04),0_0_0_1px_#fafafa]",
"bg-card text-card-foreground flex flex-col gap-6 rounded-[10px] py-6 shadow",
className,
)}
{...props}

View File

@@ -60,7 +60,7 @@ function DialogContent({
<DialogPrimitive.Content
data-slot="dialog-content"
className={cn(
"bg-card text-card-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-5 rounded-[10px] p-6 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_2px_2px_rgba(0,0,0,0.04),0_0_0_1px_#fafafa] duration-200 sm:max-w-lg",
"bg-card text-card-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 fixed top-[50%] left-[50%] z-50 grid w-full max-w-[calc(100%-2rem)] translate-x-[-50%] translate-y-[-50%] gap-5 rounded-[10px] p-6 shadow-xl duration-200 sm:max-w-lg",
className,
)}
{...props}
@@ -110,7 +110,10 @@ function DialogTitle({
return (
<DialogPrimitive.Title
data-slot="dialog-title"
className={cn("text-[24px] leading-none font-semibold tracking-[-0.04em]", className)}
className={cn(
"text-[24px] leading-none font-semibold tracking-[-0.04em]",
className,
)}
{...props}
/>
);

View File

@@ -42,7 +42,7 @@ function DropdownMenuContent({
data-slot="dropdown-menu-content"
sideOffset={sideOffset}
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-[10px] p-1.5 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_8px_24px_rgba(0,0,0,0.08)]",
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-[10px] p-1.5 shadow-lg",
className,
)}
{...props}
@@ -230,7 +230,7 @@ function DropdownMenuSubContent({
<DropdownMenuPrimitive.SubContent
data-slot="dropdown-menu-sub-content"
className={cn(
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-[10px] p-1.5 shadow-[0_0_0_1px_rgba(0,0,0,0.08),0_8px_24px_rgba(0,0,0,0.08)]",
"bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 min-w-[11rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-hidden rounded-[10px] p-1.5 shadow-lg",
className,
)}
{...props}

View File

@@ -8,7 +8,7 @@ function Input({ className, type, ...props }: React.ComponentProps<"input">) {
type={type}
data-slot="input"
className={cn(
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-10 w-full min-w-0 rounded-[8px] bg-background px-3 py-2 text-sm shadow-[0_0_0_1px_rgba(0,0,0,0.08)] transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
"file:text-foreground placeholder:text-muted-foreground selection:bg-primary selection:text-primary-foreground flex h-10 w-full min-w-0 rounded-[8px] bg-secondary px-3 py-2 text-sm shadow-sm transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50",
"focus-visible:ring-[3px] focus-visible:ring-ring/25",
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40",
className,

View File

@@ -7,7 +7,7 @@ function Textarea({ className, ...props }: React.ComponentProps<"textarea">) {
<textarea
data-slot="textarea"
className={cn(
"border-input placeholder:text-muted-foreground focus-visible:border-ring focus-visible:ring-ring/50 aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive dark:bg-input/30 flex field-sizing-content min-h-16 w-full rounded-md border bg-transparent px-3 py-2 text-base shadow-xs transition-[color,box-shadow] outline-none focus-visible:ring-[3px] disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
"placeholder:text-muted-foreground aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 flex field-sizing-content min-h-16 w-full rounded-[8px] bg-secondary px-3 py-2 text-base shadow-sm transition-[color,box-shadow] outline-none focus-visible:ring-[3px] focus-visible:ring-ring/25 disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
className,
)}
{...props}