@drawnagency/primitives 0.1.55 → 0.1.57

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (173) hide show
  1. package/dist/auth/cookies.d.ts.map +1 -1
  2. package/dist/auth/index.js +1 -1
  3. package/dist/{chunk-24SUF2BC.js → chunk-ICLXLWQ5.js} +13 -74
  4. package/dist/chunk-NSCT3AMV.js +32 -0
  5. package/dist/{chunk-KDGYHU36.js → chunk-PRKUXM7E.js} +35 -10
  6. package/dist/{chunk-PUNXQK4M.js → chunk-PYWS3MOJ.js} +12 -2
  7. package/dist/chunk-TG43X7JO.js +123 -0
  8. package/dist/chunk-VKAGMEKE.js +90 -0
  9. package/dist/{chunk-B5VYSTPB.js → chunk-XTK4BR27.js} +1 -1
  10. package/dist/components/editor/ChildBlockWrapper.d.ts +19 -0
  11. package/dist/components/editor/ChildBlockWrapper.d.ts.map +1 -0
  12. package/dist/components/editor/ColSpanControl.d.ts +9 -0
  13. package/dist/components/editor/ColSpanControl.d.ts.map +1 -0
  14. package/dist/components/editor/SectionWrapper.d.ts +1 -1
  15. package/dist/components/editor/SectionWrapper.d.ts.map +1 -1
  16. package/dist/components/editor/SettingsForm.d.ts +5 -1
  17. package/dist/components/editor/SettingsForm.d.ts.map +1 -1
  18. package/dist/components/primitives/EditableGrid.d.ts.map +1 -1
  19. package/dist/components/primitives/IconPicker.d.ts +7 -1
  20. package/dist/components/primitives/IconPicker.d.ts.map +1 -1
  21. package/dist/components/sections/Container/Container.d.ts +20 -0
  22. package/dist/components/sections/Container/Container.d.ts.map +1 -0
  23. package/dist/components/sections/Container/ContainerSettingsForm.d.ts +17 -0
  24. package/dist/components/sections/Container/ContainerSettingsForm.d.ts.map +1 -0
  25. package/dist/components/sections/Container/index.d.ts +11 -0
  26. package/dist/components/sections/Container/index.d.ts.map +1 -0
  27. package/dist/components/sections/IconList/IconList.d.ts +1 -0
  28. package/dist/components/sections/IconList/IconList.d.ts.map +1 -1
  29. package/dist/components/sections/IconList/IconListSettings.d.ts +3 -4
  30. package/dist/components/sections/IconList/IconListSettings.d.ts.map +1 -1
  31. package/dist/components/sections/IconList/index.d.ts +1 -0
  32. package/dist/components/sections/IconList/index.d.ts.map +1 -1
  33. package/dist/components/sections/Media/MediaBlock.d.ts +19 -0
  34. package/dist/components/sections/Media/MediaBlock.d.ts.map +1 -0
  35. package/dist/components/sections/{MediaGrid → Media}/index.d.ts +15 -25
  36. package/dist/components/sections/Media/index.d.ts.map +1 -0
  37. package/dist/components/sections/Prose/index.d.ts.map +1 -1
  38. package/dist/components/sections/Spacer/Spacer.d.ts +2 -0
  39. package/dist/components/sections/Spacer/Spacer.d.ts.map +1 -0
  40. package/dist/components/sections/Spacer/index.d.ts +6 -0
  41. package/dist/components/sections/Spacer/index.d.ts.map +1 -0
  42. package/dist/components/sections/all-sections.d.ts +140 -0
  43. package/dist/components/sections/all-sections.d.ts.map +1 -0
  44. package/dist/components/sections/register-schemas.d.ts.map +1 -1
  45. package/dist/components/sections/register.d.ts.map +1 -1
  46. package/dist/components/shared/Tabs.d.ts +24 -0
  47. package/dist/components/shared/Tabs.d.ts.map +1 -0
  48. package/dist/components/shell/EditorShell.d.ts +2 -1
  49. package/dist/components/shell/EditorShell.d.ts.map +1 -1
  50. package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
  51. package/dist/components/shell/blockMoveDispatch.d.ts +21 -0
  52. package/dist/components/shell/blockMoveDispatch.d.ts.map +1 -0
  53. package/dist/hooks/useBlockDnd.d.ts +48 -0
  54. package/dist/hooks/useBlockDnd.d.ts.map +1 -0
  55. package/dist/hooks/useEditorPublish.d.ts +2 -1
  56. package/dist/hooks/useEditorPublish.d.ts.map +1 -1
  57. package/dist/index.js +69 -48
  58. package/dist/lib/block-dnd.d.ts +42 -0
  59. package/dist/lib/block-dnd.d.ts.map +1 -0
  60. package/dist/lib/block-move.d.ts +31 -0
  61. package/dist/lib/block-move.d.ts.map +1 -0
  62. package/dist/lib/container-grid.d.ts +29 -0
  63. package/dist/lib/container-grid.d.ts.map +1 -0
  64. package/dist/lib/container-ops.d.ts +44 -0
  65. package/dist/lib/container-ops.d.ts.map +1 -0
  66. package/dist/lib/dexie.d.ts +12 -1
  67. package/dist/lib/dexie.d.ts.map +1 -1
  68. package/dist/lib/dexie.js +28 -3
  69. package/dist/lib/index.js +10 -7
  70. package/dist/lib/loader.d.ts.map +1 -1
  71. package/dist/lib/migrate-sections-transform.d.ts +12 -0
  72. package/dist/lib/migrate-sections-transform.d.ts.map +1 -0
  73. package/dist/lib/migrate-sections-transform.js +6 -0
  74. package/dist/lib/registry.d.ts +39 -2
  75. package/dist/lib/registry.d.ts.map +1 -1
  76. package/dist/lib/registry.js +26 -0
  77. package/dist/lib/sanitize.d.ts.map +1 -1
  78. package/dist/schemas/block.d.ts +20 -0
  79. package/dist/schemas/block.d.ts.map +1 -0
  80. package/dist/schemas/block.js +14 -0
  81. package/dist/schemas/index.js +10 -2
  82. package/dist/schemas/link.d.ts +7 -0
  83. package/dist/schemas/link.d.ts.map +1 -1
  84. package/dist/schemas/rich-text.d.ts +9 -0
  85. package/dist/schemas/rich-text.d.ts.map +1 -0
  86. package/dist/schemas/sections.d.ts +2 -0
  87. package/dist/schemas/sections.d.ts.map +1 -1
  88. package/dist/schemas/shared.d.ts +31 -0
  89. package/dist/schemas/shared.d.ts.map +1 -1
  90. package/dist/storage/index.d.ts +1 -0
  91. package/dist/storage/index.d.ts.map +1 -1
  92. package/dist/storage/types.d.ts +13 -1
  93. package/dist/storage/types.d.ts.map +1 -1
  94. package/package.json +13 -1
  95. package/src/auth/cookies.ts +6 -1
  96. package/src/components/brandguide/Colors.tsx +35 -33
  97. package/src/components/editor/ChildBlockWrapper.tsx +108 -0
  98. package/src/components/editor/ColSpanControl.tsx +56 -0
  99. package/src/components/editor/SectionWrapper.tsx +44 -20
  100. package/src/components/editor/SettingsForm.tsx +100 -73
  101. package/src/components/primitives/EditableGrid.tsx +40 -36
  102. package/src/components/primitives/IconPicker.tsx +116 -26
  103. package/src/components/sections/Container/Container.tsx +354 -0
  104. package/src/components/sections/Container/ContainerSettingsForm.tsx +113 -0
  105. package/src/components/sections/Container/index.tsx +51 -0
  106. package/src/components/sections/IconList/IconList.tsx +113 -43
  107. package/src/components/sections/IconList/IconListSettings.tsx +2 -2
  108. package/src/components/sections/IconList/index.tsx +1 -1
  109. package/src/components/sections/Media/MediaBlock.tsx +103 -0
  110. package/src/components/sections/Media/index.tsx +85 -0
  111. package/src/components/sections/Prose/index.tsx +1 -0
  112. package/src/components/sections/Spacer/Spacer.tsx +6 -0
  113. package/src/components/sections/Spacer/index.tsx +18 -0
  114. package/src/components/sections/all-sections.ts +40 -0
  115. package/src/components/sections/register-schemas.ts +13 -18
  116. package/src/components/sections/register.ts +3 -17
  117. package/src/components/shared/Tabs.tsx +63 -0
  118. package/src/components/shell/EditorShell.tsx +147 -18
  119. package/src/components/shell/SiteSettingsModal.tsx +41 -51
  120. package/src/components/shell/blockMoveDispatch.ts +40 -0
  121. package/src/hooks/useBlockDnd.ts +144 -0
  122. package/src/hooks/useEditorPublish.ts +17 -4
  123. package/src/lib/block-dnd.ts +58 -0
  124. package/src/lib/block-move.ts +236 -0
  125. package/src/lib/container-grid.ts +58 -0
  126. package/src/lib/container-ops.ts +159 -0
  127. package/src/lib/dexie.ts +47 -0
  128. package/src/lib/loader.ts +16 -4
  129. package/src/lib/migrate-sections-transform.ts +147 -0
  130. package/src/lib/registry.ts +48 -2
  131. package/src/lib/sanitize.ts +22 -1
  132. package/src/schemas/block.ts +40 -0
  133. package/src/schemas/link.ts +19 -1
  134. package/src/schemas/rich-text.ts +11 -0
  135. package/src/schemas/sections.ts +5 -1
  136. package/src/schemas/shared.ts +16 -0
  137. package/src/schemas/site-config.ts +3 -3
  138. package/src/storage/index.ts +1 -0
  139. package/src/storage/types.ts +17 -0
  140. package/dist/components/brandguide/DoDontList.d.ts +0 -16
  141. package/dist/components/brandguide/DoDontList.d.ts.map +0 -1
  142. package/dist/components/brandguide/DoDontMediaGrid.d.ts +0 -16
  143. package/dist/components/brandguide/DoDontMediaGrid.d.ts.map +0 -1
  144. package/dist/components/primitives/MediaSettingsForms.d.ts +0 -23
  145. package/dist/components/primitives/MediaSettingsForms.d.ts.map +0 -1
  146. package/dist/components/sections/DoDontList/index.d.ts +0 -21
  147. package/dist/components/sections/DoDontList/index.d.ts.map +0 -1
  148. package/dist/components/sections/DoDontMediaGrid/index.d.ts +0 -55
  149. package/dist/components/sections/DoDontMediaGrid/index.d.ts.map +0 -1
  150. package/dist/components/sections/MediaGrid/MediaGrid.d.ts +0 -17
  151. package/dist/components/sections/MediaGrid/MediaGrid.d.ts.map +0 -1
  152. package/dist/components/sections/MediaGrid/index.d.ts.map +0 -1
  153. package/dist/components/sections/SplitContent/SplitContent.d.ts +0 -14
  154. package/dist/components/sections/SplitContent/SplitContent.d.ts.map +0 -1
  155. package/dist/components/sections/SplitContent/index.d.ts +0 -13
  156. package/dist/components/sections/SplitContent/index.d.ts.map +0 -1
  157. package/src/components/brandguide/DoDontList.d.ts.map +0 -1
  158. package/src/components/brandguide/DoDontList.tsx +0 -67
  159. package/src/components/brandguide/DoDontMediaGrid.d.ts.map +0 -1
  160. package/src/components/brandguide/DoDontMediaGrid.tsx +0 -19
  161. package/src/components/primitives/MediaSettingsForms.tsx +0 -128
  162. package/src/components/sections/DoDontList/index.d.ts.map +0 -1
  163. package/src/components/sections/DoDontList/index.tsx +0 -45
  164. package/src/components/sections/DoDontMediaGrid/index.d.ts.map +0 -1
  165. package/src/components/sections/DoDontMediaGrid/index.tsx +0 -63
  166. package/src/components/sections/MediaGrid/MediaGrid.d.ts.map +0 -1
  167. package/src/components/sections/MediaGrid/MediaGrid.tsx +0 -239
  168. package/src/components/sections/MediaGrid/index.d.ts.map +0 -1
  169. package/src/components/sections/MediaGrid/index.tsx +0 -57
  170. package/src/components/sections/SplitContent/SplitContent.d.ts.map +0 -1
  171. package/src/components/sections/SplitContent/SplitContent.tsx +0 -84
  172. package/src/components/sections/SplitContent/index.d.ts.map +0 -1
  173. package/src/components/sections/SplitContent/index.tsx +0 -55
@@ -1,63 +0,0 @@
1
- import { defineSection } from "../../../lib/registry";
2
- import { z } from "zod";
3
- import { GalleryVerticalEnd } from "lucide-react";
4
- import { MediaReferenceSchema } from "../../../schemas/shared";
5
- import { MediaGridOptionsSchema } from "../../../schemas/media-grid-options";
6
- import DoDontMediaGrid from "../../brandguide/DoDontMediaGrid";
7
-
8
- const schema = z.object({
9
- type: z.literal("do_dont_grid"),
10
- content: z.object({
11
- columns: z.number().int().min(1).max(5),
12
- media: z.array(MediaReferenceSchema),
13
- }),
14
- options: MediaGridOptionsSchema,
15
- });
16
-
17
- export default defineSection({
18
- type: "do_dont_grid",
19
- label: "Do / Don't Grid",
20
- icon: <GalleryVerticalEnd size={18} />,
21
- schema,
22
- component: ({ content, options, onChange, openModal }) => (
23
- <DoDontMediaGrid
24
- media={content.content.media}
25
- columns={content.content.columns}
26
- square={options?.square as boolean}
27
- border={options?.border as boolean}
28
- crop={options?.crop as boolean}
29
- showCaptions={options?.showCaptions as boolean}
30
- onChange={onChange ? (c) => onChange(c as typeof content) : undefined}
31
- openModal={openModal}
32
- />
33
- ),
34
- defaults: () => ({
35
- type: "do_dont_grid" as const,
36
- options: {},
37
- content: {
38
- columns: 2,
39
- media: [
40
- { type: "doDontImage" as const, imageId: "", doDont: "do" as const },
41
- { type: "doDontImage" as const, imageId: "", doDont: "dont" as const },
42
- ],
43
- },
44
- }),
45
- getLabel: (content) => {
46
- const n = content.content.media.length;
47
- return `${n} item${n === 1 ? "" : "s"}`;
48
- },
49
- getThumbnails: (content) =>
50
- content.content.media
51
- .filter((m) => m.imageId)
52
- .map((m) => ({ type: "image" as const, src: m.imageId })),
53
- settings: {
54
- columns: {
55
- type: "select", label: "Columns", default: "2", target: "content", coerce: "number",
56
- options: [{ label: "1", value: "1" }, { label: "2", value: "2" }, { label: "3", value: "3" }, { label: "4", value: "4" }],
57
- },
58
- border: { type: "checkbox", label: "Show border", default: false },
59
- square: { type: "checkbox", label: "Square aspect ratio", default: false },
60
- crop: { type: "checkbox", label: "Crop to fill", default: false },
61
- showCaptions: { type: "checkbox", label: "Show captions", default: false },
62
- },
63
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"MediaGrid.d.ts","sourceRoot":"","sources":["MediaGrid.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAOhE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAIvC,UAAU,KAAK;IACb,KAAK,EAAE,cAAc,EAAE,CAAC;IACxB,OAAO,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,SAAS,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,SAAS,KAAK,IAAI,CAAC;CACzD;AAED,MAAM,CAAC,OAAO,UAAU,SAAS,CAAC,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,EAAE,KAAK,2CAgChI"}
@@ -1,239 +0,0 @@
1
- import type { MediaReference } from "../../../schemas/shared";
2
- import type { SectionContent } from "../../../schemas/sections";
3
- import { cn } from "../../../lib/cn";
4
- import { gridColsClass } from "../../../lib/grid";
5
- import { EditableGrid } from "../../primitives/EditableGrid";
6
- import { ResolvedMedia } from "../../primitives/ResolvedMedia";
7
- import { ImageSettingsForm, DoDontImageSettingsForm } from "../../primitives/MediaSettingsForms";
8
- import { EditablePlainText } from "../../primitives/EditablePlainText";
9
- import type { ReactNode } from "react";
10
- import { Check, X } from "lucide-react";
11
- import { useMediaLibrary } from "../../shell/MediaLibraryContext";
12
- import { ImageDropZone } from "../../primitives/ImageDropZone";
13
-
14
- interface Props {
15
- media: MediaReference[];
16
- columns: number;
17
- square?: boolean;
18
- border?: boolean;
19
- crop?: boolean;
20
- showCaptions?: boolean;
21
- sectionType?: string;
22
- onChange?: (content: SectionContent) => void;
23
- openModal?: (title: string, content: ReactNode) => void;
24
- }
25
-
26
- export default function MediaGrid({ media, columns, square, border, crop, showCaptions, sectionType, onChange, openModal }: Props) {
27
- if (onChange && openModal) {
28
- return (
29
- <MediaGridEditable
30
- media={media}
31
- columns={columns}
32
- square={square}
33
- border={border}
34
- crop={crop}
35
- showCaptions={showCaptions}
36
- sectionType={sectionType}
37
- onChange={onChange}
38
- openModal={openModal}
39
- />
40
- );
41
- }
42
-
43
- return (
44
- <div className={cn("grid gap-4", gridColsClass[columns] || "grid-cols-1")}>
45
- {media.map((item, i) => (
46
- <MediaGridItem
47
- key={i}
48
- item={item}
49
- isEditMode={false}
50
- square={square}
51
- border={border}
52
- crop={crop}
53
- showCaptions={showCaptions}
54
- />
55
- ))}
56
- </div>
57
- );
58
- }
59
-
60
- function MediaGridEditable({ media, columns, square, border, crop, showCaptions, sectionType = "media_grid", onChange, openModal }: Props & { onChange: (content: SectionContent) => void; openModal: (title: string, content: ReactNode) => void }) {
61
- const mediaLibrary = useMediaLibrary();
62
-
63
- const opts = square || border || crop || showCaptions
64
- ? { options: { square, border, crop, showCaptions } }
65
- : {};
66
-
67
- const createItem = (): MediaReference =>
68
- sectionType === "do_dont_grid"
69
- ? { type: "doDontImage", imageId: "", doDont: "do" }
70
- : { type: "image", imageId: "" };
71
-
72
- const handleItemSettings = (index: number) => {
73
- const item = media[index];
74
-
75
- if (item.type === "doDontImage") {
76
- openModal(
77
- "Image Settings",
78
- <DoDontImageSettingsForm
79
- border={item.border}
80
- objectFit={item.objectFit}
81
- invertFrom={item.invertFrom}
82
- doDont={item.doDont}
83
- onChange={(updated) => {
84
- const newMedia = media.map((m, i) => i === index ? { ...m, ...updated } : m);
85
- onChange({ type: sectionType, content: { columns, media: newMedia }, ...opts } as SectionContent);
86
- }}
87
- />,
88
- );
89
- } else {
90
- openModal(
91
- "Image Settings",
92
- <ImageSettingsForm
93
- border={item.border}
94
- objectFit={item.objectFit}
95
- invertFrom={item.invertFrom}
96
- onChange={(updated) => {
97
- const newMedia = media.map((m, i) => i === index ? { ...m, ...updated } : m);
98
- onChange({ type: sectionType, content: { columns, media: newMedia }, ...opts } as SectionContent);
99
- }}
100
- />,
101
- );
102
- }
103
- };
104
-
105
- const setItemImage = (index: number, imageId: string) => {
106
- const newMedia = media.map((m, i) => i === index ? { ...m, imageId } : m);
107
- onChange({ type: sectionType, content: { columns, media: newMedia }, ...opts } as SectionContent);
108
- };
109
-
110
- const handleItemImageClick = (index: number) => {
111
- mediaLibrary?.openSelectModal((imageId) => setItemImage(index, imageId));
112
- };
113
-
114
- return (
115
- <EditableGrid
116
- items={media}
117
- columns={columns}
118
- onChange={(newMedia) =>
119
- onChange({ type: sectionType, content: { columns, media: newMedia as MediaReference[] }, ...opts } as SectionContent)
120
- }
121
- createItem={createItem}
122
- isEditMode={true}
123
- onItemSettings={handleItemSettings}
124
- onItemImageClick={mediaLibrary ? handleItemImageClick : undefined}
125
- chromeTopClass={sectionType === "do_dont_grid" ? "top-[50px]" : undefined}
126
- renderItem={(item, { isEditMode, index }) => (
127
- <MediaGridItem
128
- item={item}
129
- isEditMode={isEditMode}
130
- square={square}
131
- border={border}
132
- crop={crop}
133
- showCaptions={showCaptions}
134
- onImageReplace={mediaLibrary ? (imageId) => setItemImage(index, imageId) : undefined}
135
- onCaptionChange={(caption) => {
136
- const newMedia = media.map((m, i) => i === index ? { ...m, caption: caption || undefined } : m);
137
- onChange({ type: sectionType, content: { columns, media: newMedia }, ...opts } as SectionContent);
138
- }}
139
- />
140
- )}
141
- />
142
- );
143
- }
144
-
145
- function MediaGridItem({
146
- item,
147
- isEditMode,
148
- square,
149
- border,
150
- crop,
151
- showCaptions,
152
- onCaptionChange,
153
- onImageReplace,
154
- }: {
155
- item: MediaReference;
156
- isEditMode: boolean;
157
- square?: boolean;
158
- border?: boolean;
159
- crop?: boolean;
160
- showCaptions?: boolean;
161
- onCaptionChange?: (caption: string) => void;
162
- onImageReplace?: (imageId: string) => void;
163
- }) {
164
- const isDoDont = item.type === "doDontImage";
165
-
166
- const showBorder = item.border ?? border;
167
- const itemFit = item.objectFit ?? (crop ? "cover" : undefined);
168
-
169
- const fitClass = itemFit === "cover" ? "object-cover" : "object-contain";
170
-
171
- const captionStr = item.caption
172
- ? (Array.isArray(item.caption) ? item.caption.join("\n") : item.caption)
173
- : "";
174
-
175
- const itemAny = item as Record<string, unknown>;
176
- const resolvedMedia = (
177
- <ResolvedMedia
178
- imageId={item.imageId || undefined}
179
- src={itemAny.src as string | undefined}
180
- srcset={itemAny.srcset as string | undefined}
181
- alt={itemAny.alt as string | undefined}
182
- className="h-full w-full"
183
- imgClassName={fitClass}
184
- invertFrom={item.invertFrom}
185
- />
186
- );
187
- const media = onImageReplace ? (
188
- <ImageDropZone onImageSelected={onImageReplace} className="h-full w-full">
189
- {resolvedMedia}
190
- </ImageDropZone>
191
- ) : (
192
- resolvedMedia
193
- );
194
-
195
- return (
196
- <figure>
197
- {isDoDont && (
198
- <div className="flex h-10 items-center justify-center pb-1">
199
- {item.doDont === "do"
200
- ? <Check size={28} className="text-green-600" />
201
- : <X size={28} className="text-red-600" />
202
- }
203
- </div>
204
- )}
205
-
206
- <div className={cn(
207
- "overflow-hidden rounded-md",
208
- showBorder && "border border-base-200",
209
- square && "aspect-square",
210
- )}>
211
- {item.type === "linkedImage" && !isEditMode ? (
212
- <a href={item.href} target={item.target} className="group block">
213
- {media}
214
- {item.linkText && (
215
- <span className="mt-2 block text-sm text-primary group-hover:underline">{item.linkText}</span>
216
- )}
217
- </a>
218
- ) : media}
219
- </div>
220
-
221
- {showCaptions && (
222
- <figcaption className="mt-2 min-h-[1em] text-sm text-base-contrast-light">
223
- {isEditMode && onCaptionChange ? (
224
- <EditablePlainText
225
- tag="span"
226
- value={captionStr}
227
- onChange={onCaptionChange}
228
- isEditMode={true}
229
- placeholder="Caption"
230
- className="block min-h-[1em]"
231
- />
232
- ) : (
233
- captionStr || " "
234
- )}
235
- </figcaption>
236
- )}
237
- </figure>
238
- );
239
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.tsx"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAeA,wBA+BG"}
@@ -1,57 +0,0 @@
1
- import { defineSection } from "../../../lib/registry";
2
- import { z } from "zod";
3
- import { LayoutGrid } from "lucide-react";
4
- import { MediaReferenceSchema } from "../../../schemas/shared";
5
- import { MediaGridOptionsSchema } from "../../../schemas/media-grid-options";
6
- import MediaGrid from "./MediaGrid";
7
-
8
- const schema = z.object({
9
- type: z.literal("media_grid"),
10
- content: z.object({
11
- columns: z.number().int().min(1).max(5),
12
- media: z.array(MediaReferenceSchema),
13
- }),
14
- options: MediaGridOptionsSchema,
15
- });
16
-
17
- export default defineSection({
18
- type: "media_grid",
19
- label: "Media Grid",
20
- icon: <LayoutGrid size={18} />,
21
- schema,
22
- component: ({ content, options, onChange, openModal }) => (
23
- <MediaGrid
24
- media={content.content.media}
25
- columns={content.content.columns}
26
- square={options?.square as boolean}
27
- border={options?.border as boolean}
28
- crop={options?.crop as boolean}
29
- showCaptions={options?.showCaptions as boolean}
30
- onChange={onChange ? (c) => onChange(c as typeof content) : undefined}
31
- openModal={openModal}
32
- />
33
- ),
34
- defaults: () => ({
35
- type: "media_grid" as const,
36
- content: { columns: 2, media: [{ type: "image" as const, imageId: "" }] },
37
- options: {},
38
- }),
39
- getLabel: (content) => {
40
- const n = content.content.media.length;
41
- return `${n} image${n === 1 ? "" : "s"}`;
42
- },
43
- getThumbnails: (content) =>
44
- content.content.media
45
- .filter((m) => m.imageId)
46
- .map((m) => ({ type: "image" as const, src: m.imageId })),
47
- settings: {
48
- columns: {
49
- type: "select", label: "Columns", default: "2", target: "content", coerce: "number",
50
- options: [{ label: "1", value: "1" }, { label: "2", value: "2" }, { label: "3", value: "3" }, { label: "4", value: "4" }],
51
- },
52
- border: { type: "checkbox", label: "Show border", default: false },
53
- square: { type: "checkbox", label: "Square aspect ratio", default: false },
54
- crop: { type: "checkbox", label: "Crop to fill", default: false },
55
- showCaptions: { type: "checkbox", label: "Show captions", default: false },
56
- },
57
- });
@@ -1 +0,0 @@
1
- {"version":3,"file":"SplitContent.d.ts","sourceRoot":"","sources":["SplitContent.tsx"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,2BAA2B,CAAC;AAIhE,UAAU,KAAK;IACb,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;IACjC,QAAQ,CAAC,EAAE,CAAC,OAAO,EAAE,cAAc,KAAK,IAAI,CAAC;CAC9C;AAED,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,aAAsB,EAAE,QAAQ,EAAE,EAAE,KAAK,2CA2DtG"}
@@ -1,84 +0,0 @@
1
- import { cn } from "../../../lib/cn";
2
- import { sanitizeHtml } from "../../../lib/sanitize";
3
- import { ResolvedMedia } from "../../primitives/ResolvedMedia";
4
- import { EditableRichText } from "../../primitives/EditableRichText";
5
- import { IconButton } from "../../shared/IconButton";
6
- import { ImageDropZone } from "../../primitives/ImageDropZone";
7
- import type { SectionContent } from "../../../schemas/sections";
8
- import { useMediaLibrary } from "../../shell/MediaLibraryContext";
9
- import { ImageIcon } from "lucide-react";
10
-
11
- interface Props {
12
- imageId: string | undefined;
13
- src?: string;
14
- srcset?: string;
15
- alt?: string;
16
- body: string;
17
- border?: boolean;
18
- imagePosition?: "left" | "right";
19
- onChange?: (content: SectionContent) => void;
20
- }
21
-
22
- export default function SplitContent({ imageId, src, srcset, alt, body, border, imagePosition = "left", onChange }: Props) {
23
- const mediaLibrary = useMediaLibrary();
24
-
25
- const handleImageChange = (newImageId: string) => {
26
- onChange?.({
27
- type: "split_content",
28
- content: { imageId: newImageId, body },
29
- options: { border, imagePosition },
30
- });
31
- };
32
-
33
- const handleBodyChange = (html: string) => {
34
- onChange?.({
35
- type: "split_content",
36
- content: { imageId, body: html, src, srcset, alt },
37
- options: { border, imagePosition },
38
- });
39
- };
40
-
41
- const handleImageClick = () => {
42
- mediaLibrary?.openSelectModal(handleImageChange);
43
- };
44
-
45
- return (
46
- <div className={cn(
47
- "flex flex-col gap-6 lg:flex-row lg:items-start",
48
- imagePosition === "right" && "lg:flex-row-reverse",
49
- )}>
50
- <div className={cn("group/img relative flex-shrink-0 lg:w-1/2", border && "overflow-hidden rounded-md border border-base-200")}>
51
- {onChange && mediaLibrary ? (
52
- <ImageDropZone onImageSelected={handleImageChange}>
53
- <ResolvedMedia imageId={imageId} src={src} srcset={srcset} alt={alt} className="w-full" />
54
- </ImageDropZone>
55
- ) : (
56
- <ResolvedMedia imageId={imageId} src={src} srcset={srcset} alt={alt} className="w-full" />
57
- )}
58
- {onChange && mediaLibrary && (
59
- <div className="absolute top-1.5 right-1.5 z-10 opacity-0 transition-opacity group-hover/img:opacity-100">
60
- <IconButton
61
- icon={<ImageIcon size={16} />}
62
- label="Change image"
63
- onClick={handleImageClick}
64
- className="bg-base/80 shadow-sm"
65
- />
66
- </div>
67
- )}
68
- </div>
69
- <div className="prose-content lg:w-1/2">
70
- {onChange ? (
71
- <EditableRichText
72
- value={body}
73
- onChange={handleBodyChange}
74
- isEditMode={true}
75
- preset="rich"
76
- />
77
- ) : (
78
- // eslint-disable-next-line react/no-danger
79
- <div dangerouslySetInnerHTML={{ __html: sanitizeHtml(body) }} />
80
- )}
81
- </div>
82
- </div>
83
- );
84
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["index.tsx"],"names":[],"mappings":";;;;;;;;;;;AAiBA,wBAkBG"}
@@ -1,55 +0,0 @@
1
- import { defineSection } from "../../../lib/registry";
2
- import { z } from "zod";
3
- import { Columns2 } from "lucide-react";
4
- import SplitContent from "./SplitContent";
5
- import { stripHtmlToPlainText, truncate } from "../../../lib/text";
6
-
7
- const schema = z.object({
8
- type: z.literal("split_content"),
9
- content: z.object({
10
- imageId: z.string().optional(),
11
- body: z.string(),
12
- }),
13
- options: z.object({
14
- border: z.boolean().optional(),
15
- imagePosition: z.enum(["left", "right"]).optional(),
16
- }).optional(),
17
- });
18
-
19
- export default defineSection({
20
- type: "split_content",
21
- label: "Split Content",
22
- icon: <Columns2 size={18} />,
23
- schema,
24
- component: ({ content, options, onChange }) => (
25
- <SplitContent
26
- imageId={content.content.imageId as string | undefined}
27
- src={(content.content as Record<string, unknown>).src as string | undefined}
28
- srcset={(content.content as Record<string, unknown>).srcset as string | undefined}
29
- alt={(content.content as Record<string, unknown>).alt as string | undefined}
30
- body={content.content.body as string}
31
- border={options?.border as boolean}
32
- imagePosition={options?.imagePosition as "left" | "right"}
33
- onChange={onChange ? (c) => onChange(c as typeof content) : undefined}
34
- />
35
- ),
36
- defaults: () => ({
37
- type: "split_content" as const,
38
- content: { imageId: undefined, body: "<p></p>" },
39
- }),
40
- settings: {
41
- imagePosition: {
42
- type: "select",
43
- label: "Image Position",
44
- default: "left",
45
- options: [
46
- { label: "Left", value: "left" },
47
- { label: "Right", value: "right" },
48
- ],
49
- },
50
- border: { type: "checkbox", label: "Show border", default: false },
51
- },
52
- getLabel: (content) => truncate(stripHtmlToPlainText(content.content.body), 60),
53
- getThumbnails: (content) =>
54
- content.content.imageId ? [{ type: "image" as const, src: content.content.imageId }] : [],
55
- });