mirror of
https://github.com/pacnpal/thrilltrack-explorer.git
synced 2025-12-21 11:51:14 -05:00
Refactor code structure and remove redundant changes
This commit is contained in:
143
src-old/components/ui/multi-select-combobox.tsx
Normal file
143
src-old/components/ui/multi-select-combobox.tsx
Normal file
@@ -0,0 +1,143 @@
|
||||
import * as React from "react";
|
||||
import { useState, useMemo } from "react";
|
||||
import { Check, ChevronsUpDown, X } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Badge } from "@/components/ui/badge";
|
||||
import { Checkbox } from "@/components/ui/checkbox";
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from "@/components/ui/command";
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "@/components/ui/popover";
|
||||
|
||||
export interface MultiSelectOption {
|
||||
label: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
interface MultiSelectComboboxProps {
|
||||
options: MultiSelectOption[];
|
||||
value?: string[];
|
||||
onValueChange: (values: string[]) => void;
|
||||
placeholder?: string;
|
||||
searchPlaceholder?: string;
|
||||
emptyText?: string;
|
||||
maxDisplay?: number;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
export function MultiSelectCombobox({
|
||||
options,
|
||||
value = [],
|
||||
onValueChange,
|
||||
placeholder = "Select options...",
|
||||
searchPlaceholder = "Search...",
|
||||
emptyText = "No options found.",
|
||||
maxDisplay = 2,
|
||||
className,
|
||||
}: MultiSelectComboboxProps) {
|
||||
const [open, setOpen] = useState(false);
|
||||
|
||||
const handleSelect = (selectedValue: string) => {
|
||||
const newValues = value.includes(selectedValue)
|
||||
? value.filter((v) => v !== selectedValue)
|
||||
: [...value, selectedValue];
|
||||
onValueChange(newValues);
|
||||
};
|
||||
|
||||
const handleRemove = (valueToRemove: string) => {
|
||||
onValueChange(value.filter((v) => v !== valueToRemove));
|
||||
};
|
||||
|
||||
const displayText = useMemo(() => {
|
||||
if (value.length === 0) return placeholder;
|
||||
if (value.length <= maxDisplay) {
|
||||
return value
|
||||
.map((v) => options.find((o) => o.value === v)?.label)
|
||||
.filter(Boolean)
|
||||
.join(", ");
|
||||
}
|
||||
return `${value.length} selected`;
|
||||
}, [value, options, maxDisplay, placeholder]);
|
||||
|
||||
return (
|
||||
<div className="space-y-2">
|
||||
<Popover open={open} onOpenChange={setOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className={cn("w-full justify-between", className)}
|
||||
>
|
||||
<span className="truncate">{displayText}</span>
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-full p-0 z-50" align="start">
|
||||
<Command>
|
||||
<CommandInput placeholder={searchPlaceholder} />
|
||||
<CommandList>
|
||||
<CommandEmpty>{emptyText}</CommandEmpty>
|
||||
<CommandGroup>
|
||||
{options.map((option) => (
|
||||
<CommandItem
|
||||
key={option.value}
|
||||
value={option.value}
|
||||
onSelect={() => handleSelect(option.value)}
|
||||
>
|
||||
<Checkbox
|
||||
checked={value.includes(option.value)}
|
||||
className="mr-2"
|
||||
/>
|
||||
<span>{option.label}</span>
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
|
||||
{/* Selected Items Display */}
|
||||
{value.length > 0 && (
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{value.map((v) => {
|
||||
const option = options.find((o) => o.value === v);
|
||||
return option ? (
|
||||
<Badge key={v} variant="secondary" className="gap-1">
|
||||
{option.label}
|
||||
<X
|
||||
className="w-3 h-3 cursor-pointer hover:text-destructive"
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
handleRemove(v);
|
||||
}}
|
||||
/>
|
||||
</Badge>
|
||||
) : null;
|
||||
})}
|
||||
{value.length > 1 && (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="sm"
|
||||
className="h-6 px-2 text-xs"
|
||||
onClick={() => onValueChange([])}
|
||||
>
|
||||
Clear all
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user