diff --git a/frontend/package-lock.json b/frontend/package-lock.json index b2c6892..1f37bc8 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -36,6 +36,7 @@ "better-auth": "^1.3.11", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cmdk": "^1.1.1", "date-fns": "^4.1.0", "is-mobile": "^5.0.0", "js-cookie": "^3.0.5", @@ -4945,6 +4946,22 @@ "node": ">=6" } }, + "node_modules/cmdk": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cmdk/-/cmdk-1.1.1.tgz", + "integrity": "sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-compose-refs": "^1.1.1", + "@radix-ui/react-dialog": "^1.1.6", + "@radix-ui/react-id": "^1.1.0", + "@radix-ui/react-primitive": "^2.0.2" + }, + "peerDependencies": { + "react": "^18 || ^19 || ^19.0.0-rc", + "react-dom": "^18 || ^19 || ^19.0.0-rc" + } + }, "node_modules/color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index d3ea4bc..5e3cb3f 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -38,6 +38,7 @@ "better-auth": "^1.3.11", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", + "cmdk": "^1.1.1", "date-fns": "^4.1.0", "is-mobile": "^5.0.0", "js-cookie": "^3.0.5", diff --git a/frontend/src/components/ui/command.tsx b/frontend/src/components/ui/command.tsx new file mode 100644 index 0000000..8cb4ca7 --- /dev/null +++ b/frontend/src/components/ui/command.tsx @@ -0,0 +1,184 @@ +"use client" + +import * as React from "react" +import { Command as CommandPrimitive } from "cmdk" +import { SearchIcon } from "lucide-react" + +import { cn } from "@/lib/utils" +import { + Dialog, + DialogContent, + DialogDescription, + DialogHeader, + DialogTitle, +} from "@/components/ui/dialog" + +function Command({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandDialog({ + title = "Command Palette", + description = "Search for a command to run...", + children, + className, + showCloseButton = true, + ...props +}: React.ComponentProps & { + title?: string + description?: string + className?: string + showCloseButton?: boolean +}) { + return ( + + + {title} + {description} + + + + {children} + + + + ) +} + +function CommandInput({ + className, + ...props +}: React.ComponentProps) { + return ( +
+ + +
+ ) +} + +function CommandList({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandEmpty({ + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandGroup({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandItem({ + className, + ...props +}: React.ComponentProps) { + return ( + + ) +} + +function CommandShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ) +} + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +} diff --git a/frontend/src/lib/formStuff/components/Searchable.tsx b/frontend/src/lib/formStuff/components/Searchable.tsx new file mode 100644 index 0000000..9e5e53d --- /dev/null +++ b/frontend/src/lib/formStuff/components/Searchable.tsx @@ -0,0 +1,98 @@ +import { Check, ChevronsUpDown } from "lucide-react"; +import { useState } from "react"; +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 { cn } from "@/lib/utils"; +import { Label } from "../../../components/ui/label"; +import { useFieldContext } from ".."; +import { FieldErrors } from "./FieldErrors"; + +type SelectOption = { + value: string; + label: string; +}; + +type SelectFieldProps = { + label: string; + options: SelectOption[]; + searchFor?: string; +}; + +export const Searchable = ({ label, options, searchFor }: SelectFieldProps) => { + const field = useFieldContext(); + const [open, setOpen] = useState(false); + + return ( +
+
+ + + + + + + + + + {`No ${searchFor} found.`} + + {options.map((options) => ( + { + field.handleChange( + currentValue === field.state.value + ? "" + : currentValue, + ); + setOpen(false); + }} + > + {options.label} + + + ))} + + + + + +
+ +
+ ); +}; diff --git a/frontend/src/lib/formStuff/index.tsx b/frontend/src/lib/formStuff/index.tsx index 448385e..bcd993b 100644 --- a/frontend/src/lib/formStuff/index.tsx +++ b/frontend/src/lib/formStuff/index.tsx @@ -3,6 +3,7 @@ import { DateField } from "./components/CalenderSelect"; import { CheckboxField } from "./components/CheckBox"; import { InputField } from "./components/InputField"; import { InputPasswordField } from "./components/InputPasswordField"; +import { Searchable } from "./components/Searchable"; import { SelectField } from "./components/SelectField"; import { SubmitButton } from "./components/SubmitButton"; import { TextArea } from "./components/TextArea"; @@ -18,6 +19,7 @@ export const { useAppForm } = createFormHook({ CheckboxField, DateField, TextArea, + Searchable, }, formComponents: { SubmitButton }, fieldContext, diff --git a/frontend/src/routes/_app/_forklifts/-components/NewForklift.tsx b/frontend/src/routes/_app/_forklifts/-components/NewForklift.tsx index e9bc6fc..952b6bc 100644 --- a/frontend/src/routes/_app/_forklifts/-components/NewForklift.tsx +++ b/frontend/src/routes/_app/_forklifts/-components/NewForklift.tsx @@ -226,9 +226,9 @@ export default function NewForklift({ setOpenDialog }: { setOpenDialog: any }) { ( - )}