@drawnagency/primitives 0.1.60 → 0.1.62
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/dist/chunk-2BHPWO7M.js +558 -0
- package/dist/chunk-4E66N6UV.js +10 -0
- package/dist/{chunk-RFZNNCAS.js → chunk-53DKVAB6.js} +1 -61
- package/dist/chunk-5THS4K5D.js +123 -0
- package/dist/chunk-677NTHAZ.js +27 -0
- package/dist/{chunk-TG43X7JO.js → chunk-75P6HWPN.js} +29 -5
- package/dist/chunk-7EOSDFS3.js +10 -0
- package/dist/{chunk-ODCJQOVO.js → chunk-7IMQVDDJ.js} +1 -1
- package/dist/chunk-FJBDGYHE.js +782 -0
- package/dist/chunk-I5737FJY.js +62 -0
- package/dist/chunk-JRT4KWHU.js +1201 -0
- package/dist/chunk-QWDOJUUO.js +648 -0
- package/dist/{chunk-BT7STGDW.js → chunk-TEYTLQVH.js} +0 -15
- package/dist/chunk-WDSVHKAH.js +54 -0
- package/dist/{chunk-Q5EEYBMJ.js → chunk-ZYXLNJ5M.js} +6 -30
- package/dist/components/brandguide/ColorSwatchSettings.d.ts +1 -1
- package/dist/components/brandguide/ColorSwatchSettings.d.ts.map +1 -1
- package/dist/components/brandguide/Colors.d.ts +1 -1
- package/dist/components/brandguide/Colors.d.ts.map +1 -1
- package/dist/components/editor/index.js +642 -0
- package/dist/components/primitives/IconPicker.d.ts +1 -7
- package/dist/components/primitives/IconPicker.d.ts.map +1 -1
- package/dist/components/primitives/index.d.ts +10 -0
- package/dist/components/primitives/index.d.ts.map +1 -0
- package/dist/components/primitives/index.js +169 -0
- package/dist/components/sections/Colors/index.d.ts.map +1 -1
- package/dist/components/sections/Colors/schema.d.ts +19 -0
- package/dist/components/sections/Colors/schema.d.ts.map +1 -0
- package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts +20 -0
- package/dist/components/sections/DoDontMedia/DoDontMediaBlock.d.ts.map +1 -0
- package/dist/components/sections/DoDontMedia/index.d.ts +45 -0
- package/dist/components/sections/DoDontMedia/index.d.ts.map +1 -0
- package/dist/components/sections/IconList/DoDontToggle.d.ts +14 -0
- package/dist/components/sections/IconList/DoDontToggle.d.ts.map +1 -0
- package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
- package/dist/components/sections/IconList/index.d.ts.map +1 -1
- package/dist/components/sections/Media/MediaBlock.d.ts +1 -3
- package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -1
- package/dist/components/sections/Media/index.d.ts +0 -1
- package/dist/components/sections/Media/index.d.ts.map +1 -1
- package/dist/components/sections/all-sections.d.ts +54 -18
- package/dist/components/sections/all-sections.d.ts.map +1 -1
- package/dist/components/sections/brand-guide.d.ts +84 -0
- package/dist/components/sections/brand-guide.d.ts.map +1 -0
- package/dist/components/sections/brand-guide.js +21 -0
- package/dist/components/sections/core-sections.d.ts +93 -0
- package/dist/components/sections/core-sections.d.ts.map +1 -0
- package/dist/components/sections/register-schemas.js +240 -3353
- package/dist/index.js +48 -46
- package/dist/lib/index.js +17 -11
- package/dist/lib/loader.d.ts.map +1 -1
- package/dist/lib/migrate-sections-transform.d.ts.map +1 -1
- package/dist/lib/migrate-sections-transform.js +1 -1
- package/dist/lib/registry.d.ts +6 -1
- package/dist/lib/registry.d.ts.map +1 -1
- package/dist/media/index.js +1 -1
- package/dist/schemas/index.js +9 -13
- package/dist/schemas/link.js +13 -0
- package/dist/schemas/shared.d.ts +0 -17
- package/dist/schemas/shared.d.ts.map +1 -1
- package/package.json +13 -1
- package/src/components/brandguide/ColorSwatchSettings.tsx +1 -1
- package/src/components/brandguide/Colors.tsx +1 -1
- package/src/components/primitives/IconPicker.tsx +27 -119
- package/src/components/primitives/index.ts +11 -0
- package/src/components/sections/Colors/index.tsx +2 -1
- package/src/components/sections/Colors/schema.ts +24 -0
- package/src/components/sections/DoDontMedia/DoDontMediaBlock.tsx +35 -0
- package/src/components/sections/DoDontMedia/index.tsx +84 -0
- package/src/components/sections/IconList/DoDontToggle.tsx +76 -0
- package/src/components/sections/IconList/IconList.tsx +24 -14
- package/src/components/sections/IconList/index.tsx +1 -0
- package/src/components/sections/Media/MediaBlock.tsx +1 -11
- package/src/components/sections/Media/index.tsx +0 -15
- package/src/components/sections/all-sections.ts +7 -35
- package/src/components/sections/brand-guide.ts +13 -0
- package/src/components/sections/core-sections.ts +26 -0
- package/src/lib/loader.ts +10 -4
- package/src/lib/migrate-sections-transform.ts +33 -5
- package/src/lib/registry.ts +6 -1
- package/src/schemas/shared.ts +0 -18
- /package/dist/{chunk-ZU2MKPTG.js → chunk-3DCG4DNU.js} +0 -0
|
@@ -1,207 +1,71 @@
|
|
|
1
1
|
import {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
brandGuideSectionDefs,
|
|
3
|
+
pluralize,
|
|
4
|
+
stripHtmlToPlainText,
|
|
5
|
+
truncate
|
|
6
|
+
} from "../../chunk-JRT4KWHU.js";
|
|
7
|
+
import {
|
|
8
|
+
DeleteButton,
|
|
9
|
+
DragHandle,
|
|
10
|
+
Popover,
|
|
11
|
+
PopoverItem,
|
|
12
|
+
SettingsButton,
|
|
13
|
+
SettingsForm,
|
|
14
|
+
buildBlockDragData,
|
|
15
|
+
buildBlockDropData,
|
|
16
|
+
canDropBlock,
|
|
17
|
+
isBlockDragData
|
|
18
|
+
} from "../../chunk-2BHPWO7M.js";
|
|
19
|
+
import "../../chunk-5THS4K5D.js";
|
|
20
|
+
import {
|
|
21
|
+
EditableRichText,
|
|
22
|
+
defineHeadingSection
|
|
23
|
+
} from "../../chunk-FJBDGYHE.js";
|
|
24
|
+
import {
|
|
25
|
+
EditablePlainText,
|
|
26
|
+
MAX_CONTAINER_COLUMNS,
|
|
27
|
+
MediaBlock,
|
|
28
|
+
colSpanClass,
|
|
29
|
+
containerGridClass,
|
|
30
|
+
spacerHiddenClass
|
|
31
|
+
} from "../../chunk-QWDOJUUO.js";
|
|
32
|
+
import "../../chunk-4E66N6UV.js";
|
|
33
|
+
import "../../chunk-I5737FJY.js";
|
|
34
|
+
import "../../chunk-CBWK3KPV.js";
|
|
4
35
|
import {
|
|
5
36
|
DEFAULT_LINK,
|
|
6
37
|
LinkValueSchema
|
|
7
|
-
} from "../../chunk-
|
|
38
|
+
} from "../../chunk-3DCG4DNU.js";
|
|
39
|
+
import "../../chunk-WDSVHKAH.js";
|
|
8
40
|
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
getIcon,
|
|
12
|
-
sanitizeHtml,
|
|
13
|
-
toSectionId
|
|
14
|
-
} from "../../chunk-RFZNNCAS.js";
|
|
41
|
+
sanitizeHtml
|
|
42
|
+
} from "../../chunk-53DKVAB6.js";
|
|
15
43
|
import "../../chunk-ZGFAYZWB.js";
|
|
44
|
+
import {
|
|
45
|
+
cn
|
|
46
|
+
} from "../../chunk-7EOSDFS3.js";
|
|
16
47
|
import {
|
|
17
48
|
getSectionSchema
|
|
18
49
|
} from "../../chunk-TZQPOR5A.js";
|
|
50
|
+
import {
|
|
51
|
+
SingleMediaReferenceSchema
|
|
52
|
+
} from "../../chunk-TEYTLQVH.js";
|
|
19
53
|
import {
|
|
20
54
|
defineSection,
|
|
21
55
|
getSection,
|
|
22
56
|
registerRichText,
|
|
23
57
|
registerSchema
|
|
24
58
|
} from "../../chunk-VKAGMEKE.js";
|
|
25
|
-
import {
|
|
26
|
-
ColorItemSchema,
|
|
27
|
-
SingleMediaReferenceSchema
|
|
28
|
-
} from "../../chunk-BT7STGDW.js";
|
|
29
59
|
import "../../chunk-NSCT3AMV.js";
|
|
30
60
|
import "../../chunk-JSBRDJBE.js";
|
|
31
61
|
|
|
32
62
|
// src/components/sections/LinkHeading/index.tsx
|
|
33
63
|
import { Heading1 } from "lucide-react";
|
|
34
|
-
|
|
35
|
-
// src/components/primitives/defineHeadingSection.tsx
|
|
36
|
-
import { z } from "zod";
|
|
37
|
-
|
|
38
|
-
// src/components/primitives/EditablePlainText.tsx
|
|
39
|
-
import {
|
|
40
|
-
useRef as useRef2,
|
|
41
|
-
useEffect as useEffect2,
|
|
42
|
-
useCallback as useCallback2,
|
|
43
|
-
createElement
|
|
44
|
-
} from "react";
|
|
45
|
-
|
|
46
|
-
// src/components/primitives/useEditablePlainText.ts
|
|
47
|
-
import { useState, useEffect, useRef, useCallback } from "react";
|
|
48
|
-
function useEditablePlainText({
|
|
49
|
-
value: propValue,
|
|
50
|
-
onChange,
|
|
51
|
-
multiline = false
|
|
52
|
-
}) {
|
|
53
|
-
const [value, setValue] = useState(propValue);
|
|
54
|
-
const lastPropValue = useRef(propValue);
|
|
55
|
-
useEffect(() => {
|
|
56
|
-
if (propValue !== lastPropValue.current) {
|
|
57
|
-
setValue(propValue);
|
|
58
|
-
lastPropValue.current = propValue;
|
|
59
|
-
}
|
|
60
|
-
}, [propValue]);
|
|
61
|
-
const handleInput = useCallback((text) => {
|
|
62
|
-
setValue(text);
|
|
63
|
-
}, []);
|
|
64
|
-
const handleBlur = useCallback(() => {
|
|
65
|
-
if (value !== propValue) {
|
|
66
|
-
onChange(value);
|
|
67
|
-
lastPropValue.current = value;
|
|
68
|
-
}
|
|
69
|
-
}, [value, propValue, onChange]);
|
|
70
|
-
return {
|
|
71
|
-
value,
|
|
72
|
-
handleInput,
|
|
73
|
-
handleBlur,
|
|
74
|
-
shouldPreventEnter: !multiline
|
|
75
|
-
};
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// src/components/primitives/EditablePlainText.tsx
|
|
79
|
-
function EditablePlainText({
|
|
80
|
-
tag,
|
|
81
|
-
value,
|
|
82
|
-
onChange,
|
|
83
|
-
isEditMode,
|
|
84
|
-
multiline = false,
|
|
85
|
-
placeholder,
|
|
86
|
-
className,
|
|
87
|
-
...htmlAttrs
|
|
88
|
-
}) {
|
|
89
|
-
const ref = useRef2(null);
|
|
90
|
-
const {
|
|
91
|
-
value: localValue,
|
|
92
|
-
handleInput,
|
|
93
|
-
handleBlur,
|
|
94
|
-
shouldPreventEnter
|
|
95
|
-
} = useEditablePlainText({ value, onChange, multiline });
|
|
96
|
-
useEffect2(() => {
|
|
97
|
-
if (ref.current && ref.current.textContent !== localValue) {
|
|
98
|
-
ref.current.textContent = localValue;
|
|
99
|
-
}
|
|
100
|
-
}, [localValue]);
|
|
101
|
-
const onInput = useCallback2(() => {
|
|
102
|
-
if (ref.current) {
|
|
103
|
-
handleInput(ref.current.textContent || "");
|
|
104
|
-
}
|
|
105
|
-
}, [handleInput]);
|
|
106
|
-
const onKeyDown = useCallback2(
|
|
107
|
-
(e) => {
|
|
108
|
-
if (e.key === "Enter" && shouldPreventEnter) {
|
|
109
|
-
e.preventDefault();
|
|
110
|
-
}
|
|
111
|
-
},
|
|
112
|
-
[shouldPreventEnter]
|
|
113
|
-
);
|
|
114
|
-
const onPaste = useCallback2(
|
|
115
|
-
(e) => {
|
|
116
|
-
e.preventDefault();
|
|
117
|
-
const text = e.clipboardData.getData("text/plain");
|
|
118
|
-
const selection = window.getSelection();
|
|
119
|
-
if (selection && selection.rangeCount > 0) {
|
|
120
|
-
const range = selection.getRangeAt(0);
|
|
121
|
-
range.deleteContents();
|
|
122
|
-
range.insertNode(document.createTextNode(text));
|
|
123
|
-
range.collapse(false);
|
|
124
|
-
selection.removeAllRanges();
|
|
125
|
-
selection.addRange(range);
|
|
126
|
-
}
|
|
127
|
-
if (ref.current) {
|
|
128
|
-
handleInput(ref.current.textContent || "");
|
|
129
|
-
}
|
|
130
|
-
},
|
|
131
|
-
[handleInput]
|
|
132
|
-
);
|
|
133
|
-
return createElement(
|
|
134
|
-
tag,
|
|
135
|
-
{
|
|
136
|
-
ref,
|
|
137
|
-
className: isEditMode && placeholder ? `editable-placeholder ${className ?? ""}` : className,
|
|
138
|
-
contentEditable: isEditMode ? "true" : void 0,
|
|
139
|
-
suppressContentEditableWarning: isEditMode || void 0,
|
|
140
|
-
onInput: isEditMode ? onInput : void 0,
|
|
141
|
-
onBlur: isEditMode ? handleBlur : void 0,
|
|
142
|
-
onKeyDown: isEditMode ? onKeyDown : void 0,
|
|
143
|
-
onPaste: isEditMode ? onPaste : void 0,
|
|
144
|
-
"data-placeholder": isEditMode && placeholder ? placeholder : void 0,
|
|
145
|
-
...htmlAttrs
|
|
146
|
-
},
|
|
147
|
-
value
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// src/components/primitives/HeadingSection.tsx
|
|
152
64
|
import { jsx } from "react/jsx-runtime";
|
|
153
|
-
function HeadingSection({ heading, tag, placeholder, className, onChange }) {
|
|
154
|
-
return /* @__PURE__ */ jsx(
|
|
155
|
-
EditablePlainText,
|
|
156
|
-
{
|
|
157
|
-
tag,
|
|
158
|
-
value: heading,
|
|
159
|
-
onChange: onChange ?? (() => {
|
|
160
|
-
}),
|
|
161
|
-
isEditMode: !!onChange,
|
|
162
|
-
placeholder,
|
|
163
|
-
id: toSectionId(heading),
|
|
164
|
-
className: cn("scroll-mt-20", className)
|
|
165
|
-
}
|
|
166
|
-
);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
// src/components/primitives/defineHeadingSection.tsx
|
|
170
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
171
|
-
function defineHeadingSection(config) {
|
|
172
|
-
const content = config.navExclusion ? z.object({ heading: z.string(), excludeFromNav: z.boolean().optional() }) : z.object({ heading: z.string() });
|
|
173
|
-
const schema8 = z.object({ type: z.literal(config.type), content });
|
|
174
|
-
return defineSection({
|
|
175
|
-
type: config.type,
|
|
176
|
-
label: config.label,
|
|
177
|
-
icon: config.icon,
|
|
178
|
-
schema: schema8,
|
|
179
|
-
navRole: config.navRole,
|
|
180
|
-
component: ({ content: content2, onChange }) => /* @__PURE__ */ jsx2(
|
|
181
|
-
HeadingSection,
|
|
182
|
-
{
|
|
183
|
-
heading: content2.content.heading,
|
|
184
|
-
tag: config.tag,
|
|
185
|
-
placeholder: config.placeholder,
|
|
186
|
-
onChange: onChange ? (heading) => onChange({ ...content2, content: { ...content2.content, heading } }) : void 0
|
|
187
|
-
}
|
|
188
|
-
),
|
|
189
|
-
defaults: () => ({ type: config.type, content: { heading: config.defaultHeading } }),
|
|
190
|
-
getLabel: (content2) => content2.content.heading,
|
|
191
|
-
...config.navExclusion ? {
|
|
192
|
-
settings: {
|
|
193
|
-
excludeFromNav: { type: "checkbox", label: "Exclude from navigation", default: false, target: "content" }
|
|
194
|
-
}
|
|
195
|
-
} : {}
|
|
196
|
-
});
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
// src/components/sections/LinkHeading/index.tsx
|
|
200
|
-
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
201
65
|
var LinkHeading_default = defineHeadingSection({
|
|
202
66
|
type: "link_heading",
|
|
203
67
|
label: "Link Heading",
|
|
204
|
-
icon: /* @__PURE__ */
|
|
68
|
+
icon: /* @__PURE__ */ jsx(Heading1, { size: 18 }),
|
|
205
69
|
navRole: "h1",
|
|
206
70
|
tag: "h2",
|
|
207
71
|
placeholder: "Section heading",
|
|
@@ -210,11 +74,11 @@ var LinkHeading_default = defineHeadingSection({
|
|
|
210
74
|
|
|
211
75
|
// src/components/sections/SubHeading/index.tsx
|
|
212
76
|
import { Heading2 } from "lucide-react";
|
|
213
|
-
import { jsx as
|
|
77
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
214
78
|
var SubHeading_default = defineHeadingSection({
|
|
215
79
|
type: "sub_heading",
|
|
216
80
|
label: "Sub Heading",
|
|
217
|
-
icon: /* @__PURE__ */
|
|
81
|
+
icon: /* @__PURE__ */ jsx2(Heading2, { size: 18 }),
|
|
218
82
|
navRole: "h2",
|
|
219
83
|
tag: "h3",
|
|
220
84
|
placeholder: "Sub heading",
|
|
@@ -224,11 +88,11 @@ var SubHeading_default = defineHeadingSection({
|
|
|
224
88
|
|
|
225
89
|
// src/components/sections/SubSubHeading/index.tsx
|
|
226
90
|
import { Heading3 } from "lucide-react";
|
|
227
|
-
import { jsx as
|
|
91
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
228
92
|
var SubSubHeading_default = defineHeadingSection({
|
|
229
93
|
type: "sub_sub_heading",
|
|
230
94
|
label: "Sub Sub Heading",
|
|
231
|
-
icon: /* @__PURE__ */
|
|
95
|
+
icon: /* @__PURE__ */ jsx3(Heading3, { size: 18 }),
|
|
232
96
|
navRole: "h3",
|
|
233
97
|
tag: "h4",
|
|
234
98
|
placeholder: "Sub sub heading",
|
|
@@ -237,732 +101,14 @@ var SubSubHeading_default = defineHeadingSection({
|
|
|
237
101
|
});
|
|
238
102
|
|
|
239
103
|
// src/components/sections/Prose/index.tsx
|
|
240
|
-
import { z
|
|
104
|
+
import { z } from "zod";
|
|
241
105
|
import { AlignLeft } from "lucide-react";
|
|
242
106
|
|
|
243
|
-
// src/components/primitives/EditableRichText.tsx
|
|
244
|
-
import { useRef as useRef4, useCallback as useCallback4, useEffect as useEffect4 } from "react";
|
|
245
|
-
import { EditorContent } from "@tiptap/react";
|
|
246
|
-
import { BubbleMenu } from "@tiptap/react/menus";
|
|
247
|
-
|
|
248
|
-
// src/components/primitives/useEditableRichText.ts
|
|
249
|
-
import { useState as useState2, useRef as useRef3, useCallback as useCallback3, useEffect as useEffect3 } from "react";
|
|
250
|
-
import { Editor } from "@tiptap/core";
|
|
251
|
-
import Placeholder from "@tiptap/extension-placeholder";
|
|
252
|
-
|
|
253
|
-
// src/components/primitives/tiptap-presets.ts
|
|
254
|
-
import StarterKit from "@tiptap/starter-kit";
|
|
255
|
-
import Underline from "@tiptap/extension-underline";
|
|
256
|
-
import Link from "@tiptap/extension-link";
|
|
257
|
-
|
|
258
|
-
// ../../node_modules/.pnpm/@tiptap+extension-paragraph@3.22.4_@tiptap+core@3.22.4_@tiptap+pm@3.22.4_/node_modules/@tiptap/extension-paragraph/dist/index.js
|
|
259
|
-
import { mergeAttributes, Node } from "@tiptap/core";
|
|
260
|
-
var EMPTY_PARAGRAPH_MARKDOWN = " ";
|
|
261
|
-
var NBSP_CHAR = "\xA0";
|
|
262
|
-
var Paragraph = Node.create({
|
|
263
|
-
name: "paragraph",
|
|
264
|
-
priority: 1e3,
|
|
265
|
-
addOptions() {
|
|
266
|
-
return {
|
|
267
|
-
HTMLAttributes: {}
|
|
268
|
-
};
|
|
269
|
-
},
|
|
270
|
-
group: "block",
|
|
271
|
-
content: "inline*",
|
|
272
|
-
parseHTML() {
|
|
273
|
-
return [{ tag: "p" }];
|
|
274
|
-
},
|
|
275
|
-
renderHTML({ HTMLAttributes }) {
|
|
276
|
-
return ["p", mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0];
|
|
277
|
-
},
|
|
278
|
-
parseMarkdown: (token, helpers) => {
|
|
279
|
-
const tokens = token.tokens || [];
|
|
280
|
-
if (tokens.length === 1 && tokens[0].type === "image") {
|
|
281
|
-
return helpers.parseChildren([tokens[0]]);
|
|
282
|
-
}
|
|
283
|
-
const content = helpers.parseInline(tokens);
|
|
284
|
-
const hasExplicitEmptyParagraphMarker = tokens.length === 1 && tokens[0].type === "text" && (tokens[0].raw === EMPTY_PARAGRAPH_MARKDOWN || tokens[0].text === EMPTY_PARAGRAPH_MARKDOWN || tokens[0].raw === NBSP_CHAR || tokens[0].text === NBSP_CHAR);
|
|
285
|
-
if (hasExplicitEmptyParagraphMarker && content.length === 1 && content[0].type === "text" && (content[0].text === EMPTY_PARAGRAPH_MARKDOWN || content[0].text === NBSP_CHAR)) {
|
|
286
|
-
return helpers.createNode("paragraph", void 0, []);
|
|
287
|
-
}
|
|
288
|
-
return helpers.createNode("paragraph", void 0, content);
|
|
289
|
-
},
|
|
290
|
-
renderMarkdown: (node, h, ctx) => {
|
|
291
|
-
var _a, _b;
|
|
292
|
-
if (!node) {
|
|
293
|
-
return "";
|
|
294
|
-
}
|
|
295
|
-
const content = Array.isArray(node.content) ? node.content : [];
|
|
296
|
-
if (content.length === 0) {
|
|
297
|
-
const previousContent = Array.isArray((_a = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _a.content) ? ctx.previousNode.content : [];
|
|
298
|
-
const previousNodeIsEmptyParagraph = ((_b = ctx == null ? void 0 : ctx.previousNode) == null ? void 0 : _b.type) === "paragraph" && previousContent.length === 0;
|
|
299
|
-
return previousNodeIsEmptyParagraph ? EMPTY_PARAGRAPH_MARKDOWN : "";
|
|
300
|
-
}
|
|
301
|
-
return h.renderChildren(content);
|
|
302
|
-
},
|
|
303
|
-
addCommands() {
|
|
304
|
-
return {
|
|
305
|
-
setParagraph: () => ({ commands }) => {
|
|
306
|
-
return commands.setNode(this.name);
|
|
307
|
-
}
|
|
308
|
-
};
|
|
309
|
-
},
|
|
310
|
-
addKeyboardShortcuts() {
|
|
311
|
-
return {
|
|
312
|
-
"Mod-Alt-0": () => this.editor.commands.setParagraph()
|
|
313
|
-
};
|
|
314
|
-
}
|
|
315
|
-
});
|
|
316
|
-
var index_default = Paragraph;
|
|
317
|
-
|
|
318
|
-
// src/components/primitives/CustomParagraph.ts
|
|
319
|
-
var ALLOWED_CLASSES = ["large", "lead-in"];
|
|
320
|
-
var CustomParagraph = index_default.extend({
|
|
321
|
-
addAttributes() {
|
|
322
|
-
return {
|
|
323
|
-
...this.parent?.(),
|
|
324
|
-
class: {
|
|
325
|
-
default: null,
|
|
326
|
-
parseHTML: (element) => {
|
|
327
|
-
const cls = element.getAttribute("class");
|
|
328
|
-
if (cls && ALLOWED_CLASSES.includes(cls)) {
|
|
329
|
-
return cls;
|
|
330
|
-
}
|
|
331
|
-
return null;
|
|
332
|
-
},
|
|
333
|
-
renderHTML: (attributes) => {
|
|
334
|
-
if (!attributes.class) return {};
|
|
335
|
-
return { class: attributes.class };
|
|
336
|
-
}
|
|
337
|
-
}
|
|
338
|
-
};
|
|
339
|
-
}
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
// src/components/primitives/tiptap-presets.ts
|
|
343
|
-
var basic = [
|
|
344
|
-
StarterKit.configure({
|
|
345
|
-
paragraph: false,
|
|
346
|
-
heading: false,
|
|
347
|
-
blockquote: false,
|
|
348
|
-
bulletList: false,
|
|
349
|
-
orderedList: false,
|
|
350
|
-
listItem: false,
|
|
351
|
-
codeBlock: false,
|
|
352
|
-
horizontalRule: false,
|
|
353
|
-
code: false,
|
|
354
|
-
strike: false
|
|
355
|
-
}),
|
|
356
|
-
CustomParagraph,
|
|
357
|
-
Underline
|
|
358
|
-
];
|
|
359
|
-
var rich = [
|
|
360
|
-
StarterKit.configure({
|
|
361
|
-
paragraph: false,
|
|
362
|
-
heading: { levels: [3, 4] },
|
|
363
|
-
blockquote: false,
|
|
364
|
-
codeBlock: false,
|
|
365
|
-
horizontalRule: false,
|
|
366
|
-
code: false,
|
|
367
|
-
strike: false
|
|
368
|
-
}),
|
|
369
|
-
CustomParagraph,
|
|
370
|
-
Underline,
|
|
371
|
-
// `page` protocol: stable internal-page hrefs (page://{pageId}#{sectionId})
|
|
372
|
-
// resolved to real routes at SSR — see lib/links.ts.
|
|
373
|
-
Link.configure({ openOnClick: false, protocols: ["page"] })
|
|
374
|
-
];
|
|
375
|
-
var presets = { basic, rich };
|
|
376
|
-
|
|
377
|
-
// src/components/primitives/useEditableRichText.ts
|
|
378
|
-
function useEditableRichText({
|
|
379
|
-
value,
|
|
380
|
-
onChange,
|
|
381
|
-
preset,
|
|
382
|
-
placeholder
|
|
383
|
-
}) {
|
|
384
|
-
const editorRef = useRef3(null);
|
|
385
|
-
const [editor, setEditor] = useState2(null);
|
|
386
|
-
const valueRef = useRef3(value);
|
|
387
|
-
const onChangeRef = useRef3(onChange);
|
|
388
|
-
useEffect3(() => {
|
|
389
|
-
valueRef.current = value;
|
|
390
|
-
}, [value]);
|
|
391
|
-
useEffect3(() => {
|
|
392
|
-
onChangeRef.current = onChange;
|
|
393
|
-
}, [onChange]);
|
|
394
|
-
const activate = useCallback3(() => {
|
|
395
|
-
if (editorRef.current) return;
|
|
396
|
-
const extensions = placeholder ? [...presets[preset], Placeholder.configure({ placeholder })] : presets[preset];
|
|
397
|
-
const ed = new Editor({
|
|
398
|
-
extensions,
|
|
399
|
-
content: valueRef.current,
|
|
400
|
-
// Commit edits to onChange on every transaction, not only on deactivate().
|
|
401
|
-
// Without this, content lives only inside TipTap until blur; clicking a
|
|
402
|
-
// Save button while the editor is still focused flushes persistence before
|
|
403
|
-
// the (150ms-delayed) blur->deactivate commit fires, silently dropping the
|
|
404
|
-
// in-progress edit. Live-committing keeps persistence in sync continuously.
|
|
405
|
-
onUpdate: ({ editor: updated }) => {
|
|
406
|
-
const html = updated.getHTML();
|
|
407
|
-
if (html !== valueRef.current) {
|
|
408
|
-
valueRef.current = html;
|
|
409
|
-
onChangeRef.current(html);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
});
|
|
413
|
-
editorRef.current = ed;
|
|
414
|
-
setEditor(ed);
|
|
415
|
-
}, [preset, placeholder]);
|
|
416
|
-
const deactivate = useCallback3(() => {
|
|
417
|
-
const ed = editorRef.current;
|
|
418
|
-
if (!ed) return;
|
|
419
|
-
const html = ed.getHTML();
|
|
420
|
-
ed.destroy();
|
|
421
|
-
editorRef.current = null;
|
|
422
|
-
setEditor(null);
|
|
423
|
-
if (html !== valueRef.current) {
|
|
424
|
-
onChangeRef.current(html);
|
|
425
|
-
}
|
|
426
|
-
}, []);
|
|
427
|
-
useEffect3(() => {
|
|
428
|
-
return () => {
|
|
429
|
-
editorRef.current?.destroy();
|
|
430
|
-
editorRef.current = null;
|
|
431
|
-
};
|
|
432
|
-
}, []);
|
|
433
|
-
return {
|
|
434
|
-
isEditorActive: editor !== null,
|
|
435
|
-
editor,
|
|
436
|
-
activate,
|
|
437
|
-
deactivate
|
|
438
|
-
};
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
// src/components/primitives/RichTextToolbar.tsx
|
|
442
|
-
import { useState as useState4 } from "react";
|
|
443
|
-
import { useEditorState } from "@tiptap/react";
|
|
444
|
-
|
|
445
|
-
// src/components/primitives/LinkPopover.tsx
|
|
446
|
-
import { useState as useState3 } from "react";
|
|
447
|
-
|
|
448
|
-
// src/components/shared/Button.tsx
|
|
449
|
-
import { forwardRef } from "react";
|
|
450
|
-
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
451
|
-
var boxSize = {
|
|
452
|
-
sm: "rounded px-3 py-1.5 text-xs font-medium",
|
|
453
|
-
md: "rounded px-4 py-2 text-sm font-medium"
|
|
454
|
-
};
|
|
455
|
-
var ghostSize = {
|
|
456
|
-
sm: "text-xs font-medium",
|
|
457
|
-
md: "text-sm font-medium"
|
|
458
|
-
};
|
|
459
|
-
var variantClasses = {
|
|
460
|
-
primary: "bg-base-contrast text-base-accent hover:bg-base-contrast/90",
|
|
461
|
-
brand: "bg-primary text-primary-contrast hover:opacity-90",
|
|
462
|
-
secondary: "border border-base-200 text-base-contrast hover:bg-base-accent",
|
|
463
|
-
destructive: "border border-red-600 text-red-600 hover:bg-red-600 hover:text-white"
|
|
464
|
-
};
|
|
465
|
-
var ghostToneClasses = {
|
|
466
|
-
neutral: "text-base-contrast-light hover:text-base-contrast",
|
|
467
|
-
destructive: "text-red-600 hover:text-red-800"
|
|
468
|
-
};
|
|
469
|
-
var Button = forwardRef(function Button2({
|
|
470
|
-
variant = "primary",
|
|
471
|
-
size = "sm",
|
|
472
|
-
tone = "neutral",
|
|
473
|
-
fullWidth = false,
|
|
474
|
-
isLoading = false,
|
|
475
|
-
loadingLabel,
|
|
476
|
-
disabled,
|
|
477
|
-
className,
|
|
478
|
-
children,
|
|
479
|
-
...rest
|
|
480
|
-
}, ref) {
|
|
481
|
-
const isGhost = variant === "ghost";
|
|
482
|
-
const resolvedDisabled = disabled || isLoading;
|
|
483
|
-
const label = isLoading && loadingLabel ? loadingLabel : children;
|
|
484
|
-
return /* @__PURE__ */ jsx6(
|
|
485
|
-
"button",
|
|
486
|
-
{
|
|
487
|
-
ref,
|
|
488
|
-
disabled: resolvedDisabled,
|
|
489
|
-
className: cn(
|
|
490
|
-
"inline-flex items-center justify-center transition-colors",
|
|
491
|
-
isGhost ? ghostSize[size] : boxSize[size],
|
|
492
|
-
isGhost ? ghostToneClasses[tone] : variantClasses[variant],
|
|
493
|
-
fullWidth && "w-full",
|
|
494
|
-
resolvedDisabled ? "cursor-not-allowed opacity-50" : "cursor-pointer",
|
|
495
|
-
className
|
|
496
|
-
),
|
|
497
|
-
...rest,
|
|
498
|
-
children: label
|
|
499
|
-
}
|
|
500
|
-
);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
// src/components/shared/PagesContext.tsx
|
|
504
|
-
import { createContext, useContext } from "react";
|
|
505
|
-
var PagesContext = createContext({ pages: [], getPageHeadings: () => [] });
|
|
506
|
-
function usePages() {
|
|
507
|
-
return useContext(PagesContext);
|
|
508
|
-
}
|
|
509
|
-
|
|
510
|
-
// src/lib/links.ts
|
|
511
|
-
function internalHref(pageId, anchorSectionId) {
|
|
512
|
-
return `page://${pageId}${anchorSectionId ? `#${anchorSectionId}` : ""}`;
|
|
513
|
-
}
|
|
514
|
-
function parseInternalHref(href) {
|
|
515
|
-
const m = /^page:\/\/([^#]+)(?:#(.+))?$/.exec(href);
|
|
516
|
-
return m ? { pageId: m[1], anchorSectionId: m[2] ?? null } : null;
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
// src/components/primitives/LinkPopover.tsx
|
|
520
|
-
import { Fragment, jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
521
|
-
var selectClasses = "w-full rounded border border-base-contrast/20 bg-base px-2 py-1 text-sm text-base-contrast focus:outline-none focus:ring-1 focus:ring-primary";
|
|
522
|
-
function LinkPopover({ editor, onClose }) {
|
|
523
|
-
const { pages, getPageHeadings } = usePages();
|
|
524
|
-
const existingAttrs = editor.getAttributes("link");
|
|
525
|
-
const existingInternal = parseInternalHref(existingAttrs.href ?? "");
|
|
526
|
-
const [mode, setMode] = useState3(existingInternal ? "internal" : "external");
|
|
527
|
-
const [url, setUrl] = useState3(existingInternal ? "" : existingAttrs.href ?? "");
|
|
528
|
-
const [pageId, setPageId] = useState3(existingInternal?.pageId ?? "");
|
|
529
|
-
const [anchorId, setAnchorId] = useState3(existingInternal?.anchorSectionId ?? "");
|
|
530
|
-
const [openInNewTab, setOpenInNewTab] = useState3(
|
|
531
|
-
existingAttrs.target === "_blank"
|
|
532
|
-
);
|
|
533
|
-
const hasLink = Boolean(existingAttrs.href);
|
|
534
|
-
const headings = pageId ? getPageHeadings(pageId) : [];
|
|
535
|
-
const handleApply = () => {
|
|
536
|
-
if (mode === "internal") {
|
|
537
|
-
if (pageId) {
|
|
538
|
-
editor.chain().focus().extendMarkRange("link").setLink({ href: internalHref(pageId, anchorId || null), target: null }).run();
|
|
539
|
-
}
|
|
540
|
-
} else if (url.trim()) {
|
|
541
|
-
editor.chain().focus().extendMarkRange("link").setLink({ href: url.trim(), target: openInNewTab ? "_blank" : null }).run();
|
|
542
|
-
}
|
|
543
|
-
onClose();
|
|
544
|
-
};
|
|
545
|
-
const handleRemove = () => {
|
|
546
|
-
editor.chain().focus().extendMarkRange("link").unsetLink().run();
|
|
547
|
-
onClose();
|
|
548
|
-
};
|
|
549
|
-
const handleKeyDown = (e) => {
|
|
550
|
-
if (e.key === "Enter") {
|
|
551
|
-
e.preventDefault();
|
|
552
|
-
handleApply();
|
|
553
|
-
} else if (e.key === "Escape") {
|
|
554
|
-
e.preventDefault();
|
|
555
|
-
onClose();
|
|
556
|
-
}
|
|
557
|
-
};
|
|
558
|
-
return /* @__PURE__ */ jsxs(
|
|
559
|
-
"div",
|
|
560
|
-
{
|
|
561
|
-
className: "flex w-64 flex-col gap-2 rounded bg-base-accent p-3 shadow-lg",
|
|
562
|
-
onMouseDown: (e) => e.stopPropagation(),
|
|
563
|
-
onKeyDown: handleKeyDown,
|
|
564
|
-
children: [
|
|
565
|
-
/* @__PURE__ */ jsx7("div", { className: "flex gap-2", role: "tablist", children: ["external", "internal"].map((kind) => /* @__PURE__ */ jsx7(
|
|
566
|
-
"button",
|
|
567
|
-
{
|
|
568
|
-
type: "button",
|
|
569
|
-
role: "tab",
|
|
570
|
-
"aria-selected": mode === kind,
|
|
571
|
-
onClick: () => setMode(kind),
|
|
572
|
-
className: cn(
|
|
573
|
-
"cursor-pointer rounded border px-2 py-0.5 text-xs",
|
|
574
|
-
mode === kind ? "border-primary bg-primary text-primary-contrast" : "border-base-200 text-base-contrast"
|
|
575
|
-
),
|
|
576
|
-
children: kind === "external" ? "External URL" : "Internal page"
|
|
577
|
-
},
|
|
578
|
-
kind
|
|
579
|
-
)) }),
|
|
580
|
-
mode === "external" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
581
|
-
/* @__PURE__ */ jsx7(
|
|
582
|
-
"input",
|
|
583
|
-
{
|
|
584
|
-
autoFocus: true,
|
|
585
|
-
type: "url",
|
|
586
|
-
value: url,
|
|
587
|
-
onChange: (e) => setUrl(e.target.value),
|
|
588
|
-
placeholder: "https://example.com",
|
|
589
|
-
className: "rounded border border-base-contrast/20 bg-base px-2 py-1 text-sm text-base-contrast placeholder:text-base-contrast/40 focus:outline-none focus:ring-1 focus:ring-primary"
|
|
590
|
-
}
|
|
591
|
-
),
|
|
592
|
-
/* @__PURE__ */ jsxs("label", { className: "flex cursor-pointer items-center gap-2 text-sm text-base-contrast", children: [
|
|
593
|
-
/* @__PURE__ */ jsx7(
|
|
594
|
-
"input",
|
|
595
|
-
{
|
|
596
|
-
type: "checkbox",
|
|
597
|
-
checked: openInNewTab,
|
|
598
|
-
onChange: (e) => setOpenInNewTab(e.target.checked),
|
|
599
|
-
className: "accent-primary"
|
|
600
|
-
}
|
|
601
|
-
),
|
|
602
|
-
"Open in new tab"
|
|
603
|
-
] })
|
|
604
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
605
|
-
/* @__PURE__ */ jsxs(
|
|
606
|
-
"select",
|
|
607
|
-
{
|
|
608
|
-
autoFocus: true,
|
|
609
|
-
"aria-label": "Page",
|
|
610
|
-
value: pageId,
|
|
611
|
-
onChange: (e) => {
|
|
612
|
-
setPageId(e.target.value);
|
|
613
|
-
setAnchorId("");
|
|
614
|
-
},
|
|
615
|
-
className: selectClasses,
|
|
616
|
-
children: [
|
|
617
|
-
/* @__PURE__ */ jsx7("option", { value: "", children: "Select a page\u2026" }),
|
|
618
|
-
pages.map((p) => /* @__PURE__ */ jsx7("option", { value: p.id, children: p.title }, p.id))
|
|
619
|
-
]
|
|
620
|
-
}
|
|
621
|
-
),
|
|
622
|
-
/* @__PURE__ */ jsxs(
|
|
623
|
-
"select",
|
|
624
|
-
{
|
|
625
|
-
"aria-label": "Section",
|
|
626
|
-
value: anchorId,
|
|
627
|
-
disabled: !pageId,
|
|
628
|
-
onChange: (e) => setAnchorId(e.target.value),
|
|
629
|
-
className: cn(selectClasses, !pageId && "cursor-not-allowed opacity-50"),
|
|
630
|
-
children: [
|
|
631
|
-
/* @__PURE__ */ jsx7("option", { value: "", children: "None (top of page)" }),
|
|
632
|
-
headings.map((h) => /* @__PURE__ */ jsx7("option", { value: h.id, children: h.label }, h.id))
|
|
633
|
-
]
|
|
634
|
-
}
|
|
635
|
-
)
|
|
636
|
-
] }),
|
|
637
|
-
/* @__PURE__ */ jsxs("div", { className: "flex gap-2", children: [
|
|
638
|
-
/* @__PURE__ */ jsx7(
|
|
639
|
-
Button,
|
|
640
|
-
{
|
|
641
|
-
variant: "brand",
|
|
642
|
-
size: "sm",
|
|
643
|
-
onMouseDown: (e) => {
|
|
644
|
-
e.preventDefault();
|
|
645
|
-
handleApply();
|
|
646
|
-
},
|
|
647
|
-
children: "Apply"
|
|
648
|
-
}
|
|
649
|
-
),
|
|
650
|
-
hasLink && /* @__PURE__ */ jsx7(
|
|
651
|
-
Button,
|
|
652
|
-
{
|
|
653
|
-
variant: "secondary",
|
|
654
|
-
size: "sm",
|
|
655
|
-
onMouseDown: (e) => {
|
|
656
|
-
e.preventDefault();
|
|
657
|
-
handleRemove();
|
|
658
|
-
},
|
|
659
|
-
children: "Remove"
|
|
660
|
-
}
|
|
661
|
-
),
|
|
662
|
-
/* @__PURE__ */ jsx7(
|
|
663
|
-
Button,
|
|
664
|
-
{
|
|
665
|
-
variant: "secondary",
|
|
666
|
-
size: "sm",
|
|
667
|
-
onMouseDown: (e) => {
|
|
668
|
-
e.preventDefault();
|
|
669
|
-
onClose();
|
|
670
|
-
},
|
|
671
|
-
children: "Cancel"
|
|
672
|
-
}
|
|
673
|
-
)
|
|
674
|
-
] })
|
|
675
|
-
]
|
|
676
|
-
}
|
|
677
|
-
);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
// src/components/primitives/RichTextToolbar.tsx
|
|
681
|
-
import { Fragment as Fragment2, jsx as jsx8, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
682
|
-
function ToolbarButton({ isActive, onClick, title, children }) {
|
|
683
|
-
return /* @__PURE__ */ jsx8(
|
|
684
|
-
"button",
|
|
685
|
-
{
|
|
686
|
-
type: "button",
|
|
687
|
-
title,
|
|
688
|
-
"aria-label": title,
|
|
689
|
-
"aria-pressed": isActive,
|
|
690
|
-
onMouseDown: (e) => {
|
|
691
|
-
e.preventDefault();
|
|
692
|
-
onClick();
|
|
693
|
-
},
|
|
694
|
-
className: cn(
|
|
695
|
-
"cursor-pointer rounded px-2 py-1 text-sm font-medium transition-colors",
|
|
696
|
-
isActive ? "bg-primary text-primary-contrast" : "bg-base-accent text-base-contrast hover:opacity-80"
|
|
697
|
-
),
|
|
698
|
-
children
|
|
699
|
-
}
|
|
700
|
-
);
|
|
701
|
-
}
|
|
702
|
-
function Separator() {
|
|
703
|
-
return /* @__PURE__ */ jsx8("div", { className: "mx-1 h-5 w-px bg-base-contrast/20" });
|
|
704
|
-
}
|
|
705
|
-
function RichTextToolbar({ editor, preset }) {
|
|
706
|
-
const [showLinkPopover, setShowLinkPopover] = useState4(false);
|
|
707
|
-
const state = useEditorState({
|
|
708
|
-
editor,
|
|
709
|
-
selector: ({ editor: ed }) => ({
|
|
710
|
-
isBold: ed.isActive("bold"),
|
|
711
|
-
isItalic: ed.isActive("italic"),
|
|
712
|
-
isUnderline: ed.isActive("underline"),
|
|
713
|
-
isLink: ed.isActive("link"),
|
|
714
|
-
isBulletList: ed.isActive("bulletList"),
|
|
715
|
-
isOrderedList: ed.isActive("orderedList"),
|
|
716
|
-
isH3: ed.isActive("heading", { level: 3 }),
|
|
717
|
-
isH4: ed.isActive("heading", { level: 4 }),
|
|
718
|
-
isLarge: ed.isActive("paragraph", { class: "large" }),
|
|
719
|
-
isLeadIn: ed.isActive("paragraph", { class: "lead-in" })
|
|
720
|
-
})
|
|
721
|
-
});
|
|
722
|
-
const toggleParagraphVariant = (cls, isCurrentlyActive) => {
|
|
723
|
-
if (isCurrentlyActive) {
|
|
724
|
-
editor.chain().focus().setNode("paragraph").run();
|
|
725
|
-
} else {
|
|
726
|
-
editor.chain().focus().setNode("paragraph", { class: cls }).run();
|
|
727
|
-
}
|
|
728
|
-
};
|
|
729
|
-
return /* @__PURE__ */ jsxs2(
|
|
730
|
-
"div",
|
|
731
|
-
{
|
|
732
|
-
"data-testid": "rich-text-toolbar",
|
|
733
|
-
className: "flex items-center gap-1 rounded border border-base-contrast/10 bg-base-accent p-1 shadow-md",
|
|
734
|
-
children: [
|
|
735
|
-
/* @__PURE__ */ jsx8(
|
|
736
|
-
ToolbarButton,
|
|
737
|
-
{
|
|
738
|
-
isActive: state.isBold,
|
|
739
|
-
onClick: () => editor.chain().focus().toggleBold().run(),
|
|
740
|
-
title: "Bold",
|
|
741
|
-
children: /* @__PURE__ */ jsx8("strong", { children: "B" })
|
|
742
|
-
}
|
|
743
|
-
),
|
|
744
|
-
/* @__PURE__ */ jsx8(
|
|
745
|
-
ToolbarButton,
|
|
746
|
-
{
|
|
747
|
-
isActive: state.isItalic,
|
|
748
|
-
onClick: () => editor.chain().focus().toggleItalic().run(),
|
|
749
|
-
title: "Italic",
|
|
750
|
-
children: /* @__PURE__ */ jsx8("em", { children: "I" })
|
|
751
|
-
}
|
|
752
|
-
),
|
|
753
|
-
/* @__PURE__ */ jsx8(
|
|
754
|
-
ToolbarButton,
|
|
755
|
-
{
|
|
756
|
-
isActive: state.isUnderline,
|
|
757
|
-
onClick: () => editor.chain().focus().toggleUnderline().run(),
|
|
758
|
-
title: "Underline",
|
|
759
|
-
children: /* @__PURE__ */ jsx8("span", { className: "underline", children: "U" })
|
|
760
|
-
}
|
|
761
|
-
),
|
|
762
|
-
preset === "rich" && /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
763
|
-
/* @__PURE__ */ jsx8(Separator, {}),
|
|
764
|
-
/* @__PURE__ */ jsxs2("div", { className: "relative", children: [
|
|
765
|
-
/* @__PURE__ */ jsx8(
|
|
766
|
-
ToolbarButton,
|
|
767
|
-
{
|
|
768
|
-
isActive: state.isLink || showLinkPopover,
|
|
769
|
-
onClick: () => setShowLinkPopover((prev) => !prev),
|
|
770
|
-
title: "Link",
|
|
771
|
-
children: "\u{1F517}"
|
|
772
|
-
}
|
|
773
|
-
),
|
|
774
|
-
showLinkPopover && /* @__PURE__ */ jsx8("div", { className: "absolute left-0 top-full z-50 mt-1", children: /* @__PURE__ */ jsx8(
|
|
775
|
-
LinkPopover,
|
|
776
|
-
{
|
|
777
|
-
editor,
|
|
778
|
-
onClose: () => setShowLinkPopover(false)
|
|
779
|
-
}
|
|
780
|
-
) })
|
|
781
|
-
] }),
|
|
782
|
-
/* @__PURE__ */ jsx8(Separator, {}),
|
|
783
|
-
/* @__PURE__ */ jsx8(
|
|
784
|
-
ToolbarButton,
|
|
785
|
-
{
|
|
786
|
-
isActive: state.isBulletList,
|
|
787
|
-
onClick: () => editor.chain().focus().toggleBulletList().run(),
|
|
788
|
-
title: "Bullet List",
|
|
789
|
-
children: "\u2022\u2261"
|
|
790
|
-
}
|
|
791
|
-
),
|
|
792
|
-
/* @__PURE__ */ jsx8(
|
|
793
|
-
ToolbarButton,
|
|
794
|
-
{
|
|
795
|
-
isActive: state.isOrderedList,
|
|
796
|
-
onClick: () => editor.chain().focus().toggleOrderedList().run(),
|
|
797
|
-
title: "Ordered List",
|
|
798
|
-
children: "1\u2261"
|
|
799
|
-
}
|
|
800
|
-
),
|
|
801
|
-
/* @__PURE__ */ jsx8(Separator, {}),
|
|
802
|
-
/* @__PURE__ */ jsx8(
|
|
803
|
-
ToolbarButton,
|
|
804
|
-
{
|
|
805
|
-
isActive: state.isH3,
|
|
806
|
-
onClick: () => editor.chain().focus().toggleHeading({ level: 3 }).run(),
|
|
807
|
-
title: "Heading 3",
|
|
808
|
-
children: "H3"
|
|
809
|
-
}
|
|
810
|
-
),
|
|
811
|
-
/* @__PURE__ */ jsx8(
|
|
812
|
-
ToolbarButton,
|
|
813
|
-
{
|
|
814
|
-
isActive: state.isH4,
|
|
815
|
-
onClick: () => editor.chain().focus().toggleHeading({ level: 4 }).run(),
|
|
816
|
-
title: "Heading 4",
|
|
817
|
-
children: "H4"
|
|
818
|
-
}
|
|
819
|
-
),
|
|
820
|
-
/* @__PURE__ */ jsx8(
|
|
821
|
-
ToolbarButton,
|
|
822
|
-
{
|
|
823
|
-
isActive: state.isLarge,
|
|
824
|
-
onClick: () => toggleParagraphVariant("large", state.isLarge),
|
|
825
|
-
title: "Large Paragraph",
|
|
826
|
-
children: "Lg"
|
|
827
|
-
}
|
|
828
|
-
),
|
|
829
|
-
/* @__PURE__ */ jsx8(
|
|
830
|
-
ToolbarButton,
|
|
831
|
-
{
|
|
832
|
-
isActive: state.isLeadIn,
|
|
833
|
-
onClick: () => toggleParagraphVariant("lead-in", state.isLeadIn),
|
|
834
|
-
title: "Lead-In",
|
|
835
|
-
children: "Li"
|
|
836
|
-
}
|
|
837
|
-
)
|
|
838
|
-
] })
|
|
839
|
-
]
|
|
840
|
-
}
|
|
841
|
-
);
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
// src/components/primitives/EditableRichText.tsx
|
|
845
|
-
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
846
|
-
function isContentEmpty(html) {
|
|
847
|
-
return html.replace(/<[^>]*>/g, "").trim().length === 0;
|
|
848
|
-
}
|
|
849
|
-
var DEFAULT_PLACEHOLDER = "Click to edit\u2026";
|
|
850
|
-
function EditableRichText({
|
|
851
|
-
value,
|
|
852
|
-
onChange,
|
|
853
|
-
isEditMode,
|
|
854
|
-
preset = "rich",
|
|
855
|
-
className,
|
|
856
|
-
placeholder = DEFAULT_PLACEHOLDER
|
|
857
|
-
}) {
|
|
858
|
-
const { isEditorActive, editor, activate, deactivate } = useEditableRichText({ value, onChange, preset, placeholder });
|
|
859
|
-
const wrapperRef = useRef4(null);
|
|
860
|
-
const blurTimeoutRef = useRef4(null);
|
|
861
|
-
const clickCoordsRef = useRef4(null);
|
|
862
|
-
useEffect4(() => {
|
|
863
|
-
return () => {
|
|
864
|
-
if (blurTimeoutRef.current) {
|
|
865
|
-
clearTimeout(blurTimeoutRef.current);
|
|
866
|
-
}
|
|
867
|
-
};
|
|
868
|
-
}, []);
|
|
869
|
-
useEffect4(() => {
|
|
870
|
-
if (!isEditorActive || !editor) return;
|
|
871
|
-
requestAnimationFrame(() => {
|
|
872
|
-
if (editor.isDestroyed) return;
|
|
873
|
-
const coords = clickCoordsRef.current;
|
|
874
|
-
if (coords) {
|
|
875
|
-
try {
|
|
876
|
-
const pos = editor.view.posAtCoords(coords);
|
|
877
|
-
if (pos) {
|
|
878
|
-
editor.commands.focus();
|
|
879
|
-
editor.commands.setTextSelection(pos.pos);
|
|
880
|
-
} else {
|
|
881
|
-
editor.commands.focus("end");
|
|
882
|
-
}
|
|
883
|
-
} catch {
|
|
884
|
-
editor.commands.focus("end");
|
|
885
|
-
} finally {
|
|
886
|
-
clickCoordsRef.current = null;
|
|
887
|
-
}
|
|
888
|
-
} else {
|
|
889
|
-
editor.commands.focus("end");
|
|
890
|
-
}
|
|
891
|
-
});
|
|
892
|
-
}, [isEditorActive, editor]);
|
|
893
|
-
const handleClick = useCallback4((e) => {
|
|
894
|
-
if (isEditMode && !isEditorActive) {
|
|
895
|
-
clickCoordsRef.current = { left: e.clientX, top: e.clientY };
|
|
896
|
-
activate();
|
|
897
|
-
}
|
|
898
|
-
}, [isEditMode, isEditorActive, activate]);
|
|
899
|
-
const handleFocus = useCallback4(() => {
|
|
900
|
-
if (blurTimeoutRef.current) {
|
|
901
|
-
clearTimeout(blurTimeoutRef.current);
|
|
902
|
-
blurTimeoutRef.current = null;
|
|
903
|
-
}
|
|
904
|
-
}, []);
|
|
905
|
-
const handleBlur = useCallback4(() => {
|
|
906
|
-
blurTimeoutRef.current = setTimeout(() => {
|
|
907
|
-
if (wrapperRef.current && !wrapperRef.current.contains(document.activeElement)) {
|
|
908
|
-
deactivate();
|
|
909
|
-
}
|
|
910
|
-
}, 150);
|
|
911
|
-
}, [deactivate]);
|
|
912
|
-
if (!isEditMode) {
|
|
913
|
-
return /* @__PURE__ */ jsx9(
|
|
914
|
-
"div",
|
|
915
|
-
{
|
|
916
|
-
className,
|
|
917
|
-
dangerouslySetInnerHTML: { __html: sanitizeHtml(value) }
|
|
918
|
-
}
|
|
919
|
-
);
|
|
920
|
-
}
|
|
921
|
-
if (!isEditorActive || !editor) {
|
|
922
|
-
const empty = isContentEmpty(value);
|
|
923
|
-
if (empty) {
|
|
924
|
-
return /* @__PURE__ */ jsx9("div", { className, onClick: handleClick, children: /* @__PURE__ */ jsx9("p", { className: "tiptap-placeholder", children: placeholder }) });
|
|
925
|
-
}
|
|
926
|
-
return /* @__PURE__ */ jsx9(
|
|
927
|
-
"div",
|
|
928
|
-
{
|
|
929
|
-
className,
|
|
930
|
-
onClick: handleClick,
|
|
931
|
-
dangerouslySetInnerHTML: { __html: sanitizeHtml(value) }
|
|
932
|
-
}
|
|
933
|
-
);
|
|
934
|
-
}
|
|
935
|
-
return /* @__PURE__ */ jsxs3(
|
|
936
|
-
"div",
|
|
937
|
-
{
|
|
938
|
-
ref: wrapperRef,
|
|
939
|
-
className,
|
|
940
|
-
onFocus: handleFocus,
|
|
941
|
-
onBlur: handleBlur,
|
|
942
|
-
children: [
|
|
943
|
-
/* @__PURE__ */ jsx9(
|
|
944
|
-
BubbleMenu,
|
|
945
|
-
{
|
|
946
|
-
editor,
|
|
947
|
-
className: "z-50",
|
|
948
|
-
shouldShow: ({ editor: ed, state }) => {
|
|
949
|
-
const { from, to } = state.selection;
|
|
950
|
-
return ed.isFocused && from !== to;
|
|
951
|
-
},
|
|
952
|
-
children: /* @__PURE__ */ jsx9(RichTextToolbar, { editor, preset })
|
|
953
|
-
}
|
|
954
|
-
),
|
|
955
|
-
/* @__PURE__ */ jsx9(EditorContent, { editor })
|
|
956
|
-
]
|
|
957
|
-
}
|
|
958
|
-
);
|
|
959
|
-
}
|
|
960
|
-
|
|
961
107
|
// src/components/sections/Prose/Prose.tsx
|
|
962
|
-
import { jsx as
|
|
108
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
963
109
|
function Prose({ body, onChange }) {
|
|
964
110
|
if (onChange) {
|
|
965
|
-
return /* @__PURE__ */
|
|
111
|
+
return /* @__PURE__ */ jsx4("div", { className: "prose-content", children: /* @__PURE__ */ jsx4(
|
|
966
112
|
EditableRichText,
|
|
967
113
|
{
|
|
968
114
|
value: body,
|
|
@@ -973,7 +119,7 @@ function Prose({ body, onChange }) {
|
|
|
973
119
|
}
|
|
974
120
|
) });
|
|
975
121
|
}
|
|
976
|
-
return /* @__PURE__ */
|
|
122
|
+
return /* @__PURE__ */ jsx4(
|
|
977
123
|
"div",
|
|
978
124
|
{
|
|
979
125
|
className: "prose-content",
|
|
@@ -982,254 +128,51 @@ function Prose({ body, onChange }) {
|
|
|
982
128
|
);
|
|
983
129
|
}
|
|
984
130
|
|
|
985
|
-
// src/lib/text.ts
|
|
986
|
-
function stripHtmlToPlainText(html) {
|
|
987
|
-
return html.replace(/<(script|style)\b[^>]*>[\s\S]*?<\/\1>/gi, "").replace(/<[^>]+>/g, " ").replace(/\s+/g, " ").trim();
|
|
988
|
-
}
|
|
989
|
-
function truncate(text, maxLength) {
|
|
990
|
-
if (text.length <= maxLength) return text;
|
|
991
|
-
return text.slice(0, maxLength) + "...";
|
|
992
|
-
}
|
|
993
|
-
function pluralize(n, word) {
|
|
994
|
-
return `${n} ${word}${n === 1 ? "" : "s"}`;
|
|
995
|
-
}
|
|
996
|
-
|
|
997
131
|
// src/components/sections/Prose/index.tsx
|
|
998
|
-
import { jsx as
|
|
999
|
-
var schema =
|
|
1000
|
-
type:
|
|
1001
|
-
content:
|
|
132
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
133
|
+
var schema = z.object({
|
|
134
|
+
type: z.literal("prose"),
|
|
135
|
+
content: z.object({ body: z.string() })
|
|
1002
136
|
});
|
|
1003
137
|
var Prose_default = defineSection({
|
|
1004
138
|
type: "prose",
|
|
1005
139
|
label: "Prose",
|
|
1006
|
-
icon: /* @__PURE__ */
|
|
140
|
+
icon: /* @__PURE__ */ jsx5(AlignLeft, { size: 18 }),
|
|
1007
141
|
schema,
|
|
1008
142
|
richTextFields: ["body"],
|
|
1009
|
-
component: ({ content, onChange }) => /* @__PURE__ */
|
|
143
|
+
component: ({ content, onChange }) => /* @__PURE__ */ jsx5(Prose, { body: content.content.body, onChange: onChange ? (c) => onChange(c) : void 0 }),
|
|
1010
144
|
defaults: () => ({ type: "prose", content: { body: "<p></p>" } }),
|
|
1011
145
|
getLabel: (content) => truncate(stripHtmlToPlainText(content.content.body), 60)
|
|
1012
146
|
});
|
|
1013
147
|
|
|
1014
148
|
// src/components/sections/Media/index.tsx
|
|
1015
|
-
import { z as
|
|
1016
|
-
import { Image as
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
// src/components/primitives/ResolvedMedia.tsx
|
|
1022
|
-
import { ImageIcon } from "lucide-react";
|
|
1023
|
-
|
|
1024
|
-
// src/hooks/useResolvedMedia.ts
|
|
1025
|
-
import { useMemo } from "react";
|
|
1026
|
-
|
|
1027
|
-
// src/components/shell/MediaLibraryContext.tsx
|
|
1028
|
-
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
1029
|
-
var MediaLibraryContext = createContext2(null);
|
|
1030
|
-
function useMediaLibrary() {
|
|
1031
|
-
return useContext2(MediaLibraryContext);
|
|
1032
|
-
}
|
|
1033
|
-
|
|
1034
|
-
// src/hooks/useResolvedMedia.ts
|
|
1035
|
-
function useResolvedMedia(imageId) {
|
|
1036
|
-
const ctx = useMediaLibrary();
|
|
1037
|
-
return useMemo(() => {
|
|
1038
|
-
if (!imageId || !ctx) {
|
|
1039
|
-
return { src: void 0, srcset: void 0, poster: void 0, alt: "", kind: "image" };
|
|
1040
|
-
}
|
|
1041
|
-
const { manifest, pendingItems, pendingLocalUrls, siteConfig } = ctx;
|
|
1042
|
-
const sizes = siteConfig?.media?.sizes ?? [640, 1080, 1920];
|
|
1043
|
-
const manifestItem = manifest.images[imageId];
|
|
1044
|
-
const pendingItem = pendingItems.find((i) => i.id === imageId);
|
|
1045
|
-
const item = manifestItem ?? pendingItem;
|
|
1046
|
-
const alt = item?.alt ?? "";
|
|
1047
|
-
const kind = item?.kind ?? "image";
|
|
1048
|
-
const localUrl = pendingLocalUrls[imageId];
|
|
1049
|
-
if (localUrl) {
|
|
1050
|
-
return { src: localUrl, srcset: void 0, poster: void 0, alt, kind };
|
|
1051
|
-
}
|
|
1052
|
-
if (manifestItem) {
|
|
1053
|
-
const provider = getMediaProvider();
|
|
1054
|
-
const resolved = provider.resolve(manifestItem, sizes);
|
|
1055
|
-
if (resolved && resolved.tag === "img") {
|
|
1056
|
-
return {
|
|
1057
|
-
src: resolved.src,
|
|
1058
|
-
srcset: "srcSet" in resolved ? resolved.srcSet : void 0,
|
|
1059
|
-
poster: void 0,
|
|
1060
|
-
alt,
|
|
1061
|
-
kind
|
|
1062
|
-
};
|
|
1063
|
-
}
|
|
1064
|
-
if (resolved && resolved.tag === "video") {
|
|
1065
|
-
return { src: resolved.src, srcset: void 0, poster: resolved.poster, alt, kind };
|
|
1066
|
-
}
|
|
1067
|
-
}
|
|
1068
|
-
return { src: void 0, srcset: void 0, poster: void 0, alt, kind };
|
|
1069
|
-
}, [imageId, ctx]);
|
|
1070
|
-
}
|
|
1071
|
-
|
|
1072
|
-
// src/components/primitives/ResolvedMedia.tsx
|
|
1073
|
-
import { jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1074
|
-
function ResolvedMedia({
|
|
1075
|
-
imageId,
|
|
1076
|
-
src: propSrc,
|
|
1077
|
-
srcset: propSrcset,
|
|
1078
|
-
alt: propAlt,
|
|
1079
|
-
className,
|
|
1080
|
-
imgClassName,
|
|
1081
|
-
invertFrom
|
|
1082
|
-
}) {
|
|
1083
|
-
const resolved = useResolvedMedia(imageId);
|
|
1084
|
-
const src = propSrc || resolved.src;
|
|
1085
|
-
const srcset = propSrcset || resolved.srcset;
|
|
1086
|
-
const poster = resolved.poster;
|
|
1087
|
-
const alt = propAlt ?? resolved.alt;
|
|
1088
|
-
const kind = resolved.kind;
|
|
1089
|
-
const invertClass = invertFrom === "light" ? "invert dark:invert-0" : invertFrom === "dark" ? "dark:invert" : void 0;
|
|
1090
|
-
const mediaClass = cn("h-full w-full", imgClassName, invertClass);
|
|
1091
|
-
return /* @__PURE__ */ jsx12("div", { className, children: src ? kind === "video" ? /* @__PURE__ */ jsx12("video", { src, poster, muted: true, playsInline: true, loop: true, autoPlay: true, className: mediaClass }) : /* @__PURE__ */ jsx12("img", { src, srcSet: srcset, alt, className: mediaClass }) : /* @__PURE__ */ jsxs4("div", { className: "flex aspect-video h-full w-full flex-col items-center justify-center gap-1 rounded bg-base-accent text-base-contrast-light/50", children: [
|
|
1092
|
-
/* @__PURE__ */ jsx12(ImageIcon, { size: 24 }),
|
|
1093
|
-
/* @__PURE__ */ jsx12("span", { className: "text-sm", children: "No Image" })
|
|
1094
|
-
] }) });
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
// src/components/primitives/ImageDropZone.tsx
|
|
1098
|
-
import { useState as useState5 } from "react";
|
|
1099
|
-
import { Fragment as Fragment3, jsx as jsx13, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1100
|
-
var ACCEPTED = /^(image|video)\//;
|
|
1101
|
-
function ImageDropZone({ onImageSelected, className, children }) {
|
|
1102
|
-
const mediaLibrary = useMediaLibrary();
|
|
1103
|
-
const [dragging, setDragging] = useState5(false);
|
|
1104
|
-
if (!mediaLibrary) return /* @__PURE__ */ jsx13(Fragment3, { children });
|
|
1105
|
-
const maxFileSize = mediaLibrary.siteConfig?.media.maxFileSize;
|
|
1106
|
-
const hasFiles = (e) => e.dataTransfer.types.includes("Files");
|
|
1107
|
-
const handleDragOver = (e) => {
|
|
1108
|
-
if (!hasFiles(e)) return;
|
|
1109
|
-
e.preventDefault();
|
|
1110
|
-
e.dataTransfer.dropEffect = "copy";
|
|
1111
|
-
setDragging(true);
|
|
1112
|
-
};
|
|
1113
|
-
const handleDragLeave = (e) => {
|
|
1114
|
-
if (!hasFiles(e)) return;
|
|
1115
|
-
const related = e.relatedTarget;
|
|
1116
|
-
if (related && e.currentTarget.contains(related)) return;
|
|
1117
|
-
setDragging(false);
|
|
1118
|
-
};
|
|
1119
|
-
const handleDrop = (e) => {
|
|
1120
|
-
if (!hasFiles(e)) return;
|
|
1121
|
-
e.preventDefault();
|
|
1122
|
-
e.stopPropagation();
|
|
1123
|
-
setDragging(false);
|
|
1124
|
-
const file = e.dataTransfer.files[0];
|
|
1125
|
-
if (!file) return;
|
|
1126
|
-
if (!ACCEPTED.test(file.type)) {
|
|
1127
|
-
mediaLibrary.reportRejectedUploads([{ name: file.name, reason: "type" }]);
|
|
1128
|
-
return;
|
|
1129
|
-
}
|
|
1130
|
-
if (maxFileSize && file.size > maxFileSize) {
|
|
1131
|
-
mediaLibrary.reportRejectedUploads([{ name: file.name, reason: "size" }]);
|
|
1132
|
-
return;
|
|
1133
|
-
}
|
|
1134
|
-
mediaLibrary.uploadFileWithCallback(file, onImageSelected);
|
|
1135
|
-
};
|
|
1136
|
-
return /* @__PURE__ */ jsxs5(
|
|
1137
|
-
"div",
|
|
1138
|
-
{
|
|
1139
|
-
className: cn("relative", className),
|
|
1140
|
-
onDragOver: handleDragOver,
|
|
1141
|
-
onDragLeave: handleDragLeave,
|
|
1142
|
-
onDrop: handleDrop,
|
|
1143
|
-
children: [
|
|
1144
|
-
children,
|
|
1145
|
-
dragging && /* @__PURE__ */ jsx13("div", { className: "pointer-events-none absolute inset-0 z-10 rounded-md border-2 border-primary bg-primary/5" })
|
|
1146
|
-
]
|
|
1147
|
-
}
|
|
1148
|
-
);
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
// src/components/sections/Media/MediaBlock.tsx
|
|
1152
|
-
import { jsx as jsx14, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1153
|
-
function MediaBlock({ refValue, options, link, dodont, isEditMode, onRefChange }) {
|
|
1154
|
-
const mediaLibrary = useMediaLibrary();
|
|
1155
|
-
const fit = refValue.objectFit ?? options.objectFit;
|
|
1156
|
-
const fitClass = fit === "cover" ? "object-cover" : "object-contain";
|
|
1157
|
-
const showBorder = refValue.border ?? options.border;
|
|
1158
|
-
const captionStr = refValue.caption ? Array.isArray(refValue.caption) ? refValue.caption.join("\n") : refValue.caption : "";
|
|
1159
|
-
const replace = onRefChange ? (imageId) => onRefChange({ ...refValue, imageId }) : void 0;
|
|
1160
|
-
const resolved = /* @__PURE__ */ jsx14(
|
|
1161
|
-
ResolvedMedia,
|
|
1162
|
-
{
|
|
1163
|
-
imageId: refValue.imageId || void 0,
|
|
1164
|
-
className: "h-full w-full",
|
|
1165
|
-
imgClassName: fitClass,
|
|
1166
|
-
invertFrom: refValue.invertFrom
|
|
1167
|
-
}
|
|
1168
|
-
);
|
|
1169
|
-
let media = isEditMode && replace ? /* @__PURE__ */ jsx14(ImageDropZone, { onImageSelected: replace, className: "h-full w-full", children: resolved }) : resolved;
|
|
1170
|
-
if (!isEditMode && link && link.kind === "external" && link.href) {
|
|
1171
|
-
media = /* @__PURE__ */ jsx14("a", { href: link.href, target: link.target, className: "group block", children: media });
|
|
1172
|
-
}
|
|
1173
|
-
const onImageClick = isEditMode && replace && mediaLibrary ? () => mediaLibrary.openSelectModal((imageId) => replace(imageId)) : void 0;
|
|
1174
|
-
return /* @__PURE__ */ jsxs6("figure", { children: [
|
|
1175
|
-
dodont && /* @__PURE__ */ jsx14("div", { className: "flex h-10 items-center justify-center pb-1", children: dodont === "do" ? /* @__PURE__ */ jsx14(Check, { size: 28, className: "text-green-600" }) : /* @__PURE__ */ jsx14(X, { size: 28, className: "text-red-600" }) }),
|
|
1176
|
-
/* @__PURE__ */ jsx14(
|
|
1177
|
-
"div",
|
|
1178
|
-
{
|
|
1179
|
-
"data-testid": "media-open-surface",
|
|
1180
|
-
className: cn(
|
|
1181
|
-
"overflow-hidden rounded-md",
|
|
1182
|
-
showBorder && "border border-base-200",
|
|
1183
|
-
options.square && "aspect-square",
|
|
1184
|
-
onImageClick && "cursor-pointer"
|
|
1185
|
-
),
|
|
1186
|
-
onClick: onImageClick,
|
|
1187
|
-
onPointerDown: onImageClick ? (e) => e.stopPropagation() : void 0,
|
|
1188
|
-
children: media
|
|
1189
|
-
}
|
|
1190
|
-
),
|
|
1191
|
-
options.showCaption && /* @__PURE__ */ jsx14("figcaption", { className: "mt-2 min-h-[1em] text-sm text-base-contrast-light", children: isEditMode && onRefChange ? /* @__PURE__ */ jsx14(
|
|
1192
|
-
EditablePlainText,
|
|
1193
|
-
{
|
|
1194
|
-
tag: "span",
|
|
1195
|
-
value: captionStr,
|
|
1196
|
-
onChange: (caption) => onRefChange({ ...refValue, caption: caption || void 0 }),
|
|
1197
|
-
isEditMode: true,
|
|
1198
|
-
placeholder: "Caption",
|
|
1199
|
-
className: "block min-h-[1em]"
|
|
1200
|
-
}
|
|
1201
|
-
) : captionStr || " " })
|
|
1202
|
-
] });
|
|
1203
|
-
}
|
|
1204
|
-
|
|
1205
|
-
// src/components/sections/Media/index.tsx
|
|
1206
|
-
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
1207
|
-
var schema2 = z3.object({
|
|
1208
|
-
type: z3.literal("media"),
|
|
1209
|
-
content: z3.object({
|
|
149
|
+
import { z as z2 } from "zod";
|
|
150
|
+
import { Image as ImageIcon } from "lucide-react";
|
|
151
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
152
|
+
var schema2 = z2.object({
|
|
153
|
+
type: z2.literal("media"),
|
|
154
|
+
content: z2.object({
|
|
1210
155
|
ref: SingleMediaReferenceSchema,
|
|
1211
|
-
link: LinkValueSchema.optional()
|
|
1212
|
-
dodont: z3.enum(["do", "dont"]).optional()
|
|
156
|
+
link: LinkValueSchema.optional()
|
|
1213
157
|
}),
|
|
1214
|
-
options:
|
|
1215
|
-
square:
|
|
1216
|
-
showCaption:
|
|
1217
|
-
border:
|
|
1218
|
-
objectFit:
|
|
158
|
+
options: z2.object({
|
|
159
|
+
square: z2.boolean().optional(),
|
|
160
|
+
showCaption: z2.boolean().optional(),
|
|
161
|
+
border: z2.boolean().optional(),
|
|
162
|
+
objectFit: z2.enum(["cover", "contain"]).optional()
|
|
1219
163
|
}).default({})
|
|
1220
164
|
});
|
|
1221
165
|
var Media_default = defineSection({
|
|
1222
166
|
type: "media",
|
|
1223
167
|
label: "Media",
|
|
1224
|
-
icon: /* @__PURE__ */
|
|
168
|
+
icon: /* @__PURE__ */ jsx6(ImageIcon, { size: 18 }),
|
|
1225
169
|
schema: schema2,
|
|
1226
|
-
component: ({ content, options, onChange }) => /* @__PURE__ */
|
|
170
|
+
component: ({ content, options, onChange }) => /* @__PURE__ */ jsx6(
|
|
1227
171
|
MediaBlock,
|
|
1228
172
|
{
|
|
1229
173
|
refValue: content.content.ref,
|
|
1230
174
|
options: options ?? {},
|
|
1231
175
|
link: content.content.link,
|
|
1232
|
-
dodont: content.content.dodont,
|
|
1233
176
|
isEditMode: !!onChange,
|
|
1234
177
|
onRefChange: onChange ? (ref) => onChange({ ...content, content: { ...content.content, ref } }) : void 0
|
|
1235
178
|
}
|
|
@@ -1242,1863 +185,126 @@ var Media_default = defineSection({
|
|
|
1242
185
|
getLabel: () => "Media",
|
|
1243
186
|
getThumbnails: (content) => content.content.ref.imageId ? [{ type: "image", src: content.content.ref.imageId }] : [],
|
|
1244
187
|
settings: {
|
|
1245
|
-
square: { type: "checkbox", label: "Square aspect ratio", default: false },
|
|
1246
|
-
showCaption: { type: "checkbox", label: "Show caption", default: false },
|
|
1247
|
-
border: { type: "checkbox", label: "Border", default: false },
|
|
1248
|
-
objectFit: {
|
|
1249
|
-
type: "select",
|
|
1250
|
-
label: "Image fit",
|
|
1251
|
-
default: "contain",
|
|
1252
|
-
options: [
|
|
1253
|
-
{ label: "Contain", value: "contain" },
|
|
1254
|
-
{ label: "Cover", value: "cover" }
|
|
1255
|
-
]
|
|
1256
|
-
},
|
|
1257
|
-
link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" },
|
|
1258
|
-
dodont: {
|
|
1259
|
-
type: "select",
|
|
1260
|
-
label: "Do / Don't",
|
|
1261
|
-
target: "content",
|
|
1262
|
-
default: "",
|
|
1263
|
-
emptyIsUndefined: true,
|
|
1264
|
-
options: [
|
|
1265
|
-
{ label: "None", value: "" },
|
|
1266
|
-
{ label: "Do", value: "do" },
|
|
1267
|
-
{ label: "Don't", value: "dont" }
|
|
1268
|
-
]
|
|
1269
|
-
}
|
|
1270
|
-
},
|
|
1271
|
-
inheritableSettings: ["square", "showCaption", "border", "objectFit"],
|
|
1272
|
-
settingsTabs: [
|
|
1273
|
-
{ label: "Display", fields: ["square", "showCaption", "border", "objectFit"] },
|
|
1274
|
-
{ label: "Link", fields: ["link"] },
|
|
1275
|
-
{ label: "Do / Don't", fields: ["dodont"] }
|
|
1276
|
-
]
|
|
1277
|
-
});
|
|
1278
|
-
|
|
1279
|
-
// src/components/sections/Button/index.tsx
|
|
1280
|
-
import { z as z4 } from "zod";
|
|
1281
|
-
import { RectangleHorizontal } from "lucide-react";
|
|
1282
|
-
|
|
1283
|
-
// src/components/sections/Button/CTAButton.tsx
|
|
1284
|
-
import { Download } from "lucide-react";
|
|
1285
|
-
import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
1286
|
-
function Button3({ text, link, download, onChange }) {
|
|
1287
|
-
const base = "inline-block rounded-md px-6 py-3 font-bold transition-colors";
|
|
1288
|
-
const variant = "border-2 border-primary text-primary hover:bg-primary hover:text-primary-contrast";
|
|
1289
|
-
if (onChange) {
|
|
1290
|
-
return /* @__PURE__ */ jsxs7("span", { className: cn(base, variant, "inline-flex items-center gap-2"), children: [
|
|
1291
|
-
download && /* @__PURE__ */ jsx16(Download, { size: 16, className: "shrink-0" }),
|
|
1292
|
-
/* @__PURE__ */ jsx16(
|
|
1293
|
-
EditablePlainText,
|
|
1294
|
-
{
|
|
1295
|
-
tag: "span",
|
|
1296
|
-
value: text,
|
|
1297
|
-
onChange: (newText) => onChange({ type: "button", content: { text: newText, link, download } }),
|
|
1298
|
-
isEditMode: true,
|
|
1299
|
-
placeholder: "Button text"
|
|
1300
|
-
}
|
|
1301
|
-
)
|
|
1302
|
-
] });
|
|
1303
|
-
}
|
|
1304
|
-
const href = link && link.kind === "external" ? link.href : "";
|
|
1305
|
-
const target = link?.target;
|
|
1306
|
-
if (href) {
|
|
1307
|
-
return /* @__PURE__ */ jsxs7(
|
|
1308
|
-
"a",
|
|
1309
|
-
{
|
|
1310
|
-
href,
|
|
1311
|
-
target,
|
|
1312
|
-
download: download ? "" : void 0,
|
|
1313
|
-
className: cn(base, variant, download && "inline-flex items-center gap-2"),
|
|
1314
|
-
children: [
|
|
1315
|
-
download && /* @__PURE__ */ jsx16(Download, { size: 16, className: "shrink-0" }),
|
|
1316
|
-
text
|
|
1317
|
-
]
|
|
1318
|
-
}
|
|
1319
|
-
);
|
|
1320
|
-
}
|
|
1321
|
-
return /* @__PURE__ */ jsx16("button", { className: cn("cursor-pointer", base, variant), children: text });
|
|
1322
|
-
}
|
|
1323
|
-
|
|
1324
|
-
// src/components/sections/Button/index.tsx
|
|
1325
|
-
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1326
|
-
var schema3 = z4.object({
|
|
1327
|
-
type: z4.literal("button"),
|
|
1328
|
-
content: z4.object({
|
|
1329
|
-
text: z4.string(),
|
|
1330
|
-
link: LinkValueSchema.optional(),
|
|
1331
|
-
download: z4.boolean().optional()
|
|
1332
|
-
})
|
|
1333
|
-
});
|
|
1334
|
-
var Button_default = defineSection({
|
|
1335
|
-
type: "button",
|
|
1336
|
-
label: "Button",
|
|
1337
|
-
icon: /* @__PURE__ */ jsx17(RectangleHorizontal, { size: 18 }),
|
|
1338
|
-
schema: schema3,
|
|
1339
|
-
component: ({ content, onChange }) => /* @__PURE__ */ jsx17(
|
|
1340
|
-
Button3,
|
|
1341
|
-
{
|
|
1342
|
-
text: content.content.text,
|
|
1343
|
-
link: content.content.link,
|
|
1344
|
-
download: content.content.download,
|
|
1345
|
-
onChange: onChange ? (c) => onChange(c) : void 0
|
|
1346
|
-
}
|
|
1347
|
-
),
|
|
1348
|
-
defaults: () => ({ type: "button", content: { text: "Button" } }),
|
|
1349
|
-
getLabel: (content) => content.content.text,
|
|
1350
|
-
settings: {
|
|
1351
|
-
link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" },
|
|
1352
|
-
download: { type: "checkbox", label: "Download link", default: false, target: "content" }
|
|
1353
|
-
}
|
|
1354
|
-
});
|
|
1355
|
-
|
|
1356
|
-
// src/components/sections/Colors/index.tsx
|
|
1357
|
-
import { z as z5 } from "zod";
|
|
1358
|
-
import { Palette } from "lucide-react";
|
|
1359
|
-
|
|
1360
|
-
// src/components/brandguide/Colors.tsx
|
|
1361
|
-
import { useState as useState9, useEffect as useEffect7 } from "react";
|
|
1362
|
-
import { Eye, EyeOff } from "lucide-react";
|
|
1363
|
-
|
|
1364
|
-
// src/lib/container-grid.ts
|
|
1365
|
-
var MAX_CONTAINER_COLUMNS = 6;
|
|
1366
|
-
var containerGridClass = {
|
|
1367
|
-
1: "grid-cols-1",
|
|
1368
|
-
2: "grid-cols-1 @sm:grid-cols-2",
|
|
1369
|
-
3: "grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-3",
|
|
1370
|
-
4: "grid-cols-1 @xs:grid-cols-2 @lg:grid-cols-4",
|
|
1371
|
-
5: "grid-cols-1 @xs:grid-cols-2 @md:grid-cols-3 @xl:grid-cols-5",
|
|
1372
|
-
6: "grid-cols-1 @xs:grid-cols-2 @md:grid-cols-3 @2xl:grid-cols-6"
|
|
1373
|
-
};
|
|
1374
|
-
var colSpanClass = {
|
|
1375
|
-
1: { 1: "" },
|
|
1376
|
-
2: { 1: "", 2: "col-span-1 @sm:col-span-2" },
|
|
1377
|
-
3: { 1: "", 2: "col-span-1 @sm:col-span-2", 3: "col-span-1 @sm:col-span-2 @lg:col-span-3" },
|
|
1378
|
-
4: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @lg:col-span-3", 4: "col-span-1 @xs:col-span-2 @lg:col-span-4" },
|
|
1379
|
-
5: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @md:col-span-3", 4: "col-span-1 @xs:col-span-2 @md:col-span-3 @xl:col-span-4", 5: "col-span-1 @xs:col-span-2 @md:col-span-3 @xl:col-span-5" },
|
|
1380
|
-
6: { 1: "", 2: "col-span-1 @xs:col-span-2", 3: "col-span-1 @xs:col-span-2 @md:col-span-3", 4: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-4", 5: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-5", 6: "col-span-1 @xs:col-span-2 @md:col-span-3 @2xl:col-span-6" }
|
|
1381
|
-
};
|
|
1382
|
-
var spacerHiddenClass = {
|
|
1383
|
-
1: "hidden",
|
|
1384
|
-
2: "hidden @sm:block",
|
|
1385
|
-
3: "hidden @sm:block",
|
|
1386
|
-
4: "hidden @xs:block",
|
|
1387
|
-
5: "hidden @xs:block",
|
|
1388
|
-
6: "hidden @xs:block"
|
|
1389
|
-
};
|
|
1390
|
-
|
|
1391
|
-
// src/components/primitives/EditableGrid.tsx
|
|
1392
|
-
import { useRef as useRef6, useEffect as useEffect6, useState as useState7 } from "react";
|
|
1393
|
-
import { ImageIcon as ImageIcon3 } from "lucide-react";
|
|
1394
|
-
|
|
1395
|
-
// src/components/shared/icons.tsx
|
|
1396
|
-
import { GripVertical, Plus, Trash2, X as X2, Settings } from "lucide-react";
|
|
1397
|
-
import { GripVertical as GripVertical2, Plus as Plus2, Trash2 as Trash22, X as X3, Settings as Settings2 } from "lucide-react";
|
|
1398
|
-
import { jsx as jsx18 } from "react/jsx-runtime";
|
|
1399
|
-
function DragHandle({ size = 16 }) {
|
|
1400
|
-
return /* @__PURE__ */ jsx18(GripVertical, { size });
|
|
1401
|
-
}
|
|
1402
|
-
function AddIcon({ size = 14 }) {
|
|
1403
|
-
return /* @__PURE__ */ jsx18(Plus, { size });
|
|
1404
|
-
}
|
|
1405
|
-
function DeleteIcon({ size = 14 }) {
|
|
1406
|
-
return /* @__PURE__ */ jsx18(Trash2, { size });
|
|
1407
|
-
}
|
|
1408
|
-
function SettingsIcon({ size = 14 }) {
|
|
1409
|
-
return /* @__PURE__ */ jsx18(Settings, { size });
|
|
1410
|
-
}
|
|
1411
|
-
|
|
1412
|
-
// src/components/shared/IconButton.tsx
|
|
1413
|
-
import { forwardRef as forwardRef2 } from "react";
|
|
1414
|
-
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1415
|
-
var sizeClasses = {
|
|
1416
|
-
sm: "h-chrome-sm w-chrome-sm",
|
|
1417
|
-
md: "h-chrome-md w-chrome-md",
|
|
1418
|
-
lg: "h-chrome-lg w-chrome-lg"
|
|
1419
|
-
};
|
|
1420
|
-
var intentClasses = {
|
|
1421
|
-
default: "text-base-contrast-light hover:text-base-contrast",
|
|
1422
|
-
destructive: "text-destructive hover:text-destructive-hover",
|
|
1423
|
-
primary: "text-primary/60 hover:text-primary"
|
|
1424
|
-
};
|
|
1425
|
-
var IconButton = forwardRef2(
|
|
1426
|
-
function IconButton2({ icon, label, size = "md", intent = "default", className, ...rest }, ref) {
|
|
1427
|
-
return /* @__PURE__ */ jsx19(
|
|
1428
|
-
"button",
|
|
1429
|
-
{
|
|
1430
|
-
ref,
|
|
1431
|
-
type: "button",
|
|
1432
|
-
className: cn(
|
|
1433
|
-
"cursor-pointer flex items-center justify-center rounded transition-colors",
|
|
1434
|
-
sizeClasses[size],
|
|
1435
|
-
intentClasses[intent],
|
|
1436
|
-
className
|
|
1437
|
-
),
|
|
1438
|
-
"aria-label": label,
|
|
1439
|
-
...rest,
|
|
1440
|
-
children: icon
|
|
1441
|
-
}
|
|
1442
|
-
);
|
|
1443
|
-
}
|
|
1444
|
-
);
|
|
1445
|
-
|
|
1446
|
-
// src/components/primitives/useEditableCollection.ts
|
|
1447
|
-
import { useState as useState6, useCallback as useCallback5, useRef as useRef5, useEffect as useEffect5 } from "react";
|
|
1448
|
-
var nextId = 0;
|
|
1449
|
-
function uid() {
|
|
1450
|
-
return typeof crypto !== "undefined" && typeof crypto.randomUUID === "function" ? crypto.randomUUID() : `_id_${nextId++}_${Date.now()}`;
|
|
1451
|
-
}
|
|
1452
|
-
function wrapItems(items) {
|
|
1453
|
-
return items.map((data) => ({ id: uid(), data }));
|
|
1454
|
-
}
|
|
1455
|
-
function useEditableCollection({
|
|
1456
|
-
items,
|
|
1457
|
-
onChange,
|
|
1458
|
-
createItem
|
|
1459
|
-
}) {
|
|
1460
|
-
const [wrappedItems, setWrappedItems] = useState6(
|
|
1461
|
-
() => wrapItems(items)
|
|
1462
|
-
);
|
|
1463
|
-
const prevItemsRef = useRef5(items);
|
|
1464
|
-
useEffect5(() => {
|
|
1465
|
-
if (items === prevItemsRef.current) return;
|
|
1466
|
-
prevItemsRef.current = items;
|
|
1467
|
-
setWrappedItems((prev) => {
|
|
1468
|
-
return items.map((data, i) => {
|
|
1469
|
-
if (i < prev.length) {
|
|
1470
|
-
return { id: prev[i].id, data };
|
|
1471
|
-
}
|
|
1472
|
-
return { id: uid(), data };
|
|
1473
|
-
});
|
|
1474
|
-
});
|
|
1475
|
-
}, [items]);
|
|
1476
|
-
const onReorder = useCallback5(
|
|
1477
|
-
(fromIndex, toIndex) => {
|
|
1478
|
-
setWrappedItems((prev) => {
|
|
1479
|
-
const next = [...prev];
|
|
1480
|
-
const [moved] = next.splice(fromIndex, 1);
|
|
1481
|
-
next.splice(toIndex, 0, moved);
|
|
1482
|
-
onChange(next.map((w) => w.data));
|
|
1483
|
-
return next;
|
|
1484
|
-
});
|
|
1485
|
-
},
|
|
1486
|
-
[onChange]
|
|
1487
|
-
);
|
|
1488
|
-
const onAdd = useCallback5(() => {
|
|
1489
|
-
const newItem = createItem();
|
|
1490
|
-
setWrappedItems((prev) => {
|
|
1491
|
-
const next = [...prev, { id: uid(), data: newItem }];
|
|
1492
|
-
onChange(next.map((w) => w.data));
|
|
1493
|
-
return next;
|
|
1494
|
-
});
|
|
1495
|
-
}, [createItem, onChange]);
|
|
1496
|
-
const onInsert = useCallback5(
|
|
1497
|
-
(index) => {
|
|
1498
|
-
const newItem = createItem();
|
|
1499
|
-
setWrappedItems((prev) => {
|
|
1500
|
-
const next = [...prev];
|
|
1501
|
-
next.splice(index, 0, { id: uid(), data: newItem });
|
|
1502
|
-
onChange(next.map((w) => w.data));
|
|
1503
|
-
return next;
|
|
1504
|
-
});
|
|
1505
|
-
},
|
|
1506
|
-
[createItem, onChange]
|
|
1507
|
-
);
|
|
1508
|
-
const onRemove = useCallback5(
|
|
1509
|
-
(id) => {
|
|
1510
|
-
setWrappedItems((prev) => {
|
|
1511
|
-
const next = prev.filter((w) => w.id !== id);
|
|
1512
|
-
onChange(next.map((w) => w.data));
|
|
1513
|
-
return next;
|
|
1514
|
-
});
|
|
1515
|
-
},
|
|
1516
|
-
[onChange]
|
|
1517
|
-
);
|
|
1518
|
-
return { wrappedItems, onReorder, onAdd, onInsert, onRemove };
|
|
1519
|
-
}
|
|
1520
|
-
|
|
1521
|
-
// src/components/primitives/EditableGrid.tsx
|
|
1522
|
-
import { jsx as jsx20, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1523
|
-
function EditableGrid({
|
|
1524
|
-
items,
|
|
1525
|
-
columns,
|
|
1526
|
-
onChange,
|
|
1527
|
-
createItem,
|
|
1528
|
-
isEditMode,
|
|
1529
|
-
renderItem,
|
|
1530
|
-
onItemSettings,
|
|
1531
|
-
onItemImageClick,
|
|
1532
|
-
chromeTopClass,
|
|
1533
|
-
className
|
|
1534
|
-
}) {
|
|
1535
|
-
const { wrappedItems, onReorder, onAdd, onInsert, onRemove } = useEditableCollection({
|
|
1536
|
-
items,
|
|
1537
|
-
onChange,
|
|
1538
|
-
createItem
|
|
1539
|
-
});
|
|
1540
|
-
const [dragState, setDragState] = useState7({ sourceId: null, closestEdge: null });
|
|
1541
|
-
const [isDragging, setIsDragging] = useState7(false);
|
|
1542
|
-
useEffect6(() => {
|
|
1543
|
-
let cleanup;
|
|
1544
|
-
let cancelled = false;
|
|
1545
|
-
import("../../adapter-HH47ZPGM.js").then(({ monitorForElements }) => {
|
|
1546
|
-
if (cancelled) return;
|
|
1547
|
-
cleanup = monitorForElements({
|
|
1548
|
-
onDragStart: ({ source }) => {
|
|
1549
|
-
if (source.data.dragType === "grid-cell") setIsDragging(true);
|
|
1550
|
-
},
|
|
1551
|
-
onDrop: ({ source }) => {
|
|
1552
|
-
if (source.data.dragType === "grid-cell") setIsDragging(false);
|
|
1553
|
-
}
|
|
1554
|
-
});
|
|
1555
|
-
});
|
|
1556
|
-
return () => {
|
|
1557
|
-
cancelled = true;
|
|
1558
|
-
cleanup?.();
|
|
1559
|
-
};
|
|
1560
|
-
}, []);
|
|
1561
|
-
if (!isEditMode) {
|
|
1562
|
-
return /* @__PURE__ */ jsx20("div", { className: "@container", children: /* @__PURE__ */ jsx20("div", { className: cn("grid gap-4", containerGridClass[columns] || containerGridClass[1], className), children: wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx20("div", { children: renderItem(wrapped.data, { isEditMode: false, index }) }, wrapped.id)) }) });
|
|
1563
|
-
}
|
|
1564
|
-
return /* @__PURE__ */ jsx20("div", { className: "@container", children: /* @__PURE__ */ jsxs8("div", { className: cn("group/grid relative grid gap-4", containerGridClass[columns] || containerGridClass[1], className), children: [
|
|
1565
|
-
wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx20(
|
|
1566
|
-
GridCell,
|
|
1567
|
-
{
|
|
1568
|
-
id: wrapped.id,
|
|
1569
|
-
index,
|
|
1570
|
-
isLast: index === wrappedItems.length - 1,
|
|
1571
|
-
isDragging,
|
|
1572
|
-
onReorder,
|
|
1573
|
-
onRemove,
|
|
1574
|
-
onInsert,
|
|
1575
|
-
onSettings: onItemSettings ? () => onItemSettings(index) : void 0,
|
|
1576
|
-
onImageClick: onItemImageClick ? () => onItemImageClick(index) : void 0,
|
|
1577
|
-
chromeTopClass,
|
|
1578
|
-
dragState,
|
|
1579
|
-
setDragState,
|
|
1580
|
-
children: renderItem(wrapped.data, { isEditMode: true, index })
|
|
1581
|
-
},
|
|
1582
|
-
wrapped.id
|
|
1583
|
-
)),
|
|
1584
|
-
/* @__PURE__ */ jsx20(
|
|
1585
|
-
IconButton,
|
|
1586
|
-
{
|
|
1587
|
-
icon: /* @__PURE__ */ jsx20(AddIcon, { size: 16 }),
|
|
1588
|
-
label: "Add item",
|
|
1589
|
-
size: "lg",
|
|
1590
|
-
intent: "primary",
|
|
1591
|
-
onClick: onAdd,
|
|
1592
|
-
className: "absolute -bottom-6 left-1/2 z-20 -translate-x-1/2 rounded-full border border-base-200 bg-base opacity-0 transition-opacity group-hover/grid:opacity-100"
|
|
1593
|
-
}
|
|
1594
|
-
)
|
|
1595
|
-
] }) });
|
|
1596
|
-
}
|
|
1597
|
-
function GridCell({
|
|
1598
|
-
id,
|
|
1599
|
-
index,
|
|
1600
|
-
isLast,
|
|
1601
|
-
isDragging,
|
|
1602
|
-
onReorder,
|
|
1603
|
-
onRemove,
|
|
1604
|
-
onInsert,
|
|
1605
|
-
onSettings,
|
|
1606
|
-
onImageClick,
|
|
1607
|
-
chromeTopClass,
|
|
1608
|
-
dragState,
|
|
1609
|
-
setDragState,
|
|
1610
|
-
children
|
|
1611
|
-
}) {
|
|
1612
|
-
const cellRef = useRef6(null);
|
|
1613
|
-
const handleRef = useRef6(null);
|
|
1614
|
-
useEffect6(() => {
|
|
1615
|
-
const cell = cellRef.current;
|
|
1616
|
-
const handle = handleRef.current;
|
|
1617
|
-
if (!cell || !handle) return;
|
|
1618
|
-
let cleanup;
|
|
1619
|
-
let cancelled = false;
|
|
1620
|
-
Promise.all([
|
|
1621
|
-
import("../../adapter-HH47ZPGM.js"),
|
|
1622
|
-
import("../../closest-edge-EBOXL3YW.js")
|
|
1623
|
-
]).then(([{ draggable, dropTargetForElements }, { attachClosestEdge, extractClosestEdge }]) => {
|
|
1624
|
-
if (cancelled) return;
|
|
1625
|
-
const cleanupDraggable = draggable({
|
|
1626
|
-
element: handle,
|
|
1627
|
-
getInitialData: () => ({ dragType: "grid-cell", id, index }),
|
|
1628
|
-
onDragStart: () => setDragState({ sourceId: id, closestEdge: null }),
|
|
1629
|
-
onDrop: () => setDragState({ sourceId: null, closestEdge: null })
|
|
1630
|
-
});
|
|
1631
|
-
const cleanupDropTarget = dropTargetForElements({
|
|
1632
|
-
element: cell,
|
|
1633
|
-
canDrop: ({ source }) => source.data.dragType === "grid-cell",
|
|
1634
|
-
getData: ({ input, element }) => attachClosestEdge(
|
|
1635
|
-
{ id, index },
|
|
1636
|
-
{ input, element, allowedEdges: ["left", "right"] }
|
|
1637
|
-
),
|
|
1638
|
-
onDragEnter: ({ self }) => {
|
|
1639
|
-
const edge = extractClosestEdge(self.data);
|
|
1640
|
-
if (edge) setDragState((prev) => ({ ...prev, closestEdge: { id, edge } }));
|
|
1641
|
-
},
|
|
1642
|
-
onDrag: ({ self }) => {
|
|
1643
|
-
const edge = extractClosestEdge(self.data);
|
|
1644
|
-
if (edge) setDragState((prev) => ({ ...prev, closestEdge: { id, edge } }));
|
|
1645
|
-
},
|
|
1646
|
-
onDragLeave: () => {
|
|
1647
|
-
setDragState((prev) => prev.closestEdge?.id === id ? { ...prev, closestEdge: null } : prev);
|
|
1648
|
-
},
|
|
1649
|
-
onDrop: ({ source, self }) => {
|
|
1650
|
-
const fromIndex = source.data.index;
|
|
1651
|
-
const edge = extractClosestEdge(self.data);
|
|
1652
|
-
let toIndex = index;
|
|
1653
|
-
if (edge === "right") toIndex = index + 1;
|
|
1654
|
-
if (fromIndex < toIndex) toIndex--;
|
|
1655
|
-
if (fromIndex !== toIndex) {
|
|
1656
|
-
onReorder(fromIndex, toIndex);
|
|
1657
|
-
}
|
|
1658
|
-
}
|
|
1659
|
-
});
|
|
1660
|
-
cleanup = () => {
|
|
1661
|
-
cleanupDraggable();
|
|
1662
|
-
cleanupDropTarget();
|
|
1663
|
-
};
|
|
1664
|
-
});
|
|
1665
|
-
return () => {
|
|
1666
|
-
cancelled = true;
|
|
1667
|
-
cleanup?.();
|
|
1668
|
-
};
|
|
1669
|
-
}, [id, index, onReorder, setDragState]);
|
|
1670
|
-
const isCellDragging = dragState.sourceId === id;
|
|
1671
|
-
const showLeftEdge = dragState.closestEdge?.id === id && dragState.closestEdge.edge === "left" && dragState.sourceId !== id;
|
|
1672
|
-
const showRightEdge = dragState.closestEdge?.id === id && dragState.closestEdge.edge === "right" && dragState.sourceId !== id;
|
|
1673
|
-
return /* @__PURE__ */ jsxs8(
|
|
1674
|
-
"div",
|
|
1675
|
-
{
|
|
1676
|
-
ref: cellRef,
|
|
1677
|
-
className: cn(
|
|
1678
|
-
"group/cell relative",
|
|
1679
|
-
isCellDragging && "opacity-50"
|
|
1680
|
-
),
|
|
1681
|
-
children: [
|
|
1682
|
-
showLeftEdge && /* @__PURE__ */ jsx20("div", { className: "absolute top-0 bottom-0 left-0 z-10 w-0.5 -translate-x-2 bg-primary" }),
|
|
1683
|
-
showRightEdge && /* @__PURE__ */ jsx20("div", { className: "absolute top-0 right-0 bottom-0 z-10 w-0.5 translate-x-2 bg-primary" }),
|
|
1684
|
-
!isDragging && !isLast && /* @__PURE__ */ jsx20(
|
|
1685
|
-
IconButton,
|
|
1686
|
-
{
|
|
1687
|
-
icon: /* @__PURE__ */ jsx20(AddIcon, { size: 12 }),
|
|
1688
|
-
label: "Insert item",
|
|
1689
|
-
size: "sm",
|
|
1690
|
-
intent: "primary",
|
|
1691
|
-
onClick: () => onInsert(index + 1),
|
|
1692
|
-
className: "absolute top-1/2 -right-2 z-20 -translate-y-1/2 translate-x-1/2 rounded-full border border-base-200 bg-base opacity-0 group-hover/cell:opacity-100"
|
|
1693
|
-
}
|
|
1694
|
-
),
|
|
1695
|
-
/* @__PURE__ */ jsx20(
|
|
1696
|
-
IconButton,
|
|
1697
|
-
{
|
|
1698
|
-
ref: handleRef,
|
|
1699
|
-
icon: /* @__PURE__ */ jsx20(DragHandle, { size: 16 }),
|
|
1700
|
-
label: "Drag to reorder",
|
|
1701
|
-
className: cn("absolute left-1.5 z-10 cursor-grab bg-base/80 opacity-0 shadow-sm group-hover/cell:opacity-100 no-hover:opacity-100", chromeTopClass || "top-1.5"),
|
|
1702
|
-
tabIndex: -1
|
|
1703
|
-
}
|
|
1704
|
-
),
|
|
1705
|
-
/* @__PURE__ */ jsxs8("div", { className: cn("absolute right-1.5 z-10 flex items-center gap-1 opacity-0 group-hover/cell:opacity-100 no-hover:opacity-100", chromeTopClass || "top-1.5"), children: [
|
|
1706
|
-
onImageClick && /* @__PURE__ */ jsx20(
|
|
1707
|
-
IconButton,
|
|
1708
|
-
{
|
|
1709
|
-
icon: /* @__PURE__ */ jsx20(ImageIcon3, { size: 16 }),
|
|
1710
|
-
label: "Change image",
|
|
1711
|
-
onClick: onImageClick,
|
|
1712
|
-
className: "bg-base/80 shadow-sm"
|
|
1713
|
-
}
|
|
1714
|
-
),
|
|
1715
|
-
onSettings && /* @__PURE__ */ jsx20(
|
|
1716
|
-
IconButton,
|
|
1717
|
-
{
|
|
1718
|
-
icon: /* @__PURE__ */ jsx20(SettingsIcon, { size: 16 }),
|
|
1719
|
-
label: "Item settings",
|
|
1720
|
-
onClick: onSettings,
|
|
1721
|
-
className: "bg-base/80 shadow-sm"
|
|
1722
|
-
}
|
|
1723
|
-
),
|
|
1724
|
-
/* @__PURE__ */ jsx20(
|
|
1725
|
-
IconButton,
|
|
1726
|
-
{
|
|
1727
|
-
icon: /* @__PURE__ */ jsx20(DeleteIcon, { size: 16 }),
|
|
1728
|
-
label: "Delete item",
|
|
1729
|
-
intent: "destructive",
|
|
1730
|
-
onClick: () => onRemove(id),
|
|
1731
|
-
className: "bg-base/80 shadow-sm"
|
|
1732
|
-
}
|
|
1733
|
-
)
|
|
1734
|
-
] }),
|
|
1735
|
-
children
|
|
1736
|
-
]
|
|
1737
|
-
}
|
|
1738
|
-
);
|
|
1739
|
-
}
|
|
1740
|
-
|
|
1741
|
-
// src/components/brandguide/ColorSwatchSettings.tsx
|
|
1742
|
-
import { useState as useState8 } from "react";
|
|
1743
|
-
|
|
1744
|
-
// src/components/shared/Input.tsx
|
|
1745
|
-
import { forwardRef as forwardRef3, useId } from "react";
|
|
1746
|
-
|
|
1747
|
-
// src/components/shared/FormLabel.tsx
|
|
1748
|
-
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1749
|
-
function FormLabel({ htmlFor, children, className }) {
|
|
1750
|
-
return /* @__PURE__ */ jsx21(
|
|
1751
|
-
"label",
|
|
1752
|
-
{
|
|
1753
|
-
htmlFor,
|
|
1754
|
-
className: cn("mb-1.5 block text-sm font-medium text-base-contrast", className),
|
|
1755
|
-
children
|
|
1756
|
-
}
|
|
1757
|
-
);
|
|
1758
|
-
}
|
|
1759
|
-
|
|
1760
|
-
// src/components/shared/Input.tsx
|
|
1761
|
-
import { jsx as jsx22, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1762
|
-
var Input = forwardRef3(function Input2({ label, value, onChange, type = "text", className, disabled, error, ...rest }, ref) {
|
|
1763
|
-
const id = useId();
|
|
1764
|
-
const errorId = `${id}-error`;
|
|
1765
|
-
return /* @__PURE__ */ jsxs9("div", { className, children: [
|
|
1766
|
-
/* @__PURE__ */ jsx22(FormLabel, { htmlFor: id, children: label }),
|
|
1767
|
-
/* @__PURE__ */ jsx22(
|
|
1768
|
-
"input",
|
|
1769
|
-
{
|
|
1770
|
-
ref,
|
|
1771
|
-
id,
|
|
1772
|
-
type,
|
|
1773
|
-
value,
|
|
1774
|
-
onChange: (e) => onChange(e.target.value),
|
|
1775
|
-
disabled,
|
|
1776
|
-
"aria-invalid": error ? true : void 0,
|
|
1777
|
-
"aria-describedby": error ? errorId : void 0,
|
|
1778
|
-
className: cn(
|
|
1779
|
-
"w-full rounded border bg-base px-3 py-2 text-sm text-base-contrast focus:outline-none focus:ring-1",
|
|
1780
|
-
error ? "border-red-600 focus:border-red-600 focus:ring-red-600" : "border-base-200 focus:border-base-contrast focus:ring-base-contrast",
|
|
1781
|
-
disabled && "cursor-not-allowed opacity-50"
|
|
1782
|
-
),
|
|
1783
|
-
...rest
|
|
1784
|
-
}
|
|
1785
|
-
),
|
|
1786
|
-
error && /* @__PURE__ */ jsx22("p", { id: errorId, className: "mt-1 text-xs text-red-600", children: error })
|
|
1787
|
-
] });
|
|
1788
|
-
});
|
|
1789
|
-
|
|
1790
|
-
// src/components/brandguide/ColorSwatchSettings.tsx
|
|
1791
|
-
import { jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1792
|
-
function mergeSpaces(spaces) {
|
|
1793
|
-
return Object.assign({}, ...spaces);
|
|
1794
|
-
}
|
|
1795
|
-
function ColorSwatchSettings({ color, onChange }) {
|
|
1796
|
-
const [localColor, setLocalColor] = useState8(() => ({
|
|
1797
|
-
...color,
|
|
1798
|
-
spaces: [mergeSpaces(color.spaces)]
|
|
1799
|
-
}));
|
|
1800
|
-
const space = localColor.spaces[0] || {};
|
|
1801
|
-
const update = (updated) => {
|
|
1802
|
-
setLocalColor(updated);
|
|
1803
|
-
onChange(updated);
|
|
1804
|
-
};
|
|
1805
|
-
const updateSpace = (key, value) => {
|
|
1806
|
-
const newSpace = { ...space, [key]: value || void 0 };
|
|
1807
|
-
update({ ...localColor, spaces: [newSpace] });
|
|
1808
|
-
};
|
|
1809
|
-
return /* @__PURE__ */ jsxs10("div", { className: "space-y-3", children: [
|
|
1810
|
-
/* @__PURE__ */ jsx23(
|
|
1811
|
-
Input,
|
|
1812
|
-
{
|
|
1813
|
-
label: "Name",
|
|
1814
|
-
value: localColor.name || "",
|
|
1815
|
-
onChange: (name) => update({ ...localColor, name })
|
|
1816
|
-
}
|
|
1817
|
-
),
|
|
1818
|
-
["hex", "rgb", "cmyk", "pantone"].map((key) => /* @__PURE__ */ jsx23(
|
|
1819
|
-
Input,
|
|
1820
|
-
{
|
|
1821
|
-
label: key.toUpperCase(),
|
|
1822
|
-
value: space[key] || "",
|
|
1823
|
-
onChange: (value) => updateSpace(key, value)
|
|
1824
|
-
},
|
|
1825
|
-
key
|
|
1826
|
-
))
|
|
1827
|
-
] });
|
|
1828
|
-
}
|
|
1829
|
-
|
|
1830
|
-
// src/components/brandguide/Colors.tsx
|
|
1831
|
-
import { jsx as jsx24, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
1832
|
-
function getContrastClass(hex) {
|
|
1833
|
-
if (!hex) return "text-white";
|
|
1834
|
-
const h = hex.replace("#", "");
|
|
1835
|
-
if (h.length < 6) return "text-white";
|
|
1836
|
-
const r = parseInt(h.substring(0, 2), 16);
|
|
1837
|
-
const g = parseInt(h.substring(2, 4), 16);
|
|
1838
|
-
const b = parseInt(h.substring(4, 6), 16);
|
|
1839
|
-
const yiq = (r * 299 + g * 587 + b * 114) / 1e3;
|
|
1840
|
-
return yiq >= 128 ? "text-black" : "text-white";
|
|
1841
|
-
}
|
|
1842
|
-
var createColorItem = () => ({
|
|
1843
|
-
name: "",
|
|
1844
|
-
spaces: [{ hex: "#cccccc" }]
|
|
1845
|
-
});
|
|
1846
|
-
function buildContent(colors, options) {
|
|
1847
|
-
const { label, columns, collapsing, showLabel } = options;
|
|
1848
|
-
return {
|
|
1849
|
-
type: "colors",
|
|
1850
|
-
content: { colors },
|
|
1851
|
-
...label || columns || collapsing !== void 0 || showLabel !== void 0 ? { options: { label, columns, collapsing, showLabel } } : {}
|
|
1852
|
-
};
|
|
1853
|
-
}
|
|
1854
|
-
function Colors({ colors, columns = 3, label, collapsing, showLabel = true, onChange, openModal }) {
|
|
1855
|
-
if (onChange && openModal) {
|
|
1856
|
-
return /* @__PURE__ */ jsx24(
|
|
1857
|
-
ColorsEditable,
|
|
1858
|
-
{
|
|
1859
|
-
colors,
|
|
1860
|
-
columns,
|
|
1861
|
-
label,
|
|
1862
|
-
collapsing,
|
|
1863
|
-
showLabel,
|
|
1864
|
-
onChange,
|
|
1865
|
-
openModal
|
|
1866
|
-
}
|
|
1867
|
-
);
|
|
1868
|
-
}
|
|
1869
|
-
return /* @__PURE__ */ jsx24(ColorsView, { colors, columns, label, collapsing, showLabel });
|
|
1870
|
-
}
|
|
1871
|
-
function ColorsView({
|
|
1872
|
-
colors,
|
|
1873
|
-
columns,
|
|
1874
|
-
label,
|
|
1875
|
-
collapsing,
|
|
1876
|
-
showLabel
|
|
1877
|
-
}) {
|
|
1878
|
-
const [expanded, setExpanded] = useState9(!collapsing);
|
|
1879
|
-
const [copiedIndex, setCopiedIndex] = useState9(null);
|
|
1880
|
-
const handleCopy = (value, colorIndex) => {
|
|
1881
|
-
if (navigator.clipboard?.writeText) {
|
|
1882
|
-
navigator.clipboard.writeText(value);
|
|
1883
|
-
} else {
|
|
1884
|
-
const ta = document.createElement("textarea");
|
|
1885
|
-
ta.value = value;
|
|
1886
|
-
ta.style.position = "fixed";
|
|
1887
|
-
ta.style.opacity = "0";
|
|
1888
|
-
document.body.appendChild(ta);
|
|
1889
|
-
ta.select();
|
|
1890
|
-
document.execCommand("copy");
|
|
1891
|
-
document.body.removeChild(ta);
|
|
1892
|
-
}
|
|
1893
|
-
setCopiedIndex(colorIndex);
|
|
1894
|
-
setTimeout(() => setCopiedIndex(null), 1500);
|
|
1895
|
-
};
|
|
1896
|
-
return /* @__PURE__ */ jsxs11("div", { children: [
|
|
1897
|
-
(showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs11("div", { className: "mb-4 flex items-center gap-2", children: [
|
|
1898
|
-
showLabel && !!label && /* @__PURE__ */ jsx24("span", { className: "text-lg font-bold", children: label }),
|
|
1899
|
-
collapsing && /* @__PURE__ */ jsxs11(
|
|
1900
|
-
"button",
|
|
1901
|
-
{
|
|
1902
|
-
onClick: () => setExpanded(!expanded),
|
|
1903
|
-
className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast",
|
|
1904
|
-
children: [
|
|
1905
|
-
/* @__PURE__ */ jsx24("span", { children: expanded ? "Hide Details" : "Show Details" }),
|
|
1906
|
-
expanded ? /* @__PURE__ */ jsx24(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx24(Eye, { size: 16 })
|
|
1907
|
-
]
|
|
1908
|
-
}
|
|
1909
|
-
)
|
|
1910
|
-
] }),
|
|
1911
|
-
/* @__PURE__ */ jsx24("div", { className: "@container", children: /* @__PURE__ */ jsx24("div", { className: cn("grid gap-4", containerGridClass[columns] || containerGridClass[3]), children: colors.map((color, i) => {
|
|
1912
|
-
const hex = color.spaces[0]?.hex;
|
|
1913
|
-
const contrast = getContrastClass(hex);
|
|
1914
|
-
return /* @__PURE__ */ jsxs11("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
|
|
1915
|
-
/* @__PURE__ */ jsxs11("div", { className: cn("relative flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: [
|
|
1916
|
-
color.name && /* @__PURE__ */ jsx24("span", { className: "text-sm font-bold", children: color.name }),
|
|
1917
|
-
copiedIndex === i && /* @__PURE__ */ jsx24("span", { className: cn(
|
|
1918
|
-
"absolute top-2 right-2 rounded-full px-2.5 py-0.5 text-xs font-medium",
|
|
1919
|
-
getContrastClass(hex) === "text-black" ? "bg-black/15 text-black" : "bg-white/25 text-white"
|
|
1920
|
-
), children: "Copied!" })
|
|
1921
|
-
] }),
|
|
1922
|
-
expanded && /* @__PURE__ */ jsx24("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
|
|
1923
|
-
(space, j) => Object.entries(space).map(
|
|
1924
|
-
([key, value]) => value ? /* @__PURE__ */ jsxs11("button", { onClick: () => handleCopy(value, i), className: "cursor-pointer flex w-full justify-between hover:text-primary", children: [
|
|
1925
|
-
/* @__PURE__ */ jsx24("span", { className: "font-medium uppercase", children: key }),
|
|
1926
|
-
/* @__PURE__ */ jsx24("span", { children: value })
|
|
1927
|
-
] }, `${j}-${key}`) : null
|
|
1928
|
-
)
|
|
1929
|
-
) })
|
|
1930
|
-
] }, i);
|
|
1931
|
-
}) }) })
|
|
1932
|
-
] });
|
|
1933
|
-
}
|
|
1934
|
-
function ColorsEditable({
|
|
1935
|
-
colors,
|
|
1936
|
-
columns,
|
|
1937
|
-
label,
|
|
1938
|
-
collapsing,
|
|
1939
|
-
showLabel,
|
|
1940
|
-
onChange,
|
|
1941
|
-
openModal
|
|
1942
|
-
}) {
|
|
1943
|
-
const [expanded, setExpanded] = useState9(!collapsing);
|
|
1944
|
-
const options = { label, columns, collapsing, showLabel };
|
|
1945
|
-
useEffect7(() => {
|
|
1946
|
-
setExpanded(!collapsing);
|
|
1947
|
-
}, [collapsing]);
|
|
1948
|
-
const handleItemSettings = (index) => {
|
|
1949
|
-
const color = colors[index];
|
|
1950
|
-
openModal(
|
|
1951
|
-
"Color Settings",
|
|
1952
|
-
/* @__PURE__ */ jsx24(ColorSwatchSettings, { color, onChange: (updated) => {
|
|
1953
|
-
const newColors = colors.map((c, i) => i === index ? updated : c);
|
|
1954
|
-
onChange(buildContent(newColors, options));
|
|
1955
|
-
} })
|
|
1956
|
-
);
|
|
1957
|
-
};
|
|
1958
|
-
return /* @__PURE__ */ jsxs11("div", { children: [
|
|
1959
|
-
(showLabel && !!label || collapsing) && /* @__PURE__ */ jsxs11("div", { className: "mb-4 flex items-center gap-2", children: [
|
|
1960
|
-
showLabel && !!label && /* @__PURE__ */ jsx24(
|
|
1961
|
-
EditablePlainText,
|
|
1962
|
-
{
|
|
1963
|
-
tag: "span",
|
|
1964
|
-
value: label,
|
|
1965
|
-
onChange: (newLabel) => onChange(buildContent(colors, { ...options, label: newLabel })),
|
|
1966
|
-
isEditMode: true,
|
|
1967
|
-
className: "text-lg font-bold"
|
|
1968
|
-
}
|
|
1969
|
-
),
|
|
1970
|
-
collapsing && /* @__PURE__ */ jsxs11(
|
|
1971
|
-
"button",
|
|
1972
|
-
{
|
|
1973
|
-
onClick: () => setExpanded(!expanded),
|
|
1974
|
-
className: "cursor-pointer ml-auto flex items-center gap-1.5 text-sm text-base-contrast-light hover:text-base-contrast",
|
|
1975
|
-
children: [
|
|
1976
|
-
/* @__PURE__ */ jsx24("span", { children: expanded ? "Hide Details" : "Show Details" }),
|
|
1977
|
-
expanded ? /* @__PURE__ */ jsx24(EyeOff, { size: 16 }) : /* @__PURE__ */ jsx24(Eye, { size: 16 })
|
|
1978
|
-
]
|
|
1979
|
-
}
|
|
1980
|
-
)
|
|
1981
|
-
] }),
|
|
1982
|
-
/* @__PURE__ */ jsx24(
|
|
1983
|
-
EditableGrid,
|
|
1984
|
-
{
|
|
1985
|
-
items: colors,
|
|
1986
|
-
columns,
|
|
1987
|
-
onChange: (newColors) => onChange(buildContent(newColors, options)),
|
|
1988
|
-
createItem: createColorItem,
|
|
1989
|
-
isEditMode: true,
|
|
1990
|
-
onItemSettings: handleItemSettings,
|
|
1991
|
-
renderItem: (color, { index }) => /* @__PURE__ */ jsx24(
|
|
1992
|
-
ColorSwatchEditable,
|
|
1993
|
-
{
|
|
1994
|
-
color,
|
|
1995
|
-
index,
|
|
1996
|
-
colors,
|
|
1997
|
-
options,
|
|
1998
|
-
onChange,
|
|
1999
|
-
expanded
|
|
2000
|
-
}
|
|
2001
|
-
)
|
|
2002
|
-
}
|
|
2003
|
-
)
|
|
2004
|
-
] });
|
|
2005
|
-
}
|
|
2006
|
-
function ColorSwatchEditable({
|
|
2007
|
-
color,
|
|
2008
|
-
index,
|
|
2009
|
-
colors,
|
|
2010
|
-
options,
|
|
2011
|
-
onChange,
|
|
2012
|
-
expanded
|
|
2013
|
-
}) {
|
|
2014
|
-
const hex = color.spaces[0]?.hex;
|
|
2015
|
-
const contrast = getContrastClass(hex);
|
|
2016
|
-
const updateColor = (updated) => {
|
|
2017
|
-
const newColors = colors.map((c, i) => i === index ? updated : c);
|
|
2018
|
-
onChange(buildContent(newColors, options));
|
|
2019
|
-
};
|
|
2020
|
-
return /* @__PURE__ */ jsxs11("div", { className: "overflow-hidden rounded-md border border-base-200", children: [
|
|
2021
|
-
/* @__PURE__ */ jsx24("div", { className: cn("flex min-h-[80px] items-end p-3", contrast), style: { backgroundColor: hex || "#ccc" }, children: /* @__PURE__ */ jsx24(
|
|
2022
|
-
EditablePlainText,
|
|
2023
|
-
{
|
|
2024
|
-
tag: "span",
|
|
2025
|
-
value: color.name || "",
|
|
2026
|
-
onChange: (name) => updateColor({ ...color, name }),
|
|
2027
|
-
isEditMode: true,
|
|
2028
|
-
placeholder: "Color name",
|
|
2029
|
-
className: "text-sm font-bold"
|
|
2030
|
-
}
|
|
2031
|
-
) }),
|
|
2032
|
-
expanded && /* @__PURE__ */ jsx24("div", { className: "space-y-1 bg-base-accent p-3 text-sm", children: color.spaces.map(
|
|
2033
|
-
(space, j) => Object.entries(space).map(
|
|
2034
|
-
([key, value]) => value ? /* @__PURE__ */ jsxs11("div", { className: "flex w-full justify-between", children: [
|
|
2035
|
-
/* @__PURE__ */ jsx24("span", { className: "font-medium uppercase", children: key }),
|
|
2036
|
-
/* @__PURE__ */ jsx24("span", { children: value })
|
|
2037
|
-
] }, `${j}-${key}`) : null
|
|
2038
|
-
)
|
|
2039
|
-
) })
|
|
2040
|
-
] });
|
|
2041
|
-
}
|
|
2042
|
-
|
|
2043
|
-
// src/components/sections/Colors/index.tsx
|
|
2044
|
-
import { jsx as jsx25 } from "react/jsx-runtime";
|
|
2045
|
-
var schema4 = z5.object({
|
|
2046
|
-
type: z5.literal("colors"),
|
|
2047
|
-
content: z5.object({ colors: z5.array(ColorItemSchema) }),
|
|
2048
|
-
options: z5.object({
|
|
2049
|
-
label: z5.string().optional(),
|
|
2050
|
-
columns: z5.number().int().min(2).max(4).optional(),
|
|
2051
|
-
collapsing: z5.boolean().optional(),
|
|
2052
|
-
showLabel: z5.boolean().optional()
|
|
2053
|
-
}).optional()
|
|
2054
|
-
});
|
|
2055
|
-
var Colors_default = defineSection({
|
|
2056
|
-
type: "colors",
|
|
2057
|
-
label: "Colors",
|
|
2058
|
-
icon: /* @__PURE__ */ jsx25(Palette, { size: 18 }),
|
|
2059
|
-
schema: schema4,
|
|
2060
|
-
component: ({ content, options, onChange, openModal }) => /* @__PURE__ */ jsx25(
|
|
2061
|
-
Colors,
|
|
2062
|
-
{
|
|
2063
|
-
colors: content.content.colors,
|
|
2064
|
-
columns: options?.columns,
|
|
2065
|
-
label: options?.label,
|
|
2066
|
-
collapsing: options?.collapsing,
|
|
2067
|
-
showLabel: options?.showLabel,
|
|
2068
|
-
onChange: onChange ? (c) => onChange(c) : void 0,
|
|
2069
|
-
openModal
|
|
2070
|
-
}
|
|
2071
|
-
),
|
|
2072
|
-
defaults: () => ({
|
|
2073
|
-
type: "colors",
|
|
2074
|
-
content: { colors: [{ spaces: [{ hex: "#000000" }] }] }
|
|
2075
|
-
}),
|
|
2076
|
-
getLabel: (content) => pluralize(content.content.colors.length, "color"),
|
|
2077
|
-
getThumbnails: (content) => content.content.colors.filter((c) => c.spaces[0]?.hex).map((c) => ({ type: "color", value: c.spaces[0].hex })),
|
|
2078
|
-
settings: {
|
|
2079
|
-
columns: {
|
|
2080
|
-
type: "select",
|
|
2081
|
-
label: "Columns",
|
|
2082
|
-
default: "3",
|
|
2083
|
-
coerce: "number",
|
|
2084
|
-
options: [{ label: "2", value: "2" }, { label: "3", value: "3" }, { label: "4", value: "4" }]
|
|
2085
|
-
},
|
|
2086
|
-
label: { type: "text", label: "Label", default: "", placeholder: "Color Section Label" },
|
|
2087
|
-
showLabel: { type: "checkbox", label: "Show label", default: true },
|
|
2088
|
-
collapsing: { type: "checkbox", label: "Collapsing layout", default: false }
|
|
2089
|
-
}
|
|
2090
|
-
});
|
|
2091
|
-
|
|
2092
|
-
// src/components/sections/IconList/index.tsx
|
|
2093
|
-
import { z as z6 } from "zod";
|
|
2094
|
-
import { List } from "lucide-react";
|
|
2095
|
-
|
|
2096
|
-
// src/components/sections/IconList/IconList.tsx
|
|
2097
|
-
import { useRef as useRef8, useEffect as useEffect9, useState as useState11, useCallback as useCallback6 } from "react";
|
|
2098
|
-
import { CopyPlus, Pencil } from "lucide-react";
|
|
2099
|
-
|
|
2100
|
-
// src/components/primitives/IconPicker.tsx
|
|
2101
|
-
import { useEffect as useEffect8, useRef as useRef7, useState as useState10 } from "react";
|
|
2102
|
-
import { Check as Check2, X as X4 } from "lucide-react";
|
|
2103
|
-
import { Fragment as Fragment4, jsx as jsx26, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
2104
|
-
function IconPicker({
|
|
2105
|
-
selected,
|
|
2106
|
-
onSelect,
|
|
2107
|
-
onClose,
|
|
2108
|
-
showRemove = true,
|
|
2109
|
-
allowDoDont = false,
|
|
2110
|
-
dodont,
|
|
2111
|
-
onSelectDoDont
|
|
2112
|
-
}) {
|
|
2113
|
-
const panelRef = useRef7(null);
|
|
2114
|
-
const [mode, setMode] = useState10(dodont ? "dodont" : "none");
|
|
2115
|
-
useEffect8(() => {
|
|
2116
|
-
function handleMouseDown(e) {
|
|
2117
|
-
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
2118
|
-
onClose();
|
|
2119
|
-
}
|
|
2120
|
-
}
|
|
2121
|
-
document.addEventListener("mousedown", handleMouseDown);
|
|
2122
|
-
return () => document.removeEventListener("mousedown", handleMouseDown);
|
|
2123
|
-
}, [onClose]);
|
|
2124
|
-
const showDoDont = allowDoDont && mode === "dodont";
|
|
2125
|
-
return /* @__PURE__ */ jsxs12(
|
|
2126
|
-
"div",
|
|
2127
|
-
{
|
|
2128
|
-
ref: panelRef,
|
|
2129
|
-
className: "absolute z-50 w-56 rounded-lg border border-base-200 bg-base p-2 shadow-lg",
|
|
2130
|
-
children: [
|
|
2131
|
-
allowDoDont && /* @__PURE__ */ jsxs12("div", { role: "tablist", "aria-label": "Icon mode", className: "mb-2 flex gap-1 rounded-md bg-base-200 p-0.5", children: [
|
|
2132
|
-
/* @__PURE__ */ jsx26(
|
|
2133
|
-
"button",
|
|
2134
|
-
{
|
|
2135
|
-
type: "button",
|
|
2136
|
-
role: "tab",
|
|
2137
|
-
"aria-label": "None",
|
|
2138
|
-
"aria-selected": mode === "none",
|
|
2139
|
-
className: cn(
|
|
2140
|
-
"cursor-pointer flex-1 rounded px-2 py-1 text-xs font-medium transition-colors",
|
|
2141
|
-
mode === "none" ? "bg-base text-base-contrast shadow-sm" : "text-base-contrast-light hover:text-base-contrast"
|
|
2142
|
-
),
|
|
2143
|
-
onClick: () => {
|
|
2144
|
-
setMode("none");
|
|
2145
|
-
onSelectDoDont?.(void 0);
|
|
2146
|
-
},
|
|
2147
|
-
children: "None"
|
|
2148
|
-
}
|
|
2149
|
-
),
|
|
2150
|
-
/* @__PURE__ */ jsx26(
|
|
2151
|
-
"button",
|
|
2152
|
-
{
|
|
2153
|
-
type: "button",
|
|
2154
|
-
role: "tab",
|
|
2155
|
-
"aria-label": "Do / Don't",
|
|
2156
|
-
"aria-selected": mode === "dodont",
|
|
2157
|
-
className: cn(
|
|
2158
|
-
"cursor-pointer flex-1 rounded px-2 py-1 text-xs font-medium transition-colors",
|
|
2159
|
-
mode === "dodont" ? "bg-base text-base-contrast shadow-sm" : "text-base-contrast-light hover:text-base-contrast"
|
|
2160
|
-
),
|
|
2161
|
-
onClick: () => setMode("dodont"),
|
|
2162
|
-
children: "Do / Don't"
|
|
2163
|
-
}
|
|
2164
|
-
)
|
|
2165
|
-
] }),
|
|
2166
|
-
showDoDont ? /* @__PURE__ */ jsxs12("div", { className: "grid grid-cols-2 gap-2", children: [
|
|
2167
|
-
/* @__PURE__ */ jsxs12(
|
|
2168
|
-
"button",
|
|
2169
|
-
{
|
|
2170
|
-
type: "button",
|
|
2171
|
-
"aria-label": "Do",
|
|
2172
|
-
className: cn(
|
|
2173
|
-
"cursor-pointer flex flex-col items-center justify-center gap-1 rounded py-2 transition-colors",
|
|
2174
|
-
"text-green-600 hover:bg-base-accent",
|
|
2175
|
-
dodont === "do" && "ring-2 ring-primary bg-base-accent"
|
|
2176
|
-
),
|
|
2177
|
-
onClick: () => onSelectDoDont?.("do"),
|
|
2178
|
-
children: [
|
|
2179
|
-
/* @__PURE__ */ jsx26(Check2, { size: 20 }),
|
|
2180
|
-
/* @__PURE__ */ jsx26("span", { className: "text-xs font-medium", children: "Do" })
|
|
2181
|
-
]
|
|
2182
|
-
}
|
|
2183
|
-
),
|
|
2184
|
-
/* @__PURE__ */ jsxs12(
|
|
2185
|
-
"button",
|
|
2186
|
-
{
|
|
2187
|
-
type: "button",
|
|
2188
|
-
"aria-label": "Don't",
|
|
2189
|
-
className: cn(
|
|
2190
|
-
"cursor-pointer flex flex-col items-center justify-center gap-1 rounded py-2 transition-colors",
|
|
2191
|
-
"text-red-600 hover:bg-base-accent",
|
|
2192
|
-
dodont === "dont" && "ring-2 ring-primary bg-base-accent"
|
|
2193
|
-
),
|
|
2194
|
-
onClick: () => onSelectDoDont?.("dont"),
|
|
2195
|
-
children: [
|
|
2196
|
-
/* @__PURE__ */ jsx26(X4, { size: 20 }),
|
|
2197
|
-
/* @__PURE__ */ jsx26("span", { className: "text-xs font-medium", children: "Don't" })
|
|
2198
|
-
]
|
|
2199
|
-
}
|
|
2200
|
-
)
|
|
2201
|
-
] }) : /* @__PURE__ */ jsxs12(Fragment4, { children: [
|
|
2202
|
-
/* @__PURE__ */ jsx26("div", { className: "grid grid-cols-5 gap-1", children: curatedIcons.map((entry) => {
|
|
2203
|
-
const Icon = entry.icon;
|
|
2204
|
-
const isSelected = selected === entry.id;
|
|
2205
|
-
return /* @__PURE__ */ jsx26(
|
|
2206
|
-
"button",
|
|
2207
|
-
{
|
|
2208
|
-
"aria-label": entry.label,
|
|
2209
|
-
className: cn(
|
|
2210
|
-
"cursor-pointer flex h-9 w-9 items-center justify-center rounded transition-colors",
|
|
2211
|
-
"text-base-contrast-light hover:bg-base-accent hover:text-base-contrast",
|
|
2212
|
-
isSelected && "ring-2 ring-primary bg-base-accent text-primary"
|
|
2213
|
-
),
|
|
2214
|
-
onClick: () => onSelect(entry.id),
|
|
2215
|
-
children: /* @__PURE__ */ jsx26(Icon, { size: 18 })
|
|
2216
|
-
},
|
|
2217
|
-
entry.id
|
|
2218
|
-
);
|
|
2219
|
-
}) }),
|
|
2220
|
-
showRemove && /* @__PURE__ */ jsx26(
|
|
2221
|
-
"button",
|
|
2222
|
-
{
|
|
2223
|
-
className: "cursor-pointer mt-2 w-full rounded px-2 py-1.5 text-center text-xs text-base-contrast-light hover:bg-base-accent hover:text-base-contrast",
|
|
2224
|
-
onClick: () => onSelect(null),
|
|
2225
|
-
children: "Remove icon"
|
|
2226
|
-
}
|
|
2227
|
-
)
|
|
2228
|
-
] })
|
|
2229
|
-
]
|
|
2230
|
-
}
|
|
2231
|
-
);
|
|
2232
|
-
}
|
|
2233
|
-
|
|
2234
|
-
// src/components/sections/IconList/IconList.tsx
|
|
2235
|
-
import { jsx as jsx27, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
2236
|
-
function IconList({
|
|
2237
|
-
items,
|
|
2238
|
-
icon = null,
|
|
2239
|
-
showLabel = true,
|
|
2240
|
-
stackText = false,
|
|
2241
|
-
labelClassName = "font-bold text-base-contrast",
|
|
2242
|
-
textClassName = "text-base-contrast-light",
|
|
2243
|
-
iconClassName = "text-primary",
|
|
2244
|
-
onChange,
|
|
2245
|
-
onItemsChange
|
|
2246
|
-
}) {
|
|
2247
|
-
const isEditMode = !!onChange || !!onItemsChange;
|
|
2248
|
-
const emitItems = useCallback6(
|
|
2249
|
-
(newItems) => {
|
|
2250
|
-
onChange?.({
|
|
2251
|
-
type: "icon_list",
|
|
2252
|
-
content: { items: newItems },
|
|
2253
|
-
options: { icon, showLabel, stackText }
|
|
2254
|
-
});
|
|
2255
|
-
onItemsChange?.(newItems);
|
|
2256
|
-
},
|
|
2257
|
-
[onChange, onItemsChange, icon, showLabel, stackText]
|
|
2258
|
-
);
|
|
2259
|
-
if (!isEditMode) {
|
|
2260
|
-
return /* @__PURE__ */ jsx27(
|
|
2261
|
-
ViewIconList,
|
|
2262
|
-
{
|
|
2263
|
-
items,
|
|
2264
|
-
defaultIcon: icon,
|
|
2265
|
-
showLabel,
|
|
2266
|
-
stackText,
|
|
2267
|
-
labelClassName,
|
|
2268
|
-
textClassName,
|
|
2269
|
-
iconClassName
|
|
2270
|
-
}
|
|
2271
|
-
);
|
|
2272
|
-
}
|
|
2273
|
-
return /* @__PURE__ */ jsx27(
|
|
2274
|
-
EditIconList,
|
|
2275
|
-
{
|
|
2276
|
-
items,
|
|
2277
|
-
defaultIcon: icon,
|
|
2278
|
-
showLabel,
|
|
2279
|
-
stackText,
|
|
2280
|
-
labelClassName,
|
|
2281
|
-
textClassName,
|
|
2282
|
-
iconClassName,
|
|
2283
|
-
onItemsChange: emitItems
|
|
2284
|
-
}
|
|
2285
|
-
);
|
|
2286
|
-
}
|
|
2287
|
-
function resolveIcon(item, defaultIcon) {
|
|
2288
|
-
if (item.dodont === "do") return getIcon("check") ?? null;
|
|
2289
|
-
if (item.dodont === "dont") return getIcon("x") ?? null;
|
|
2290
|
-
const id = item.icon ?? defaultIcon;
|
|
2291
|
-
return id ? getIcon(id) : null;
|
|
2292
|
-
}
|
|
2293
|
-
function resolveIconColor(item, iconClassName) {
|
|
2294
|
-
if (item.dodont === "do") return "text-green-600";
|
|
2295
|
-
if (item.dodont === "dont") return "text-red-600";
|
|
2296
|
-
return iconClassName;
|
|
2297
|
-
}
|
|
2298
|
-
function ViewIconList({
|
|
2299
|
-
items,
|
|
2300
|
-
defaultIcon,
|
|
2301
|
-
showLabel,
|
|
2302
|
-
stackText,
|
|
2303
|
-
labelClassName,
|
|
2304
|
-
textClassName,
|
|
2305
|
-
iconClassName
|
|
2306
|
-
}) {
|
|
2307
|
-
const hasAnyIcon = items.some((item) => resolveIcon(item, defaultIcon));
|
|
2308
|
-
return /* @__PURE__ */ jsx27("div", { className: "grid gap-4 pb-4", children: items.map((item, i) => {
|
|
2309
|
-
const iconEntry = resolveIcon(item, defaultIcon);
|
|
2310
|
-
const iconColor = resolveIconColor(item, iconClassName);
|
|
2311
|
-
return /* @__PURE__ */ jsxs13(
|
|
2312
|
-
"div",
|
|
2313
|
-
{
|
|
2314
|
-
className: cn(
|
|
2315
|
-
"grid gap-x-3",
|
|
2316
|
-
hasAnyIcon ? "grid-cols-[24px_1fr]" : "grid-cols-1"
|
|
2317
|
-
),
|
|
2318
|
-
children: [
|
|
2319
|
-
hasAnyIcon && /* @__PURE__ */ jsx27(
|
|
2320
|
-
"div",
|
|
2321
|
-
{
|
|
2322
|
-
"data-testid": "icon-list-icon",
|
|
2323
|
-
className: cn("flex items-start pt-0.5", iconColor),
|
|
2324
|
-
children: iconEntry && /* @__PURE__ */ jsx27(iconEntry.icon, { size: 18 })
|
|
2325
|
-
}
|
|
2326
|
-
),
|
|
2327
|
-
/* @__PURE__ */ jsxs13(
|
|
2328
|
-
"div",
|
|
2329
|
-
{
|
|
2330
|
-
"data-testid": "icon-list-content",
|
|
2331
|
-
className: stackText ? "flex flex-col" : void 0,
|
|
2332
|
-
children: [
|
|
2333
|
-
showLabel && /* @__PURE__ */ jsxs13("span", { className: labelClassName, children: [
|
|
2334
|
-
item.label,
|
|
2335
|
-
!stackText && " "
|
|
2336
|
-
] }),
|
|
2337
|
-
/* @__PURE__ */ jsx27("span", { className: textClassName, children: item.text })
|
|
2338
|
-
]
|
|
2339
|
-
}
|
|
2340
|
-
)
|
|
2341
|
-
]
|
|
2342
|
-
},
|
|
2343
|
-
i
|
|
2344
|
-
);
|
|
2345
|
-
}) });
|
|
2346
|
-
}
|
|
2347
|
-
function EditIconList({
|
|
2348
|
-
items,
|
|
2349
|
-
defaultIcon,
|
|
2350
|
-
showLabel,
|
|
2351
|
-
stackText,
|
|
2352
|
-
labelClassName,
|
|
2353
|
-
textClassName,
|
|
2354
|
-
iconClassName,
|
|
2355
|
-
onItemsChange
|
|
2356
|
-
}) {
|
|
2357
|
-
const { wrappedItems, onReorder, onAdd, onRemove } = useEditableCollection({
|
|
2358
|
-
items,
|
|
2359
|
-
onChange: onItemsChange,
|
|
2360
|
-
createItem: () => ({ label: "", text: "" })
|
|
2361
|
-
});
|
|
2362
|
-
const [dragState, setDragState] = useState11({ sourceId: null, targetId: null });
|
|
2363
|
-
const updateItem = useCallback6(
|
|
2364
|
-
(index, patch) => {
|
|
2365
|
-
const updated = wrappedItems.map(
|
|
2366
|
-
(w, i) => i === index ? { ...w.data, ...patch } : w.data
|
|
2367
|
-
);
|
|
2368
|
-
onItemsChange(updated);
|
|
2369
|
-
},
|
|
2370
|
-
[wrappedItems, onItemsChange]
|
|
2371
|
-
);
|
|
2372
|
-
const duplicateItem = useCallback6(
|
|
2373
|
-
(index) => {
|
|
2374
|
-
const copy = { ...wrappedItems[index].data };
|
|
2375
|
-
const next = [
|
|
2376
|
-
...wrappedItems.slice(0, index + 1).map((w) => w.data),
|
|
2377
|
-
copy,
|
|
2378
|
-
...wrappedItems.slice(index + 1).map((w) => w.data)
|
|
2379
|
-
];
|
|
2380
|
-
onItemsChange(next);
|
|
2381
|
-
},
|
|
2382
|
-
[wrappedItems, onItemsChange]
|
|
2383
|
-
);
|
|
2384
|
-
const hasAnyIcon = true;
|
|
2385
|
-
return /* @__PURE__ */ jsxs13("div", { className: "group/list relative grid gap-4 pb-4", children: [
|
|
2386
|
-
wrappedItems.map((wrapped, index) => /* @__PURE__ */ jsx27(
|
|
2387
|
-
EditableRow,
|
|
2388
|
-
{
|
|
2389
|
-
id: wrapped.id,
|
|
2390
|
-
index,
|
|
2391
|
-
item: wrapped.data,
|
|
2392
|
-
defaultIcon,
|
|
2393
|
-
hasAnyIcon,
|
|
2394
|
-
showLabel,
|
|
2395
|
-
stackText,
|
|
2396
|
-
labelClassName,
|
|
2397
|
-
textClassName,
|
|
2398
|
-
iconClassName,
|
|
2399
|
-
dragState,
|
|
2400
|
-
setDragState,
|
|
2401
|
-
onReorder,
|
|
2402
|
-
onRemove,
|
|
2403
|
-
onUpdateItem: (patch) => updateItem(index, patch),
|
|
2404
|
-
onDuplicate: () => duplicateItem(index)
|
|
2405
|
-
},
|
|
2406
|
-
wrapped.id
|
|
2407
|
-
)),
|
|
2408
|
-
/* @__PURE__ */ jsx27(
|
|
2409
|
-
TrailingDropZone,
|
|
2410
|
-
{
|
|
2411
|
-
index: wrappedItems.length,
|
|
2412
|
-
dragState,
|
|
2413
|
-
setDragState,
|
|
2414
|
-
onReorder
|
|
2415
|
-
}
|
|
2416
|
-
),
|
|
2417
|
-
/* @__PURE__ */ jsx27(
|
|
2418
|
-
IconButton,
|
|
2419
|
-
{
|
|
2420
|
-
icon: /* @__PURE__ */ jsx27(AddIcon, { size: 16 }),
|
|
2421
|
-
label: "Add item",
|
|
2422
|
-
size: "lg",
|
|
2423
|
-
intent: "primary",
|
|
2424
|
-
onClick: onAdd,
|
|
2425
|
-
className: "absolute -bottom-6 left-1/2 z-20 -translate-x-1/2 rounded-full border border-base-200 bg-base opacity-0 transition-opacity group-hover/list:opacity-100"
|
|
2426
|
-
}
|
|
2427
|
-
)
|
|
2428
|
-
] });
|
|
2429
|
-
}
|
|
2430
|
-
function EditableRow({
|
|
2431
|
-
id,
|
|
2432
|
-
index,
|
|
2433
|
-
item,
|
|
2434
|
-
defaultIcon,
|
|
2435
|
-
hasAnyIcon,
|
|
2436
|
-
showLabel,
|
|
2437
|
-
stackText,
|
|
2438
|
-
labelClassName,
|
|
2439
|
-
textClassName,
|
|
2440
|
-
iconClassName,
|
|
2441
|
-
dragState,
|
|
2442
|
-
setDragState,
|
|
2443
|
-
onReorder,
|
|
2444
|
-
onRemove,
|
|
2445
|
-
onUpdateItem,
|
|
2446
|
-
onDuplicate
|
|
2447
|
-
}) {
|
|
2448
|
-
const rowRef = useRef8(null);
|
|
2449
|
-
const handleRef = useRef8(null);
|
|
2450
|
-
const [iconHover, setIconHover] = useState11(false);
|
|
2451
|
-
const [pickerOpen, setPickerOpen] = useState11(false);
|
|
2452
|
-
const [editingSuppressed, setEditingSuppressed] = useState11(false);
|
|
2453
|
-
const iconEntry = resolveIcon(item, defaultIcon);
|
|
2454
|
-
const effectiveIconId = item.icon ?? defaultIcon ?? null;
|
|
2455
|
-
const iconColor = resolveIconColor(item, iconClassName);
|
|
2456
|
-
useEffect9(() => {
|
|
2457
|
-
const row = rowRef.current;
|
|
2458
|
-
const handle = handleRef.current;
|
|
2459
|
-
if (!row || !handle) return;
|
|
2460
|
-
let cleanup;
|
|
2461
|
-
let cancelled = false;
|
|
2462
|
-
import("../../adapter-HH47ZPGM.js").then(({ draggable, dropTargetForElements }) => {
|
|
2463
|
-
if (cancelled) return;
|
|
2464
|
-
const cleanupDraggable = draggable({
|
|
2465
|
-
element: handle,
|
|
2466
|
-
getInitialData: () => ({ dragType: "icon-list-row", id, index }),
|
|
2467
|
-
onDragStart: () => setDragState({ sourceId: id, targetId: null }),
|
|
2468
|
-
onDrop: () => setDragState({ sourceId: null, targetId: null })
|
|
2469
|
-
});
|
|
2470
|
-
const cleanupDropTarget = dropTargetForElements({
|
|
2471
|
-
element: row,
|
|
2472
|
-
canDrop: ({ source }) => source.data.dragType === "icon-list-row",
|
|
2473
|
-
getData: () => ({ id, index }),
|
|
2474
|
-
onDragEnter: () => setDragState((prev) => ({ ...prev, targetId: id })),
|
|
2475
|
-
onDragLeave: () => setDragState(
|
|
2476
|
-
(prev) => prev.targetId === id ? { ...prev, targetId: null } : prev
|
|
2477
|
-
),
|
|
2478
|
-
onDrop: ({ source }) => {
|
|
2479
|
-
const fromIndex = source.data.index;
|
|
2480
|
-
if (fromIndex !== index) onReorder(fromIndex, index);
|
|
2481
|
-
}
|
|
2482
|
-
});
|
|
2483
|
-
cleanup = () => {
|
|
2484
|
-
cleanupDraggable();
|
|
2485
|
-
cleanupDropTarget();
|
|
2486
|
-
};
|
|
2487
|
-
});
|
|
2488
|
-
return () => {
|
|
2489
|
-
cancelled = true;
|
|
2490
|
-
cleanup?.();
|
|
2491
|
-
};
|
|
2492
|
-
}, [id, index, onReorder, setDragState]);
|
|
2493
|
-
const isDropTarget = dragState.targetId === id && dragState.sourceId !== id;
|
|
2494
|
-
const onEditableActivity = (e) => {
|
|
2495
|
-
const t = e.target;
|
|
2496
|
-
if (t.matches?.("input, textarea, [contenteditable], [contenteditable='true']")) {
|
|
2497
|
-
setEditingSuppressed(true);
|
|
2498
|
-
}
|
|
2499
|
-
};
|
|
2500
|
-
return /* @__PURE__ */ jsxs13(
|
|
2501
|
-
"div",
|
|
2502
|
-
{
|
|
2503
|
-
ref: rowRef,
|
|
2504
|
-
className: cn(
|
|
2505
|
-
"group/row relative grid gap-x-3",
|
|
2506
|
-
hasAnyIcon ? "grid-cols-[24px_1fr]" : "grid-cols-1",
|
|
2507
|
-
isDropTarget && "border-t-2 border-primary"
|
|
2508
|
-
),
|
|
2509
|
-
onFocusCapture: onEditableActivity,
|
|
2510
|
-
onInput: onEditableActivity,
|
|
2511
|
-
onMouseMove: () => setEditingSuppressed(false),
|
|
2512
|
-
children: [
|
|
2513
|
-
hasAnyIcon && /* @__PURE__ */ jsxs13(
|
|
2514
|
-
"div",
|
|
2515
|
-
{
|
|
2516
|
-
"data-testid": "icon-list-icon",
|
|
2517
|
-
className: cn("relative flex items-start pt-0.5", iconColor),
|
|
2518
|
-
onMouseEnter: () => setIconHover(true),
|
|
2519
|
-
onMouseLeave: () => setIconHover(false),
|
|
2520
|
-
children: [
|
|
2521
|
-
/* @__PURE__ */ jsx27(
|
|
2522
|
-
"button",
|
|
2523
|
-
{
|
|
2524
|
-
className: "cursor-pointer transition-opacity hover:opacity-70",
|
|
2525
|
-
"aria-label": "Change icon",
|
|
2526
|
-
onClick: () => setPickerOpen((prev) => !prev),
|
|
2527
|
-
children: iconHover && !pickerOpen ? /* @__PURE__ */ jsx27(Pencil, { size: 18, className: "text-base-contrast-light" }) : iconEntry ? /* @__PURE__ */ jsx27(iconEntry.icon, { size: 18 }) : /* @__PURE__ */ jsx27("span", { className: "flex h-[18px] w-[18px] items-center justify-center rounded-sm border border-dashed border-base-contrast-light/40" })
|
|
2528
|
-
}
|
|
2529
|
-
),
|
|
2530
|
-
pickerOpen && /* @__PURE__ */ jsx27("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx27(
|
|
2531
|
-
IconPicker,
|
|
2532
|
-
{
|
|
2533
|
-
selected: effectiveIconId,
|
|
2534
|
-
showRemove: true,
|
|
2535
|
-
allowDoDont: true,
|
|
2536
|
-
dodont: item.dodont,
|
|
2537
|
-
onSelect: (newIcon) => {
|
|
2538
|
-
onUpdateItem({ icon: newIcon ?? void 0, dodont: void 0 });
|
|
2539
|
-
setPickerOpen(false);
|
|
2540
|
-
setIconHover(false);
|
|
2541
|
-
},
|
|
2542
|
-
onSelectDoDont: (v) => {
|
|
2543
|
-
onUpdateItem({ dodont: v });
|
|
2544
|
-
if (v !== void 0) {
|
|
2545
|
-
setPickerOpen(false);
|
|
2546
|
-
setIconHover(false);
|
|
2547
|
-
}
|
|
2548
|
-
},
|
|
2549
|
-
onClose: () => {
|
|
2550
|
-
setPickerOpen(false);
|
|
2551
|
-
setIconHover(false);
|
|
2552
|
-
}
|
|
2553
|
-
}
|
|
2554
|
-
) })
|
|
2555
|
-
]
|
|
2556
|
-
}
|
|
2557
|
-
),
|
|
2558
|
-
/* @__PURE__ */ jsxs13("div", { className: stackText ? "flex flex-col" : void 0, children: [
|
|
2559
|
-
showLabel && /* @__PURE__ */ jsx27(
|
|
2560
|
-
EditablePlainText,
|
|
2561
|
-
{
|
|
2562
|
-
tag: "span",
|
|
2563
|
-
value: item.label,
|
|
2564
|
-
onChange: (label) => onUpdateItem({ label }),
|
|
2565
|
-
isEditMode: true,
|
|
2566
|
-
placeholder: "Label",
|
|
2567
|
-
className: cn(labelClassName, !stackText && "mr-1")
|
|
2568
|
-
}
|
|
2569
|
-
),
|
|
2570
|
-
/* @__PURE__ */ jsx27(
|
|
2571
|
-
EditablePlainText,
|
|
2572
|
-
{
|
|
2573
|
-
tag: "span",
|
|
2574
|
-
value: item.text,
|
|
2575
|
-
onChange: (text) => onUpdateItem({ text }),
|
|
2576
|
-
isEditMode: true,
|
|
2577
|
-
placeholder: "Text",
|
|
2578
|
-
className: textClassName
|
|
2579
|
-
}
|
|
2580
|
-
)
|
|
2581
|
-
] }),
|
|
2582
|
-
/* @__PURE__ */ jsxs13(
|
|
2583
|
-
"div",
|
|
2584
|
-
{
|
|
2585
|
-
className: cn(
|
|
2586
|
-
"absolute right-1 top-1 z-10 flex items-center gap-1",
|
|
2587
|
-
editingSuppressed ? "opacity-0 pointer-events-none" : "opacity-0 group-hover/row:opacity-100 no-hover:opacity-100"
|
|
2588
|
-
),
|
|
2589
|
-
children: [
|
|
2590
|
-
/* @__PURE__ */ jsx27(
|
|
2591
|
-
IconButton,
|
|
2592
|
-
{
|
|
2593
|
-
ref: handleRef,
|
|
2594
|
-
icon: /* @__PURE__ */ jsx27(DragHandle, { size: 14 }),
|
|
2595
|
-
label: "Drag to reorder",
|
|
2596
|
-
size: "sm",
|
|
2597
|
-
className: "cursor-grab rounded bg-base/80 p-1 shadow-sm text-base-contrast-light/80 hover:text-base-contrast active:cursor-grabbing",
|
|
2598
|
-
tabIndex: -1
|
|
2599
|
-
}
|
|
2600
|
-
),
|
|
2601
|
-
/* @__PURE__ */ jsx27(
|
|
2602
|
-
"button",
|
|
2603
|
-
{
|
|
2604
|
-
"aria-label": "Duplicate item",
|
|
2605
|
-
onClick: onDuplicate,
|
|
2606
|
-
className: "cursor-pointer rounded bg-base/80 p-1 shadow-sm text-base-contrast-light hover:text-primary",
|
|
2607
|
-
children: /* @__PURE__ */ jsx27(CopyPlus, { size: 14 })
|
|
2608
|
-
}
|
|
2609
|
-
),
|
|
2610
|
-
/* @__PURE__ */ jsx27(
|
|
2611
|
-
IconButton,
|
|
2612
|
-
{
|
|
2613
|
-
icon: /* @__PURE__ */ jsx27(DeleteIcon, { size: 14 }),
|
|
2614
|
-
label: "Delete item",
|
|
2615
|
-
size: "sm",
|
|
2616
|
-
intent: "destructive",
|
|
2617
|
-
onClick: () => onRemove(id),
|
|
2618
|
-
className: "bg-base/80 shadow-sm"
|
|
2619
|
-
}
|
|
2620
|
-
)
|
|
2621
|
-
]
|
|
2622
|
-
}
|
|
2623
|
-
)
|
|
2624
|
-
]
|
|
2625
|
-
}
|
|
2626
|
-
);
|
|
2627
|
-
}
|
|
2628
|
-
function TrailingDropZone({
|
|
2629
|
-
index,
|
|
2630
|
-
dragState,
|
|
2631
|
-
setDragState,
|
|
2632
|
-
onReorder
|
|
2633
|
-
}) {
|
|
2634
|
-
const ref = useRef8(null);
|
|
2635
|
-
const trailingId = "__trailing__";
|
|
2636
|
-
useEffect9(() => {
|
|
2637
|
-
const el = ref.current;
|
|
2638
|
-
if (!el) return;
|
|
2639
|
-
let cleanup;
|
|
2640
|
-
let cancelled = false;
|
|
2641
|
-
import("../../adapter-HH47ZPGM.js").then(({ dropTargetForElements }) => {
|
|
2642
|
-
if (cancelled) return;
|
|
2643
|
-
cleanup = dropTargetForElements({
|
|
2644
|
-
element: el,
|
|
2645
|
-
canDrop: ({ source }) => source.data.dragType === "icon-list-row",
|
|
2646
|
-
getData: () => ({ id: trailingId, index }),
|
|
2647
|
-
onDragEnter: () => setDragState((prev) => ({ ...prev, targetId: trailingId })),
|
|
2648
|
-
onDragLeave: () => setDragState(
|
|
2649
|
-
(prev) => prev.targetId === trailingId ? { ...prev, targetId: null } : prev
|
|
2650
|
-
),
|
|
2651
|
-
onDrop: ({ source }) => {
|
|
2652
|
-
const fromIndex = source.data.index;
|
|
2653
|
-
if (fromIndex !== index - 1) onReorder(fromIndex, index - 1);
|
|
2654
|
-
}
|
|
2655
|
-
});
|
|
2656
|
-
});
|
|
2657
|
-
return () => {
|
|
2658
|
-
cancelled = true;
|
|
2659
|
-
cleanup?.();
|
|
2660
|
-
};
|
|
2661
|
-
}, [index, onReorder, setDragState]);
|
|
2662
|
-
const isDropTarget = dragState.targetId === trailingId && dragState.sourceId !== null;
|
|
2663
|
-
return /* @__PURE__ */ jsx27(
|
|
2664
|
-
"div",
|
|
2665
|
-
{
|
|
2666
|
-
ref,
|
|
2667
|
-
className: cn("absolute bottom-0 left-0 right-0 h-4", isDropTarget && "border-t-2 border-primary")
|
|
2668
|
-
}
|
|
2669
|
-
);
|
|
2670
|
-
}
|
|
2671
|
-
|
|
2672
|
-
// src/components/sections/IconList/IconListSettings.tsx
|
|
2673
|
-
import { useState as useState12 } from "react";
|
|
2674
|
-
|
|
2675
|
-
// src/components/shared/Checkbox.tsx
|
|
2676
|
-
import { useId as useId2 } from "react";
|
|
2677
|
-
import { Check as Check3 } from "lucide-react";
|
|
2678
|
-
import { jsx as jsx28, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
2679
|
-
function Checkbox({
|
|
2680
|
-
checked,
|
|
2681
|
-
onChange,
|
|
2682
|
-
label,
|
|
2683
|
-
description,
|
|
2684
|
-
disabled,
|
|
2685
|
-
className,
|
|
2686
|
-
startAdornment,
|
|
2687
|
-
align = "start"
|
|
2688
|
-
}) {
|
|
2689
|
-
const id = useId2();
|
|
2690
|
-
return /* @__PURE__ */ jsxs14(
|
|
2691
|
-
"label",
|
|
2692
|
-
{
|
|
2693
|
-
htmlFor: id,
|
|
2694
|
-
className: cn(
|
|
2695
|
-
"flex cursor-pointer gap-3 select-none hover:opacity-80",
|
|
2696
|
-
align === "start" ? "items-start" : "items-center",
|
|
2697
|
-
disabled && "cursor-not-allowed opacity-50",
|
|
2698
|
-
className
|
|
2699
|
-
),
|
|
2700
|
-
children: [
|
|
2701
|
-
/* @__PURE__ */ jsxs14(
|
|
2702
|
-
"span",
|
|
2703
|
-
{
|
|
2704
|
-
className: cn(
|
|
2705
|
-
"relative flex h-5 w-5 shrink-0 items-center justify-center",
|
|
2706
|
-
align === "start" && "mt-0.5"
|
|
2707
|
-
),
|
|
2708
|
-
children: [
|
|
2709
|
-
/* @__PURE__ */ jsx28(
|
|
2710
|
-
"input",
|
|
2711
|
-
{
|
|
2712
|
-
id,
|
|
2713
|
-
type: "checkbox",
|
|
2714
|
-
checked,
|
|
2715
|
-
disabled,
|
|
2716
|
-
onChange: (e) => onChange(e.target.checked),
|
|
2717
|
-
className: "sr-only"
|
|
2718
|
-
}
|
|
2719
|
-
),
|
|
2720
|
-
/* @__PURE__ */ jsx28(
|
|
2721
|
-
"span",
|
|
2722
|
-
{
|
|
2723
|
-
"aria-hidden": "true",
|
|
2724
|
-
className: cn(
|
|
2725
|
-
"flex h-5 w-5 items-center justify-center rounded border transition-colors",
|
|
2726
|
-
checked ? "border-primary bg-primary text-primary-contrast" : "border-base-300 bg-base hover:border-primary",
|
|
2727
|
-
disabled && "pointer-events-none"
|
|
2728
|
-
),
|
|
2729
|
-
children: checked && /* @__PURE__ */ jsx28(Check3, { size: 14, strokeWidth: 3 })
|
|
2730
|
-
}
|
|
2731
|
-
)
|
|
2732
|
-
]
|
|
2733
|
-
}
|
|
2734
|
-
),
|
|
2735
|
-
startAdornment,
|
|
2736
|
-
/* @__PURE__ */ jsxs14("div", { className: "text-sm", children: [
|
|
2737
|
-
/* @__PURE__ */ jsx28("span", { className: "font-medium text-base-contrast", children: label }),
|
|
2738
|
-
description && /* @__PURE__ */ jsx28("span", { className: "block text-base-contrast-light", children: description })
|
|
2739
|
-
] })
|
|
188
|
+
square: { type: "checkbox", label: "Square aspect ratio", default: false },
|
|
189
|
+
showCaption: { type: "checkbox", label: "Show caption", default: false },
|
|
190
|
+
border: { type: "checkbox", label: "Border", default: false },
|
|
191
|
+
objectFit: {
|
|
192
|
+
type: "select",
|
|
193
|
+
label: "Image fit",
|
|
194
|
+
default: "contain",
|
|
195
|
+
options: [
|
|
196
|
+
{ label: "Contain", value: "contain" },
|
|
197
|
+
{ label: "Cover", value: "cover" }
|
|
2740
198
|
]
|
|
2741
|
-
}
|
|
2742
|
-
|
|
2743
|
-
}
|
|
199
|
+
},
|
|
200
|
+
link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" }
|
|
201
|
+
},
|
|
202
|
+
inheritableSettings: ["square", "showCaption", "border", "objectFit"],
|
|
203
|
+
settingsTabs: [
|
|
204
|
+
{ label: "Display", fields: ["square", "showCaption", "border", "objectFit"] },
|
|
205
|
+
{ label: "Link", fields: ["link"] }
|
|
206
|
+
]
|
|
207
|
+
});
|
|
2744
208
|
|
|
2745
|
-
// src/components/sections/
|
|
2746
|
-
import {
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
}) {
|
|
2753
|
-
const
|
|
2754
|
-
const
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
return /* @__PURE__ */ jsxs15("div", { className: "space-y-4", children: [
|
|
2761
|
-
/* @__PURE__ */ jsxs15("div", { className: "relative", children: [
|
|
2762
|
-
/* @__PURE__ */ jsx29(FormLabel, { htmlFor: "icon-picker-btn", children: "Default Icon" }),
|
|
2763
|
-
/* @__PURE__ */ jsxs15("div", { className: "flex items-center gap-2", children: [
|
|
2764
|
-
/* @__PURE__ */ jsxs15(
|
|
2765
|
-
"button",
|
|
2766
|
-
{
|
|
2767
|
-
id: "icon-picker-btn",
|
|
2768
|
-
className: "cursor-pointer flex items-center gap-2 rounded border border-base-200 px-3 py-1.5 text-sm text-base-contrast-light hover:border-primary hover:text-primary",
|
|
2769
|
-
onClick: () => setPickerOpen((prev) => !prev),
|
|
2770
|
-
children: [
|
|
2771
|
-
iconEntry && /* @__PURE__ */ jsx29(iconEntry.icon, { size: 16 }),
|
|
2772
|
-
/* @__PURE__ */ jsx29("span", { children: iconEntry?.label ?? "None" })
|
|
2773
|
-
]
|
|
2774
|
-
}
|
|
2775
|
-
),
|
|
2776
|
-
icon && /* @__PURE__ */ jsx29(
|
|
2777
|
-
"button",
|
|
2778
|
-
{
|
|
2779
|
-
className: "cursor-pointer text-xs text-base-contrast-light hover:text-base-contrast",
|
|
2780
|
-
onClick: () => {
|
|
2781
|
-
setIcon(null);
|
|
2782
|
-
emit({ icon: null });
|
|
2783
|
-
},
|
|
2784
|
-
children: "Clear"
|
|
2785
|
-
}
|
|
2786
|
-
)
|
|
2787
|
-
] }),
|
|
2788
|
-
pickerOpen && /* @__PURE__ */ jsx29("div", { className: "absolute top-full left-0 z-50 mt-1", children: /* @__PURE__ */ jsx29(
|
|
2789
|
-
IconPicker,
|
|
209
|
+
// src/components/sections/Button/index.tsx
|
|
210
|
+
import { z as z3 } from "zod";
|
|
211
|
+
import { RectangleHorizontal } from "lucide-react";
|
|
212
|
+
|
|
213
|
+
// src/components/sections/Button/CTAButton.tsx
|
|
214
|
+
import { Download } from "lucide-react";
|
|
215
|
+
import { jsx as jsx7, jsxs } from "react/jsx-runtime";
|
|
216
|
+
function Button({ text, link, download, onChange }) {
|
|
217
|
+
const base = "inline-block rounded-md px-6 py-3 font-bold transition-colors";
|
|
218
|
+
const variant = "border-2 border-primary text-primary hover:bg-primary hover:text-primary-contrast";
|
|
219
|
+
if (onChange) {
|
|
220
|
+
return /* @__PURE__ */ jsxs("span", { className: cn(base, variant, "inline-flex items-center gap-2"), children: [
|
|
221
|
+
download && /* @__PURE__ */ jsx7(Download, { size: 16, className: "shrink-0" }),
|
|
222
|
+
/* @__PURE__ */ jsx7(
|
|
223
|
+
EditablePlainText,
|
|
2790
224
|
{
|
|
2791
|
-
|
|
2792
|
-
|
|
2793
|
-
|
|
2794
|
-
|
|
2795
|
-
|
|
2796
|
-
}
|
|
2797
|
-
setPickerOpen(false);
|
|
2798
|
-
},
|
|
2799
|
-
onClose: () => setPickerOpen(false)
|
|
225
|
+
tag: "span",
|
|
226
|
+
value: text,
|
|
227
|
+
onChange: (newText) => onChange({ type: "button", content: { text: newText, link, download } }),
|
|
228
|
+
isEditMode: true,
|
|
229
|
+
placeholder: "Button text"
|
|
2800
230
|
}
|
|
2801
|
-
)
|
|
2802
|
-
] })
|
|
2803
|
-
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2809
|
-
emit({ showLabel: v });
|
|
2810
|
-
},
|
|
2811
|
-
label: "Show labels"
|
|
2812
|
-
}
|
|
2813
|
-
),
|
|
2814
|
-
showLabel && /* @__PURE__ */ jsx29(
|
|
2815
|
-
Checkbox,
|
|
231
|
+
)
|
|
232
|
+
] });
|
|
233
|
+
}
|
|
234
|
+
const href = link && link.kind === "external" ? link.href : "";
|
|
235
|
+
const target = link?.target;
|
|
236
|
+
if (href) {
|
|
237
|
+
return /* @__PURE__ */ jsxs(
|
|
238
|
+
"a",
|
|
2816
239
|
{
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
240
|
+
href,
|
|
241
|
+
target,
|
|
242
|
+
download: download ? "" : void 0,
|
|
243
|
+
className: cn(base, variant, download && "inline-flex items-center gap-2"),
|
|
244
|
+
children: [
|
|
245
|
+
download && /* @__PURE__ */ jsx7(Download, { size: 16, className: "shrink-0" }),
|
|
246
|
+
text
|
|
247
|
+
]
|
|
2823
248
|
}
|
|
2824
|
-
)
|
|
2825
|
-
|
|
249
|
+
);
|
|
250
|
+
}
|
|
251
|
+
return /* @__PURE__ */ jsx7("button", { className: cn("cursor-pointer", base, variant), children: text });
|
|
2826
252
|
}
|
|
2827
253
|
|
|
2828
|
-
// src/components/sections/
|
|
2829
|
-
import { jsx as
|
|
2830
|
-
var
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
type: z6.literal("icon_list"),
|
|
2838
|
-
content: z6.object({
|
|
2839
|
-
items: z6.array(IconListItemSchema)
|
|
2840
|
-
}),
|
|
2841
|
-
options: z6.object({
|
|
2842
|
-
icon: z6.string().nullable().optional(),
|
|
2843
|
-
showLabel: z6.boolean().optional(),
|
|
2844
|
-
stackText: z6.boolean().optional()
|
|
2845
|
-
}).optional()
|
|
254
|
+
// src/components/sections/Button/index.tsx
|
|
255
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
256
|
+
var schema3 = z3.object({
|
|
257
|
+
type: z3.literal("button"),
|
|
258
|
+
content: z3.object({
|
|
259
|
+
text: z3.string(),
|
|
260
|
+
link: LinkValueSchema.optional(),
|
|
261
|
+
download: z3.boolean().optional()
|
|
262
|
+
})
|
|
2846
263
|
});
|
|
2847
|
-
var
|
|
2848
|
-
type: "
|
|
2849
|
-
label: "
|
|
2850
|
-
icon: /* @__PURE__ */
|
|
2851
|
-
schema:
|
|
2852
|
-
component: ({ content,
|
|
2853
|
-
|
|
264
|
+
var Button_default = defineSection({
|
|
265
|
+
type: "button",
|
|
266
|
+
label: "Button",
|
|
267
|
+
icon: /* @__PURE__ */ jsx8(RectangleHorizontal, { size: 18 }),
|
|
268
|
+
schema: schema3,
|
|
269
|
+
component: ({ content, onChange }) => /* @__PURE__ */ jsx8(
|
|
270
|
+
Button,
|
|
2854
271
|
{
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
stackText: options?.stackText,
|
|
272
|
+
text: content.content.text,
|
|
273
|
+
link: content.content.link,
|
|
274
|
+
download: content.content.download,
|
|
2859
275
|
onChange: onChange ? (c) => onChange(c) : void 0
|
|
2860
276
|
}
|
|
2861
277
|
),
|
|
2862
|
-
defaults: () => ({
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
278
|
+
defaults: () => ({ type: "button", content: { text: "Button" } }),
|
|
279
|
+
getLabel: (content) => content.content.text,
|
|
280
|
+
settings: {
|
|
281
|
+
link: { type: "link", label: "Link", default: DEFAULT_LINK, target: "content" },
|
|
282
|
+
download: { type: "checkbox", label: "Download link", default: false, target: "content" }
|
|
283
|
+
}
|
|
2868
284
|
});
|
|
2869
285
|
|
|
2870
286
|
// src/components/sections/Container/index.tsx
|
|
2871
|
-
import { z as
|
|
287
|
+
import { z as z4 } from "zod";
|
|
2872
288
|
import { LayoutTemplate } from "lucide-react";
|
|
2873
289
|
|
|
2874
290
|
// src/components/sections/Container/Container.tsx
|
|
2875
291
|
import "react";
|
|
2876
292
|
|
|
2877
293
|
// src/components/editor/ChildBlockWrapper.tsx
|
|
2878
|
-
import { forwardRef
|
|
2879
|
-
import { CopyPlus
|
|
2880
|
-
|
|
2881
|
-
// src/components/editor/DragHandle.tsx
|
|
2882
|
-
import { forwardRef as forwardRef4 } from "react";
|
|
2883
|
-
|
|
2884
|
-
// src/components/shared/Tooltip.tsx
|
|
2885
|
-
import { jsx as jsx31, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
2886
|
-
function Tooltip({ content, children, className }) {
|
|
2887
|
-
return /* @__PURE__ */ jsxs16("div", { className: cn("group/tooltip relative inline-flex", className), children: [
|
|
2888
|
-
children,
|
|
2889
|
-
/* @__PURE__ */ jsx31(
|
|
2890
|
-
"span",
|
|
2891
|
-
{
|
|
2892
|
-
className: "pointer-events-none absolute left-1/2 top-full z-50 mt-1.5 -translate-x-1/2 opacity-0 transition-opacity delay-300 group-hover/tooltip:opacity-100",
|
|
2893
|
-
role: "tooltip",
|
|
2894
|
-
children: /* @__PURE__ */ jsx31("span", { className: "block whitespace-nowrap rounded bg-tooltip px-2 py-1 text-center text-xs leading-relaxed text-tooltip-muted", children: content })
|
|
2895
|
-
}
|
|
2896
|
-
)
|
|
2897
|
-
] });
|
|
2898
|
-
}
|
|
2899
|
-
function Kbd({ children }) {
|
|
2900
|
-
return /* @__PURE__ */ jsx31("strong", { className: "text-tooltip-contrast", children });
|
|
2901
|
-
}
|
|
2902
|
-
|
|
2903
|
-
// src/components/editor/DragHandle.tsx
|
|
2904
|
-
import { Fragment as Fragment5, jsx as jsx32, jsxs as jsxs17 } from "react/jsx-runtime";
|
|
2905
|
-
var DragHandle2 = forwardRef4(function DragHandle3(_, ref) {
|
|
2906
|
-
return /* @__PURE__ */ jsx32(Tooltip, { content: /* @__PURE__ */ jsxs17(Fragment5, { children: [
|
|
2907
|
-
/* @__PURE__ */ jsx32(Kbd, { children: "Drag" }),
|
|
2908
|
-
" to move"
|
|
2909
|
-
] }), children: /* @__PURE__ */ jsx32(
|
|
2910
|
-
IconButton,
|
|
2911
|
-
{
|
|
2912
|
-
ref,
|
|
2913
|
-
icon: /* @__PURE__ */ jsx32(DragHandle, { size: 18 }),
|
|
2914
|
-
label: "Drag to reorder section",
|
|
2915
|
-
className: "pointer-events-auto cursor-grab active:cursor-grabbing rounded-md text-base-contrast-light/80 hover:bg-base-contrast-light/10 hover:text-base-contrast",
|
|
2916
|
-
tabIndex: -1
|
|
2917
|
-
}
|
|
2918
|
-
) });
|
|
2919
|
-
});
|
|
2920
|
-
|
|
2921
|
-
// src/components/editor/DeleteButton.tsx
|
|
2922
|
-
import { jsx as jsx33 } from "react/jsx-runtime";
|
|
2923
|
-
function DeleteButton({ onDelete }) {
|
|
2924
|
-
return /* @__PURE__ */ jsx33(
|
|
2925
|
-
IconButton,
|
|
2926
|
-
{
|
|
2927
|
-
icon: /* @__PURE__ */ jsx33(DeleteIcon, { size: 16 }),
|
|
2928
|
-
label: "Delete section",
|
|
2929
|
-
intent: "destructive",
|
|
2930
|
-
onClick: onDelete,
|
|
2931
|
-
className: "pointer-events-auto"
|
|
2932
|
-
}
|
|
2933
|
-
);
|
|
2934
|
-
}
|
|
2935
|
-
|
|
2936
|
-
// src/components/editor/SettingsButton.tsx
|
|
2937
|
-
import { jsx as jsx34 } from "react/jsx-runtime";
|
|
2938
|
-
function SettingsButton({ onClick }) {
|
|
2939
|
-
return /* @__PURE__ */ jsx34(
|
|
2940
|
-
IconButton,
|
|
2941
|
-
{
|
|
2942
|
-
icon: /* @__PURE__ */ jsx34(SettingsIcon, { size: 16 }),
|
|
2943
|
-
label: "Section settings",
|
|
2944
|
-
onClick,
|
|
2945
|
-
className: "pointer-events-auto"
|
|
2946
|
-
}
|
|
2947
|
-
);
|
|
2948
|
-
}
|
|
294
|
+
import { forwardRef } from "react";
|
|
295
|
+
import { CopyPlus } from "lucide-react";
|
|
2949
296
|
|
|
2950
297
|
// src/components/editor/ColSpanControl.tsx
|
|
2951
|
-
import { useRef
|
|
298
|
+
import { useRef, useState } from "react";
|
|
2952
299
|
import { Columns3 } from "lucide-react";
|
|
2953
|
-
|
|
2954
|
-
// src/components/shared/Popover.tsx
|
|
2955
|
-
import { useEffect as useEffect11, useLayoutEffect, useRef as useRef9, useState as useState13 } from "react";
|
|
2956
|
-
|
|
2957
|
-
// src/hooks/useFocusTrap.ts
|
|
2958
|
-
import { useEffect as useEffect10 } from "react";
|
|
2959
|
-
var FOCUSABLE_SELECTOR = [
|
|
2960
|
-
"a[href]",
|
|
2961
|
-
"button:not([disabled])",
|
|
2962
|
-
"input:not([disabled])",
|
|
2963
|
-
"select:not([disabled])",
|
|
2964
|
-
"textarea:not([disabled])",
|
|
2965
|
-
'[tabindex]:not([tabindex="-1"])'
|
|
2966
|
-
].join(", ");
|
|
2967
|
-
function useFocusTrap(ref, active) {
|
|
2968
|
-
useEffect10(() => {
|
|
2969
|
-
if (!active || !ref.current) return;
|
|
2970
|
-
const container = ref.current;
|
|
2971
|
-
const previouslyFocused = document.activeElement;
|
|
2972
|
-
const getFocusable = () => Array.from(container.querySelectorAll(FOCUSABLE_SELECTOR));
|
|
2973
|
-
const focusable = getFocusable();
|
|
2974
|
-
if (focusable.length > 0) {
|
|
2975
|
-
focusable[0].focus();
|
|
2976
|
-
}
|
|
2977
|
-
const handleKeyDown = (e) => {
|
|
2978
|
-
if (e.key !== "Tab") return;
|
|
2979
|
-
const elements = getFocusable();
|
|
2980
|
-
if (elements.length === 0) return;
|
|
2981
|
-
const first = elements[0];
|
|
2982
|
-
const last = elements[elements.length - 1];
|
|
2983
|
-
if (e.shiftKey) {
|
|
2984
|
-
if (document.activeElement === first) {
|
|
2985
|
-
e.preventDefault();
|
|
2986
|
-
last.focus();
|
|
2987
|
-
}
|
|
2988
|
-
} else {
|
|
2989
|
-
if (document.activeElement === last) {
|
|
2990
|
-
e.preventDefault();
|
|
2991
|
-
first.focus();
|
|
2992
|
-
}
|
|
2993
|
-
}
|
|
2994
|
-
};
|
|
2995
|
-
container.addEventListener("keydown", handleKeyDown);
|
|
2996
|
-
return () => {
|
|
2997
|
-
container.removeEventListener("keydown", handleKeyDown);
|
|
2998
|
-
if (previouslyFocused && document.body.contains(previouslyFocused)) {
|
|
2999
|
-
previouslyFocused.focus();
|
|
3000
|
-
}
|
|
3001
|
-
};
|
|
3002
|
-
}, [active, ref]);
|
|
3003
|
-
}
|
|
3004
|
-
|
|
3005
|
-
// src/components/shared/Popover.tsx
|
|
3006
|
-
import { jsx as jsx35 } from "react/jsx-runtime";
|
|
3007
|
-
function Popover({
|
|
3008
|
-
isOpen,
|
|
3009
|
-
onClose,
|
|
3010
|
-
anchorRef,
|
|
3011
|
-
children,
|
|
3012
|
-
align = "auto",
|
|
3013
|
-
className
|
|
3014
|
-
}) {
|
|
3015
|
-
const panelRef = useRef9(null);
|
|
3016
|
-
const [resolvedAlign, setResolvedAlign] = useState13("start");
|
|
3017
|
-
useFocusTrap(panelRef, isOpen);
|
|
3018
|
-
useLayoutEffect(() => {
|
|
3019
|
-
if (!isOpen || align !== "auto") {
|
|
3020
|
-
if (!isOpen) setResolvedAlign("start");
|
|
3021
|
-
return;
|
|
3022
|
-
}
|
|
3023
|
-
const panel = panelRef.current;
|
|
3024
|
-
if (!panel) return;
|
|
3025
|
-
panel.style.left = "0";
|
|
3026
|
-
panel.style.right = "auto";
|
|
3027
|
-
const rect = panel.getBoundingClientRect();
|
|
3028
|
-
if (rect.right > window.innerWidth) {
|
|
3029
|
-
setResolvedAlign("end");
|
|
3030
|
-
} else {
|
|
3031
|
-
setResolvedAlign("start");
|
|
3032
|
-
}
|
|
3033
|
-
panel.style.left = "";
|
|
3034
|
-
panel.style.right = "";
|
|
3035
|
-
}, [isOpen, align]);
|
|
3036
|
-
useEffect11(() => {
|
|
3037
|
-
if (!isOpen) return;
|
|
3038
|
-
function onKeyDown(e) {
|
|
3039
|
-
if (e.key === "Escape") onClose();
|
|
3040
|
-
}
|
|
3041
|
-
function onMouseDown(e) {
|
|
3042
|
-
const target = e.target;
|
|
3043
|
-
if (panelRef.current?.contains(target)) return;
|
|
3044
|
-
if (anchorRef.current?.contains(target)) return;
|
|
3045
|
-
onClose();
|
|
3046
|
-
}
|
|
3047
|
-
document.addEventListener("keydown", onKeyDown);
|
|
3048
|
-
document.addEventListener("mousedown", onMouseDown);
|
|
3049
|
-
return () => {
|
|
3050
|
-
document.removeEventListener("keydown", onKeyDown);
|
|
3051
|
-
document.removeEventListener("mousedown", onMouseDown);
|
|
3052
|
-
};
|
|
3053
|
-
}, [isOpen, onClose, anchorRef]);
|
|
3054
|
-
if (!isOpen) return null;
|
|
3055
|
-
const effectiveAlign = align === "auto" ? resolvedAlign : align;
|
|
3056
|
-
return /* @__PURE__ */ jsx35(
|
|
3057
|
-
"div",
|
|
3058
|
-
{
|
|
3059
|
-
ref: panelRef,
|
|
3060
|
-
role: "dialog",
|
|
3061
|
-
"aria-modal": "false",
|
|
3062
|
-
className: cn(
|
|
3063
|
-
"absolute top-full z-50 mt-1 rounded-md border border-base-200 bg-base shadow-lg",
|
|
3064
|
-
effectiveAlign === "end" ? "right-0" : "left-0",
|
|
3065
|
-
className
|
|
3066
|
-
),
|
|
3067
|
-
children
|
|
3068
|
-
}
|
|
3069
|
-
);
|
|
3070
|
-
}
|
|
3071
|
-
|
|
3072
|
-
// src/components/shared/PopoverItem.tsx
|
|
3073
|
-
import { forwardRef as forwardRef5 } from "react";
|
|
3074
|
-
import { jsx as jsx36 } from "react/jsx-runtime";
|
|
3075
|
-
var PopoverItem = forwardRef5(
|
|
3076
|
-
function PopoverItem2({ className, children, ...rest }, ref) {
|
|
3077
|
-
return /* @__PURE__ */ jsx36(
|
|
3078
|
-
"button",
|
|
3079
|
-
{
|
|
3080
|
-
ref,
|
|
3081
|
-
type: "button",
|
|
3082
|
-
className: cn(
|
|
3083
|
-
"flex w-full cursor-pointer items-center gap-3 px-3 py-1.5 text-left text-xs hover:bg-base-accent",
|
|
3084
|
-
className
|
|
3085
|
-
),
|
|
3086
|
-
...rest,
|
|
3087
|
-
children
|
|
3088
|
-
}
|
|
3089
|
-
);
|
|
3090
|
-
}
|
|
3091
|
-
);
|
|
3092
|
-
|
|
3093
|
-
// src/components/editor/ColSpanControl.tsx
|
|
3094
|
-
import { jsx as jsx37, jsxs as jsxs18 } from "react/jsx-runtime";
|
|
300
|
+
import { jsx as jsx9, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
3095
301
|
function ColSpanControl({ colSpan, columns, onChange }) {
|
|
3096
|
-
const buttonRef =
|
|
3097
|
-
const [open, setOpen] =
|
|
302
|
+
const buttonRef = useRef(null);
|
|
303
|
+
const [open, setOpen] = useState(false);
|
|
3098
304
|
if (columns <= 1) return null;
|
|
3099
305
|
const current = Math.min(Math.max(colSpan, 1), columns);
|
|
3100
|
-
return /* @__PURE__ */
|
|
3101
|
-
/* @__PURE__ */
|
|
306
|
+
return /* @__PURE__ */ jsxs2("div", { className: "relative", children: [
|
|
307
|
+
/* @__PURE__ */ jsx9(
|
|
3102
308
|
"button",
|
|
3103
309
|
{
|
|
3104
310
|
ref: buttonRef,
|
|
@@ -3108,10 +314,10 @@ function ColSpanControl({ colSpan, columns, onChange }) {
|
|
|
3108
314
|
"aria-expanded": open,
|
|
3109
315
|
onClick: () => setOpen((v) => !v),
|
|
3110
316
|
className: "pointer-events-auto inline-flex cursor-pointer items-center gap-1 rounded p-1 text-xs text-base-contrast-light hover:text-primary",
|
|
3111
|
-
children: /* @__PURE__ */
|
|
317
|
+
children: /* @__PURE__ */ jsx9(Columns3, { size: 14 })
|
|
3112
318
|
}
|
|
3113
319
|
),
|
|
3114
|
-
/* @__PURE__ */
|
|
320
|
+
/* @__PURE__ */ jsx9(Popover, { isOpen: open, onClose: () => setOpen(false), anchorRef: buttonRef, className: "min-w-28", children: /* @__PURE__ */ jsx9("ul", { role: "list", className: "py-1", children: Array.from({ length: columns }, (_, i) => i + 1).map((span) => /* @__PURE__ */ jsx9("li", { children: /* @__PURE__ */ jsxs2(
|
|
3115
321
|
PopoverItem,
|
|
3116
322
|
{
|
|
3117
323
|
"aria-current": span === current,
|
|
@@ -3130,8 +336,8 @@ function ColSpanControl({ colSpan, columns, onChange }) {
|
|
|
3130
336
|
}
|
|
3131
337
|
|
|
3132
338
|
// src/components/editor/ChildBlockWrapper.tsx
|
|
3133
|
-
import { jsx as
|
|
3134
|
-
var ChildBlockWrapper =
|
|
339
|
+
import { jsx as jsx10, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
340
|
+
var ChildBlockWrapper = forwardRef(
|
|
3135
341
|
function ChildBlockWrapper2({
|
|
3136
342
|
label,
|
|
3137
343
|
columns,
|
|
@@ -3146,7 +352,7 @@ var ChildBlockWrapper = forwardRef6(
|
|
|
3146
352
|
onOpenSettings,
|
|
3147
353
|
children
|
|
3148
354
|
}, ref) {
|
|
3149
|
-
return /* @__PURE__ */
|
|
355
|
+
return /* @__PURE__ */ jsxs3(
|
|
3150
356
|
"div",
|
|
3151
357
|
{
|
|
3152
358
|
ref,
|
|
@@ -3156,39 +362,39 @@ var ChildBlockWrapper = forwardRef6(
|
|
|
3156
362
|
"hover:outline hover:outline-2 hover:outline-primary/30"
|
|
3157
363
|
),
|
|
3158
364
|
children: [
|
|
3159
|
-
/* @__PURE__ */
|
|
3160
|
-
/* @__PURE__ */
|
|
3161
|
-
/* @__PURE__ */
|
|
3162
|
-
/* @__PURE__ */
|
|
3163
|
-
hasSettings && onOpenSettings && /* @__PURE__ */
|
|
3164
|
-
/* @__PURE__ */
|
|
365
|
+
/* @__PURE__ */ jsxs3("div", { className: "absolute top-0 left-0 -translate-x-full z-20 flex flex-col items-center gap-1 opacity-0 transition-opacity group-hover/childblock:opacity-100 group-focus-within/childblock:opacity-100 pointer-events-none", children: [
|
|
366
|
+
/* @__PURE__ */ jsx10("span", { className: "sr-only", children: label }),
|
|
367
|
+
/* @__PURE__ */ jsx10("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx10(DragHandle, { ref: dragHandleRef }) }),
|
|
368
|
+
/* @__PURE__ */ jsx10("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx10(ColSpanControl, { colSpan, columns, onChange: onColSpanChange }) }),
|
|
369
|
+
hasSettings && onOpenSettings && /* @__PURE__ */ jsx10("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx10(SettingsButton, { onClick: onOpenSettings }) }),
|
|
370
|
+
/* @__PURE__ */ jsx10("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx10(
|
|
3165
371
|
"button",
|
|
3166
372
|
{
|
|
3167
373
|
type: "button",
|
|
3168
374
|
"aria-label": "Duplicate block",
|
|
3169
375
|
onClick: onDuplicate,
|
|
3170
376
|
className: "cursor-pointer rounded p-1 text-base-contrast-light hover:text-primary",
|
|
3171
|
-
children: /* @__PURE__ */
|
|
377
|
+
children: /* @__PURE__ */ jsx10(CopyPlus, { size: 16 })
|
|
3172
378
|
}
|
|
3173
379
|
) }),
|
|
3174
|
-
/* @__PURE__ */
|
|
380
|
+
/* @__PURE__ */ jsx10("div", { className: "pointer-events-auto", children: /* @__PURE__ */ jsx10(DeleteButton, { onDelete }) })
|
|
3175
381
|
] }),
|
|
3176
|
-
closestEdge === "left" && /* @__PURE__ */
|
|
382
|
+
closestEdge === "left" && /* @__PURE__ */ jsx10(
|
|
3177
383
|
"div",
|
|
3178
384
|
{
|
|
3179
385
|
"data-drop-edge": "left",
|
|
3180
386
|
className: "absolute bottom-0 left-0 top-0 z-10 w-0.5 -translate-x-1 bg-primary"
|
|
3181
387
|
}
|
|
3182
388
|
),
|
|
3183
|
-
closestEdge === "right" && /* @__PURE__ */
|
|
389
|
+
closestEdge === "right" && /* @__PURE__ */ jsx10(
|
|
3184
390
|
"div",
|
|
3185
391
|
{
|
|
3186
392
|
"data-drop-edge": "right",
|
|
3187
393
|
className: "absolute bottom-0 right-0 top-0 z-10 w-0.5 translate-x-1 bg-primary"
|
|
3188
394
|
}
|
|
3189
395
|
),
|
|
3190
|
-
closestEdge === "top" && /* @__PURE__ */
|
|
3191
|
-
closestEdge === "bottom" && /* @__PURE__ */
|
|
396
|
+
closestEdge === "top" && /* @__PURE__ */ jsx10("div", { "data-drop-edge": "top", className: "absolute left-0 right-0 top-0 z-10 h-0.5 -translate-y-1 bg-primary" }),
|
|
397
|
+
closestEdge === "bottom" && /* @__PURE__ */ jsx10("div", { "data-drop-edge": "bottom", className: "absolute left-0 right-0 bottom-0 z-10 h-0.5 translate-y-1 bg-primary" }),
|
|
3192
398
|
children
|
|
3193
399
|
]
|
|
3194
400
|
}
|
|
@@ -3196,334 +402,14 @@ var ChildBlockWrapper = forwardRef6(
|
|
|
3196
402
|
}
|
|
3197
403
|
);
|
|
3198
404
|
|
|
3199
|
-
// src/components/editor/SettingsForm.tsx
|
|
3200
|
-
import { useId as useId4, useState as useState16 } from "react";
|
|
3201
|
-
|
|
3202
|
-
// src/components/shared/Select.tsx
|
|
3203
|
-
import { useId as useId3 } from "react";
|
|
3204
|
-
import { ChevronDown } from "lucide-react";
|
|
3205
|
-
import { jsx as jsx39, jsxs as jsxs20 } from "react/jsx-runtime";
|
|
3206
|
-
function Select({
|
|
3207
|
-
label,
|
|
3208
|
-
value,
|
|
3209
|
-
onChange,
|
|
3210
|
-
options,
|
|
3211
|
-
disabled,
|
|
3212
|
-
className,
|
|
3213
|
-
selectClassName
|
|
3214
|
-
}) {
|
|
3215
|
-
const id = useId3();
|
|
3216
|
-
return /* @__PURE__ */ jsxs20("div", { className, children: [
|
|
3217
|
-
label && /* @__PURE__ */ jsx39(FormLabel, { htmlFor: id, children: label }),
|
|
3218
|
-
/* @__PURE__ */ jsxs20("div", { className: "relative", children: [
|
|
3219
|
-
/* @__PURE__ */ jsx39(
|
|
3220
|
-
"select",
|
|
3221
|
-
{
|
|
3222
|
-
id,
|
|
3223
|
-
value,
|
|
3224
|
-
onChange: (e) => onChange(e.target.value),
|
|
3225
|
-
disabled,
|
|
3226
|
-
className: cn(
|
|
3227
|
-
"w-full appearance-none rounded border border-base-200 bg-base py-2 pr-8 pl-3 text-sm text-base-contrast",
|
|
3228
|
-
"focus:border-base-contrast focus:outline-none focus:ring-1 focus:ring-base-contrast",
|
|
3229
|
-
disabled && "cursor-not-allowed opacity-50",
|
|
3230
|
-
selectClassName
|
|
3231
|
-
),
|
|
3232
|
-
children: options.map((opt) => /* @__PURE__ */ jsx39("option", { value: opt.value, children: opt.label }, opt.value))
|
|
3233
|
-
}
|
|
3234
|
-
),
|
|
3235
|
-
/* @__PURE__ */ jsx39(
|
|
3236
|
-
ChevronDown,
|
|
3237
|
-
{
|
|
3238
|
-
size: 14,
|
|
3239
|
-
className: "pointer-events-none absolute right-2.5 top-1/2 -translate-y-1/2 text-base-contrast-light"
|
|
3240
|
-
}
|
|
3241
|
-
)
|
|
3242
|
-
] })
|
|
3243
|
-
] });
|
|
3244
|
-
}
|
|
3245
|
-
|
|
3246
|
-
// src/components/shared/LinkField.tsx
|
|
3247
|
-
import { Fragment as Fragment6, jsx as jsx40, jsxs as jsxs21 } from "react/jsx-runtime";
|
|
3248
|
-
var TARGET_OPTIONS = [
|
|
3249
|
-
{ label: "Same tab (_self)", value: "_self" },
|
|
3250
|
-
{ label: "New tab (_blank)", value: "_blank" }
|
|
3251
|
-
];
|
|
3252
|
-
function LinkField({ label, value, onChange }) {
|
|
3253
|
-
const { pages, getPageHeadings } = usePages();
|
|
3254
|
-
const isInternal = value.kind === "internal";
|
|
3255
|
-
function setMode(kind) {
|
|
3256
|
-
if (kind === value.kind) return;
|
|
3257
|
-
onChange(kind === "external" ? { kind: "external", href: "", target: value.target } : { kind: "internal", pageId: "", anchorSectionId: null, target: "_self" });
|
|
3258
|
-
}
|
|
3259
|
-
const pageId = isInternal ? value.pageId : "";
|
|
3260
|
-
const headings = pageId ? getPageHeadings(pageId) : [];
|
|
3261
|
-
return /* @__PURE__ */ jsxs21("div", { className: "flex flex-col gap-3", children: [
|
|
3262
|
-
/* @__PURE__ */ jsx40(FormLabel, { children: label }),
|
|
3263
|
-
/* @__PURE__ */ jsx40("div", { className: "flex gap-2", role: "tablist", children: ["external", "internal"].map((kind) => /* @__PURE__ */ jsx40(
|
|
3264
|
-
"button",
|
|
3265
|
-
{
|
|
3266
|
-
type: "button",
|
|
3267
|
-
role: "tab",
|
|
3268
|
-
"aria-selected": value.kind === kind,
|
|
3269
|
-
onClick: () => setMode(kind),
|
|
3270
|
-
className: cn(
|
|
3271
|
-
"cursor-pointer rounded border px-3 py-1 text-sm capitalize",
|
|
3272
|
-
value.kind === kind ? "border-primary bg-primary text-primary-contrast" : "border-base-200 text-base-contrast"
|
|
3273
|
-
),
|
|
3274
|
-
children: kind === "external" ? "External URL" : "Internal page"
|
|
3275
|
-
},
|
|
3276
|
-
kind
|
|
3277
|
-
)) }),
|
|
3278
|
-
value.kind === "external" ? /* @__PURE__ */ jsx40(
|
|
3279
|
-
Input,
|
|
3280
|
-
{
|
|
3281
|
-
label: "URL",
|
|
3282
|
-
value: value.href,
|
|
3283
|
-
placeholder: "https://...",
|
|
3284
|
-
onChange: (href) => onChange({ kind: "external", href, target: value.target })
|
|
3285
|
-
}
|
|
3286
|
-
) : /* @__PURE__ */ jsxs21(Fragment6, { children: [
|
|
3287
|
-
/* @__PURE__ */ jsx40(
|
|
3288
|
-
Select,
|
|
3289
|
-
{
|
|
3290
|
-
label: "Page",
|
|
3291
|
-
value: value.pageId,
|
|
3292
|
-
options: [{ label: "Select a page\u2026", value: "" }, ...pages.map((p) => ({ label: p.title, value: p.id }))],
|
|
3293
|
-
onChange: (pid) => onChange({ kind: "internal", pageId: pid, anchorSectionId: null, target: value.target })
|
|
3294
|
-
}
|
|
3295
|
-
),
|
|
3296
|
-
/* @__PURE__ */ jsx40(
|
|
3297
|
-
Select,
|
|
3298
|
-
{
|
|
3299
|
-
label: "Section",
|
|
3300
|
-
value: value.anchorSectionId ?? "",
|
|
3301
|
-
disabled: !pageId,
|
|
3302
|
-
options: [{ label: "None (top of page)", value: "" }, ...headings.map((h) => ({ label: h.label, value: h.id }))],
|
|
3303
|
-
onChange: (anchor) => onChange({ kind: "internal", pageId, anchorSectionId: anchor || null, target: value.target })
|
|
3304
|
-
}
|
|
3305
|
-
)
|
|
3306
|
-
] }),
|
|
3307
|
-
value.kind === "external" && /* @__PURE__ */ jsx40(
|
|
3308
|
-
Select,
|
|
3309
|
-
{
|
|
3310
|
-
label: "Opens in",
|
|
3311
|
-
value: value.target,
|
|
3312
|
-
options: TARGET_OPTIONS,
|
|
3313
|
-
onChange: (t) => onChange({ ...value, target: t })
|
|
3314
|
-
}
|
|
3315
|
-
)
|
|
3316
|
-
] });
|
|
3317
|
-
}
|
|
3318
|
-
|
|
3319
|
-
// src/components/shared/Tabs.tsx
|
|
3320
|
-
import { useState as useState15 } from "react";
|
|
3321
|
-
import { jsx as jsx41, jsxs as jsxs22 } from "react/jsx-runtime";
|
|
3322
|
-
function Tabs({ tabs, defaultTabId, activeTabId, onTabChange, fullBleedTabBar }) {
|
|
3323
|
-
const [uncontrolledId, setUncontrolledId] = useState15(defaultTabId ?? tabs[0]?.id);
|
|
3324
|
-
const isControlled = activeTabId !== void 0;
|
|
3325
|
-
const activeId = isControlled ? activeTabId : uncontrolledId;
|
|
3326
|
-
const activeTab = tabs.find((t) => t.id === activeId) ?? tabs[0];
|
|
3327
|
-
function handleSelect(id) {
|
|
3328
|
-
if (!isControlled) setUncontrolledId(id);
|
|
3329
|
-
onTabChange?.(id);
|
|
3330
|
-
}
|
|
3331
|
-
return /* @__PURE__ */ jsxs22("div", { className: "flex flex-1 flex-col overflow-hidden", children: [
|
|
3332
|
-
/* @__PURE__ */ jsx41("div", { className: cn("border-b border-base-200", fullBleedTabBar && "-mx-6 px-6"), children: /* @__PURE__ */ jsx41("div", { className: "flex", role: "tablist", children: tabs.map((tab) => /* @__PURE__ */ jsx41(
|
|
3333
|
-
"button",
|
|
3334
|
-
{
|
|
3335
|
-
type: "button",
|
|
3336
|
-
role: "tab",
|
|
3337
|
-
"aria-selected": activeTab?.id === tab.id,
|
|
3338
|
-
onClick: () => handleSelect(tab.id),
|
|
3339
|
-
className: cn(
|
|
3340
|
-
"cursor-pointer px-4 py-2 text-sm font-medium border-b-2 -mb-px",
|
|
3341
|
-
activeTab?.id === tab.id ? "border-brand text-brand" : "border-transparent text-base-contrast-light hover:text-base-contrast"
|
|
3342
|
-
),
|
|
3343
|
-
children: tab.label
|
|
3344
|
-
},
|
|
3345
|
-
tab.id
|
|
3346
|
-
)) }) }),
|
|
3347
|
-
/* @__PURE__ */ jsx41("div", { role: "tabpanel", children: activeTab?.content })
|
|
3348
|
-
] });
|
|
3349
|
-
}
|
|
3350
|
-
|
|
3351
|
-
// src/components/editor/SettingsForm.tsx
|
|
3352
|
-
import { jsx as jsx42, jsxs as jsxs23 } from "react/jsx-runtime";
|
|
3353
|
-
function resolveValues(schema8, values) {
|
|
3354
|
-
const resolved = {};
|
|
3355
|
-
for (const [key, field] of Object.entries(schema8)) {
|
|
3356
|
-
resolved[key] = values[key] ?? field.default;
|
|
3357
|
-
}
|
|
3358
|
-
return resolved;
|
|
3359
|
-
}
|
|
3360
|
-
function coerceValue(field, value) {
|
|
3361
|
-
if (field.type === "select" && "coerce" in field && field.coerce === "number") {
|
|
3362
|
-
return Number(value);
|
|
3363
|
-
}
|
|
3364
|
-
return value;
|
|
3365
|
-
}
|
|
3366
|
-
function normalizeEmpty(field, value) {
|
|
3367
|
-
if (field.type === "select" && "emptyIsUndefined" in field && field.emptyIsUndefined && value === "") {
|
|
3368
|
-
return void 0;
|
|
3369
|
-
}
|
|
3370
|
-
return value;
|
|
3371
|
-
}
|
|
3372
|
-
function splitByTarget(schema8, allValues) {
|
|
3373
|
-
const content = {};
|
|
3374
|
-
const options = {};
|
|
3375
|
-
for (const [key, field] of Object.entries(schema8)) {
|
|
3376
|
-
const value = normalizeEmpty(field, coerceValue(field, allValues[key]));
|
|
3377
|
-
const target = field.target ?? "options";
|
|
3378
|
-
if (target === "content") {
|
|
3379
|
-
content[key] = value;
|
|
3380
|
-
} else {
|
|
3381
|
-
options[key] = value;
|
|
3382
|
-
}
|
|
3383
|
-
}
|
|
3384
|
-
return { content, options };
|
|
3385
|
-
}
|
|
3386
|
-
function RangeField({
|
|
3387
|
-
field,
|
|
3388
|
-
value,
|
|
3389
|
-
onChange
|
|
3390
|
-
}) {
|
|
3391
|
-
const id = useId4();
|
|
3392
|
-
return /* @__PURE__ */ jsxs23("div", { children: [
|
|
3393
|
-
/* @__PURE__ */ jsx42(FormLabel, { htmlFor: id, children: field.label }),
|
|
3394
|
-
/* @__PURE__ */ jsx42(
|
|
3395
|
-
"input",
|
|
3396
|
-
{
|
|
3397
|
-
id,
|
|
3398
|
-
type: "range",
|
|
3399
|
-
min: field.min,
|
|
3400
|
-
max: field.max,
|
|
3401
|
-
step: field.step,
|
|
3402
|
-
value,
|
|
3403
|
-
onChange: (e) => onChange(Number(e.target.value)),
|
|
3404
|
-
className: cn(
|
|
3405
|
-
"w-full accent-primary"
|
|
3406
|
-
)
|
|
3407
|
-
}
|
|
3408
|
-
)
|
|
3409
|
-
] });
|
|
3410
|
-
}
|
|
3411
|
-
function renderField(key, field, value, handleFieldChange) {
|
|
3412
|
-
switch (field.type) {
|
|
3413
|
-
case "text":
|
|
3414
|
-
return /* @__PURE__ */ jsx42(
|
|
3415
|
-
Input,
|
|
3416
|
-
{
|
|
3417
|
-
label: field.label,
|
|
3418
|
-
value: String(value ?? ""),
|
|
3419
|
-
placeholder: field.placeholder,
|
|
3420
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3421
|
-
},
|
|
3422
|
-
key
|
|
3423
|
-
);
|
|
3424
|
-
case "number":
|
|
3425
|
-
return /* @__PURE__ */ jsx42(
|
|
3426
|
-
Input,
|
|
3427
|
-
{
|
|
3428
|
-
label: field.label,
|
|
3429
|
-
type: "number",
|
|
3430
|
-
value: String(value ?? ""),
|
|
3431
|
-
onChange: (v) => handleFieldChange(key, v === "" ? "" : Number(v))
|
|
3432
|
-
},
|
|
3433
|
-
key
|
|
3434
|
-
);
|
|
3435
|
-
case "checkbox":
|
|
3436
|
-
return /* @__PURE__ */ jsx42(
|
|
3437
|
-
Checkbox,
|
|
3438
|
-
{
|
|
3439
|
-
label: field.label,
|
|
3440
|
-
checked: Boolean(value),
|
|
3441
|
-
onChange: (checked) => handleFieldChange(key, checked)
|
|
3442
|
-
},
|
|
3443
|
-
key
|
|
3444
|
-
);
|
|
3445
|
-
case "select":
|
|
3446
|
-
return /* @__PURE__ */ jsx42(
|
|
3447
|
-
Select,
|
|
3448
|
-
{
|
|
3449
|
-
label: field.label,
|
|
3450
|
-
value: String(value ?? ""),
|
|
3451
|
-
options: field.options,
|
|
3452
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3453
|
-
},
|
|
3454
|
-
key
|
|
3455
|
-
);
|
|
3456
|
-
case "range":
|
|
3457
|
-
return /* @__PURE__ */ jsx42(
|
|
3458
|
-
RangeField,
|
|
3459
|
-
{
|
|
3460
|
-
field,
|
|
3461
|
-
value: Number(value ?? field.min),
|
|
3462
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3463
|
-
},
|
|
3464
|
-
key
|
|
3465
|
-
);
|
|
3466
|
-
case "link":
|
|
3467
|
-
return /* @__PURE__ */ jsx42(
|
|
3468
|
-
LinkField,
|
|
3469
|
-
{
|
|
3470
|
-
label: field.label,
|
|
3471
|
-
value: value ?? field.default,
|
|
3472
|
-
onChange: (v) => handleFieldChange(key, v)
|
|
3473
|
-
},
|
|
3474
|
-
key
|
|
3475
|
-
);
|
|
3476
|
-
default:
|
|
3477
|
-
return null;
|
|
3478
|
-
}
|
|
3479
|
-
}
|
|
3480
|
-
function SettingsForm({ schema: schema8, values, onChange, tabs }) {
|
|
3481
|
-
const [local, setLocal] = useState16(() => resolveValues(schema8, values));
|
|
3482
|
-
function handleFieldChange(key, newValue) {
|
|
3483
|
-
const next = { ...local, [key]: newValue };
|
|
3484
|
-
setLocal(next);
|
|
3485
|
-
onChange(splitByTarget(schema8, next));
|
|
3486
|
-
}
|
|
3487
|
-
if (tabs) {
|
|
3488
|
-
const fields = (keys) => keys.filter((key) => key in schema8).map((key) => renderField(key, schema8[key], local[key], handleFieldChange));
|
|
3489
|
-
const listed = new Set(tabs.flatMap((t) => t.fields));
|
|
3490
|
-
const otherKeys = Object.keys(schema8).filter((key) => !listed.has(key));
|
|
3491
|
-
const tabItems = [
|
|
3492
|
-
...tabs.map((t) => ({ id: t.label, label: t.label, content: /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-4", children: fields(t.fields) }) })),
|
|
3493
|
-
...otherKeys.length > 0 ? [{ id: "__other__", label: "Other", content: /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-4", children: fields(otherKeys) }) }] : []
|
|
3494
|
-
];
|
|
3495
|
-
return /* @__PURE__ */ jsx42(Tabs, { tabs: tabItems, fullBleedTabBar: true });
|
|
3496
|
-
}
|
|
3497
|
-
return /* @__PURE__ */ jsx42("div", { className: "flex flex-col gap-4", children: Object.entries(schema8).map(([key, field]) => renderField(key, field, local[key], handleFieldChange)) });
|
|
3498
|
-
}
|
|
3499
|
-
|
|
3500
|
-
// src/hooks/useBlockDnd.ts
|
|
3501
|
-
import { useEffect as useEffect12, useRef as useRef11, useState as useState17 } from "react";
|
|
3502
|
-
|
|
3503
|
-
// src/lib/block-dnd.ts
|
|
3504
|
-
var ROOT_CONTAINER_ID = "__root__";
|
|
3505
|
-
function buildBlockDragData(args) {
|
|
3506
|
-
return { dragType: "block", ...args };
|
|
3507
|
-
}
|
|
3508
|
-
function buildBlockDropData(args) {
|
|
3509
|
-
return { ...args };
|
|
3510
|
-
}
|
|
3511
|
-
function isBlockDragData(data) {
|
|
3512
|
-
return data.dragType === "block";
|
|
3513
|
-
}
|
|
3514
|
-
function canDropBlock(source, dropContainerId) {
|
|
3515
|
-
if (source.blockId === dropContainerId) return false;
|
|
3516
|
-
if (source.isContainer && dropContainerId !== ROOT_CONTAINER_ID) return false;
|
|
3517
|
-
return true;
|
|
3518
|
-
}
|
|
3519
|
-
|
|
3520
405
|
// src/hooks/useBlockDnd.ts
|
|
406
|
+
import { useEffect, useRef as useRef2, useState as useState2 } from "react";
|
|
3521
407
|
function useBlockDnd({ blockId, containerId, index, isContainer, allowedEdges, enabled }) {
|
|
3522
|
-
const dragRef =
|
|
3523
|
-
const handleRef =
|
|
3524
|
-
const [closestEdge, setClosestEdge] =
|
|
3525
|
-
const [isDragging, setIsDragging] =
|
|
3526
|
-
|
|
408
|
+
const dragRef = useRef2(null);
|
|
409
|
+
const handleRef = useRef2(null);
|
|
410
|
+
const [closestEdge, setClosestEdge] = useState2(null);
|
|
411
|
+
const [isDragging, setIsDragging] = useState2(false);
|
|
412
|
+
useEffect(() => {
|
|
3527
413
|
const element = dragRef.current;
|
|
3528
414
|
const handle = handleRef.current;
|
|
3529
415
|
if (!element || !enabled) return;
|
|
@@ -3579,9 +465,9 @@ function useBlockDnd({ blockId, containerId, index, isContainer, allowedEdges, e
|
|
|
3579
465
|
return { dragRef, handleRef, closestEdge, isDragging };
|
|
3580
466
|
}
|
|
3581
467
|
function useBlockDropZone({ containerId, index, toColumn, allowedEdges, enabled }) {
|
|
3582
|
-
const dropRef =
|
|
3583
|
-
const [closestEdge, setClosestEdge] =
|
|
3584
|
-
|
|
468
|
+
const dropRef = useRef2(null);
|
|
469
|
+
const [closestEdge, setClosestEdge] = useState2(null);
|
|
470
|
+
useEffect(() => {
|
|
3585
471
|
const element = dropRef.current;
|
|
3586
472
|
if (!element || !enabled) return;
|
|
3587
473
|
let cleanup;
|
|
@@ -3678,7 +564,7 @@ function trimTrailingSpacers(container) {
|
|
|
3678
564
|
}
|
|
3679
565
|
|
|
3680
566
|
// src/components/sections/Container/Container.tsx
|
|
3681
|
-
import { jsx as
|
|
567
|
+
import { jsx as jsx11, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
3682
568
|
var ROW_EDGES = ["left", "right"];
|
|
3683
569
|
var COL_EDGES = ["top", "bottom"];
|
|
3684
570
|
function ContainerChild({
|
|
@@ -3709,14 +595,14 @@ function ContainerChild({
|
|
|
3709
595
|
allowedEdges: flow === "column" ? COL_EDGES : ROW_EDGES,
|
|
3710
596
|
enabled: true
|
|
3711
597
|
});
|
|
3712
|
-
return /* @__PURE__ */
|
|
598
|
+
return /* @__PURE__ */ jsx11(
|
|
3713
599
|
"div",
|
|
3714
600
|
{
|
|
3715
601
|
ref: dragRef,
|
|
3716
602
|
className: cellClass,
|
|
3717
603
|
"data-child-index": index,
|
|
3718
604
|
"data-child-id": child.id,
|
|
3719
|
-
children: /* @__PURE__ */
|
|
605
|
+
children: /* @__PURE__ */ jsx11(
|
|
3720
606
|
ChildBlockWrapper,
|
|
3721
607
|
{
|
|
3722
608
|
label,
|
|
@@ -3730,7 +616,7 @@ function ContainerChild({
|
|
|
3730
616
|
onDuplicate,
|
|
3731
617
|
onColSpanChange,
|
|
3732
618
|
onOpenSettings,
|
|
3733
|
-
children: /* @__PURE__ */
|
|
619
|
+
children: /* @__PURE__ */ jsx11(
|
|
3734
620
|
ChildComp,
|
|
3735
621
|
{
|
|
3736
622
|
content: child,
|
|
@@ -3758,7 +644,7 @@ function EmptyColumnCell({
|
|
|
3758
644
|
enabled: true
|
|
3759
645
|
});
|
|
3760
646
|
const active = closestEdge !== null;
|
|
3761
|
-
return /* @__PURE__ */
|
|
647
|
+
return /* @__PURE__ */ jsx11(
|
|
3762
648
|
"div",
|
|
3763
649
|
{
|
|
3764
650
|
ref: dropRef,
|
|
@@ -3796,7 +682,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3796
682
|
flow === "column" && "grid-flow-col"
|
|
3797
683
|
);
|
|
3798
684
|
if (!editable) {
|
|
3799
|
-
return /* @__PURE__ */
|
|
685
|
+
return /* @__PURE__ */ jsx11("div", { className: "@container", children: /* @__PURE__ */ jsx11("div", { className: gridClass, children: children.map((child, index) => {
|
|
3800
686
|
const def = getSection(child.type);
|
|
3801
687
|
if (!def) return null;
|
|
3802
688
|
const Child = def.component;
|
|
@@ -3807,7 +693,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3807
693
|
colSpanClass[columns]?.[Math.min(span, columns)] || void 0,
|
|
3808
694
|
child.type === "spacer" && spacerHiddenClass[columns]
|
|
3809
695
|
);
|
|
3810
|
-
return /* @__PURE__ */
|
|
696
|
+
return /* @__PURE__ */ jsx11("div", { className: cellClass, children: /* @__PURE__ */ jsx11(Child, { content: child, options: mergedOptions, isEditMode }) }, child.id ?? index);
|
|
3811
697
|
}) }) });
|
|
3812
698
|
}
|
|
3813
699
|
function columnStartOf(index) {
|
|
@@ -3821,7 +707,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3821
707
|
const def = getSection(child.type);
|
|
3822
708
|
if (!def) return null;
|
|
3823
709
|
if (isSpacer(child)) {
|
|
3824
|
-
return /* @__PURE__ */
|
|
710
|
+
return /* @__PURE__ */ jsx11(
|
|
3825
711
|
EmptyColumnCell,
|
|
3826
712
|
{
|
|
3827
713
|
containerId: container.id,
|
|
@@ -3849,12 +735,12 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3849
735
|
const CustomForm = def.settingsForm;
|
|
3850
736
|
openModal(
|
|
3851
737
|
`${def.label} Settings`,
|
|
3852
|
-
/* @__PURE__ */
|
|
738
|
+
/* @__PURE__ */ jsx11(CustomForm, { ...seed, onChange: applyResult })
|
|
3853
739
|
);
|
|
3854
740
|
} else if (def.settings) {
|
|
3855
741
|
openModal(
|
|
3856
742
|
`${def.label} Settings`,
|
|
3857
|
-
/* @__PURE__ */
|
|
743
|
+
/* @__PURE__ */ jsx11(
|
|
3858
744
|
SettingsForm,
|
|
3859
745
|
{
|
|
3860
746
|
schema: def.settings,
|
|
@@ -3866,7 +752,7 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3866
752
|
);
|
|
3867
753
|
}
|
|
3868
754
|
} : void 0;
|
|
3869
|
-
return /* @__PURE__ */
|
|
755
|
+
return /* @__PURE__ */ jsx11(
|
|
3870
756
|
ContainerChild,
|
|
3871
757
|
{
|
|
3872
758
|
containerId: container.id,
|
|
@@ -3892,9 +778,9 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3892
778
|
}
|
|
3893
779
|
const occupied = occupiedColumns(children, columns);
|
|
3894
780
|
const emptyCols = occupied < columns ? columns - occupied : 0;
|
|
3895
|
-
return /* @__PURE__ */
|
|
781
|
+
return /* @__PURE__ */ jsx11("div", { className: "@container", children: /* @__PURE__ */ jsxs4("div", { className: gridClass, children: [
|
|
3896
782
|
children.map(renderEditChild),
|
|
3897
|
-
Array.from({ length: emptyCols }, (_, i) => /* @__PURE__ */
|
|
783
|
+
Array.from({ length: emptyCols }, (_, i) => /* @__PURE__ */ jsx11(
|
|
3898
784
|
EmptyColumnCell,
|
|
3899
785
|
{
|
|
3900
786
|
containerId: container.id,
|
|
@@ -3907,8 +793,8 @@ function Container({ content, isEditMode, onChange, openModal }) {
|
|
|
3907
793
|
}
|
|
3908
794
|
|
|
3909
795
|
// src/components/sections/Container/ContainerSettingsForm.tsx
|
|
3910
|
-
import { useState as
|
|
3911
|
-
import { jsx as
|
|
796
|
+
import { useState as useState3 } from "react";
|
|
797
|
+
import { jsx as jsx12, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
3912
798
|
function inheritableSchema(children) {
|
|
3913
799
|
const out = {};
|
|
3914
800
|
for (const child of children) {
|
|
@@ -3928,8 +814,8 @@ function ContainerSettingsForm({
|
|
|
3928
814
|
children = [],
|
|
3929
815
|
onChange
|
|
3930
816
|
}) {
|
|
3931
|
-
const [layout, setLayout] =
|
|
3932
|
-
const [defaults, setDefaults] =
|
|
817
|
+
const [layout, setLayout] = useState3({ columns, flow });
|
|
818
|
+
const [defaults, setDefaults] = useState3(childDefaults);
|
|
3933
819
|
const childSchema = inheritableSchema(children);
|
|
3934
820
|
const hasChildDefaults = Object.keys(childSchema).length > 0;
|
|
3935
821
|
function emit(nextLayout, nextDefaults) {
|
|
@@ -3958,10 +844,10 @@ function ContainerSettingsForm({
|
|
|
3958
844
|
]
|
|
3959
845
|
}
|
|
3960
846
|
};
|
|
3961
|
-
return /* @__PURE__ */
|
|
3962
|
-
/* @__PURE__ */
|
|
3963
|
-
/* @__PURE__ */
|
|
3964
|
-
/* @__PURE__ */
|
|
847
|
+
return /* @__PURE__ */ jsxs5("div", { className: "flex flex-col gap-6", children: [
|
|
848
|
+
/* @__PURE__ */ jsxs5("fieldset", { className: "flex flex-col gap-4", children: [
|
|
849
|
+
/* @__PURE__ */ jsx12("legend", { className: "mb-2 text-sm font-semibold text-base-contrast", children: "Layout" }),
|
|
850
|
+
/* @__PURE__ */ jsx12(
|
|
3965
851
|
SettingsForm,
|
|
3966
852
|
{
|
|
3967
853
|
schema: layoutSchema,
|
|
@@ -3977,9 +863,9 @@ function ContainerSettingsForm({
|
|
|
3977
863
|
}
|
|
3978
864
|
)
|
|
3979
865
|
] }),
|
|
3980
|
-
hasChildDefaults && /* @__PURE__ */
|
|
3981
|
-
/* @__PURE__ */
|
|
3982
|
-
/* @__PURE__ */
|
|
866
|
+
hasChildDefaults && /* @__PURE__ */ jsxs5("fieldset", { className: "flex flex-col gap-4 border-t border-base-200 pt-4", children: [
|
|
867
|
+
/* @__PURE__ */ jsx12("legend", { className: "mb-2 text-sm font-semibold text-base-contrast", children: "Apply to all items" }),
|
|
868
|
+
/* @__PURE__ */ jsx12(
|
|
3983
869
|
SettingsForm,
|
|
3984
870
|
{
|
|
3985
871
|
schema: childSchema,
|
|
@@ -3996,16 +882,16 @@ function ContainerSettingsForm({
|
|
|
3996
882
|
}
|
|
3997
883
|
|
|
3998
884
|
// src/components/sections/Container/index.tsx
|
|
3999
|
-
import { jsx as
|
|
4000
|
-
var
|
|
4001
|
-
type:
|
|
4002
|
-
content:
|
|
4003
|
-
columns:
|
|
4004
|
-
flow:
|
|
4005
|
-
childDefaults:
|
|
885
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
886
|
+
var schema4 = z4.object({
|
|
887
|
+
type: z4.literal("container"),
|
|
888
|
+
content: z4.object({
|
|
889
|
+
columns: z4.number().int().min(1).max(MAX_CONTAINER_COLUMNS).default(1),
|
|
890
|
+
flow: z4.enum(["row", "column"]).default("row"),
|
|
891
|
+
childDefaults: z4.record(z4.string(), z4.unknown()).optional(),
|
|
4006
892
|
// Recursive: children are full blocks. z.lazy defers evaluation to parse
|
|
4007
893
|
// time, by which point every section schema (incl. container) is registered.
|
|
4008
|
-
children:
|
|
894
|
+
children: z4.array(z4.lazy(() => getSectionSchema())).default([])
|
|
4009
895
|
}).transform((c) => ({
|
|
4010
896
|
...c,
|
|
4011
897
|
children: c.children.map(
|
|
@@ -4016,9 +902,9 @@ var schema6 = z7.object({
|
|
|
4016
902
|
var Container_default = defineSection({
|
|
4017
903
|
type: "container",
|
|
4018
904
|
label: "Container",
|
|
4019
|
-
icon: /* @__PURE__ */
|
|
4020
|
-
schema:
|
|
4021
|
-
component: ({ content, onChange, isEditMode, openModal }) => /* @__PURE__ */
|
|
905
|
+
icon: /* @__PURE__ */ jsx13(LayoutTemplate, { size: 18 }),
|
|
906
|
+
schema: schema4,
|
|
907
|
+
component: ({ content, onChange, isEditMode, openModal }) => /* @__PURE__ */ jsx13(Container, { content, isEditMode: !!isEditMode, onChange, openModal }),
|
|
4022
908
|
defaults: () => ({
|
|
4023
909
|
type: "container",
|
|
4024
910
|
content: { columns: 1, flow: "row", children: [] }
|
|
@@ -4028,44 +914,45 @@ var Container_default = defineSection({
|
|
|
4028
914
|
});
|
|
4029
915
|
|
|
4030
916
|
// src/components/sections/Spacer/index.tsx
|
|
4031
|
-
import { z as
|
|
917
|
+
import { z as z5 } from "zod";
|
|
4032
918
|
import { SquareDashed } from "lucide-react";
|
|
4033
919
|
|
|
4034
920
|
// src/components/sections/Spacer/Spacer.tsx
|
|
4035
|
-
import { jsx as
|
|
921
|
+
import { jsx as jsx14 } from "react/jsx-runtime";
|
|
4036
922
|
function Spacer() {
|
|
4037
|
-
return /* @__PURE__ */
|
|
923
|
+
return /* @__PURE__ */ jsx14("div", { "data-spacer": true, "aria-hidden": "true", className: "h-full" });
|
|
4038
924
|
}
|
|
4039
925
|
|
|
4040
926
|
// src/components/sections/Spacer/index.tsx
|
|
4041
|
-
import { jsx as
|
|
4042
|
-
var
|
|
4043
|
-
type:
|
|
4044
|
-
content:
|
|
927
|
+
import { jsx as jsx15 } from "react/jsx-runtime";
|
|
928
|
+
var schema5 = z5.object({
|
|
929
|
+
type: z5.literal("spacer"),
|
|
930
|
+
content: z5.object({}).default({})
|
|
4045
931
|
});
|
|
4046
932
|
var Spacer_default = defineSection({
|
|
4047
933
|
type: "spacer",
|
|
4048
934
|
label: "Spacer",
|
|
4049
|
-
icon: /* @__PURE__ */
|
|
4050
|
-
schema:
|
|
4051
|
-
component: () => /* @__PURE__ */
|
|
935
|
+
icon: /* @__PURE__ */ jsx15(SquareDashed, { size: 18 }),
|
|
936
|
+
schema: schema5,
|
|
937
|
+
component: () => /* @__PURE__ */ jsx15(Spacer, {}),
|
|
4052
938
|
defaults: () => ({ type: "spacer", content: {} })
|
|
4053
939
|
});
|
|
4054
940
|
|
|
4055
|
-
// src/components/sections/
|
|
4056
|
-
var
|
|
941
|
+
// src/components/sections/core-sections.ts
|
|
942
|
+
var coreSectionDefs = [
|
|
4057
943
|
LinkHeading_default,
|
|
4058
944
|
SubHeading_default,
|
|
4059
945
|
SubSubHeading_default,
|
|
4060
946
|
Prose_default,
|
|
4061
947
|
Media_default,
|
|
4062
948
|
Button_default,
|
|
4063
|
-
Colors_default,
|
|
4064
|
-
IconList_default,
|
|
4065
949
|
Container_default,
|
|
4066
950
|
Spacer_default
|
|
4067
951
|
];
|
|
4068
952
|
|
|
953
|
+
// src/components/sections/all-sections.ts
|
|
954
|
+
var allSectionDefs = [...coreSectionDefs, ...brandGuideSectionDefs];
|
|
955
|
+
|
|
4069
956
|
// src/components/sections/register-schemas.ts
|
|
4070
957
|
var _ensured = false;
|
|
4071
958
|
function ensureSchemasRegistered() {
|