"use client";
import {
type ButtonHTMLAttributes,
type InputHTMLAttributes,
type ReactNode,
type SelectHTMLAttributes,
type TextareaHTMLAttributes,
useEffect,
} from "react";
import { cn } from "@/lib/utils";
import { CloseIcon, SpinnerIcon } from "./icons";
/* ------------------------------- Button -------------------------------- */
type ButtonVariant = "primary" | "secondary" | "danger" | "ghost";
interface ButtonProps extends ButtonHTMLAttributes {
variant?: ButtonVariant;
loading?: boolean;
icon?: ReactNode;
}
const buttonVariants: Record = {
primary: "bg-primary text-white hover:bg-primary-hover",
secondary:
"bg-surface-muted text-foreground hover:bg-[#e2e6f2] border border-border",
danger: "bg-danger text-white hover:opacity-90",
ghost: "text-muted hover:bg-surface-muted",
};
export function Button({
variant = "primary",
loading,
icon,
className,
children,
disabled,
...props
}: ButtonProps) {
return (
);
}
/* ------------------------------- Fields -------------------------------- */
export function Field({
label,
hint,
required,
children,
}: {
label: string;
hint?: string;
required?: boolean;
children: ReactNode;
}) {
return (
);
}
const fieldClass =
"w-full rounded-xl border border-border bg-surface px-3 py-2 text-sm outline-none transition focus:border-primary focus:ring-4 focus:ring-[var(--ring)] disabled:opacity-60";
export function Input(props: InputHTMLAttributes) {
return ;
}
export function Textarea(props: TextareaHTMLAttributes) {
return (
);
}
export function Select(props: SelectHTMLAttributes) {
return ;
}
export function Switch({
checked,
onChange,
label,
}: {
checked: boolean;
onChange: (v: boolean) => void;
label?: string;
}) {
return (
);
}
/* ----------------------------- Containers ------------------------------ */
export function Card({
className,
children,
}: {
className?: string;
children: ReactNode;
}) {
return (
{children}
);
}
export function PageHeader({
title,
subtitle,
action,
}: {
title: string;
subtitle?: string;
action?: ReactNode;
}) {
return (
{title}
{subtitle &&
{subtitle}
}
{action}
);
}
export function Badge({
children,
tone = "neutral",
}: {
children: ReactNode;
tone?: "neutral" | "success" | "danger" | "primary";
}) {
return (
{children}
);
}
export function EmptyState({
title,
message,
icon,
action,
}: {
title?: string;
message: string;
icon?: ReactNode;
action?: ReactNode;
}) {
return (
{icon ?? "🌙"}
{title &&
{title}
}
{message}
{action &&
{action}
}
);
}
export function Spinner({ className }: { className?: string }) {
return ;
}
/* ------------------------------- Modal --------------------------------- */
export function Modal({
open,
onClose,
title,
children,
footer,
}: {
open: boolean;
onClose: () => void;
title: string;
children: ReactNode;
footer?: ReactNode;
}) {
useEffect(() => {
if (!open) return;
const onKey = (e: KeyboardEvent) => e.key === "Escape" && onClose();
document.addEventListener("keydown", onKey);
return () => document.removeEventListener("keydown", onKey);
}, [open, onClose]);
if (!open) return null;
return (
{title}
{children}
{footer && (
{footer}
)}
);
}
export function ConfirmDialog({
open,
title = "حذف مورد",
message,
confirmText = "حذف",
loading,
onConfirm,
onClose,
}: {
open: boolean;
title?: string;
message: string;
confirmText?: string;
loading?: boolean;
onConfirm: () => void;
onClose: () => void;
}) {
return (
>
}
>
{message}
);
}