@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
package/dist/media/queue.js
DELETED
|
@@ -1,116 +0,0 @@
|
|
|
1
|
-
export class ProcessingQueue {
|
|
2
|
-
items = new Map();
|
|
3
|
-
pending = [];
|
|
4
|
-
activeWorkers = new Map();
|
|
5
|
-
options;
|
|
6
|
-
nextId = 0;
|
|
7
|
-
constructor(options) {
|
|
8
|
-
this.options = options;
|
|
9
|
-
}
|
|
10
|
-
add(input) {
|
|
11
|
-
const id = `media-${this.nextId++}`;
|
|
12
|
-
const item = {
|
|
13
|
-
id,
|
|
14
|
-
originalName: input.originalName,
|
|
15
|
-
mimeType: input.mimeType,
|
|
16
|
-
hash: input.hash,
|
|
17
|
-
kind: input.kind,
|
|
18
|
-
percent: 0,
|
|
19
|
-
state: "queued",
|
|
20
|
-
};
|
|
21
|
-
this.items.set(id, item);
|
|
22
|
-
this.pending.push({ input, id });
|
|
23
|
-
this.options.onEvent({ type: "queued", item: { ...item } });
|
|
24
|
-
this.processNext();
|
|
25
|
-
return id;
|
|
26
|
-
}
|
|
27
|
-
getStatus() {
|
|
28
|
-
let active = 0;
|
|
29
|
-
let queued = 0;
|
|
30
|
-
for (const item of this.items.values()) {
|
|
31
|
-
if (item.state === "active")
|
|
32
|
-
active++;
|
|
33
|
-
if (item.state === "queued")
|
|
34
|
-
queued++;
|
|
35
|
-
}
|
|
36
|
-
return {
|
|
37
|
-
active,
|
|
38
|
-
queued,
|
|
39
|
-
total: this.items.size,
|
|
40
|
-
items: Array.from(this.items.values()),
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
processNext() {
|
|
44
|
-
while (this.activeWorkers.size < this.options.maxConcurrent && this.pending.length > 0) {
|
|
45
|
-
const next = this.pending.shift();
|
|
46
|
-
this.startProcessing(next.id, next.input);
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
startProcessing(id, input) {
|
|
50
|
-
const item = this.items.get(id);
|
|
51
|
-
item.state = "active";
|
|
52
|
-
this.options.onEvent({ type: "started", item: { ...item } });
|
|
53
|
-
const worker = this.options.createWorker();
|
|
54
|
-
this.activeWorkers.set(id, worker);
|
|
55
|
-
worker.onmessage = (e) => {
|
|
56
|
-
const msg = e.data;
|
|
57
|
-
if (msg.id !== id)
|
|
58
|
-
return;
|
|
59
|
-
if (msg.type === "progress") {
|
|
60
|
-
item.percent = msg.percent;
|
|
61
|
-
this.options.onEvent({ type: "progress", item: { ...item } });
|
|
62
|
-
}
|
|
63
|
-
else if (msg.type === "complete") {
|
|
64
|
-
item.state = "complete";
|
|
65
|
-
item.percent = 100;
|
|
66
|
-
item.result = {
|
|
67
|
-
variants: msg.variants,
|
|
68
|
-
primaryBlob: msg.primaryBlob,
|
|
69
|
-
posterBlob: msg.posterBlob,
|
|
70
|
-
width: msg.width,
|
|
71
|
-
height: msg.height,
|
|
72
|
-
};
|
|
73
|
-
this.options.onEvent({ type: "complete", item: { ...item } });
|
|
74
|
-
this.cleanupWorker(id, worker);
|
|
75
|
-
this.processNext();
|
|
76
|
-
}
|
|
77
|
-
else if (msg.type === "error") {
|
|
78
|
-
item.state = "error";
|
|
79
|
-
item.error = msg.message;
|
|
80
|
-
this.options.onEvent({ type: "error", item: { ...item } });
|
|
81
|
-
this.cleanupWorker(id, worker);
|
|
82
|
-
this.processNext();
|
|
83
|
-
}
|
|
84
|
-
};
|
|
85
|
-
worker.onerror = (e) => {
|
|
86
|
-
item.state = "error";
|
|
87
|
-
item.error = e.message || "Worker error";
|
|
88
|
-
this.options.onEvent({ type: "error", item: { ...item } });
|
|
89
|
-
this.cleanupWorker(id, worker);
|
|
90
|
-
this.processNext();
|
|
91
|
-
};
|
|
92
|
-
worker.postMessage({
|
|
93
|
-
type: "process",
|
|
94
|
-
id,
|
|
95
|
-
buffer: input.buffer,
|
|
96
|
-
originalName: input.originalName,
|
|
97
|
-
mimeType: input.mimeType,
|
|
98
|
-
hash: input.hash,
|
|
99
|
-
kind: input.kind,
|
|
100
|
-
sizes: this.options.sizes,
|
|
101
|
-
quality: this.options.quality,
|
|
102
|
-
});
|
|
103
|
-
}
|
|
104
|
-
cleanupWorker(id, worker) {
|
|
105
|
-
worker.terminate();
|
|
106
|
-
this.activeWorkers.delete(id);
|
|
107
|
-
}
|
|
108
|
-
destroy() {
|
|
109
|
-
for (const [id, worker] of this.activeWorkers) {
|
|
110
|
-
worker.terminate();
|
|
111
|
-
this.activeWorkers.delete(id);
|
|
112
|
-
}
|
|
113
|
-
this.pending = [];
|
|
114
|
-
this.items.clear();
|
|
115
|
-
}
|
|
116
|
-
}
|
package/dist/media/resolve.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { createMediaAdapter } from "./index";
|
|
2
|
-
export function resolveMedia(item, manifest, sizes) {
|
|
3
|
-
if (!item.imageId)
|
|
4
|
-
return null;
|
|
5
|
-
const adapter = createMediaAdapter(manifest);
|
|
6
|
-
return adapter.resolve(item.imageId, sizes);
|
|
7
|
-
}
|
|
8
|
-
/**
|
|
9
|
-
* Deep-walk section content and resolve any { imageId } references to
|
|
10
|
-
* { src, srcset } values using the media manifest.
|
|
11
|
-
*
|
|
12
|
-
* This lets view-mode section components use `item.src` and `item.srcset`
|
|
13
|
-
* without needing to know about the manifest themselves.
|
|
14
|
-
*/
|
|
15
|
-
export function resolveManifestReferences(content, manifest, sizes) {
|
|
16
|
-
if (Array.isArray(content)) {
|
|
17
|
-
return content.map((item) => resolveManifestReferences(item, manifest, sizes));
|
|
18
|
-
}
|
|
19
|
-
if (content !== null && typeof content === "object") {
|
|
20
|
-
const obj = content;
|
|
21
|
-
// If this object has an imageId, resolve it and merge resolved fields
|
|
22
|
-
if (typeof obj.imageId === "string") {
|
|
23
|
-
const manifestItem = manifest.images[obj.imageId];
|
|
24
|
-
const resolved = resolveMedia({ imageId: obj.imageId }, manifest, sizes);
|
|
25
|
-
const patch = {
|
|
26
|
-
alt: manifestItem?.alt ?? "",
|
|
27
|
-
};
|
|
28
|
-
if (resolved && resolved.tag === "img") {
|
|
29
|
-
patch.src = resolved.src;
|
|
30
|
-
if ("srcSet" in resolved && resolved.srcSet) {
|
|
31
|
-
patch.srcset = resolved.srcSet;
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
else if (resolved && resolved.tag === "video") {
|
|
35
|
-
patch.src = resolved.src;
|
|
36
|
-
if (resolved.poster) {
|
|
37
|
-
patch.poster = resolved.poster;
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
return { ...obj, ...patch };
|
|
41
|
-
}
|
|
42
|
-
// Recurse into all values
|
|
43
|
-
const result = {};
|
|
44
|
-
for (const [key, value] of Object.entries(obj)) {
|
|
45
|
-
result[key] = resolveManifestReferences(value, manifest, sizes);
|
|
46
|
-
}
|
|
47
|
-
return result;
|
|
48
|
-
}
|
|
49
|
-
return content;
|
|
50
|
-
}
|
package/dist/media/types.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export { VariantSchema, MediaItemSchema, ImageManifestSchema, MediaConfigSchema, } from "../schemas/media";
|
package/dist/media/utils.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
export async function hashFileBuffer(buffer) {
|
|
2
|
-
if (typeof crypto !== "undefined" && crypto.subtle) {
|
|
3
|
-
const hashBuffer = await crypto.subtle.digest("SHA-256", buffer);
|
|
4
|
-
const hashArray = new Uint8Array(hashBuffer);
|
|
5
|
-
return Array.from(hashArray.slice(0, 8))
|
|
6
|
-
.map((b) => b.toString(16).padStart(2, "0"))
|
|
7
|
-
.join("");
|
|
8
|
-
}
|
|
9
|
-
// FNV-1a fallback: two passes with different seeds, concatenated for 16 hex chars
|
|
10
|
-
const bytes = new Uint8Array(buffer);
|
|
11
|
-
const seeds = [0x811c9dc5, 0x050c5d1f];
|
|
12
|
-
let result = "";
|
|
13
|
-
for (const seed of seeds) {
|
|
14
|
-
let h = seed;
|
|
15
|
-
for (let i = 0; i < bytes.length; i++) {
|
|
16
|
-
h ^= bytes[i];
|
|
17
|
-
h = Math.imul(h, 0x01000193);
|
|
18
|
-
}
|
|
19
|
-
result += (h >>> 0).toString(16).padStart(8, "0");
|
|
20
|
-
}
|
|
21
|
-
return result;
|
|
22
|
-
}
|
|
23
|
-
export function sanitizeMediaName(name) {
|
|
24
|
-
return name.replace(/\.[^.]+$/, "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "");
|
|
25
|
-
}
|
|
26
|
-
export const MIME_TO_EXT = {
|
|
27
|
-
"image/gif": "gif", "image/apng": "apng", "image/png": "png",
|
|
28
|
-
"image/jpeg": "jpg", "image/webp": "webp", "image/svg+xml": "svg",
|
|
29
|
-
"video/mp4": "mp4", "video/webm": "webm",
|
|
30
|
-
};
|
|
31
|
-
export const EXT_TO_MIME = {
|
|
32
|
-
...Object.fromEntries(Object.entries(MIME_TO_EXT).map(([mime, ext]) => [`.${ext}`, mime])),
|
|
33
|
-
".jpeg": "image/jpeg",
|
|
34
|
-
};
|
|
35
|
-
export function mimeToExt(mime) {
|
|
36
|
-
return MIME_TO_EXT[mime] ?? "bin";
|
|
37
|
-
}
|
|
38
|
-
export function displayFilenameExt(mime) {
|
|
39
|
-
const ext = MIME_TO_EXT[mime];
|
|
40
|
-
return ext ? `.${ext}` : "";
|
|
41
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
export function generateVideoPoster(blob, quality) {
|
|
2
|
-
return new Promise((resolve, reject) => {
|
|
3
|
-
const video = document.createElement("video");
|
|
4
|
-
const url = URL.createObjectURL(blob);
|
|
5
|
-
video.muted = true;
|
|
6
|
-
video.preload = "auto";
|
|
7
|
-
video.src = url;
|
|
8
|
-
const cleanup = () => {
|
|
9
|
-
URL.revokeObjectURL(url);
|
|
10
|
-
video.removeAttribute("src");
|
|
11
|
-
video.load();
|
|
12
|
-
};
|
|
13
|
-
video.addEventListener("loadeddata", () => {
|
|
14
|
-
video.addEventListener("seeked", () => {
|
|
15
|
-
try {
|
|
16
|
-
const w = video.videoWidth;
|
|
17
|
-
const h = video.videoHeight;
|
|
18
|
-
const canvas = document.createElement("canvas");
|
|
19
|
-
canvas.width = w;
|
|
20
|
-
canvas.height = h;
|
|
21
|
-
const ctx = canvas.getContext("2d");
|
|
22
|
-
ctx.drawImage(video, 0, 0);
|
|
23
|
-
canvas.toBlob((posterBlob) => {
|
|
24
|
-
cleanup();
|
|
25
|
-
if (!posterBlob) {
|
|
26
|
-
reject(new Error("Failed to create poster blob"));
|
|
27
|
-
return;
|
|
28
|
-
}
|
|
29
|
-
resolve({ posterBlob, width: w, height: h });
|
|
30
|
-
}, "image/webp", quality / 100);
|
|
31
|
-
}
|
|
32
|
-
catch (err) {
|
|
33
|
-
cleanup();
|
|
34
|
-
reject(err);
|
|
35
|
-
}
|
|
36
|
-
}, { once: true });
|
|
37
|
-
video.currentTime = isFinite(video.duration) ? Math.min(0.1, video.duration / 2) : 0;
|
|
38
|
-
}, { once: true });
|
|
39
|
-
video.addEventListener("error", () => {
|
|
40
|
-
cleanup();
|
|
41
|
-
reject(new Error("Failed to load video for poster generation"));
|
|
42
|
-
}, { once: true });
|
|
43
|
-
});
|
|
44
|
-
}
|
package/dist/media/worker.js
DELETED
|
@@ -1,73 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
self.onmessage = async (e) => {
|
|
3
|
-
const msg = e.data;
|
|
4
|
-
if (msg.type !== "process")
|
|
5
|
-
return;
|
|
6
|
-
try {
|
|
7
|
-
const post = (data) => self.postMessage(data);
|
|
8
|
-
post({ type: "progress", id: msg.id, percent: 5 });
|
|
9
|
-
if (msg.kind === "animated" || msg.kind === "video") {
|
|
10
|
-
const primaryBlob = new Blob([msg.buffer], { type: msg.mimeType });
|
|
11
|
-
let posterBlob;
|
|
12
|
-
let width = 0;
|
|
13
|
-
let height = 0;
|
|
14
|
-
if (msg.kind === "animated") {
|
|
15
|
-
const bitmap = await createImageBitmap(primaryBlob);
|
|
16
|
-
width = bitmap.width;
|
|
17
|
-
height = bitmap.height;
|
|
18
|
-
const canvas = new OffscreenCanvas(bitmap.width, bitmap.height);
|
|
19
|
-
const ctx = canvas.getContext("2d");
|
|
20
|
-
ctx.drawImage(bitmap, 0, 0);
|
|
21
|
-
posterBlob = await canvas.convertToBlob({ type: "image/webp", quality: msg.quality / 100 });
|
|
22
|
-
bitmap.close();
|
|
23
|
-
}
|
|
24
|
-
if (msg.kind === "video") {
|
|
25
|
-
width = 0;
|
|
26
|
-
height = 0;
|
|
27
|
-
}
|
|
28
|
-
post({ type: "progress", id: msg.id, percent: 100 });
|
|
29
|
-
post({ type: "complete", id: msg.id, variants: [], primaryBlob, posterBlob, width, height });
|
|
30
|
-
return;
|
|
31
|
-
}
|
|
32
|
-
// Static image processing
|
|
33
|
-
const originalBlob = new Blob([msg.buffer], { type: msg.mimeType });
|
|
34
|
-
const bitmap = await createImageBitmap(originalBlob);
|
|
35
|
-
const origWidth = bitmap.width;
|
|
36
|
-
const origHeight = bitmap.height;
|
|
37
|
-
post({ type: "progress", id: msg.id, percent: 25 });
|
|
38
|
-
const applicableSizes = msg.sizes
|
|
39
|
-
.filter((s) => s <= origWidth)
|
|
40
|
-
.sort((a, b) => b - a);
|
|
41
|
-
if (applicableSizes.length === 0) {
|
|
42
|
-
applicableSizes.push(origWidth);
|
|
43
|
-
}
|
|
44
|
-
const variants = [];
|
|
45
|
-
const totalVariants = applicableSizes.length;
|
|
46
|
-
for (let i = 0; i < applicableSizes.length; i++) {
|
|
47
|
-
const targetWidth = applicableSizes[i];
|
|
48
|
-
const scale = targetWidth / origWidth;
|
|
49
|
-
const targetHeight = Math.round(origHeight * scale);
|
|
50
|
-
const canvas = new OffscreenCanvas(targetWidth, targetHeight);
|
|
51
|
-
const ctx = canvas.getContext("2d");
|
|
52
|
-
ctx.drawImage(bitmap, 0, 0, targetWidth, targetHeight);
|
|
53
|
-
const blob = await canvas.convertToBlob({ type: "image/webp", quality: msg.quality / 100 });
|
|
54
|
-
variants.push({ width: targetWidth, height: targetHeight, size: blob.size, blob });
|
|
55
|
-
const percent = 25 + Math.round(((i + 1) / totalVariants) * 75);
|
|
56
|
-
post({ type: "progress", id: msg.id, percent });
|
|
57
|
-
}
|
|
58
|
-
bitmap.close();
|
|
59
|
-
const primaryBlob = variants[0]?.blob ?? originalBlob;
|
|
60
|
-
post({
|
|
61
|
-
type: "complete",
|
|
62
|
-
id: msg.id,
|
|
63
|
-
variants,
|
|
64
|
-
primaryBlob,
|
|
65
|
-
width: origWidth,
|
|
66
|
-
height: origHeight,
|
|
67
|
-
});
|
|
68
|
-
}
|
|
69
|
-
catch (err) {
|
|
70
|
-
const message = err instanceof Error ? err.message : "Processing failed";
|
|
71
|
-
self.postMessage({ type: "error", id: msg.id, message });
|
|
72
|
-
}
|
|
73
|
-
};
|
package/dist/schemas/audience.js
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { HexColorSchema } from "./shared";
|
|
3
|
-
export const AudienceNameSchema = z
|
|
4
|
-
.string()
|
|
5
|
-
.min(1)
|
|
6
|
-
.max(32)
|
|
7
|
-
.regex(/^[a-z0-9]([a-z0-9_-]*[a-z0-9])?$/, "lowercase alphanumeric, dashes and underscores allowed");
|
|
8
|
-
export const AudienceColorSchema = HexColorSchema.nullable();
|
|
9
|
-
/**
|
|
10
|
-
* Convert a friendly display string into an audience slug.
|
|
11
|
-
* Lowercases, replaces non-alphanumeric runs with single dashes,
|
|
12
|
-
* strips leading/trailing dashes. Result must pass AudienceNameSchema.
|
|
13
|
-
*/
|
|
14
|
-
export function slugifyAudienceName(input) {
|
|
15
|
-
return input
|
|
16
|
-
.toLowerCase()
|
|
17
|
-
.replace(/[^a-z0-9]+/g, "-")
|
|
18
|
-
.replace(/^-+|-+$/g, "");
|
|
19
|
-
}
|
package/dist/schemas/auth.js
DELETED
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export const RoleSchema = z.enum(["owner", "editor"]);
|
|
3
|
-
export const SessionSchema = z.object({
|
|
4
|
-
userId: z.string().nullable(),
|
|
5
|
-
email: z.string().nullable(),
|
|
6
|
-
role: RoleSchema,
|
|
7
|
-
siteId: z.string(),
|
|
8
|
-
});
|
|
9
|
-
export const SiteUserSchema = z.object({
|
|
10
|
-
id: z.string(),
|
|
11
|
-
email: z.string(),
|
|
12
|
-
role: RoleSchema,
|
|
13
|
-
createdAt: z.string(),
|
|
14
|
-
});
|
|
15
|
-
export const AudienceSchema = z.object({
|
|
16
|
-
name: z.string(),
|
|
17
|
-
displayName: z.string(),
|
|
18
|
-
color: z.string().nullable(),
|
|
19
|
-
readonly: z.boolean(),
|
|
20
|
-
hasPassword: z.boolean(),
|
|
21
|
-
isDefault: z.boolean(),
|
|
22
|
-
});
|
package/dist/schemas/media.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
export const VariantSchema = z.object({
|
|
3
|
-
width: z.number().int().positive(),
|
|
4
|
-
height: z.number().int().positive(),
|
|
5
|
-
size: z.number().int().nonnegative(),
|
|
6
|
-
});
|
|
7
|
-
export const MediaItemSchema = z.object({
|
|
8
|
-
id: z.string(),
|
|
9
|
-
hash: z.string(),
|
|
10
|
-
kind: z.enum(["image", "animated", "video"]),
|
|
11
|
-
originalName: z.string(),
|
|
12
|
-
width: z.number().int().positive(),
|
|
13
|
-
height: z.number().int().positive(),
|
|
14
|
-
mimeType: z.string(),
|
|
15
|
-
size: z.number().int().nonnegative(),
|
|
16
|
-
folder: z.string(),
|
|
17
|
-
variants: z.array(VariantSchema),
|
|
18
|
-
alt: z.string().default(""),
|
|
19
|
-
});
|
|
20
|
-
export const ImageManifestSchema = z.object({
|
|
21
|
-
images: z.record(z.string(), MediaItemSchema),
|
|
22
|
-
});
|
|
23
|
-
export const MediaConfigSchema = z.object({
|
|
24
|
-
adapter: z.enum(["github"]).default("github"),
|
|
25
|
-
sizes: z.array(z.number()).default([640, 1080, 1920]),
|
|
26
|
-
maxFileSize: z.number().default(5242880),
|
|
27
|
-
quality: z.number().min(1).max(100).default(85),
|
|
28
|
-
});
|
package/dist/schemas/sections.js
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { getAllSchemas } from "../lib/registry";
|
|
3
|
-
export function getSectionContentSchema() {
|
|
4
|
-
const schemas = getAllSchemas();
|
|
5
|
-
if (schemas.length < 2) {
|
|
6
|
-
throw new Error("At least 2 section schemas must be registered before validation");
|
|
7
|
-
}
|
|
8
|
-
return z.union(schemas);
|
|
9
|
-
}
|
|
10
|
-
export function getSectionSchema() {
|
|
11
|
-
return z.object({ id: z.string() }).and(getSectionContentSchema());
|
|
12
|
-
}
|
package/dist/schemas/shared.js
DELETED
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
// --- Text ---
|
|
3
|
-
const TextHeadingLine = z.object({
|
|
4
|
-
type: z.literal("heading"),
|
|
5
|
-
text: z.string(),
|
|
6
|
-
});
|
|
7
|
-
const TextParagraphLine = z.object({
|
|
8
|
-
type: z.enum(["paragraph", "paragraph_large"]),
|
|
9
|
-
text: z.string(),
|
|
10
|
-
});
|
|
11
|
-
const TextLabelValueLine = z.object({
|
|
12
|
-
type: z.literal("label_value"),
|
|
13
|
-
label: z.string(),
|
|
14
|
-
text: z.string(),
|
|
15
|
-
});
|
|
16
|
-
const TextListItemLine = z.object({
|
|
17
|
-
type: z.enum(["list_item_unordered", "list_item_ordered"]),
|
|
18
|
-
text: z.string(),
|
|
19
|
-
});
|
|
20
|
-
export const TextLineSchema = z.discriminatedUnion("type", [
|
|
21
|
-
TextHeadingLine,
|
|
22
|
-
TextParagraphLine,
|
|
23
|
-
TextLabelValueLine,
|
|
24
|
-
TextListItemLine,
|
|
25
|
-
]);
|
|
26
|
-
// --- Media References ---
|
|
27
|
-
const BaseMediaRef = z.object({
|
|
28
|
-
imageId: z.string().default(""),
|
|
29
|
-
caption: z.union([z.string(), z.array(z.string())]).optional(),
|
|
30
|
-
background: z.string().optional(),
|
|
31
|
-
invertFrom: z.string().optional(),
|
|
32
|
-
border: z.boolean().optional(),
|
|
33
|
-
objectFit: z.enum(["cover", "contain"]).optional(),
|
|
34
|
-
});
|
|
35
|
-
const ImageRef = BaseMediaRef.extend({
|
|
36
|
-
type: z.literal("image"),
|
|
37
|
-
});
|
|
38
|
-
const VideoRef = BaseMediaRef.extend({
|
|
39
|
-
type: z.literal("video"),
|
|
40
|
-
poster: z.string().optional(),
|
|
41
|
-
autoplay: z.boolean().optional(),
|
|
42
|
-
loop: z.boolean().optional(),
|
|
43
|
-
muted: z.boolean().optional(),
|
|
44
|
-
});
|
|
45
|
-
const DoDontImageRef = BaseMediaRef.extend({
|
|
46
|
-
type: z.literal("doDontImage"),
|
|
47
|
-
doDont: z.enum(["do", "dont"]),
|
|
48
|
-
});
|
|
49
|
-
const LinkedImageRef = BaseMediaRef.extend({
|
|
50
|
-
type: z.literal("linkedImage"),
|
|
51
|
-
href: z.string(),
|
|
52
|
-
target: z.string().optional(),
|
|
53
|
-
linkText: z.string().optional(),
|
|
54
|
-
});
|
|
55
|
-
export const MediaReferenceSchema = z.discriminatedUnion("type", [
|
|
56
|
-
ImageRef, VideoRef, DoDontImageRef, LinkedImageRef,
|
|
57
|
-
]);
|
|
58
|
-
// --- Colors ---
|
|
59
|
-
export const HexColorSchema = z
|
|
60
|
-
.string()
|
|
61
|
-
.regex(/^#[0-9a-fA-F]{6}$/, "must be a 6-digit hex color");
|
|
62
|
-
export const ColorSpaceSchema = z.object({
|
|
63
|
-
hex: HexColorSchema.optional(),
|
|
64
|
-
rgb: z.string().optional(),
|
|
65
|
-
cmyk: z.string().optional(),
|
|
66
|
-
pantone: z.string().optional(),
|
|
67
|
-
}).refine((data) => data.hex !== undefined || data.rgb !== undefined || data.cmyk !== undefined || data.pantone !== undefined, { message: "At least one color space must be defined" });
|
|
68
|
-
export const ColorItemSchema = z.object({
|
|
69
|
-
name: z.string().optional(),
|
|
70
|
-
spaces: z.array(ColorSpaceSchema).min(1),
|
|
71
|
-
});
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
import { z } from "zod";
|
|
2
|
-
import { MediaConfigSchema } from "./media";
|
|
3
|
-
import { HexColorSchema } from "./shared";
|
|
4
|
-
export const SectionMetaSchema = z.object({
|
|
5
|
-
type: z.string(),
|
|
6
|
-
status: z.enum(["draft", "published", "archived"]),
|
|
7
|
-
access: z.array(z.string()),
|
|
8
|
-
});
|
|
9
|
-
export const IndexSchema = z.object({
|
|
10
|
-
siteId: z.string(),
|
|
11
|
-
order: z.array(z.string()),
|
|
12
|
-
sections: z.record(z.string(), SectionMetaSchema),
|
|
13
|
-
}).refine((data) => data.order.every((id) => id in data.sections), { message: "All order entries must have a corresponding section in sections" });
|
|
14
|
-
export const SiteConfigSchema = z.object({
|
|
15
|
-
siteName: z.string().default("Brand Portal"),
|
|
16
|
-
primaryColor: HexColorSchema.default("#009ca6"),
|
|
17
|
-
primaryContrast: HexColorSchema.default("#f0f0f0"),
|
|
18
|
-
darkMode: z.enum(["light", "dark", "optional"]).default("light"),
|
|
19
|
-
headingFont: z.string().default("system-ui"),
|
|
20
|
-
bodyFont: z.string().default("system-ui"),
|
|
21
|
-
googleFontsUrl: z.string()
|
|
22
|
-
.refine(url => url.startsWith("https://fonts.googleapis.com/"), "Must be a Google Fonts URL")
|
|
23
|
-
.nullable()
|
|
24
|
-
.default(null),
|
|
25
|
-
media: MediaConfigSchema.default(MediaConfigSchema.parse({})),
|
|
26
|
-
});
|