From 3da0c2e736f87bb884b69a3c84b56e2fcfe76e58 Mon Sep 17 00:00:00 2001 From: Guy Ben-Aharon Date: Thu, 8 Aug 2024 16:42:33 +0300 Subject: [PATCH] table columns --- src/components/accordion/accordion.tsx | 55 +++++ src/components/combobox/combobox.tsx | 190 ++++++++++++++++++ src/components/command/command.tsx | 156 ++++++++++++++ src/components/command/dialog.tsx | 120 +++++++++++ src/components/dialog/dialog.tsx | 120 +++++++++++ src/components/input/input.tsx | 25 +++ src/components/popover/popover.tsx | 31 +++ src/components/scroll-area/scroll-area.tsx | 48 +++++ src/lib/utils.ts | 3 + .../table-list-item-content.tsx | 85 ++++++++ .../table-list-item-header-button.tsx | 12 ++ .../table-list-item-header.tsx | 28 +++ .../table-list-item/table-list-item.tsx | 30 +++ .../tables-section/table-list/table-list.tsx | 15 ++ .../tables-section/tables-section.tsx | 7 +- 15 files changed, 924 insertions(+), 1 deletion(-) create mode 100644 src/components/accordion/accordion.tsx create mode 100644 src/components/combobox/combobox.tsx create mode 100644 src/components/command/command.tsx create mode 100644 src/components/command/dialog.tsx create mode 100644 src/components/dialog/dialog.tsx create mode 100644 src/components/input/input.tsx create mode 100644 src/components/popover/popover.tsx create mode 100644 src/components/scroll-area/scroll-area.tsx create mode 100644 src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-content/table-list-item-content.tsx create mode 100644 src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header-button/table-list-item-header-button.tsx create mode 100644 src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header.tsx create mode 100644 src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item.tsx create mode 100644 src/pages/editor-page/side-panel/tables-section/table-list/table-list.tsx diff --git a/src/components/accordion/accordion.tsx b/src/components/accordion/accordion.tsx new file mode 100644 index 00000000..f2cf8abb --- /dev/null +++ b/src/components/accordion/accordion.tsx @@ -0,0 +1,55 @@ +import * as React from 'react'; +import * as AccordionPrimitive from '@radix-ui/react-accordion'; +import { ChevronDownIcon } from '@radix-ui/react-icons'; + +import { cn } from '@/lib/utils'; + +const Accordion = AccordionPrimitive.Root; + +const AccordionItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AccordionItem.displayName = 'AccordionItem'; + +const AccordionTrigger = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + svg]:rotate-180', + className + )} + {...props} + > + + {children} + + +)); +AccordionTrigger.displayName = AccordionPrimitive.Trigger.displayName; + +const AccordionContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + +
{children}
+
+)); +AccordionContent.displayName = AccordionPrimitive.Content.displayName; + +export { Accordion, AccordionItem, AccordionTrigger, AccordionContent }; diff --git a/src/components/combobox/combobox.tsx b/src/components/combobox/combobox.tsx new file mode 100644 index 00000000..90fdd474 --- /dev/null +++ b/src/components/combobox/combobox.tsx @@ -0,0 +1,190 @@ +import * as React from 'react'; +import { Check, ChevronsUpDown } from 'lucide-react'; + +import { cn } from '@/lib/utils'; +import { Button } from '@/components/button/button'; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList, +} from '@/components/command/command'; +import { + Popover, + PopoverContent, + PopoverTrigger, +} from '@/components/popover/popover'; +import { ScrollArea } from '@/components/scroll-area/scroll-area'; + +export type ComboboxOptions = { + value: string; + label: string; +}; + +type Mode = 'single' | 'multiple'; + +interface ComboboxProps { + mode?: Mode; + options: ComboboxOptions[]; + selected: string | string[]; // Updated to handle multiple selections + className?: string; + placeholder?: string; + onChange?: (event: string | string[]) => void; // Updated to handle multiple selections + onCreate?: (value: string) => void; + emptyText?: string; +} + +export function Combobox({ + options, + selected, + className, + placeholder, + mode = 'single', + emptyText, + onChange, + onCreate, +}: ComboboxProps) { + const [open, setOpen] = React.useState(false); + const [query, setQuery] = React.useState(''); + + return ( +
+ + + + + + { + if (value.includes(search)) return 1; + return 0; + }} + // shouldFilter={true} + > + setQuery(value)} + /> + {onCreate ? ( + { + if (onCreate) { + onCreate(query); + setQuery(''); + } + }} + className="flex cursor-pointer items-center justify-center gap-1 italic" + > +

Create:

+

+ {query} +

+
+ ) : ( + + {emptyText ?? 'No option found.'} + + )} + + +
+ + + {options.map((option) => ( + { + if (onChange) { + if ( + mode === + 'multiple' && + Array.isArray( + selected + ) + ) { + onChange( + selected.includes( + option.value + ) + ? selected.filter( + ( + item + ) => + item !== + option.value + ) + : [ + ...selected, + option.value, + ] + ); + } else { + onChange( + option.value + ); + } + } + }} + > + + {option.label} + + ))} + + +
+
+
+
+
+
+ ); +} diff --git a/src/components/command/command.tsx b/src/components/command/command.tsx new file mode 100644 index 00000000..d22a1651 --- /dev/null +++ b/src/components/command/command.tsx @@ -0,0 +1,156 @@ +import * as React from 'react'; +import { type DialogProps } from '@radix-ui/react-dialog'; +import { MagnifyingGlassIcon } from '@radix-ui/react-icons'; +import { Command as CommandPrimitive } from 'cmdk'; + +import { cn } from '@/lib/utils'; +import { Dialog, DialogContent } from '@/components/dialog/dialog'; + +const Command = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +Command.displayName = CommandPrimitive.displayName; + +interface CommandDialogProps extends DialogProps {} + +const CommandDialog = ({ children, ...props }: CommandDialogProps) => { + return ( + + + + {children} + + + + ); +}; + +const CommandInput = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( +
+ + +
+)); + +CommandInput.displayName = CommandPrimitive.Input.displayName; + +const CommandList = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandList.displayName = CommandPrimitive.List.displayName; + +const CommandEmpty = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>((props, ref) => ( + +)); + +CommandEmpty.displayName = CommandPrimitive.Empty.displayName; + +const CommandGroup = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandGroup.displayName = CommandPrimitive.Group.displayName; + +const CommandSeparator = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +CommandSeparator.displayName = CommandPrimitive.Separator.displayName; + +const CommandItem = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); + +CommandItem.displayName = CommandPrimitive.Item.displayName; + +const CommandShortcut = ({ + className, + ...props +}: React.HTMLAttributes) => { + return ( + + ); +}; +CommandShortcut.displayName = 'CommandShortcut'; + +export { + Command, + CommandDialog, + CommandInput, + CommandList, + CommandEmpty, + CommandGroup, + CommandItem, + CommandShortcut, + CommandSeparator, +}; diff --git a/src/components/command/dialog.tsx b/src/components/command/dialog.tsx new file mode 100644 index 00000000..457e32d1 --- /dev/null +++ b/src/components/command/dialog.tsx @@ -0,0 +1,120 @@ +import React from 'react'; +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { Cross2Icon } from '@radix-ui/react-icons'; + +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, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = 'DialogHeader'; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = 'DialogFooter'; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/src/components/dialog/dialog.tsx b/src/components/dialog/dialog.tsx new file mode 100644 index 00000000..457e32d1 --- /dev/null +++ b/src/components/dialog/dialog.tsx @@ -0,0 +1,120 @@ +import React from 'react'; +import * as DialogPrimitive from '@radix-ui/react-dialog'; +import { Cross2Icon } from '@radix-ui/react-icons'; + +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, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogOverlay.displayName = DialogPrimitive.Overlay.displayName; + +const DialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + + {children} + + + Close + + + +)); +DialogContent.displayName = DialogPrimitive.Content.displayName; + +const DialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogHeader.displayName = 'DialogHeader'; + +const DialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
+); +DialogFooter.displayName = 'DialogFooter'; + +const DialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogTitle.displayName = DialogPrimitive.Title.displayName; + +const DialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +DialogDescription.displayName = DialogPrimitive.Description.displayName; + +export { + Dialog, + DialogPortal, + DialogOverlay, + DialogTrigger, + DialogClose, + DialogContent, + DialogHeader, + DialogFooter, + DialogTitle, + DialogDescription, +}; diff --git a/src/components/input/input.tsx b/src/components/input/input.tsx new file mode 100644 index 00000000..ca6fc739 --- /dev/null +++ b/src/components/input/input.tsx @@ -0,0 +1,25 @@ +import React from 'react'; + +import { cn } from '@/lib/utils'; + +export interface InputProps + extends React.InputHTMLAttributes {} + +const Input = React.forwardRef( + ({ className, type, ...props }, ref) => { + return ( + + ); + } +); +Input.displayName = 'Input'; + +export { Input }; diff --git a/src/components/popover/popover.tsx b/src/components/popover/popover.tsx new file mode 100644 index 00000000..f621e461 --- /dev/null +++ b/src/components/popover/popover.tsx @@ -0,0 +1,31 @@ +import React from 'react'; +import * as PopoverPrimitive from '@radix-ui/react-popover'; + +import { cn } from '@/lib/utils'; + +const Popover = PopoverPrimitive.Root; + +const PopoverTrigger = PopoverPrimitive.Trigger; + +const PopoverAnchor = PopoverPrimitive.Anchor; + +const PopoverContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => ( + + + +)); +PopoverContent.displayName = PopoverPrimitive.Content.displayName; + +export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor }; diff --git a/src/components/scroll-area/scroll-area.tsx b/src/components/scroll-area/scroll-area.tsx new file mode 100644 index 00000000..f32e97b9 --- /dev/null +++ b/src/components/scroll-area/scroll-area.tsx @@ -0,0 +1,48 @@ +import React from 'react'; +import * as ScrollAreaPrimitive from '@radix-ui/react-scroll-area'; + +import { cn } from '@/lib/utils'; + +const ScrollArea = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, children, ...props }, ref) => ( + + + {children} + + + + +)); +ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName; + +const ScrollBar = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef< + typeof ScrollAreaPrimitive.ScrollAreaScrollbar + > +>(({ className, orientation = 'vertical', ...props }, ref) => ( + + + +)); +ScrollBar.displayName = ScrollAreaPrimitive.ScrollAreaScrollbar.displayName; + +export { ScrollArea, ScrollBar }; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index dd53ea89..0e85dc04 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -4,3 +4,6 @@ import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } + +export const randomHSLA = () => + `hsla(${~~(360 * Math.random())}, 70%, 72%, 0.8)`; diff --git a/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-content/table-list-item-content.tsx b/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-content/table-list-item-content.tsx new file mode 100644 index 00000000..072a40de --- /dev/null +++ b/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-content/table-list-item-content.tsx @@ -0,0 +1,85 @@ +import React from 'react'; +import { Ellipsis } from 'lucide-react'; +import { Input } from '@/components/input/input'; +import { Combobox } from '@/components/combobox/combobox'; +import { Button } from '@/components/button/button'; +import { KeyRound } from 'lucide-react'; + +export interface TableListItemContentProps { + tableColor: string; +} + +export const TableListItemContent: React.FC = ({ + tableColor, +}) => { + const renderColumn = () => { + return ( +
+
+ + console.log(value)} + emptyText="No types found." + /> +
+
+ + + +
+
+ ); + }; + + return ( +
+ {renderColumn()} +
+ ); +}; diff --git a/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header-button/table-list-item-header-button.tsx b/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header-button/table-list-item-header-button.tsx new file mode 100644 index 00000000..de4290ed --- /dev/null +++ b/src/pages/editor-page/side-panel/tables-section/table-list/table-list-item/table-list-item-header/table-list-item-header-button/table-list-item-header-button.tsx @@ -0,0 +1,12 @@ +import React from 'react'; +import { Button, ButtonProps } from '@/components/button/button'; + +export const TableListItemHeaderButton: React.FC = (props) => { + return ( +