@drawnagency/primitives 0.1.111 → 0.1.113
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/types.d.ts +1 -0
- package/dist/auth/types.d.ts.map +1 -1
- package/dist/chunk-4I5OO5UB.js +785 -0
- package/dist/{chunk-7WQJ57XG.js → chunk-6BZ2KNTP.js} +68 -260
- package/dist/{chunk-UVIYI4J6.js → chunk-AHALSCQH.js} +19 -3
- package/dist/{chunk-7MI3HCOF.js → chunk-BDFTMGCL.js} +10 -6
- package/dist/chunk-CXZ5YJG4.js +85 -0
- package/dist/{chunk-RA5IOFPY.js → chunk-DNY72JZN.js} +16 -38
- package/dist/{chunk-3GAG6ZXB.js → chunk-DS4GCYV2.js} +8 -4
- package/dist/{chunk-XQMDWXD6.js → chunk-FRE2CCLV.js} +3 -2
- package/dist/chunk-FV7JQRCN.js +94 -0
- package/dist/chunk-IIDKW7AV.js +41 -0
- package/dist/chunk-IINIZBQB.js +204 -0
- package/dist/{chunk-ELQ4C677.js → chunk-JH762VUH.js} +9 -44
- package/dist/{chunk-OUYB2GCW.js → chunk-K7DYZXVU.js} +1 -57
- package/dist/{chunk-NXGIHSL5.js → chunk-KR2MHTNJ.js} +11 -91
- package/dist/chunk-MM7KZS5C.js +30 -0
- package/dist/{chunk-OTDA6KWL.js → chunk-NHN2LSIU.js} +1 -1
- package/dist/chunk-QQ3S3P5P.js +38 -0
- package/dist/chunk-VAYZJKVR.js +209 -0
- package/dist/{chunk-VCCNKTFD.js → chunk-VWWY5TL5.js} +3 -31
- package/dist/chunk-WUJ3XNFI.js +62 -0
- package/dist/{chunk-ALMEC3XN.js → chunk-Z7W3DQTR.js} +22 -18
- package/dist/collab/rebase.js +1 -1
- package/dist/components/chat/ChatComposer.d.ts +25 -0
- package/dist/components/chat/ChatComposer.d.ts.map +1 -0
- package/dist/components/chat/ChatPanel.d.ts +5 -4
- package/dist/components/chat/ChatPanel.d.ts.map +1 -1
- package/dist/components/chat/ChatWidget.d.ts.map +1 -1
- package/dist/components/chat/markdown.d.ts +14 -0
- package/dist/components/chat/markdown.d.ts.map +1 -0
- package/dist/components/editor/index.js +16 -11
- package/dist/components/primitives/EditablePlainText.d.ts.map +1 -1
- package/dist/components/primitives/index.js +15 -10
- package/dist/components/sections/brand-guide.js +11 -9
- package/dist/components/sections/register-schemas.js +19 -14
- package/dist/components/sections/register.js +19 -14
- package/dist/components/shared/Navigation.d.ts +1 -0
- package/dist/components/shared/Navigation.d.ts.map +1 -1
- package/dist/components/shell/AudienceChips.d.ts +10 -0
- package/dist/components/shell/AudienceChips.d.ts.map +1 -0
- package/dist/components/shell/EditorShell.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsChatbot.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsDecks.d.ts +13 -0
- package/dist/components/shell/SiteSettingsDecks.d.ts.map +1 -0
- package/dist/components/shell/SiteSettingsDisplay.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsModal.d.ts.map +1 -1
- package/dist/components/shell/SiteSettingsUsers.d.ts.map +1 -1
- package/dist/deck/DeckComponentView.d.ts +13 -0
- package/dist/deck/DeckComponentView.d.ts.map +1 -0
- package/dist/deck/DeckPlayer.d.ts +26 -0
- package/dist/deck/DeckPlayer.d.ts.map +1 -0
- package/dist/deck/DeckSlideView.d.ts +17 -0
- package/dist/deck/DeckSlideView.d.ts.map +1 -0
- package/dist/deck/DeckStage.d.ts +16 -0
- package/dist/deck/DeckStage.d.ts.map +1 -0
- package/dist/deck/components/DeckImage.d.ts +14 -0
- package/dist/deck/components/DeckImage.d.ts.map +1 -0
- package/dist/deck/components/DeckImageGrid.d.ts +27 -0
- package/dist/deck/components/DeckImageGrid.d.ts.map +1 -0
- package/dist/deck/components/DeckRichText.d.ts +22 -0
- package/dist/deck/components/DeckRichText.d.ts.map +1 -0
- package/dist/deck/components/DeckVideo.d.ts +15 -0
- package/dist/deck/components/DeckVideo.d.ts.map +1 -0
- package/dist/deck/editing.d.ts +50 -0
- package/dist/deck/editing.d.ts.map +1 -0
- package/dist/deck/flip.d.ts +11 -0
- package/dist/deck/flip.d.ts.map +1 -0
- package/dist/deck/index.d.ts +24 -0
- package/dist/deck/index.d.ts.map +1 -0
- package/dist/deck/index.js +53 -0
- package/dist/deck/layouts/CenteredTextLayout.d.ts +12 -0
- package/dist/deck/layouts/CenteredTextLayout.d.ts.map +1 -0
- package/dist/deck/layouts/ColumnSplitLayout.d.ts +14 -0
- package/dist/deck/layouts/ColumnSplitLayout.d.ts.map +1 -0
- package/dist/deck/layouts/FullBleedImageLayout.d.ts +14 -0
- package/dist/deck/layouts/FullBleedImageLayout.d.ts.map +1 -0
- package/dist/deck/media.d.ts +33 -0
- package/dist/deck/media.d.ts.map +1 -0
- package/dist/deck/tokens.d.ts +22 -0
- package/dist/deck/tokens.d.ts.map +1 -0
- package/dist/deck/useStageScale.d.ts +10 -0
- package/dist/deck/useStageScale.d.ts.map +1 -0
- package/dist/deck-builder/DeckBuilderApp.d.ts +30 -0
- package/dist/deck-builder/DeckBuilderApp.d.ts.map +1 -0
- package/dist/deck-builder/DeckBuilderTopBar.d.ts +24 -0
- package/dist/deck-builder/DeckBuilderTopBar.d.ts.map +1 -0
- package/dist/deck-builder/DeckChatPanel.d.ts +45 -0
- package/dist/deck-builder/DeckChatPanel.d.ts.map +1 -0
- package/dist/deck-builder/DeckEditor.d.ts +37 -0
- package/dist/deck-builder/DeckEditor.d.ts.map +1 -0
- package/dist/deck-builder/DeckLibrary.d.ts +22 -0
- package/dist/deck-builder/DeckLibrary.d.ts.map +1 -0
- package/dist/deck-builder/DeckSlideSurface.d.ts +31 -0
- package/dist/deck-builder/DeckSlideSurface.d.ts.map +1 -0
- package/dist/deck-builder/deck-api.d.ts +76 -0
- package/dist/deck-builder/deck-api.d.ts.map +1 -0
- package/dist/deck-builder/deck-chat-client.d.ts +44 -0
- package/dist/deck-builder/deck-chat-client.d.ts.map +1 -0
- package/dist/deck-builder/deck-chat-history.d.ts +10 -0
- package/dist/deck-builder/deck-chat-history.d.ts.map +1 -0
- package/dist/deck-builder/index.d.ts +13 -0
- package/dist/deck-builder/index.d.ts.map +1 -0
- package/dist/deck-builder/index.js +1505 -0
- package/dist/deck-builder/starter-deck.d.ts +23 -0
- package/dist/deck-builder/starter-deck.d.ts.map +1 -0
- package/dist/deck-builder/types.d.ts +29 -0
- package/dist/deck-builder/types.d.ts.map +1 -0
- package/dist/deck-builder/useSortableSlide.d.ts +29 -0
- package/dist/deck-builder/useSortableSlide.d.ts.map +1 -0
- package/dist/index.js +70 -63
- package/dist/lib/deck-access.d.ts +86 -0
- package/dist/lib/deck-access.d.ts.map +1 -0
- package/dist/lib/deck-access.js +58 -0
- package/dist/lib/deck-dexie.d.ts +88 -0
- package/dist/lib/deck-dexie.d.ts.map +1 -0
- package/dist/lib/deck-dexie.js +22 -0
- package/dist/lib/deck-edit.d.ts +67 -0
- package/dist/lib/deck-edit.d.ts.map +1 -0
- package/dist/lib/deck-media-assets.d.ts +27 -0
- package/dist/lib/deck-media-assets.d.ts.map +1 -0
- package/dist/lib/deck-media-assets.js +25 -0
- package/dist/lib/deck-media-refs.d.ts +35 -0
- package/dist/lib/deck-media-refs.d.ts.map +1 -0
- package/dist/lib/deck-media-refs.js +36 -0
- package/dist/lib/deck-tool.d.ts +25 -0
- package/dist/lib/deck-tool.d.ts.map +1 -0
- package/dist/lib/deck-tool.js +58 -0
- package/dist/lib/index-ops.js +2 -2
- package/dist/lib/index.js +17 -12
- package/dist/lib/nav.d.ts.map +1 -1
- package/dist/media/index.js +3 -3
- package/dist/media/resolve.d.ts +2 -0
- package/dist/media/resolve.d.ts.map +1 -1
- package/dist/schemas/deck-meta.d.ts +85 -0
- package/dist/schemas/deck-meta.d.ts.map +1 -0
- package/dist/schemas/deck-meta.js +64 -0
- package/dist/schemas/deck.d.ts +954 -0
- package/dist/schemas/deck.d.ts.map +1 -0
- package/dist/schemas/deck.js +65 -0
- package/dist/schemas/index.js +39 -37
- package/dist/schemas/site-config.d.ts +14 -1
- package/dist/schemas/site-config.d.ts.map +1 -1
- package/dist/types/database.d.ts +8 -0
- package/dist/types/database.d.ts.map +1 -1
- package/package.json +37 -1
- package/src/auth/types.ts +1 -0
- package/src/components/chat/ChatComposer.tsx +100 -0
- package/src/components/chat/ChatPanel.tsx +20 -69
- package/src/components/chat/ChatWidget.tsx +5 -4
- package/src/components/chat/markdown.ts +32 -0
- package/src/components/primitives/EditablePlainText.tsx +11 -1
- package/src/components/shared/Navigation.tsx +26 -18
- package/src/components/shell/AudienceChips.tsx +30 -0
- package/src/components/shell/EditorShell.tsx +12 -0
- package/src/components/shell/SiteSettingsChatbot.tsx +1 -18
- package/src/components/shell/SiteSettingsDecks.tsx +41 -0
- package/src/components/shell/SiteSettingsDisplay.tsx +10 -1
- package/src/components/shell/SiteSettingsModal.tsx +11 -0
- package/src/components/shell/SiteSettingsUsers.tsx +49 -2
- package/src/deck/DeckComponentView.tsx +28 -0
- package/src/deck/DeckPlayer.tsx +166 -0
- package/src/deck/DeckSlideView.tsx +38 -0
- package/src/deck/DeckStage.tsx +39 -0
- package/src/deck/components/DeckImage.tsx +38 -0
- package/src/deck/components/DeckImageGrid.tsx +254 -0
- package/src/deck/components/DeckRichText.tsx +111 -0
- package/src/deck/components/DeckVideo.tsx +81 -0
- package/src/deck/editing.tsx +201 -0
- package/src/deck/flip.ts +70 -0
- package/src/deck/index.ts +30 -0
- package/src/deck/layouts/CenteredTextLayout.tsx +29 -0
- package/src/deck/layouts/ColumnSplitLayout.tsx +69 -0
- package/src/deck/layouts/FullBleedImageLayout.tsx +58 -0
- package/src/deck/media.tsx +46 -0
- package/src/deck/tokens.ts +57 -0
- package/src/deck/useStageScale.ts +44 -0
- package/src/deck-builder/DeckBuilderApp.tsx +572 -0
- package/src/deck-builder/DeckBuilderTopBar.tsx +62 -0
- package/src/deck-builder/DeckChatPanel.tsx +334 -0
- package/src/deck-builder/DeckEditor.tsx +258 -0
- package/src/deck-builder/DeckLibrary.tsx +195 -0
- package/src/deck-builder/DeckSlideSurface.tsx +55 -0
- package/src/deck-builder/deck-api.ts +177 -0
- package/src/deck-builder/deck-chat-client.ts +129 -0
- package/src/deck-builder/deck-chat-history.ts +62 -0
- package/src/deck-builder/index.ts +12 -0
- package/src/deck-builder/starter-deck.ts +86 -0
- package/src/deck-builder/types.ts +24 -0
- package/src/deck-builder/useSortableSlide.ts +102 -0
- package/src/lib/deck-access.ts +132 -0
- package/src/lib/deck-dexie.ts +190 -0
- package/src/lib/deck-edit.ts +196 -0
- package/src/lib/deck-media-assets.ts +57 -0
- package/src/lib/deck-media-refs.ts +67 -0
- package/src/lib/deck-tool.ts +95 -0
- package/src/lib/nav.ts +21 -1
- package/src/media/resolve.ts +3 -1
- package/src/schemas/deck-meta.ts +88 -0
- package/src/schemas/deck.ts +478 -0
- package/src/schemas/index.ts +4 -0
- package/src/schemas/site-config.ts +27 -1
- package/src/types/database.ts +4 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// src/lib/insert-menu.ts
|
|
2
|
+
var PRESET_PREFIX = "__preset:";
|
|
3
|
+
var INSERT_MENU_ORDER = [
|
|
4
|
+
"container",
|
|
5
|
+
"link_heading",
|
|
6
|
+
"sub_heading",
|
|
7
|
+
"sub_sub_heading",
|
|
8
|
+
"prose",
|
|
9
|
+
"media",
|
|
10
|
+
"video",
|
|
11
|
+
"button",
|
|
12
|
+
"colors",
|
|
13
|
+
"document",
|
|
14
|
+
"icon_list",
|
|
15
|
+
`${PRESET_PREFIX}do_dont_list`,
|
|
16
|
+
"dodont_media"
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
// src/lib/container-ops.ts
|
|
20
|
+
function getContainerChildren(block) {
|
|
21
|
+
const content = block.content;
|
|
22
|
+
return Array.isArray(content?.children) ? content.children : [];
|
|
23
|
+
}
|
|
24
|
+
function withChildren(container, children) {
|
|
25
|
+
return { ...container, content: { ...container.content, children } };
|
|
26
|
+
}
|
|
27
|
+
function containerColumns(container) {
|
|
28
|
+
const n = container.content?.columns;
|
|
29
|
+
return typeof n === "number" && n >= 1 ? n : 1;
|
|
30
|
+
}
|
|
31
|
+
function removeChildAt(container, index) {
|
|
32
|
+
const children = getContainerChildren(container);
|
|
33
|
+
if (index < 0 || index >= children.length) return { container, removed: null };
|
|
34
|
+
const next = [...children];
|
|
35
|
+
const [removed] = next.splice(index, 1);
|
|
36
|
+
return { container: withChildren(container, next), removed };
|
|
37
|
+
}
|
|
38
|
+
function duplicateChildAt(container, index, newId) {
|
|
39
|
+
const children = getContainerChildren(container);
|
|
40
|
+
if (index < 0 || index >= children.length) return container;
|
|
41
|
+
const clone = { ...JSON.parse(JSON.stringify(children[index])), id: newId() };
|
|
42
|
+
const next = [...children];
|
|
43
|
+
next.splice(index + 1, 0, clone);
|
|
44
|
+
return withChildren(container, next);
|
|
45
|
+
}
|
|
46
|
+
function setChildColSpan(container, index, span) {
|
|
47
|
+
const children = getContainerChildren(container);
|
|
48
|
+
if (index < 0 || index >= children.length) return container;
|
|
49
|
+
const clamped = Math.max(1, Math.min(span, containerColumns(container)));
|
|
50
|
+
const next = children.map((child, i) => {
|
|
51
|
+
if (i !== index) return child;
|
|
52
|
+
if (clamped <= 1) {
|
|
53
|
+
const { layout: _drop, ...rest } = child;
|
|
54
|
+
return rest;
|
|
55
|
+
}
|
|
56
|
+
return { ...child, layout: { ...child.layout, colSpan: clamped } };
|
|
57
|
+
});
|
|
58
|
+
return withChildren(container, next);
|
|
59
|
+
}
|
|
60
|
+
function effectiveSpan(child, columns) {
|
|
61
|
+
return isSpacer(child) ? 1 : Math.min(child.layout?.colSpan ?? 1, columns);
|
|
62
|
+
}
|
|
63
|
+
function isSpacer(child) {
|
|
64
|
+
return child.type === "spacer";
|
|
65
|
+
}
|
|
66
|
+
function occupiedColumns(children, columns) {
|
|
67
|
+
return children.reduce((sum, c) => sum + effectiveSpan(c, columns), 0);
|
|
68
|
+
}
|
|
69
|
+
function trimTrailingSpacers(container) {
|
|
70
|
+
const children = getContainerChildren(container);
|
|
71
|
+
let end = children.length;
|
|
72
|
+
while (end > 0 && isSpacer(children[end - 1])) end--;
|
|
73
|
+
if (end === children.length) return container;
|
|
74
|
+
return withChildren(container, children.slice(0, end));
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export {
|
|
78
|
+
getContainerChildren,
|
|
79
|
+
removeChildAt,
|
|
80
|
+
duplicateChildAt,
|
|
81
|
+
setChildColSpan,
|
|
82
|
+
isSpacer,
|
|
83
|
+
occupiedColumns,
|
|
84
|
+
trimTrailingSpacers
|
|
85
|
+
};
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import {
|
|
2
|
+
getContainerChildren
|
|
3
|
+
} from "./chunk-CXZ5YJG4.js";
|
|
1
4
|
import {
|
|
2
5
|
getSection
|
|
3
6
|
} from "./chunk-FTPETWXE.js";
|
|
@@ -12,6 +15,17 @@ function toSectionId(text) {
|
|
|
12
15
|
}
|
|
13
16
|
return `section-${Math.abs(hash).toString(36)}`;
|
|
14
17
|
}
|
|
18
|
+
function flattenForNav(sections) {
|
|
19
|
+
const flat = [];
|
|
20
|
+
const walk = (loaded) => {
|
|
21
|
+
flat.push(loaded);
|
|
22
|
+
for (const child of getContainerChildren(loaded.section)) {
|
|
23
|
+
walk({ section: child, meta: loaded.meta });
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
sections.forEach(walk);
|
|
27
|
+
return flat;
|
|
28
|
+
}
|
|
15
29
|
function generateNavLinks(sections, registry) {
|
|
16
30
|
const nav = [];
|
|
17
31
|
let currentParent = null;
|
|
@@ -20,7 +34,7 @@ function generateNavLinks(sections, registry) {
|
|
|
20
34
|
const def = registry ? registry.getSection(type) : getSection(type);
|
|
21
35
|
return def?.navRole;
|
|
22
36
|
};
|
|
23
|
-
for (const { section, meta } of sections) {
|
|
37
|
+
for (const { section, meta } of flattenForNav(sections)) {
|
|
24
38
|
const content = section.content;
|
|
25
39
|
if (!content.heading) continue;
|
|
26
40
|
const role = lookupRole(section.type);
|
|
@@ -66,43 +80,7 @@ function generateNavLinks(sections, registry) {
|
|
|
66
80
|
return nav;
|
|
67
81
|
}
|
|
68
82
|
|
|
69
|
-
// src/lib/sanitize.ts
|
|
70
|
-
var purifierPromise = null;
|
|
71
|
-
var purifier = null;
|
|
72
|
-
if (typeof window !== "undefined") {
|
|
73
|
-
purifierPromise = import("dompurify").then((mod) => {
|
|
74
|
-
const DOMPurify = mod.default ?? mod;
|
|
75
|
-
purifier = (html) => DOMPurify.sanitize(html);
|
|
76
|
-
return mod;
|
|
77
|
-
});
|
|
78
|
-
}
|
|
79
|
-
var sanitizeCache = /* @__PURE__ */ new Map();
|
|
80
|
-
var SANITIZE_CACHE_LIMIT = 500;
|
|
81
|
-
function sanitizeHtml(html) {
|
|
82
|
-
if (!html) return "";
|
|
83
|
-
if (!purifier) return html;
|
|
84
|
-
const cached = sanitizeCache.get(html);
|
|
85
|
-
if (cached !== void 0) return cached;
|
|
86
|
-
const clean = purifier(html);
|
|
87
|
-
if (sanitizeCache.size >= SANITIZE_CACHE_LIMIT) {
|
|
88
|
-
const oldest = sanitizeCache.keys().next().value;
|
|
89
|
-
if (oldest !== void 0) sanitizeCache.delete(oldest);
|
|
90
|
-
}
|
|
91
|
-
sanitizeCache.set(html, clean);
|
|
92
|
-
return clean;
|
|
93
|
-
}
|
|
94
|
-
function isSanitizerReady() {
|
|
95
|
-
return typeof window === "undefined" || purifier !== null;
|
|
96
|
-
}
|
|
97
|
-
async function ensureSanitizer() {
|
|
98
|
-
if (typeof window === "undefined") return;
|
|
99
|
-
if (!purifier && purifierPromise) await purifierPromise;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
83
|
export {
|
|
103
84
|
toSectionId,
|
|
104
|
-
generateNavLinks
|
|
105
|
-
sanitizeHtml,
|
|
106
|
-
isSanitizerReady,
|
|
107
|
-
ensureSanitizer
|
|
85
|
+
generateNavLinks
|
|
108
86
|
};
|
|
@@ -2,14 +2,16 @@ import {
|
|
|
2
2
|
AddIcon,
|
|
3
3
|
DeleteIcon,
|
|
4
4
|
DragHandle,
|
|
5
|
-
IconButton,
|
|
6
5
|
SettingsIcon,
|
|
7
6
|
useMediaLibrary,
|
|
8
7
|
useResolvedMedia
|
|
9
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-JH762VUH.js";
|
|
9
|
+
import {
|
|
10
|
+
IconButton
|
|
11
|
+
} from "./chunk-IIDKW7AV.js";
|
|
10
12
|
import {
|
|
11
13
|
rebindImageRef
|
|
12
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-FRE2CCLV.js";
|
|
13
15
|
import {
|
|
14
16
|
cn
|
|
15
17
|
} from "./chunk-7EOSDFS3.js";
|
|
@@ -74,6 +76,8 @@ function EditablePlainText({
|
|
|
74
76
|
...htmlAttrs
|
|
75
77
|
}) {
|
|
76
78
|
const ref = useRef2(null);
|
|
79
|
+
const uncontrolled = useRef2(value);
|
|
80
|
+
if (!isEditMode) uncontrolled.current = value;
|
|
77
81
|
const {
|
|
78
82
|
value: localValue,
|
|
79
83
|
handleInput,
|
|
@@ -131,7 +135,7 @@ function EditablePlainText({
|
|
|
131
135
|
"data-placeholder": isEditMode && placeholder ? placeholder : void 0,
|
|
132
136
|
...htmlAttrs
|
|
133
137
|
},
|
|
134
|
-
value
|
|
138
|
+
isEditMode ? uncontrolled.current : value
|
|
135
139
|
);
|
|
136
140
|
}
|
|
137
141
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
slugifyPageSlug
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-NHN2LSIU.js";
|
|
4
4
|
|
|
5
5
|
// src/media/utils.ts
|
|
6
6
|
async function hashFileBuffer(buffer) {
|
|
@@ -248,7 +248,8 @@ function resolveLogo(logo, manifest, provider) {
|
|
|
248
248
|
lightUrl: light.src,
|
|
249
249
|
darkUrl,
|
|
250
250
|
invertInDark: logo.invertInDark,
|
|
251
|
-
showInNav: logo.showInNav
|
|
251
|
+
showInNav: logo.showInNav,
|
|
252
|
+
hideTitle: logo.hideTitle
|
|
252
253
|
};
|
|
253
254
|
}
|
|
254
255
|
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import {
|
|
2
|
+
serializeDeck
|
|
3
|
+
} from "./chunk-VAYZJKVR.js";
|
|
4
|
+
|
|
5
|
+
// src/lib/deck-dexie.ts
|
|
6
|
+
import Dexie from "dexie";
|
|
7
|
+
var DeckDraftDatabase = class extends Dexie {
|
|
8
|
+
drafts;
|
|
9
|
+
constructor(name) {
|
|
10
|
+
super(name);
|
|
11
|
+
this.version(1).stores({ drafts: "deckId" });
|
|
12
|
+
}
|
|
13
|
+
};
|
|
14
|
+
function databaseName(siteId, scope) {
|
|
15
|
+
return `brand-portal-decks-${siteId}-${scope}`;
|
|
16
|
+
}
|
|
17
|
+
var db = null;
|
|
18
|
+
function initDeckDraftStore(siteId, scope) {
|
|
19
|
+
const name = databaseName(siteId, scope);
|
|
20
|
+
if (db?.name === name) return;
|
|
21
|
+
db?.close();
|
|
22
|
+
db = new DeckDraftDatabase(name);
|
|
23
|
+
}
|
|
24
|
+
function getDb() {
|
|
25
|
+
if (!db) throw new Error("Deck draft store not initialized. Call initDeckDraftStore first.");
|
|
26
|
+
return db;
|
|
27
|
+
}
|
|
28
|
+
async function listDeckDrafts() {
|
|
29
|
+
const rows = await getDb().drafts.toArray();
|
|
30
|
+
return rows.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));
|
|
31
|
+
}
|
|
32
|
+
async function getDeckDraft(deckId) {
|
|
33
|
+
return await getDb().drafts.get(deckId) ?? null;
|
|
34
|
+
}
|
|
35
|
+
async function putDeckDraft(deck) {
|
|
36
|
+
const db2 = getDb();
|
|
37
|
+
return db2.transaction("rw", db2.drafts, async () => {
|
|
38
|
+
const existing = await db2.drafts.get(deck.id);
|
|
39
|
+
const row = {
|
|
40
|
+
deckId: deck.id,
|
|
41
|
+
deck,
|
|
42
|
+
baseVersion: existing?.baseVersion ?? null,
|
|
43
|
+
publishedText: existing?.publishedText ?? null,
|
|
44
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
45
|
+
};
|
|
46
|
+
await db2.drafts.put(row);
|
|
47
|
+
return row;
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
async function markDeckDraftPublished(deck, version, updatedAt) {
|
|
51
|
+
const row = {
|
|
52
|
+
deckId: deck.id,
|
|
53
|
+
deck,
|
|
54
|
+
baseVersion: version,
|
|
55
|
+
publishedText: serializeDeck(deck),
|
|
56
|
+
updatedAt: updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
57
|
+
};
|
|
58
|
+
await getDb().drafts.put(row);
|
|
59
|
+
return row;
|
|
60
|
+
}
|
|
61
|
+
async function recordDeckPublish(deckId, publishedDeck, version) {
|
|
62
|
+
const db2 = getDb();
|
|
63
|
+
return db2.transaction("rw", db2.drafts, async () => {
|
|
64
|
+
const existing = await db2.drafts.get(deckId);
|
|
65
|
+
if (!existing) return null;
|
|
66
|
+
const row = {
|
|
67
|
+
...existing,
|
|
68
|
+
baseVersion: version,
|
|
69
|
+
publishedText: serializeDeck(publishedDeck),
|
|
70
|
+
// "Now", as the previous implementation stamped: a publish is activity the
|
|
71
|
+
// deck grid should sort on, even though it did not change the body.
|
|
72
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
73
|
+
};
|
|
74
|
+
await db2.drafts.put(row);
|
|
75
|
+
return row;
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
async function deleteDeckDraft(deckId) {
|
|
79
|
+
await getDb().drafts.delete(deckId);
|
|
80
|
+
}
|
|
81
|
+
function hasUnpublishedChanges(row) {
|
|
82
|
+
return row.publishedText === null || serializeDeck(row.deck) !== row.publishedText;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export {
|
|
86
|
+
initDeckDraftStore,
|
|
87
|
+
listDeckDrafts,
|
|
88
|
+
getDeckDraft,
|
|
89
|
+
putDeckDraft,
|
|
90
|
+
markDeckDraftPublished,
|
|
91
|
+
recordDeckPublish,
|
|
92
|
+
deleteDeckDraft,
|
|
93
|
+
hasUnpublishedChanges
|
|
94
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-7EOSDFS3.js";
|
|
4
|
+
|
|
5
|
+
// src/components/shared/IconButton.tsx
|
|
6
|
+
import { forwardRef } from "react";
|
|
7
|
+
import { jsx } from "react/jsx-runtime";
|
|
8
|
+
var sizeClasses = {
|
|
9
|
+
sm: "h-chrome-sm w-chrome-sm",
|
|
10
|
+
md: "h-chrome-md w-chrome-md",
|
|
11
|
+
lg: "h-chrome-lg w-chrome-lg"
|
|
12
|
+
};
|
|
13
|
+
var intentClasses = {
|
|
14
|
+
default: "text-base-contrast-light hover:text-base-contrast",
|
|
15
|
+
destructive: "text-destructive hover:text-destructive-hover",
|
|
16
|
+
primary: "text-primary/60 hover:text-primary"
|
|
17
|
+
};
|
|
18
|
+
var IconButton = forwardRef(
|
|
19
|
+
function IconButton2({ icon, label, size = "md", intent = "default", className, ...rest }, ref) {
|
|
20
|
+
return /* @__PURE__ */ jsx(
|
|
21
|
+
"button",
|
|
22
|
+
{
|
|
23
|
+
ref,
|
|
24
|
+
type: "button",
|
|
25
|
+
className: cn(
|
|
26
|
+
"cursor-pointer flex items-center justify-center rounded transition-colors",
|
|
27
|
+
sizeClasses[size],
|
|
28
|
+
intentClasses[intent],
|
|
29
|
+
className
|
|
30
|
+
),
|
|
31
|
+
"aria-label": label,
|
|
32
|
+
...rest,
|
|
33
|
+
children: icon
|
|
34
|
+
}
|
|
35
|
+
);
|
|
36
|
+
}
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
export {
|
|
40
|
+
IconButton
|
|
41
|
+
};
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cn
|
|
3
|
+
} from "./chunk-7EOSDFS3.js";
|
|
4
|
+
|
|
5
|
+
// src/components/shared/Tooltip.tsx
|
|
6
|
+
import { jsx, jsxs } from "react/jsx-runtime";
|
|
7
|
+
var sideClasses = {
|
|
8
|
+
bottom: "left-1/2 top-full mt-1.5 -translate-x-1/2",
|
|
9
|
+
right: "left-full top-1/2 ml-1.5 -translate-y-1/2",
|
|
10
|
+
"bottom-clamp": "top-full mt-1.5 left-1/2 -translate-x-1/2 max-xl:left-auto max-xl:right-0 max-xl:translate-x-0"
|
|
11
|
+
};
|
|
12
|
+
function Tooltip({ content, children, className, side = "bottom" }) {
|
|
13
|
+
return /* @__PURE__ */ jsxs("div", { className: cn("group/tooltip relative inline-flex", className), children: [
|
|
14
|
+
children,
|
|
15
|
+
/* @__PURE__ */ jsx(
|
|
16
|
+
"span",
|
|
17
|
+
{
|
|
18
|
+
className: cn(
|
|
19
|
+
"pointer-events-none absolute z-50 opacity-0 transition-opacity delay-300 group-hover/tooltip:opacity-100",
|
|
20
|
+
sideClasses[side]
|
|
21
|
+
),
|
|
22
|
+
role: "tooltip",
|
|
23
|
+
children: /* @__PURE__ */ jsx("span", { className: "block whitespace-nowrap rounded bg-tooltip px-2 py-1 text-center text-xs leading-relaxed text-tooltip-muted", children: content })
|
|
24
|
+
}
|
|
25
|
+
)
|
|
26
|
+
] });
|
|
27
|
+
}
|
|
28
|
+
function Kbd({ children }) {
|
|
29
|
+
return /* @__PURE__ */ jsx("strong", { className: "text-tooltip-contrast", children });
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// src/components/shared/Popover.tsx
|
|
33
|
+
import { useEffect as useEffect2, useLayoutEffect, useRef, useState } from "react";
|
|
34
|
+
import { createPortal } from "react-dom";
|
|
35
|
+
|
|
36
|
+
// src/hooks/useFocusTrap.ts
|
|
37
|
+
import { useEffect } from "react";
|
|
38
|
+
var FOCUSABLE_SELECTOR = [
|
|
39
|
+
"a[href]",
|
|
40
|
+
"button:not([disabled])",
|
|
41
|
+
"input:not([disabled])",
|
|
42
|
+
"select:not([disabled])",
|
|
43
|
+
"textarea:not([disabled])",
|
|
44
|
+
'[tabindex]:not([tabindex="-1"])'
|
|
45
|
+
].join(", ");
|
|
46
|
+
function useInitialFocus(ref, active) {
|
|
47
|
+
useEffect(() => {
|
|
48
|
+
if (!active || !ref.current) return;
|
|
49
|
+
const previouslyFocused = document.activeElement;
|
|
50
|
+
ref.current.querySelector(FOCUSABLE_SELECTOR)?.focus();
|
|
51
|
+
return () => {
|
|
52
|
+
if (previouslyFocused && document.body.contains(previouslyFocused)) {
|
|
53
|
+
previouslyFocused.focus();
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
}, [active, ref]);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// src/components/shared/Popover.tsx
|
|
60
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
61
|
+
function Popover({
|
|
62
|
+
isOpen,
|
|
63
|
+
onClose,
|
|
64
|
+
anchorRef,
|
|
65
|
+
children,
|
|
66
|
+
align = "auto",
|
|
67
|
+
className,
|
|
68
|
+
portal = false,
|
|
69
|
+
placement = "bottom"
|
|
70
|
+
}) {
|
|
71
|
+
const panelRef = useRef(null);
|
|
72
|
+
const [resolvedAlign, setResolvedAlign] = useState("start");
|
|
73
|
+
const [fixedPos, setFixedPos] = useState(null);
|
|
74
|
+
useInitialFocus(panelRef, isOpen && (!portal || fixedPos !== null));
|
|
75
|
+
useLayoutEffect(() => {
|
|
76
|
+
if (!portal) return;
|
|
77
|
+
if (!isOpen) {
|
|
78
|
+
setFixedPos(null);
|
|
79
|
+
return;
|
|
80
|
+
}
|
|
81
|
+
const anchor = anchorRef.current;
|
|
82
|
+
if (!anchor) return;
|
|
83
|
+
const update = () => {
|
|
84
|
+
const r = anchor.getBoundingClientRect();
|
|
85
|
+
const next = placement === "top" ? { left: r.left, bottom: window.innerHeight - r.top + 4 } : { left: r.left, top: r.bottom + 4 };
|
|
86
|
+
setFixedPos(
|
|
87
|
+
(prev) => prev && prev.left === next.left && prev.top === next.top && prev.bottom === next.bottom ? prev : next
|
|
88
|
+
);
|
|
89
|
+
};
|
|
90
|
+
update();
|
|
91
|
+
window.addEventListener("resize", update);
|
|
92
|
+
window.addEventListener("scroll", update, true);
|
|
93
|
+
return () => {
|
|
94
|
+
window.removeEventListener("resize", update);
|
|
95
|
+
window.removeEventListener("scroll", update, true);
|
|
96
|
+
};
|
|
97
|
+
}, [isOpen, portal, placement, anchorRef]);
|
|
98
|
+
useLayoutEffect(() => {
|
|
99
|
+
if (portal) return;
|
|
100
|
+
if (!isOpen || align !== "auto") {
|
|
101
|
+
if (!isOpen) setResolvedAlign("start");
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
const panel = panelRef.current;
|
|
105
|
+
if (!panel) return;
|
|
106
|
+
panel.style.left = "0";
|
|
107
|
+
panel.style.right = "auto";
|
|
108
|
+
const rect = panel.getBoundingClientRect();
|
|
109
|
+
if (rect.right > window.innerWidth) {
|
|
110
|
+
setResolvedAlign("end");
|
|
111
|
+
} else {
|
|
112
|
+
setResolvedAlign("start");
|
|
113
|
+
}
|
|
114
|
+
panel.style.left = "";
|
|
115
|
+
panel.style.right = "";
|
|
116
|
+
}, [isOpen, align]);
|
|
117
|
+
useEffect2(() => {
|
|
118
|
+
if (!isOpen) return;
|
|
119
|
+
function onKeyDown(e) {
|
|
120
|
+
if (e.key !== "Escape") return;
|
|
121
|
+
if (document.querySelector("[data-modal-layer]")) return;
|
|
122
|
+
onClose();
|
|
123
|
+
}
|
|
124
|
+
function onMouseDown(e) {
|
|
125
|
+
const target = e.target;
|
|
126
|
+
if (panelRef.current?.contains(target)) return;
|
|
127
|
+
if (anchorRef.current?.contains(target)) return;
|
|
128
|
+
if (target instanceof Element && target.closest("[data-modal-layer]")) return;
|
|
129
|
+
onClose();
|
|
130
|
+
}
|
|
131
|
+
document.addEventListener("keydown", onKeyDown);
|
|
132
|
+
document.addEventListener("mousedown", onMouseDown);
|
|
133
|
+
return () => {
|
|
134
|
+
document.removeEventListener("keydown", onKeyDown);
|
|
135
|
+
document.removeEventListener("mousedown", onMouseDown);
|
|
136
|
+
};
|
|
137
|
+
}, [isOpen, onClose, anchorRef]);
|
|
138
|
+
if (!isOpen) return null;
|
|
139
|
+
const effectiveAlign = align === "auto" ? resolvedAlign : align;
|
|
140
|
+
if (portal) {
|
|
141
|
+
if (!fixedPos) return null;
|
|
142
|
+
return createPortal(
|
|
143
|
+
/* @__PURE__ */ jsx2(
|
|
144
|
+
"div",
|
|
145
|
+
{
|
|
146
|
+
ref: panelRef,
|
|
147
|
+
role: "dialog",
|
|
148
|
+
"aria-modal": "false",
|
|
149
|
+
style: {
|
|
150
|
+
position: "fixed",
|
|
151
|
+
left: `${fixedPos.left}px`,
|
|
152
|
+
...fixedPos.top !== void 0 ? { top: `${fixedPos.top}px` } : {},
|
|
153
|
+
...fixedPos.bottom !== void 0 ? { bottom: `${fixedPos.bottom}px` } : {}
|
|
154
|
+
},
|
|
155
|
+
className: cn("z-50 rounded-md border border-base-200 bg-base shadow-lg", className),
|
|
156
|
+
children
|
|
157
|
+
}
|
|
158
|
+
),
|
|
159
|
+
document.body
|
|
160
|
+
);
|
|
161
|
+
}
|
|
162
|
+
return /* @__PURE__ */ jsx2(
|
|
163
|
+
"div",
|
|
164
|
+
{
|
|
165
|
+
ref: panelRef,
|
|
166
|
+
role: "dialog",
|
|
167
|
+
"aria-modal": "false",
|
|
168
|
+
className: cn(
|
|
169
|
+
"absolute top-full z-50 mt-1 rounded-md border border-base-200 bg-base shadow-lg",
|
|
170
|
+
effectiveAlign === "end" ? "right-0" : "left-0",
|
|
171
|
+
className
|
|
172
|
+
),
|
|
173
|
+
children
|
|
174
|
+
}
|
|
175
|
+
);
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
// src/components/shared/PopoverItem.tsx
|
|
179
|
+
import { forwardRef } from "react";
|
|
180
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
181
|
+
var PopoverItem = forwardRef(
|
|
182
|
+
function PopoverItem2({ className, children, ...rest }, ref) {
|
|
183
|
+
return /* @__PURE__ */ jsx3(
|
|
184
|
+
"button",
|
|
185
|
+
{
|
|
186
|
+
ref,
|
|
187
|
+
type: "button",
|
|
188
|
+
className: cn(
|
|
189
|
+
"flex w-full cursor-pointer items-center gap-3 px-3 py-1.5 text-left text-xs hover:bg-base-accent",
|
|
190
|
+
className
|
|
191
|
+
),
|
|
192
|
+
...rest,
|
|
193
|
+
children
|
|
194
|
+
}
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
);
|
|
198
|
+
|
|
199
|
+
export {
|
|
200
|
+
Tooltip,
|
|
201
|
+
Kbd,
|
|
202
|
+
Popover,
|
|
203
|
+
PopoverItem
|
|
204
|
+
};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
getMediaProvider
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-FRE2CCLV.js";
|
|
4
4
|
import {
|
|
5
5
|
cn
|
|
6
6
|
} from "./chunk-7EOSDFS3.js";
|
|
@@ -72,44 +72,10 @@ function SettingsIcon({ size = 14 }) {
|
|
|
72
72
|
return /* @__PURE__ */ jsx(Settings, { size });
|
|
73
73
|
}
|
|
74
74
|
|
|
75
|
-
// src/components/shared/IconButton.tsx
|
|
76
|
-
import { forwardRef } from "react";
|
|
77
|
-
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
78
|
-
var sizeClasses = {
|
|
79
|
-
sm: "h-chrome-sm w-chrome-sm",
|
|
80
|
-
md: "h-chrome-md w-chrome-md",
|
|
81
|
-
lg: "h-chrome-lg w-chrome-lg"
|
|
82
|
-
};
|
|
83
|
-
var intentClasses = {
|
|
84
|
-
default: "text-base-contrast-light hover:text-base-contrast",
|
|
85
|
-
destructive: "text-destructive hover:text-destructive-hover",
|
|
86
|
-
primary: "text-primary/60 hover:text-primary"
|
|
87
|
-
};
|
|
88
|
-
var IconButton = forwardRef(
|
|
89
|
-
function IconButton2({ icon, label, size = "md", intent = "default", className, ...rest }, ref) {
|
|
90
|
-
return /* @__PURE__ */ jsx2(
|
|
91
|
-
"button",
|
|
92
|
-
{
|
|
93
|
-
ref,
|
|
94
|
-
type: "button",
|
|
95
|
-
className: cn(
|
|
96
|
-
"cursor-pointer flex items-center justify-center rounded transition-colors",
|
|
97
|
-
sizeClasses[size],
|
|
98
|
-
intentClasses[intent],
|
|
99
|
-
className
|
|
100
|
-
),
|
|
101
|
-
"aria-label": label,
|
|
102
|
-
...rest,
|
|
103
|
-
children: icon
|
|
104
|
-
}
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
);
|
|
108
|
-
|
|
109
75
|
// src/components/shared/FormLabel.tsx
|
|
110
|
-
import { jsx as
|
|
76
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
111
77
|
function FormLabel({ htmlFor, children, className }) {
|
|
112
|
-
return /* @__PURE__ */
|
|
78
|
+
return /* @__PURE__ */ jsx2(
|
|
113
79
|
"label",
|
|
114
80
|
{
|
|
115
81
|
htmlFor,
|
|
@@ -120,14 +86,14 @@ function FormLabel({ htmlFor, children, className }) {
|
|
|
120
86
|
}
|
|
121
87
|
|
|
122
88
|
// src/components/shared/Input.tsx
|
|
123
|
-
import { forwardRef
|
|
124
|
-
import { jsx as
|
|
125
|
-
var Input =
|
|
89
|
+
import { forwardRef, useId } from "react";
|
|
90
|
+
import { jsx as jsx3, jsxs } from "react/jsx-runtime";
|
|
91
|
+
var Input = forwardRef(function Input2({ label, value, onChange, type = "text", className, disabled, error, ...rest }, ref) {
|
|
126
92
|
const id = useId();
|
|
127
93
|
const errorId = `${id}-error`;
|
|
128
94
|
return /* @__PURE__ */ jsxs("div", { className, children: [
|
|
129
|
-
/* @__PURE__ */
|
|
130
|
-
/* @__PURE__ */
|
|
95
|
+
/* @__PURE__ */ jsx3(FormLabel, { htmlFor: id, children: label }),
|
|
96
|
+
/* @__PURE__ */ jsx3(
|
|
131
97
|
"input",
|
|
132
98
|
{
|
|
133
99
|
ref,
|
|
@@ -146,7 +112,7 @@ var Input = forwardRef2(function Input2({ label, value, onChange, type = "text",
|
|
|
146
112
|
...rest
|
|
147
113
|
}
|
|
148
114
|
),
|
|
149
|
-
error && /* @__PURE__ */
|
|
115
|
+
error && /* @__PURE__ */ jsx3("p", { id: errorId, className: "mt-1 text-xs text-red-600", children: error })
|
|
150
116
|
] });
|
|
151
117
|
});
|
|
152
118
|
|
|
@@ -157,7 +123,6 @@ export {
|
|
|
157
123
|
AddIcon,
|
|
158
124
|
DeleteIcon,
|
|
159
125
|
SettingsIcon,
|
|
160
|
-
IconButton,
|
|
161
126
|
FormLabel,
|
|
162
127
|
Input
|
|
163
128
|
};
|