feat: introduce DropdownMenu UI component and create HeatmapGrid file.

This commit is contained in:
Michael committed 2026-03-06 11:14:56 +01:00
1 parent baebf50d7a
commit eb5bceb5bf
2 files changed
+41 -13

No files matched your search

+10 -10
View File
@@ -42,7 +42,7 @@ function DropdownMenuContent({
data-slot="dropdown-menu-content" data-slot="dropdown-menu-content"
sideOffset={sideOffset} sideOffset={sideOffset}
className={cn( className={cn(
"z-50 max-h-(--radix-dropdown-menu-content-available-height) min-w-[8rem] origin-(--radix-dropdown-menu-content-transform-origin) overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-1 text-popover-foreground shadow-md data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[state=open]:animate-in data-[state=open]:fade-in-0 data-[state=open]:zoom-in-95", "z-50 max-h-[80vh] min-w-[12rem] overflow-x-hidden overflow-y-auto rounded-md border bg-popover p-2 text-popover-foreground shadow-md data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
className className
)} )}
{...props} {...props}
@@ -74,7 +74,7 @@ function DropdownMenuItem({
data-inset={inset} data-inset={inset}
data-variant={variant} data-variant={variant}
className={cn( className={cn(
"relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!", "relative flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm focus:outline-none select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 data-[inset]:pl-8 data-[variant=destructive]:text-destructive data-[variant=destructive]:focus:bg-destructive/10 data-[variant=destructive]:focus:text-destructive dark:data-[variant=destructive]:focus:bg-destructive/20 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='w-'])]:w-4 [&_svg:not([class*='h-'])]:h-4 [&_svg:not([class*='text-'])]:text-muted-foreground data-[variant=destructive]:*:[svg]:text-destructive!",
className className
)} )}
{...props} {...props}
@@ -92,15 +92,15 @@ function DropdownMenuCheckboxItem({
<DropdownMenuPrimitive.CheckboxItem <DropdownMenuPrimitive.CheckboxItem
data-slot="dropdown-menu-checkbox-item" data-slot="dropdown-menu-checkbox-item"
className={cn( className={cn(
"relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "relative flex cursor-default select-none items-center rounded-sm py-2 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className className
)} )}
checked={checked} checked={checked}
{...props} {...props}
> >
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <span className="pointer-events-none absolute left-2 flex w-3.5 h-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator> <DropdownMenuPrimitive.ItemIndicator>
<CheckIcon className="size-4" /> <CheckIcon className="w-4 h-4" />
</DropdownMenuPrimitive.ItemIndicator> </DropdownMenuPrimitive.ItemIndicator>
</span> </span>
{children} {children}
@@ -128,14 +128,14 @@ function DropdownMenuRadioItem({
<DropdownMenuPrimitive.RadioItem <DropdownMenuPrimitive.RadioItem
data-slot="dropdown-menu-radio-item" data-slot="dropdown-menu-radio-item"
className={cn( className={cn(
"relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4", "relative flex cursor-default items-center gap-2 rounded-sm py-1.5 pr-2 pl-8 text-sm focus:outline-none select-none focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='w-'])]:w-4 [&_svg:not([class*='h-'])]:h-4",
className className
)} )}
{...props} {...props}
> >
<span className="pointer-events-none absolute left-2 flex size-3.5 items-center justify-center"> <span className="pointer-events-none absolute left-2 flex w-3.5 h-3.5 items-center justify-center">
<DropdownMenuPrimitive.ItemIndicator> <DropdownMenuPrimitive.ItemIndicator>
<CircleIcon className="size-2 fill-current" /> <CircleIcon className="w-2 h-2 fill-current" />
</DropdownMenuPrimitive.ItemIndicator> </DropdownMenuPrimitive.ItemIndicator>
</span> </span>
{children} {children}
@@ -211,13 +211,13 @@ function DropdownMenuSubTrigger({
data-slot="dropdown-menu-sub-trigger" data-slot="dropdown-menu-sub-trigger"
data-inset={inset} data-inset={inset}
className={cn( className={cn(
"flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-hidden select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4 [&_svg:not([class*='text-'])]:text-muted-foreground", "flex cursor-default items-center gap-2 rounded-sm px-2 py-1.5 text-sm focus:outline-none select-none focus:bg-accent focus:text-accent-foreground data-[inset]:pl-8 data-[state=open]:bg-accent data-[state=open]:text-accent-foreground [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='w-'])]:w-4 [&_svg:not([class*='h-'])]:h-4 [&_svg:not([class*='text-'])]:text-muted-foreground",
className className
)} )}
{...props} {...props}
> >
{children} {children}
<ChevronRightIcon className="ml-auto size-4" /> <ChevronRightIcon className="ml-auto w-4 h-4" />
</DropdownMenuPrimitive.SubTrigger> </DropdownMenuPrimitive.SubTrigger>
) )
} }
+31 -3
View File
@@ -248,7 +248,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
}, },
{ {
accessorKey: "codein", accessorKey: "codein",
header: "Code", header: "Code interne",
size: 90, size: 90,
cell: ({ getValue }) => { cell: ({ getValue }) => {
const value = getValue<string>(); const value = getValue<string>();
@@ -266,7 +266,7 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
<div <div
onClick={handleCopy} onClick={handleCopy}
className="group flex items-center gap-1.5 cursor-pointer hover:text-emerald-500 transition-colors" className="group flex items-center gap-1.5 cursor-pointer hover:text-emerald-500 transition-colors"
title="Copier le code" title="Copier le code interne"
> >
<span className="tabular-nums font-bold text-[12px] tracking-tight opacity-70 group-hover:opacity-100" style={{ color: "var(--text-muted)" }}> <span className="tabular-nums font-bold text-[12px] tracking-tight opacity-70 group-hover:opacity-100" style={{ color: "var(--text-muted)" }}>
{value} {value}
@@ -282,6 +282,32 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
); );
}, },
}, },
{
accessorKey: "reference",
header: "Référence",
size: 110,
cell: ({ getValue }) => {
const val = getValue<string>();
return (
<span className="text-[12px] font-mono opacity-80" style={{ color: "var(--text-secondary)" }}>
{val || "-"}
</span>
);
},
},
{
accessorKey: "gtin",
header: "EAN / GTIN",
size: 120,
cell: ({ getValue }) => {
const val = getValue<string>();
return (
<span className="text-[12px] font-mono tracking-tight opacity-70" style={{ color: "var(--text-secondary)" }}>
{val || "-"}
</span>
);
},
},
{ {
accessorKey: "libelle1", accessorKey: "libelle1",
header: "Désignation", header: "Désignation",
@@ -432,7 +458,9 @@ export function HeatmapGrid({ onSelectionChange }: HeatmapGridProps) {
const search = String(filterValue).toLowerCase(); const search = String(filterValue).toLowerCase();
const libelle = String(row.original.libelle1 || "").toLowerCase(); const libelle = String(row.original.libelle1 || "").toLowerCase();
const code = String(row.original.codein || "").toLowerCase(); const code = String(row.original.codein || "").toLowerCase();
return libelle.includes(search) || code.includes(search); const reference = String(row.original.reference || "").toLowerCase();
const gtin = String(row.original.gtin || "").toLowerCase();
return libelle.includes(search) || code.includes(search) || reference.includes(search) || gtin.includes(search);
}, },
}); });