Extract pilot skin-aware component recipes

This commit is contained in:
2026-03-20 11:28:35 +08:00
parent 246851a68e
commit 40a05df4b3
10 changed files with 350 additions and 41 deletions
+6 -5
View File
@@ -494,7 +494,7 @@ Deliverables:
Status: Status:
- not started - completed
### Phase 3: Docs Validation Surface ### Phase 3: Docs Validation Surface
@@ -603,8 +603,9 @@ As of 2026-03-20, the project is at this point:
- `@ai-ui/ui/skins.css` export added - `@ai-ui/ui/skins.css` export added
- Storybook globals now switch `skin` - Storybook globals now switch `skin`
- docs switching surface added in `Foundation/Style Contract` - docs switching surface added in `Foundation/Style Contract`
- no component extraction started - pilot recipe extraction completed for `Button`, `Card`, `Input`, `Dialog`, `Switch`,
- no broad skin-aware component recipes implemented yet and `Skeleton`
- broader component-library rollout still pending
The next implementation task should be Phase 2: pilot skin extraction for The next implementation task should be Phase 3: add a dedicated comparison-oriented docs
`Button`, `Card`, `Input`, `Dialog`, `Switch`, and `Skeleton`. validation surface for skins and motion modes.
+6 -6
View File
@@ -20,7 +20,7 @@ function Spinner() {
{...createSlot("icon")} {...createSlot("icon")}
aria-hidden="true" aria-hidden="true"
animate={{ opacity: 1, rotate: 0, scale: 1 }} animate={{ opacity: 1, rotate: 0, scale: 1 }}
className="size-4 rounded-full border-2 border-current border-r-transparent animate-spin" className="size-4 rounded-[var(--ui-spinner-radius)] [border-width:var(--ui-spinner-border-width)] border-current border-r-transparent animate-spin"
exit={{ opacity: 0, rotate: 90, scale: 0.7 }} exit={{ opacity: 0, rotate: 90, scale: 0.7 }}
initial={{ opacity: 0, rotate: -90, scale: 0.7 }} initial={{ opacity: 0, rotate: -90, scale: 0.7 }}
transition={{ transition={{
@@ -74,14 +74,14 @@ export const Button = forwardRef<HTMLButtonElement, ButtonProps>(function Button
<motion.span <motion.span
animate={ animate={
prefersReducedMotion || isDisabled prefersReducedMotion || isDisabled
? { opacity: 0, x: "-120%" } ? { x: "-120%" }
: isHovered : isHovered
? { opacity: 0.75, x: "115%" } ? { x: "115%" }
: { opacity: 0, x: "-120%" } : { x: "-120%" }
} }
aria-hidden="true" aria-hidden="true"
className="pointer-events-none absolute inset-y-0 left-0 w-1/2 rounded-[inherit] bg-[linear-gradient(120deg,transparent_0%,rgba(255,255,255,0.32)_45%,transparent_100%)] mix-blend-screen" className="pointer-events-none absolute inset-y-0 left-0 w-1/2 rounded-[inherit] bg-[var(--ui-button-sheen-gradient)] opacity-[var(--ui-button-sheen-opacity)] [mix-blend-mode:var(--ui-button-sheen-mix)]"
initial={false} initial={{ x: "-120%" }}
transition={{ transition={{
duration: prefersReducedMotion ? 0.01 : 0.55, duration: prefersReducedMotion ? 0.01 : 0.55,
ease: [0.16, 1, 0.3, 1] ease: [0.16, 1, 0.3, 1]
@@ -4,7 +4,8 @@ import { getMotionRecipeClassNames } from "../lib/motion";
export const buttonVariants = cva( export const buttonVariants = cva(
[ [
"relative isolate inline-flex shrink-0 items-center justify-center gap-2 overflow-hidden whitespace-nowrap", "relative isolate inline-flex shrink-0 items-center justify-center gap-2 overflow-hidden whitespace-nowrap",
"rounded-[var(--radius-sm)] border font-medium select-none", "rounded-[var(--ui-button-radius)] [border-width:var(--ui-button-border-width)] font-medium select-none",
"[transition-duration:var(--ui-button-transition-duration,var(--dur-fast))]",
"outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-ring)]", "outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-ring)]",
"focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)]", "focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)]",
"disabled:pointer-events-none disabled:opacity-55", "disabled:pointer-events-none disabled:opacity-55",
@@ -20,15 +21,15 @@ export const buttonVariants = cva(
}, },
variant: { variant: {
primary: primary:
"border-transparent bg-[var(--color-primary)] text-[var(--color-primary-foreground)] shadow-[var(--shadow-xs)]", "border-[var(--ui-button-primary-border)] bg-[var(--ui-button-primary-bg)] text-[var(--ui-button-primary-fg)] shadow-[var(--ui-button-primary-shadow)] hover:bg-[var(--ui-button-primary-hover-bg)]",
secondary: secondary:
"border-[var(--color-border-strong)] bg-[var(--color-secondary)] text-[var(--color-secondary-foreground)]", "border-[var(--ui-button-secondary-border)] bg-[var(--ui-button-secondary-bg)] text-[var(--ui-button-secondary-fg)] shadow-[var(--ui-button-secondary-shadow)] hover:bg-[var(--ui-button-secondary-hover-bg)]",
ghost: ghost:
"border-transparent bg-transparent text-[var(--color-foreground)] hover:bg-[var(--color-surface)]", "border-[var(--ui-button-ghost-border)] bg-[var(--ui-button-ghost-bg)] text-[var(--ui-button-ghost-fg)] shadow-[var(--ui-button-ghost-shadow)] hover:bg-[var(--ui-button-ghost-hover-bg)]",
subtle: subtle:
"border-[var(--color-border)] bg-[var(--color-card)] text-[var(--color-foreground)] shadow-[var(--shadow-xs)]", "border-[var(--ui-button-subtle-border)] bg-[var(--ui-button-subtle-bg)] text-[var(--ui-button-subtle-fg)] shadow-[var(--ui-button-subtle-shadow)] hover:bg-[var(--ui-button-subtle-hover-bg)]",
destructive: destructive:
"border-transparent bg-[var(--color-destructive)] text-[var(--color-destructive-foreground)] shadow-[var(--shadow-xs)]" "border-[var(--ui-button-destructive-border)] bg-[var(--ui-button-destructive-bg)] text-[var(--ui-button-destructive-fg)] shadow-[var(--ui-button-destructive-shadow)] hover:bg-[var(--ui-button-destructive-hover-bg)]"
}, },
loading: { loading: {
false: "", false: "",
+7 -6
View File
@@ -3,22 +3,23 @@ import { getMotionRecipeClassNames } from "../lib/motion";
export const cardVariants = cva( export const cardVariants = cva(
[ [
"rounded-[var(--radius-lg)] border text-[var(--color-card-foreground)]", "rounded-[var(--ui-card-radius)] border text-[var(--color-card-foreground)]",
"bg-[var(--color-card)] shadow-[var(--shadow-sm)]", "bg-[var(--ui-card-bg)] shadow-[var(--ui-card-shadow)] [border-width:var(--ui-card-border-width)]",
getMotionRecipeClassNames("transition", "ring") getMotionRecipeClassNames("transition", "ring")
], ],
{ {
variants: { variants: {
tone: { tone: {
default: "border-[var(--color-border)]", default:
"border-[var(--ui-card-default-border)] bg-[var(--ui-card-default-bg)] shadow-[var(--ui-card-default-shadow)]",
subtle: subtle:
"border-[color-mix(in_oklch,var(--color-border)_86%,transparent)] bg-[var(--color-surface)] shadow-[var(--shadow-xs)]", "border-[var(--ui-card-subtle-border)] bg-[var(--ui-card-subtle-bg)] shadow-[var(--ui-card-subtle-shadow)]",
accent: accent:
"border-[color-mix(in_oklch,var(--color-primary)_26%,var(--color-border))] bg-[color-mix(in_oklch,var(--color-primary)_8%,var(--color-card))]" "border-[var(--ui-card-accent-border)] bg-[var(--ui-card-accent-bg)] shadow-[var(--ui-card-accent-shadow)]"
}, },
interactive: { interactive: {
false: "", false: "",
true: "hover:-translate-y-[2px] hover:shadow-[var(--shadow-md)]" true: "hover:translate-y-[var(--ui-card-hover-translate)] hover:shadow-[var(--ui-card-hover-shadow)]"
} }
}, },
defaultVariants: { defaultVariants: {
+1 -1
View File
@@ -45,7 +45,7 @@ export const DialogContent = forwardRef<
{children} {children}
<DialogPrimitive.Close <DialogPrimitive.Close
aria-label="Close dialog" aria-label="Close dialog"
className="absolute right-4 top-4 inline-flex size-9 items-center justify-center rounded-[var(--radius-full)] text-[var(--color-muted-foreground)] outline-none transition-colors duration-[var(--dur-fast)] ease-[var(--ease-standard)] hover:bg-[var(--color-surface)] hover:text-[var(--color-foreground)] focus-visible:ring-2 focus-visible:ring-[var(--color-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-card)]" className="absolute right-4 top-4 inline-flex size-9 items-center justify-center rounded-[var(--ui-control-radius)] border border-transparent text-[var(--color-muted-foreground)] outline-none transition-colors duration-[var(--dur-fast)] ease-[var(--ease-standard)] hover:border-[var(--ui-control-border)] hover:bg-[var(--ui-control-bg)] hover:text-[var(--color-foreground)] hover:shadow-[var(--ui-control-shadow)] focus-visible:ring-2 focus-visible:ring-[var(--color-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--ui-panel-bg)]"
> >
<span aria-hidden="true" className="text-lg leading-none"> <span aria-hidden="true" className="text-lg leading-none">
× ×
@@ -1,7 +1,7 @@
import { cva } from "../lib/cva"; import { cva } from "../lib/cva";
export const dialogOverlayVariants = cva([ export const dialogOverlayVariants = cva([
"fixed inset-0 z-50 bg-[var(--color-overlay)] backdrop-blur-[2px]", "fixed inset-0 z-50 bg-[var(--ui-panel-overlay-bg)] backdrop-blur-[var(--ui-panel-overlay-blur)]",
"data-[state=open]:motion-overlay-enter data-[state=closed]:motion-overlay-exit" "data-[state=open]:motion-overlay-enter data-[state=closed]:motion-overlay-exit"
]); ]);
@@ -9,7 +9,8 @@ export const dialogContentVariants = cva(
[ [
"fixed left-1/2 top-1/2 z-50 grid -translate-x-1/2 -translate-y-1/2 gap-5", "fixed left-1/2 top-1/2 z-50 grid -translate-x-1/2 -translate-y-1/2 gap-5",
"w-[min(calc(100vw-2rem),40rem)] max-h-[calc(100vh-2rem)] overflow-y-auto", "w-[min(calc(100vw-2rem),40rem)] max-h-[calc(100vh-2rem)] overflow-y-auto",
"rounded-[var(--radius-lg)] border border-[var(--color-border)] bg-[var(--color-card)] p-6 text-[var(--color-card-foreground)] shadow-[var(--shadow-md)] outline-none", "rounded-[var(--ui-panel-radius)] border border-[var(--ui-panel-border)] bg-[var(--ui-panel-bg)] p-6 text-[var(--color-card-foreground)] shadow-[var(--ui-panel-shadow)] outline-none",
"[border-width:var(--ui-panel-border-width)] backdrop-blur-[var(--ui-panel-backdrop-blur)]",
"data-[state=open]:motion-enter-rise data-[state=closed]:motion-exit-drop" "data-[state=open]:motion-enter-rise data-[state=closed]:motion-exit-drop"
], ],
{ {
+5 -4
View File
@@ -3,12 +3,13 @@ import { getMotionRecipeClassNames } from "../lib/motion";
export const inputVariants = cva( export const inputVariants = cva(
[ [
"flex w-full min-w-0 rounded-[var(--radius-md)] border border-[var(--color-input)] bg-[var(--color-card)]", "flex w-full min-w-0 rounded-[var(--ui-input-radius)] border bg-[var(--ui-input-bg)]",
"text-[var(--color-foreground)] shadow-[var(--shadow-xs)] outline-none", "text-[var(--ui-input-fg)] shadow-[var(--ui-input-shadow)] outline-none",
"[border-width:var(--ui-input-border-width)] border-[var(--ui-input-border)] backdrop-blur-[var(--ui-input-backdrop-blur)]",
"placeholder:text-[var(--color-muted-foreground)]", "placeholder:text-[var(--color-muted-foreground)]",
"focus-visible:ring-2 focus-visible:ring-[var(--color-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)]", "focus-visible:ring-2 focus-visible:ring-[var(--color-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)]",
"disabled:cursor-not-allowed disabled:bg-[var(--color-surface)] disabled:text-[var(--color-muted-foreground)] disabled:opacity-100", "disabled:cursor-not-allowed disabled:bg-[var(--ui-input-disabled-bg)] disabled:text-[var(--color-muted-foreground)] disabled:opacity-100",
"read-only:bg-[var(--color-surface)] read-only:text-[var(--color-muted-foreground)]", "read-only:bg-[var(--ui-input-readonly-bg)] read-only:text-[var(--color-muted-foreground)]",
"aria-[invalid=true]:border-[color-mix(in_oklch,var(--color-destructive)_42%,var(--color-border-strong))]", "aria-[invalid=true]:border-[color-mix(in_oklch,var(--color-destructive)_42%,var(--color-border-strong))]",
"aria-[invalid=true]:shadow-[0_0_0_1px_color-mix(in_oklch,var(--color-destructive)_28%,transparent)]", "aria-[invalid=true]:shadow-[0_0_0_1px_color-mix(in_oklch,var(--color-destructive)_28%,transparent)]",
getMotionRecipeClassNames("ring") getMotionRecipeClassNames("ring")
+7 -8
View File
@@ -6,21 +6,20 @@ import { createDataAttributes, createSlot } from "../lib/contracts";
const skeletonVariants = cva( const skeletonVariants = cva(
[ [
"relative overflow-hidden rounded-[var(--radius-sm)] bg-[color-mix(in_oklch,var(--color-surface)_74%,var(--color-border))]", "relative overflow-hidden rounded-[var(--ui-skeleton-radius)] bg-[var(--ui-skeleton-bg)]",
"before:absolute before:inset-0 before:bg-[linear-gradient(110deg,transparent_0%,rgba(255,255,255,0.48)_42%,transparent_72%)] before:opacity-70 before:content-[''] before:animate-[aiui-skeleton-shimmer_1.8s_var(--ease-standard)_infinite]" "before:absolute before:inset-0 before:bg-[var(--ui-skeleton-gradient)] before:opacity-70 before:content-[''] before:animate-[aiui-skeleton-shimmer_1.8s_var(--ease-standard)_infinite]"
], ],
{ {
variants: { variants: {
shape: { shape: {
line: "h-4 w-full", line: "h-4 w-full",
block: "h-24 w-full rounded-[var(--radius-md)]", block: "h-24 w-full rounded-[var(--ui-skeleton-block-radius)]",
pill: "h-10 w-32 rounded-[var(--radius-full)]", pill: "h-10 w-32 rounded-[var(--ui-skeleton-pill-radius)]",
avatar: "size-12 rounded-[var(--radius-full)]" avatar: "size-12 rounded-[var(--ui-skeleton-avatar-radius)]"
}, },
tone: { tone: {
default: default: "bg-[var(--ui-skeleton-bg)]",
"bg-[color-mix(in_oklch,var(--color-surface)_74%,var(--color-border))]", muted: "bg-[var(--ui-skeleton-muted-bg)]"
muted: "bg-[var(--color-muted)]"
} }
}, },
defaultVariants: { defaultVariants: {
@@ -3,17 +3,18 @@ import { getMotionRecipeClassNames } from "../lib/motion";
export const switchVariants = cva( export const switchVariants = cva(
[ [
"inline-flex h-7 w-12 shrink-0 items-center rounded-full border border-transparent bg-[var(--color-border)] shadow-[var(--shadow-xs)] outline-none", "inline-flex h-7 w-12 shrink-0 items-center rounded-[var(--ui-switch-track-radius)] border bg-[var(--ui-switch-track-bg)] shadow-[var(--ui-switch-track-shadow)] outline-none",
"[border-width:var(--ui-switch-track-border-width)] border-[var(--ui-switch-track-border)]",
"transition-[background-color,box-shadow] duration-[var(--dur-fast)] ease-[var(--ease-standard)]", "transition-[background-color,box-shadow] duration-[var(--dur-fast)] ease-[var(--ease-standard)]",
"focus-visible:ring-2 focus-visible:ring-[var(--color-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)]", "focus-visible:ring-2 focus-visible:ring-[var(--color-ring)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-background)]",
"data-[state=checked]:bg-[var(--color-primary)] data-[disabled]:cursor-not-allowed data-[disabled]:opacity-45", "data-[state=checked]:bg-[var(--ui-switch-track-checked-bg)] data-[state=checked]:border-[var(--ui-switch-track-checked-border)] data-[disabled]:cursor-not-allowed data-[disabled]:opacity-45",
"aria-[invalid=true]:border-[color-mix(in_oklch,var(--color-destructive)_42%,var(--color-border-strong))]", "aria-[invalid=true]:border-[color-mix(in_oklch,var(--color-destructive)_42%,var(--color-border-strong))]",
getMotionRecipeClassNames("ring") getMotionRecipeClassNames("ring")
] ]
); );
export const switchThumbVariants = cva([ export const switchThumbVariants = cva([
"pointer-events-none block size-5 rounded-full bg-white shadow-[var(--shadow-xs)]", "pointer-events-none block size-5 rounded-[var(--ui-switch-thumb-radius)] bg-[var(--ui-switch-thumb-bg)] shadow-[var(--ui-switch-thumb-shadow)]",
"translate-x-0.5 transition-transform duration-[var(--dur-fast)] ease-[var(--ease-standard)]", "translate-x-0.5 transition-transform duration-[var(--dur-fast)] ease-[var(--ease-standard)]",
"data-[state=checked]:translate-x-[1.55rem]" "data-[state=checked]:translate-x-[1.55rem]"
]); ]);
+304
View File
@@ -17,6 +17,108 @@
--ui-control-radius: var(--radius-md); --ui-control-radius: var(--radius-md);
--ui-ornament-opacity: 0.1; --ui-ornament-opacity: 0.1;
--ui-ornament-mix: normal; --ui-ornament-mix: normal;
--ui-button-radius: var(--radius-sm);
--ui-button-border-width: 1px;
--ui-button-transition-duration: var(--dur-fast);
--ui-button-sheen-opacity: 0.14;
--ui-button-sheen-mix: screen;
--ui-button-sheen-gradient: linear-gradient(
120deg,
transparent 0%,
rgba(255, 255, 255, 0.24) 45%,
transparent 100%
);
--ui-button-primary-bg: var(--color-primary);
--ui-button-primary-hover-bg: color-mix(in oklch, var(--color-primary) 90%, black 10%);
--ui-button-primary-fg: var(--color-primary-foreground);
--ui-button-primary-border: transparent;
--ui-button-primary-shadow: var(--shadow-xs);
--ui-button-secondary-bg: var(--color-secondary);
--ui-button-secondary-hover-bg: color-mix(in oklch, var(--color-secondary) 88%, black 12%);
--ui-button-secondary-fg: var(--color-secondary-foreground);
--ui-button-secondary-border: var(--color-border-strong);
--ui-button-secondary-shadow: none;
--ui-button-ghost-bg: transparent;
--ui-button-ghost-hover-bg: var(--color-surface);
--ui-button-ghost-fg: var(--color-foreground);
--ui-button-ghost-border: transparent;
--ui-button-ghost-shadow: none;
--ui-button-subtle-bg: var(--color-card);
--ui-button-subtle-hover-bg: color-mix(in oklch, var(--color-card) 88%, black 12%);
--ui-button-subtle-fg: var(--color-foreground);
--ui-button-subtle-border: var(--color-border);
--ui-button-subtle-shadow: var(--shadow-xs);
--ui-button-destructive-bg: var(--color-destructive);
--ui-button-destructive-hover-bg: color-mix(
in oklch,
var(--color-destructive) 88%,
black 12%
);
--ui-button-destructive-fg: var(--color-destructive-foreground);
--ui-button-destructive-border: transparent;
--ui-button-destructive-shadow: var(--shadow-xs);
--ui-spinner-radius: var(--radius-full);
--ui-spinner-border-width: 2px;
--ui-card-radius: var(--radius-lg);
--ui-card-border-width: 1px;
--ui-card-bg: var(--color-card);
--ui-card-shadow: var(--shadow-sm);
--ui-card-default-bg: var(--color-card);
--ui-card-default-border: var(--color-border);
--ui-card-default-shadow: var(--shadow-sm);
--ui-card-subtle-bg: var(--color-surface);
--ui-card-subtle-border: color-mix(in oklch, var(--color-border) 86%, transparent);
--ui-card-subtle-shadow: var(--shadow-xs);
--ui-card-accent-bg: color-mix(in oklch, var(--color-primary) 8%, var(--color-card));
--ui-card-accent-border: color-mix(in oklch, var(--color-primary) 26%, var(--color-border));
--ui-card-accent-shadow: var(--shadow-sm);
--ui-card-hover-translate: -2px;
--ui-card-hover-shadow: var(--shadow-md);
--ui-input-radius: var(--radius-md);
--ui-input-border-width: 1px;
--ui-input-bg: var(--color-card);
--ui-input-border: var(--color-input);
--ui-input-fg: var(--color-foreground);
--ui-input-shadow: var(--shadow-xs);
--ui-input-disabled-bg: var(--color-surface);
--ui-input-readonly-bg: var(--color-surface);
--ui-input-backdrop-blur: 0px;
--ui-panel-radius: var(--radius-lg);
--ui-panel-border-width: 1px;
--ui-panel-bg: var(--color-card);
--ui-panel-border: var(--color-border);
--ui-panel-shadow: var(--shadow-md);
--ui-panel-backdrop-blur: 0px;
--ui-panel-overlay-bg: var(--color-overlay);
--ui-panel-overlay-blur: 2px;
--ui-switch-track-radius: var(--radius-full);
--ui-switch-track-border-width: 1px;
--ui-switch-track-bg: var(--color-border);
--ui-switch-track-border: transparent;
--ui-switch-track-shadow: var(--shadow-xs);
--ui-switch-track-checked-bg: var(--color-primary);
--ui-switch-track-checked-border: transparent;
--ui-switch-thumb-radius: var(--radius-full);
--ui-switch-thumb-bg: white;
--ui-switch-thumb-shadow: var(--shadow-xs);
--ui-skeleton-radius: var(--radius-sm);
--ui-skeleton-block-radius: var(--radius-md);
--ui-skeleton-pill-radius: var(--radius-full);
--ui-skeleton-avatar-radius: var(--radius-full);
--ui-skeleton-bg: color-mix(in oklch, var(--color-surface) 74%, var(--color-border));
--ui-skeleton-muted-bg: var(--color-muted);
--ui-skeleton-gradient: linear-gradient(
110deg,
transparent 0%,
rgba(255, 255, 255, 0.48) 42%,
transparent 72%
);
} }
[data-skin="glass"] { [data-skin="glass"] {
@@ -48,6 +150,108 @@
--ui-control-radius: var(--radius-lg); --ui-control-radius: var(--radius-lg);
--ui-ornament-opacity: 0.36; --ui-ornament-opacity: 0.36;
--ui-ornament-mix: screen; --ui-ornament-mix: screen;
--ui-button-radius: var(--radius-lg);
--ui-button-border-width: 1px;
--ui-button-transition-duration: var(--dur-base);
--ui-button-sheen-opacity: 0.42;
--ui-button-sheen-mix: screen;
--ui-button-sheen-gradient: linear-gradient(
120deg,
transparent 0%,
rgba(255, 255, 255, 0.34) 45%,
transparent 100%
);
--ui-button-primary-bg: color-mix(in oklch, var(--color-primary) 72%, white 28%);
--ui-button-primary-hover-bg: color-mix(in oklch, var(--color-primary) 78%, white 22%);
--ui-button-primary-fg: var(--color-primary-foreground);
--ui-button-primary-border: color-mix(in oklch, white 28%, var(--color-primary));
--ui-button-primary-shadow: 0 16px 34px oklch(0.24 0.06 250 / 0.18);
--ui-button-secondary-bg: color-mix(in oklch, var(--color-secondary) 52%, transparent);
--ui-button-secondary-hover-bg: color-mix(in oklch, var(--color-secondary) 64%, transparent);
--ui-button-secondary-fg: var(--color-secondary-foreground);
--ui-button-secondary-border: color-mix(in oklch, white 34%, var(--color-border-strong));
--ui-button-secondary-shadow: 0 12px 28px oklch(0.24 0.04 250 / 0.12);
--ui-button-ghost-bg: transparent;
--ui-button-ghost-hover-bg: color-mix(in oklch, white 18%, transparent);
--ui-button-ghost-fg: var(--color-foreground);
--ui-button-ghost-border: color-mix(in oklch, white 20%, transparent);
--ui-button-ghost-shadow: none;
--ui-button-subtle-bg: color-mix(in oklch, var(--color-card) 56%, transparent);
--ui-button-subtle-hover-bg: color-mix(in oklch, var(--color-card) 66%, transparent);
--ui-button-subtle-fg: var(--color-foreground);
--ui-button-subtle-border: color-mix(in oklch, white 30%, var(--color-border));
--ui-button-subtle-shadow: 0 12px 30px oklch(0.24 0.04 250 / 0.12);
--ui-button-destructive-bg: color-mix(in oklch, var(--color-destructive) 74%, white 26%);
--ui-button-destructive-hover-bg: color-mix(
in oklch,
var(--color-destructive) 80%,
white 20%
);
--ui-button-destructive-fg: var(--color-destructive-foreground);
--ui-button-destructive-border: color-mix(in oklch, white 28%, var(--color-destructive));
--ui-button-destructive-shadow: 0 16px 34px oklch(0.32 0.07 18 / 0.18);
--ui-spinner-radius: var(--radius-full);
--ui-spinner-border-width: 2px;
--ui-card-radius: var(--radius-xl);
--ui-card-border-width: 1px;
--ui-card-bg: color-mix(in oklch, var(--color-card) 58%, transparent);
--ui-card-shadow: 0 24px 64px oklch(0.18 0.03 255 / 0.18);
--ui-card-default-bg: color-mix(in oklch, var(--color-card) 58%, transparent);
--ui-card-default-border: color-mix(in oklch, white 42%, var(--color-border));
--ui-card-default-shadow: 0 24px 64px oklch(0.18 0.03 255 / 0.18);
--ui-card-subtle-bg: color-mix(in oklch, var(--color-surface) 52%, transparent);
--ui-card-subtle-border: color-mix(in oklch, white 32%, var(--color-border));
--ui-card-subtle-shadow: 0 18px 46px oklch(0.18 0.03 255 / 0.12);
--ui-card-accent-bg: color-mix(in oklch, var(--color-primary) 16%, transparent);
--ui-card-accent-border: color-mix(in oklch, white 26%, var(--color-primary));
--ui-card-accent-shadow: 0 24px 54px oklch(0.22 0.08 245 / 0.18);
--ui-card-hover-translate: -4px;
--ui-card-hover-shadow: 0 30px 72px oklch(0.18 0.03 255 / 0.22);
--ui-input-radius: var(--radius-lg);
--ui-input-border-width: 1px;
--ui-input-bg: color-mix(in oklch, var(--color-card) 50%, transparent);
--ui-input-border: color-mix(in oklch, white 34%, var(--color-border));
--ui-input-fg: var(--color-foreground);
--ui-input-shadow: 0 14px 34px oklch(0.2 0.03 255 / 0.12);
--ui-input-disabled-bg: color-mix(in oklch, var(--color-surface) 72%, transparent);
--ui-input-readonly-bg: color-mix(in oklch, var(--color-surface) 68%, transparent);
--ui-input-backdrop-blur: 12px;
--ui-panel-radius: var(--radius-xl);
--ui-panel-border-width: 1px;
--ui-panel-bg: color-mix(in oklch, var(--color-card) 54%, transparent);
--ui-panel-border: color-mix(in oklch, white 40%, var(--color-border));
--ui-panel-shadow: 0 28px 72px oklch(0.16 0.03 255 / 0.24);
--ui-panel-backdrop-blur: 20px;
--ui-panel-overlay-bg: color-mix(in oklch, var(--color-overlay) 74%, transparent);
--ui-panel-overlay-blur: 8px;
--ui-switch-track-radius: var(--radius-full);
--ui-switch-track-border-width: 1px;
--ui-switch-track-bg: color-mix(in oklch, var(--color-card) 44%, transparent);
--ui-switch-track-border: color-mix(in oklch, white 32%, var(--color-border));
--ui-switch-track-shadow: 0 10px 24px oklch(0.18 0.03 255 / 0.14);
--ui-switch-track-checked-bg: color-mix(in oklch, var(--color-primary) 72%, white 28%);
--ui-switch-track-checked-border: color-mix(in oklch, white 30%, var(--color-primary));
--ui-switch-thumb-radius: var(--radius-full);
--ui-switch-thumb-bg: color-mix(in oklch, white 84%, var(--color-card));
--ui-switch-thumb-shadow: 0 8px 18px oklch(0.16 0.02 255 / 0.22);
--ui-skeleton-radius: var(--radius-md);
--ui-skeleton-block-radius: var(--radius-lg);
--ui-skeleton-pill-radius: var(--radius-full);
--ui-skeleton-avatar-radius: var(--radius-full);
--ui-skeleton-bg: color-mix(in oklch, var(--color-surface) 42%, transparent);
--ui-skeleton-muted-bg: color-mix(in oklch, var(--color-muted) 54%, transparent);
--ui-skeleton-gradient: linear-gradient(
110deg,
transparent 0%,
rgba(255, 255, 255, 0.58) 44%,
transparent 74%
);
} }
[data-skin="pixel"] { [data-skin="pixel"] {
@@ -79,4 +283,104 @@
--ui-control-radius: 0px; --ui-control-radius: 0px;
--ui-ornament-opacity: 0.2; --ui-ornament-opacity: 0.2;
--ui-ornament-mix: multiply; --ui-ornament-mix: multiply;
--ui-button-radius: 0px;
--ui-button-border-width: 2px;
--ui-button-transition-duration: var(--dur-instant);
--ui-button-sheen-opacity: 0;
--ui-button-sheen-mix: normal;
--ui-button-sheen-gradient: linear-gradient(90deg, transparent, transparent);
--ui-button-primary-bg: var(--color-primary);
--ui-button-primary-hover-bg: color-mix(in oklch, var(--color-primary) 88%, white 12%);
--ui-button-primary-fg: var(--color-primary-foreground);
--ui-button-primary-border: var(--color-foreground);
--ui-button-primary-shadow: 3px 3px 0 color-mix(in oklch, var(--color-foreground) 34%, transparent);
--ui-button-secondary-bg: var(--color-secondary);
--ui-button-secondary-hover-bg: color-mix(in oklch, var(--color-secondary) 86%, black 14%);
--ui-button-secondary-fg: var(--color-secondary-foreground);
--ui-button-secondary-border: var(--color-foreground);
--ui-button-secondary-shadow: 3px 3px 0 color-mix(in oklch, var(--color-foreground) 30%, transparent);
--ui-button-ghost-bg: transparent;
--ui-button-ghost-hover-bg: color-mix(in oklch, var(--color-surface) 86%, black 14%);
--ui-button-ghost-fg: var(--color-foreground);
--ui-button-ghost-border: var(--color-foreground);
--ui-button-ghost-shadow: none;
--ui-button-subtle-bg: var(--color-card);
--ui-button-subtle-hover-bg: color-mix(in oklch, var(--color-card) 88%, black 12%);
--ui-button-subtle-fg: var(--color-foreground);
--ui-button-subtle-border: var(--color-foreground);
--ui-button-subtle-shadow: 3px 3px 0 color-mix(in oklch, var(--color-foreground) 30%, transparent);
--ui-button-destructive-bg: var(--color-destructive);
--ui-button-destructive-hover-bg: color-mix(
in oklch,
var(--color-destructive) 88%,
white 12%
);
--ui-button-destructive-fg: var(--color-destructive-foreground);
--ui-button-destructive-border: var(--color-foreground);
--ui-button-destructive-shadow: 3px 3px 0 color-mix(in oklch, var(--color-foreground) 34%, transparent);
--ui-spinner-radius: 0px;
--ui-spinner-border-width: 2px;
--ui-card-radius: 0px;
--ui-card-border-width: 2px;
--ui-card-bg: var(--color-card);
--ui-card-shadow: 6px 6px 0 color-mix(in oklch, var(--color-foreground) 38%, transparent);
--ui-card-default-bg: var(--color-card);
--ui-card-default-border: var(--color-foreground);
--ui-card-default-shadow: 6px 6px 0 color-mix(in oklch, var(--color-foreground) 38%, transparent);
--ui-card-subtle-bg: var(--color-surface);
--ui-card-subtle-border: var(--color-foreground);
--ui-card-subtle-shadow: 4px 4px 0 color-mix(in oklch, var(--color-foreground) 34%, transparent);
--ui-card-accent-bg: color-mix(in oklch, var(--color-primary) 12%, var(--color-card));
--ui-card-accent-border: var(--color-foreground);
--ui-card-accent-shadow: 6px 6px 0 color-mix(in oklch, var(--color-primary) 34%, transparent);
--ui-card-hover-translate: -2px;
--ui-card-hover-shadow: 8px 8px 0 color-mix(in oklch, var(--color-foreground) 42%, transparent);
--ui-input-radius: 0px;
--ui-input-border-width: 2px;
--ui-input-bg: var(--color-background);
--ui-input-border: var(--color-foreground);
--ui-input-fg: var(--color-foreground);
--ui-input-shadow: 3px 3px 0 color-mix(in oklch, var(--color-foreground) 28%, transparent);
--ui-input-disabled-bg: var(--color-surface);
--ui-input-readonly-bg: var(--color-surface);
--ui-input-backdrop-blur: 0px;
--ui-panel-radius: 0px;
--ui-panel-border-width: 2px;
--ui-panel-bg: var(--color-card);
--ui-panel-border: var(--color-foreground);
--ui-panel-shadow: 8px 8px 0 color-mix(in oklch, var(--color-foreground) 40%, transparent);
--ui-panel-backdrop-blur: 0px;
--ui-panel-overlay-bg: color-mix(in oklch, var(--color-overlay) 92%, black 8%);
--ui-panel-overlay-blur: 0px;
--ui-switch-track-radius: 0px;
--ui-switch-track-border-width: 2px;
--ui-switch-track-bg: var(--color-border);
--ui-switch-track-border: var(--color-foreground);
--ui-switch-track-shadow: 2px 2px 0 color-mix(in oklch, var(--color-foreground) 24%, transparent);
--ui-switch-track-checked-bg: var(--color-primary);
--ui-switch-track-checked-border: var(--color-foreground);
--ui-switch-thumb-radius: 0px;
--ui-switch-thumb-bg: var(--color-background);
--ui-switch-thumb-shadow: 2px 2px 0 color-mix(in oklch, var(--color-foreground) 24%, transparent);
--ui-skeleton-radius: 0px;
--ui-skeleton-block-radius: 0px;
--ui-skeleton-pill-radius: 0px;
--ui-skeleton-avatar-radius: 0px;
--ui-skeleton-bg: color-mix(in oklch, var(--color-foreground) 18%, var(--color-background));
--ui-skeleton-muted-bg: color-mix(in oklch, var(--color-muted) 72%, black 28%);
--ui-skeleton-gradient: linear-gradient(
90deg,
transparent 0%,
transparent 28%,
rgba(255, 255, 255, 0.2) 28%,
rgba(255, 255, 255, 0.2) 42%,
transparent 42%,
transparent 100%
);
} }