@inspirare/design-system 0.0.8 → 0.0.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. package/dist/index.css +1 -1
  2. package/package.json +5 -3
  3. package/src/App.css +184 -0
  4. package/src/App.tsx +222 -0
  5. package/src/assets/hero.png +0 -0
  6. package/src/assets/react.svg +1 -0
  7. package/src/assets/vite.svg +1 -0
  8. package/src/components/ui/accessibility-improvements.tsx +117 -0
  9. package/src/components/ui/accordion.tsx +66 -0
  10. package/src/components/ui/alert-dialog.tsx +151 -0
  11. package/src/components/ui/avatar.tsx +53 -0
  12. package/src/components/ui/badge.tsx +46 -0
  13. package/src/components/ui/button.tsx +59 -0
  14. package/src/components/ui/calendar.tsx +220 -0
  15. package/src/components/ui/card.tsx +92 -0
  16. package/src/components/ui/checkbox.tsx +32 -0
  17. package/src/components/ui/collapsible.tsx +36 -0
  18. package/src/components/ui/color-picker.tsx +183 -0
  19. package/src/components/ui/command.tsx +184 -0
  20. package/src/components/ui/dialog.tsx +157 -0
  21. package/src/components/ui/drawer.tsx +149 -0
  22. package/src/components/ui/dropdown-menu.tsx +259 -0
  23. package/src/components/ui/form.tsx +168 -0
  24. package/src/components/ui/hover-card.tsx +49 -0
  25. package/src/components/ui/input.tsx +21 -0
  26. package/src/components/ui/label.tsx +24 -0
  27. package/src/components/ui/popover.tsx +55 -0
  28. package/src/components/ui/progress.tsx +31 -0
  29. package/src/components/ui/radio-group.tsx +43 -0
  30. package/src/components/ui/scroll-area.tsx +32 -0
  31. package/src/components/ui/select.tsx +185 -0
  32. package/src/components/ui/separator.tsx +28 -0
  33. package/src/components/ui/sheet.tsx +153 -0
  34. package/src/components/ui/skeleton.tsx +121 -0
  35. package/src/components/ui/slider.tsx +63 -0
  36. package/src/components/ui/sonner.tsx +25 -0
  37. package/src/components/ui/switch.tsx +35 -0
  38. package/src/components/ui/table.tsx +116 -0
  39. package/src/components/ui/tabs.tsx +66 -0
  40. package/src/components/ui/textarea.tsx +18 -0
  41. package/src/components/ui/theme-toggle.tsx +106 -0
  42. package/src/components/ui/toggle-group.tsx +73 -0
  43. package/src/components/ui/toggle.tsx +47 -0
  44. package/src/components/ui/tooltip.tsx +68 -0
  45. package/src/demo/ButtonsDemo.tsx +82 -0
  46. package/src/demo/CalendarDemo.tsx +25 -0
  47. package/src/demo/FeedbackDemo.tsx +113 -0
  48. package/src/demo/FormsDemo.tsx +100 -0
  49. package/src/demo/NavigationDemo.tsx +141 -0
  50. package/src/demo/OverlaysDemo.tsx +187 -0
  51. package/src/index.css +1434 -0
  52. package/src/index.ts +41 -0
  53. package/src/lib/utils.ts +6 -0
  54. package/src/main.tsx +13 -0
@@ -0,0 +1,46 @@
1
+ import * as React from "react";
2
+ import { Slot } from "@radix-ui/react-slot";
3
+ import { cva, type VariantProps } from "class-variance-authority";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const badgeVariants = cva(
8
+ "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
14
+ secondary:
15
+ "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
16
+ destructive:
17
+ "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
18
+ outline:
19
+ "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground",
20
+ },
21
+ },
22
+ defaultVariants: {
23
+ variant: "default",
24
+ },
25
+ }
26
+ );
27
+
28
+ function Badge({
29
+ className,
30
+ variant,
31
+ asChild = false,
32
+ ...props
33
+ }: React.ComponentProps<"span"> &
34
+ VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
35
+ const Comp = asChild ? Slot : "span";
36
+
37
+ return (
38
+ <Comp
39
+ data-slot="badge"
40
+ className={cn(badgeVariants({ variant }), className)}
41
+ {...props}
42
+ />
43
+ );
44
+ }
45
+
46
+ export { Badge, badgeVariants };
@@ -0,0 +1,59 @@
1
+ import { Slot } from "@radix-ui/react-slot";
2
+ import { cva, type VariantProps } from "class-variance-authority";
3
+ import * as React from "react";
4
+
5
+ import { cn } from "@/lib/utils";
6
+
7
+ const buttonVariants = cva(
8
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all cursor-pointer disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive",
9
+ {
10
+ variants: {
11
+ variant: {
12
+ default:
13
+ "bg-primary text-primary-foreground shadow-xs hover:bg-primary/90",
14
+ destructive:
15
+ "bg-destructive text-white shadow-xs hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
16
+ outline:
17
+ "border border-input bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-card dark:border-border dark:hover:bg-accent dark:hover:text-accent-foreground",
18
+ secondary:
19
+ "bg-secondary text-secondary-foreground shadow-xs hover:bg-secondary/80 dark:bg-secondary/20 dark:text-secondary-foreground dark:hover:bg-secondary/30",
20
+ ghost:
21
+ "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent dark:hover:text-accent-foreground",
22
+ link: "text-primary underline-offset-4 hover:underline",
23
+ },
24
+ size: {
25
+ default: "h-9 px-4 py-2 has-[>svg]:px-3",
26
+ sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5",
27
+ lg: "h-10 rounded-md px-6 has-[>svg]:px-4",
28
+ icon: "size-9",
29
+ },
30
+ },
31
+ defaultVariants: {
32
+ variant: "default",
33
+ size: "default",
34
+ },
35
+ }
36
+ );
37
+
38
+ function Button({
39
+ className,
40
+ variant,
41
+ size,
42
+ asChild = false,
43
+ ...props
44
+ }: React.ComponentProps<"button"> &
45
+ VariantProps<typeof buttonVariants> & {
46
+ asChild?: boolean;
47
+ }) {
48
+ const Comp = asChild ? Slot : "button";
49
+
50
+ return (
51
+ <Comp
52
+ data-slot="button"
53
+ className={cn(buttonVariants({ variant, size, className }))}
54
+ {...props}
55
+ />
56
+ );
57
+ }
58
+
59
+ export { Button, buttonVariants };
@@ -0,0 +1,220 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import {
5
+ ChevronDownIcon,
6
+ ChevronLeftIcon,
7
+ ChevronRightIcon,
8
+ } from "lucide-react"
9
+ import {
10
+ DayPicker,
11
+ getDefaultClassNames,
12
+ type DayButton,
13
+ } from "react-day-picker"
14
+
15
+ import { cn } from "@/lib/utils"
16
+ import { Button, buttonVariants } from "@/components/ui/button"
17
+
18
+ function Calendar({
19
+ className,
20
+ classNames,
21
+ showOutsideDays = true,
22
+ captionLayout = "label",
23
+ buttonVariant = "ghost",
24
+ formatters,
25
+ components,
26
+ ...props
27
+ }: React.ComponentProps<typeof DayPicker> & {
28
+ buttonVariant?: React.ComponentProps<typeof Button>["variant"]
29
+ }) {
30
+ const defaultClassNames = getDefaultClassNames()
31
+
32
+ return (
33
+ <DayPicker
34
+ showOutsideDays={showOutsideDays}
35
+ className={cn(
36
+ "group/calendar bg-background p-3 [--cell-size:--spacing(8)] [[data-slot=card-content]_&]:bg-transparent [[data-slot=popover-content]_&]:bg-transparent",
37
+ String.raw`rtl:**:[.rdp-button\_next>svg]:rotate-180`,
38
+ String.raw`rtl:**:[.rdp-button\_previous>svg]:rotate-180`,
39
+ className
40
+ )}
41
+ captionLayout={captionLayout}
42
+ formatters={{
43
+ formatMonthDropdown: (date) =>
44
+ date.toLocaleString("default", { month: "short" }),
45
+ ...formatters,
46
+ }}
47
+ classNames={{
48
+ root: cn("w-fit", defaultClassNames.root),
49
+ months: cn(
50
+ "relative flex flex-col gap-4 md:flex-row",
51
+ defaultClassNames.months
52
+ ),
53
+ month: cn("flex w-full flex-col gap-4", defaultClassNames.month),
54
+ nav: cn(
55
+ "absolute inset-x-0 top-0 flex w-full items-center justify-between gap-1",
56
+ defaultClassNames.nav
57
+ ),
58
+ button_previous: cn(
59
+ buttonVariants({ variant: buttonVariant }),
60
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
61
+ defaultClassNames.button_previous
62
+ ),
63
+ button_next: cn(
64
+ buttonVariants({ variant: buttonVariant }),
65
+ "size-(--cell-size) p-0 select-none aria-disabled:opacity-50",
66
+ defaultClassNames.button_next
67
+ ),
68
+ month_caption: cn(
69
+ "flex h-(--cell-size) w-full items-center justify-center px-(--cell-size)",
70
+ defaultClassNames.month_caption
71
+ ),
72
+ dropdowns: cn(
73
+ "flex h-(--cell-size) w-full items-center justify-center gap-1.5 text-sm font-medium",
74
+ defaultClassNames.dropdowns
75
+ ),
76
+ dropdown_root: cn(
77
+ "relative rounded-md border border-input shadow-xs has-focus:border-ring has-focus:ring-[3px] has-focus:ring-ring/50",
78
+ defaultClassNames.dropdown_root
79
+ ),
80
+ dropdown: cn(
81
+ "absolute inset-0 bg-popover opacity-0",
82
+ defaultClassNames.dropdown
83
+ ),
84
+ caption_label: cn(
85
+ "font-medium select-none",
86
+ captionLayout === "label"
87
+ ? "text-sm"
88
+ : "flex h-8 items-center gap-1 rounded-md pr-1 pl-2 text-sm [&>svg]:size-3.5 [&>svg]:text-muted-foreground",
89
+ defaultClassNames.caption_label
90
+ ),
91
+ table: "w-full border-collapse",
92
+ weekdays: cn("flex", defaultClassNames.weekdays),
93
+ weekday: cn(
94
+ "flex-1 rounded-md text-[0.8rem] font-normal text-muted-foreground select-none",
95
+ defaultClassNames.weekday
96
+ ),
97
+ week: cn("mt-2 flex w-full", defaultClassNames.week),
98
+ week_number_header: cn(
99
+ "w-(--cell-size) select-none",
100
+ defaultClassNames.week_number_header
101
+ ),
102
+ week_number: cn(
103
+ "text-[0.8rem] text-muted-foreground select-none",
104
+ defaultClassNames.week_number
105
+ ),
106
+ day: cn(
107
+ "group/day relative aspect-square h-full w-full p-0 text-center select-none [&:last-child[data-selected=true]_button]:rounded-r-md",
108
+ props.showWeekNumber
109
+ ? "[&:nth-child(2)[data-selected=true]_button]:rounded-l-md"
110
+ : "[&:first-child[data-selected=true]_button]:rounded-l-md",
111
+ defaultClassNames.day
112
+ ),
113
+ range_start: cn(
114
+ "rounded-l-md bg-accent",
115
+ defaultClassNames.range_start
116
+ ),
117
+ range_middle: cn("rounded-none", defaultClassNames.range_middle),
118
+ range_end: cn("rounded-r-md bg-accent", defaultClassNames.range_end),
119
+ today: cn(
120
+ "rounded-md bg-accent text-accent-foreground data-[selected=true]:rounded-none",
121
+ defaultClassNames.today
122
+ ),
123
+ outside: cn(
124
+ "text-muted-foreground aria-selected:text-muted-foreground",
125
+ defaultClassNames.outside
126
+ ),
127
+ disabled: cn(
128
+ "text-muted-foreground opacity-50",
129
+ defaultClassNames.disabled
130
+ ),
131
+ hidden: cn("invisible", defaultClassNames.hidden),
132
+ ...classNames,
133
+ }}
134
+ components={{
135
+ Root: ({ className, rootRef, ...props }) => {
136
+ return (
137
+ <div
138
+ data-slot="calendar"
139
+ ref={rootRef}
140
+ className={cn(className)}
141
+ {...props}
142
+ />
143
+ )
144
+ },
145
+ Chevron: ({ className, orientation, ...props }) => {
146
+ if (orientation === "left") {
147
+ return (
148
+ <ChevronLeftIcon className={cn("size-4", className)} {...props} />
149
+ )
150
+ }
151
+
152
+ if (orientation === "right") {
153
+ return (
154
+ <ChevronRightIcon
155
+ className={cn("size-4", className)}
156
+ {...props}
157
+ />
158
+ )
159
+ }
160
+
161
+ return (
162
+ <ChevronDownIcon className={cn("size-4", className)} {...props} />
163
+ )
164
+ },
165
+ DayButton: CalendarDayButton,
166
+ WeekNumber: ({ children, ...props }) => {
167
+ return (
168
+ <td {...props}>
169
+ <div className="flex size-(--cell-size) items-center justify-center text-center">
170
+ {children}
171
+ </div>
172
+ </td>
173
+ )
174
+ },
175
+ ...components,
176
+ }}
177
+ {...props}
178
+ />
179
+ )
180
+ }
181
+
182
+ function CalendarDayButton({
183
+ className,
184
+ day,
185
+ modifiers,
186
+ ...props
187
+ }: React.ComponentProps<typeof DayButton>) {
188
+ const defaultClassNames = getDefaultClassNames()
189
+
190
+ const ref = React.useRef<HTMLButtonElement>(null)
191
+ React.useEffect(() => {
192
+ if (modifiers.focused) ref.current?.focus()
193
+ }, [modifiers.focused])
194
+
195
+ return (
196
+ <Button
197
+ ref={ref}
198
+ variant="ghost"
199
+ size="icon"
200
+ data-day={day.date.toLocaleDateString()}
201
+ data-selected-single={
202
+ modifiers.selected &&
203
+ !modifiers.range_start &&
204
+ !modifiers.range_end &&
205
+ !modifiers.range_middle
206
+ }
207
+ data-range-start={modifiers.range_start}
208
+ data-range-end={modifiers.range_end}
209
+ data-range-middle={modifiers.range_middle}
210
+ className={cn(
211
+ "flex aspect-square size-auto w-full min-w-(--cell-size) flex-col gap-1 leading-none font-normal group-data-[focused=true]/day:relative group-data-[focused=true]/day:z-10 group-data-[focused=true]/day:border-ring group-data-[focused=true]/day:ring-[3px] group-data-[focused=true]/day:ring-ring/50 data-[range-end=true]:rounded-md data-[range-end=true]:rounded-r-md data-[range-end=true]:bg-primary data-[range-end=true]:text-primary-foreground data-[range-middle=true]:rounded-none data-[range-middle=true]:bg-accent data-[range-middle=true]:text-accent-foreground data-[range-start=true]:rounded-md data-[range-start=true]:rounded-l-md data-[range-start=true]:bg-primary data-[range-start=true]:text-primary-foreground data-[selected-single=true]:bg-primary data-[selected-single=true]:text-primary-foreground dark:hover:text-accent-foreground [&>span]:text-xs [&>span]:opacity-70",
212
+ defaultClassNames.day,
213
+ className
214
+ )}
215
+ {...props}
216
+ />
217
+ )
218
+ }
219
+
220
+ export { Calendar, CalendarDayButton }
@@ -0,0 +1,92 @@
1
+ import * as React from "react";
2
+
3
+ import { cn } from "@/lib/utils";
4
+
5
+ function Card({ className, ...props }: React.ComponentProps<"div">) {
6
+ return (
7
+ <div
8
+ data-slot="card"
9
+ className={cn(
10
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
11
+ className
12
+ )}
13
+ {...props}
14
+ />
15
+ );
16
+ }
17
+
18
+ function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
19
+ return (
20
+ <div
21
+ data-slot="card-header"
22
+ className={cn(
23
+ "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1.5 px-6 has-data-[slot=card-action]:grid-cols-[1fr_auto] [.border-b]:pb-6",
24
+ className
25
+ )}
26
+ {...props}
27
+ />
28
+ );
29
+ }
30
+
31
+ function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
32
+ return (
33
+ <div
34
+ data-slot="card-title"
35
+ className={cn("leading-none font-semibold", className)}
36
+ {...props}
37
+ />
38
+ );
39
+ }
40
+
41
+ function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
42
+ return (
43
+ <div
44
+ data-slot="card-description"
45
+ className={cn("text-muted-foreground text-sm", className)}
46
+ {...props}
47
+ />
48
+ );
49
+ }
50
+
51
+ function CardAction({ className, ...props }: React.ComponentProps<"div">) {
52
+ return (
53
+ <div
54
+ data-slot="card-action"
55
+ className={cn(
56
+ "col-start-2 row-span-2 row-start-1 self-start justify-self-end",
57
+ className
58
+ )}
59
+ {...props}
60
+ />
61
+ );
62
+ }
63
+
64
+ function CardContent({ className, ...props }: React.ComponentProps<"div">) {
65
+ return (
66
+ <div
67
+ data-slot="card-content"
68
+ className={cn("px-6", className)}
69
+ {...props}
70
+ />
71
+ );
72
+ }
73
+
74
+ function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
75
+ return (
76
+ <div
77
+ data-slot="card-footer"
78
+ className={cn("flex items-center px-6 [.border-t]:pt-6", className)}
79
+ {...props}
80
+ />
81
+ );
82
+ }
83
+
84
+ export {
85
+ Card,
86
+ CardHeader,
87
+ CardFooter,
88
+ CardTitle,
89
+ CardAction,
90
+ CardDescription,
91
+ CardContent,
92
+ };
@@ -0,0 +1,32 @@
1
+ "use client"
2
+
3
+ import * as React from "react"
4
+ import { CheckIcon } from "lucide-react"
5
+ import { Checkbox as CheckboxPrimitive } from "radix-ui"
6
+
7
+ import { cn } from "@/lib/utils"
8
+
9
+ function Checkbox({
10
+ className,
11
+ ...props
12
+ }: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
13
+ return (
14
+ <CheckboxPrimitive.Root
15
+ data-slot="checkbox"
16
+ className={cn(
17
+ "peer size-4 shrink-0 rounded-[4px] border border-input shadow-xs transition-shadow outline-none focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-[state=checked]:border-primary data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground dark:bg-input/30 dark:aria-invalid:ring-destructive/40 dark:data-[state=checked]:bg-primary",
18
+ className
19
+ )}
20
+ {...props}
21
+ >
22
+ <CheckboxPrimitive.Indicator
23
+ data-slot="checkbox-indicator"
24
+ className="grid place-content-center text-current transition-none"
25
+ >
26
+ <CheckIcon className="size-3.5" />
27
+ </CheckboxPrimitive.Indicator>
28
+ </CheckboxPrimitive.Root>
29
+ )
30
+ }
31
+
32
+ export { Checkbox }
@@ -0,0 +1,36 @@
1
+ "use client";
2
+
3
+ import * as CollapsiblePrimitive from "@radix-ui/react-collapsible";
4
+ import { cn } from "@/lib/utils";
5
+
6
+ function Collapsible({
7
+ ...props
8
+ }: React.ComponentProps<typeof CollapsiblePrimitive.Root>) {
9
+ return <CollapsiblePrimitive.Root data-slot="collapsible" {...props} />;
10
+ }
11
+
12
+ function CollapsibleTrigger({
13
+ className,
14
+ ...props
15
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleTrigger>) {
16
+ return (
17
+ <CollapsiblePrimitive.CollapsibleTrigger
18
+ data-slot="collapsible-trigger"
19
+ className={cn("cursor-pointer", className)}
20
+ {...props}
21
+ />
22
+ );
23
+ }
24
+
25
+ function CollapsibleContent({
26
+ ...props
27
+ }: React.ComponentProps<typeof CollapsiblePrimitive.CollapsibleContent>) {
28
+ return (
29
+ <CollapsiblePrimitive.CollapsibleContent
30
+ data-slot="collapsible-content"
31
+ {...props}
32
+ />
33
+ );
34
+ }
35
+
36
+ export { Collapsible, CollapsibleTrigger, CollapsibleContent };
@@ -0,0 +1,183 @@
1
+ "use client";
2
+
3
+ import { Button } from "@/components/ui/button";
4
+ import { Input } from "@/components/ui/input";
5
+ import {
6
+ Popover,
7
+ PopoverContent,
8
+ PopoverTrigger,
9
+ } from "@/components/ui/popover";
10
+ import { cn } from "@/lib/utils";
11
+ import { useState } from "react";
12
+ import { HexColorPicker } from "react-colorful";
13
+
14
+ interface ColorPickerProps {
15
+ value: string;
16
+ onChange: (color: string) => void;
17
+ className?: string;
18
+ disabled?: boolean;
19
+ }
20
+
21
+ export function ColorPicker({
22
+ value,
23
+ onChange,
24
+ className,
25
+ disabled = false,
26
+ }: ColorPickerProps) {
27
+ const [color, setColor] = useState(value);
28
+ const [isOpen, setIsOpen] = useState(false);
29
+
30
+ const handleColorChange = (newColor: string) => {
31
+ setColor(newColor);
32
+ onChange(newColor);
33
+ };
34
+
35
+ const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
36
+ const newColor = e.target.value;
37
+ if (/^#[0-9A-F]{6}$/i.test(newColor) || newColor === "") {
38
+ setColor(newColor);
39
+ if (newColor !== "") {
40
+ onChange(newColor);
41
+ }
42
+ }
43
+ };
44
+
45
+ // Paleta de cores premium alinhada com a marca
46
+ const presetColors = [
47
+ // Cores da marca Inspirare
48
+ "#9192FA", // Inspirare Purple
49
+ "#60A5FA", // Inspirare Blue
50
+ "#e0e7ff", // Inspirare Purple Light
51
+ "#dbeafe", // Inspirare Blue Light
52
+
53
+ // Cores neutras sofisticadas
54
+ "#1f2937", // Gray 800
55
+ "#374151", // Gray 700
56
+ "#6b7280", // Gray 500
57
+ "#9ca3af", // Gray 400
58
+ "#d1d5db", // Gray 300
59
+ "#f3f4f6", // Gray 100
60
+ "#ffffff", // White
61
+ "#000000", // Black
62
+
63
+ // Cores semânticas modernas
64
+ "#dc2626", // Red 600
65
+ "#ea580c", // Orange 600
66
+ "#d97706", // Amber 600
67
+ "#16a34a", // Green 600
68
+ "#2563eb", // Blue 600
69
+ "#4f46e5", // Indigo 600
70
+ "#9333ea", // Purple 600
71
+ "#e11d48", // Rose 600
72
+
73
+ // Tons pastéis para destaque
74
+ "#fef3c7", // Amber 100
75
+ "#d1fae5", // Green 100
76
+ "#fce7f3", // Pink 100
77
+ "#e9d5ff", // Purple 100
78
+ ];
79
+
80
+ return (
81
+ <Popover open={isOpen} onOpenChange={setIsOpen}>
82
+ <PopoverTrigger asChild>
83
+ <Button
84
+ variant="outline"
85
+ className={cn(
86
+ "w-[200px] justify-start text-left font-normal border-border hover:border-primary/50 transition-colors gap-2 px-3",
87
+ !color && "text-muted-foreground",
88
+ className
89
+ )}
90
+ disabled={disabled}
91
+ >
92
+ <div
93
+ className="w-4 h-4 rounded border border-border shadow-sm shrink-0"
94
+ style={{ backgroundColor: color || "#ffffff" }}
95
+ />
96
+ <span className="truncate flex-1">
97
+ {color ? (
98
+ <span className="font-mono text-xs">{color.toUpperCase()}</span>
99
+ ) : (
100
+ "Selecionar cor"
101
+ )}
102
+ </span>
103
+ </Button>
104
+ </PopoverTrigger>
105
+ <PopoverContent className="w-80 p-0">
106
+ <div className="p-4 space-y-4">
107
+ {/* Header */}
108
+ <div className="text-sm font-medium text-foreground pb-2 border-b border-border">
109
+ Seletor de Cor
110
+ </div>
111
+
112
+ {/* Color Picker */}
113
+ <div className="space-y-3">
114
+ <HexColorPicker
115
+ color={color || "#ffffff"}
116
+ onChange={handleColorChange}
117
+ className="w-full !h-32"
118
+ />
119
+
120
+ {/* Input para código hex */}
121
+ <div className="space-y-1">
122
+ <label className="text-xs font-medium text-muted-foreground">
123
+ Código Hexadecimal
124
+ </label>
125
+ <Input
126
+ value={color || ""}
127
+ onChange={handleInputChange}
128
+ placeholder="#000000"
129
+ className="font-mono text-sm border-border focus:border-primary/50 focus:ring-primary/20 bg-background text-foreground"
130
+ />
131
+ </div>
132
+ </div>
133
+
134
+ {/* Paleta de cores predefinidas */}
135
+ <div className="space-y-2">
136
+ <label className="text-xs font-medium text-muted-foreground">
137
+ Cores Predefinidas
138
+ </label>
139
+ <div className="grid grid-cols-8 gap-1.5">
140
+ {presetColors.map((presetColor) => (
141
+ <button
142
+ key={presetColor}
143
+ className={cn(
144
+ "w-7 h-7 rounded border cursor-pointer transition-all duration-200 hover:scale-110 hover:shadow-md",
145
+ color === presetColor
146
+ ? "border-primary ring-2 ring-primary/20"
147
+ : "border-border hover:border-muted-foreground/50"
148
+ )}
149
+ style={{ backgroundColor: presetColor }}
150
+ onClick={() => handleColorChange(presetColor)}
151
+ title={presetColor.toUpperCase()}
152
+ />
153
+ ))}
154
+ </div>
155
+ </div>
156
+
157
+ {/* Preview da cor atual */}
158
+ {color && (
159
+ <div className="pt-2 border-t border-border">
160
+ <div className="text-xs font-medium text-muted-foreground mb-2">
161
+ Cor Atual
162
+ </div>
163
+ <div className="flex items-center gap-3 p-2 bg-muted/50 rounded-md cursor-pointer hover:bg-muted transition-colors">
164
+ <div
165
+ className="w-8 h-8 rounded border border-border shadow-sm shrink-0"
166
+ style={{ backgroundColor: color }}
167
+ />
168
+ <div className="flex-1">
169
+ <div className="font-mono text-sm font-medium text-foreground">
170
+ {color.toUpperCase()}
171
+ </div>
172
+ <div className="text-xs text-muted-foreground">
173
+ Clique para copiar
174
+ </div>
175
+ </div>
176
+ </div>
177
+ </div>
178
+ )}
179
+ </div>
180
+ </PopoverContent>
181
+ </Popover>
182
+ );
183
+ }