filter combo box

This commit is contained in:
Yash 2024-04-02 10:51:44 +00:00
parent 35f17603c0
commit 4400648205
7 changed files with 440 additions and 19 deletions

View file

@ -21,6 +21,7 @@
"@radix-ui/react-slot": "^1.0.2",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cmdk": "^1.0.0",
"framer-motion": "^11.0.24",
"lucide-react": "^0.338.0",
"next": "14.1.0",

View file

@ -26,6 +26,12 @@ dependencies:
clsx:
specifier: ^2.1.0
version: 2.1.0
cmdk:
specifier: ^1.0.0
version: 1.0.0(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
framer-motion:
specifier: ^11.0.24
version: 11.0.24(react-dom@18.2.0)(react@18.2.0)
lucide-react:
specifier: ^0.338.0
version: 0.338.0(react@18.2.0)
@ -1982,6 +1988,21 @@ packages:
engines: {node: '>=6'}
dev: false
/cmdk@1.0.0(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-gDzVf0a09TvoJ5jnuPvygTB77+XdOSwEmJ88L6XPFPlv7T3RxbP9jgenfylrAMD0+Le1aO0nVjQUzl2g+vjz5Q==}
peerDependencies:
react: ^18.0.0
react-dom: ^18.0.0
dependencies:
'@radix-ui/react-dialog': 1.0.5(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
'@radix-ui/react-primitive': 1.0.3(@types/react-dom@18.2.23)(@types/react@18.2.73)(react-dom@18.2.0)(react@18.2.0)
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
transitivePeerDependencies:
- '@types/react'
- '@types/react-dom'
dev: false
/code-block-writer@10.1.1:
resolution: {integrity: sha512-67ueh2IRGst/51p0n6FvPrnRjAGHY5F8xdjkgrYE7DDzpJe6qA07RYQ9VcoUeo5ATOjSOiWpSL3SWBRRbempMw==}
dev: true
@ -3243,6 +3264,25 @@ packages:
resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==}
dev: true
/framer-motion@11.0.24(react-dom@18.2.0)(react@18.2.0):
resolution: {integrity: sha512-l2iM8NR53qtcujgAqYvGPJJGModPNWEVUaATRDLfnaLvUoFpImovBm0AHalSSsY8tW6knP8mfJTW4WYGbnAe4w==}
peerDependencies:
'@emotion/is-prop-valid': '*'
react: ^18.0.0
react-dom: ^18.0.0
peerDependenciesMeta:
'@emotion/is-prop-valid':
optional: true
react:
optional: true
react-dom:
optional: true
dependencies:
react: 18.2.0
react-dom: 18.2.0(react@18.2.0)
tslib: 2.6.2
dev: false
/fs-extra@11.1.0:
resolution: {integrity: sha512-0rcTq621PD5jM/e0a3EJoGC/1TC5ZBCERW82LQuwfGnCa1V8w7dpYH1yNu+SLb6E5dkeCBzKEyLGlFrnr+dUyw==}
engines: {node: '>=14.14'}

View file

@ -1,8 +1,12 @@
import { SpaceIcon } from "@/assets/Memories";
"use client";
import { useState } from "react";
import { FilterCombobox } from "./Sidebar/FilterCombobox";
import { Textarea2 } from "./ui/textarea";
import { ArrowRight, ChevronDown, GlobeIcon } from "lucide-react";
import { ArrowRight } from "lucide-react";
export default function Main() {
const [value, setValue] = useState("");
return (
<main className="flex h-screen w-full items-center justify-center px-60">
<Textarea2
@ -10,20 +14,16 @@ export default function Main() {
textAreaProps={{
placeholder: "Ask your SuperMemory...",
className: "text-lg p-2 text-rgray-11",
value,
onChange: (e) => setValue(e.target.value),
}}
>
<div className="text-rgray-11/70 flex w-full items-center justify-center p-2">
<button className="text-rgray-11/70 focus-visible:ring-rgray-8 hover:bg-rgray-3 flex items-center justify-center gap-1 rounded-md px-2 py-1 ring-2 ring-transparent focus-visible:outline-none">
<SpaceIcon className="mr-1 h-5 w-5" />
Spaces
<ChevronDown className="h-4 w-4" />
</button>
<button className="text-rgray-11/70 focus-visible:ring-rgray-8 hover:bg-rgray-3 flex items-center justify-center gap-1 rounded-md px-2 py-1 ring-2 ring-transparent focus-visible:outline-none">
<GlobeIcon className="mr-1 h-4 w-4" />
Pages
<ChevronDown className="h-4 w-4" />
</button>
<button className="text-rgray-11/70 bg-rgray-3 focus-visible:ring-rgray-8 hover:bg-rgray-4 ml-auto flex items-center justify-center rounded-full p-2 ring-2 ring-transparent focus-visible:outline-none">
<div className="text-rgray-11/70 flex w-full items-center justify-center p-2 pl-0">
<FilterCombobox />
<button
disabled={value.trim().length < 1}
className="text-rgray-11/70 bg-rgray-3 focus-visible:ring-rgray-8 hover:bg-rgray-4 ml-auto flex items-center justify-center rounded-full p-2 ring-2 ring-transparent focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
>
<ArrowRight className="h-5 w-5" />
</button>
</div>

View file

@ -0,0 +1,103 @@
"use client";
import * as React from "react";
import { Check, ChevronsUpDown } from "lucide-react";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
Command,
CommandEmpty,
CommandGroup,
CommandInput,
CommandItem,
CommandList,
} from "@/components/ui/command";
import {
Popover,
PopoverContent,
PopoverTrigger,
} from "@/components/ui/popover";
import { SpaceIcon } from "@/assets/Memories";
const spaces = [
{
value: "1",
label: "Cool Tech",
},
{
value: "2",
label: "Cool Courses",
},
{
value: "3",
label: "Cool Libraries",
},
];
export function FilterCombobox() {
const [open, setOpen] = React.useState(false);
const [values, setValues] = React.useState<string[]>([]);
return (
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>
<button
data-state-on={open}
className="text-rgray-11/70 on:bg-rgray-3 focus-visible:ring-rgray-8 hover:bg-rgray-3 relative flex items-center justify-center gap-1 rounded-md px-3 py-1.5 ring-2 ring-transparent focus-visible:outline-none"
>
<SpaceIcon className="mr-1 h-5 w-5" />
Filter
<ChevronsUpDown className="h-4 w-4" />
<div
data-state-on={values.length > 0}
className="on:flex text-rgray-11 border-rgray-6 bg-rgray-2 absolute left-0 top-0 hidden aspect-[1] h-4 w-4 -translate-x-1/3 -translate-y-1/3 items-center justify-center rounded-full border text-center text-[9px]"
>
{values.length}
</div>
</button>
</PopoverTrigger>
<PopoverContent className="w-[200px] p-0">
<Command
filter={(val, search) =>
spaces
.find((s) => s.value === val)
?.label.toLowerCase()
.includes(search.toLowerCase().trim())
? 1
: 0
}
>
<CommandInput placeholder="Filter spaces..." />
<CommandList>
<CommandEmpty>Nothing found</CommandEmpty>
<CommandGroup>
{spaces.map((space) => (
<CommandItem
key={space.value}
value={space.value}
onSelect={(val) => {
console.log(val, "selected");
setValues((prev) =>
prev.includes(val)
? prev.filter((v) => v !== val)
: [...prev, val],
);
}}
>
<SpaceIcon className="mr-2 h-4 w-4" />
{space.label}
{values.includes(space.value)}
<Check
data-state-on={values.includes(space.value)}
className={cn("on:opacity-100 ml-auto h-4 w-4 opacity-0")}
/>
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
);
}

View file

@ -35,7 +35,7 @@ export default async function Sidebar() {
// data-state-on="true"
className="on:opacity-100 on:bg-rgray-4 focus-visible:ring-rgray-7 flex w-full flex-col items-center justify-center rounded-md px-3 py-3 opacity-80 ring-2 ring-transparent transition hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none"
>
<MemoryIcon className="h-12 w-12" />
<MemoryIcon className="h-10 w-10" />
<span className="">Memories</span>
</button>
<button
@ -46,7 +46,7 @@ export default async function Sidebar() {
<span className="">Trash</span>
</button>
<button
data-state-on="true"
// data-state-on="true"
className="on:opacity-100 on:bg-rgray-3 focus-visible:ring-rgray-7 flex w-full flex-col items-center justify-center gap-1 rounded-md px-3 py-4 opacity-80 ring-2 ring-transparent transition hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none"
>
<User2 strokeWidth={1.3} className="h-6 w-6" />
@ -81,12 +81,12 @@ export async function SubSidebar() {
];
return (
<aside className="bg-rgray-2 border-rgray-6 flex h-screen w-max flex-col items-center border-r px-3 py-5 font-light">
<aside className="bg-rgray-2 border-rgray-6 flex h-screen w-[20vw] flex-col items-center border-r px-3 py-5 font-light">
<button
// data-state-on="true"
className="on:opacity-100 on:bg-rgray-3 focus-visible:ring-rgray-7 flex w-full flex-col items-center justify-center rounded-md px-4 py-3 opacity-80 ring-2 ring-transparent transition hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none"
>
<MemoryIcon className="h-12 w-12" />
<MemoryIcon className="h-10 w-10" />
<span className="">Memories</span>
</button>
<button
@ -94,7 +94,7 @@ export async function SubSidebar() {
className="on:opacity-100 focus-visible:ring-rgray-7 mt-auto flex w-full flex-col items-center justify-center gap-1 rounded-md bg-black p-4 opacity-80 ring-2 ring-transparent transition hover:opacity-100 focus-visible:opacity-100 focus-visible:outline-none"
>
<Trash2 strokeWidth={1.3} className="h-6 w-6" />
<span className="">Trash3</span>
<span className="">Trash</span>
</button>
<button
// data-state-on="true"

View file

@ -0,0 +1,155 @@
"use client";
import * as React from "react";
import { type DialogProps } from "@radix-ui/react-dialog";
import { Command as CommandPrimitive } from "cmdk";
import { Search } from "lucide-react";
import { cn } from "@/lib/utils";
import { Dialog, DialogContent } from "@/components/ui/dialog";
const Command = React.forwardRef<
React.ElementRef<typeof CommandPrimitive>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
>(({ className, ...props }, ref) => (
<CommandPrimitive
ref={ref}
className={cn(
"bg-rgray-3 text-rgray-11 flex h-full w-full flex-col overflow-hidden rounded-md",
className,
)}
{...props}
/>
));
Command.displayName = CommandPrimitive.displayName;
interface CommandDialogProps extends DialogProps {}
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
return (
<Dialog {...props}>
<DialogContent className="overflow-hidden p-0 shadow-lg">
<Command className="[&_[cmdk-group-heading]]:text-rgray-11 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
{children}
</Command>
</DialogContent>
</Dialog>
);
};
const CommandInput = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Input>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
>(({ className, ...props }, ref) => (
<div
className="border-rgray-6 flex items-center border-b px-3"
cmdk-input-wrapper=""
>
<Search className="mr-2 h-4 w-4 shrink-0 opacity-50" />
<CommandPrimitive.Input
ref={ref}
className={cn(
"placeholder:text-rgray-11/50 flex h-11 w-full rounded-md bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50",
className,
)}
{...props}
/>
</div>
));
CommandInput.displayName = CommandPrimitive.Input.displayName;
const CommandList = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.List>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
>(({ className, ...props }, ref) => (
<CommandPrimitive.List
ref={ref}
className={cn("max-h-[300px] overflow-y-auto overflow-x-hidden", className)}
{...props}
/>
));
CommandList.displayName = CommandPrimitive.List.displayName;
const CommandEmpty = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Empty>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
>((props, ref) => (
<CommandPrimitive.Empty
ref={ref}
className="py-6 text-center text-sm"
{...props}
/>
));
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
const CommandGroup = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Group>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Group
ref={ref}
className={cn(
"text-rgray-12 [&_[cmdk-group-heading]]:text-rgray-11 overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium",
className,
)}
{...props}
/>
));
CommandGroup.displayName = CommandPrimitive.Group.displayName;
const CommandSeparator = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Separator>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Separator
ref={ref}
className={cn("bg-rgray-3 -mx-1 h-px", className)}
{...props}
/>
));
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
const CommandItem = React.forwardRef<
React.ElementRef<typeof CommandPrimitive.Item>,
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
>(({ className, ...props }, ref) => (
<CommandPrimitive.Item
ref={ref}
className={cn(
"aria-selected:bg-rgray-5 aria-selected:text-rgray-12 relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
className,
)}
{...props}
/>
));
CommandItem.displayName = CommandPrimitive.Item.displayName;
const CommandShortcut = ({
className,
...props
}: React.HTMLAttributes<HTMLSpanElement>) => {
return (
<span
className={cn("text-gray-11 ml-auto text-xs tracking-widest", className)}
{...props}
/>
);
};
CommandShortcut.displayName = "CommandShortcut";
export {
Command,
CommandDialog,
CommandInput,
CommandList,
CommandEmpty,
CommandGroup,
CommandItem,
CommandShortcut,
CommandSeparator,
};

View file

@ -0,0 +1,122 @@
"use client";
import * as React from "react";
import * as DialogPrimitive from "@radix-ui/react-dialog";
import { X } from "lucide-react";
import { cn } from "@/lib/utils";
const Dialog = DialogPrimitive.Root;
const DialogTrigger = DialogPrimitive.Trigger;
const DialogPortal = DialogPrimitive.Portal;
const DialogClose = DialogPrimitive.Close;
const DialogOverlay = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Overlay>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Overlay
ref={ref}
className={cn(
"data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80",
className,
)}
{...props}
/>
));
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
const DialogContent = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Content>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
>(({ className, children, ...props }, ref) => (
<DialogPortal>
<DialogOverlay />
<DialogPrimitive.Content
ref={ref}
className={cn(
"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-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] border-rgray-6 bg-rgray-3 fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg",
className,
)}
{...props}
>
{children}
<DialogPrimitive.Close className="ring-offset-rgray-2 focus:ring-rgray-7 data-[state=open]:bg-rgray-3 data-[state=open]:text-rgray-11 absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
<X className="h-4 w-4" />
<span className="sr-only">Close</span>
</DialogPrimitive.Close>
</DialogPrimitive.Content>
</DialogPortal>
));
DialogContent.displayName = DialogPrimitive.Content.displayName;
const DialogHeader = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col space-y-1.5 text-center sm:text-left",
className,
)}
{...props}
/>
);
DialogHeader.displayName = "DialogHeader";
const DialogFooter = ({
className,
...props
}: React.HTMLAttributes<HTMLDivElement>) => (
<div
className={cn(
"flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2",
className,
)}
{...props}
/>
);
DialogFooter.displayName = "DialogFooter";
const DialogTitle = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Title>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Title
ref={ref}
className={cn(
"text-lg font-semibold leading-none tracking-tight",
className,
)}
{...props}
/>
));
DialogTitle.displayName = DialogPrimitive.Title.displayName;
const DialogDescription = React.forwardRef<
React.ElementRef<typeof DialogPrimitive.Description>,
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
>(({ className, ...props }, ref) => (
<DialogPrimitive.Description
ref={ref}
className={cn("text-rgray-11 text-sm", className)}
{...props}
/>
));
DialogDescription.displayName = DialogPrimitive.Description.displayName;
export {
Dialog,
DialogPortal,
DialogOverlay,
DialogClose,
DialogTrigger,
DialogContent,
DialogHeader,
DialogFooter,
DialogTitle,
DialogDescription,
};