-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* Add react-table dependency * Add shadcn Tasks components * Expose PopoverClose * Add adapted filters for future tags
- Loading branch information
Showing
10 changed files
with
622 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
import { Button } from "@/components/ui/button"; | ||
import { | ||
DropdownMenu, | ||
DropdownMenuContent, | ||
DropdownMenuItem, | ||
DropdownMenuSeparator, | ||
DropdownMenuTrigger, | ||
} from "@/components/ui/dropdown-menu"; | ||
import { cn } from "@/lib/utils"; | ||
import { | ||
ArrowDownIcon, | ||
ArrowUpIcon, | ||
CaretSortIcon, | ||
EyeNoneIcon, | ||
} from "@radix-ui/react-icons"; | ||
import { Column } from "@tanstack/react-table"; | ||
|
||
interface DataTableColumnHeaderProps<TData, TValue> | ||
extends React.HTMLAttributes<HTMLDivElement> { | ||
column: Column<TData, TValue>; | ||
title: string; | ||
} | ||
|
||
export function DataTableColumnHeader<TData, TValue>({ | ||
column, | ||
title, | ||
className, | ||
}: DataTableColumnHeaderProps<TData, TValue>) { | ||
if (!column.getCanSort()) { | ||
return <div className={cn(className)}>{title}</div>; | ||
} | ||
|
||
return ( | ||
<div className={cn("flex items-center space-x-2", className)}> | ||
<DropdownMenu> | ||
<DropdownMenuTrigger asChild> | ||
<Button | ||
variant="ghost" | ||
size="sm" | ||
className="-ml-3 h-8 data-[state=open]:bg-accent" | ||
> | ||
<span>{title}</span> | ||
{column.getIsSorted() === "desc" ? ( | ||
<ArrowDownIcon className="ml-2 h-4 w-4" /> | ||
) : column.getIsSorted() === "asc" ? ( | ||
<ArrowUpIcon className="ml-2 h-4 w-4" /> | ||
) : ( | ||
<CaretSortIcon className="ml-2 h-4 w-4" /> | ||
)} | ||
</Button> | ||
</DropdownMenuTrigger> | ||
<DropdownMenuContent align="start"> | ||
<DropdownMenuItem onClick={() => column.toggleSorting(false)}> | ||
<ArrowUpIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" /> | ||
Asc | ||
</DropdownMenuItem> | ||
<DropdownMenuItem onClick={() => column.toggleSorting(true)}> | ||
<ArrowDownIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" /> | ||
Desc | ||
</DropdownMenuItem> | ||
<DropdownMenuSeparator /> | ||
<DropdownMenuItem onClick={() => column.toggleVisibility(false)}> | ||
<EyeNoneIcon className="mr-2 h-3.5 w-3.5 text-muted-foreground/70" /> | ||
Hide | ||
</DropdownMenuItem> | ||
</DropdownMenuContent> | ||
</DropdownMenu> | ||
</div> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,129 @@ | ||
"use client"; | ||
|
||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Popover, | ||
PopoverClose, | ||
PopoverContent, | ||
PopoverTrigger, | ||
} from "@/components/ui/popover"; | ||
import { Pencil2Icon } from "@radix-ui/react-icons"; | ||
import { Column } from "@tanstack/react-table"; | ||
import { useState } from "react"; | ||
import { Input } from "../ui/input"; | ||
import { Label } from "../ui/label"; | ||
|
||
interface DataTableKvButtonProps<TData, TValue> { | ||
column?: Column<TData, TValue>; | ||
filteredKey: string; | ||
} | ||
|
||
export function DataTableKvButton<TData, TValue>({ | ||
column, | ||
filteredKey, | ||
}: DataTableKvButtonProps<TData, TValue>) { | ||
const [open, setOpen] = useState(false); | ||
const [filteredValue, setFilteredValue] = useState( | ||
(column?.getFilterValue() as Map<string, string>).get(filteredKey) || "", | ||
); | ||
|
||
return ( | ||
<Popover | ||
open={open} | ||
onOpenChange={(open) => { | ||
setOpen(open); | ||
setFilteredValue( | ||
(column?.getFilterValue() as Map<string, string>).get(filteredKey) || | ||
"", | ||
); | ||
}} | ||
> | ||
<PopoverTrigger asChild> | ||
<Button variant="outline" size="sm" className="h-8"> | ||
{filteredKey} | ||
<Pencil2Icon className="ml-2 h-4 w-4" /> | ||
</Button> | ||
</PopoverTrigger> | ||
<PopoverContent className="w-80" forceMount> | ||
<div className="grid gap-4"> | ||
<div className="space-y-2"> | ||
<h4 className="font-medium leading-none">Filter {filteredKey}</h4> | ||
</div> | ||
<form | ||
className="space-y-2" | ||
onSubmit={(e) => { | ||
e.preventDefault(); | ||
}} | ||
> | ||
<div className="grid gap-2"> | ||
<div className="grid grid-cols-3 items-center gap-4"> | ||
<Label htmlFor="width">Key</Label> | ||
<Input | ||
id="key" | ||
className="col-span-2 h-8" | ||
defaultValue={filteredKey} | ||
disabled | ||
aria-disabled | ||
/> | ||
</div> | ||
<div className="grid grid-cols-3 items-center gap-4"> | ||
<Label htmlFor="maxWidth">Value</Label> | ||
<Input | ||
id="value" | ||
className="col-span-2 h-8" | ||
value={filteredValue} | ||
onChange={({ target }) => { | ||
setFilteredValue(target.value); | ||
}} | ||
/> | ||
</div> | ||
</div> | ||
<div className="grid grid-cols-3 gap-2"> | ||
<Button | ||
type="button" | ||
variant="destructive" | ||
onClick={() => { | ||
column?.setFilterValue( | ||
(kvs: Map<string, string> | undefined) => { | ||
if (kvs) { | ||
const newKvs = kvs; | ||
newKvs.delete(filteredKey); | ||
return newKvs.size > 0 ? newKvs : undefined; | ||
} | ||
}, | ||
); | ||
setOpen(false); | ||
}} | ||
> | ||
Remove | ||
</Button> | ||
<PopoverClose asChild> | ||
<Button type="button" variant="secondary"> | ||
Cancel | ||
</Button> | ||
</PopoverClose> | ||
<Button | ||
type="submit" | ||
disabled={!filteredValue} | ||
onClick={() => { | ||
column?.setFilterValue( | ||
(kvs: Map<string, string> | undefined) => { | ||
if (kvs) { | ||
return kvs.set(filteredKey, filteredValue); | ||
} else { | ||
return new Map([[filteredKey, filteredValue]]); | ||
} | ||
}, | ||
); | ||
setOpen(false); | ||
}} | ||
> | ||
Filter | ||
</Button> | ||
</div> | ||
</form> | ||
</div> | ||
</PopoverContent> | ||
</Popover> | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
"use client"; | ||
|
||
import { Button } from "@/components/ui/button"; | ||
import { | ||
Popover, | ||
PopoverClose, | ||
PopoverContent, | ||
PopoverTrigger, | ||
} from "@/components/ui/popover"; | ||
import { Separator } from "@/components/ui/separator"; | ||
import { PlusCircledIcon } from "@radix-ui/react-icons"; | ||
import { Column } from "@tanstack/react-table"; | ||
import { useState } from "react"; | ||
import { Input } from "../ui/input"; | ||
import { Label } from "../ui/label"; | ||
import { DataTableKvButton } from "./data-table-kv-button"; | ||
|
||
interface DataTableKvFilterProps<TData, TValue> { | ||
column?: Column<TData, TValue>; | ||
title?: string; | ||
} | ||
|
||
export function DataTableKvFilter<TData, TValue>({ | ||
column, | ||
title, | ||
}: DataTableKvFilterProps<TData, TValue>) { | ||
const [open, setOpen] = useState(false); | ||
const [kvKey, setKvKey] = useState(""); | ||
const [kvValue, setKvValue] = useState(""); | ||
|
||
const filteredKeys = Array.from( | ||
(column?.getFilterValue() as Map<string, string>)?.keys() ?? new Map(), | ||
).sort(); | ||
|
||
return ( | ||
<Popover open={open} onOpenChange={setOpen}> | ||
<div className="flex flex-wrap gap-2"> | ||
{filteredKeys.map((filteredKey) => ( | ||
<DataTableKvButton | ||
key={filteredKey} | ||
column={column} | ||
filteredKey={filteredKey} | ||
/> | ||
))} | ||
<Separator orientation="vertical" className="mx-2 h-8" /> | ||
<PopoverTrigger asChild> | ||
<Button variant="outline" size="sm" className="h-8 border-dashed"> | ||
<PlusCircledIcon className="mr-2 h-4 w-4" /> | ||
{title} | ||
</Button> | ||
</PopoverTrigger> | ||
</div> | ||
<PopoverContent className="w-80"> | ||
<div className="grid gap-4"> | ||
<div className="space-y-2"> | ||
<h4 className="font-medium leading-none"> | ||
New {column?.id} filter | ||
</h4> | ||
</div> | ||
<form | ||
className="space-y-2" | ||
onSubmit={(e) => { | ||
e.preventDefault(); | ||
}} | ||
> | ||
<div className="grid gap-2"> | ||
<div className="grid grid-cols-3 items-center gap-4"> | ||
<Label htmlFor="width">Key</Label> | ||
<Input | ||
id="key" | ||
className="col-span-2 h-8" | ||
value={kvKey} | ||
onChange={({ target }) => { | ||
setKvKey(target.value); | ||
}} | ||
/> | ||
</div> | ||
<div className="grid grid-cols-3 items-center gap-4"> | ||
<Label htmlFor="maxWidth">Value</Label> | ||
<Input | ||
id="value" | ||
className="col-span-2 h-8" | ||
value={kvValue} | ||
onChange={({ target }) => { | ||
setKvValue(target.value); | ||
}} | ||
/> | ||
</div> | ||
</div> | ||
<div className="grid grid-cols-3 gap-2"> | ||
<PopoverClose asChild> | ||
<Button | ||
type="button" | ||
variant="secondary" | ||
className="col-start-2" | ||
> | ||
Cancel | ||
</Button> | ||
</PopoverClose> | ||
<Button | ||
type="submit" | ||
disabled={!kvKey || !kvValue} | ||
onClick={() => { | ||
column?.setFilterValue( | ||
(kvs: Map<string, string> | undefined) => { | ||
if (kvs) { | ||
return kvs.set(kvKey, kvValue); | ||
} else { | ||
return new Map([[kvKey, kvValue]]); | ||
} | ||
}, | ||
); | ||
setOpen(false); | ||
setKvKey(""); | ||
setKvValue(""); | ||
}} | ||
> | ||
Filter | ||
</Button> | ||
</div> | ||
</form> | ||
</div> | ||
</PopoverContent> | ||
</Popover> | ||
); | ||
} |
Oops, something went wrong.