import type { ButtonHTMLAttributes, InputHTMLAttributes, ReactNode } from "react";
export function cx(...classes: Array): string {
return classes.filter(Boolean).join(" ");
}
/* -------------------------------------------------------------------- Card */
export function Card({
children,
className,
}: {
children: ReactNode;
className?: string;
}) {
return (
);
}
export function CardTitle({
children,
hint,
}: {
children: ReactNode;
hint?: ReactNode;
}) {
return (
{children}
{hint ?
{hint}
: null}
);
}
/* ------------------------------------------------------------------ Button */
type ButtonProps = ButtonHTMLAttributes & {
variant?: "primary" | "secondary" | "ghost" | "danger";
size?: "md" | "sm";
};
const BUTTON_VARIANTS: Record, string> = {
primary:
"bg-indigo-600 text-white hover:bg-indigo-700 disabled:hover:bg-indigo-600",
secondary:
"border border-slate-300 bg-white text-slate-700 hover:bg-slate-50 disabled:hover:bg-white",
ghost: "text-slate-600 hover:bg-slate-100 disabled:hover:bg-transparent",
danger: "bg-red-600 text-white hover:bg-red-700 disabled:hover:bg-red-600",
};
export function Button({
variant = "primary",
size = "md",
className,
...props
}: ButtonProps) {
return (
);
}
/* ------------------------------------------------------------------- Field */
export function Field({
label,
hint,
error,
htmlFor,
children,
}: {
label: string;
hint?: ReactNode;
error?: string | null;
htmlFor?: string;
children: ReactNode;
}) {
return (
{children}
{error ? (
{error}
) : hint ? (
{hint}
) : null}
);
}
export function TextInput({
invalid,
className,
...props
}: InputHTMLAttributes & { invalid?: boolean }) {
return (
);
}
/* ------------------------------------------------------------------- Badge */
export function Badge({
tone = "neutral",
children,
}: {
tone?: "neutral" | "popular" | "soon" | "success";
children: ReactNode;
}) {
const tones: Record = {
neutral: "bg-slate-100 text-slate-600",
popular: "bg-indigo-100 text-indigo-700",
soon: "bg-slate-100 text-slate-500",
success: "bg-emerald-100 text-emerald-700",
};
return (
{children}
);
}
/* ------------------------------------------------------------------ Notice */
export function Notice({
tone,
children,
}: {
tone: "warning" | "error" | "info" | "success";
children: ReactNode;
}) {
const tones: Record = {
warning: "border-amber-300 bg-amber-50 text-amber-900",
error: "border-red-300 bg-red-50 text-red-800",
info: "border-sky-300 bg-sky-50 text-sky-900",
success: "border-emerald-300 bg-emerald-50 text-emerald-900",
};
return (
{children}
);
}