135 lines
6.8 KiB
Plaintext
135 lines
6.8 KiB
Plaintext
---
|
|
import type { HTMLAttributes } from "astro/types";
|
|
import { cn } from "../utils/cn";
|
|
import { Icon } from "astro-icon/components";
|
|
|
|
type Variant = "solid" | "outline" | "ghost" | "soft" | "link";
|
|
type Color =
|
|
| "primary"
|
|
| "secondary"
|
|
| "tertiary"
|
|
| "accent"
|
|
| "info"
|
|
| "success"
|
|
| "warning"
|
|
| "danger"
|
|
| "neutral";
|
|
type Size = "sm" | "md" | "lg" | "icon";
|
|
|
|
interface Props extends HTMLAttributes<"button"> {
|
|
variant?: Variant;
|
|
color?: Color;
|
|
size?: Size;
|
|
pill?: boolean;
|
|
icon?: string;
|
|
}
|
|
|
|
const {
|
|
variant = "solid",
|
|
color = "primary",
|
|
size = "md",
|
|
pill = false,
|
|
icon = "",
|
|
class: className,
|
|
...rest
|
|
}: Props = Astro.props;
|
|
|
|
const base =
|
|
"inline-flex items-center justify-center gap-2 font-medium transition-colors " +
|
|
"focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-2 " +
|
|
"disabled:opacity-50 disabled:pointer-events-none";
|
|
|
|
const sizeClass: Record<Size, string> = {
|
|
sm: "h-8 px-3 text-sm",
|
|
md: "h-10 px-4 text-sm",
|
|
lg: "h-11 px-5 text-base",
|
|
icon: "h-10 w-10 p-0",
|
|
};
|
|
|
|
const radius = pill ? "rounded-full" : "rounded-md";
|
|
|
|
const styles: Record<Color, Record<Variant, string>> = {
|
|
primary: {
|
|
solid: "bg-primary text-primary-foreground hover:bg-primary/90 border border-transparent focus-visible:ring-primary/40",
|
|
outline:
|
|
"border border-primary text-primary hover:bg-primary/10 focus-visible:ring-primary/40",
|
|
ghost: "text-primary hover:bg-primary/10 border border-transparent focus-visible:ring-primary/30",
|
|
soft: "bg-primary/15 text-primary hover:bg-primary/20 border border-transparent focus-visible:ring-primary/30",
|
|
link: "text-primary underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-primary/40",
|
|
},
|
|
secondary: {
|
|
solid: "bg-secondary text-secondary-foreground hover:bg-secondary/90 border border-transparent focus-visible:ring-secondary/40",
|
|
outline:
|
|
"border border-secondary text-secondary hover:bg-secondary/10 focus-visible:ring-secondary/40",
|
|
ghost: "text-secondary hover:bg-secondary/10 border border-transparent focus-visible:ring-secondary/30",
|
|
soft: "bg-secondary/15 text-secondary hover:bg-secondary/20 border border-transparent focus-visible:ring-secondary/30",
|
|
link: "text-secondary underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-secondary/40",
|
|
},
|
|
tertiary: {
|
|
solid: "bg-tertiary text-tertiary-foreground hover:bg-tertiary/90 border border-transparent focus-visible:ring-tertiary/40",
|
|
outline:
|
|
"border border-tertiary text-tertiary hover:bg-tertiary/10 focus-visible:ring-tertiary/40",
|
|
ghost: "text-tertiary hover:bg-tertiary/10 border border-transparent focus-visible:ring-tertiary/30",
|
|
soft: "bg-tertiary/15 text-tertiary hover:bg-tertiary/20 border border-transparent focus-visible:ring-tertiary/30",
|
|
link: "text-tertiary underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-tertiary/40",
|
|
},
|
|
accent: {
|
|
solid: "bg-accent text-accent-foreground hover:bg-accent/90 border border-transparent focus-visible:ring-accent/40",
|
|
outline:
|
|
"border border-accent text-accent hover:bg-accent/10 focus-visible:ring-accent/40",
|
|
ghost: "text-accent hover:bg-accent/10 border border-transparent focus-visible:ring-accent/30",
|
|
soft: "bg-accent/15 text-accent hover:bg-accent/20 border border-transparent focus-visible:ring-accent/30",
|
|
link: "text-accent underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-accent/40",
|
|
},
|
|
info: {
|
|
solid: "bg-info text-info-foreground hover:bg-info/90 border border-transparent focus-visible:ring-info/40",
|
|
outline:
|
|
"border border-info text-info hover:bg-info/10 focus-visible:ring-info/40",
|
|
ghost: "text-info hover:bg-info/10 border border-transparent focus-visible:ring-info/30",
|
|
soft: "bg-info/15 text-info hover:bg-info/20 border border-transparent focus-visible:ring-info/30",
|
|
link: "text-info underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-info/40",
|
|
},
|
|
success: {
|
|
solid: "bg-success text-success-foreground hover:bg-success/90 border border-transparent focus-visible:ring-success/40",
|
|
outline:
|
|
"border border-success text-success hover:bg-success/10 focus-visible:ring-success/40",
|
|
ghost: "text-success hover:bg-success/10 border border-transparent focus-visible:ring-success/30",
|
|
soft: "bg-success/15 text-success hover:bg-success/20 border border-transparent focus-visible:ring-success/30",
|
|
link: "text-success underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-success/40",
|
|
},
|
|
warning: {
|
|
solid: "bg-warning text-warning-foreground hover:bg-warning/90 border border-transparent focus-visible:ring-warning/40",
|
|
outline:
|
|
"border border-warning text-warning hover:bg-warning/10 focus-visible:ring-warning/40",
|
|
ghost: "text-warning hover:bg-warning/10 border border-transparent focus-visible:ring-warning/30",
|
|
soft: "bg-warning/14 text-warning hover:bg-warning/20 border border-transparent focus-visible:ring-warning/30",
|
|
link: "text-warning underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-warning/40",
|
|
},
|
|
danger: {
|
|
solid: "bg-danger text-danger-foreground hover:bg-danger/90 border border-transparent focus-visible:ring-danger/40",
|
|
outline:
|
|
"border border-danger text-danger hover:bg-danger/10 focus-visible:ring-danger/40",
|
|
ghost: "text-danger hover:bg-danger/10 border border-transparent focus-visible:ring-danger/30",
|
|
soft: "bg-danger/15 text-danger hover:bg-danger/20 border border-transparent focus-visible:ring-danger/30",
|
|
link: "text-danger underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-danger/40",
|
|
},
|
|
neutral: {
|
|
solid: "bg-neutral text-neutral-foreground hover:bg-neutral/90 border border-transparent focus-visible:ring-neutral/40",
|
|
outline:
|
|
"border border-neutral text-neutral hover:bg-neutral/10 focus-visible:ring-neutral/40",
|
|
ghost: "text-neutral hover:bg-neutral/10 border border-transparent focus-visible:ring-neutral/30",
|
|
soft: "bg-neutral/15 text-neutral hover:bg-neutral/20 border border-transparent focus-visible:ring-neutral/30",
|
|
link: "text-neutral underline underline-offset-4 p-0 h-auto border-0 focus-visible:ring-neutral/40",
|
|
},
|
|
};
|
|
|
|
const variantColor = styles[color][variant];
|
|
const sizeKls = variant === "link" ? "" : sizeClass[size];
|
|
const iconSize = size === "sm" ? "size-4" : size === "lg" ? "size-5" : "size-5";
|
|
---
|
|
|
|
<button class={cn(base, radius, sizeKls, variantColor, className)} {...rest}>
|
|
{icon && <Icon name={icon} class={cn(iconSize, "shrink-0")} />}
|
|
<slot />
|
|
</button>
|