mirror of
https://github.com/Significant-Gravitas/AutoGPT.git
synced 2026-04-08 03:00:28 -04:00
fix filter sheets
This commit is contained in:
@@ -1,11 +1,12 @@
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { cn } from "@/lib/utils";
|
||||
import { X } from "lucide-react";
|
||||
import React, { ButtonHTMLAttributes } from "react";
|
||||
import React, { ButtonHTMLAttributes, useState } from "react";
|
||||
|
||||
interface Props extends ButtonHTMLAttributes<HTMLButtonElement> {
|
||||
selected?: boolean;
|
||||
number?: number;
|
||||
needHover?: boolean;
|
||||
name?: string;
|
||||
}
|
||||
|
||||
@@ -13,27 +14,31 @@ const FilterChip: React.FC<Props> = ({
|
||||
selected = false,
|
||||
number,
|
||||
name,
|
||||
needHover,
|
||||
className,
|
||||
...rest
|
||||
}) => {
|
||||
const [isHovering, setIsHovering] = useState(false);
|
||||
return (
|
||||
<Button
|
||||
className={cn(
|
||||
"group w-fit space-x-1 rounded-[1.5rem] border border-zinc-300 bg-transparent px-[0.625rem] py-[0.375rem] shadow-none hover:bg-zinc-100 focus:ring-0 disabled:pointer-events-none",
|
||||
)}
|
||||
{...rest}
|
||||
onMouseEnter={() => setIsHovering(true)}
|
||||
onMouseLeave={() => setIsHovering(false)}
|
||||
>
|
||||
<span className="font-sans text-sm font-medium leading-[1.375rem] text-zinc-600 group-disabled:text-zinc-400">
|
||||
{name}
|
||||
</span>
|
||||
{selected &&
|
||||
(number ? (
|
||||
(needHover && isHovering && number ? (
|
||||
<span className="flex h-[1.375rem] items-center rounded-[1.25rem] bg-violet-700 p-[0.375rem] text-zinc-50">
|
||||
{number}
|
||||
{number > 100 ? "100+" : number}
|
||||
</span>
|
||||
) : (
|
||||
<span className="flex h-5 w-5 items-center justify-center rounded-full bg-zinc-600">
|
||||
<X className="h-4 w-4 rounded-full text-white" strokeWidth={1.25} />
|
||||
<span className="flex h-4 w-4 items-center justify-center rounded-full bg-zinc-600">
|
||||
<X className="h-3 w-3 rounded-full text-white" strokeWidth={2} />
|
||||
</span>
|
||||
))}
|
||||
</Button>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Used v0 for this component, so review it very carefully
|
||||
|
||||
import FilterChip from "../FilterChip";
|
||||
import { useState, useEffect } from "react";
|
||||
import { useState, useEffect, Dispatch, SetStateAction } from "react";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { X } from "lucide-react";
|
||||
import { cn } from "@/lib/utils";
|
||||
@@ -12,30 +12,72 @@ import { Checkbox } from "@/components/ui/checkbox";
|
||||
export default function FilterSheet({
|
||||
filters,
|
||||
creators,
|
||||
onCategoryChange,
|
||||
onCreatorChange,
|
||||
setFilters,
|
||||
categories,
|
||||
}: {
|
||||
filters: Filters;
|
||||
creators: string[];
|
||||
onCategoryChange: (category: CategoryKey) => void;
|
||||
onCreatorChange: (creator: string) => void;
|
||||
setFilters: Dispatch<SetStateAction<Filters>>;
|
||||
categories: Array<{ key: CategoryKey; name: string }>;
|
||||
}) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
const [isSheetVisible, setIsSheetVisible] = useState(false);
|
||||
const [localFilters, setLocalFilters] = useState<Filters>(filters);
|
||||
|
||||
// Animation
|
||||
useEffect(() => {
|
||||
if (isOpen) {
|
||||
setIsSheetVisible(true);
|
||||
// Reset local filters to current filters when opening
|
||||
setLocalFilters(filters);
|
||||
} else {
|
||||
const timer = setTimeout(() => {
|
||||
setIsSheetVisible(false);
|
||||
}, 300);
|
||||
return () => clearTimeout(timer);
|
||||
}
|
||||
}, [isOpen]);
|
||||
}, [isOpen, filters]);
|
||||
|
||||
const onCategoryChange = (category: CategoryKey) => {
|
||||
setLocalFilters({
|
||||
...localFilters,
|
||||
categories: {
|
||||
...localFilters.categories,
|
||||
[category]: !localFilters.categories[category],
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
const onCreatorChange = (creator: string) => {
|
||||
const updatedCreators = localFilters.createdBy.includes(creator)
|
||||
? localFilters.createdBy.filter((c) => c !== creator)
|
||||
: [...localFilters.createdBy, creator];
|
||||
|
||||
setLocalFilters({
|
||||
...localFilters,
|
||||
createdBy: updatedCreators,
|
||||
});
|
||||
};
|
||||
|
||||
const handleApplyFilters = () => {
|
||||
setFilters(localFilters);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
const handleClearFilters = () => {
|
||||
const clearedFilters: Filters = {
|
||||
categories: {
|
||||
blocks: false,
|
||||
integrations: false,
|
||||
marketplace_agents: false,
|
||||
my_agents: false,
|
||||
templates: false,
|
||||
},
|
||||
createdBy: [],
|
||||
};
|
||||
setFilters(clearedFilters);
|
||||
setIsOpen(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="m-0 inline w-fit p-0">
|
||||
@@ -80,11 +122,11 @@ export default function FilterSheet({
|
||||
|
||||
{/* Categories */}
|
||||
|
||||
<div className="px-5">
|
||||
<div className="space-y-4 px-5">
|
||||
<p className="font-sans text-base font-medium text-zinc-800">
|
||||
Categories
|
||||
</p>
|
||||
<div className="mt-2 space-y-2">
|
||||
<div className="space-y-2">
|
||||
{categories.map((category) => (
|
||||
<div
|
||||
key={category.key}
|
||||
@@ -92,7 +134,7 @@ export default function FilterSheet({
|
||||
>
|
||||
<Checkbox
|
||||
id={category.key}
|
||||
checked={filters.categories[category.key]}
|
||||
checked={localFilters.categories[category.key]}
|
||||
onCheckedChange={() => onCategoryChange(category.key)}
|
||||
className="border border-[#D4D4D4] shadow-none data-[state=checked]:border-none data-[state=checked]:bg-zinc-500 data-[state=checked]:text-white"
|
||||
/>
|
||||
@@ -111,18 +153,18 @@ export default function FilterSheet({
|
||||
|
||||
{/* Created By */}
|
||||
|
||||
<div className="px-5">
|
||||
<div className="space-y-4 px-5">
|
||||
<p className="font-sans text-base font-medium text-zinc-800">
|
||||
Created by
|
||||
</p>
|
||||
<div className="mt-2 space-y-2">
|
||||
<div className="space-y-2">
|
||||
{creators.map((creator) => (
|
||||
<div key={creator} className="flex items-center space-x-2">
|
||||
<Checkbox
|
||||
id={`creator-${creator}`}
|
||||
checked={filters.createdBy.includes(creator)}
|
||||
checked={localFilters.createdBy.includes(creator)}
|
||||
onCheckedChange={() => onCreatorChange(creator)}
|
||||
className="border border-[#D4D4D4] shadow-none data-[state=checked]:bg-white data-[state=checked]:text-zinc-500"
|
||||
className="border border-[#D4D4D4] shadow-none data-[state=checked]:border-none data-[state=checked]:bg-zinc-500 data-[state=checked]:text-white"
|
||||
/>
|
||||
<label
|
||||
htmlFor={`creator-${creator}`}
|
||||
@@ -133,6 +175,30 @@ export default function FilterSheet({
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<Button
|
||||
variant={"link"}
|
||||
className="m-0 p-0 font-sans text-sm font-medium leading-[1.375rem] text-zinc-800 underline hover:text-zinc-600"
|
||||
>
|
||||
More
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
{/* Footer buttons */}
|
||||
<div className="absolute bottom-0 flex w-full justify-between gap-3 border-t border-zinc-300 px-5 py-3">
|
||||
<Button
|
||||
className="min-w-[5rem] rounded-[0.5rem] border-none px-1.5 py-2 font-sans text-sm font-medium leading-[1.375rem] text-zinc-800 shadow-none ring-1 ring-zinc-400"
|
||||
variant={"outline"}
|
||||
onClick={handleClearFilters}
|
||||
>
|
||||
Clear
|
||||
</Button>
|
||||
|
||||
<Button
|
||||
className="min-w-[6.25rem] rounded-[0.5rem] border-none bg-zinc-700 px-1.5 py-2 font-sans text-sm font-medium leading-[1.375rem] text-white shadow-none ring-1 ring-zinc-700"
|
||||
onClick={handleApplyFilters}
|
||||
>
|
||||
Apply filters
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
|
||||
@@ -76,16 +76,14 @@ const FiltersList = () => {
|
||||
filters={filters}
|
||||
creators={creators}
|
||||
categories={categories}
|
||||
onCategoryChange={handleCategoryFilter}
|
||||
onCreatorChange={handleCreatorFilter}
|
||||
setFilters={setFilters}
|
||||
/>
|
||||
|
||||
{filters.createdBy.map((creator) => (
|
||||
<FilterChip
|
||||
key={creator}
|
||||
name={creator}
|
||||
name={"Created by " + creator}
|
||||
selected={true}
|
||||
number={4}
|
||||
onClick={() => handleCreatorFilter(creator)}
|
||||
/>
|
||||
))}
|
||||
@@ -94,6 +92,11 @@ const FiltersList = () => {
|
||||
<FilterChip
|
||||
key={category.key}
|
||||
name={category.name}
|
||||
needHover={
|
||||
Object.values(filters.categories).filter(Boolean).length === 1 &&
|
||||
filters.categories[category.key]
|
||||
}
|
||||
number={103}
|
||||
selected={filters.categories[category.key]}
|
||||
onClick={() => handleCategoryFilter(category.key)}
|
||||
/>
|
||||
|
||||
@@ -14,7 +14,7 @@ const Checkbox = React.forwardRef<
|
||||
<CheckboxPrimitive.Root
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-neutral-200 border-neutral-900 shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-neutral-950 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-neutral-900 data-[state=checked]:text-neutral-50 dark:border-neutral-50 dark:border-neutral-800 dark:focus-visible:ring-neutral-300 dark:data-[state=checked]:bg-neutral-50 dark:data-[state=checked]:text-neutral-900",
|
||||
"peer h-4 w-4 shrink-0 rounded-sm border border-neutral-900 shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-neutral-950 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-neutral-900 data-[state=checked]:text-neutral-50 dark:border-neutral-50 dark:border-neutral-800 dark:focus-visible:ring-neutral-300 dark:data-[state=checked]:bg-neutral-50 dark:data-[state=checked]:text-neutral-900",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
||||
Reference in New Issue
Block a user