@ckc-net/puck-extended 0.3.0 → 0.5.0
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.
- package/README.md +18 -0
- package/dist/index.d.ts +258 -223
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1311 -350
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -4,28 +4,28 @@ import { useRender } from "@base-ui/react/use-render";
|
|
|
4
4
|
import { cva } from "class-variance-authority";
|
|
5
5
|
import { clsx } from "clsx";
|
|
6
6
|
import { twMerge } from "tailwind-merge";
|
|
7
|
-
import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, BaselineIcon, BoldIcon, BoxIcon, CaseLowerIcon, CaseSensitiveIcon, CaseUpperIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsUpDownIcon, CircleAlertIcon, CircleCheckIcon, DatabaseIcon, FileIcon, FileTextIcon, GripVerticalIcon, InfoIcon, ItalicIcon, LightbulbIcon, LinkIcon, Loader2Icon, LoaderCircleIcon, LockIcon, MinusIcon, MoreHorizontalIcon, PlusIcon, SearchIcon, StrikethroughIcon, Trash2Icon, TriangleAlertIcon, UnderlineIcon, UploadIcon, XIcon } from "lucide-react";
|
|
7
|
+
import { AlignCenterIcon, AlignJustifyIcon, AlignLeftIcon, AlignRightIcon, BaselineIcon, BoldIcon, BoxIcon, CaseLowerIcon, CaseSensitiveIcon, CaseUpperIcon, CheckIcon, ChevronDownIcon, ChevronLeftIcon, ChevronRightIcon, ChevronUpIcon, ChevronsUpDownIcon, CircleAlertIcon, CircleCheckIcon, DatabaseIcon, DownloadIcon, ExternalLinkIcon, FileIcon, FilePlayIcon, FileTextIcon, GripVerticalIcon, InfoIcon, ItalicIcon, LightbulbIcon, LinkIcon, Loader2Icon, LoaderCircleIcon, LockIcon, MinusIcon, MoreHorizontalIcon, PlusIcon, SearchIcon, SlidersHorizontalIcon, SparklesIcon, StrikethroughIcon, Trash2Icon, TriangleAlertIcon, UnderlineIcon, UploadIcon, XIcon, ZoomInIcon } from "lucide-react";
|
|
8
8
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
9
|
-
import { Tooltip as
|
|
9
|
+
import { Tooltip as TooltipPrimitive } from "@base-ui/react/tooltip";
|
|
10
10
|
import { Checkbox as Checkbox$1 } from "@base-ui/react/checkbox";
|
|
11
11
|
import { Input as Input$1 } from "@base-ui/react/input";
|
|
12
12
|
import { Select as Select$1 } from "@base-ui/react/select";
|
|
13
13
|
import { Radio } from "@base-ui/react/radio";
|
|
14
14
|
import { RadioGroup as RadioGroup$1 } from "@base-ui/react/radio-group";
|
|
15
|
+
import { Switch as Switch$1 } from "@base-ui/react/switch";
|
|
15
16
|
import { Field } from "@base-ui/react/field";
|
|
16
17
|
import { AutoField, createUsePuck, walkTree } from "@puckeditor/core";
|
|
17
|
-
import { Tabs as
|
|
18
|
+
import { Tabs as TabsPrimitive } from "@base-ui/react/tabs";
|
|
18
19
|
import { Accordion as AccordionPrimitive } from "@base-ui/react/accordion";
|
|
19
20
|
import { Popover as Popover$1 } from "@base-ui/react/popover";
|
|
20
21
|
import { Dialog as Dialog$1 } from "@base-ui/react/dialog";
|
|
21
|
-
import { ScrollArea as
|
|
22
|
+
import { ScrollArea as ScrollAreaPrimitive } from "@base-ui/react/scroll-area";
|
|
22
23
|
import { flexRender, getCoreRowModel, useReactTable } from "@tanstack/react-table";
|
|
23
24
|
import { Color } from "@tiptap/extension-color";
|
|
24
25
|
import { TextStyle } from "@tiptap/extension-text-style";
|
|
25
26
|
import { HexColorPicker } from "react-colorful";
|
|
26
|
-
import { Menu as
|
|
27
|
+
import { Menu as MenuPrimitive } from "@base-ui/react/menu";
|
|
27
28
|
import { Separator as Separator$1 } from "@base-ui/react/separator";
|
|
28
|
-
import { Switch as Switch$1 } from "@base-ui/react/switch";
|
|
29
29
|
import { Toast } from "@base-ui/react/toast";
|
|
30
30
|
|
|
31
31
|
//#region src/lib/utils.ts
|
|
@@ -59,7 +59,7 @@ const buttonVariants = cva("[&_svg]:-mx-0.5 relative inline-flex shrink-0 cursor
|
|
|
59
59
|
"destructive-outline": "border-input bg-transparent not-dark:bg-clip-padding text-destructive-foreground not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none [:hover,[data-pressed]]:border-destructive/32 [:hover,[data-pressed]]:bg-destructive/4",
|
|
60
60
|
ghost: "border-transparent data-pressed:bg-accent [:hover,[data-pressed]]:bg-accent",
|
|
61
61
|
link: "border-transparent underline-offset-4 [:hover,[data-pressed]]:underline",
|
|
62
|
-
outline: "border-input bg-background not-dark:bg-clip-padding not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none
|
|
62
|
+
outline: "border-input bg-background hover:bg-gray-50 not-dark:bg-clip-padding not-disabled:not-active:not-data-pressed:before:shadow-[0_1px_--theme(--color-black/6%)] dark:bg-input/32 dark:not-disabled:before:shadow-[0_-1px_--theme(--color-white/2%)] dark:not-disabled:not-active:not-data-pressed:before:shadow-[0_-1px_--theme(--color-white/6%)] [:disabled,:active,[data-pressed]]:shadow-none",
|
|
63
63
|
primary: "border-transparent from-primary-600 to-primary-500 hover:from-primary-500 hover:to-primary-600 bg-linear-to-t text-white inset-shadow-[0_2px_0_0] inset-shadow-white/25 hover:text-white",
|
|
64
64
|
secondary: "border-transparent bg-secondary text-secondary-foreground [:active,[data-pressed]]:bg-secondary/80 [:hover,[data-pressed]]:bg-secondary/90"
|
|
65
65
|
}
|
|
@@ -96,192 +96,61 @@ function Label$2({ className, readOnly, children, ...props }) {
|
|
|
96
96
|
|
|
97
97
|
//#endregion
|
|
98
98
|
//#region src/components/ui/tooltip.tsx
|
|
99
|
-
const
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
fade: [`[transition-property:opacity,scale]`, `data-starting-style:scale-98 data-starting-style:opacity-0 data-ending-style:opacity-0 data-ending-style:scale-98`],
|
|
103
|
-
slideOutside: [
|
|
104
|
-
`[transition-property:translate,opacity]`,
|
|
105
|
-
`data-[side=bottom]:data-starting-style:opacity-0 data-[side=bottom]:data-starting-style:translate-y-[10px] data-[side=bottom]:data-ending-style:translate-y-[10px] data-[side=bottom]:data-ending-style:opacity-0`,
|
|
106
|
-
`data-[side=top]:data-starting-style:opacity-0 data-[side=top]:data-starting-style:translate-y-[-10px] data-[side=top]:data-ending-style:translate-y-[-10px] data-[side=top]:data-ending-style:opacity-0`,
|
|
107
|
-
`data-[side=left]:data-starting-style:opacity-0 data-[side=left]:data-starting-style:translate-x-[-10px] data-[side=left]:data-ending-style:translate-x-[-10px] data-[side=left]:data-ending-style:opacity-0`,
|
|
108
|
-
`data-[side=right]:data-starting-style:opacity-0 data-[side=right]:data-starting-style:translate-x-[10px] data-[side=right]:data-ending-style:translate-x-[10px] data-[side=right]:data-ending-style:opacity-0`,
|
|
109
|
-
`data-[side=inline-start]:data-starting-style:opacity-0 data-[side=inline-start]:data-starting-style:translate-x-[-10px] data-[side=inline-start]:data-ending-style:translate-x-[-10px] data-[side=inline-start]:data-ending-style:opacity-0`,
|
|
110
|
-
`data-[side=inline-end]:data-starting-style:opacity-0 data-[side=inline-end]:data-starting-style:translate-x-[10px] data-[side=inline-end]:data-ending-style:translate-x-[10px] data-[side=inline-end]:data-ending-style:opacity-0`
|
|
111
|
-
],
|
|
112
|
-
slideInside: [
|
|
113
|
-
`[transition-property:translate,opacity]`,
|
|
114
|
-
`data-[side=bottom]:data-starting-style:opacity-0 data-[side=bottom]:data-starting-style:translate-y-[-10px] data-[side=bottom]:data-ending-style:translate-y-[-10px] data-[side=bottom]:data-ending-style:opacity-0`,
|
|
115
|
-
`data-[side=top]:data-starting-style:opacity-0 data-[side=top]:data-starting-style:translate-y-[10px] data-[side=top]:data-ending-style:translate-y-[10px] data-[side=top]:data-ending-style:opacity-0`,
|
|
116
|
-
`data-[side=left]:data-starting-style:opacity-0 data-[side=left]:data-starting-style:translate-x-[10px] data-[side=left]:data-ending-style:translate-x-[10px] data-[side=left]:data-ending-style:opacity-0`,
|
|
117
|
-
`data-[side=right]:data-starting-style:opacity-0 data-[side=right]:data-starting-style:translate-x-[-10px] data-[side=right]:data-ending-style:translate-x-[-10px] data-[side=right]:data-ending-style:opacity-0`,
|
|
118
|
-
`data-[side=inline-start]:data-starting-style:opacity-0 data-[side=inline-start]:data-starting-style:translate-x-[10px] data-[side=inline-start]:data-ending-style:translate-x-[10px] data-[side=inline-start]:data-ending-style:opacity-0`,
|
|
119
|
-
`data-[side=inline-end]:data-starting-style:opacity-0 data-[side=inline-end]:data-starting-style:translate-x-[-10px] data-[side=inline-end]:data-ending-style:translate-x-[-10px] data-[side=inline-end]:data-ending-style:opacity-0`
|
|
120
|
-
],
|
|
121
|
-
wipe: [
|
|
122
|
-
`[transition-property:clip-path] [will-change:clip-path]`,
|
|
123
|
-
`[clip-path:inset(0_0_0_0_round_var(--radius))] [-webkit-clip-path:inset(0_0_0_0_round_var(--radius))]`,
|
|
124
|
-
`data-[side=bottom]:data-starting-style:[clip-path:inset(0_0_100%_0_round_var(--radius))] data-[side=bottom]:data-ending-style:[clip-path:inset(0_0_100%_0_round_var(--radius))]`,
|
|
125
|
-
`data-[side=top]:data-starting-style:[clip-path:inset(100%_0_0_0_round_var(--radius))] data-[side=top]:data-ending-style:[clip-path:inset(100%_0_0_0_round_var(--radius))]`,
|
|
126
|
-
`data-[side=left]:data-starting-style:[clip-path:inset(0_0_0_100%_round_var(--radius))] data-[side=left]:data-ending-style:[clip-path:inset(0_0_0_100%_round_var(--radius))]`,
|
|
127
|
-
`data-[side=right]:data-starting-style:[clip-path:inset(0_100%_0_0_round_var(--radius))] data-[side=right]:data-ending-style:[clip-path:inset(0_100%_0_0_round_var(--radius))]`,
|
|
128
|
-
`data-[side=inline-start]:data-starting-style:[clip-path:inset(0_0_0_100%_round_var(--radius))] data-[side=inline-start]:data-ending-style:[clip-path:inset(0_0_0_100%_round_var(--radius))]`,
|
|
129
|
-
`data-[side=inline-end]:data-starting-style:[clip-path:inset(0_100%_0_0_round_var(--radius))] data-[side=inline-end]:data-ending-style:[clip-path:inset(0_100%_0_0_round_var(--radius))]`
|
|
130
|
-
],
|
|
131
|
-
wipeScale: [
|
|
132
|
-
`[transition-property:clip-path,scale] [will-change:clip-path,scale]`,
|
|
133
|
-
`[clip-path:inset(0_0_0_0_round_var(--radius))] [-webkit-clip-path:inset(0_0_0_0_round_var(--radius))]`,
|
|
134
|
-
`data-starting-style:scale-80 data-ending-style:scale-80`,
|
|
135
|
-
`data-[side=bottom]:data-starting-style:[clip-path:inset(0_0_100%_0_round_var(--radius))] data-[side=bottom]:data-ending-style:[clip-path:inset(0_0_100%_0_round_var(--radius))]`,
|
|
136
|
-
`data-[side=top]:data-starting-style:[clip-path:inset(100%_0_0_0_round_var(--radius))] data-[side=top]:data-ending-style:[clip-path:inset(100%_0_0_0_round_var(--radius))]`,
|
|
137
|
-
`data-[side=left]:data-starting-style:[clip-path:inset(0_0_0_100%_round_var(--radius))] data-[side=left]:data-ending-style:[clip-path:inset(0_0_0_100%_round_var(--radius))]`,
|
|
138
|
-
`data-[side=right]:data-starting-style:[clip-path:inset(0_100%_0_0_round_var(--radius))] data-[side=right]:data-ending-style:[clip-path:inset(0_100%_0_0_round_var(--radius))]`,
|
|
139
|
-
`data-[side=inline-start]:data-starting-style:[clip-path:inset(0_0_0_100%_round_var(--radius))] data-[side=inline-start]:data-ending-style:[clip-path:inset(0_0_0_100%_round_var(--radius))]`,
|
|
140
|
-
`data-[side=inline-end]:data-starting-style:[clip-path:inset(0_100%_0_0_round_var(--radius))] data-[side=inline-end]:data-ending-style:[clip-path:inset(0_100%_0_0_round_var(--radius))]`
|
|
141
|
-
],
|
|
142
|
-
motion: [
|
|
143
|
-
`[transition-property:translate,scale,opacity,rotateX,rotateY,transform] [will-change:translate,scale,opacity,rotateX,rotateY,transform]`,
|
|
144
|
-
`[transform:perspective(1000px)]`,
|
|
145
|
-
`data-[side=bottom]:data-starting-style:translate-y-[7px] data-[side=bottom]:data-starting-style:opacity-0 data-[side=bottom]:data-starting-style:scale-[0.26] data-[side=bottom]:data-starting-style:rotate-x-[70deg] data-[side=bottom]:data-ending-style:translate-y-[7px] data-[side=bottom]:data-ending-style:opacity-0 data-[side=bottom]:data-ending-style:scale-[0.26] data-[side=bottom]:data-ending-style:rotate-x-[70deg]`,
|
|
146
|
-
`data-[side=top]:data-starting-style:translate-y-[7px] data-[side=top]:data-starting-style:opacity-0 data-[side=top]:data-starting-style:scale-[0.26] data-[side=top]:data-starting-style:rotate-x-[70deg] data-[side=top]:data-ending-style:translate-y-[7px] data-[side=top]:data-ending-style:opacity-0 data-[side=top]:data-ending-style:scale-[0.26] data-[side=top]:data-ending-style:rotate-x-[70deg]`,
|
|
147
|
-
`data-[side=left]:data-starting-style:translate-x-[-7px] data-[side=left]:data-starting-style:opacity-0 data-[side=left]:data-starting-style:scale-[0.26] data-[side=left]:data-starting-style:rotate-y-[-40deg] data-[side=left]:data-ending-style:translate-x-[-7px] data-[side=left]:data-ending-style:opacity-0 data-[side=left]:data-ending-style:scale-[0.26] data-[side=left]:data-ending-style:rotate-y-[-40deg]`,
|
|
148
|
-
`data-[side=right]:data-starting-style:translate-x-[7px] data-[side=right]:data-starting-style:opacity-0 data-[side=right]:data-starting-style:scale-[0.26] data-[side=right]:data-starting-style:rotate-y-[40deg] data-[side=right]:data-ending-style:translate-x-[7px] data-[side=right]:data-ending-style:opacity-0 data-[side=right]:data-ending-style:scale-[0.26] data-[side=right]:data-ending-style:rotate-y-[40deg]`,
|
|
149
|
-
`data-[side=inline-start]:data-starting-style:translate-x-[-7px] data-[side=inline-start]:data-starting-style:opacity-0 data-[side=inline-start]:data-starting-style:scale-[0.26] data-[side=inline-start]:data-starting-style:rotate-y-[-40deg] data-[side=inline-start]:data-ending-style:translate-x-[-7px] data-[side=inline-start]:data-ending-style:opacity-0 data-[side=inline-start]:data-ending-style:scale-[0.26] data-[side=inline-start]:data-ending-style:rotate-y-[-40deg]`,
|
|
150
|
-
`data-[side=inline-end]:data-starting-style:translate-x-[7px] data-[side=inline-end]:data-starting-style:opacity-0 data-[side=inline-end]:data-starting-style:scale-[0.26] data-[side=inline-end]:data-starting-style:rotate-y-[40deg] data-[side=inline-end]:data-ending-style:translate-x-[7px] data-[side=inline-end]:data-ending-style:opacity-0 data-[side=inline-end]:data-ending-style:scale-[0.26] data-[side=inline-end]:data-ending-style:rotate-y-[40deg]`
|
|
151
|
-
],
|
|
152
|
-
motionBlur: [
|
|
153
|
-
`[transition-property:translate,scale,opacity,rotateX,rotateY,transform,filter] [will-change:translate,scale,opacity,rotateX,rotateY,transform,filter]`,
|
|
154
|
-
`[transform:perspective(1000px)]`,
|
|
155
|
-
`data-starting-style:blur-[9px] data-ending-style:blur-[9px]`,
|
|
156
|
-
`data-[side=bottom]:data-starting-style:translate-y-[7px] data-[side=bottom]:data-starting-style:opacity-0 data-[side=bottom]:data-starting-style:scale-[0.26] data-[side=bottom]:data-starting-style:rotate-x-[70deg] data-[side=bottom]:data-ending-style:translate-y-[7px] data-[side=bottom]:data-ending-style:opacity-0 data-[side=bottom]:data-ending-style:scale-[0.26] data-[side=bottom]:data-ending-style:rotate-x-[70deg]`,
|
|
157
|
-
`data-[side=top]:data-starting-style:translate-y-[7px] data-[side=top]:data-starting-style:opacity-0 data-[side=top]:data-starting-style:scale-[0.26] data-[side=top]:data-starting-style:rotate-x-[70deg] data-[side=top]:data-ending-style:translate-y-[7px] data-[side=top]:data-ending-style:opacity-0 data-[side=top]:data-ending-style:scale-[0.26] data-[side=top]:data-ending-style:rotate-x-[70deg]`,
|
|
158
|
-
`data-[side=left]:data-starting-style:translate-x-[-7px] data-[side=left]:data-starting-style:opacity-0 data-[side=left]:data-starting-style:scale-[0.26] data-[side=left]:data-starting-style:rotate-y-[-40deg] data-[side=left]:data-ending-style:translate-x-[-7px] data-[side=left]:data-ending-style:opacity-0 data-[side=left]:data-ending-style:scale-[0.26] data-[side=left]:data-ending-style:rotate-y-[-40deg]`,
|
|
159
|
-
`data-[side=right]:data-starting-style:translate-x-[7px] data-[side=right]:data-starting-style:opacity-0 data-[side=right]:data-starting-style:scale-[0.26] data-[side=right]:data-starting-style:rotate-y-[40deg] data-[side=right]:data-ending-style:translate-x-[7px] data-[side=right]:data-ending-style:opacity-0 data-[side=right]:data-ending-style:scale-[0.26] data-[side=right]:data-ending-style:rotate-y-[40deg]`,
|
|
160
|
-
`data-[side=inline-start]:data-starting-style:translate-x-[-7px] data-[side=inline-start]:data-starting-style:opacity-0 data-[side=inline-start]:data-starting-style:scale-[0.26] data-[side=inline-start]:data-starting-style:rotate-y-[-40deg] data-[side=inline-start]:data-ending-style:translate-x-[-7px] data-[side=inline-start]:data-ending-style:opacity-0 data-[side=inline-start]:data-ending-style:scale-[0.26] data-[side=inline-start]:data-ending-style:rotate-y-[-40deg]`,
|
|
161
|
-
`data-[side=inline-end]:data-starting-style:translate-x-[7px] data-[side=inline-end]:data-starting-style:opacity-0 data-[side=inline-end]:data-starting-style:scale-[0.26] data-[side=inline-end]:data-starting-style:rotate-y-[40deg] data-[side=inline-end]:data-ending-style:translate-x-[7px] data-[side=inline-end]:data-ending-style:opacity-0 data-[side=inline-end]:data-ending-style:scale-[0.26] data-[side=inline-end]:data-ending-style:rotate-y-[40deg]`
|
|
162
|
-
]
|
|
163
|
-
};
|
|
164
|
-
const cssTransitionPresets = {
|
|
165
|
-
inExpo: `duration-[0.25s] ease-[cubic-bezier(0.95,0.05,0.795,0.035)]`,
|
|
166
|
-
outExpo: `duration-[0.25s] ease-[cubic-bezier(0.19,1,0.22,1)]`,
|
|
167
|
-
inOutExpo: `duration-[0.25s] ease-[cubic-bezier(1,0,0,1)]`,
|
|
168
|
-
anticipate: `duration-[0.25s] ease-[cubic-bezier(1,-0.4,0.35,0.95)]`,
|
|
169
|
-
quickOut: `duration-[0.25s] ease-out`,
|
|
170
|
-
overshootOut: `duration-[0.25s] ease-[cubic-bezier(0.175,0.885,0.32,1.275)]`,
|
|
171
|
-
swiftOut: `duration-[0.25s] ease-[cubic-bezier(0.175,0.885,0.32,1.1)]`,
|
|
172
|
-
snappyOut: `duration-[0.25s] ease-[cubic-bezier(0.19,1,0.22,1)]`,
|
|
173
|
-
in: `duration-[0.25s] ease-[cubic-bezier(0.42,0,1,1)]`,
|
|
174
|
-
out: `duration-[0.25s] ease-[cubic-bezier(0,0,0.58,1)]`,
|
|
175
|
-
inOut: `duration-[0.25s] ease-[cubic-bezier(0.42,0,0.58,1)]`,
|
|
176
|
-
outIn: `duration-[0.25s] ease-[cubic-bezier(0.1,0.7,0.9,0.5)]`,
|
|
177
|
-
inQuad: `duration-[0.25s] ease-[cubic-bezier(0.55,0.085,0.68,0.53)]`,
|
|
178
|
-
outQuad: `duration-[0.25s] ease-[cubic-bezier(0.25,0.46,0.45,0.94)]`,
|
|
179
|
-
inOutQuad: `duration-[0.32s] ease-[cubic-bezier(0.455,0.03,0.515,0.955)]`,
|
|
180
|
-
inCubic: `duration-[0.25s] ease-[cubic-bezier(0.55,0.055,0.675,0.19)]`,
|
|
181
|
-
outCubic: `duration-[0.25s] ease-[cubic-bezier(0.215,0.61,0.355,1)]`,
|
|
182
|
-
inOutCubic: `duration-[0.25s] ease-[cubic-bezier(0.645,0.045,0.355,1)]`,
|
|
183
|
-
inQuart: `duration-[0.25s] ease-[cubic-bezier(0.895,0.03,0.685,0.22)]`,
|
|
184
|
-
outQuart: `duration-[0.25s] ease-[cubic-bezier(0.165,0.84,0.44,1)]`,
|
|
185
|
-
inOutQuart: `duration-[0.25s] ease-[cubic-bezier(0.77,0,0.175,1)]`,
|
|
186
|
-
inQuint: `duration-[0.25s] ease-[cubic-bezier(0.755,0.05,0.855,0.06)]`,
|
|
187
|
-
outQuint: `duration-[0.25s] ease-[cubic-bezier(0.23,1,0.32,1)]`,
|
|
188
|
-
inOutQuint: `duration-[0.25s] ease-[cubic-bezier(0.86,0,0.07,1)]`,
|
|
189
|
-
inCirc: `duration-[0.25s] ease-[cubic-bezier(0.6,0.04,0.98,0.335)]`,
|
|
190
|
-
outCirc: `duration-[0.25s] ease-[cubic-bezier(0.075,0.82,0.165,1)]`,
|
|
191
|
-
inOutCirc: `duration-[0.25s] ease-[cubic-bezier(0.785,0.135,0.15,0.86)]`,
|
|
192
|
-
inOutBase: `duration-[0.25s] ease-[cubic-bezier(0.25,0.1,0.25,1)]`,
|
|
193
|
-
none: `duration-0 ease-none`
|
|
194
|
-
};
|
|
195
|
-
function TooltipProvider({ delay = 300, ...props }) {
|
|
196
|
-
return /* @__PURE__ */ jsx(Tooltip$1.Provider, {
|
|
197
|
-
"data-slot": "tooltip-provider",
|
|
198
|
-
delay,
|
|
199
|
-
...props
|
|
200
|
-
});
|
|
201
|
-
}
|
|
202
|
-
function Tooltip({ ...props }) {
|
|
203
|
-
return /* @__PURE__ */ jsx(Tooltip$1.Root, {
|
|
204
|
-
"data-slot": "tooltip",
|
|
205
|
-
...props
|
|
206
|
-
});
|
|
207
|
-
}
|
|
99
|
+
const TooltipCreateHandle = TooltipPrimitive.createHandle;
|
|
100
|
+
const TooltipProvider = TooltipPrimitive.Provider;
|
|
101
|
+
const Tooltip = TooltipPrimitive.Root;
|
|
208
102
|
function TooltipTrigger(props) {
|
|
209
|
-
return /* @__PURE__ */ jsx(
|
|
103
|
+
return /* @__PURE__ */ jsx(TooltipPrimitive.Trigger, {
|
|
210
104
|
"data-slot": "tooltip-trigger",
|
|
211
105
|
...props
|
|
212
106
|
});
|
|
213
107
|
}
|
|
214
|
-
function
|
|
215
|
-
return /* @__PURE__ */ jsx(
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
animationPreset,
|
|
235
|
-
reduceMotion,
|
|
236
|
-
side
|
|
237
|
-
]);
|
|
238
|
-
const cssTransitionConfig = useMemo(() => {
|
|
239
|
-
if (reduceMotion) return "none";
|
|
240
|
-
if (transitionPreset) return cssTransitionPresets[transitionPreset];
|
|
241
|
-
return cssTransitionPresets.snappyOut;
|
|
242
|
-
}, [
|
|
243
|
-
transitionPreset,
|
|
244
|
-
reduceMotion,
|
|
245
|
-
side
|
|
246
|
-
]);
|
|
247
|
-
return /* @__PURE__ */ jsx(TooltipPositioner, {
|
|
248
|
-
side,
|
|
249
|
-
sideOffset,
|
|
250
|
-
align,
|
|
251
|
-
alignOffset,
|
|
252
|
-
children: /* @__PURE__ */ jsx(Tooltip$1.Popup, {
|
|
253
|
-
"data-slot": "tooltip-popup",
|
|
254
|
-
className: cn("[--radius:10px]", "bg-popover border-border pointer-events-auto w-fit origin-(--transform-origin) rounded-(--radius) border px-2 py-1 text-[13px] text-balance shadow-xs data-instant:duration-0!", className, cssAnimationConfig, cssTransitionConfig, showArrow && [
|
|
255
|
-
`before: before:bg-popover z-[-1] before:absolute before:h-2 before:w-2 before:rotate-45 before:content-['']`,
|
|
256
|
-
side === "top" && `before:border-border before:-bottom-[4.7px] before:left-1/2 before:-translate-x-1/2 before:border-r before:border-b`,
|
|
257
|
-
side === "right" && `before:border-border before:top-1/2 before:-left-[4.07px] before:-translate-y-1/2 before:border-b before:border-l`,
|
|
258
|
-
side === "bottom" && `before:border-border before:-top-[4.7px] before:left-1/2 before:-translate-x-1/2 before:border-t before:border-l`,
|
|
259
|
-
side === "left" && `before:border-border before:top-1/2 before:-right-[4.07px] before:-translate-y-1/2 before:border-t before:border-r`,
|
|
260
|
-
side === "inline-start" && `before:border-border before:top-1/2 before:-right-[4.07px] before:-translate-y-1/2 before:border-t before:border-r`,
|
|
261
|
-
side === "inline-end" && `before:border-border before:top-1/2 before:-left-[4.07px] before:-translate-y-1/2 before:border-b before:border-l`
|
|
262
|
-
]),
|
|
263
|
-
...rest
|
|
108
|
+
function TooltipPopup({ className, align = "center", sideOffset = 4, side = "top", anchor, children, portalProps, ...props }) {
|
|
109
|
+
return /* @__PURE__ */ jsx(TooltipPrimitive.Portal, {
|
|
110
|
+
...portalProps,
|
|
111
|
+
children: /* @__PURE__ */ jsx(TooltipPrimitive.Positioner, {
|
|
112
|
+
align,
|
|
113
|
+
anchor,
|
|
114
|
+
className: "z-50 h-(--positioner-height) w-(--positioner-width) max-w-(--available-width) transition-[top,left,right,bottom,transform] data-instant:transition-none",
|
|
115
|
+
"data-slot": "tooltip-positioner",
|
|
116
|
+
side,
|
|
117
|
+
sideOffset,
|
|
118
|
+
children: /* @__PURE__ */ jsx(TooltipPrimitive.Popup, {
|
|
119
|
+
className: cn("relative flex h-(--popup-height,auto) w-(--popup-width,auto) origin-(--transform-origin) text-balance rounded-md border bg-popover not-dark:bg-clip-padding text-popover-foreground text-xs shadow-md/5 transition-[width,height,scale,opacity] before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-md)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 data-instant:duration-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", className),
|
|
120
|
+
"data-slot": "tooltip-popup",
|
|
121
|
+
...props,
|
|
122
|
+
children: /* @__PURE__ */ jsx(TooltipPrimitive.Viewport, {
|
|
123
|
+
className: "relative size-full overflow-clip px-(--viewport-inline-padding) py-1 [--viewport-inline-padding:--spacing(2)] data-instant:transition-none **:data-current:data-ending-style:opacity-0 **:data-current:data-starting-style:opacity-0 **:data-previous:data-ending-style:opacity-0 **:data-previous:data-starting-style:opacity-0 **:data-current:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:w-[calc(var(--popup-width)-2*var(--viewport-inline-padding)-2px)] **:data-previous:truncate **:data-current:opacity-100 **:data-previous:opacity-100 **:data-current:transition-opacity **:data-previous:transition-opacity",
|
|
124
|
+
"data-slot": "tooltip-viewport",
|
|
125
|
+
children
|
|
126
|
+
})
|
|
127
|
+
})
|
|
264
128
|
})
|
|
265
129
|
});
|
|
266
130
|
}
|
|
267
131
|
|
|
268
132
|
//#endregion
|
|
269
133
|
//#region src/components/Fields/Label/index.tsx
|
|
270
|
-
const Label$1 = ({ label, readOnly, tooltip }) => /* @__PURE__ */ jsxs(Label$2, {
|
|
134
|
+
const Label$1 = ({ label, readOnly, tooltip, action, className }) => /* @__PURE__ */ jsxs(Label$2, {
|
|
271
135
|
readOnly,
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
136
|
+
className,
|
|
137
|
+
children: [label, (action || tooltip) && /* @__PURE__ */ jsxs("div", {
|
|
138
|
+
className: "flex items-center gap-x-1.5",
|
|
139
|
+
children: [action, tooltip && /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
140
|
+
delay: 200,
|
|
141
|
+
render: /* @__PURE__ */ jsx("span", {}),
|
|
142
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
143
|
+
variant: "secondary",
|
|
144
|
+
className: "!text-xs !rounded-full !p-0 !size-5 flex items-center justify-center",
|
|
145
|
+
children: "?"
|
|
146
|
+
})
|
|
147
|
+
}), /* @__PURE__ */ jsx(TooltipPopup, {
|
|
148
|
+
side: "top",
|
|
149
|
+
align: "end",
|
|
150
|
+
className: "max-w-64 text-xs",
|
|
151
|
+
children: tooltip
|
|
152
|
+
})] })]
|
|
153
|
+
})]
|
|
285
154
|
});
|
|
286
155
|
var Label_default = Label$1;
|
|
287
156
|
|
|
@@ -696,6 +565,49 @@ const FieldRadio = ({ onChange, value, readOnly, field, label }) => {
|
|
|
696
565
|
};
|
|
697
566
|
var Radio_default = FieldRadio;
|
|
698
567
|
|
|
568
|
+
//#endregion
|
|
569
|
+
//#region src/components/ui/switch.tsx
|
|
570
|
+
function Switch({ className, ...props }) {
|
|
571
|
+
return /* @__PURE__ */ jsx(Switch$1.Root, {
|
|
572
|
+
className: cn("inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(5)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(4)] cursor-pointer", className),
|
|
573
|
+
"data-slot": "switch",
|
|
574
|
+
...props,
|
|
575
|
+
children: /* @__PURE__ */ jsx(Switch$1.Thumb, {
|
|
576
|
+
className: cn("pointer-events-none block aspect-square h-full origin-left in-[[role=switch]:active,[data-slot=label]:active,[data-slot=field-label]:active]:not-data-disabled:scale-x-110 in-[[role=switch]:active,[data-slot=label]:active,[data-slot=field-label]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.1)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s] data-checked:origin-[var(--thumb-size)_50%] data-checked:translate-x-[calc(var(--thumb-size)-4px)]"),
|
|
577
|
+
"data-slot": "switch-thumb"
|
|
578
|
+
})
|
|
579
|
+
});
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
//#endregion
|
|
583
|
+
//#region src/components/Fields/Switch/index.tsx
|
|
584
|
+
const FieldSwitch = ({ onChange, value, readOnly, field, label }) => {
|
|
585
|
+
const layout = field.layout || "stacked";
|
|
586
|
+
const handleCheckedChange = (checked) => {
|
|
587
|
+
if (!readOnly) onChange(checked);
|
|
588
|
+
};
|
|
589
|
+
const switchEl = /* @__PURE__ */ jsx(Switch, {
|
|
590
|
+
checked: !!value,
|
|
591
|
+
onCheckedChange: handleCheckedChange,
|
|
592
|
+
disabled: field.readOnly || readOnly
|
|
593
|
+
});
|
|
594
|
+
if (layout === "stacked") return /* @__PURE__ */ jsxs(Fragment, { children: [label && /* @__PURE__ */ jsx(Label_default, {
|
|
595
|
+
label,
|
|
596
|
+
readOnly: field.readOnly || readOnly,
|
|
597
|
+
tooltip: field.tooltip
|
|
598
|
+
}), switchEl] });
|
|
599
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
600
|
+
className: "flex items-center gap-x-3",
|
|
601
|
+
children: [switchEl, label && /* @__PURE__ */ jsx(Label_default, {
|
|
602
|
+
label,
|
|
603
|
+
readOnly: field.readOnly || readOnly,
|
|
604
|
+
tooltip: field.tooltip,
|
|
605
|
+
className: "mb-0"
|
|
606
|
+
})]
|
|
607
|
+
});
|
|
608
|
+
};
|
|
609
|
+
var Switch_default = FieldSwitch;
|
|
610
|
+
|
|
699
611
|
//#endregion
|
|
700
612
|
//#region src/components/ui/textarea.tsx
|
|
701
613
|
function Textarea({ className, size = "default", unstyled = false, ...props }) {
|
|
@@ -763,32 +675,32 @@ var ActionBar_default = ActionBar;
|
|
|
763
675
|
//#endregion
|
|
764
676
|
//#region src/components/ui/tabs.tsx
|
|
765
677
|
function Tabs({ className, ...props }) {
|
|
766
|
-
return /* @__PURE__ */ jsx(
|
|
678
|
+
return /* @__PURE__ */ jsx(TabsPrimitive.Root, {
|
|
767
679
|
className: cn("flex flex-col gap-2 data-[orientation=vertical]:flex-row", className),
|
|
768
680
|
"data-slot": "tabs",
|
|
769
681
|
...props
|
|
770
682
|
});
|
|
771
683
|
}
|
|
772
684
|
function TabsList({ variant = "default", className, children, ...props }) {
|
|
773
|
-
return /* @__PURE__ */ jsxs(
|
|
774
|
-
className: cn("
|
|
685
|
+
return /* @__PURE__ */ jsxs(TabsPrimitive.List, {
|
|
686
|
+
className: cn("relative z-0 flex w-fit items-center justify-center gap-x-0.5 text-muted-foreground", "data-[orientation=vertical]:flex-col", variant === "default" ? "rounded-lg bg-muted p-0.5 text-muted-foreground/72" : "data-[orientation=vertical]:px-1 data-[orientation=horizontal]:py-1 *:data-[slot=tabs-tab]:hover:bg-accent", className),
|
|
775
687
|
"data-slot": "tabs-list",
|
|
776
688
|
...props,
|
|
777
|
-
children: [children, /* @__PURE__ */ jsx(
|
|
778
|
-
className: cn("absolute bottom-0 left-0 h-(--active-tab-height) w-(--active-tab-width) translate-x-(--active-tab-left) -translate-y-(--active-tab-bottom) transition-[width,translate] duration-200 ease-in-out", variant === "underline" ? "bg-primary
|
|
689
|
+
children: [children, /* @__PURE__ */ jsx(TabsPrimitive.Indicator, {
|
|
690
|
+
className: cn("absolute bottom-0 left-0 h-(--active-tab-height) w-(--active-tab-width) translate-x-(--active-tab-left) -translate-y-(--active-tab-bottom) transition-[width,translate] duration-200 ease-in-out", variant === "underline" ? "z-10 bg-primary data-[orientation=horizontal]:h-0.5 data-[orientation=vertical]:w-0.5 data-[orientation=vertical]:-translate-x-px data-[orientation=horizontal]:translate-y-px" : "-z-1 rounded-md bg-background shadow-sm/5 dark:bg-input"),
|
|
779
691
|
"data-slot": "tab-indicator"
|
|
780
692
|
})]
|
|
781
693
|
});
|
|
782
694
|
}
|
|
783
695
|
function TabsTab({ className, ...props }) {
|
|
784
|
-
return /* @__PURE__ */ jsx(
|
|
785
|
-
className: cn("
|
|
696
|
+
return /* @__PURE__ */ jsx(TabsPrimitive.Tab, {
|
|
697
|
+
className: cn("relative flex h-9 shrink-0 grow cursor-pointer items-center justify-center gap-1.5 whitespace-nowrap rounded-md border border-transparent px-[calc(--spacing(2.5)-1px)] font-medium text-base outline-none transition-[color,background-color,box-shadow] hover:text-muted-foreground focus-visible:ring-2 focus-visible:ring-ring data-disabled:pointer-events-none data-[orientation=vertical]:w-full data-[orientation=vertical]:justify-start data-active:text-foreground data-disabled:opacity-64 sm:h-8 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:-mx-0.5 [&_svg]:shrink-0", className),
|
|
786
698
|
"data-slot": "tabs-tab",
|
|
787
699
|
...props
|
|
788
700
|
});
|
|
789
701
|
}
|
|
790
702
|
function TabsPanel({ className, ...props }) {
|
|
791
|
-
return /* @__PURE__ */ jsx(
|
|
703
|
+
return /* @__PURE__ */ jsx(TabsPrimitive.Panel, {
|
|
792
704
|
className: cn("flex-1 outline-none", className),
|
|
793
705
|
"data-slot": "tabs-content",
|
|
794
706
|
...props
|
|
@@ -1039,7 +951,7 @@ const DrawerItem = ({ name, icon }) => {
|
|
|
1039
951
|
children: [/* @__PURE__ */ jsxs("div", {
|
|
1040
952
|
className: "flex items-center gap-2 truncate",
|
|
1041
953
|
children: [/* @__PURE__ */ jsx("div", {
|
|
1042
|
-
className: "border-border group-hover:border-muted rounded-
|
|
954
|
+
className: "border-border group-hover:border-muted rounded-md border bg-white p-3",
|
|
1043
955
|
children: displayIcon
|
|
1044
956
|
}), /* @__PURE__ */ jsx("span", {
|
|
1045
957
|
className: "truncate text-sm font-medium",
|
|
@@ -1081,13 +993,14 @@ const createPuckOverridesPlugin = () => {
|
|
|
1081
993
|
fields: FieldGroups_default,
|
|
1082
994
|
fieldLabel: ({ children, label, field, tooltip }) => /* @__PURE__ */ jsxs(Fragment, { children: [label && /* @__PURE__ */ jsx(Label_default, {
|
|
1083
995
|
label,
|
|
1084
|
-
tooltip
|
|
996
|
+
tooltip: tooltip ?? field?.tooltip
|
|
1085
997
|
}), children] }),
|
|
1086
998
|
fieldTypes: {
|
|
1087
999
|
checkbox: Checkbox_default,
|
|
1088
1000
|
numberUnit: NumberUnit_default,
|
|
1089
1001
|
radio: Radio_default,
|
|
1090
1002
|
select: Select_default,
|
|
1003
|
+
switch: Switch_default,
|
|
1091
1004
|
text: Input_default,
|
|
1092
1005
|
textarea: Textarea_default
|
|
1093
1006
|
}
|
|
@@ -1189,28 +1102,28 @@ function Badge({ className, variant, size, render, ...props }) {
|
|
|
1189
1102
|
//#endregion
|
|
1190
1103
|
//#region src/components/ui/scroll-area.tsx
|
|
1191
1104
|
function ScrollArea({ className, children, scrollFade = false, scrollbarGutter = false, ...props }) {
|
|
1192
|
-
return /* @__PURE__ */ jsxs(
|
|
1105
|
+
return /* @__PURE__ */ jsxs(ScrollAreaPrimitive.Root, {
|
|
1193
1106
|
className: cn("size-full min-h-0", className),
|
|
1194
1107
|
...props,
|
|
1195
1108
|
children: [
|
|
1196
|
-
/* @__PURE__ */ jsx(
|
|
1197
|
-
className: cn("h-full rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-x:overscroll-x-contain", scrollFade && "mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]", scrollbarGutter && "data-has-overflow-y:pe-2.5 data-has-overflow-x:pb-2.5"),
|
|
1109
|
+
/* @__PURE__ */ jsx(ScrollAreaPrimitive.Viewport, {
|
|
1110
|
+
className: cn("h-full rounded-[inherit] outline-none transition-shadows focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-has-overflow-y:overscroll-y-contain data-has-overflow-x:overscroll-x-contain", scrollFade && "mask-t-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-start)))] mask-b-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-y-end)))] mask-l-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-start)))] mask-r-from-[calc(100%-min(var(--fade-size),var(--scroll-area-overflow-x-end)))] [--fade-size:1.5rem]", scrollbarGutter && "data-has-overflow-y:pe-2.5 data-has-overflow-x:pb-2.5"),
|
|
1198
1111
|
"data-slot": "scroll-area-viewport",
|
|
1199
1112
|
children
|
|
1200
1113
|
}),
|
|
1201
1114
|
/* @__PURE__ */ jsx(ScrollBar, { orientation: "vertical" }),
|
|
1202
1115
|
/* @__PURE__ */ jsx(ScrollBar, { orientation: "horizontal" }),
|
|
1203
|
-
/* @__PURE__ */ jsx(
|
|
1116
|
+
/* @__PURE__ */ jsx(ScrollAreaPrimitive.Corner, { "data-slot": "scroll-area-corner" })
|
|
1204
1117
|
]
|
|
1205
1118
|
});
|
|
1206
1119
|
}
|
|
1207
1120
|
function ScrollBar({ className, orientation = "vertical", ...props }) {
|
|
1208
|
-
return /* @__PURE__ */ jsx(
|
|
1121
|
+
return /* @__PURE__ */ jsx(ScrollAreaPrimitive.Scrollbar, {
|
|
1209
1122
|
className: cn("m-1 flex opacity-0 transition-opacity delay-300 data-[orientation=horizontal]:h-1.5 data-[orientation=vertical]:w-1.5 data-[orientation=horizontal]:flex-col data-hovering:opacity-100 data-scrolling:opacity-100 data-hovering:delay-0 data-scrolling:delay-0 data-hovering:duration-100 data-scrolling:duration-100", className),
|
|
1210
1123
|
"data-slot": "scroll-area-scrollbar",
|
|
1211
1124
|
orientation,
|
|
1212
1125
|
...props,
|
|
1213
|
-
children: /* @__PURE__ */ jsx(
|
|
1126
|
+
children: /* @__PURE__ */ jsx(ScrollAreaPrimitive.Thumb, {
|
|
1214
1127
|
className: "relative flex-1 rounded-full bg-foreground/20",
|
|
1215
1128
|
"data-slot": "scroll-area-thumb"
|
|
1216
1129
|
})
|
|
@@ -1246,7 +1159,7 @@ function DialogPopup({ className, children, showCloseButton = true, bottomStickO
|
|
|
1246
1159
|
return /* @__PURE__ */ jsxs(DialogPortal, { children: [/* @__PURE__ */ jsx(DialogBackdrop, {}), /* @__PURE__ */ jsx(DialogViewport, {
|
|
1247
1160
|
className: cn(bottomStickOnMobile && "max-sm:grid-rows-[1fr_auto] max-sm:p-0 max-sm:pt-12"),
|
|
1248
1161
|
children: /* @__PURE__ */ jsxs(Dialog$1.Popup, {
|
|
1249
|
-
className: cn("-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border bg-popover not-dark:bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg/5 transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", bottomStickOnMobile && "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden max-sm:before:rounded-none", className),
|
|
1162
|
+
className: cn("-translate-y-[calc(1.25rem*var(--nested-dialogs))] relative row-start-2 flex max-h-full min-h-0 w-full min-w-0 max-w-lg scale-[calc(1-0.1*var(--nested-dialogs))] flex-col rounded-2xl border bg-popover not-dark:bg-clip-padding text-popover-foreground opacity-[calc(1-0.1*var(--nested-dialogs))] shadow-lg/5 transition-[scale,opacity,translate] duration-200 ease-in-out will-change-transform before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-2xl)-1px)] before:shadow-[0_1px_--theme(--color-black/6%)] data-nested:data-ending-style:translate-y-8 data-nested:data-starting-style:translate-y-8 data-nested-dialog-open:origin-top data-ending-style:scale-98 data-starting-style:scale-98 data-ending-style:opacity-0 data-starting-style:opacity-0 dark:before:shadow-[0_-1px_--theme(--color-white/6%)] overflow-hidden", bottomStickOnMobile && "max-sm:max-w-none max-sm:rounded-none max-sm:border-x-0 max-sm:border-t max-sm:border-b-0 max-sm:opacity-[calc(1-min(var(--nested-dialogs),1))] max-sm:data-ending-style:translate-y-4 max-sm:data-starting-style:translate-y-4 max-sm:before:hidden max-sm:before:rounded-none", className),
|
|
1250
1163
|
"data-slot": "dialog-popup",
|
|
1251
1164
|
...props,
|
|
1252
1165
|
children: [children, showCloseButton && /* @__PURE__ */ jsx(Dialog$1.Close, {
|
|
@@ -1579,7 +1492,7 @@ function PickerModal({ title, searchQuery, onSearch, searchPlaceholder = "Search
|
|
|
1579
1492
|
25,
|
|
1580
1493
|
50,
|
|
1581
1494
|
100
|
|
1582
|
-
], emptyIcon, emptyMessage = "No results found", footer }) {
|
|
1495
|
+
], emptyIcon, emptyMessage = "No results found", footer, filterContent, tableContent, overlay }) {
|
|
1583
1496
|
const table = useReactTable({
|
|
1584
1497
|
data,
|
|
1585
1498
|
columns,
|
|
@@ -1597,16 +1510,35 @@ function PickerModal({ title, searchQuery, onSearch, searchPlaceholder = "Search
|
|
|
1597
1510
|
});
|
|
1598
1511
|
const pageSize = table.getState().pagination.pageSize;
|
|
1599
1512
|
return /* @__PURE__ */ jsxs(DialogPopup, {
|
|
1600
|
-
className: "max-w-4xl",
|
|
1513
|
+
className: "relative max-w-4xl",
|
|
1601
1514
|
children: [
|
|
1602
1515
|
/* @__PURE__ */ jsx(DialogHeader, { children: /* @__PURE__ */ jsx(DialogTitle, { children: title }) }),
|
|
1603
1516
|
/* @__PURE__ */ jsxs(DialogPanel, {
|
|
1604
1517
|
className: "flex flex-col gap-4",
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1518
|
+
scrollFade: false,
|
|
1519
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
1520
|
+
className: "flex items-center gap-2",
|
|
1521
|
+
children: [/* @__PURE__ */ jsxs(InputGroup, {
|
|
1522
|
+
className: "flex-1",
|
|
1523
|
+
children: [/* @__PURE__ */ jsx(InputGroupInput, {
|
|
1524
|
+
placeholder: searchPlaceholder,
|
|
1525
|
+
value: searchQuery,
|
|
1526
|
+
onChange: (e) => onSearch(e.target.value)
|
|
1527
|
+
}), /* @__PURE__ */ jsx(InputGroupAddon, {
|
|
1528
|
+
align: "inline-end",
|
|
1529
|
+
children: searchQuery ? /* @__PURE__ */ jsx(Button, {
|
|
1530
|
+
"aria-label": "Clear search",
|
|
1531
|
+
onClick: () => onSearch(""),
|
|
1532
|
+
size: "icon-xs",
|
|
1533
|
+
variant: "ghost",
|
|
1534
|
+
children: /* @__PURE__ */ jsx(XIcon, { "aria-hidden": "true" })
|
|
1535
|
+
}) : /* @__PURE__ */ jsx(SearchIcon, { className: "size-4" })
|
|
1536
|
+
})]
|
|
1537
|
+
}), filterContent && /* @__PURE__ */ jsx("div", {
|
|
1538
|
+
className: "flex items-center gap-2",
|
|
1539
|
+
children: filterContent
|
|
1540
|
+
})]
|
|
1541
|
+
}), tableContent ? tableContent : loading ? /* @__PURE__ */ jsx("div", {
|
|
1610
1542
|
className: "flex items-center justify-center py-12",
|
|
1611
1543
|
children: /* @__PURE__ */ jsx(Loader2Icon, { className: "text-muted-foreground size-8 animate-spin" })
|
|
1612
1544
|
}) : /* @__PURE__ */ jsxs(Frame, {
|
|
@@ -1777,7 +1709,8 @@ function PickerModal({ title, searchQuery, onSearch, searchPlaceholder = "Search
|
|
|
1777
1709
|
})]
|
|
1778
1710
|
})]
|
|
1779
1711
|
}),
|
|
1780
|
-
footer && /* @__PURE__ */ jsx(DialogFooter, { children: footer })
|
|
1712
|
+
footer && /* @__PURE__ */ jsx(DialogFooter, { children: footer }),
|
|
1713
|
+
overlay
|
|
1781
1714
|
]
|
|
1782
1715
|
});
|
|
1783
1716
|
}
|
|
@@ -2360,6 +2293,486 @@ function RichTextMenuColorPicker({ editor, ...props }) {
|
|
|
2360
2293
|
});
|
|
2361
2294
|
}
|
|
2362
2295
|
|
|
2296
|
+
//#endregion
|
|
2297
|
+
//#region src/plugins/unsplash/utils/unsplashClient.ts
|
|
2298
|
+
const DEFAULT_SEARCH_ENDPOINT = "/admin/puck/unsplash/search";
|
|
2299
|
+
const DEFAULT_DOWNLOAD_ENDPOINT = "/admin/puck/unsplash/download";
|
|
2300
|
+
const DEFAULT_UPLOAD_ENDPOINT = "/admin/puck/unsplash/upload";
|
|
2301
|
+
/** Terme utilisé pour afficher les photos "à la une" quand aucune recherche n'est saisie. */
|
|
2302
|
+
const DEFAULT_FEATURED_QUERY = "editorial";
|
|
2303
|
+
const TIMEOUT_MS$1 = 2e4;
|
|
2304
|
+
async function searchUnsplashPhotos({ endpoint = DEFAULT_SEARCH_ENDPOINT, query, page = 1, portrait = false, landscape = false }) {
|
|
2305
|
+
const controller = new AbortController();
|
|
2306
|
+
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS$1);
|
|
2307
|
+
const params = new URLSearchParams();
|
|
2308
|
+
params.set("query", query);
|
|
2309
|
+
if (page > 1) params.set("page", String(page));
|
|
2310
|
+
if (portrait) params.set("portrait", "1");
|
|
2311
|
+
if (landscape) params.set("landscape", "1");
|
|
2312
|
+
try {
|
|
2313
|
+
const response = await fetch(`${endpoint}?${params.toString()}`, {
|
|
2314
|
+
method: "GET",
|
|
2315
|
+
headers: { Accept: "application/json" },
|
|
2316
|
+
credentials: "same-origin",
|
|
2317
|
+
signal: controller.signal
|
|
2318
|
+
});
|
|
2319
|
+
if (!response.ok) {
|
|
2320
|
+
const body = await response.json().catch(() => ({}));
|
|
2321
|
+
throw new Error(body.error || `Erreur serveur (${response.status})`);
|
|
2322
|
+
}
|
|
2323
|
+
const data = await response.json();
|
|
2324
|
+
const items = (Array.isArray(data.items) ? data.items : Array.isArray(data.results) ? data.results : []).map((item) => ({
|
|
2325
|
+
id: String(item.id),
|
|
2326
|
+
description: item.description ?? null,
|
|
2327
|
+
altDescription: item.alt_description ?? item.altDescription ?? null,
|
|
2328
|
+
thumbUrl: item.thumbUrl ?? item.urls?.thumb ?? item.urls?.small ?? "",
|
|
2329
|
+
regularUrl: item.regularUrl ?? item.urls?.regular ?? item.urls?.small ?? "",
|
|
2330
|
+
htmlUrl: item.htmlUrl ?? item.links?.html ?? "",
|
|
2331
|
+
width: item.width,
|
|
2332
|
+
height: item.height,
|
|
2333
|
+
authorName: item.authorName ?? item.user?.name
|
|
2334
|
+
}));
|
|
2335
|
+
return {
|
|
2336
|
+
items,
|
|
2337
|
+
total: Number(data.total ?? data.total_results ?? items.length) || 0
|
|
2338
|
+
};
|
|
2339
|
+
} catch (error) {
|
|
2340
|
+
if (error.name === "AbortError") throw new Error("La requête Unsplash a expiré. Réessayez.");
|
|
2341
|
+
throw error;
|
|
2342
|
+
} finally {
|
|
2343
|
+
clearTimeout(timeoutId);
|
|
2344
|
+
}
|
|
2345
|
+
}
|
|
2346
|
+
async function downloadUnsplashPhoto({ endpoint = DEFAULT_DOWNLOAD_ENDPOINT, uploadEndpoint = DEFAULT_UPLOAD_ENDPOINT, id }) {
|
|
2347
|
+
const params = new URLSearchParams();
|
|
2348
|
+
params.set("id", id);
|
|
2349
|
+
const response = await fetch(`${endpoint}?${params.toString()}`, {
|
|
2350
|
+
method: "GET",
|
|
2351
|
+
headers: { Accept: "application/json" },
|
|
2352
|
+
credentials: "same-origin"
|
|
2353
|
+
});
|
|
2354
|
+
if (!response.ok) {
|
|
2355
|
+
const body = await response.json().catch(() => ({}));
|
|
2356
|
+
throw new Error(body.error || `Erreur serveur (${response.status})`);
|
|
2357
|
+
}
|
|
2358
|
+
const data = await response.json().catch(() => ({}));
|
|
2359
|
+
const downloadUrl = typeof data.url === "string" ? data.url.trim() : "";
|
|
2360
|
+
if (!downloadUrl) throw new Error("La réponse de download ne contient pas d'URL exploitable.");
|
|
2361
|
+
await uploadUnsplashPhoto({
|
|
2362
|
+
endpoint: uploadEndpoint,
|
|
2363
|
+
url: downloadUrl
|
|
2364
|
+
});
|
|
2365
|
+
}
|
|
2366
|
+
async function uploadUnsplashPhoto({ endpoint = DEFAULT_UPLOAD_ENDPOINT, url }) {
|
|
2367
|
+
const token = getCsrfToken();
|
|
2368
|
+
const response = await fetch(endpoint, {
|
|
2369
|
+
method: "POST",
|
|
2370
|
+
headers: {
|
|
2371
|
+
Accept: "application/json",
|
|
2372
|
+
"Content-Type": "application/json",
|
|
2373
|
+
...token ? { "X-CSRF-TOKEN": token } : {}
|
|
2374
|
+
},
|
|
2375
|
+
credentials: "same-origin",
|
|
2376
|
+
body: JSON.stringify({ url })
|
|
2377
|
+
});
|
|
2378
|
+
if (!response.ok) {
|
|
2379
|
+
const body = await response.json().catch(() => ({}));
|
|
2380
|
+
throw new Error(body.error || `Erreur serveur (${response.status})`);
|
|
2381
|
+
}
|
|
2382
|
+
}
|
|
2383
|
+
|
|
2384
|
+
//#endregion
|
|
2385
|
+
//#region src/plugins/unsplash/hooks/useUnsplashSearch.ts
|
|
2386
|
+
function useUnsplashSearch({ endpoint, featuredQuery = DEFAULT_FEATURED_QUERY, initialQuery = "", perPage = 12, debounceMs = 300, enabled = true }) {
|
|
2387
|
+
const [query, setQuery] = useState(initialQuery);
|
|
2388
|
+
const [page, setPage] = useState(1);
|
|
2389
|
+
const [portrait, setPortrait] = useState(false);
|
|
2390
|
+
const [landscape, setLandscape] = useState(false);
|
|
2391
|
+
const [items, setItems] = useState([]);
|
|
2392
|
+
const [total, setTotal] = useState(0);
|
|
2393
|
+
const [loading, setLoading] = useState(false);
|
|
2394
|
+
const [error, setError] = useState(null);
|
|
2395
|
+
const [refreshIndex, setRefreshIndex] = useState(0);
|
|
2396
|
+
const [hasMore, setHasMore] = useState(false);
|
|
2397
|
+
const [isFeatured, setIsFeatured] = useState(false);
|
|
2398
|
+
const totalPages = useMemo(() => Math.max(1, Math.ceil(total / perPage)), [total, perPage]);
|
|
2399
|
+
useEffect(() => {
|
|
2400
|
+
if (!enabled) return;
|
|
2401
|
+
const isFeaturedMode = !query.trim();
|
|
2402
|
+
const effectiveQuery = isFeaturedMode ? featuredQuery : query.trim();
|
|
2403
|
+
setIsFeatured(isFeaturedMode);
|
|
2404
|
+
const timer = setTimeout(async () => {
|
|
2405
|
+
setLoading(true);
|
|
2406
|
+
setError(null);
|
|
2407
|
+
try {
|
|
2408
|
+
const result = await searchUnsplashPhotos({
|
|
2409
|
+
endpoint,
|
|
2410
|
+
query: effectiveQuery,
|
|
2411
|
+
page,
|
|
2412
|
+
portrait,
|
|
2413
|
+
landscape
|
|
2414
|
+
});
|
|
2415
|
+
setItems((prev) => page > 1 ? [...prev, ...result.items] : result.items);
|
|
2416
|
+
setTotal(result.total);
|
|
2417
|
+
setHasMore(result.items.length > 0);
|
|
2418
|
+
} catch (err) {
|
|
2419
|
+
setItems([]);
|
|
2420
|
+
setTotal(0);
|
|
2421
|
+
setHasMore(false);
|
|
2422
|
+
setError(err?.message || "Impossible de charger les photos Unsplash.");
|
|
2423
|
+
} finally {
|
|
2424
|
+
setLoading(false);
|
|
2425
|
+
}
|
|
2426
|
+
}, debounceMs);
|
|
2427
|
+
return () => {
|
|
2428
|
+
clearTimeout(timer);
|
|
2429
|
+
};
|
|
2430
|
+
}, [
|
|
2431
|
+
enabled,
|
|
2432
|
+
endpoint,
|
|
2433
|
+
featuredQuery,
|
|
2434
|
+
query,
|
|
2435
|
+
page,
|
|
2436
|
+
perPage,
|
|
2437
|
+
debounceMs,
|
|
2438
|
+
refreshIndex,
|
|
2439
|
+
portrait,
|
|
2440
|
+
landscape
|
|
2441
|
+
]);
|
|
2442
|
+
return {
|
|
2443
|
+
query,
|
|
2444
|
+
page,
|
|
2445
|
+
portrait,
|
|
2446
|
+
landscape,
|
|
2447
|
+
totalPages,
|
|
2448
|
+
hasMore,
|
|
2449
|
+
isFeatured,
|
|
2450
|
+
items,
|
|
2451
|
+
total,
|
|
2452
|
+
loading,
|
|
2453
|
+
error,
|
|
2454
|
+
onSearchChange: useCallback((value) => {
|
|
2455
|
+
setQuery(value);
|
|
2456
|
+
setPage(1);
|
|
2457
|
+
setHasMore(false);
|
|
2458
|
+
}, []),
|
|
2459
|
+
onPageChange: useCallback((nextPage) => {
|
|
2460
|
+
setPage(Math.max(1, nextPage));
|
|
2461
|
+
}, []),
|
|
2462
|
+
onPortraitChange: useCallback((value) => {
|
|
2463
|
+
setPortrait(value);
|
|
2464
|
+
setPage(1);
|
|
2465
|
+
}, []),
|
|
2466
|
+
onLandscapeChange: useCallback((value) => {
|
|
2467
|
+
setLandscape(value);
|
|
2468
|
+
setPage(1);
|
|
2469
|
+
}, []),
|
|
2470
|
+
refresh: useCallback(() => {
|
|
2471
|
+
setRefreshIndex((value) => value + 1);
|
|
2472
|
+
}, [])
|
|
2473
|
+
};
|
|
2474
|
+
}
|
|
2475
|
+
|
|
2476
|
+
//#endregion
|
|
2477
|
+
//#region src/plugins/unsplash/hooks/useUnsplashModalController.ts
|
|
2478
|
+
function useUnsplashModalController({ downloadEndpoint, uploadEndpoint, onDownloadPhoto, onPhotoRegistered, items, refresh }) {
|
|
2479
|
+
const [selectedPhotoId, setSelectedPhotoId] = useState(null);
|
|
2480
|
+
const [saveError, setSaveError] = useState(null);
|
|
2481
|
+
const [saving, setSaving] = useState(false);
|
|
2482
|
+
const selectedPhoto = useMemo(() => items.find((item) => item.id === selectedPhotoId) ?? null, [items, selectedPhotoId]);
|
|
2483
|
+
const onSelectPhoto = useCallback((photoId) => {
|
|
2484
|
+
setSelectedPhotoId(photoId);
|
|
2485
|
+
}, []);
|
|
2486
|
+
const savePhoto = useCallback(async (photo) => {
|
|
2487
|
+
if (saving) return;
|
|
2488
|
+
setSaving(true);
|
|
2489
|
+
setSaveError(null);
|
|
2490
|
+
try {
|
|
2491
|
+
if (onDownloadPhoto) await onDownloadPhoto(photo);
|
|
2492
|
+
else await downloadUnsplashPhoto({
|
|
2493
|
+
endpoint: downloadEndpoint,
|
|
2494
|
+
uploadEndpoint,
|
|
2495
|
+
id: photo.id
|
|
2496
|
+
});
|
|
2497
|
+
onPhotoRegistered?.();
|
|
2498
|
+
toastManager.add({
|
|
2499
|
+
title: "Download successful",
|
|
2500
|
+
type: "success"
|
|
2501
|
+
});
|
|
2502
|
+
refresh();
|
|
2503
|
+
} catch (err) {
|
|
2504
|
+
setSaveError(err?.message || "An error occurred while downloading the photo.");
|
|
2505
|
+
toastManager.add({
|
|
2506
|
+
title: "Download failed",
|
|
2507
|
+
description: err?.message || "An error occurred while downloading the photo.",
|
|
2508
|
+
type: "error"
|
|
2509
|
+
});
|
|
2510
|
+
} finally {
|
|
2511
|
+
setSaving(false);
|
|
2512
|
+
}
|
|
2513
|
+
}, [
|
|
2514
|
+
downloadEndpoint,
|
|
2515
|
+
onDownloadPhoto,
|
|
2516
|
+
onPhotoRegistered,
|
|
2517
|
+
refresh,
|
|
2518
|
+
saving,
|
|
2519
|
+
uploadEndpoint
|
|
2520
|
+
]);
|
|
2521
|
+
return {
|
|
2522
|
+
selectedPhotoId,
|
|
2523
|
+
selectedPhoto,
|
|
2524
|
+
saveError,
|
|
2525
|
+
saving,
|
|
2526
|
+
onSelectPhoto,
|
|
2527
|
+
onSavePhoto: useCallback(async (photoId) => {
|
|
2528
|
+
const photo = items.find((item) => item.id === photoId);
|
|
2529
|
+
if (!photo) return;
|
|
2530
|
+
await savePhoto(photo);
|
|
2531
|
+
}, [items, savePhoto]),
|
|
2532
|
+
onSave: useCallback(async () => {
|
|
2533
|
+
if (!selectedPhoto) return;
|
|
2534
|
+
await savePhoto(selectedPhoto);
|
|
2535
|
+
}, [savePhoto, selectedPhoto])
|
|
2536
|
+
};
|
|
2537
|
+
}
|
|
2538
|
+
|
|
2539
|
+
//#endregion
|
|
2540
|
+
//#region src/plugins/unsplash/components/UnsplashPhotoGrid.tsx
|
|
2541
|
+
function PhotoPreviewOverlay({ photo, onClose, onDownload }) {
|
|
2542
|
+
useEffect(() => {
|
|
2543
|
+
const handleKey = (e) => {
|
|
2544
|
+
if (e.key === "Escape") onClose();
|
|
2545
|
+
};
|
|
2546
|
+
document.addEventListener("keydown", handleKey);
|
|
2547
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
2548
|
+
}, [onClose]);
|
|
2549
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2550
|
+
className: "fixed inset-0 z-[9999] flex items-center justify-center bg-black/80 backdrop-blur-sm p-4",
|
|
2551
|
+
onClick: onClose,
|
|
2552
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2553
|
+
className: "relative flex max-h-full max-w-5xl flex-col overflow-hidden rounded-xl shadow-2xl",
|
|
2554
|
+
onClick: (e) => e.stopPropagation(),
|
|
2555
|
+
children: [
|
|
2556
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2557
|
+
className: "absolute right-2 top-2 z-10 flex gap-1.5",
|
|
2558
|
+
children: [photo.htmlUrl && /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, { render: /* @__PURE__ */ jsx(Button, {
|
|
2559
|
+
type: "button",
|
|
2560
|
+
size: "icon",
|
|
2561
|
+
variant: "outline",
|
|
2562
|
+
className: "bg-white/90 backdrop-blur-sm hover:bg-white",
|
|
2563
|
+
onClick: () => window.open(photo.htmlUrl, "_blank"),
|
|
2564
|
+
children: /* @__PURE__ */ jsx(ExternalLinkIcon, { className: "size-4" })
|
|
2565
|
+
}) }), /* @__PURE__ */ jsx(TooltipPopup, {
|
|
2566
|
+
className: "text-xs",
|
|
2567
|
+
children: "View on Unsplash"
|
|
2568
|
+
})] }), /* @__PURE__ */ jsx(Button, {
|
|
2569
|
+
type: "button",
|
|
2570
|
+
size: "icon",
|
|
2571
|
+
variant: "outline",
|
|
2572
|
+
onClick: onClose,
|
|
2573
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
|
|
2574
|
+
})]
|
|
2575
|
+
}),
|
|
2576
|
+
/* @__PURE__ */ jsx("div", {
|
|
2577
|
+
className: "overflow-hidden",
|
|
2578
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
2579
|
+
src: photo.regularUrl,
|
|
2580
|
+
alt: photo.description,
|
|
2581
|
+
className: "h-auto w-full object-contain"
|
|
2582
|
+
})
|
|
2583
|
+
}),
|
|
2584
|
+
/* @__PURE__ */ jsxs("div", {
|
|
2585
|
+
className: "flex items-center justify-between gap-4 bg-white px-4 py-3",
|
|
2586
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2587
|
+
className: "min-w-0",
|
|
2588
|
+
children: [photo.authorName && /* @__PURE__ */ jsx("p", {
|
|
2589
|
+
className: "text-sm font-medium text-gray-900 truncate",
|
|
2590
|
+
children: photo.authorName
|
|
2591
|
+
}), photo.description && /* @__PURE__ */ jsx("p", {
|
|
2592
|
+
className: "text-xs text-gray-500 truncate",
|
|
2593
|
+
children: photo.description
|
|
2594
|
+
})]
|
|
2595
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
2596
|
+
type: "button",
|
|
2597
|
+
size: "sm",
|
|
2598
|
+
onClick: () => {
|
|
2599
|
+
onDownload(photo.id);
|
|
2600
|
+
onClose();
|
|
2601
|
+
},
|
|
2602
|
+
children: "Download"
|
|
2603
|
+
})]
|
|
2604
|
+
})
|
|
2605
|
+
]
|
|
2606
|
+
})
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
function UnsplashPhotoGrid({ items, selectedPhotoId, onSelectPhoto, onDownloadPhoto }) {
|
|
2610
|
+
const [previewPhoto, setPreviewPhoto] = useState(null);
|
|
2611
|
+
const openPreview = useCallback((photo, description) => {
|
|
2612
|
+
setPreviewPhoto({
|
|
2613
|
+
...photo,
|
|
2614
|
+
description
|
|
2615
|
+
});
|
|
2616
|
+
}, []);
|
|
2617
|
+
const closePreview = useCallback(() => {
|
|
2618
|
+
setPreviewPhoto(null);
|
|
2619
|
+
}, []);
|
|
2620
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("div", {
|
|
2621
|
+
className: "columns-2 gap-3 sm:columns-3",
|
|
2622
|
+
children: items.map((photo) => {
|
|
2623
|
+
const rawDescription = photo.altDescription || photo.description || "Photo Unsplash";
|
|
2624
|
+
const description = rawDescription.charAt(0).toUpperCase() + rawDescription.slice(1);
|
|
2625
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
2626
|
+
onClick: () => onSelectPhoto(photo.id),
|
|
2627
|
+
className: "group relative mb-3 w-full overflow-hidden rounded-lg border text-left transition break-inside-avoid cursor-pointer",
|
|
2628
|
+
children: [
|
|
2629
|
+
/* @__PURE__ */ jsx("img", {
|
|
2630
|
+
src: photo.thumbUrl,
|
|
2631
|
+
alt: description,
|
|
2632
|
+
className: "h-auto w-full object-cover"
|
|
2633
|
+
}),
|
|
2634
|
+
selectedPhotoId === photo.id && /* @__PURE__ */ jsx("div", { className: "absolute inset-0 rounded-lg ring-2 ring-primary ring-offset-1 pointer-events-none" }),
|
|
2635
|
+
/* @__PURE__ */ jsx("div", {
|
|
2636
|
+
className: "absolute inset-0 bg-gradient-to-t from-black/75 via-black/45 to-transparent opacity-0 transition-all duration-300 ease-out group-hover:opacity-100",
|
|
2637
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
2638
|
+
className: "absolute inset-x-0 bottom-0 translate-y-3 p-3 transition-transform duration-300 ease-out group-hover:translate-y-0 flex gap-x-3 justify-between items-end",
|
|
2639
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
2640
|
+
className: "flex flex-col gap-y-1.5 text-white min-w-0",
|
|
2641
|
+
children: [photo.authorName && /* @__PURE__ */ jsx("div", {
|
|
2642
|
+
className: "text-xs font-medium truncate",
|
|
2643
|
+
children: photo.authorName
|
|
2644
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
2645
|
+
className: "line-clamp-2 text-xs text-white/80",
|
|
2646
|
+
children: description
|
|
2647
|
+
})]
|
|
2648
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
2649
|
+
className: "flex shrink-0 gap-1.5",
|
|
2650
|
+
children: [/* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
2651
|
+
delay: 50,
|
|
2652
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
2653
|
+
type: "button",
|
|
2654
|
+
variant: "outline",
|
|
2655
|
+
className: "hover:bg-stone-50!",
|
|
2656
|
+
size: "icon-lg",
|
|
2657
|
+
onClick: (e) => {
|
|
2658
|
+
e.stopPropagation();
|
|
2659
|
+
openPreview(photo, description);
|
|
2660
|
+
},
|
|
2661
|
+
children: /* @__PURE__ */ jsx(ZoomInIcon, {
|
|
2662
|
+
"aria-hidden": "true",
|
|
2663
|
+
className: "size-4"
|
|
2664
|
+
})
|
|
2665
|
+
})
|
|
2666
|
+
}), /* @__PURE__ */ jsx(TooltipPopup, {
|
|
2667
|
+
className: "text-xs",
|
|
2668
|
+
children: "Preview"
|
|
2669
|
+
})] }), /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
2670
|
+
delay: 50,
|
|
2671
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
2672
|
+
type: "button",
|
|
2673
|
+
variant: "outline",
|
|
2674
|
+
className: "hover:bg-stone-50!",
|
|
2675
|
+
size: "icon-lg",
|
|
2676
|
+
onClick: (e) => {
|
|
2677
|
+
e.stopPropagation();
|
|
2678
|
+
onSelectPhoto(photo.id);
|
|
2679
|
+
onDownloadPhoto(photo.id);
|
|
2680
|
+
},
|
|
2681
|
+
children: /* @__PURE__ */ jsx(DownloadIcon, {
|
|
2682
|
+
"aria-hidden": "true",
|
|
2683
|
+
className: "size-4"
|
|
2684
|
+
})
|
|
2685
|
+
})
|
|
2686
|
+
}), /* @__PURE__ */ jsx(TooltipPopup, {
|
|
2687
|
+
className: "text-xs",
|
|
2688
|
+
children: "Download"
|
|
2689
|
+
})] })]
|
|
2690
|
+
})]
|
|
2691
|
+
})
|
|
2692
|
+
})
|
|
2693
|
+
]
|
|
2694
|
+
}, photo.id);
|
|
2695
|
+
})
|
|
2696
|
+
}), previewPhoto && /* @__PURE__ */ jsx(PhotoPreviewOverlay, {
|
|
2697
|
+
photo: previewPhoto,
|
|
2698
|
+
onClose: closePreview,
|
|
2699
|
+
onDownload: (id) => {
|
|
2700
|
+
onSelectPhoto(id);
|
|
2701
|
+
return onDownloadPhoto(id);
|
|
2702
|
+
}
|
|
2703
|
+
})] });
|
|
2704
|
+
}
|
|
2705
|
+
|
|
2706
|
+
//#endregion
|
|
2707
|
+
//#region src/components/ui/alert.tsx
|
|
2708
|
+
const alertVariants = cva("relative grid w-full items-start gap-x-2 gap-y-0.5 rounded-lg border text-card-foreground text-sm has-[>svg]:has-data-[slot=alert-action]:grid-cols-[calc(var(--spacing)*4)_1fr_auto] has-[>svg]:grid-cols-[calc(var(--spacing)*4)_1fr] has-data-[slot=alert-action]:grid-cols-[1fr_auto] has-[>svg]:gap-x-2 [&>svg]:h-lh [&>svg]:w-4", {
|
|
2709
|
+
defaultVariants: {
|
|
2710
|
+
size: "default",
|
|
2711
|
+
variant: "default"
|
|
2712
|
+
},
|
|
2713
|
+
variants: {
|
|
2714
|
+
size: {
|
|
2715
|
+
default: "px-3.5 py-3",
|
|
2716
|
+
sm: "px-2.5 py-2 text-xs"
|
|
2717
|
+
},
|
|
2718
|
+
variant: {
|
|
2719
|
+
default: "bg-transparent dark:bg-input/32 [&>svg]:text-muted-foreground",
|
|
2720
|
+
error: "border-destructive/32 bg-destructive/4 [&>svg]:text-destructive",
|
|
2721
|
+
info: "border-info/32 bg-info/4 [&>svg]:text-info",
|
|
2722
|
+
success: "border-success/32 bg-success/4 [&>svg]:text-success",
|
|
2723
|
+
warning: "border-warning/32 bg-warning/4 [&>svg]:text-warning"
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
});
|
|
2727
|
+
function Alert({ className, size, variant, ...props }) {
|
|
2728
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2729
|
+
className: cn(alertVariants({
|
|
2730
|
+
size,
|
|
2731
|
+
variant
|
|
2732
|
+
}), className),
|
|
2733
|
+
"data-slot": "alert",
|
|
2734
|
+
role: "alert",
|
|
2735
|
+
...props
|
|
2736
|
+
});
|
|
2737
|
+
}
|
|
2738
|
+
function AlertTitle({ className, ...props }) {
|
|
2739
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2740
|
+
className: cn("font-medium [svg~&]:col-start-2", className),
|
|
2741
|
+
"data-slot": "alert-title",
|
|
2742
|
+
...props
|
|
2743
|
+
});
|
|
2744
|
+
}
|
|
2745
|
+
function AlertDescription({ className, ...props }) {
|
|
2746
|
+
return /* @__PURE__ */ jsx("div", {
|
|
2747
|
+
className: cn("flex flex-col gap-2.5 text-muted-foreground [svg~&]:col-start-2", className),
|
|
2748
|
+
"data-slot": "alert-description",
|
|
2749
|
+
...props
|
|
2750
|
+
});
|
|
2751
|
+
}
|
|
2752
|
+
|
|
2753
|
+
//#endregion
|
|
2754
|
+
//#region src/plugins/unsplash/components/UnsplashStatus.tsx
|
|
2755
|
+
function UnsplashStatus({ loading = false, error = null, saveError = null, noResults = false }) {
|
|
2756
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
2757
|
+
error ? /* @__PURE__ */ jsxs(Alert, {
|
|
2758
|
+
variant: "error",
|
|
2759
|
+
children: [/* @__PURE__ */ jsx(TriangleAlertIcon, {}), /* @__PURE__ */ jsx(AlertDescription, { children: error })]
|
|
2760
|
+
}) : null,
|
|
2761
|
+
saveError ? /* @__PURE__ */ jsxs(Alert, {
|
|
2762
|
+
variant: "error",
|
|
2763
|
+
children: [/* @__PURE__ */ jsx(TriangleAlertIcon, {}), /* @__PURE__ */ jsx(AlertDescription, { children: saveError })]
|
|
2764
|
+
}) : null,
|
|
2765
|
+
noResults ? /* @__PURE__ */ jsxs(Alert, {
|
|
2766
|
+
variant: "info",
|
|
2767
|
+
children: [/* @__PURE__ */ jsx(InfoIcon, {}), /* @__PURE__ */ jsx(AlertDescription, { children: "No photos found for your search." })]
|
|
2768
|
+
}) : null,
|
|
2769
|
+
loading ? /* @__PURE__ */ jsx("div", {
|
|
2770
|
+
className: "flex items-center justify-center py-8",
|
|
2771
|
+
children: /* @__PURE__ */ jsx(Loader2Icon, { className: "text-muted-foreground size-8 animate-spin" })
|
|
2772
|
+
}) : null
|
|
2773
|
+
] });
|
|
2774
|
+
}
|
|
2775
|
+
|
|
2363
2776
|
//#endregion
|
|
2364
2777
|
//#region src/components/MediaPicker/index.tsx
|
|
2365
2778
|
const getEditorConfig = () => {
|
|
@@ -2422,7 +2835,7 @@ const MediaUploadZone = ({ onUploadSuccess, acceptedTypes = "image/*,video/*,app
|
|
|
2422
2835
|
return new Promise((resolve, reject) => {
|
|
2423
2836
|
try {
|
|
2424
2837
|
const { uploadUrl, langId } = getEditorConfig();
|
|
2425
|
-
const csrfToken =
|
|
2838
|
+
const csrfToken = getCsrfToken();
|
|
2426
2839
|
const formData = new FormData();
|
|
2427
2840
|
formData.append("file", file);
|
|
2428
2841
|
if (langId) formData.append("lang_id", langId);
|
|
@@ -2431,17 +2844,20 @@ const MediaUploadZone = ({ onUploadSuccess, acceptedTypes = "image/*,video/*,app
|
|
|
2431
2844
|
if (e.lengthComputable) setUploadProgress(e.loaded / e.total * 100);
|
|
2432
2845
|
});
|
|
2433
2846
|
xhr.addEventListener("load", () => {
|
|
2434
|
-
|
|
2847
|
+
try {
|
|
2435
2848
|
const response = JSON.parse(xhr.responseText);
|
|
2436
|
-
if (response.success && response.media) resolve(response.media);
|
|
2437
|
-
else reject(
|
|
2438
|
-
}
|
|
2849
|
+
if (xhr.status === 200 && response.success && response.media) resolve(response.media);
|
|
2850
|
+
else reject(new Error(response.message || response.error || `Upload failed (${xhr.status})`));
|
|
2851
|
+
} catch {
|
|
2852
|
+
reject(/* @__PURE__ */ new Error(`Server returned an unexpected response (status ${xhr.status}). The server may not accept this file type.`));
|
|
2853
|
+
}
|
|
2439
2854
|
});
|
|
2440
2855
|
xhr.addEventListener("error", () => {
|
|
2441
2856
|
reject(/* @__PURE__ */ new Error("Error during upload"));
|
|
2442
2857
|
});
|
|
2443
2858
|
xhr.open("POST", uploadUrl);
|
|
2444
|
-
|
|
2859
|
+
xhr.setRequestHeader("Accept", "application/json");
|
|
2860
|
+
if (csrfToken) xhr.setRequestHeader("X-CSRF-TOKEN", csrfToken);
|
|
2445
2861
|
xhr.send(formData);
|
|
2446
2862
|
} catch (error) {
|
|
2447
2863
|
reject(error);
|
|
@@ -2559,24 +2975,86 @@ const MediaUploadZone = ({ onUploadSuccess, acceptedTypes = "image/*,video/*,app
|
|
|
2559
2975
|
});
|
|
2560
2976
|
};
|
|
2561
2977
|
const MediaPreview = ({ media, className }) => {
|
|
2562
|
-
|
|
2563
|
-
|
|
2564
|
-
|
|
2565
|
-
|
|
2566
|
-
|
|
2978
|
+
const type = media.type.toLowerCase();
|
|
2979
|
+
const isVideo = type.startsWith("video/") || type === "video";
|
|
2980
|
+
const isImage = type.startsWith("image/") || type === "picture";
|
|
2981
|
+
const isFile = !isVideo && !isImage;
|
|
2982
|
+
if (isVideo) return /* @__PURE__ */ jsx("div", {
|
|
2983
|
+
className: cn("flex items-center justify-center aspect-square border border-border rounded-md bg-muted", className),
|
|
2984
|
+
children: /* @__PURE__ */ jsx(FilePlayIcon, { className: "text-muted-foreground size-5" })
|
|
2985
|
+
});
|
|
2986
|
+
if (isFile) return /* @__PURE__ */ jsx("div", {
|
|
2987
|
+
className: cn("flex items-center justify-center aspect-square border border-border rounded-md bg-muted", className),
|
|
2988
|
+
children: /* @__PURE__ */ jsx(FileTextIcon, { className: "text-muted-foreground size-5" })
|
|
2567
2989
|
});
|
|
2568
2990
|
return /* @__PURE__ */ jsx("img", {
|
|
2569
|
-
src: media.
|
|
2991
|
+
src: media.url,
|
|
2570
2992
|
alt: media.name,
|
|
2571
2993
|
className: cn("h-auto w-full aspect-square border border-border rounded-md object-cover", className)
|
|
2572
2994
|
});
|
|
2573
2995
|
};
|
|
2996
|
+
function isMediaPicture(type) {
|
|
2997
|
+
const t = type.toLowerCase();
|
|
2998
|
+
return t.startsWith("image/") || t === "picture";
|
|
2999
|
+
}
|
|
3000
|
+
function MediaPreviewOverlay({ media, onClose }) {
|
|
3001
|
+
useEffect(() => {
|
|
3002
|
+
const handleKey = (e) => {
|
|
3003
|
+
if (e.key === "Escape") onClose();
|
|
3004
|
+
};
|
|
3005
|
+
document.addEventListener("keydown", handleKey);
|
|
3006
|
+
return () => document.removeEventListener("keydown", handleKey);
|
|
3007
|
+
}, [onClose]);
|
|
3008
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3009
|
+
className: "absolute inset-0 z-10 flex items-center justify-center bg-black/80 backdrop-blur-sm p-4",
|
|
3010
|
+
onClick: onClose,
|
|
3011
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
3012
|
+
className: "relative flex max-h-full max-w-5xl flex-col overflow-hidden rounded-xl shadow-2xl",
|
|
3013
|
+
onClick: (e) => e.stopPropagation(),
|
|
3014
|
+
children: [
|
|
3015
|
+
/* @__PURE__ */ jsx("div", {
|
|
3016
|
+
className: "absolute right-2 top-2 z-10 flex gap-1.5",
|
|
3017
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
3018
|
+
type: "button",
|
|
3019
|
+
size: "icon",
|
|
3020
|
+
variant: "outline",
|
|
3021
|
+
onClick: onClose,
|
|
3022
|
+
children: /* @__PURE__ */ jsx(XIcon, { className: "size-4" })
|
|
3023
|
+
})
|
|
3024
|
+
}),
|
|
3025
|
+
/* @__PURE__ */ jsx("div", {
|
|
3026
|
+
className: "overflow-hidden",
|
|
3027
|
+
children: /* @__PURE__ */ jsx("img", {
|
|
3028
|
+
src: media.url,
|
|
3029
|
+
alt: media.name,
|
|
3030
|
+
className: "h-auto w-full object-contain"
|
|
3031
|
+
})
|
|
3032
|
+
}),
|
|
3033
|
+
/* @__PURE__ */ jsx("div", {
|
|
3034
|
+
className: "flex items-center justify-between gap-4 bg-white px-4 py-3",
|
|
3035
|
+
children: /* @__PURE__ */ jsxs("div", {
|
|
3036
|
+
className: "min-w-0",
|
|
3037
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
3038
|
+
className: "text-sm font-medium text-gray-900 truncate",
|
|
3039
|
+
children: media.name
|
|
3040
|
+
}), /* @__PURE__ */ jsx("p", {
|
|
3041
|
+
className: "text-xs text-gray-500",
|
|
3042
|
+
children: media.type
|
|
3043
|
+
})]
|
|
3044
|
+
})
|
|
3045
|
+
})
|
|
3046
|
+
]
|
|
3047
|
+
})
|
|
3048
|
+
});
|
|
3049
|
+
}
|
|
2574
3050
|
const DEFAULT_VALUE = {
|
|
2575
3051
|
type: "media",
|
|
2576
3052
|
media: null
|
|
2577
3053
|
};
|
|
2578
3054
|
const PAGE_SIZE = 10;
|
|
2579
|
-
const MediaLibraryModal = ({ value, onChange, mediaType, open, onOpenChange, acceptedTypes, maxSize }) => {
|
|
3055
|
+
const MediaLibraryModal = ({ value, onChange, mediaType, open, onOpenChange, acceptedTypes, maxSize, unsplashSearchEndpoint, unsplashFeaturedQuery, unsplashDownloadEndpoint, unsplashUploadEndpoint, onUnsplashDownloadPhoto }) => {
|
|
3056
|
+
const [source, setSource] = useState("media-library");
|
|
3057
|
+
const [previewMedia, setPreviewMedia] = useState(null);
|
|
2580
3058
|
const [medias, setMedias] = useState([]);
|
|
2581
3059
|
const [loading, setLoading] = useState(false);
|
|
2582
3060
|
const [totalItems, setTotalItems] = useState(0);
|
|
@@ -2607,25 +3085,15 @@ const MediaLibraryModal = ({ value, onChange, mediaType, open, onOpenChange, acc
|
|
|
2607
3085
|
}
|
|
2608
3086
|
}, [mediaType]);
|
|
2609
3087
|
useEffect(() => {
|
|
2610
|
-
if (open) loadMedias(pagination.pageIndex, pagination.pageSize, searchQuery, sorting);
|
|
3088
|
+
if (open && source === "media-library") loadMedias(pagination.pageIndex, pagination.pageSize, searchQuery, sorting);
|
|
2611
3089
|
}, [
|
|
2612
3090
|
open,
|
|
3091
|
+
source,
|
|
2613
3092
|
pagination,
|
|
2614
3093
|
sorting,
|
|
2615
3094
|
searchQuery,
|
|
2616
3095
|
loadMedias
|
|
2617
3096
|
]);
|
|
2618
|
-
const handleSearch = useCallback((query) => {
|
|
2619
|
-
setSearchQuery(query);
|
|
2620
|
-
setPagination((prev) => ({
|
|
2621
|
-
...prev,
|
|
2622
|
-
pageIndex: 0
|
|
2623
|
-
}));
|
|
2624
|
-
}, []);
|
|
2625
|
-
const handleRowClick = useCallback((media) => {
|
|
2626
|
-
onChange(media);
|
|
2627
|
-
onOpenChange(false);
|
|
2628
|
-
}, [onChange, onOpenChange]);
|
|
2629
3097
|
const handleUploadSuccess = useCallback(async (_media) => {
|
|
2630
3098
|
await loadMedias(0, pagination.pageSize, searchQuery, sorting);
|
|
2631
3099
|
setPagination((prev) => ({
|
|
@@ -2638,42 +3106,204 @@ const MediaLibraryModal = ({ value, onChange, mediaType, open, onOpenChange, acc
|
|
|
2638
3106
|
searchQuery,
|
|
2639
3107
|
sorting
|
|
2640
3108
|
]);
|
|
3109
|
+
const handleRowClick = useCallback((media) => {
|
|
3110
|
+
onChange(media);
|
|
3111
|
+
onOpenChange(false);
|
|
3112
|
+
}, [onChange, onOpenChange]);
|
|
3113
|
+
const { query: unsplashQuery, page: unsplashPage, portrait, landscape, isFeatured: unsplashIsFeatured, items: unsplashItems, hasMore, loading: unsplashLoading, error: unsplashError, onSearchChange: onUnsplashSearchChange, onPageChange: onUnsplashPageChange, onPortraitChange, onLandscapeChange, refresh: refreshUnsplash } = useUnsplashSearch({
|
|
3114
|
+
endpoint: unsplashSearchEndpoint,
|
|
3115
|
+
featuredQuery: unsplashFeaturedQuery,
|
|
3116
|
+
enabled: source === "unsplash"
|
|
3117
|
+
});
|
|
3118
|
+
const { selectedPhotoId, saveError, onSelectPhoto, onSavePhoto } = useUnsplashModalController({
|
|
3119
|
+
downloadEndpoint: unsplashDownloadEndpoint,
|
|
3120
|
+
uploadEndpoint: unsplashUploadEndpoint,
|
|
3121
|
+
onDownloadPhoto: onUnsplashDownloadPhoto,
|
|
3122
|
+
onPhotoRegistered: useCallback(() => {
|
|
3123
|
+
setSource("media-library");
|
|
3124
|
+
loadMedias(0, pagination.pageSize, searchQuery, sorting);
|
|
3125
|
+
setPagination((prev) => ({
|
|
3126
|
+
...prev,
|
|
3127
|
+
pageIndex: 0
|
|
3128
|
+
}));
|
|
3129
|
+
}, [
|
|
3130
|
+
loadMedias,
|
|
3131
|
+
pagination.pageSize,
|
|
3132
|
+
searchQuery,
|
|
3133
|
+
sorting
|
|
3134
|
+
]),
|
|
3135
|
+
items: unsplashItems,
|
|
3136
|
+
refresh: refreshUnsplash
|
|
3137
|
+
});
|
|
3138
|
+
const activeSearchQuery = source === "unsplash" ? unsplashQuery : searchQuery;
|
|
3139
|
+
const handleSearch = useCallback((query) => {
|
|
3140
|
+
if (source === "unsplash") onUnsplashSearchChange(query);
|
|
3141
|
+
else {
|
|
3142
|
+
setSearchQuery(query);
|
|
3143
|
+
setPagination((prev) => ({
|
|
3144
|
+
...prev,
|
|
3145
|
+
pageIndex: 0
|
|
3146
|
+
}));
|
|
3147
|
+
}
|
|
3148
|
+
}, [source, onUnsplashSearchChange]);
|
|
3149
|
+
const handleSourceChange = useCallback((newSource) => {
|
|
3150
|
+
setSource(newSource);
|
|
3151
|
+
if (newSource === "media-library") setPagination((prev) => ({
|
|
3152
|
+
...prev,
|
|
3153
|
+
pageIndex: 0
|
|
3154
|
+
}));
|
|
3155
|
+
}, []);
|
|
3156
|
+
const columns = useMemo(() => [
|
|
3157
|
+
{
|
|
3158
|
+
id: "thumbnail",
|
|
3159
|
+
header: "Preview",
|
|
3160
|
+
size: 80,
|
|
3161
|
+
enableSorting: false,
|
|
3162
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(MediaPreview, {
|
|
3163
|
+
media: row.original,
|
|
3164
|
+
className: "size-12"
|
|
3165
|
+
})
|
|
3166
|
+
},
|
|
3167
|
+
{
|
|
3168
|
+
accessorKey: "name",
|
|
3169
|
+
header: "Name",
|
|
3170
|
+
cell: ({ row }) => /* @__PURE__ */ jsx("div", {
|
|
3171
|
+
className: "font-medium",
|
|
3172
|
+
children: row.getValue("name")
|
|
3173
|
+
})
|
|
3174
|
+
},
|
|
3175
|
+
{
|
|
3176
|
+
accessorKey: "type",
|
|
3177
|
+
header: "Type",
|
|
3178
|
+
size: 140,
|
|
3179
|
+
cell: ({ row }) => /* @__PURE__ */ jsx(Badge, {
|
|
3180
|
+
variant: "outline",
|
|
3181
|
+
children: row.getValue("type")
|
|
3182
|
+
})
|
|
3183
|
+
},
|
|
3184
|
+
{
|
|
3185
|
+
id: "actions",
|
|
3186
|
+
header: "",
|
|
3187
|
+
size: 60,
|
|
3188
|
+
enableSorting: false,
|
|
3189
|
+
cell: ({ row }) => {
|
|
3190
|
+
const media = row.original;
|
|
3191
|
+
if (!isMediaPicture(media.type)) return null;
|
|
3192
|
+
return /* @__PURE__ */ jsx("div", {
|
|
3193
|
+
className: "flex justify-end",
|
|
3194
|
+
children: /* @__PURE__ */ jsxs(Tooltip, { children: [/* @__PURE__ */ jsx(TooltipTrigger, {
|
|
3195
|
+
delay: 50,
|
|
3196
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
3197
|
+
type: "button",
|
|
3198
|
+
variant: "outline",
|
|
3199
|
+
size: "icon-lg",
|
|
3200
|
+
onClick: (e) => {
|
|
3201
|
+
e.stopPropagation();
|
|
3202
|
+
setPreviewMedia(media);
|
|
3203
|
+
},
|
|
3204
|
+
"aria-label": "Preview image",
|
|
3205
|
+
children: /* @__PURE__ */ jsx(ZoomInIcon, { className: "size-4" })
|
|
3206
|
+
})
|
|
3207
|
+
}), /* @__PURE__ */ jsx(TooltipPopup, {
|
|
3208
|
+
className: "text-xs",
|
|
3209
|
+
children: "Preview"
|
|
3210
|
+
})] })
|
|
3211
|
+
});
|
|
3212
|
+
}
|
|
3213
|
+
}
|
|
3214
|
+
], [setPreviewMedia]);
|
|
3215
|
+
const filterContent = /* @__PURE__ */ jsxs(Fragment, { children: [source === "unsplash" && /* @__PURE__ */ jsxs(Popover, { children: [/* @__PURE__ */ jsx(PopoverTrigger, { render: /* @__PURE__ */ jsx(Button, {
|
|
3216
|
+
size: "icon",
|
|
3217
|
+
variant: portrait || landscape ? "secondary" : "outline",
|
|
3218
|
+
"aria-label": "Unsplash filters",
|
|
3219
|
+
children: /* @__PURE__ */ jsx(SlidersHorizontalIcon, { className: "size-4" })
|
|
3220
|
+
}) }), /* @__PURE__ */ jsxs(PopoverPopup, {
|
|
3221
|
+
align: "end",
|
|
3222
|
+
className: "min-w-44",
|
|
3223
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
3224
|
+
className: "mb-3 text-sm font-medium",
|
|
3225
|
+
children: "Filters"
|
|
3226
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
3227
|
+
className: "flex flex-col gap-2",
|
|
3228
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
3229
|
+
className: "flex items-center gap-2",
|
|
3230
|
+
children: [/* @__PURE__ */ jsx(Checkbox, {
|
|
3231
|
+
id: "unsplash-portrait",
|
|
3232
|
+
checked: portrait,
|
|
3233
|
+
onCheckedChange: onPortraitChange,
|
|
3234
|
+
layout: "inline"
|
|
3235
|
+
}), /* @__PURE__ */ jsx("label", {
|
|
3236
|
+
htmlFor: "unsplash-portrait",
|
|
3237
|
+
className: "cursor-pointer text-sm font-medium leading-none",
|
|
3238
|
+
children: "Portrait"
|
|
3239
|
+
})]
|
|
3240
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
3241
|
+
className: "flex items-center gap-2",
|
|
3242
|
+
children: [/* @__PURE__ */ jsx(Checkbox, {
|
|
3243
|
+
id: "unsplash-landscape",
|
|
3244
|
+
checked: landscape,
|
|
3245
|
+
onCheckedChange: onLandscapeChange,
|
|
3246
|
+
layout: "inline"
|
|
3247
|
+
}), /* @__PURE__ */ jsx("label", {
|
|
3248
|
+
htmlFor: "unsplash-landscape",
|
|
3249
|
+
className: "cursor-pointer text-sm font-medium leading-none",
|
|
3250
|
+
children: "Landscape"
|
|
3251
|
+
})]
|
|
3252
|
+
})]
|
|
3253
|
+
})]
|
|
3254
|
+
})] }), /* @__PURE__ */ jsxs(Select, {
|
|
3255
|
+
value: source,
|
|
3256
|
+
onValueChange: (val) => handleSourceChange(val),
|
|
3257
|
+
children: [/* @__PURE__ */ jsx(SelectTrigger, { children: /* @__PURE__ */ jsx(SelectValue, { children: source === "media-library" ? "Media Library" : "Unsplash" }) }), /* @__PURE__ */ jsxs(SelectPopup, { children: [/* @__PURE__ */ jsx(SelectItem, {
|
|
3258
|
+
value: "media-library",
|
|
3259
|
+
children: "Media Library"
|
|
3260
|
+
}), /* @__PURE__ */ jsx(SelectItem, {
|
|
3261
|
+
value: "unsplash",
|
|
3262
|
+
children: "Unsplash"
|
|
3263
|
+
})] })]
|
|
3264
|
+
})] });
|
|
3265
|
+
const unsplashContent = source === "unsplash" ? /* @__PURE__ */ jsxs("div", {
|
|
3266
|
+
className: "flex flex-col gap-4",
|
|
3267
|
+
children: [
|
|
3268
|
+
/* @__PURE__ */ jsx(UnsplashStatus, {
|
|
3269
|
+
error: unsplashError,
|
|
3270
|
+
saveError
|
|
3271
|
+
}),
|
|
3272
|
+
unsplashItems.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(UnsplashPhotoGrid, {
|
|
3273
|
+
items: unsplashItems,
|
|
3274
|
+
selectedPhotoId,
|
|
3275
|
+
onSelectPhoto,
|
|
3276
|
+
onDownloadPhoto: onSavePhoto
|
|
3277
|
+
}), hasMore && /* @__PURE__ */ jsx("div", {
|
|
3278
|
+
className: "flex justify-center",
|
|
3279
|
+
children: /* @__PURE__ */ jsx(Button, {
|
|
3280
|
+
type: "button",
|
|
3281
|
+
variant: "outline",
|
|
3282
|
+
disabled: unsplashLoading,
|
|
3283
|
+
onClick: () => onUnsplashPageChange(unsplashPage + 1),
|
|
3284
|
+
children: "Load more"
|
|
3285
|
+
})
|
|
3286
|
+
})] }),
|
|
3287
|
+
/* @__PURE__ */ jsx(UnsplashStatus, {
|
|
3288
|
+
loading: unsplashLoading,
|
|
3289
|
+
noResults: !unsplashLoading && unsplashItems.length === 0 && !unsplashIsFeatured
|
|
3290
|
+
})
|
|
3291
|
+
]
|
|
3292
|
+
}) : void 0;
|
|
3293
|
+
const footer = source === "media-library" ? /* @__PURE__ */ jsx(MediaUploadZone, {
|
|
3294
|
+
onUploadSuccess: handleUploadSuccess,
|
|
3295
|
+
acceptedTypes,
|
|
3296
|
+
maxSize
|
|
3297
|
+
}) : void 0;
|
|
2641
3298
|
return /* @__PURE__ */ jsx(PickerModal, {
|
|
2642
3299
|
title: "Select Media",
|
|
2643
|
-
searchQuery,
|
|
3300
|
+
searchQuery: activeSearchQuery,
|
|
2644
3301
|
onSearch: handleSearch,
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
enableSorting: false,
|
|
2651
|
-
cell: ({ row }) => /* @__PURE__ */ jsx(MediaPreview, {
|
|
2652
|
-
media: row.original,
|
|
2653
|
-
className: "size-12"
|
|
2654
|
-
})
|
|
2655
|
-
},
|
|
2656
|
-
{
|
|
2657
|
-
accessorKey: "name",
|
|
2658
|
-
header: "Name",
|
|
2659
|
-
cell: ({ row }) => /* @__PURE__ */ jsx("div", {
|
|
2660
|
-
className: "font-medium",
|
|
2661
|
-
children: row.getValue("name")
|
|
2662
|
-
})
|
|
2663
|
-
},
|
|
2664
|
-
{
|
|
2665
|
-
accessorKey: "type",
|
|
2666
|
-
header: "Type",
|
|
2667
|
-
size: 140,
|
|
2668
|
-
cell: ({ row }) => /* @__PURE__ */ jsx(Badge, {
|
|
2669
|
-
variant: "outline",
|
|
2670
|
-
children: row.getValue("type")
|
|
2671
|
-
})
|
|
2672
|
-
}
|
|
2673
|
-
], []),
|
|
2674
|
-
data: medias,
|
|
2675
|
-
loading,
|
|
2676
|
-
totalItems,
|
|
3302
|
+
searchPlaceholder: source === "unsplash" ? "Search Unsplash photos…" : "Search media…",
|
|
3303
|
+
columns,
|
|
3304
|
+
data: source === "media-library" ? medias : [],
|
|
3305
|
+
loading: source === "media-library" ? loading : false,
|
|
3306
|
+
totalItems: source === "media-library" ? totalItems : 0,
|
|
2677
3307
|
selectedId: value?.id,
|
|
2678
3308
|
onRowClick: handleRowClick,
|
|
2679
3309
|
pagination,
|
|
@@ -2682,16 +3312,19 @@ const MediaLibraryModal = ({ value, onChange, mediaType, open, onOpenChange, acc
|
|
|
2682
3312
|
onSortingChange: setSorting,
|
|
2683
3313
|
emptyIcon: /* @__PURE__ */ jsx(FileIcon, { className: "mb-2 size-12 opacity-20" }),
|
|
2684
3314
|
emptyMessage: "No media found",
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
3315
|
+
filterContent,
|
|
3316
|
+
tableContent: unsplashContent,
|
|
3317
|
+
footer,
|
|
3318
|
+
overlay: previewMedia ? /* @__PURE__ */ jsx(MediaPreviewOverlay, {
|
|
3319
|
+
media: previewMedia,
|
|
3320
|
+
onClose: () => setPreviewMedia(null)
|
|
3321
|
+
}) : void 0
|
|
2690
3322
|
});
|
|
2691
3323
|
};
|
|
2692
|
-
const MediaPicker = ({ value, onChange, mediaType, acceptedTypes = "image/*,video/*,application/pdf", maxSize = 10 }) => {
|
|
3324
|
+
const MediaPicker = ({ value, onChange, mediaType, acceptedTypes = "image/*,video/*,application/pdf", maxSize = 10, unsplashSearchEndpoint, unsplashFeaturedQuery, unsplashDownloadEndpoint, unsplashUploadEndpoint, onUnsplashDownloadPhoto }) => {
|
|
2693
3325
|
const [open, setOpen] = useState(false);
|
|
2694
3326
|
const currentValue = value || DEFAULT_VALUE;
|
|
3327
|
+
const { url: previewUrl } = useMediaUrl(currentValue);
|
|
2695
3328
|
const displayValue = currentValue.type === "media" && currentValue.media ? currentValue.media.name : currentValue.url || "";
|
|
2696
3329
|
const hasValue = Boolean(currentValue.type === "media" && currentValue.media || currentValue.type === "url" && currentValue.url);
|
|
2697
3330
|
const handleInputChange = (e) => {
|
|
@@ -2705,8 +3338,7 @@ const MediaPicker = ({ value, onChange, mediaType, acceptedTypes = "image/*,vide
|
|
|
2705
3338
|
type: "media",
|
|
2706
3339
|
media: {
|
|
2707
3340
|
id: media.id,
|
|
2708
|
-
name: media.name
|
|
2709
|
-
thumbnail: media.thumbnail
|
|
3341
|
+
name: media.name
|
|
2710
3342
|
}
|
|
2711
3343
|
});
|
|
2712
3344
|
};
|
|
@@ -2721,12 +3353,12 @@ const MediaPicker = ({ value, onChange, mediaType, acceptedTypes = "image/*,vide
|
|
|
2721
3353
|
children: [/* @__PURE__ */ jsx("div", {
|
|
2722
3354
|
className: "flex items-center gap-2",
|
|
2723
3355
|
children: /* @__PURE__ */ jsxs(InputGroup, { children: [
|
|
2724
|
-
|
|
3356
|
+
previewUrl && /* @__PURE__ */ jsx(InputGroupAddon, {
|
|
2725
3357
|
align: "inline-start",
|
|
2726
3358
|
className: "pl-1.5",
|
|
2727
3359
|
children: /* @__PURE__ */ jsx("img", {
|
|
2728
|
-
src:
|
|
2729
|
-
alt: currentValue.media
|
|
3360
|
+
src: previewUrl,
|
|
3361
|
+
alt: currentValue.media?.name ?? "",
|
|
2730
3362
|
className: cn("max-h-12 my-1.5 aspect-square border border-border rounded-md object-cover")
|
|
2731
3363
|
})
|
|
2732
3364
|
}),
|
|
@@ -2757,20 +3389,17 @@ const MediaPicker = ({ value, onChange, mediaType, acceptedTypes = "image/*,vide
|
|
|
2757
3389
|
open,
|
|
2758
3390
|
onOpenChange: setOpen,
|
|
2759
3391
|
acceptedTypes,
|
|
2760
|
-
maxSize
|
|
3392
|
+
maxSize,
|
|
3393
|
+
unsplashSearchEndpoint,
|
|
3394
|
+
unsplashFeaturedQuery,
|
|
3395
|
+
unsplashDownloadEndpoint,
|
|
3396
|
+
unsplashUploadEndpoint,
|
|
3397
|
+
onUnsplashDownloadPhoto
|
|
2761
3398
|
})]
|
|
2762
3399
|
})
|
|
2763
3400
|
});
|
|
2764
3401
|
};
|
|
2765
3402
|
/**
|
|
2766
|
-
* Retourne l'URL directe si le type est "url".
|
|
2767
|
-
* Pour les références média (`type: "media"`), utiliser `useMediaUrl` à la place.
|
|
2768
|
-
*/
|
|
2769
|
-
const getMediaUrl = (value) => {
|
|
2770
|
-
if (!value) return void 0;
|
|
2771
|
-
if (value.type === "url") return value.url;
|
|
2772
|
-
};
|
|
2773
|
-
/**
|
|
2774
3403
|
* Hook React qui résout dynamiquement l'URL courante d'un `MediaPickerValue`.
|
|
2775
3404
|
*
|
|
2776
3405
|
* Pour les références média (`type: "media"`), l'URL est récupérée depuis
|
|
@@ -2815,43 +3444,49 @@ const useMediaUrl = (value) => {
|
|
|
2815
3444
|
|
|
2816
3445
|
//#endregion
|
|
2817
3446
|
//#region src/components/ui/menu.tsx
|
|
2818
|
-
const MenuCreateHandle =
|
|
2819
|
-
const Menu =
|
|
2820
|
-
const MenuPortal =
|
|
2821
|
-
function MenuTrigger(props) {
|
|
2822
|
-
return /* @__PURE__ */ jsx(
|
|
3447
|
+
const MenuCreateHandle = MenuPrimitive.createHandle;
|
|
3448
|
+
const Menu = MenuPrimitive.Root;
|
|
3449
|
+
const MenuPortal = MenuPrimitive.Portal;
|
|
3450
|
+
function MenuTrigger({ className, children, ...props }) {
|
|
3451
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.Trigger, {
|
|
3452
|
+
className,
|
|
2823
3453
|
"data-slot": "menu-trigger",
|
|
2824
|
-
...props
|
|
3454
|
+
...props,
|
|
3455
|
+
children
|
|
2825
3456
|
});
|
|
2826
3457
|
}
|
|
2827
|
-
function MenuPopup({ children, className, sideOffset = 4, align = "center", alignOffset, side = "bottom", ...props }) {
|
|
2828
|
-
return /* @__PURE__ */ jsx(
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
3458
|
+
function MenuPopup({ children, className, sideOffset = 4, align = "center", alignOffset, side = "bottom", anchor, portalProps, ...props }) {
|
|
3459
|
+
return /* @__PURE__ */ jsx(MenuPortal, {
|
|
3460
|
+
...portalProps,
|
|
3461
|
+
children: /* @__PURE__ */ jsx(MenuPrimitive.Positioner, {
|
|
3462
|
+
align,
|
|
3463
|
+
alignOffset,
|
|
3464
|
+
anchor,
|
|
3465
|
+
className: "z-50",
|
|
3466
|
+
"data-slot": "menu-positioner",
|
|
3467
|
+
side,
|
|
3468
|
+
sideOffset,
|
|
3469
|
+
children: /* @__PURE__ */ jsx(MenuPrimitive.Popup, {
|
|
3470
|
+
className: cn("relative flex not-[class*='w-']:min-w-32 origin-(--transform-origin) rounded-lg border bg-popover not-dark:bg-clip-padding shadow-lg/5 outline-none before:pointer-events-none before:absolute before:inset-0 before:rounded-[calc(var(--radius-lg)-1px)] before:shadow-[0_1px_--theme(--color-black/4%)] focus:outline-none dark:before:shadow-[0_-1px_--theme(--color-white/6%)]", className),
|
|
3471
|
+
"data-slot": "menu-popup",
|
|
3472
|
+
...props,
|
|
3473
|
+
children: /* @__PURE__ */ jsx("div", {
|
|
3474
|
+
className: "max-h-(--available-height) w-full overflow-y-auto p-1",
|
|
3475
|
+
children
|
|
3476
|
+
})
|
|
2842
3477
|
})
|
|
2843
3478
|
})
|
|
2844
|
-
})
|
|
3479
|
+
});
|
|
2845
3480
|
}
|
|
2846
3481
|
function MenuGroup(props) {
|
|
2847
|
-
return /* @__PURE__ */ jsx(
|
|
3482
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.Group, {
|
|
2848
3483
|
"data-slot": "menu-group",
|
|
2849
3484
|
...props
|
|
2850
3485
|
});
|
|
2851
3486
|
}
|
|
2852
3487
|
function MenuItem({ className, inset, variant = "default", ...props }) {
|
|
2853
|
-
return /* @__PURE__ */ jsx(
|
|
2854
|
-
className: cn("
|
|
3488
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.Item, {
|
|
3489
|
+
className: cn("flex min-h-8 cursor-default select-none items-center gap-2 rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-inset:ps-8 data-[variant=destructive]:text-destructive-foreground data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not([class*='opacity-'])]:opacity-80 [&>svg:not([class*='size-'])]:size-4.5 sm:[&>svg:not([class*='size-'])]:size-4 [&>svg]:pointer-events-none [&>svg]:-mx-0.5 [&>svg]:shrink-0", className),
|
|
2855
3490
|
"data-inset": inset,
|
|
2856
3491
|
"data-slot": "menu-item",
|
|
2857
3492
|
"data-variant": variant,
|
|
@@ -2859,21 +3494,22 @@ function MenuItem({ className, inset, variant = "default", ...props }) {
|
|
|
2859
3494
|
});
|
|
2860
3495
|
}
|
|
2861
3496
|
function MenuCheckboxItem({ className, children, checked, variant = "default", ...props }) {
|
|
2862
|
-
return /* @__PURE__ */ jsx(
|
|
3497
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.CheckboxItem, {
|
|
2863
3498
|
checked,
|
|
2864
|
-
className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default items-center gap-2 rounded-sm py-1 ps-2 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", variant === "switch" ? "grid-cols-[1fr_auto] gap-4 pe-1.5" : "grid-cols-[
|
|
3499
|
+
className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default items-center gap-2 rounded-sm py-1 ps-2 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", variant === "switch" ? "grid-cols-[1fr_auto] gap-4 pe-1.5" : "grid-cols-[.75rem_1fr] pe-4", className),
|
|
2865
3500
|
"data-slot": "menu-checkbox-item",
|
|
2866
3501
|
...props,
|
|
2867
3502
|
children: variant === "switch" ? /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx("span", {
|
|
2868
3503
|
className: "col-start-1",
|
|
2869
3504
|
children
|
|
2870
|
-
}), /* @__PURE__ */ jsx(
|
|
2871
|
-
className: "inset-shadow-[0_1px_--theme(--color-black/
|
|
3505
|
+
}), /* @__PURE__ */ jsx(MenuPrimitive.CheckboxItemIndicator, {
|
|
3506
|
+
className: "inset-shadow-[0_1px_--theme(--color-black/4%)] inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(4)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(3)]",
|
|
2872
3507
|
keepMounted: true,
|
|
2873
3508
|
children: /* @__PURE__ */ jsx("span", { className: "pointer-events-none block aspect-square h-full in-[[data-slot=menu-checkbox-item][data-checked]]:origin-[var(--thumb-size)_50%] origin-left in-[[data-slot=menu-checkbox-item][data-checked]]:translate-x-[calc(var(--thumb-size)-4px)] in-[[data-slot=menu-checkbox-item]:active]:not-data-disabled:scale-x-110 in-[[data-slot=menu-checkbox-item]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.10)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s]" })
|
|
2874
|
-
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(
|
|
2875
|
-
className: "col-start-1",
|
|
3509
|
+
})] }) : /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(MenuPrimitive.CheckboxItemIndicator, {
|
|
3510
|
+
className: "col-start-1 -ms-0.5",
|
|
2876
3511
|
children: /* @__PURE__ */ jsx("svg", {
|
|
3512
|
+
"aria-hidden": "true",
|
|
2877
3513
|
fill: "none",
|
|
2878
3514
|
height: "24",
|
|
2879
3515
|
stroke: "currentColor",
|
|
@@ -2892,19 +3528,20 @@ function MenuCheckboxItem({ className, children, checked, variant = "default", .
|
|
|
2892
3528
|
});
|
|
2893
3529
|
}
|
|
2894
3530
|
function MenuRadioGroup(props) {
|
|
2895
|
-
return /* @__PURE__ */ jsx(
|
|
3531
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.RadioGroup, {
|
|
2896
3532
|
"data-slot": "menu-radio-group",
|
|
2897
3533
|
...props
|
|
2898
3534
|
});
|
|
2899
3535
|
}
|
|
2900
3536
|
function MenuRadioItem({ className, children, ...props }) {
|
|
2901
|
-
return /* @__PURE__ */ jsxs(
|
|
2902
|
-
className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[
|
|
3537
|
+
return /* @__PURE__ */ jsxs(MenuPrimitive.RadioItem, {
|
|
3538
|
+
className: cn("grid min-h-8 in-data-[side=none]:min-w-[calc(var(--anchor-width)+1.25rem)] cursor-default grid-cols-[.75rem_1fr] items-center gap-2 rounded-sm py-1 ps-2 pe-4 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-highlighted:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none [&_svg]:shrink-0", className),
|
|
2903
3539
|
"data-slot": "menu-radio-item",
|
|
2904
3540
|
...props,
|
|
2905
|
-
children: [/* @__PURE__ */ jsx(
|
|
2906
|
-
className: "col-start-1",
|
|
3541
|
+
children: [/* @__PURE__ */ jsx(MenuPrimitive.RadioItemIndicator, {
|
|
3542
|
+
className: "col-start-1 -ms-0.5",
|
|
2907
3543
|
children: /* @__PURE__ */ jsx("svg", {
|
|
3544
|
+
"aria-hidden": "true",
|
|
2908
3545
|
fill: "none",
|
|
2909
3546
|
height: "24",
|
|
2910
3547
|
stroke: "currentColor",
|
|
@@ -2923,7 +3560,7 @@ function MenuRadioItem({ className, children, ...props }) {
|
|
|
2923
3560
|
});
|
|
2924
3561
|
}
|
|
2925
3562
|
function MenuGroupLabel({ className, inset, ...props }) {
|
|
2926
|
-
return /* @__PURE__ */ jsx(
|
|
3563
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.GroupLabel, {
|
|
2927
3564
|
className: cn("px-2 py-1.5 font-medium text-muted-foreground text-xs data-inset:ps-9 sm:data-inset:ps-8", className),
|
|
2928
3565
|
"data-inset": inset,
|
|
2929
3566
|
"data-slot": "menu-label",
|
|
@@ -2931,32 +3568,25 @@ function MenuGroupLabel({ className, inset, ...props }) {
|
|
|
2931
3568
|
});
|
|
2932
3569
|
}
|
|
2933
3570
|
function MenuSeparator({ className, ...props }) {
|
|
2934
|
-
return /* @__PURE__ */ jsx(
|
|
3571
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.Separator, {
|
|
2935
3572
|
className: cn("mx-2 my-1 h-px bg-border", className),
|
|
2936
3573
|
"data-slot": "menu-separator",
|
|
2937
3574
|
...props
|
|
2938
3575
|
});
|
|
2939
3576
|
}
|
|
2940
|
-
function MenuShortcut({ className, ...props }) {
|
|
2941
|
-
return /* @__PURE__ */ jsx("kbd", {
|
|
2942
|
-
className: cn("ms-auto font-medium font-sans text-muted-foreground/72 text-xs tracking-widest", className),
|
|
2943
|
-
"data-slot": "menu-shortcut",
|
|
2944
|
-
...props
|
|
2945
|
-
});
|
|
2946
|
-
}
|
|
2947
3577
|
function MenuSub(props) {
|
|
2948
|
-
return /* @__PURE__ */ jsx(
|
|
3578
|
+
return /* @__PURE__ */ jsx(MenuPrimitive.SubmenuRoot, {
|
|
2949
3579
|
"data-slot": "menu-sub",
|
|
2950
3580
|
...props
|
|
2951
3581
|
});
|
|
2952
3582
|
}
|
|
2953
3583
|
function MenuSubTrigger({ className, inset, children, ...props }) {
|
|
2954
|
-
return /* @__PURE__ */ jsxs(
|
|
2955
|
-
className: cn("flex min-h-8 items-center gap-2 rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-popup-open:bg-accent data-inset:ps-8 data-highlighted:text-accent-foreground data-popup-open:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", className),
|
|
3584
|
+
return /* @__PURE__ */ jsxs(MenuPrimitive.SubmenuTrigger, {
|
|
3585
|
+
className: cn("flex min-h-8 items-center gap-2 rounded-sm px-2 py-1 text-base text-foreground outline-none data-disabled:pointer-events-none data-highlighted:bg-accent data-popup-open:bg-accent data-inset:ps-8 data-highlighted:text-accent-foreground data-popup-open:text-accent-foreground data-disabled:opacity-64 sm:min-h-7 sm:text-sm [&>svg:not(:last-child)]:-mx-0.5 [&_svg:not([class*='size-'])]:size-4.5 sm:[&_svg:not([class*='size-'])]:size-4 [&_svg]:pointer-events-none", className),
|
|
2956
3586
|
"data-inset": inset,
|
|
2957
3587
|
"data-slot": "menu-sub-trigger",
|
|
2958
3588
|
...props,
|
|
2959
|
-
children: [children, /* @__PURE__ */ jsx(ChevronRightIcon, { className: "-me-0.5
|
|
3589
|
+
children: [children, /* @__PURE__ */ jsx(ChevronRightIcon, { className: "ms-auto -me-0.5 opacity-80" })]
|
|
2960
3590
|
});
|
|
2961
3591
|
}
|
|
2962
3592
|
function MenuSubPopup({ className, sideOffset = 0, alignOffset, align = "start", ...props }) {
|
|
@@ -2982,20 +3612,6 @@ function Separator({ className, orientation = "horizontal", ...props }) {
|
|
|
2982
3612
|
});
|
|
2983
3613
|
}
|
|
2984
3614
|
|
|
2985
|
-
//#endregion
|
|
2986
|
-
//#region src/components/ui/switch.tsx
|
|
2987
|
-
function Switch({ className, ...props }) {
|
|
2988
|
-
return /* @__PURE__ */ jsx(Switch$1.Root, {
|
|
2989
|
-
className: cn("inline-flex h-[calc(var(--thumb-size)+2px)] w-[calc(var(--thumb-size)*2-2px)] shrink-0 items-center rounded-full p-px outline-none transition-[background-color,box-shadow] duration-200 [--thumb-size:--spacing(5)] focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1 focus-visible:ring-offset-background data-checked:bg-primary data-unchecked:bg-input data-disabled:opacity-64 sm:[--thumb-size:--spacing(4)]", className),
|
|
2990
|
-
"data-slot": "switch",
|
|
2991
|
-
...props,
|
|
2992
|
-
children: /* @__PURE__ */ jsx(Switch$1.Thumb, {
|
|
2993
|
-
className: cn("pointer-events-none block aspect-square h-full origin-left in-[[role=switch]:active,[data-slot=label]:active,[data-slot=field-label]:active]:not-data-disabled:scale-x-110 in-[[role=switch]:active,[data-slot=label]:active,[data-slot=field-label]:active]:rounded-[var(--thumb-size)/calc(var(--thumb-size)*1.1)] rounded-(--thumb-size) bg-background shadow-sm/5 will-change-transform [transition:translate_.15s,border-radius_.15s,scale_.1s_.1s,transform-origin_.15s] data-checked:origin-[var(--thumb-size)_50%] data-checked:translate-x-[calc(var(--thumb-size)-4px)]"),
|
|
2994
|
-
"data-slot": "switch-thumb"
|
|
2995
|
-
})
|
|
2996
|
-
});
|
|
2997
|
-
}
|
|
2998
|
-
|
|
2999
3615
|
//#endregion
|
|
3000
3616
|
//#region src/components/ui/toast.tsx
|
|
3001
3617
|
const toastManager = Toast.createToastManager();
|
|
@@ -4268,7 +4884,7 @@ const sizeDefaultProps = {
|
|
|
4268
4884
|
|
|
4269
4885
|
//#endregion
|
|
4270
4886
|
//#region src/utils/spacing.tsx
|
|
4271
|
-
const
|
|
4887
|
+
const spacingField = {
|
|
4272
4888
|
...marginField,
|
|
4273
4889
|
...paddingField
|
|
4274
4890
|
};
|
|
@@ -4559,7 +5175,7 @@ const textTransformDefaultProps = { textTransform: "none" };
|
|
|
4559
5175
|
|
|
4560
5176
|
//#endregion
|
|
4561
5177
|
//#region src/utils/typography.tsx
|
|
4562
|
-
const
|
|
5178
|
+
const typographyField = {
|
|
4563
5179
|
...textAlignField,
|
|
4564
5180
|
...textTransformField,
|
|
4565
5181
|
...textDecorationField,
|
|
@@ -4598,6 +5214,20 @@ const typographyFieldNames = [
|
|
|
4598
5214
|
"fontWeight"
|
|
4599
5215
|
];
|
|
4600
5216
|
|
|
5217
|
+
//#endregion
|
|
5218
|
+
//#region src/utils/csrf.ts
|
|
5219
|
+
/**
|
|
5220
|
+
* Récupère le jeton CSRF à partir d'une balise meta dans le DOM.
|
|
5221
|
+
* Standard Laravel : <meta name="csrf-token" content="...">
|
|
5222
|
+
*
|
|
5223
|
+
* @returns Le jeton CSRF sous forme de chaîne, ou null s'il n'est pas trouvé ou si l'exécution n'est pas côté client.
|
|
5224
|
+
*/
|
|
5225
|
+
function getCsrfToken() {
|
|
5226
|
+
if (typeof document === "undefined") return null;
|
|
5227
|
+
const meta = document.querySelector("meta[name=\"csrf-token\"]");
|
|
5228
|
+
return meta ? meta.getAttribute("content") : null;
|
|
5229
|
+
}
|
|
5230
|
+
|
|
4601
5231
|
//#endregion
|
|
4602
5232
|
//#region src/hooks/useOptimizedImage.tsx
|
|
4603
5233
|
const BREAKPOINTS = [
|
|
@@ -4695,5 +5325,336 @@ function useOptimizedImage(src) {
|
|
|
4695
5325
|
}
|
|
4696
5326
|
|
|
4697
5327
|
//#endregion
|
|
4698
|
-
|
|
5328
|
+
//#region src/plugins/redactor-assistant/utils/constants.ts
|
|
5329
|
+
const QUICK_ACTIONS = [
|
|
5330
|
+
{
|
|
5331
|
+
label: "Improve",
|
|
5332
|
+
task: "rewrite",
|
|
5333
|
+
instructions: "Improve this text to make it clearer and more engaging."
|
|
5334
|
+
},
|
|
5335
|
+
{
|
|
5336
|
+
label: "Shorten",
|
|
5337
|
+
task: "rewrite",
|
|
5338
|
+
instructions: "Shorten this text while keeping the essential ideas."
|
|
5339
|
+
},
|
|
5340
|
+
{
|
|
5341
|
+
label: "Lengthen",
|
|
5342
|
+
task: "rewrite",
|
|
5343
|
+
instructions: "Expand this text with more details."
|
|
5344
|
+
},
|
|
5345
|
+
{
|
|
5346
|
+
label: "Pro tone",
|
|
5347
|
+
task: "rewrite",
|
|
5348
|
+
instructions: "Rewrite this text with a professional and formal tone."
|
|
5349
|
+
},
|
|
5350
|
+
{
|
|
5351
|
+
label: "SEO",
|
|
5352
|
+
task: "seo",
|
|
5353
|
+
instructions: "Optimize this text for search engines."
|
|
5354
|
+
},
|
|
5355
|
+
{
|
|
5356
|
+
label: "Summarize",
|
|
5357
|
+
task: "summarize",
|
|
5358
|
+
instructions: "Summarize this text in a few concise sentences, capturing the key points."
|
|
5359
|
+
}
|
|
5360
|
+
];
|
|
5361
|
+
|
|
5362
|
+
//#endregion
|
|
5363
|
+
//#region src/plugins/redactor-assistant/components/RedactorMenuButton.tsx
|
|
5364
|
+
function RedactorMenuButton({ onAction, onGenerate, loading = false }) {
|
|
5365
|
+
return /* @__PURE__ */ jsxs(Menu, { children: [/* @__PURE__ */ jsx(MenuTrigger, {
|
|
5366
|
+
openOnHover: true,
|
|
5367
|
+
render: /* @__PURE__ */ jsx(Button, {
|
|
5368
|
+
size: "icon-sm",
|
|
5369
|
+
title: "AI writing assistance",
|
|
5370
|
+
disabled: loading,
|
|
5371
|
+
children: /* @__PURE__ */ jsx(SparklesIcon, { size: 10 })
|
|
5372
|
+
})
|
|
5373
|
+
}), /* @__PURE__ */ jsxs(MenuPopup, {
|
|
5374
|
+
align: "end",
|
|
5375
|
+
className: "min-w-0!",
|
|
5376
|
+
children: [
|
|
5377
|
+
/* @__PURE__ */ jsx(MenuGroup, { children: /* @__PURE__ */ jsx(MenuItem, {
|
|
5378
|
+
className: "cursor-pointer",
|
|
5379
|
+
onClick: () => onGenerate?.(),
|
|
5380
|
+
children: "Generate"
|
|
5381
|
+
}) }),
|
|
5382
|
+
/* @__PURE__ */ jsx(MenuSeparator, {}),
|
|
5383
|
+
/* @__PURE__ */ jsx(MenuGroup, { children: QUICK_ACTIONS.map((action) => /* @__PURE__ */ jsx(MenuItem, {
|
|
5384
|
+
className: "cursor-pointer",
|
|
5385
|
+
onClick: () => onAction(action.task, action.instructions),
|
|
5386
|
+
children: action.label
|
|
5387
|
+
}, action.label)) })
|
|
5388
|
+
]
|
|
5389
|
+
})] });
|
|
5390
|
+
}
|
|
5391
|
+
|
|
5392
|
+
//#endregion
|
|
5393
|
+
//#region src/plugins/redactor-assistant/utils/redactorClient.ts
|
|
5394
|
+
const AI_ENDPOINT = "/admin/puck/redactor";
|
|
5395
|
+
const TIMEOUT_MS = 35e3;
|
|
5396
|
+
/**
|
|
5397
|
+
* Appelle l'endpoint Redactor backend. Ne jamais exposer de clé API côté client.
|
|
5398
|
+
*/
|
|
5399
|
+
async function callRedactor(request) {
|
|
5400
|
+
const token = getCsrfToken();
|
|
5401
|
+
const controller = new AbortController();
|
|
5402
|
+
const timeoutId = setTimeout(() => controller.abort(), TIMEOUT_MS);
|
|
5403
|
+
try {
|
|
5404
|
+
const response = await fetch(AI_ENDPOINT, {
|
|
5405
|
+
method: "POST",
|
|
5406
|
+
headers: {
|
|
5407
|
+
"Content-Type": "application/json",
|
|
5408
|
+
Accept: "application/json",
|
|
5409
|
+
...token ? { "X-CSRF-TOKEN": token } : {}
|
|
5410
|
+
},
|
|
5411
|
+
body: JSON.stringify(request),
|
|
5412
|
+
credentials: "same-origin",
|
|
5413
|
+
signal: controller.signal
|
|
5414
|
+
});
|
|
5415
|
+
if (!response.ok) {
|
|
5416
|
+
const body = await response.json().catch(() => ({}));
|
|
5417
|
+
throw new Error(body.error || `Erreur serveur (${response.status})`);
|
|
5418
|
+
}
|
|
5419
|
+
const data = await response.json();
|
|
5420
|
+
if (!data.text || typeof data.text !== "string") throw new Error("Réponse Redactor invalide.");
|
|
5421
|
+
return { text: data.text };
|
|
5422
|
+
} catch (error) {
|
|
5423
|
+
if (error.name === "AbortError") throw new Error("La requête Redactor a expiré. Réessayez.");
|
|
5424
|
+
throw error;
|
|
5425
|
+
} finally {
|
|
5426
|
+
clearTimeout(timeoutId);
|
|
5427
|
+
}
|
|
5428
|
+
}
|
|
5429
|
+
|
|
5430
|
+
//#endregion
|
|
5431
|
+
//#region src/plugins/redactor-assistant/utils/buildContext.ts
|
|
5432
|
+
/**
|
|
5433
|
+
* Construit un résumé textuel de la page à partir des données Puck.
|
|
5434
|
+
*/
|
|
5435
|
+
function buildPageSummary(data) {
|
|
5436
|
+
if (!data?.content?.length) return "Page vide.";
|
|
5437
|
+
return data.content.map((block, i) => {
|
|
5438
|
+
const textProps = extractTextProps(block.props);
|
|
5439
|
+
const propsStr = textProps.length > 0 ? `: ${textProps.join(", ")}` : "";
|
|
5440
|
+
return `[${i + 1}] ${block.type}${propsStr}`;
|
|
5441
|
+
}).join("\n");
|
|
5442
|
+
}
|
|
5443
|
+
/**
|
|
5444
|
+
* Extrait les propriétés textuelles d'un bloc pour le résumé.
|
|
5445
|
+
*/
|
|
5446
|
+
function extractTextProps(props) {
|
|
5447
|
+
const textFields = [];
|
|
5448
|
+
for (const [key, value] of Object.entries(props)) {
|
|
5449
|
+
if (key === "id") continue;
|
|
5450
|
+
if (typeof value === "string" && value.length > 0 && value.length <= 200) {
|
|
5451
|
+
const truncated = value.length > 80 ? value.substring(0, 80) + "…" : value;
|
|
5452
|
+
textFields.push(`${key}="${truncated}"`);
|
|
5453
|
+
}
|
|
5454
|
+
}
|
|
5455
|
+
return textFields;
|
|
5456
|
+
}
|
|
5457
|
+
/**
|
|
5458
|
+
* Construit le contexte AI complet à partir des données Puck et du bloc sélectionné.
|
|
5459
|
+
*/
|
|
5460
|
+
function buildContext(data, selectedBlock, brandVoice) {
|
|
5461
|
+
return {
|
|
5462
|
+
pageSummary: buildPageSummary(data),
|
|
5463
|
+
currentBlock: selectedBlock ? {
|
|
5464
|
+
type: selectedBlock.type,
|
|
5465
|
+
props: selectedBlock.props
|
|
5466
|
+
} : null,
|
|
5467
|
+
brandVoice: {
|
|
5468
|
+
tone: brandVoice?.tone ?? "professionnel",
|
|
5469
|
+
language: brandVoice?.language ?? "français"
|
|
5470
|
+
}
|
|
5471
|
+
};
|
|
5472
|
+
}
|
|
5473
|
+
|
|
5474
|
+
//#endregion
|
|
5475
|
+
//#region src/plugins/redactor-assistant/hooks/useRedactor.ts
|
|
5476
|
+
/**
|
|
5477
|
+
* Custom hook to manage the Redactor logic (API calls, loading, error, result).
|
|
5478
|
+
* Encapsulates the core logic for both the sidebar plugin and the richtext button.
|
|
5479
|
+
*/
|
|
5480
|
+
function useRedactor() {
|
|
5481
|
+
const [instructions, setInstructions] = useState("");
|
|
5482
|
+
const [loading, setLoading] = useState(false);
|
|
5483
|
+
const [error, setError] = useState(null);
|
|
5484
|
+
const [result, setResult] = useState(null);
|
|
5485
|
+
const [previousValue, setPreviousValue] = useState(null);
|
|
5486
|
+
/**
|
|
5487
|
+
* Call the redactor API to generate or rewrite text.
|
|
5488
|
+
*/
|
|
5489
|
+
const generate = async ({ task, taskInstructions, input, appData, currentBlock, outputFormat }) => {
|
|
5490
|
+
setLoading(true);
|
|
5491
|
+
setError(null);
|
|
5492
|
+
setResult(null);
|
|
5493
|
+
try {
|
|
5494
|
+
const context = buildContext(appData, currentBlock);
|
|
5495
|
+
const response = await callRedactor({
|
|
5496
|
+
task,
|
|
5497
|
+
instructions: taskInstructions || instructions,
|
|
5498
|
+
input,
|
|
5499
|
+
context,
|
|
5500
|
+
outputFormat
|
|
5501
|
+
});
|
|
5502
|
+
setResult(response.text);
|
|
5503
|
+
setPreviousValue(input);
|
|
5504
|
+
return response.text;
|
|
5505
|
+
} catch (err) {
|
|
5506
|
+
setError(err.message || "Unknown error.");
|
|
5507
|
+
throw err;
|
|
5508
|
+
} finally {
|
|
5509
|
+
setLoading(false);
|
|
5510
|
+
}
|
|
5511
|
+
};
|
|
5512
|
+
return {
|
|
5513
|
+
instructions,
|
|
5514
|
+
setInstructions,
|
|
5515
|
+
loading,
|
|
5516
|
+
error,
|
|
5517
|
+
setError,
|
|
5518
|
+
result,
|
|
5519
|
+
setResult,
|
|
5520
|
+
previousValue,
|
|
5521
|
+
setPreviousValue,
|
|
5522
|
+
generate
|
|
5523
|
+
};
|
|
5524
|
+
}
|
|
5525
|
+
|
|
5526
|
+
//#endregion
|
|
5527
|
+
//#region src/plugins/redactor-assistant/components/RedactorRichTextButton.tsx
|
|
5528
|
+
const useTypedPuck = createUsePuck();
|
|
5529
|
+
function RedactorRichTextButton({ value, onChange, children, label, field }) {
|
|
5530
|
+
const appState = useTypedPuck((s) => s.appState);
|
|
5531
|
+
const [mode, setMode] = useState(null);
|
|
5532
|
+
const { instructions, setInstructions, loading, error, result, setResult, generate } = useRedactor();
|
|
5533
|
+
const textValue = typeof value === "string" ? value : "";
|
|
5534
|
+
const selectedItem = appState.ui.itemSelector ? appState.data.content?.[appState.ui.itemSelector.index] : null;
|
|
5535
|
+
const handleGenerate = async (task, taskInstructions) => {
|
|
5536
|
+
await generate({
|
|
5537
|
+
task,
|
|
5538
|
+
taskInstructions,
|
|
5539
|
+
input: textValue,
|
|
5540
|
+
appData: appState.data,
|
|
5541
|
+
currentBlock: selectedItem,
|
|
5542
|
+
outputFormat: "html"
|
|
5543
|
+
}).catch(() => {});
|
|
5544
|
+
};
|
|
5545
|
+
const applyResult = () => {
|
|
5546
|
+
if (result === null) return;
|
|
5547
|
+
onChange(result);
|
|
5548
|
+
setResult(null);
|
|
5549
|
+
setMode(null);
|
|
5550
|
+
};
|
|
5551
|
+
const showPanel = loading || mode === "generate" || result !== null || !!error;
|
|
5552
|
+
return /* @__PURE__ */ jsxs("div", { children: [
|
|
5553
|
+
label && /* @__PURE__ */ jsx(Label_default, {
|
|
5554
|
+
label,
|
|
5555
|
+
tooltip: field?.tooltip,
|
|
5556
|
+
action: /* @__PURE__ */ jsx(RedactorMenuButton, {
|
|
5557
|
+
onAction: handleGenerate,
|
|
5558
|
+
onGenerate: () => setMode("generate"),
|
|
5559
|
+
loading
|
|
5560
|
+
})
|
|
5561
|
+
}),
|
|
5562
|
+
/* @__PURE__ */ jsx("div", {
|
|
5563
|
+
className: loading ? "pointer-events-none opacity-60" : "",
|
|
5564
|
+
children
|
|
5565
|
+
}),
|
|
5566
|
+
showPanel && /* @__PURE__ */ jsxs("div", {
|
|
5567
|
+
className: "mt-3 border border-gray-200 rounded-lg bg-muted p-3 flex flex-col gap-y-3",
|
|
5568
|
+
children: [
|
|
5569
|
+
error && /* @__PURE__ */ jsx(Alert, {
|
|
5570
|
+
variant: "error",
|
|
5571
|
+
size: "sm",
|
|
5572
|
+
children: /* @__PURE__ */ jsx(AlertTitle, { children: error })
|
|
5573
|
+
}),
|
|
5574
|
+
loading && /* @__PURE__ */ jsxs("div", {
|
|
5575
|
+
className: "flex items-center justify-center gap-1.5 text-muted-foreground",
|
|
5576
|
+
children: [/* @__PURE__ */ jsx(Loader2Icon, {
|
|
5577
|
+
size: 14,
|
|
5578
|
+
className: "animate-spin"
|
|
5579
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
5580
|
+
className: "text-sm",
|
|
5581
|
+
children: "Generating…"
|
|
5582
|
+
})]
|
|
5583
|
+
}),
|
|
5584
|
+
mode === "generate" && !loading && result === null && /* @__PURE__ */ jsxs("div", {
|
|
5585
|
+
className: "flex flex-col",
|
|
5586
|
+
children: [
|
|
5587
|
+
/* @__PURE__ */ jsx(Label_default, {
|
|
5588
|
+
label: "AI writing assistance",
|
|
5589
|
+
tooltip: "The generated text will fully replace your current content. Your original text will not be preserved."
|
|
5590
|
+
}),
|
|
5591
|
+
/* @__PURE__ */ jsx(Textarea, {
|
|
5592
|
+
value: instructions,
|
|
5593
|
+
onChange: (e) => setInstructions(e.target.value),
|
|
5594
|
+
placeholder: "Ex: Write a short introduction about our services, in a professional tone…",
|
|
5595
|
+
disabled: loading
|
|
5596
|
+
}),
|
|
5597
|
+
/* @__PURE__ */ jsxs("div", {
|
|
5598
|
+
className: "flex justify-end gap-x-2 mt-3",
|
|
5599
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
5600
|
+
variant: "outline",
|
|
5601
|
+
onClick: () => setMode(null),
|
|
5602
|
+
disabled: loading,
|
|
5603
|
+
children: "Cancel"
|
|
5604
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
5605
|
+
variant: "default",
|
|
5606
|
+
onClick: () => handleGenerate(textValue ? "rewrite" : "generate", instructions),
|
|
5607
|
+
disabled: loading,
|
|
5608
|
+
children: "Generate"
|
|
5609
|
+
})]
|
|
5610
|
+
})
|
|
5611
|
+
]
|
|
5612
|
+
}),
|
|
5613
|
+
result !== null && !loading && /* @__PURE__ */ jsxs("div", {
|
|
5614
|
+
className: "flex flex-col",
|
|
5615
|
+
children: [/* @__PURE__ */ jsx(Alert, {
|
|
5616
|
+
variant: "success",
|
|
5617
|
+
size: "sm",
|
|
5618
|
+
children: /* @__PURE__ */ jsx(AlertDescription, {
|
|
5619
|
+
className: "max-h-[150px] overflow-auto",
|
|
5620
|
+
dangerouslySetInnerHTML: { __html: result }
|
|
5621
|
+
})
|
|
5622
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
5623
|
+
className: "flex justify-end gap-x-2 mt-3",
|
|
5624
|
+
children: [/* @__PURE__ */ jsx(Button, {
|
|
5625
|
+
variant: "outline",
|
|
5626
|
+
onClick: () => setResult(null),
|
|
5627
|
+
children: "Ignore"
|
|
5628
|
+
}), /* @__PURE__ */ jsx(Button, {
|
|
5629
|
+
variant: "default",
|
|
5630
|
+
onClick: applyResult,
|
|
5631
|
+
children: "Apply"
|
|
5632
|
+
})]
|
|
5633
|
+
})]
|
|
5634
|
+
})
|
|
5635
|
+
]
|
|
5636
|
+
})
|
|
5637
|
+
] });
|
|
5638
|
+
}
|
|
5639
|
+
|
|
5640
|
+
//#endregion
|
|
5641
|
+
//#region src/plugins/redactor-assistant/index.tsx
|
|
5642
|
+
createUsePuck();
|
|
5643
|
+
function createRedactorPlugin() {
|
|
5644
|
+
return {
|
|
5645
|
+
name: "redactor-assistant",
|
|
5646
|
+
overrides: { fieldTypes: { richtext: ({ children, onChange, value, field, label }) => {
|
|
5647
|
+
return /* @__PURE__ */ jsx(RedactorRichTextButton, {
|
|
5648
|
+
value,
|
|
5649
|
+
onChange,
|
|
5650
|
+
label,
|
|
5651
|
+
field,
|
|
5652
|
+
children: React.cloneElement(children, { Label: ({ children: c }) => /* @__PURE__ */ jsx(Fragment, { children: c }) })
|
|
5653
|
+
});
|
|
5654
|
+
} } }
|
|
5655
|
+
};
|
|
5656
|
+
}
|
|
5657
|
+
|
|
5658
|
+
//#endregion
|
|
5659
|
+
export { Accordion, AccordionItem, AccordionPanel, AccordionTrigger, ActionBar_default as ActionBar, AnchoredToastProvider, Badge, Button, Checkbox, ColorPicker, ColorPickerContent, Dialog, DialogDescription, DialogFooter, DialogHeader, DialogPanel, DialogPopup, DialogTitle, DialogTrigger, DrawerItem_default as DrawerItem, Checkbox_default as FieldCheckbox, FieldGroups_default as FieldGroups, Input_default as FieldInput, NumberUnit_default as FieldNumberUnit, Radio_default as FieldRadio, Select_default as FieldSelect, Switch_default as FieldSwitch, Textarea_default as FieldTextarea, Frame, FrameDescription, FrameFooter, FrameHeader, FramePanel, FrameTitle, GRAY_COLORS, Input, InputGroup, InputGroupAddon, InputGroupInput, InputGroupText, InputGroupTextarea, Label_default as Label, MediaPicker, Menu, MenuCheckboxItem, MenuGroup, MenuGroupLabel, MenuItem, MenuPopup, MenuRadioGroup, MenuRadioItem, MenuSeparator, MenuSub, MenuSubPopup, MenuSubTrigger, MenuTrigger, PREDEFINED_COLORS, PagePicker, Pagination, PaginationContent, PaginationEllipsis, PaginationItem, PaginationLink, PaginationNext, PaginationPrevious, PickerModal, Popover, PopoverClose, PopoverPopup as PopoverContent, PopoverPopup, PopoverCreateHandle, PopoverDescription, PopoverTitle, PopoverTrigger, RadioGroup, RadioGroupItem, RichTextMenuColorPicker, RichTextMenuLink, ScrollArea, ScrollBar, Select, SelectGroup, SelectGroupLabel, SelectItem, SelectPopup, SelectSeparator, SelectTrigger, SelectValue, Separator, Switch, Table, TableBody, TableCaption, TableCell, TableFooter, TableHead, TableHeader, TableRow, Tabs, TabsList, TabsPanel, TabsTab, Textarea, ToastProvider, Tooltip, TooltipPopup, TooltipProvider, TooltipTrigger, anchoredToastManager, animationDefaultProps, animationField, animationToAttributes, badgeVariants, buttonVariants, plugin_default as createPuckOverridesPlugin, createRedactorPlugin, createTemplateBlock, customClassesDefaultProps, customClassesField, customClassesToClasses, displayDefaultProps, displayField, displayToClasses, fontWeightDefaultProps, fontWeightField, fontWeightToClasses, getCsrfToken, lineHeightDefaultProps, lineHeightField, lineHeightToClasses, marginDefaultProps, marginField, marginToClasses, paddingDefaultProps, paddingField, paddingToClasses, pageField, positionDefaultProps, positionField, positionToClasses, richTextMenuColorPickerExtension, sizeDefaultProps, sizeField, sizeToClasses, spacingDefaultProps, spacingField, spacingFieldNames, spacingOptions, spacingToClasses, textAlignDefaultProps, textAlignField, textAlignToClasses, textColorDefaultProps, textColorField, textColorToClasses, textDecorationDefaultProps, textDecorationField, textDecorationToClasses, textSizeDefaultProps, textSizeField, textSizeToClasses, textTransformDefaultProps, textTransformField, textTransformToClasses, toastManager, typographyDefaultProps, typographyField, typographyFieldNames, typographyToClasses, useMediaUrl, useOptimizedImage, usePageUrl };
|
|
4699
5660
|
//# sourceMappingURL=index.js.map
|