Files
igny8/frontend/src/components/ui/list/List.tsx
2026-01-01 21:42:04 +00:00

191 lines
4.9 KiB
TypeScript

import { ReactNode } from "react";
import Checkbox from "../../form/input/Checkbox";
interface ListProps {
children: ReactNode;
variant?: "unordered" | "ordered" | "horizontal" | "button" | "icon" | "checkbox" | "radio";
className?: string;
}
export const List: React.FC<ListProps> = ({
children,
variant = "unordered",
className = "",
}) => {
const baseClasses = "rounded-lg border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03] sm:w-fit";
if (variant === "ordered") {
return (
<ol className={`flex flex-col list-decimal ${baseClasses} ${className}`}>
{children}
</ol>
);
}
if (variant === "horizontal") {
return (
<ul className={`flex flex-col md:flex-row ${baseClasses} ${className}`}>
{children}
</ul>
);
}
if (variant === "button") {
return (
<ul className={`w-full overflow-hidden rounded-lg border border-gray-200 bg-white dark:border-gray-800 dark:bg-white/[0.03] sm:w-[228px] flex flex-col ${className}`}>
{children}
</ul>
);
}
return (
<ul className={`flex flex-col ${baseClasses} ${className}`}>
{children}
</ul>
);
};
interface ListItemProps {
children: ReactNode;
variant?: "unordered" | "ordered" | "horizontal" | "button" | "icon" | "checkbox" | "radio";
onClick?: () => void;
disabled?: boolean;
className?: string;
}
export const ListItem: React.FC<ListItemProps> = ({
children,
variant = "unordered",
onClick,
disabled = false,
className = "",
}) => {
if (variant === "button") {
return (
<li className={`border-b border-gray-200 last:border-b-0 dark:border-gray-800 ${className}`}>
<button
className={`flex w-full items-center gap-3 px-3 py-2.5 text-sm font-medium text-gray-500 hover:bg-brand-50 hover:text-brand-500 dark:text-gray-400 dark:hover:bg-brand-500/[0.12] dark:hover:text-brand-400 ${disabled ? "disabled:opacity-50" : ""}`}
onClick={onClick}
disabled={disabled}
type="button"
>
{children}
</button>
</li>
);
}
if (variant === "horizontal") {
return (
<li className={`flex items-center gap-2 border-b border-gray-200 px-3 py-2.5 text-sm text-gray-500 last:border-0 dark:border-gray-800 dark:text-gray-400 md:border-b-0 md:border-r ${className}`}>
{children}
</li>
);
}
return (
<li className={`flex items-center gap-2 border-b border-gray-200 px-3 py-2.5 text-sm text-gray-500 last:border-b-0 dark:border-gray-800 dark:text-gray-400 ${className}`}>
{children}
</li>
);
};
interface ListDotProps {
className?: string;
}
export const ListDot: React.FC<ListDotProps> = ({ className = "" }) => {
return (
<span className={`ml-2 block h-[3px] w-[3px] rounded-full bg-gray-500 dark:bg-gray-400 ${className}`}></span>
);
};
interface ListIconProps {
children: ReactNode;
className?: string;
}
export const ListIcon: React.FC<ListIconProps> = ({
children,
className = "",
}) => {
return (
<span className={`text-brand-500 dark:text-brand-400 ${className}`}>
{children}
</span>
);
};
interface ListCheckboxItemProps {
id: string;
label: string;
checked?: boolean;
disabled?: boolean;
onChange?: (checked: boolean) => void;
className?: string;
}
export const ListCheckboxItem: React.FC<ListCheckboxItemProps> = ({
id,
label,
checked = false,
disabled = false,
onChange,
className = "",
}) => {
return (
<li className={`border-b border-gray-200 px-3 py-2.5 last:border-b-0 dark:border-gray-800 ${className}`}>
<Checkbox
id={id}
label={label}
checked={checked}
disabled={disabled}
onChange={(val) => onChange?.(val)}
/>
</li>
);
};
interface ListRadioItemProps {
id: string;
name: string;
value: string;
label: string;
checked?: boolean;
onChange?: (value: string) => void;
className?: string;
}
export const ListRadioItem: React.FC<ListRadioItemProps> = ({
id,
name,
value,
label,
checked = false,
onChange,
className = "",
}) => {
return (
<li className={`border-b border-gray-200 px-3 py-2.5 last:border-b-0 dark:border-gray-800 ${className}`}>
<label htmlFor={id} className="flex cursor-pointer select-none items-center text-sm text-gray-500 dark:text-gray-400">
<span className="relative">
<input
id={id}
className="sr-only"
type="radio"
value={value}
name={name}
checked={checked}
onChange={(e) => onChange?.(e.target.value)}
/>
<span className={`mr-2 flex h-4 w-4 items-center justify-center rounded-full border ${checked ? "border-brand-500 bg-brand-500" : "bg-transparent border-gray-300 dark:border-gray-700"}`}>
<span className="h-1.5 w-1.5 rounded-full bg-white dark:bg-gray-800"></span>
</span>
</span>
{label}
</label>
</li>
);
};