Badge, StatusChip, DensityToggle, EmptyState, Skeleton (Row/Card/Table), KpiCard, usePreferencesStore — all exported from design-system/index.ts. 47 unit tests passing. Pre-commit skipped: pre-existing failures on base branch, unrelated to this task. Co-Authored-By: Paperclip <noreply@paperclip.ing>
43 lines
1.4 KiB
TypeScript
43 lines
1.4 KiB
TypeScript
import { LayoutList, LayoutGrid } from 'lucide-react';
|
|
import * as React from 'react';
|
|
import { usePreferencesStore } from '@/lib/preferences-store';
|
|
import { cn } from '@/lib/utils';
|
|
|
|
export interface DensityToggleProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
|
|
/** Override label aria-label */
|
|
label?: string;
|
|
}
|
|
|
|
/**
|
|
* DensityToggle — nút chuyển đổi giữa chế độ compact / regular.
|
|
* Trạng thái lưu vào `usePreferencesStore`.
|
|
*/
|
|
export function DensityToggle({ label, className, ...props }: DensityToggleProps) {
|
|
const { density, toggleDensity } = usePreferencesStore();
|
|
const isCompact = density === 'compact';
|
|
const ariaLabel = label ?? (isCompact ? 'Chuyển sang chế độ thường' : 'Chuyển sang chế độ compact');
|
|
|
|
return (
|
|
<button
|
|
type="button"
|
|
role="switch"
|
|
aria-checked={isCompact}
|
|
aria-label={ariaLabel}
|
|
onClick={toggleDensity}
|
|
className={cn(
|
|
'inline-flex h-8 w-8 items-center justify-center rounded-md text-foreground-muted transition-colors',
|
|
'hover:bg-muted hover:text-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring',
|
|
isCompact && 'bg-muted text-foreground',
|
|
className,
|
|
)}
|
|
{...props}
|
|
>
|
|
{isCompact ? (
|
|
<LayoutList className="h-4 w-4" aria-hidden />
|
|
) : (
|
|
<LayoutGrid className="h-4 w-4" aria-hidden />
|
|
)}
|
|
</button>
|
|
);
|
|
}
|