From e5b466a3c46cd3bed6385c75e7a6e464dcab32ef Mon Sep 17 00:00:00 2001 From: Aaryan Khandelwal Date: Tue, 12 Sep 2023 19:36:35 +0530 Subject: [PATCH] chore: all attribute forms --- .../checkbox-attribute-form.tsx | 160 +++++++++++++ .../date-time-attribute-form.tsx | 129 +++++++++++ .../attribute-forms/email-attribute-form.tsx | 92 ++++++++ .../attribute-forms/file-attribute-form.tsx | 89 ++++++++ .../attribute-forms/index.ts | 9 + .../attribute-forms/number-attribute-form.tsx | 212 ++++++++++++++++++ .../relation-attribute-form.tsx | 129 +++++++++++ .../attribute-forms/select-attribute-form.tsx | 157 +++++++++++++ .../attribute-forms/text-attribute-form.tsx | 78 +++++++ .../attribute-forms/url-attribute-form.tsx | 92 ++++++++ .../dropdowns/file-formats-dropdown.tsx | 127 +++++++++++ .../custom-attributes/dropdowns/index.ts | 2 + .../dropdowns/types-dropdown.tsx | 67 ++++++ web/components/custom-attributes/index.ts | 4 + web/components/custom-attributes/input.tsx | 18 ++ .../custom-attributes/object-modal.tsx | 113 ++++++++++ web/components/ui/toggle-switch.tsx | 2 +- web/constants/custom-attributes.ts | 124 ++++++++++ .../[projectId]/settings/custom-objects.tsx | 81 +++++++ .../custom-attributes/checkbox/check.svg | 20 ++ .../checkbox/toggle-switch.svg | 16 ++ web/public/custom-attributes/number/bar.svg | 16 ++ .../custom-attributes/number/numerical.svg | 15 ++ web/public/custom-attributes/number/ring.svg | 24 ++ web/types/custom-attributes.d.ts | 33 +++ web/types/index.d.ts | 30 +-- 26 files changed, 1823 insertions(+), 16 deletions(-) create mode 100644 web/components/custom-attributes/attribute-forms/checkbox-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/date-time-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/email-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/file-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/index.ts create mode 100644 web/components/custom-attributes/attribute-forms/number-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/relation-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/select-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/text-attribute-form.tsx create mode 100644 web/components/custom-attributes/attribute-forms/url-attribute-form.tsx create mode 100644 web/components/custom-attributes/dropdowns/file-formats-dropdown.tsx create mode 100644 web/components/custom-attributes/dropdowns/index.ts create mode 100644 web/components/custom-attributes/dropdowns/types-dropdown.tsx create mode 100644 web/components/custom-attributes/index.ts create mode 100644 web/components/custom-attributes/input.tsx create mode 100644 web/components/custom-attributes/object-modal.tsx create mode 100644 web/constants/custom-attributes.ts create mode 100644 web/pages/[workspaceSlug]/projects/[projectId]/settings/custom-objects.tsx create mode 100644 web/public/custom-attributes/checkbox/check.svg create mode 100644 web/public/custom-attributes/checkbox/toggle-switch.svg create mode 100644 web/public/custom-attributes/number/bar.svg create mode 100644 web/public/custom-attributes/number/numerical.svg create mode 100644 web/public/custom-attributes/number/ring.svg create mode 100644 web/types/custom-attributes.d.ts diff --git a/web/components/custom-attributes/attribute-forms/checkbox-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/checkbox-attribute-form.tsx new file mode 100644 index 000000000..dbe4a2856 --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/checkbox-attribute-form.tsx @@ -0,0 +1,160 @@ +import Image from "next/image"; + +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure } from "@headlessui/react"; +// ui +import { ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { CheckCircle2, ChevronDown } from "lucide-react"; +// assets +import CheckRepresentation from "public/custom-attributes/checkbox/check.svg"; +import ToggleSwitchRepresentation from "public/custom-attributes/checkbox/toggle-switch.svg"; +// types +import { ICustomAttribute, TCustomAttributeTypes } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; + +type Props = {}; + +const checkboxAttributeRepresentations = [ + { + image: CheckRepresentation, + key: "check", + label: "Check", + }, + { + image: ToggleSwitchRepresentation, + key: "toggle_switch", + label: "Toggle Switch", + }, +]; + +const defaultFormValues: Partial = { + default_value: "checked", + display_name: "", + extra_settings: { + representation: "check", + }, + is_required: false, +}; + +export const CheckboxAttributeForm: React.FC = () => { + const { control, watch } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.checkbox; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+
+ +
+

Default value

+
+
+ + +
+ +
+ + +
+
+
+
+
+
+
Show as
+
+ ( + <> + {checkboxAttributeRepresentations.map((representation) => ( +
onChange(representation.key)} + > +
+ {representation.label} +
+
+ {representation.label} + {value === representation.key && ( + + )} +
+
+ ))} + + )} + /> +
+
+
+
+ ( + + )} + /> + Mandatory field +
+ +
+ + + + )} + + ); +}; diff --git a/web/components/custom-attributes/attribute-forms/date-time-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/date-time-attribute-form.tsx new file mode 100644 index 000000000..1da3519d6 --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/date-time-attribute-form.tsx @@ -0,0 +1,129 @@ +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure } from "@headlessui/react"; +// ui +import { CustomSelect, ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { ChevronDown } from "lucide-react"; +// types +import { ICustomAttribute } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST, DATE_FORMATS, TIME_FORMATS } from "constants/custom-attributes"; + +type Props = {}; + +const defaultFormValues: Partial = { + default_value: "", + display_name: "", + extra_settings: { + date_format: "DD-MM-YYYY", + time_format: "12", + }, + is_required: false, +}; + +export const DateTimeAttributeForm: React.FC = () => { + const { control } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.datetime; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+ ( + + )} + /> + ( + + {DATE_FORMATS.find((f) => f.value === value)?.label} + + } + value={value} + onChange={onChange} + buttonClassName="bg-custom-background-100 !px-3 !py-2 !border-custom-border-200 !rounded" + optionsClassName="w-full" + input + > + {DATE_FORMATS.map((format) => ( + + {format.label} + + ))} + + )} + /> + ( + + {TIME_FORMATS.find((f) => f.value === value)?.label} + + } + value={value} + onChange={onChange} + buttonClassName="bg-custom-background-100 !px-3 !py-2 !border-custom-border-200 !rounded" + optionsClassName="w-full" + input + > + {TIME_FORMATS.map((format) => ( + + {format.label} + + ))} + + )} + /> +
+
+
+ ( + + )} + /> + Mandatory field +
+ +
+
+ + )} +
+ ); +}; diff --git a/web/components/custom-attributes/attribute-forms/email-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/email-attribute-form.tsx new file mode 100644 index 000000000..3facd402a --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/email-attribute-form.tsx @@ -0,0 +1,92 @@ +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure } from "@headlessui/react"; +// ui +import { ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { ChevronDown } from "lucide-react"; +// types +import { ICustomAttribute } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; + +type Props = {}; + +const defaultFormValues: Partial = { + default_value: "", + display_name: "", + is_required: false, +}; + +export const EmailAttributeForm: React.FC = () => { + const { control } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.email; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+
+ ( + + )} + /> + ( + + )} + /> +
+
+
+
+ ( + + )} + /> + Mandatory field +
+ +
+ + + + )} + + ); +}; diff --git a/web/components/custom-attributes/attribute-forms/file-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/file-attribute-form.tsx new file mode 100644 index 000000000..87171c35f --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/file-attribute-form.tsx @@ -0,0 +1,89 @@ +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure } from "@headlessui/react"; +// components +import { FileFormatsDropdown } from "components/custom-attributes"; +// ui +import { ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { ChevronDown } from "lucide-react"; +// types +import { ICustomAttribute } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; + +type Props = {}; + +const defaultFormValues: Partial = { + display_name: "", + extra_settings: { + file_formats: [], + }, + is_multi: false, + is_required: false, +}; + +export const FileAttributeForm: React.FC = () => { + const { control } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.files; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+ ( + + )} + /> + ( + + )} + /> +
+
+
+ ( + + )} + /> + Mandatory field +
+ +
+
+ + )} +
+ ); +}; diff --git a/web/components/custom-attributes/attribute-forms/index.ts b/web/components/custom-attributes/attribute-forms/index.ts new file mode 100644 index 000000000..ce2fd80bf --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/index.ts @@ -0,0 +1,9 @@ +export * from "./checkbox-attribute-form"; +export * from "./date-time-attribute-form"; +export * from "./email-attribute-form"; +export * from "./file-attribute-form"; +export * from "./number-attribute-form"; +export * from "./relation-attribute-form"; +export * from "./select-attribute-form"; +export * from "./text-attribute-form"; +export * from "./url-attribute-form"; diff --git a/web/components/custom-attributes/attribute-forms/number-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/number-attribute-form.tsx new file mode 100644 index 000000000..5a118d58b --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/number-attribute-form.tsx @@ -0,0 +1,212 @@ +import Image from "next/image"; + +// headless ui +import { Disclosure } from "@headlessui/react"; +// ui +import { ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { CheckCircle2, ChevronDown } from "lucide-react"; +// assets +import NumericalRepresentation from "public/custom-attributes/number/numerical.svg"; +import BarRepresentation from "public/custom-attributes/number/bar.svg"; +import RingRepresentation from "public/custom-attributes/number/ring.svg"; +// types +import { ICustomAttribute, TCustomAttributeTypes } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; +import { Controller, useForm } from "react-hook-form"; + +type Props = {}; + +const numberAttributeRepresentations = [ + { + image: NumericalRepresentation, + key: "numerical", + label: "Numerical", + }, + { + image: BarRepresentation, + key: "bar", + label: "Bar", + }, + { + image: RingRepresentation, + key: "ring", + label: "Ring", + }, +]; + +const defaultFormValues: Partial = { + default_value: "", + display_name: "", + extra_settings: { + color: "Blue", + divided_by: 100, + representation: "numerical", + show_number: true, + }, + is_required: false, +}; + +export const NumberAttributeForm: React.FC = () => { + const { control, watch } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.number; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+
+ ( + + )} + /> + ( + + )} + /> +
+
+
+
Show as
+
+ ( + <> + {numberAttributeRepresentations.map((representation) => ( +
onChange(representation.key)} + > +
+ {representation.label} +
+
+ {representation.label} + {value === representation.key && ( + + )} +
+
+ ))} + + )} + /> +
+
+ {(watch("extra_settings.representation") === "bar" || + watch("extra_settings.representation") === "ring") && ( +
+ <> +
Divided by
+
+ ( + + )} + /> +
+ + <> +
Color
+
+ ( + + )} + /> +
+ + <> +
Show number
+
+ ( + + )} + /> +
+ +
+ )} +
+
+ ( + + )} + /> + Mandatory field +
+ +
+ + + + )} + + ); +}; diff --git a/web/components/custom-attributes/attribute-forms/relation-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/relation-attribute-form.tsx new file mode 100644 index 000000000..13f2f2b22 --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/relation-attribute-form.tsx @@ -0,0 +1,129 @@ +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure } from "@headlessui/react"; +// ui +import { CustomSelect, ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { ChevronDown } from "lucide-react"; +// types +import { ICustomAttribute } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST, CUSTOM_ATTRIBUTE_UNITS } from "constants/custom-attributes"; + +type Props = {}; + +const defaultFormValues: Partial = { + display_name: "", + is_multi: false, + is_required: false, + unit: "cycle", +}; + +export const RelationAttributeForm: React.FC = () => { + const { control } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.relation; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+ ( + + )} + /> + ( + {value}} + value={value} + onChange={onChange} + buttonClassName="bg-custom-background-100 !px-3 !py-2 !border-custom-border-200 !rounded" + optionsClassName="w-full" + input + > + {CUSTOM_ATTRIBUTE_UNITS.map((unit) => { + if (unit.value === "user") return null; + + return ( + + {unit.label} + + ); + })} + + )} + /> +
+

Selection type

+
+
+ + +
+ +
+ + +
+
+
+
+
+
+ ( + + )} + /> + Mandatory field +
+ +
+
+ + )} +
+ ); +}; diff --git a/web/components/custom-attributes/attribute-forms/select-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/select-attribute-form.tsx new file mode 100644 index 000000000..8bd9f852e --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/select-attribute-form.tsx @@ -0,0 +1,157 @@ +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure, Popover, Transition } from "@headlessui/react"; +// ui +import { CustomSelect, ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { ChevronDown, GripVertical, MoreHorizontal } from "lucide-react"; +// types +import { ICustomAttribute } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; +import { TwitterPicker } from "react-color"; +import React from "react"; + +type Props = {}; + +const defaultFormValues: Partial = { + default_value: "", + display_name: "", + is_required: false, +}; + +export const SelectOption: React.FC = () => ( +
+
+ {/* */} +

+ 🚀 Option 1 +

+
+
+ + +
+
+); + +export const SelectAttributeForm: React.FC = () => { + const { control } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.select; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+ ( + + )} + /> +
+

Options

+
+ {/* TODO: map over options */} + + + +
+
+
+ 🚀 + + + {({ open, close }) => ( + <> + + + + + + + ( + { + onChange(value.hex); + close(); + }} + /> + )} + /> + + + + )} + +
+
+
+
+
+
+ ( + + )} + /> + Mandatory field +
+ +
+
+ + )} +
+ ); +}; diff --git a/web/components/custom-attributes/attribute-forms/text-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/text-attribute-form.tsx new file mode 100644 index 000000000..3b70e158d --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/text-attribute-form.tsx @@ -0,0 +1,78 @@ +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure } from "@headlessui/react"; +// ui +import { ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { ChevronDown } from "lucide-react"; +// types +import { ICustomAttribute } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; + +type Props = {}; + +const defaultFormValues: Partial = { + default_value: "", + display_name: "", + is_required: false, +}; + +export const TextAttributeForm: React.FC = () => { + const { control } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.text; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+ ( + + )} + /> + ( + + )} + /> +
+
+
+ {}} /> + Mandatory field +
+ +
+
+ + )} +
+ ); +}; diff --git a/web/components/custom-attributes/attribute-forms/url-attribute-form.tsx b/web/components/custom-attributes/attribute-forms/url-attribute-form.tsx new file mode 100644 index 000000000..72a3195af --- /dev/null +++ b/web/components/custom-attributes/attribute-forms/url-attribute-form.tsx @@ -0,0 +1,92 @@ +// react-hook-form +import { Controller, useForm } from "react-hook-form"; +// headless ui +import { Disclosure } from "@headlessui/react"; +// ui +import { ToggleSwitch } from "components/ui"; +import { Input } from "../input"; +// icons +import { ChevronDown } from "lucide-react"; +// types +import { ICustomAttribute } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; + +type Props = {}; + +const defaultFormValues: Partial = { + default_value: "", + display_name: "", + is_required: false, +}; + +export const UrlAttributeForm: React.FC = () => { + const { control } = useForm({ defaultValues: defaultFormValues }); + + const typeMetaData = CUSTOM_ATTRIBUTES_LIST.url; + + return ( + + {({ open }) => ( + <> + +
+ +
{typeMetaData.label}
+
+
+ +
+
+ +
+
+ ( + + )} + /> + ( + + )} + /> +
+
+
+
+ ( + + )} + /> + Mandatory field +
+ +
+ + + + )} + + ); +}; diff --git a/web/components/custom-attributes/dropdowns/file-formats-dropdown.tsx b/web/components/custom-attributes/dropdowns/file-formats-dropdown.tsx new file mode 100644 index 000000000..61be7c505 --- /dev/null +++ b/web/components/custom-attributes/dropdowns/file-formats-dropdown.tsx @@ -0,0 +1,127 @@ +import React, { useState } from "react"; + +// headless ui +import { Combobox, Transition } from "@headlessui/react"; +import { Search } from "lucide-react"; + +type Props = { + onChange: (value: string[]) => void; + value: string[]; +}; + +const FILE_EXTENSIONS: { + [category: string]: string[]; +} = { + image: [".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tif", ".tiff", ".svg", ".eps", ".psd", ".ai"], + video: [".mp4", ".avi", ".mkv", ".mpg", ".mpeg", ".flv", ".wmv"], + audio: [".mp3", ".wav", ".ogg", ".flac", ".aac"], + document: [ + ".txt", + ".doc", + ".docx", + ".pdf", + ".ppt", + ".pptx", + ".xls", + ".xlsx", + ".html", + ".htm", + ".csv", + ".xml", + ], +}; + +const searchExtensions = (query: string) => { + query = query.toLowerCase(); + const filteredExtensions: { + [category: string]: string[]; + } = {}; + + for (const category in FILE_EXTENSIONS) { + const extensions = FILE_EXTENSIONS[category].filter((extension) => + extension.toLowerCase().includes(query) + ); + if (extensions.length > 0) { + filteredExtensions[category] = extensions; + } + } + + return filteredExtensions; +}; + +export const FileFormatsDropdown: React.FC = ({ onChange, value }) => { + const [query, setQuery] = useState(""); + + const options = searchExtensions(query); + + return ( + { + console.log(val); + onChange(val); + }} + className="relative flex-shrink-0 text-left" + multiple + > + {({ open }: { open: boolean }) => ( + <> + + All Formats + + + +
+ + setQuery(e.target.value)} + placeholder="Type to search..." + displayValue={(assigned: any) => assigned?.name} + /> +
+
+ {Object.keys(options).map((category) => + options[category].map((extension) => ( + + `flex items-center gap-1 cursor-pointer select-none truncate rounded px-1 py-1.5 accent-custom-primary-100 ${ + active ? "bg-custom-background-80" : "" + } ${selected ? "text-custom-text-100" : "text-custom-text-200"}` + } + > + {({ active, selected }) => ( + <> + + {extension} + + )} + + )) + )} +
+
+
+ + )} +
+ ); +}; diff --git a/web/components/custom-attributes/dropdowns/index.ts b/web/components/custom-attributes/dropdowns/index.ts new file mode 100644 index 000000000..03287406e --- /dev/null +++ b/web/components/custom-attributes/dropdowns/index.ts @@ -0,0 +1,2 @@ +export * from "./file-formats-dropdown"; +export * from "./types-dropdown"; diff --git a/web/components/custom-attributes/dropdowns/types-dropdown.tsx b/web/components/custom-attributes/dropdowns/types-dropdown.tsx new file mode 100644 index 000000000..315da95ab --- /dev/null +++ b/web/components/custom-attributes/dropdowns/types-dropdown.tsx @@ -0,0 +1,67 @@ +import React from "react"; + +import { useRouter } from "next/router"; + +// headless ui +import { Listbox, Transition } from "@headlessui/react"; +// icons +import { Plus } from "lucide-react"; +// types +import { TCustomAttributeTypes } from "types"; +// constants +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; + +type Props = {}; + +export const TypesDropdown: React.FC = () => { + const router = useRouter(); + const { workspaceSlug, projectId } = router.query; + + return ( + + {({ open }: { open: boolean }) => ( + <> + + + Add Attribute + + + + {Object.keys(CUSTOM_ATTRIBUTES_LIST).map((type) => { + const typeMetaData = CUSTOM_ATTRIBUTES_LIST[type as TCustomAttributeTypes]; + + return ( + + `flex items-center gap-1 cursor-pointer select-none truncate rounded px-1 py-1.5 ${ + active || selected ? "bg-custom-background-80" : "" + } ${selected ? "text-custom-text-100" : "text-custom-text-200"}` + } + > + {({ active, selected }) => ( + <> + + {typeMetaData.label} + + )} + + ); + })} + + + + )} + + ); +}; diff --git a/web/components/custom-attributes/index.ts b/web/components/custom-attributes/index.ts new file mode 100644 index 000000000..97db61381 --- /dev/null +++ b/web/components/custom-attributes/index.ts @@ -0,0 +1,4 @@ +export * from "./attribute-forms"; +export * from "./dropdowns"; +export * from "./input"; +export * from "./object-modal"; diff --git a/web/components/custom-attributes/input.tsx b/web/components/custom-attributes/input.tsx new file mode 100644 index 000000000..9787e5af5 --- /dev/null +++ b/web/components/custom-attributes/input.tsx @@ -0,0 +1,18 @@ +import { forwardRef } from "react"; + +export const Input = forwardRef( + (props: React.InputHTMLAttributes, ref: React.Ref) => { + const { className = "", type, ...rest } = props; + + return ( + + ); + } +); + +Input.displayName = "Input"; diff --git a/web/components/custom-attributes/object-modal.tsx b/web/components/custom-attributes/object-modal.tsx new file mode 100644 index 000000000..4547e4c3b --- /dev/null +++ b/web/components/custom-attributes/object-modal.tsx @@ -0,0 +1,113 @@ +import React from "react"; + +// headless ui +import { Dialog, Transition } from "@headlessui/react"; +import { + TextAttributeForm, + Input, + TypesDropdown, + NumberAttributeForm, + CheckboxAttributeForm, + RelationAttributeForm, + DateTimeAttributeForm, + UrlAttributeForm, + EmailAttributeForm, + FileAttributeForm, + SelectAttributeForm, +} from "components/custom-attributes"; +import { CUSTOM_ATTRIBUTES_LIST } from "constants/custom-attributes"; + +type Props = { + isOpen: boolean; + onClose: () => void; + onSubmit?: () => Promise; +}; + +export const ObjectModal: React.FC = ({ isOpen, onClose, onSubmit }) => { + const handleClose = () => { + onClose(); + }; + + return ( + + + +
+ + +
+
+ + +

New Object

+
+
+
+
+ 🚀 +
+ +
+