@drawnagency/primitives 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auth/index.js +26 -3
- package/dist/chunk-2VTPWODA.js +60 -0
- package/dist/chunk-CS7F6IOY.js +39 -0
- package/dist/chunk-HOJAF4VD.js +264 -0
- package/dist/chunk-IP6ODLXX.js +341 -0
- package/dist/chunk-T4BJ6RSB.js +58 -0
- package/dist/chunk-UKEVUCIZ.js +200 -0
- package/dist/chunk-UMSFICAC.js +36 -0
- package/dist/index.js +156 -4
- package/dist/lib/index.js +62 -12
- package/dist/lib/sanitize.d.ts.map +1 -1
- package/dist/media/index.js +36 -9
- package/dist/schemas/index.js +52 -7
- package/package.json +5 -4
- package/src/lib/sanitize.ts +6 -2
- package/dist/auth/cookies.js +0 -44
- package/dist/auth/errors.js +0 -10
- package/dist/auth/security.js +0 -48
- package/dist/auth/types.js +0 -1
- package/dist/components/brandguide/ColorSwatchSettings.js +0 -10
- package/dist/components/brandguide/Colors.js +0 -79
- package/dist/components/brandguide/DoDontList.js +0 -22
- package/dist/components/brandguide/DoDontMediaGrid.js +0 -5
- package/dist/components/editor/AudiencePicker.js +0 -24
- package/dist/components/editor/DeleteButton.js +0 -6
- package/dist/components/editor/DragHandle.js +0 -8
- package/dist/components/editor/InsertButton.js +0 -7
- package/dist/components/editor/SectionWrapper.js +0 -135
- package/dist/components/editor/SettingsButton.js +0 -6
- package/dist/components/editor/SettingsForm.js +0 -64
- package/dist/components/editor/StatusBadge.js +0 -10
- package/dist/components/editor/StatusPicker.js +0 -30
- package/dist/components/editor/index.js +0 -7
- package/dist/components/primitives/CustomParagraph.js +0 -24
- package/dist/components/primitives/EditableGrid.js +0 -90
- package/dist/components/primitives/EditableList.js +0 -54
- package/dist/components/primitives/EditablePlainText.js +0 -52
- package/dist/components/primitives/EditableRichText.js +0 -86
- package/dist/components/primitives/HeadingSection.js +0 -7
- package/dist/components/primitives/IconPicker.js +0 -21
- package/dist/components/primitives/LinkPopover.js +0 -48
- package/dist/components/primitives/MediaSettingsForms.js +0 -42
- package/dist/components/primitives/ResolvedMedia.js +0 -9
- package/dist/components/primitives/RichTextToolbar.js +0 -26
- package/dist/components/primitives/tiptap-presets.js +0 -44
- package/dist/components/primitives/useEditableCollection.js +0 -61
- package/dist/components/primitives/useEditablePlainText.js +0 -27
- package/dist/components/primitives/useEditableRichText.js +0 -52
- package/dist/components/sections/Button/CTAButton.js +0 -18
- package/dist/components/sections/Button/index.js +0 -28
- package/dist/components/sections/Colors/index.js +0 -34
- package/dist/components/sections/DoDontList/index.js +0 -33
- package/dist/components/sections/DoDontMediaGrid/index.js +0 -41
- package/dist/components/sections/IconList/IconList.js +0 -131
- package/dist/components/sections/IconList/IconListSettings.js +0 -22
- package/dist/components/sections/IconList/index.js +0 -27
- package/dist/components/sections/LinkHeading/index.js +0 -15
- package/dist/components/sections/MediaGrid/MediaGrid.js +0 -62
- package/dist/components/sections/MediaGrid/index.js +0 -35
- package/dist/components/sections/Prose/Prose.js +0 -11
- package/dist/components/sections/Prose/index.js +0 -15
- package/dist/components/sections/SectionLayout.js +0 -15
- package/dist/components/sections/SplitContent/SplitContent.js +0 -31
- package/dist/components/sections/SplitContent/SplitContentSettings.js +0 -17
- package/dist/components/sections/SplitContent/index.js +0 -27
- package/dist/components/sections/SubHeading/index.js +0 -18
- package/dist/components/sections/SubSubHeading/index.js +0 -18
- package/dist/components/sections/ViewRenderer.js +0 -13
- package/dist/components/sections/register-schemas.js +0 -15
- package/dist/components/sections/register.js +0 -15
- package/dist/components/shared/Button.js +0 -27
- package/dist/components/shared/Checkbox.js +0 -10
- package/dist/components/shared/ColorPicker.js +0 -5
- package/dist/components/shared/ErrorBoundary.js +0 -30
- package/dist/components/shared/FontPicker.js +0 -190
- package/dist/components/shared/FormLabel.js +0 -5
- package/dist/components/shared/IconButton.js +0 -16
- package/dist/components/shared/Input.js +0 -8
- package/dist/components/shared/Navigation.js +0 -71
- package/dist/components/shared/PasswordInput.js +0 -11
- package/dist/components/shared/Popover.js +0 -33
- package/dist/components/shared/PopoverItem.js +0 -6
- package/dist/components/shared/Select.js +0 -9
- package/dist/components/shared/Textarea.js +0 -8
- package/dist/components/shared/Toggle.js +0 -5
- package/dist/components/shared/Tooltip.js +0 -8
- package/dist/components/shared/icons.js +0 -23
- package/dist/components/shell/AudienceAddForm.js +0 -43
- package/dist/components/shell/AudienceRow.js +0 -74
- package/dist/components/shell/EditorContext.js +0 -24
- package/dist/components/shell/EditorLoginForm.js +0 -46
- package/dist/components/shell/EditorModal.js +0 -43
- package/dist/components/shell/EditorModalContext.js +0 -20
- package/dist/components/shell/EditorShell.js +0 -483
- package/dist/components/shell/MediaLibraryContext.js +0 -5
- package/dist/components/shell/MediaLibraryModal.js +0 -145
- package/dist/components/shell/ProcessingIndicator.js +0 -15
- package/dist/components/shell/SectionSkeleton.js +0 -22
- package/dist/components/shell/SectionTypePicker.js +0 -15
- package/dist/components/shell/SiteSettingsDisplay.js +0 -28
- package/dist/components/shell/SiteSettingsModal.js +0 -40
- package/dist/components/shell/SiteSettingsUsers.js +0 -87
- package/dist/components/shell/SiteSettingsViewerAccess.js +0 -94
- package/dist/components/shell/ViewerLoginForm.js +0 -40
- package/dist/data/google-fonts.json +0 -7718
- package/dist/hooks/index.js +0 -6
- package/dist/hooks/useActiveHeadings.js +0 -99
- package/dist/hooks/useEditorPersistence.js +0 -73
- package/dist/hooks/useEditorPublish.js +0 -145
- package/dist/hooks/useFocusTrap.js +0 -51
- package/dist/hooks/useMediaPipeline.js +0 -253
- package/dist/hooks/useResolvedMedia.js +0 -39
- package/dist/lib/cn.js +0 -5
- package/dist/lib/contrast.js +0 -11
- package/dist/lib/dexie.js +0 -236
- package/dist/lib/events.js +0 -15
- package/dist/lib/google-fonts.js +0 -11
- package/dist/lib/grid.js +0 -7
- package/dist/lib/icons.js +0 -27
- package/dist/lib/loader.js +0 -57
- package/dist/lib/nav.js +0 -58
- package/dist/lib/registry.js +0 -64
- package/dist/lib/safeRedirect.js +0 -11
- package/dist/lib/sanitize.js +0 -6
- package/dist/lib/timestamp.js +0 -28
- package/dist/media/github.js +0 -60
- package/dist/media/queue.js +0 -116
- package/dist/media/resolve.js +0 -50
- package/dist/media/types.js +0 -1
- package/dist/media/utils.js +0 -41
- package/dist/media/videoPoster.js +0 -44
- package/dist/media/worker.js +0 -73
- package/dist/schemas/audience.js +0 -19
- package/dist/schemas/auth.js +0 -22
- package/dist/schemas/media-grid-options.js +0 -7
- package/dist/schemas/media.js +0 -28
- package/dist/schemas/sections.js +0 -12
- package/dist/schemas/shared.js +0 -71
- package/dist/schemas/site-config.js +0 -26
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
// src/media/utils.ts
|
|
2
|
+
async function hashFileBuffer(buffer) {
|
|
3
|
+
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
4
|
+
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
5
|
+
const hashArray = new Uint8Array(hashBuffer);
|
|
6
|
+
return Array.from(hashArray.slice(0, 8)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
7
|
+
}
|
|
8
|
+
const bytes = new Uint8Array(buffer);
|
|
9
|
+
const seeds = [2166136261, 84696351];
|
|
10
|
+
let result = "";
|
|
11
|
+
for (const seed of seeds) {
|
|
12
|
+
let h = seed;
|
|
13
|
+
for (let i = 0; i < bytes.length; i++) {
|
|
14
|
+
h ^= bytes[i];
|
|
15
|
+
h = Math.imul(h, 16777619);
|
|
16
|
+
}
|
|
17
|
+
result += (h >>> 0).toString(16).padStart(8, "0");
|
|
18
|
+
}
|
|
19
|
+
return result;
|
|
20
|
+
}
|
|
21
|
+
function sanitizeMediaName(name) {
|
|
22
|
+
return name.replace(/\.[^.]+$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
23
|
+
}
|
|
24
|
+
var MIME_TO_EXT = {
|
|
25
|
+
"image/gif": "gif",
|
|
26
|
+
"image/apng": "apng",
|
|
27
|
+
"image/png": "png",
|
|
28
|
+
"image/jpeg": "jpg",
|
|
29
|
+
"image/webp": "webp",
|
|
30
|
+
"image/svg+xml": "svg",
|
|
31
|
+
"video/mp4": "mp4",
|
|
32
|
+
"video/webm": "webm"
|
|
33
|
+
};
|
|
34
|
+
var EXT_TO_MIME = {
|
|
35
|
+
...Object.fromEntries(
|
|
36
|
+
Object.entries(MIME_TO_EXT).map(([mime, ext]) => [`.${ext}`, mime])
|
|
37
|
+
),
|
|
38
|
+
".jpeg": "image/jpeg"
|
|
39
|
+
};
|
|
40
|
+
function mimeToExt(mime) {
|
|
41
|
+
return MIME_TO_EXT[mime] ?? "bin";
|
|
42
|
+
}
|
|
43
|
+
function displayFilenameExt(mime) {
|
|
44
|
+
const ext = MIME_TO_EXT[mime];
|
|
45
|
+
return ext ? `.${ext}` : "";
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// src/media/github.ts
|
|
49
|
+
function createGitHubMediaAdapter(manifest) {
|
|
50
|
+
return {
|
|
51
|
+
async hash(file) {
|
|
52
|
+
return hashFileBuffer(file.buffer);
|
|
53
|
+
},
|
|
54
|
+
async exists(hash) {
|
|
55
|
+
return hash in manifest.images;
|
|
56
|
+
},
|
|
57
|
+
async process(file, hash, _sizes) {
|
|
58
|
+
const name = sanitizeMediaName(file.originalName);
|
|
59
|
+
const folder = `${name}-${hash}`;
|
|
60
|
+
return {
|
|
61
|
+
id: hash,
|
|
62
|
+
hash,
|
|
63
|
+
kind: "image",
|
|
64
|
+
originalName: name,
|
|
65
|
+
width: 0,
|
|
66
|
+
height: 0,
|
|
67
|
+
mimeType: "image/webp",
|
|
68
|
+
size: 0,
|
|
69
|
+
folder,
|
|
70
|
+
variants: [],
|
|
71
|
+
alt: ""
|
|
72
|
+
};
|
|
73
|
+
},
|
|
74
|
+
async delete(id) {
|
|
75
|
+
delete manifest.images[id];
|
|
76
|
+
},
|
|
77
|
+
resolve(id, sizes) {
|
|
78
|
+
const item = manifest.images[id];
|
|
79
|
+
if (!item) return null;
|
|
80
|
+
if (item.kind === "video") {
|
|
81
|
+
return {
|
|
82
|
+
tag: "video",
|
|
83
|
+
src: `/api/media/${id}/original.${mimeToExt(item.mimeType)}`,
|
|
84
|
+
poster: `/api/media/${id}/poster.webp`,
|
|
85
|
+
width: item.width,
|
|
86
|
+
height: item.height,
|
|
87
|
+
autoplay: true,
|
|
88
|
+
loop: true,
|
|
89
|
+
muted: true
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
if (item.kind === "animated") {
|
|
93
|
+
return {
|
|
94
|
+
tag: "img",
|
|
95
|
+
src: `/api/media/${id}/original.${mimeToExt(item.mimeType)}`,
|
|
96
|
+
width: item.width,
|
|
97
|
+
height: item.height
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
const availableVariants = item.variants.filter(
|
|
101
|
+
(v) => sizes.length === 0 || sizes.includes(v.width)
|
|
102
|
+
);
|
|
103
|
+
const sorted = [...availableVariants].sort((a, b) => a.width - b.width);
|
|
104
|
+
const midIndex = Math.floor(sorted.length / 2);
|
|
105
|
+
const defaultVariant = sorted[midIndex] ?? sorted[0];
|
|
106
|
+
if (!defaultVariant) return null;
|
|
107
|
+
const srcSet = sorted.map((v) => `/api/media/${id}/${v.width}.webp ${v.width}w`).join(", ");
|
|
108
|
+
return {
|
|
109
|
+
tag: "img",
|
|
110
|
+
src: `/api/media/${id}/${defaultVariant.width}.webp`,
|
|
111
|
+
srcSet,
|
|
112
|
+
width: item.width,
|
|
113
|
+
height: item.height
|
|
114
|
+
};
|
|
115
|
+
},
|
|
116
|
+
async list() {
|
|
117
|
+
return Object.values(manifest.images);
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// src/media/queue.ts
|
|
123
|
+
var ProcessingQueue = class {
|
|
124
|
+
items = /* @__PURE__ */ new Map();
|
|
125
|
+
pending = [];
|
|
126
|
+
activeWorkers = /* @__PURE__ */ new Map();
|
|
127
|
+
options;
|
|
128
|
+
nextId = 0;
|
|
129
|
+
constructor(options) {
|
|
130
|
+
this.options = options;
|
|
131
|
+
}
|
|
132
|
+
add(input) {
|
|
133
|
+
const id = `media-${this.nextId++}`;
|
|
134
|
+
const item = {
|
|
135
|
+
id,
|
|
136
|
+
originalName: input.originalName,
|
|
137
|
+
mimeType: input.mimeType,
|
|
138
|
+
hash: input.hash,
|
|
139
|
+
kind: input.kind,
|
|
140
|
+
percent: 0,
|
|
141
|
+
state: "queued"
|
|
142
|
+
};
|
|
143
|
+
this.items.set(id, item);
|
|
144
|
+
this.pending.push({ input, id });
|
|
145
|
+
this.options.onEvent({ type: "queued", item: { ...item } });
|
|
146
|
+
this.processNext();
|
|
147
|
+
return id;
|
|
148
|
+
}
|
|
149
|
+
getStatus() {
|
|
150
|
+
let active = 0;
|
|
151
|
+
let queued = 0;
|
|
152
|
+
for (const item of this.items.values()) {
|
|
153
|
+
if (item.state === "active") active++;
|
|
154
|
+
if (item.state === "queued") queued++;
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
active,
|
|
158
|
+
queued,
|
|
159
|
+
total: this.items.size,
|
|
160
|
+
items: Array.from(this.items.values())
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
processNext() {
|
|
164
|
+
while (this.activeWorkers.size < this.options.maxConcurrent && this.pending.length > 0) {
|
|
165
|
+
const next = this.pending.shift();
|
|
166
|
+
this.startProcessing(next.id, next.input);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
startProcessing(id, input) {
|
|
170
|
+
const item = this.items.get(id);
|
|
171
|
+
item.state = "active";
|
|
172
|
+
this.options.onEvent({ type: "started", item: { ...item } });
|
|
173
|
+
const worker = this.options.createWorker();
|
|
174
|
+
this.activeWorkers.set(id, worker);
|
|
175
|
+
worker.onmessage = (e) => {
|
|
176
|
+
const msg = e.data;
|
|
177
|
+
if (msg.id !== id) return;
|
|
178
|
+
if (msg.type === "progress") {
|
|
179
|
+
item.percent = msg.percent;
|
|
180
|
+
this.options.onEvent({ type: "progress", item: { ...item } });
|
|
181
|
+
} else if (msg.type === "complete") {
|
|
182
|
+
item.state = "complete";
|
|
183
|
+
item.percent = 100;
|
|
184
|
+
item.result = {
|
|
185
|
+
variants: msg.variants,
|
|
186
|
+
primaryBlob: msg.primaryBlob,
|
|
187
|
+
posterBlob: msg.posterBlob,
|
|
188
|
+
width: msg.width,
|
|
189
|
+
height: msg.height
|
|
190
|
+
};
|
|
191
|
+
this.options.onEvent({ type: "complete", item: { ...item } });
|
|
192
|
+
this.cleanupWorker(id, worker);
|
|
193
|
+
this.processNext();
|
|
194
|
+
} else if (msg.type === "error") {
|
|
195
|
+
item.state = "error";
|
|
196
|
+
item.error = msg.message;
|
|
197
|
+
this.options.onEvent({ type: "error", item: { ...item } });
|
|
198
|
+
this.cleanupWorker(id, worker);
|
|
199
|
+
this.processNext();
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
worker.onerror = (e) => {
|
|
203
|
+
item.state = "error";
|
|
204
|
+
item.error = e.message || "Worker error";
|
|
205
|
+
this.options.onEvent({ type: "error", item: { ...item } });
|
|
206
|
+
this.cleanupWorker(id, worker);
|
|
207
|
+
this.processNext();
|
|
208
|
+
};
|
|
209
|
+
worker.postMessage({
|
|
210
|
+
type: "process",
|
|
211
|
+
id,
|
|
212
|
+
buffer: input.buffer,
|
|
213
|
+
originalName: input.originalName,
|
|
214
|
+
mimeType: input.mimeType,
|
|
215
|
+
hash: input.hash,
|
|
216
|
+
kind: input.kind,
|
|
217
|
+
sizes: this.options.sizes,
|
|
218
|
+
quality: this.options.quality
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
cleanupWorker(id, worker) {
|
|
222
|
+
worker.terminate();
|
|
223
|
+
this.activeWorkers.delete(id);
|
|
224
|
+
}
|
|
225
|
+
destroy() {
|
|
226
|
+
for (const [id, worker] of this.activeWorkers) {
|
|
227
|
+
worker.terminate();
|
|
228
|
+
this.activeWorkers.delete(id);
|
|
229
|
+
}
|
|
230
|
+
this.pending = [];
|
|
231
|
+
this.items.clear();
|
|
232
|
+
}
|
|
233
|
+
};
|
|
234
|
+
|
|
235
|
+
// src/media/resolve.ts
|
|
236
|
+
function resolveMedia(item, manifest, sizes) {
|
|
237
|
+
if (!item.imageId) return null;
|
|
238
|
+
const adapter = createMediaAdapter(manifest);
|
|
239
|
+
return adapter.resolve(item.imageId, sizes);
|
|
240
|
+
}
|
|
241
|
+
function resolveManifestReferences(content, manifest, sizes) {
|
|
242
|
+
if (Array.isArray(content)) {
|
|
243
|
+
return content.map((item) => resolveManifestReferences(item, manifest, sizes));
|
|
244
|
+
}
|
|
245
|
+
if (content !== null && typeof content === "object") {
|
|
246
|
+
const obj = content;
|
|
247
|
+
if (typeof obj.imageId === "string") {
|
|
248
|
+
const manifestItem = manifest.images[obj.imageId];
|
|
249
|
+
const resolved = resolveMedia({ imageId: obj.imageId }, manifest, sizes);
|
|
250
|
+
const patch = {
|
|
251
|
+
alt: manifestItem?.alt ?? ""
|
|
252
|
+
};
|
|
253
|
+
if (resolved && resolved.tag === "img") {
|
|
254
|
+
patch.src = resolved.src;
|
|
255
|
+
if ("srcSet" in resolved && resolved.srcSet) {
|
|
256
|
+
patch.srcset = resolved.srcSet;
|
|
257
|
+
}
|
|
258
|
+
} else if (resolved && resolved.tag === "video") {
|
|
259
|
+
patch.src = resolved.src;
|
|
260
|
+
if (resolved.poster) {
|
|
261
|
+
patch.poster = resolved.poster;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
return { ...obj, ...patch };
|
|
265
|
+
}
|
|
266
|
+
const result = {};
|
|
267
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
268
|
+
result[key] = resolveManifestReferences(value, manifest, sizes);
|
|
269
|
+
}
|
|
270
|
+
return result;
|
|
271
|
+
}
|
|
272
|
+
return content;
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
// src/media/videoPoster.ts
|
|
276
|
+
function generateVideoPoster(blob, quality) {
|
|
277
|
+
return new Promise((resolve, reject) => {
|
|
278
|
+
const video = document.createElement("video");
|
|
279
|
+
const url = URL.createObjectURL(blob);
|
|
280
|
+
video.muted = true;
|
|
281
|
+
video.preload = "auto";
|
|
282
|
+
video.src = url;
|
|
283
|
+
const cleanup = () => {
|
|
284
|
+
URL.revokeObjectURL(url);
|
|
285
|
+
video.removeAttribute("src");
|
|
286
|
+
video.load();
|
|
287
|
+
};
|
|
288
|
+
video.addEventListener("loadeddata", () => {
|
|
289
|
+
video.addEventListener("seeked", () => {
|
|
290
|
+
try {
|
|
291
|
+
const w = video.videoWidth;
|
|
292
|
+
const h = video.videoHeight;
|
|
293
|
+
const canvas = document.createElement("canvas");
|
|
294
|
+
canvas.width = w;
|
|
295
|
+
canvas.height = h;
|
|
296
|
+
const ctx = canvas.getContext("2d");
|
|
297
|
+
ctx.drawImage(video, 0, 0);
|
|
298
|
+
canvas.toBlob(
|
|
299
|
+
(posterBlob) => {
|
|
300
|
+
cleanup();
|
|
301
|
+
if (!posterBlob) {
|
|
302
|
+
reject(new Error("Failed to create poster blob"));
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
resolve({ posterBlob, width: w, height: h });
|
|
306
|
+
},
|
|
307
|
+
"image/webp",
|
|
308
|
+
quality / 100
|
|
309
|
+
);
|
|
310
|
+
} catch (err) {
|
|
311
|
+
cleanup();
|
|
312
|
+
reject(err);
|
|
313
|
+
}
|
|
314
|
+
}, { once: true });
|
|
315
|
+
video.currentTime = isFinite(video.duration) ? Math.min(0.1, video.duration / 2) : 0;
|
|
316
|
+
}, { once: true });
|
|
317
|
+
video.addEventListener("error", () => {
|
|
318
|
+
cleanup();
|
|
319
|
+
reject(new Error("Failed to load video for poster generation"));
|
|
320
|
+
}, { once: true });
|
|
321
|
+
});
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// src/media/index.ts
|
|
325
|
+
function createMediaAdapter(manifest) {
|
|
326
|
+
return createGitHubMediaAdapter(manifest);
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export {
|
|
330
|
+
hashFileBuffer,
|
|
331
|
+
sanitizeMediaName,
|
|
332
|
+
MIME_TO_EXT,
|
|
333
|
+
EXT_TO_MIME,
|
|
334
|
+
mimeToExt,
|
|
335
|
+
displayFilenameExt,
|
|
336
|
+
ProcessingQueue,
|
|
337
|
+
resolveMedia,
|
|
338
|
+
resolveManifestReferences,
|
|
339
|
+
generateVideoPoster,
|
|
340
|
+
createMediaAdapter
|
|
341
|
+
};
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HexColorSchema
|
|
3
|
+
} from "./chunk-UKEVUCIZ.js";
|
|
4
|
+
|
|
5
|
+
// src/schemas/audience.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var AudienceNameSchema = z.string().min(1).max(32).regex(
|
|
8
|
+
/^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$/,
|
|
9
|
+
"lowercase alphanumeric, dashes and underscores allowed"
|
|
10
|
+
);
|
|
11
|
+
var AudienceColorSchema = HexColorSchema.nullable();
|
|
12
|
+
function slugifyAudienceName(input) {
|
|
13
|
+
return input.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/schemas/media-grid-options.ts
|
|
17
|
+
import { z as z2 } from "zod";
|
|
18
|
+
var MediaGridOptionsSchema = z2.object({
|
|
19
|
+
square: z2.boolean().optional(),
|
|
20
|
+
border: z2.boolean().optional(),
|
|
21
|
+
crop: z2.boolean().optional(),
|
|
22
|
+
showCaptions: z2.boolean().optional()
|
|
23
|
+
}).default({});
|
|
24
|
+
|
|
25
|
+
// src/schemas/auth.ts
|
|
26
|
+
import { z as z3 } from "zod";
|
|
27
|
+
var RoleSchema = z3.enum(["owner", "editor"]);
|
|
28
|
+
var SessionSchema = z3.object({
|
|
29
|
+
userId: z3.string().nullable(),
|
|
30
|
+
email: z3.string().nullable(),
|
|
31
|
+
role: RoleSchema,
|
|
32
|
+
siteId: z3.string()
|
|
33
|
+
});
|
|
34
|
+
var SiteUserSchema = z3.object({
|
|
35
|
+
id: z3.string(),
|
|
36
|
+
email: z3.string(),
|
|
37
|
+
role: RoleSchema,
|
|
38
|
+
createdAt: z3.string()
|
|
39
|
+
});
|
|
40
|
+
var AudienceSchema = z3.object({
|
|
41
|
+
name: z3.string(),
|
|
42
|
+
displayName: z3.string(),
|
|
43
|
+
color: z3.string().nullable(),
|
|
44
|
+
readonly: z3.boolean(),
|
|
45
|
+
hasPassword: z3.boolean(),
|
|
46
|
+
isDefault: z3.boolean()
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
export {
|
|
50
|
+
AudienceNameSchema,
|
|
51
|
+
AudienceColorSchema,
|
|
52
|
+
slugifyAudienceName,
|
|
53
|
+
MediaGridOptionsSchema,
|
|
54
|
+
RoleSchema,
|
|
55
|
+
SessionSchema,
|
|
56
|
+
SiteUserSchema,
|
|
57
|
+
AudienceSchema
|
|
58
|
+
};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import {
|
|
2
|
+
MediaConfigSchema
|
|
3
|
+
} from "./chunk-UMSFICAC.js";
|
|
4
|
+
|
|
5
|
+
// src/schemas/shared.ts
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
var TextHeadingLine = z.object({
|
|
8
|
+
type: z.literal("heading"),
|
|
9
|
+
text: z.string()
|
|
10
|
+
});
|
|
11
|
+
var TextParagraphLine = z.object({
|
|
12
|
+
type: z.enum(["paragraph", "paragraph_large"]),
|
|
13
|
+
text: z.string()
|
|
14
|
+
});
|
|
15
|
+
var TextLabelValueLine = z.object({
|
|
16
|
+
type: z.literal("label_value"),
|
|
17
|
+
label: z.string(),
|
|
18
|
+
text: z.string()
|
|
19
|
+
});
|
|
20
|
+
var TextListItemLine = z.object({
|
|
21
|
+
type: z.enum(["list_item_unordered", "list_item_ordered"]),
|
|
22
|
+
text: z.string()
|
|
23
|
+
});
|
|
24
|
+
var TextLineSchema = z.discriminatedUnion("type", [
|
|
25
|
+
TextHeadingLine,
|
|
26
|
+
TextParagraphLine,
|
|
27
|
+
TextLabelValueLine,
|
|
28
|
+
TextListItemLine
|
|
29
|
+
]);
|
|
30
|
+
var BaseMediaRef = z.object({
|
|
31
|
+
imageId: z.string().default(""),
|
|
32
|
+
caption: z.union([z.string(), z.array(z.string())]).optional(),
|
|
33
|
+
background: z.string().optional(),
|
|
34
|
+
invertFrom: z.string().optional(),
|
|
35
|
+
border: z.boolean().optional(),
|
|
36
|
+
objectFit: z.enum(["cover", "contain"]).optional()
|
|
37
|
+
});
|
|
38
|
+
var ImageRef = BaseMediaRef.extend({
|
|
39
|
+
type: z.literal("image")
|
|
40
|
+
});
|
|
41
|
+
var VideoRef = BaseMediaRef.extend({
|
|
42
|
+
type: z.literal("video"),
|
|
43
|
+
poster: z.string().optional(),
|
|
44
|
+
autoplay: z.boolean().optional(),
|
|
45
|
+
loop: z.boolean().optional(),
|
|
46
|
+
muted: z.boolean().optional()
|
|
47
|
+
});
|
|
48
|
+
var DoDontImageRef = BaseMediaRef.extend({
|
|
49
|
+
type: z.literal("doDontImage"),
|
|
50
|
+
doDont: z.enum(["do", "dont"])
|
|
51
|
+
});
|
|
52
|
+
var LinkedImageRef = BaseMediaRef.extend({
|
|
53
|
+
type: z.literal("linkedImage"),
|
|
54
|
+
href: z.string(),
|
|
55
|
+
target: z.string().optional(),
|
|
56
|
+
linkText: z.string().optional()
|
|
57
|
+
});
|
|
58
|
+
var MediaReferenceSchema = z.discriminatedUnion("type", [
|
|
59
|
+
ImageRef,
|
|
60
|
+
VideoRef,
|
|
61
|
+
DoDontImageRef,
|
|
62
|
+
LinkedImageRef
|
|
63
|
+
]);
|
|
64
|
+
var HexColorSchema = z.string().regex(/^#[0-9a-fA-F]{6}$/, "must be a 6-digit hex color");
|
|
65
|
+
var ColorSpaceSchema = z.object({
|
|
66
|
+
hex: HexColorSchema.optional(),
|
|
67
|
+
rgb: z.string().optional(),
|
|
68
|
+
cmyk: z.string().optional(),
|
|
69
|
+
pantone: z.string().optional()
|
|
70
|
+
}).refine(
|
|
71
|
+
(data) => data.hex !== void 0 || data.rgb !== void 0 || data.cmyk !== void 0 || data.pantone !== void 0,
|
|
72
|
+
{ message: "At least one color space must be defined" }
|
|
73
|
+
);
|
|
74
|
+
var ColorItemSchema = z.object({
|
|
75
|
+
name: z.string().optional(),
|
|
76
|
+
spaces: z.array(ColorSpaceSchema).min(1)
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
// src/lib/registry.ts
|
|
80
|
+
function defineSection(def) {
|
|
81
|
+
return def;
|
|
82
|
+
}
|
|
83
|
+
function createRegistry() {
|
|
84
|
+
const sections = /* @__PURE__ */ new Map();
|
|
85
|
+
const schemas = /* @__PURE__ */ new Map();
|
|
86
|
+
return {
|
|
87
|
+
registerSection(def) {
|
|
88
|
+
if (sections.has(def.type)) {
|
|
89
|
+
throw new Error(`Section type "${def.type}" is already registered`);
|
|
90
|
+
}
|
|
91
|
+
sections.set(def.type, def);
|
|
92
|
+
},
|
|
93
|
+
registerSchema(type, schema) {
|
|
94
|
+
schemas.set(type, schema);
|
|
95
|
+
},
|
|
96
|
+
getSection(type) {
|
|
97
|
+
return sections.get(type);
|
|
98
|
+
},
|
|
99
|
+
getSchema(type) {
|
|
100
|
+
return schemas.get(type) ?? sections.get(type)?.schema;
|
|
101
|
+
},
|
|
102
|
+
getAllSections() {
|
|
103
|
+
return Array.from(sections.values());
|
|
104
|
+
},
|
|
105
|
+
getAllSchemas() {
|
|
106
|
+
const merged = new Map(schemas);
|
|
107
|
+
for (const [type, def] of sections) {
|
|
108
|
+
if (!merged.has(type)) merged.set(type, def.schema);
|
|
109
|
+
}
|
|
110
|
+
return Array.from(merged.values());
|
|
111
|
+
},
|
|
112
|
+
clearRegistry() {
|
|
113
|
+
sections.clear();
|
|
114
|
+
schemas.clear();
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
var defaultRegistry = createRegistry();
|
|
119
|
+
function registerSection(def) {
|
|
120
|
+
defaultRegistry.registerSection(def);
|
|
121
|
+
}
|
|
122
|
+
function registerSchema(type, schema) {
|
|
123
|
+
defaultRegistry.registerSchema(type, schema);
|
|
124
|
+
}
|
|
125
|
+
function getSection(type) {
|
|
126
|
+
return defaultRegistry.getSection(type);
|
|
127
|
+
}
|
|
128
|
+
function getSchema(type) {
|
|
129
|
+
return defaultRegistry.getSchema(type);
|
|
130
|
+
}
|
|
131
|
+
function getAllSections() {
|
|
132
|
+
return defaultRegistry.getAllSections();
|
|
133
|
+
}
|
|
134
|
+
function getAllSchemas() {
|
|
135
|
+
return defaultRegistry.getAllSchemas();
|
|
136
|
+
}
|
|
137
|
+
function clearRegistry() {
|
|
138
|
+
defaultRegistry.clearRegistry();
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// src/schemas/sections.ts
|
|
142
|
+
import { z as z2 } from "zod";
|
|
143
|
+
function getSectionContentSchema() {
|
|
144
|
+
const schemas = getAllSchemas();
|
|
145
|
+
if (schemas.length < 2) {
|
|
146
|
+
throw new Error("At least 2 section schemas must be registered before validation");
|
|
147
|
+
}
|
|
148
|
+
return z2.union(schemas);
|
|
149
|
+
}
|
|
150
|
+
function getSectionSchema() {
|
|
151
|
+
return z2.object({ id: z2.string() }).and(getSectionContentSchema());
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// src/schemas/site-config.ts
|
|
155
|
+
import { z as z3 } from "zod";
|
|
156
|
+
var SectionMetaSchema = z3.object({
|
|
157
|
+
type: z3.string(),
|
|
158
|
+
status: z3.enum(["draft", "published", "archived"]),
|
|
159
|
+
access: z3.array(z3.string())
|
|
160
|
+
});
|
|
161
|
+
var IndexSchema = z3.object({
|
|
162
|
+
siteId: z3.string(),
|
|
163
|
+
order: z3.array(z3.string()),
|
|
164
|
+
sections: z3.record(z3.string(), SectionMetaSchema)
|
|
165
|
+
}).refine(
|
|
166
|
+
(data) => data.order.every((id) => id in data.sections),
|
|
167
|
+
{ message: "All order entries must have a corresponding section in sections" }
|
|
168
|
+
);
|
|
169
|
+
var SiteConfigSchema = z3.object({
|
|
170
|
+
siteName: z3.string().default("Brand Portal"),
|
|
171
|
+
primaryColor: HexColorSchema.default("#009ca6"),
|
|
172
|
+
primaryContrast: HexColorSchema.default("#f0f0f0"),
|
|
173
|
+
darkMode: z3.enum(["light", "dark", "optional"]).default("light"),
|
|
174
|
+
headingFont: z3.string().default("system-ui"),
|
|
175
|
+
bodyFont: z3.string().default("system-ui"),
|
|
176
|
+
googleFontsUrl: z3.string().refine((url) => url.startsWith("https://fonts.googleapis.com/"), "Must be a Google Fonts URL").nullable().default(null),
|
|
177
|
+
media: MediaConfigSchema.default(MediaConfigSchema.parse({}))
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
export {
|
|
181
|
+
TextLineSchema,
|
|
182
|
+
MediaReferenceSchema,
|
|
183
|
+
HexColorSchema,
|
|
184
|
+
ColorSpaceSchema,
|
|
185
|
+
ColorItemSchema,
|
|
186
|
+
defineSection,
|
|
187
|
+
createRegistry,
|
|
188
|
+
registerSection,
|
|
189
|
+
registerSchema,
|
|
190
|
+
getSection,
|
|
191
|
+
getSchema,
|
|
192
|
+
getAllSections,
|
|
193
|
+
getAllSchemas,
|
|
194
|
+
clearRegistry,
|
|
195
|
+
getSectionContentSchema,
|
|
196
|
+
getSectionSchema,
|
|
197
|
+
SectionMetaSchema,
|
|
198
|
+
IndexSchema,
|
|
199
|
+
SiteConfigSchema
|
|
200
|
+
};
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// src/schemas/media.ts
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
var VariantSchema = z.object({
|
|
4
|
+
width: z.number().int().positive(),
|
|
5
|
+
height: z.number().int().positive(),
|
|
6
|
+
size: z.number().int().nonnegative()
|
|
7
|
+
});
|
|
8
|
+
var MediaItemSchema = z.object({
|
|
9
|
+
id: z.string(),
|
|
10
|
+
hash: z.string(),
|
|
11
|
+
kind: z.enum(["image", "animated", "video"]),
|
|
12
|
+
originalName: z.string(),
|
|
13
|
+
width: z.number().int().positive(),
|
|
14
|
+
height: z.number().int().positive(),
|
|
15
|
+
mimeType: z.string(),
|
|
16
|
+
size: z.number().int().nonnegative(),
|
|
17
|
+
folder: z.string(),
|
|
18
|
+
variants: z.array(VariantSchema),
|
|
19
|
+
alt: z.string().default("")
|
|
20
|
+
});
|
|
21
|
+
var ImageManifestSchema = z.object({
|
|
22
|
+
images: z.record(z.string(), MediaItemSchema)
|
|
23
|
+
});
|
|
24
|
+
var MediaConfigSchema = z.object({
|
|
25
|
+
adapter: z.enum(["github"]).default("github"),
|
|
26
|
+
sizes: z.array(z.number()).default([640, 1080, 1920]),
|
|
27
|
+
maxFileSize: z.number().default(5242880),
|
|
28
|
+
quality: z.number().min(1).max(100).default(85)
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
export {
|
|
32
|
+
VariantSchema,
|
|
33
|
+
MediaItemSchema,
|
|
34
|
+
ImageManifestSchema,
|
|
35
|
+
MediaConfigSchema
|
|
36
|
+
};
|