@arbidocs/blocks 0.5.122 → 0.5.124
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/{ClippingMediaViewer-IEIBT74X.cjs → ClippingMediaViewer-ZFEX5A3U.cjs} +11 -10
- package/dist/ClippingMediaViewer-ZFEX5A3U.cjs.map +1 -0
- package/dist/{ClippingPdfViewer-OGYLMVCE.cjs → ClippingPdfViewer-3LRTEPHV.cjs} +45 -11
- package/dist/ClippingPdfViewer-3LRTEPHV.cjs.map +1 -0
- package/dist/{ConnectedPresentation-AU25OW25.cjs → ConnectedPresentation-OV2KBOLK.cjs} +27 -153
- package/dist/ConnectedPresentation-OV2KBOLK.cjs.map +1 -0
- package/dist/{ConnectedSlidesTab-I75LKKN7.cjs → ConnectedSlidesTab-LUAGZ6FD.cjs} +60 -36
- package/dist/ConnectedSlidesTab-LUAGZ6FD.cjs.map +1 -0
- package/dist/{FilesViewerDialog-4352KIOG.cjs → FilesViewerDialog-JWKNJLWG.cjs} +10 -7
- package/dist/FilesViewerDialog-JWKNJLWG.cjs.map +1 -0
- package/dist/SpotlightStrip-ED22UYTM.cjs +398 -0
- package/dist/SpotlightStrip-ED22UYTM.cjs.map +1 -0
- package/dist/{chunk-LHWOKOMP.cjs → chunk-3IH55CDE.cjs} +4 -4
- package/dist/chunk-3IH55CDE.cjs.map +1 -0
- package/dist/chunk-3ZZZO4F7.cjs +145 -0
- package/dist/chunk-3ZZZO4F7.cjs.map +1 -0
- package/dist/{chunk-WFMWKPGY.cjs → chunk-ADPRIBSH.cjs} +9 -33
- package/dist/chunk-ADPRIBSH.cjs.map +1 -0
- package/dist/{chunk-UTJ223TI.cjs → chunk-BX6G2ZCI.cjs} +138 -146
- package/dist/chunk-BX6G2ZCI.cjs.map +1 -0
- package/dist/{chunk-WRLGLZIA.cjs → chunk-EMRY62HS.cjs} +2 -2
- package/dist/{chunk-WRLGLZIA.cjs.map → chunk-EMRY62HS.cjs.map} +1 -1
- package/dist/{chunk-USNTRL22.cjs → chunk-H236SNEV.cjs} +199 -1616
- package/dist/chunk-H236SNEV.cjs.map +1 -0
- package/dist/chunk-JITYC4OS.cjs +66 -0
- package/dist/chunk-JITYC4OS.cjs.map +1 -0
- package/dist/chunk-JY7UUZQG.cjs +1513 -0
- package/dist/chunk-JY7UUZQG.cjs.map +1 -0
- package/dist/chunk-MVXHTAJ4.cjs +111 -0
- package/dist/chunk-MVXHTAJ4.cjs.map +1 -0
- package/dist/{chunk-4TTX6ZNS.cjs → chunk-ORNLCBNE.cjs} +24 -2
- package/dist/chunk-ORNLCBNE.cjs.map +1 -0
- package/dist/chunk-WVZLAAIZ.cjs +31 -0
- package/dist/chunk-WVZLAAIZ.cjs.map +1 -0
- package/dist/chunk-ZZZITHGK.cjs +119 -0
- package/dist/chunk-ZZZITHGK.cjs.map +1 -0
- package/dist/connect/index.cjs +52 -52
- package/dist/connect/viewer.cjs +8 -5
- package/dist/connection/presentation/ClippingMediaViewer.js +3 -3
- package/dist/connection/presentation/ClippingMediaViewer.js.map +2 -2
- package/dist/connection/presentation/ClippingPdfViewer.d.ts +4 -3
- package/dist/connection/presentation/ClippingPdfViewer.js +48 -9
- package/dist/connection/presentation/ClippingPdfViewer.js.map +2 -2
- package/dist/connection/presentation/ConnectedSlidesTab.js +35 -13
- package/dist/connection/presentation/ConnectedSlidesTab.js.map +2 -2
- package/dist/connection/presentation/SpotlightLayer.d.ts +5 -0
- package/dist/connection/presentation/SpotlightLayer.js +19 -0
- package/dist/connection/presentation/SpotlightLayer.js.map +7 -0
- package/dist/connection/presentation/SpotlightStrip.d.ts +10 -0
- package/dist/connection/presentation/SpotlightStrip.js +237 -0
- package/dist/connection/presentation/SpotlightStrip.js.map +7 -0
- package/dist/connection/presentation/useViewerClipping.d.ts +4 -3
- package/dist/connection/presentation/useViewerClipping.js +8 -4
- package/dist/connection/presentation/useViewerClipping.js.map +2 -2
- package/dist/connection/viewer/ConnectedDocumentViewer.js +52 -61
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/ViewerMoreMenu.d.ts +18 -0
- package/dist/connection/viewer/ViewerMoreMenu.js +45 -0
- package/dist/connection/viewer/ViewerMoreMenu.js.map +7 -0
- package/dist/connection/viewer/pdf/PdfPassageHighlights.js +3 -2
- package/dist/connection/viewer/pdf/PdfPassageHighlights.js.map +2 -2
- package/dist/connection/viewer/pdf/passageHighlights.d.ts +5 -0
- package/dist/connection/viewer/pdf/passageHighlights.js +14 -1
- package/dist/connection/viewer/pdf/passageHighlights.js.map +2 -2
- package/dist/connection/viewer/useCleanView.d.ts +3 -1
- package/dist/connection/viewer/useCleanView.js +6 -3
- package/dist/connection/viewer/useCleanView.js.map +2 -2
- package/dist/document-tools/DocumentToolButtons.js +3 -3
- package/dist/document-tools/DocumentToolButtons.js.map +2 -2
- package/dist/document-tools/index.cjs +13 -13
- package/dist/index.cjs +53 -53
- package/dist/presentation/BoxActionBar.d.ts +2 -2
- package/dist/presentation/BoxActionBar.js +62 -30
- package/dist/presentation/BoxActionBar.js.map +2 -2
- package/dist/presentation/ClipActionBar.js +60 -7
- package/dist/presentation/ClipActionBar.js.map +2 -2
- package/dist/presentation/ClipCaptureOverlay.d.ts +7 -3
- package/dist/presentation/ClipCaptureOverlay.js +43 -14
- package/dist/presentation/ClipCaptureOverlay.js.map +2 -2
- package/dist/presentation/ClipViewControls.d.ts +3 -3
- package/dist/presentation/ClipViewControls.js +59 -64
- package/dist/presentation/ClipViewControls.js.map +2 -2
- package/dist/presentation/PresentControls.d.ts +8 -0
- package/dist/presentation/PresentControls.js +1 -0
- package/dist/presentation/PresentControls.js.map +2 -2
- package/dist/presentation/PresentationStage.d.ts +10 -2
- package/dist/presentation/PresentationStage.js +6 -3
- package/dist/presentation/PresentationStage.js.map +2 -2
- package/dist/presentation/PresenterView.js +1 -22
- package/dist/presentation/PresenterView.js.map +2 -2
- package/dist/presentation/SlidesEditor.js +56 -42
- package/dist/presentation/SlidesEditor.js.map +2 -2
- package/dist/presentation/SpotlightView.d.ts +19 -0
- package/dist/presentation/SpotlightView.js +180 -0
- package/dist/presentation/SpotlightView.js.map +7 -0
- package/dist/presentation/StageItem.js +0 -5
- package/dist/presentation/StageItem.js.map +2 -2
- package/dist/presentation/passage-clip.d.ts +17 -0
- package/dist/presentation/passage-clip.js +25 -0
- package/dist/presentation/passage-clip.js.map +7 -0
- package/dist/presentation/spotlight.d.ts +58 -0
- package/dist/presentation/spotlight.js +110 -0
- package/dist/presentation/spotlight.js.map +7 -0
- package/dist/presentation/store.d.ts +5 -0
- package/dist/presentation/store.js +19 -0
- package/dist/presentation/store.js.map +2 -2
- package/dist/presentation/usePointerActive.d.ts +2 -0
- package/dist/presentation/usePointerActive.js +28 -0
- package/dist/presentation/usePointerActive.js.map +7 -0
- package/dist/styles.css +1 -1
- package/node_modules/@arbidocs/coedit/package.json +1 -1
- package/package.json +5 -5
- package/dist/ClippingMediaViewer-IEIBT74X.cjs.map +0 -1
- package/dist/ClippingPdfViewer-OGYLMVCE.cjs.map +0 -1
- package/dist/ConnectedPresentation-AU25OW25.cjs.map +0 -1
- package/dist/ConnectedSlidesTab-I75LKKN7.cjs.map +0 -1
- package/dist/FilesViewerDialog-4352KIOG.cjs.map +0 -1
- package/dist/chunk-4TTX6ZNS.cjs.map +0 -1
- package/dist/chunk-LHWOKOMP.cjs.map +0 -1
- package/dist/chunk-USNTRL22.cjs.map +0 -1
- package/dist/chunk-UTJ223TI.cjs.map +0 -1
- package/dist/chunk-WFMWKPGY.cjs.map +0 -1
- package/dist/chunk-XK4TVJKD.cjs +0 -73
- package/dist/chunk-XK4TVJKD.cjs.map +0 -1
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
'use strict';
|
|
3
3
|
|
|
4
|
+
var chunkJY7UUZQG_cjs = require('./chunk-JY7UUZQG.cjs');
|
|
4
5
|
var chunkWOOOMTTA_cjs = require('./chunk-WOOOMTTA.cjs');
|
|
5
|
-
var chunk5GCCUXMT_cjs = require('./chunk-5GCCUXMT.cjs');
|
|
6
6
|
var chunk2F57IO7S_cjs = require('./chunk-2F57IO7S.cjs');
|
|
7
7
|
var chunkUFT22LAB_cjs = require('./chunk-UFT22LAB.cjs');
|
|
8
|
-
var
|
|
9
|
-
var
|
|
8
|
+
var chunkWVZLAAIZ_cjs = require('./chunk-WVZLAAIZ.cjs');
|
|
9
|
+
var chunkADPRIBSH_cjs = require('./chunk-ADPRIBSH.cjs');
|
|
10
|
+
var chunkORNLCBNE_cjs = require('./chunk-ORNLCBNE.cjs');
|
|
10
11
|
var chunk7JLJH5CW_cjs = require('./chunk-7JLJH5CW.cjs');
|
|
11
12
|
var chunkVZOOGA47_cjs = require('./chunk-VZOOGA47.cjs');
|
|
12
13
|
var chunkTKHCIHE2_cjs = require('./chunk-TKHCIHE2.cjs');
|
|
@@ -15,234 +16,11 @@ var react = require('react');
|
|
|
15
16
|
var lucideReact = require('lucide-react');
|
|
16
17
|
var ui = require('@arbidocs/react/ui');
|
|
17
18
|
var reactDom = require('react-dom');
|
|
18
|
-
var viewers = require('@arbidocs/react/viewers');
|
|
19
19
|
var jsxRuntime = require('react/jsx-runtime');
|
|
20
20
|
var react$1 = require('@arbidocs/react');
|
|
21
21
|
var documentTools = require('@arbidocs/react/document-tools');
|
|
22
|
+
var viewers = require('@arbidocs/react/viewers');
|
|
22
23
|
|
|
23
|
-
function cropStyle(rect) {
|
|
24
|
-
return {
|
|
25
|
-
position: "absolute",
|
|
26
|
-
width: `${100 / rect.w}%`,
|
|
27
|
-
height: `${100 / rect.h}%`,
|
|
28
|
-
left: `${-rect.x / rect.w * 100}%`,
|
|
29
|
-
top: `${-rect.y / rect.h * 100}%`,
|
|
30
|
-
maxWidth: "none"
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
|
-
function MediaClip({
|
|
34
|
-
clip,
|
|
35
|
-
className,
|
|
36
|
-
live
|
|
37
|
-
}) {
|
|
38
|
-
const url = chunkWOOOMTTA_cjs.useObjectUrl(clip.source);
|
|
39
|
-
const videoRef = react.useRef(null);
|
|
40
|
-
react.useEffect(() => {
|
|
41
|
-
const video = videoRef.current;
|
|
42
|
-
if (!video) return;
|
|
43
|
-
const toStart = () => {
|
|
44
|
-
video.currentTime = clip.start ?? 0;
|
|
45
|
-
};
|
|
46
|
-
if (video.readyState >= 1) toStart();
|
|
47
|
-
else video.addEventListener("loadedmetadata", toStart, { once: true });
|
|
48
|
-
return () => video.removeEventListener("loadedmetadata", toStart);
|
|
49
|
-
}, [clip.start, url]);
|
|
50
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
51
|
-
"div",
|
|
52
|
-
{
|
|
53
|
-
className: ui.cn("relative h-full w-full overflow-hidden bg-black", className),
|
|
54
|
-
"data-testid": `clip-image-${clip.id}`,
|
|
55
|
-
children: clip.kind === "video" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
56
|
-
"video",
|
|
57
|
-
{
|
|
58
|
-
ref: videoRef,
|
|
59
|
-
src: url,
|
|
60
|
-
muted: !live,
|
|
61
|
-
playsInline: true,
|
|
62
|
-
preload: "auto",
|
|
63
|
-
className: "pointer-events-none block select-none",
|
|
64
|
-
style: cropStyle(clip.rect),
|
|
65
|
-
...live ? { [chunkWFMWKPGY_cjs.STAGE_VIDEO_ATTRIBUTE]: "" } : {}
|
|
66
|
-
}
|
|
67
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
68
|
-
"img",
|
|
69
|
-
{
|
|
70
|
-
src: url,
|
|
71
|
-
alt: clip.caption,
|
|
72
|
-
draggable: false,
|
|
73
|
-
className: "pointer-events-none block select-none",
|
|
74
|
-
style: cropStyle(clip.rect)
|
|
75
|
-
}
|
|
76
|
-
)
|
|
77
|
-
}
|
|
78
|
-
);
|
|
79
|
-
}
|
|
80
|
-
var WIDTH_STEP = 160;
|
|
81
|
-
var SETTLE_MS = 150;
|
|
82
|
-
var ClipImage = react.memo(function ClipImage2({
|
|
83
|
-
clip,
|
|
84
|
-
className,
|
|
85
|
-
live = false
|
|
86
|
-
}) {
|
|
87
|
-
return clip.kind === "pdf" ? /* @__PURE__ */ jsxRuntime.jsx(PdfClip, { clip, className }) : /* @__PURE__ */ jsxRuntime.jsx(MediaClip, { clip, className, live });
|
|
88
|
-
});
|
|
89
|
-
var sameRect = (a, b) => a.x === b.x && a.y === b.y && a.w === b.w && a.h === b.h;
|
|
90
|
-
function PdfClip({ clip, className }) {
|
|
91
|
-
const canvasRef = react.useRef(null);
|
|
92
|
-
const [size, setSize] = react.useState({ width: 0, height: 0 });
|
|
93
|
-
const [rendered, setRendered] = react.useState(null);
|
|
94
|
-
const [failed, setFailed] = react.useState(false);
|
|
95
|
-
react.useEffect(() => {
|
|
96
|
-
const canvas = canvasRef.current;
|
|
97
|
-
const view = canvas?.ownerDocument.defaultView;
|
|
98
|
-
if (!canvas || !view) return;
|
|
99
|
-
const measure = () => {
|
|
100
|
-
const box2 = canvas.getBoundingClientRect();
|
|
101
|
-
const dpr = view.devicePixelRatio || 1;
|
|
102
|
-
const width = Math.max(1, Math.round(box2.width * dpr));
|
|
103
|
-
const height = Math.max(1, Math.round(box2.height * dpr));
|
|
104
|
-
setSize((s) => s.width === width && s.height === height ? s : { width, height });
|
|
105
|
-
};
|
|
106
|
-
measure();
|
|
107
|
-
const Observer = view.ResizeObserver ?? ResizeObserver;
|
|
108
|
-
const observer = new Observer(measure);
|
|
109
|
-
observer.observe(canvas);
|
|
110
|
-
return () => observer.disconnect();
|
|
111
|
-
}, []);
|
|
112
|
-
react.useLayoutEffect(() => {
|
|
113
|
-
const canvas = canvasRef.current;
|
|
114
|
-
const context = canvas?.getContext("2d");
|
|
115
|
-
if (!canvas || !context || !size.width) return;
|
|
116
|
-
if (canvas.width !== size.width) canvas.width = size.width;
|
|
117
|
-
if (canvas.height !== size.height) canvas.height = size.height;
|
|
118
|
-
context.fillStyle = "#fff";
|
|
119
|
-
context.fillRect(0, 0, size.width, size.height);
|
|
120
|
-
if (!rendered) return;
|
|
121
|
-
const { rect } = clip;
|
|
122
|
-
const sx = size.width / rect.w;
|
|
123
|
-
const sy = size.height / rect.h;
|
|
124
|
-
try {
|
|
125
|
-
context.drawImage(
|
|
126
|
-
rendered.image,
|
|
127
|
-
(rendered.rect.x - rect.x) * sx,
|
|
128
|
-
(rendered.rect.y - rect.y) * sy,
|
|
129
|
-
rendered.rect.w * sx,
|
|
130
|
-
rendered.rect.h * sy
|
|
131
|
-
);
|
|
132
|
-
} catch {
|
|
133
|
-
setRendered(null);
|
|
134
|
-
}
|
|
135
|
-
}, [size, rendered, clip]);
|
|
136
|
-
const wanted = Math.ceil(size.width / WIDTH_STEP) * WIDTH_STEP;
|
|
137
|
-
const stale = wanted > 0 && (!rendered || !sameRect(rendered.rect, clip.rect) || wanted > rendered.width || wanted < rendered.width / 2);
|
|
138
|
-
react.useEffect(() => {
|
|
139
|
-
if (!stale) return;
|
|
140
|
-
const controller = new AbortController();
|
|
141
|
-
const rect = clip.rect;
|
|
142
|
-
const timer = setTimeout(() => {
|
|
143
|
-
viewers.renderPdfRegion({
|
|
144
|
-
file: clip.source,
|
|
145
|
-
page: clip.page,
|
|
146
|
-
rect,
|
|
147
|
-
masks: clip.masks,
|
|
148
|
-
width: wanted,
|
|
149
|
-
signal: controller.signal
|
|
150
|
-
}).then((image) => {
|
|
151
|
-
if (controller.signal.aborted) return viewers.closePdfRegionImage(image);
|
|
152
|
-
setFailed(false);
|
|
153
|
-
setRendered({ image, rect, width: wanted });
|
|
154
|
-
}).catch(() => !controller.signal.aborted && setFailed(true));
|
|
155
|
-
}, SETTLE_MS);
|
|
156
|
-
return () => {
|
|
157
|
-
clearTimeout(timer);
|
|
158
|
-
controller.abort();
|
|
159
|
-
};
|
|
160
|
-
}, [stale, wanted, clip.source, clip.page, clip.rect, clip.masks]);
|
|
161
|
-
const previous = react.useRef(null);
|
|
162
|
-
react.useEffect(() => {
|
|
163
|
-
if (previous.current && previous.current !== rendered) {
|
|
164
|
-
viewers.closePdfRegionImage(previous.current.image);
|
|
165
|
-
}
|
|
166
|
-
previous.current = rendered;
|
|
167
|
-
}, [rendered]);
|
|
168
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
169
|
-
"div",
|
|
170
|
-
{
|
|
171
|
-
className: ui.cn("relative h-full w-full overflow-hidden bg-white", className),
|
|
172
|
-
"data-testid": `clip-image-${clip.id}`,
|
|
173
|
-
children: [
|
|
174
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
175
|
-
"canvas",
|
|
176
|
-
{
|
|
177
|
-
ref: canvasRef,
|
|
178
|
-
className: "pointer-events-none block h-full w-full",
|
|
179
|
-
role: "img",
|
|
180
|
-
"aria-label": clip.caption,
|
|
181
|
-
"aria-busy": !rendered
|
|
182
|
-
}
|
|
183
|
-
),
|
|
184
|
-
failed && !rendered && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 flex items-center justify-center p-2 text-center text-xs text-neutral-500", children: "Couldn't draw this clip" })
|
|
185
|
-
]
|
|
186
|
-
}
|
|
187
|
-
);
|
|
188
|
-
}
|
|
189
|
-
var DRAG_THRESHOLD = 6;
|
|
190
|
-
var DROP_ATTRIBUTE = "data-presentation-drop";
|
|
191
|
-
function dropAt(doc, clipId, x, y) {
|
|
192
|
-
const target = doc.elementFromPoint(x, y)?.closest(`[${DROP_ATTRIBUTE}]`);
|
|
193
|
-
if (!target) return false;
|
|
194
|
-
const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
195
|
-
if (target.getAttribute(DROP_ATTRIBUTE) === "slide") {
|
|
196
|
-
const index2 = Number(target.getAttribute("data-slide-index"));
|
|
197
|
-
if (!Number.isInteger(index2)) return false;
|
|
198
|
-
state.goTo(index2);
|
|
199
|
-
state.place(clipId);
|
|
200
|
-
return true;
|
|
201
|
-
}
|
|
202
|
-
const index = Number(target.getAttribute("data-slide-index"));
|
|
203
|
-
if (target.hasAttribute("data-slide-index") && Number.isInteger(index)) state.goTo(index);
|
|
204
|
-
const box2 = target.getBoundingClientRect();
|
|
205
|
-
state.place(clipId, { x: (x - box2.left) / box2.width, y: (y - box2.top) / box2.height });
|
|
206
|
-
return true;
|
|
207
|
-
}
|
|
208
|
-
function useClipDrag(clipId, onTap) {
|
|
209
|
-
const press = react.useRef(null);
|
|
210
|
-
const [ghost, setGhost] = react.useState(null);
|
|
211
|
-
const end = () => {
|
|
212
|
-
press.current = null;
|
|
213
|
-
setGhost(null);
|
|
214
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().setDragging(null);
|
|
215
|
-
};
|
|
216
|
-
return {
|
|
217
|
-
ghost,
|
|
218
|
-
handlers: {
|
|
219
|
-
onPointerDown: (event) => {
|
|
220
|
-
if (event.button !== 0) return;
|
|
221
|
-
press.current = { x: event.clientX, y: event.clientY, dragging: false };
|
|
222
|
-
},
|
|
223
|
-
onPointerMove: (event) => {
|
|
224
|
-
const p = press.current;
|
|
225
|
-
if (!p) return;
|
|
226
|
-
if (!p.dragging) {
|
|
227
|
-
if (Math.hypot(event.clientX - p.x, event.clientY - p.y) < DRAG_THRESHOLD) return;
|
|
228
|
-
p.dragging = true;
|
|
229
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
230
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().setDragging(clipId);
|
|
231
|
-
}
|
|
232
|
-
event.preventDefault();
|
|
233
|
-
setGhost({ x: event.clientX, y: event.clientY });
|
|
234
|
-
},
|
|
235
|
-
onPointerUp: (event) => {
|
|
236
|
-
const p = press.current;
|
|
237
|
-
if (p?.dragging)
|
|
238
|
-
dropAt(event.currentTarget.ownerDocument, clipId, event.clientX, event.clientY);
|
|
239
|
-
else if (p) onTap();
|
|
240
|
-
end();
|
|
241
|
-
},
|
|
242
|
-
onPointerCancel: end
|
|
243
|
-
}
|
|
244
|
-
};
|
|
245
|
-
}
|
|
246
24
|
var TILE_HEIGHT = 72;
|
|
247
25
|
var TILE_WIDTH = { min: 56, max: 168 };
|
|
248
26
|
function tileSize(aspect, height = TILE_HEIGHT) {
|
|
@@ -252,7 +30,7 @@ function tileSize(aspect, height = TILE_HEIGHT) {
|
|
|
252
30
|
function Fitted({ clip, box: box2 }) {
|
|
253
31
|
const wide = clip.aspect > box2.width / box2.height;
|
|
254
32
|
const size = wide ? { width: box2.width, height: box2.width / clip.aspect } : { width: box2.height * clip.aspect, height: box2.height };
|
|
255
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none", style: size, children: /* @__PURE__ */ jsxRuntime.jsx(ClipImage, { clip }) });
|
|
33
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none", style: size, children: /* @__PURE__ */ jsxRuntime.jsx(chunkJY7UUZQG_cjs.ClipImage, { clip }) });
|
|
256
34
|
}
|
|
257
35
|
function Label({ clip }) {
|
|
258
36
|
const [editing, setEditing] = react.useState(false);
|
|
@@ -265,7 +43,7 @@ function Label({ clip }) {
|
|
|
265
43
|
"aria-label": "Clip label",
|
|
266
44
|
className: "w-full rounded border border-input bg-background px-1 text-[11px] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
267
45
|
onBlur: (event) => {
|
|
268
|
-
|
|
46
|
+
chunkORNLCBNE_cjs.usePresentation.getState().setCaption(clip.id, event.target.value);
|
|
269
47
|
setEditing(false);
|
|
270
48
|
},
|
|
271
49
|
onKeyDown: (event) => {
|
|
@@ -287,8 +65,8 @@ function Label({ clip }) {
|
|
|
287
65
|
);
|
|
288
66
|
}
|
|
289
67
|
function TrayTile({ clip, onSlide }) {
|
|
290
|
-
const { place, removeClip } =
|
|
291
|
-
const drag = useClipDrag(clip.id, () => !onSlide && place(clip.id));
|
|
68
|
+
const { place, removeClip } = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
69
|
+
const drag = chunkJY7UUZQG_cjs.useClipDrag(clip.id, () => !onSlide && place(clip.id));
|
|
292
70
|
const itemRef = react.useRef(null);
|
|
293
71
|
const size = tileSize(clip.aspect);
|
|
294
72
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -354,9 +132,9 @@ function TrayTile({ clip, onSlide }) {
|
|
|
354
132
|
);
|
|
355
133
|
}
|
|
356
134
|
function ClipTray({ start }) {
|
|
357
|
-
const all =
|
|
135
|
+
const all = chunkORNLCBNE_cjs.usePresentation((s) => s.clips);
|
|
358
136
|
const clips = react.useMemo(() => all.filter((clip) => !clip.plain), [all]);
|
|
359
|
-
const slide =
|
|
137
|
+
const slide = chunkORNLCBNE_cjs.usePresentation(chunkORNLCBNE_cjs.currentSlide);
|
|
360
138
|
const onSlide = new Set(slide?.items.map((item) => item.clipId));
|
|
361
139
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "shrink-0 border-t border-border bg-background", "data-testid": "clip-tray-bar", children: clips.length || start ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
362
140
|
"ul",
|
|
@@ -411,7 +189,7 @@ function CustomColor({
|
|
|
411
189
|
"input",
|
|
412
190
|
{
|
|
413
191
|
type: "color",
|
|
414
|
-
value:
|
|
192
|
+
value: chunkORNLCBNE_cjs.isHexColor(value) ? value : "#1f2937",
|
|
415
193
|
onChange: (event) => onChange(event.target.value),
|
|
416
194
|
"aria-label": label,
|
|
417
195
|
className: "absolute inset-0 cursor-pointer opacity-0"
|
|
@@ -422,10 +200,10 @@ function CustomColor({
|
|
|
422
200
|
);
|
|
423
201
|
}
|
|
424
202
|
function DesignMenu({ onChooseLogo }) {
|
|
425
|
-
const theme =
|
|
426
|
-
const setTheme =
|
|
427
|
-
const customBackground =
|
|
428
|
-
const customAccent = !
|
|
203
|
+
const theme = chunkORNLCBNE_cjs.usePresentation((s) => s.theme);
|
|
204
|
+
const setTheme = chunkORNLCBNE_cjs.usePresentation((s) => s.setTheme);
|
|
205
|
+
const customBackground = chunkORNLCBNE_cjs.isHexColor(theme.background);
|
|
206
|
+
const customAccent = !chunkORNLCBNE_cjs.ACCENTS.some((accent) => accent.color === theme.accent);
|
|
429
207
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
|
|
430
208
|
/* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
431
209
|
ui.Button,
|
|
@@ -442,7 +220,7 @@ function DesignMenu({ onChooseLogo }) {
|
|
|
442
220
|
) }),
|
|
443
221
|
/* @__PURE__ */ jsxRuntime.jsxs(ui.PopoverContent, { align: "end", className: "flex w-[21.5rem] flex-col gap-4 overflow-x-hidden p-4", children: [
|
|
444
222
|
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Background", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-7 gap-2", children: [
|
|
445
|
-
|
|
223
|
+
chunkORNLCBNE_cjs.BACKGROUNDS.map((preset) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
446
224
|
"button",
|
|
447
225
|
{
|
|
448
226
|
type: "button",
|
|
@@ -454,7 +232,7 @@ function DesignMenu({ onChooseLogo }) {
|
|
|
454
232
|
"size-8 rounded-md border border-border shadow-sm",
|
|
455
233
|
theme.background === preset.id && "ring-2 ring-primary ring-offset-1 ring-offset-background"
|
|
456
234
|
),
|
|
457
|
-
style: { background:
|
|
235
|
+
style: { background: chunkORNLCBNE_cjs.backgroundCss(preset.id), containerType: "inline-size" },
|
|
458
236
|
"data-testid": `design-background-${preset.id}`
|
|
459
237
|
},
|
|
460
238
|
preset.id
|
|
@@ -469,7 +247,7 @@ function DesignMenu({ onChooseLogo }) {
|
|
|
469
247
|
}
|
|
470
248
|
)
|
|
471
249
|
] }) }),
|
|
472
|
-
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Typeface", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: Object.keys(
|
|
250
|
+
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Typeface", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-3 gap-2", children: Object.keys(chunkORNLCBNE_cjs.FONTS).map((font) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
473
251
|
"button",
|
|
474
252
|
{
|
|
475
253
|
type: "button",
|
|
@@ -481,14 +259,14 @@ function DesignMenu({ onChooseLogo }) {
|
|
|
481
259
|
),
|
|
482
260
|
"data-testid": `design-font-${font}`,
|
|
483
261
|
children: [
|
|
484
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xl leading-tight", style: { fontFamily:
|
|
485
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-muted-foreground", children:
|
|
262
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xl leading-tight", style: { fontFamily: chunkORNLCBNE_cjs.FONTS[font].css }, children: "Aa" }),
|
|
263
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] text-muted-foreground", children: chunkORNLCBNE_cjs.FONTS[font].label })
|
|
486
264
|
]
|
|
487
265
|
},
|
|
488
266
|
font
|
|
489
267
|
)) }) }),
|
|
490
268
|
/* @__PURE__ */ jsxRuntime.jsx(Section, { title: "Accent", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2", children: [
|
|
491
|
-
|
|
269
|
+
chunkORNLCBNE_cjs.ACCENTS.map((accent) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
492
270
|
"button",
|
|
493
271
|
{
|
|
494
272
|
type: "button",
|
|
@@ -500,7 +278,7 @@ function DesignMenu({ onChooseLogo }) {
|
|
|
500
278
|
"flex size-8 items-center justify-center rounded-full border border-black/10 shadow-sm",
|
|
501
279
|
theme.accent === accent.color && "ring-2 ring-primary ring-offset-1 ring-offset-background"
|
|
502
280
|
),
|
|
503
|
-
style: { background:
|
|
281
|
+
style: { background: chunkORNLCBNE_cjs.accentColor(accent.color) },
|
|
504
282
|
children: theme.accent === accent.color && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "size-3.5 text-black/70" })
|
|
505
283
|
},
|
|
506
284
|
accent.color
|
|
@@ -508,7 +286,7 @@ function DesignMenu({ onChooseLogo }) {
|
|
|
508
286
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
509
287
|
CustomColor,
|
|
510
288
|
{
|
|
511
|
-
value:
|
|
289
|
+
value: chunkORNLCBNE_cjs.accentColor(theme.accent),
|
|
512
290
|
selected: customAccent,
|
|
513
291
|
label: "Your own accent colour",
|
|
514
292
|
round: true,
|
|
@@ -571,13 +349,13 @@ var at = (box2) => ({
|
|
|
571
349
|
height: `${box2.h * 100}%`
|
|
572
350
|
});
|
|
573
351
|
function LayoutThumb({ layout, className }) {
|
|
574
|
-
const geometry =
|
|
352
|
+
const geometry = chunkORNLCBNE_cjs.slideGeometry({ layout, caption: "Title" }, { labels: false, logo: null });
|
|
575
353
|
const { top, right = 0, bottom = 0, columns } = geometry.reserve;
|
|
576
354
|
const room = {
|
|
577
|
-
x:
|
|
578
|
-
y:
|
|
579
|
-
w: 1 - 2 *
|
|
580
|
-
h: 1 - 2 *
|
|
355
|
+
x: chunkORNLCBNE_cjs.STAGE_MARGIN,
|
|
356
|
+
y: chunkORNLCBNE_cjs.STAGE_MARGIN + top,
|
|
357
|
+
w: 1 - 2 * chunkORNLCBNE_cjs.STAGE_MARGIN - right,
|
|
358
|
+
h: 1 - 2 * chunkORNLCBNE_cjs.STAGE_MARGIN - top - bottom
|
|
581
359
|
};
|
|
582
360
|
const blocks = layout === "title" || layout === "section" || layout === "free" ? [] : columns === 2 ? [
|
|
583
361
|
{ ...room, w: room.w / 2 - 0.02 },
|
|
@@ -628,10 +406,10 @@ function LayoutMenu({
|
|
|
628
406
|
className,
|
|
629
407
|
compact = false
|
|
630
408
|
}) {
|
|
631
|
-
const layout =
|
|
632
|
-
(s) => (index === void 0 ?
|
|
409
|
+
const layout = chunkORNLCBNE_cjs.usePresentation(
|
|
410
|
+
(s) => (index === void 0 ? chunkORNLCBNE_cjs.currentSlide(s) : s.slides[index])?.layout ?? "clips"
|
|
633
411
|
);
|
|
634
|
-
const setSlideLayout =
|
|
412
|
+
const setSlideLayout = chunkORNLCBNE_cjs.usePresentation((s) => s.setSlideLayout);
|
|
635
413
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
636
414
|
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
637
415
|
ui.Button,
|
|
@@ -644,7 +422,7 @@ function LayoutMenu({
|
|
|
644
422
|
className
|
|
645
423
|
),
|
|
646
424
|
title: "Slide layout",
|
|
647
|
-
"aria-label": `Slide layout: ${
|
|
425
|
+
"aria-label": `Slide layout: ${chunkORNLCBNE_cjs.LAYOUT_INFO[layout].label}`,
|
|
648
426
|
"data-testid": "presentation-layout",
|
|
649
427
|
children: [
|
|
650
428
|
/* @__PURE__ */ jsxRuntime.jsx(LayoutThumb, { layout, className: compact ? "w-6" : "w-7" }),
|
|
@@ -652,7 +430,7 @@ function LayoutMenu({
|
|
|
652
430
|
]
|
|
653
431
|
}
|
|
654
432
|
) }),
|
|
655
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", className: "w-56", children:
|
|
433
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", className: "w-56", children: chunkORNLCBNE_cjs.SLIDE_LAYOUTS.map((option) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
656
434
|
ui.DropdownMenuItem,
|
|
657
435
|
{
|
|
658
436
|
onSelect: () => setSlideLayout(option, index),
|
|
@@ -660,7 +438,7 @@ function LayoutMenu({
|
|
|
660
438
|
"data-testid": `presentation-layout-${option}`,
|
|
661
439
|
children: [
|
|
662
440
|
/* @__PURE__ */ jsxRuntime.jsx(LayoutThumb, { layout: option, className: "w-12" }),
|
|
663
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children:
|
|
441
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: chunkORNLCBNE_cjs.LAYOUT_INFO[option].label })
|
|
664
442
|
]
|
|
665
443
|
},
|
|
666
444
|
option
|
|
@@ -668,11 +446,11 @@ function LayoutMenu({
|
|
|
668
446
|
] });
|
|
669
447
|
}
|
|
670
448
|
function Notice() {
|
|
671
|
-
const notice =
|
|
449
|
+
const notice = chunkORNLCBNE_cjs.usePresentation((s) => s.notice);
|
|
672
450
|
react.useEffect(() => {
|
|
673
451
|
if (!notice) return;
|
|
674
452
|
const timer = setTimeout(
|
|
675
|
-
() =>
|
|
453
|
+
() => chunkORNLCBNE_cjs.usePresentation.getState().clearNotice(notice.id),
|
|
676
454
|
notice.kind === "error" ? 8e3 : 3e3
|
|
677
455
|
);
|
|
678
456
|
return () => clearTimeout(timer);
|
|
@@ -693,7 +471,7 @@ function Notice() {
|
|
|
693
471
|
type: "button",
|
|
694
472
|
className: "ml-1 rounded p-0.5 text-muted-foreground hover:text-foreground",
|
|
695
473
|
"aria-label": "Dismiss",
|
|
696
|
-
onClick: () =>
|
|
474
|
+
onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().clearNotice(notice.id),
|
|
697
475
|
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "size-3.5" })
|
|
698
476
|
}
|
|
699
477
|
)
|
|
@@ -701,1235 +479,6 @@ function Notice() {
|
|
|
701
479
|
}
|
|
702
480
|
);
|
|
703
481
|
}
|
|
704
|
-
var ACTION = "inline-flex size-7 items-center justify-center rounded text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring pointer-coarse:size-11";
|
|
705
|
-
var SIZES = [
|
|
706
|
-
{ command: "fit", label: "Fit the slide", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "size-4" }) },
|
|
707
|
-
{ command: "fullWidth", label: "Full width", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoveHorizontal, { className: "size-4" }) },
|
|
708
|
-
{ command: "fullHeight", label: "Full height", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoveVertical, { className: "size-4" }) }
|
|
709
|
-
];
|
|
710
|
-
var ALIGNMENTS = [
|
|
711
|
-
{ alignment: "left", label: "Left", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignStartVertical, { className: "size-4" }) },
|
|
712
|
-
{ alignment: "centre", label: "Centre", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterVertical, { className: "size-4" }) },
|
|
713
|
-
{ alignment: "right", label: "Right", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignEndVertical, { className: "size-4" }) },
|
|
714
|
-
{ alignment: "top", label: "Top", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignStartHorizontal, { className: "size-4" }) },
|
|
715
|
-
{ alignment: "middle", label: "Middle", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterHorizontal, { className: "size-4" }) },
|
|
716
|
-
{ alignment: "bottom", label: "Bottom", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignEndHorizontal, { className: "size-4" }) }
|
|
717
|
-
];
|
|
718
|
-
function Action({
|
|
719
|
-
label,
|
|
720
|
-
onClick,
|
|
721
|
-
children
|
|
722
|
-
}) {
|
|
723
|
-
return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: ACTION, title: label, "aria-label": label, onClick, children });
|
|
724
|
-
}
|
|
725
|
-
function ClipActionBar({
|
|
726
|
-
clipId,
|
|
727
|
-
at: at2,
|
|
728
|
-
onRemoved,
|
|
729
|
-
onEditImage,
|
|
730
|
-
onCropImage
|
|
731
|
-
}) {
|
|
732
|
-
const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
733
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
734
|
-
"div",
|
|
735
|
-
{
|
|
736
|
-
role: "toolbar",
|
|
737
|
-
"aria-label": "Clip",
|
|
738
|
-
className: "absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md",
|
|
739
|
-
style: { left: `${at2.x * 100}%`, top: `calc(${at2.y * 100}% - 40px)` },
|
|
740
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
741
|
-
"data-testid": "clip-action-bar",
|
|
742
|
-
children: [
|
|
743
|
-
SIZES.map(({ command, label, icon }) => /* @__PURE__ */ jsxRuntime.jsx(Action, { label, onClick: () => actions.applyFrame(clipId, command), children: icon }, command)),
|
|
744
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
745
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: ACTION, title: "Align", "aria-label": "Align", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterHorizontal, { className: "size-4" }) }) }),
|
|
746
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", children: ALIGNMENTS.map(({ alignment, label, icon }) => /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.align(clipId, alignment), children: [
|
|
747
|
-
icon,
|
|
748
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: label })
|
|
749
|
-
] }, alignment)) })
|
|
750
|
-
] }),
|
|
751
|
-
onCropImage && /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Crop", onClick: onCropImage, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crop, { className: "size-4" }) }),
|
|
752
|
-
onEditImage && /* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Edit image", onClick: onEditImage, children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-4" }) }),
|
|
753
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
754
|
-
/* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Bring to front", onClick: () => actions.bringToFront(clipId), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BringToFront, { className: "size-4" }) }),
|
|
755
|
-
/* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Send to back", onClick: () => actions.sendToBack(clipId), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendToBack, { className: "size-4" }) }),
|
|
756
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
757
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
758
|
-
"button",
|
|
759
|
-
{
|
|
760
|
-
type: "button",
|
|
761
|
-
className: ui.cn(ACTION, "text-destructive hover:bg-destructive/10"),
|
|
762
|
-
title: "Remove from slide (Delete)",
|
|
763
|
-
"aria-label": "Remove from slide",
|
|
764
|
-
onClick: () => {
|
|
765
|
-
actions.unplace(clipId);
|
|
766
|
-
onRemoved();
|
|
767
|
-
},
|
|
768
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" })
|
|
769
|
-
}
|
|
770
|
-
)
|
|
771
|
-
]
|
|
772
|
-
}
|
|
773
|
-
);
|
|
774
|
-
}
|
|
775
|
-
var boxStyle = (box2) => ({
|
|
776
|
-
left: `${box2.x * 100}%`,
|
|
777
|
-
top: `${box2.y * 100}%`,
|
|
778
|
-
width: `${box2.w * 100}%`,
|
|
779
|
-
height: `${box2.h * 100}%`
|
|
780
|
-
});
|
|
781
|
-
var textStyle = (box2, color) => ({
|
|
782
|
-
...boxStyle(box2),
|
|
783
|
-
fontSize: `${box2.size * 100}cqw`,
|
|
784
|
-
fontWeight: box2.weight,
|
|
785
|
-
lineHeight: box2.leading,
|
|
786
|
-
color,
|
|
787
|
-
letterSpacing: box2.tone === "title" ? "-0.01em" : void 0
|
|
788
|
-
});
|
|
789
|
-
var PLACEHOLDER_COLOR = "rgba(255,255,255,0.32)";
|
|
790
|
-
function Text({
|
|
791
|
-
box: box2,
|
|
792
|
-
lines,
|
|
793
|
-
accent,
|
|
794
|
-
placeholder,
|
|
795
|
-
onEdit,
|
|
796
|
-
testId
|
|
797
|
-
}) {
|
|
798
|
-
const empty = lines.length === 0;
|
|
799
|
-
if (empty && !placeholder) return null;
|
|
800
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
801
|
-
"div",
|
|
802
|
-
{
|
|
803
|
-
className: ui.cn(
|
|
804
|
-
"absolute flex flex-col overflow-hidden",
|
|
805
|
-
onEdit ? "pointer-events-auto cursor-text rounded-[0.3cqw] hover:outline hover:outline-1 hover:outline-white/25" : "pointer-events-none",
|
|
806
|
-
box2.align === "center" && "text-center",
|
|
807
|
-
box2.bullets && "gap-[0.6cqw]",
|
|
808
|
-
box2.anchor === "middle" && "justify-center",
|
|
809
|
-
box2.anchor === "bottom" && "justify-end"
|
|
810
|
-
),
|
|
811
|
-
style: textStyle(box2, empty ? PLACEHOLDER_COLOR : chunk4TTX6ZNS_cjs.TEXT_COLORS[box2.tone]),
|
|
812
|
-
onPointerDown: onEdit ? (event) => event.stopPropagation() : void 0,
|
|
813
|
-
onClick: onEdit,
|
|
814
|
-
"data-testid": testId,
|
|
815
|
-
children: (empty ? [placeholder] : lines).map(
|
|
816
|
-
(line, index) => box2.bullets ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-[0.8em]", children: [
|
|
817
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
818
|
-
"span",
|
|
819
|
-
{
|
|
820
|
-
"aria-hidden": true,
|
|
821
|
-
className: "inline-block size-[0.42em] shrink-0 -translate-y-[0.12em]",
|
|
822
|
-
style: { background: empty ? "currentColor" : accent }
|
|
823
|
-
}
|
|
824
|
-
),
|
|
825
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: line })
|
|
826
|
-
] }, index) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: line }, index)
|
|
827
|
-
)
|
|
828
|
-
}
|
|
829
|
-
);
|
|
830
|
-
}
|
|
831
|
-
function TextField({
|
|
832
|
-
box: box2,
|
|
833
|
-
value,
|
|
834
|
-
placeholder,
|
|
835
|
-
multiline,
|
|
836
|
-
onChange,
|
|
837
|
-
onDone,
|
|
838
|
-
testId
|
|
839
|
-
}) {
|
|
840
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
841
|
-
"textarea",
|
|
842
|
-
{
|
|
843
|
-
autoFocus: true,
|
|
844
|
-
value,
|
|
845
|
-
placeholder,
|
|
846
|
-
onChange: (event) => onChange(multiline ? event.target.value : event.target.value.replace(/\n/g, " ")),
|
|
847
|
-
onBlur: onDone,
|
|
848
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
849
|
-
onKeyDown: (event) => {
|
|
850
|
-
if (event.key === "Escape" || !multiline && event.key === "Enter") {
|
|
851
|
-
event.preventDefault();
|
|
852
|
-
event.currentTarget.blur();
|
|
853
|
-
}
|
|
854
|
-
},
|
|
855
|
-
className: ui.cn(
|
|
856
|
-
"pointer-events-auto absolute resize-none overflow-hidden rounded-[0.3cqw] bg-white/5 p-0 outline outline-1 outline-white/40 placeholder:text-white/30 focus:outline-white/60",
|
|
857
|
-
box2.align === "center" && "text-center"
|
|
858
|
-
),
|
|
859
|
-
style: {
|
|
860
|
-
...textStyle(box2, chunk4TTX6ZNS_cjs.TEXT_COLORS[box2.tone]),
|
|
861
|
-
fontFamily: "inherit",
|
|
862
|
-
// Bulleted lines keep their indent while typed.
|
|
863
|
-
paddingLeft: box2.bullets ? "1.22em" : void 0
|
|
864
|
-
},
|
|
865
|
-
"aria-label": placeholder,
|
|
866
|
-
"data-testid": testId
|
|
867
|
-
}
|
|
868
|
-
);
|
|
869
|
-
}
|
|
870
|
-
function Logo({ image, box: box2 }) {
|
|
871
|
-
const url = chunkWOOOMTTA_cjs.useObjectUrl(image);
|
|
872
|
-
if (!url) return null;
|
|
873
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
874
|
-
"img",
|
|
875
|
-
{
|
|
876
|
-
src: url,
|
|
877
|
-
alt: "",
|
|
878
|
-
className: "pointer-events-none absolute object-contain opacity-90",
|
|
879
|
-
style: { ...boxStyle(box2), objectPosition: box2.x < 0.5 ? "left bottom" : "right bottom" },
|
|
880
|
-
"data-testid": "stage-logo"
|
|
881
|
-
}
|
|
882
|
-
);
|
|
883
|
-
}
|
|
884
|
-
var SlideDecor = react.memo(function SlideDecor2({
|
|
885
|
-
slide,
|
|
886
|
-
theme,
|
|
887
|
-
labels,
|
|
888
|
-
logoImage,
|
|
889
|
-
editable,
|
|
890
|
-
editing,
|
|
891
|
-
dim
|
|
892
|
-
}) {
|
|
893
|
-
const [typing, setTyping] = react.useState(null);
|
|
894
|
-
const geometry = chunk4TTX6ZNS_cjs.slideGeometry(slide, { labels, logo: theme.logo?.corner ?? null });
|
|
895
|
-
const title = slide.caption.trim();
|
|
896
|
-
const titled = slide.layout === "title" || slide.layout === "section";
|
|
897
|
-
const info = chunk4TTX6ZNS_cjs.LAYOUT_INFO[slide.layout];
|
|
898
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("pointer-events-none absolute inset-0", dim && "opacity-30"), children: [
|
|
899
|
-
!geometry.title ? null : editing && typing === "title" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
900
|
-
TextField,
|
|
901
|
-
{
|
|
902
|
-
box: geometry.title,
|
|
903
|
-
value: slide.caption,
|
|
904
|
-
placeholder: "Title",
|
|
905
|
-
multiline: false,
|
|
906
|
-
onChange: editing.onTitle,
|
|
907
|
-
onDone: () => setTyping(null),
|
|
908
|
-
testId: "stage-slide-caption-input"
|
|
909
|
-
}
|
|
910
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
911
|
-
Text,
|
|
912
|
-
{
|
|
913
|
-
box: geometry.title,
|
|
914
|
-
lines: title ? [title] : [],
|
|
915
|
-
accent: chunk4TTX6ZNS_cjs.accentColor(theme.accent),
|
|
916
|
-
placeholder: editable && (titled || editing) ? "Click to add a title" : void 0,
|
|
917
|
-
onEdit: editing ? () => setTyping("title") : void 0,
|
|
918
|
-
testId: "stage-slide-caption"
|
|
919
|
-
}
|
|
920
|
-
),
|
|
921
|
-
geometry.rule && (title || editable && titled) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
922
|
-
"div",
|
|
923
|
-
{
|
|
924
|
-
className: "absolute",
|
|
925
|
-
style: { ...boxStyle(geometry.rule), background: chunk4TTX6ZNS_cjs.accentColor(theme.accent) }
|
|
926
|
-
}
|
|
927
|
-
),
|
|
928
|
-
geometry.text && (editing && typing === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
929
|
-
TextField,
|
|
930
|
-
{
|
|
931
|
-
box: geometry.text,
|
|
932
|
-
value: slide.points,
|
|
933
|
-
placeholder: info.text ?? "",
|
|
934
|
-
multiline: true,
|
|
935
|
-
onChange: editing.onPoints,
|
|
936
|
-
onDone: () => setTyping(null),
|
|
937
|
-
testId: "stage-slide-points-input"
|
|
938
|
-
}
|
|
939
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
940
|
-
Text,
|
|
941
|
-
{
|
|
942
|
-
box: geometry.text,
|
|
943
|
-
lines: chunk4TTX6ZNS_cjs.textLines(slide.points),
|
|
944
|
-
accent: chunk4TTX6ZNS_cjs.accentColor(theme.accent),
|
|
945
|
-
placeholder: editable ? info.text : void 0,
|
|
946
|
-
onEdit: editing ? () => setTyping("text") : void 0,
|
|
947
|
-
testId: "stage-slide-points"
|
|
948
|
-
}
|
|
949
|
-
)),
|
|
950
|
-
geometry.logo && logoImage && /* @__PURE__ */ jsxRuntime.jsx(Logo, { image: logoImage, box: geometry.logo })
|
|
951
|
-
] });
|
|
952
|
-
});
|
|
953
|
-
var PAN_STEP = 0.1;
|
|
954
|
-
var MAX_ZOOM = 800;
|
|
955
|
-
var HOLD_DELAY = 350;
|
|
956
|
-
var HOLD_EVERY = 90;
|
|
957
|
-
var BUTTON = "pointer-events-auto flex size-7 items-center justify-center rounded-full border border-border bg-background/90 text-foreground shadow-sm backdrop-blur-sm hover:bg-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-30 pointer-coarse:size-11";
|
|
958
|
-
function HoldButton({
|
|
959
|
-
label,
|
|
960
|
-
disabled,
|
|
961
|
-
onStep,
|
|
962
|
-
className,
|
|
963
|
-
children
|
|
964
|
-
}) {
|
|
965
|
-
const timer = react.useRef(null);
|
|
966
|
-
const stop = () => {
|
|
967
|
-
if (timer.current) clearTimeout(timer.current);
|
|
968
|
-
timer.current = null;
|
|
969
|
-
};
|
|
970
|
-
react.useEffect(() => stop, []);
|
|
971
|
-
react.useEffect(() => {
|
|
972
|
-
if (disabled) stop();
|
|
973
|
-
}, [disabled]);
|
|
974
|
-
const start = (event) => {
|
|
975
|
-
event.stopPropagation();
|
|
976
|
-
if (disabled || event.button !== 0) return;
|
|
977
|
-
onStep();
|
|
978
|
-
const repeat = () => {
|
|
979
|
-
onStep();
|
|
980
|
-
timer.current = setTimeout(repeat, HOLD_EVERY);
|
|
981
|
-
};
|
|
982
|
-
timer.current = setTimeout(repeat, HOLD_DELAY);
|
|
983
|
-
};
|
|
984
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
985
|
-
"button",
|
|
986
|
-
{
|
|
987
|
-
type: "button",
|
|
988
|
-
className: ui.cn(BUTTON, className),
|
|
989
|
-
title: label,
|
|
990
|
-
"aria-label": label,
|
|
991
|
-
disabled,
|
|
992
|
-
onPointerDown: start,
|
|
993
|
-
onPointerUp: stop,
|
|
994
|
-
onPointerLeave: stop,
|
|
995
|
-
onPointerCancel: stop,
|
|
996
|
-
onClick: (event) => event.detail === 0 && onStep(),
|
|
997
|
-
children
|
|
998
|
-
}
|
|
999
|
-
);
|
|
1000
|
-
}
|
|
1001
|
-
function ClipViewControls({ clip }) {
|
|
1002
|
-
const { panClip, setClipZoom } = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
1003
|
-
const { rect } = clip;
|
|
1004
|
-
const zoomBase = clip.zoomBase ?? rect.w;
|
|
1005
|
-
const minZoom = Math.min(100, Math.floor(zoomBase / Math.min(1, rect.w / rect.h) * 100));
|
|
1006
|
-
const pan = (dx, dy) => () => panClip(clip.id, dx * rect.w, dy * rect.h);
|
|
1007
|
-
const zoom = Math.round(zoomBase / rect.w * 100);
|
|
1008
|
-
const edge = 1e-6;
|
|
1009
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1010
|
-
"div",
|
|
1011
|
-
{
|
|
1012
|
-
className: "pointer-events-none absolute inset-0 z-10",
|
|
1013
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
1014
|
-
"data-testid": "clip-view-controls",
|
|
1015
|
-
children: [
|
|
1016
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1017
|
-
HoldButton,
|
|
1018
|
-
{
|
|
1019
|
-
label: "Show more above",
|
|
1020
|
-
disabled: rect.y <= edge,
|
|
1021
|
-
onStep: pan(0, -PAN_STEP),
|
|
1022
|
-
className: "absolute left-1/2 top-4 -translate-x-1/2 pointer-coarse:top-7",
|
|
1023
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-4" })
|
|
1024
|
-
}
|
|
1025
|
-
),
|
|
1026
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1027
|
-
HoldButton,
|
|
1028
|
-
{
|
|
1029
|
-
label: "Show more below",
|
|
1030
|
-
disabled: rect.y + rect.h >= 1 - edge,
|
|
1031
|
-
onStep: pan(0, PAN_STEP),
|
|
1032
|
-
className: "absolute bottom-10 left-1/2 -translate-x-1/2 pointer-coarse:bottom-14",
|
|
1033
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" })
|
|
1034
|
-
}
|
|
1035
|
-
),
|
|
1036
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1037
|
-
HoldButton,
|
|
1038
|
-
{
|
|
1039
|
-
label: "Show more on the left",
|
|
1040
|
-
disabled: rect.x <= edge,
|
|
1041
|
-
onStep: pan(-PAN_STEP, 0),
|
|
1042
|
-
className: "absolute left-4 top-1/2 -translate-y-1/2 pointer-coarse:left-7",
|
|
1043
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "size-4" })
|
|
1044
|
-
}
|
|
1045
|
-
),
|
|
1046
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1047
|
-
HoldButton,
|
|
1048
|
-
{
|
|
1049
|
-
label: "Show more on the right",
|
|
1050
|
-
disabled: rect.x + rect.w >= 1 - edge,
|
|
1051
|
-
onStep: pan(PAN_STEP, 0),
|
|
1052
|
-
className: "absolute right-4 top-1/2 -translate-y-1/2 pointer-coarse:right-7",
|
|
1053
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" })
|
|
1054
|
-
}
|
|
1055
|
-
),
|
|
1056
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1057
|
-
"div",
|
|
1058
|
-
{
|
|
1059
|
-
className: "pointer-events-auto absolute bottom-1.5 left-1/2 -translate-x-1/2",
|
|
1060
|
-
"data-testid": "clip-zoom-control",
|
|
1061
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1062
|
-
chunk5GCCUXMT_cjs.ZoomSlider,
|
|
1063
|
-
{
|
|
1064
|
-
value: zoom,
|
|
1065
|
-
min: minZoom,
|
|
1066
|
-
max: Math.max(MAX_ZOOM, zoom),
|
|
1067
|
-
zoomOutStep: 25,
|
|
1068
|
-
onChange: (value) => setClipZoom(clip.id, value),
|
|
1069
|
-
label: "Zoom",
|
|
1070
|
-
valueLabel: /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-testid": "clip-zoom", children: [
|
|
1071
|
-
zoom,
|
|
1072
|
-
"%"
|
|
1073
|
-
] }),
|
|
1074
|
-
className: "bg-background/95 shadow-sm backdrop-blur-sm pointer-coarse:h-11",
|
|
1075
|
-
sliderClassName: "w-24"
|
|
1076
|
-
}
|
|
1077
|
-
)
|
|
1078
|
-
}
|
|
1079
|
-
)
|
|
1080
|
-
]
|
|
1081
|
-
}
|
|
1082
|
-
);
|
|
1083
|
-
}
|
|
1084
|
-
var isEdge = (kind) => kind === "n" || kind === "e" || kind === "s" || kind === "w";
|
|
1085
|
-
var EDGES = [
|
|
1086
|
-
{ edge: "n", left: "50%", top: "0%", cursor: "ns-resize", label: "top" },
|
|
1087
|
-
{ edge: "e", left: "100%", top: "50%", cursor: "ew-resize", label: "right" },
|
|
1088
|
-
{ edge: "s", left: "50%", top: "100%", cursor: "ns-resize", label: "bottom" },
|
|
1089
|
-
{ edge: "w", left: "0%", top: "50%", cursor: "ew-resize", label: "left" }
|
|
1090
|
-
];
|
|
1091
|
-
var CORNERS = [
|
|
1092
|
-
{ corner: "nw", left: "0%", top: "0%", cursor: "nwse-resize" },
|
|
1093
|
-
{ corner: "ne", left: "100%", top: "0%", cursor: "nesw-resize" },
|
|
1094
|
-
{ corner: "sw", left: "0%", top: "100%", cursor: "nesw-resize" },
|
|
1095
|
-
{ corner: "se", left: "100%", top: "100%", cursor: "nwse-resize" }
|
|
1096
|
-
];
|
|
1097
|
-
var EDGE_CSS = chunk4TTX6ZNS_cjs.clipEdgeCss();
|
|
1098
|
-
var StageItem = react.memo(function StageItem2({
|
|
1099
|
-
clip,
|
|
1100
|
-
frame,
|
|
1101
|
-
editable,
|
|
1102
|
-
selected,
|
|
1103
|
-
dim,
|
|
1104
|
-
label,
|
|
1105
|
-
host
|
|
1106
|
-
}) {
|
|
1107
|
-
const element = react.useRef(null);
|
|
1108
|
-
const gesture = react.useRef(null);
|
|
1109
|
-
const [dragging, setDragging] = react.useState(false);
|
|
1110
|
-
const [reshape, setReshape] = react.useState(null);
|
|
1111
|
-
const shown = reshape ? { ...clip, ...reshape.shape } : clip;
|
|
1112
|
-
const box2 = reshape?.frame ?? frame;
|
|
1113
|
-
const view = () => element.current?.ownerDocument.defaultView ?? window;
|
|
1114
|
-
const apply = () => {
|
|
1115
|
-
const g = gesture.current;
|
|
1116
|
-
const el = element.current;
|
|
1117
|
-
if (!g) return;
|
|
1118
|
-
g.request = null;
|
|
1119
|
-
const next = g.next;
|
|
1120
|
-
if (!next || !el) return;
|
|
1121
|
-
if (next.shape) {
|
|
1122
|
-
setReshape({ frame: next.frame, shape: next.shape });
|
|
1123
|
-
} else {
|
|
1124
|
-
const dx = (next.frame.x - g.frame.x) * g.stage.width;
|
|
1125
|
-
const dy = (next.frame.y - g.frame.y) * g.stage.height;
|
|
1126
|
-
const scale = next.frame.w / g.frame.w;
|
|
1127
|
-
el.style.transform = `translate3d(${dx}px, ${dy}px, 0) scale(${scale})`;
|
|
1128
|
-
}
|
|
1129
|
-
const key = next.guides.map((guide) => `${guide.axis}${guide.at}`).join();
|
|
1130
|
-
if (key !== g.guidesKey) {
|
|
1131
|
-
g.guidesKey = key;
|
|
1132
|
-
host.guides(next.guides);
|
|
1133
|
-
}
|
|
1134
|
-
};
|
|
1135
|
-
const start = (event, kind) => {
|
|
1136
|
-
if (!editable || event.button !== 0) return;
|
|
1137
|
-
const stage = host.stageBox();
|
|
1138
|
-
if (!stage) return;
|
|
1139
|
-
event.preventDefault();
|
|
1140
|
-
event.stopPropagation();
|
|
1141
|
-
host.select(clip.id);
|
|
1142
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1143
|
-
gesture.current = {
|
|
1144
|
-
kind,
|
|
1145
|
-
pointer: { x: event.clientX, y: event.clientY },
|
|
1146
|
-
frame,
|
|
1147
|
-
shape: { rect: clip.rect, aspect: clip.aspect },
|
|
1148
|
-
stage,
|
|
1149
|
-
others: host.others(clip.id),
|
|
1150
|
-
next: null,
|
|
1151
|
-
request: null,
|
|
1152
|
-
guidesKey: ""
|
|
1153
|
-
};
|
|
1154
|
-
};
|
|
1155
|
-
const move = (event) => {
|
|
1156
|
-
const g = gesture.current;
|
|
1157
|
-
if (!g) return;
|
|
1158
|
-
if (!g.next) {
|
|
1159
|
-
setDragging(true);
|
|
1160
|
-
host.dragging(true);
|
|
1161
|
-
if (element.current) element.current.style.willChange = "transform";
|
|
1162
|
-
}
|
|
1163
|
-
const dx = (event.clientX - g.pointer.x) / g.stage.width;
|
|
1164
|
-
const dy = (event.clientY - g.pointer.y) / g.stage.height;
|
|
1165
|
-
const free = event.altKey;
|
|
1166
|
-
if (isEdge(g.kind)) {
|
|
1167
|
-
const result = chunk4TTX6ZNS_cjs.reshapeFrame(g.frame, g.shape, g.kind, dx, dy, g.others, free);
|
|
1168
|
-
g.next = {
|
|
1169
|
-
frame: result.frame,
|
|
1170
|
-
shape: { rect: result.rect, aspect: result.aspect },
|
|
1171
|
-
guides: result.guides
|
|
1172
|
-
};
|
|
1173
|
-
} else {
|
|
1174
|
-
g.next = g.kind === "move" ? chunk4TTX6ZNS_cjs.moveFrame(g.frame, g.shape.aspect, dx, dy, g.others, free) : chunk4TTX6ZNS_cjs.resizeFrame(g.frame, g.shape.aspect, g.kind, dx, dy, g.others, free);
|
|
1175
|
-
}
|
|
1176
|
-
g.request ??= view().requestAnimationFrame(apply);
|
|
1177
|
-
};
|
|
1178
|
-
const end = () => {
|
|
1179
|
-
const g = gesture.current;
|
|
1180
|
-
gesture.current = null;
|
|
1181
|
-
if (!g) return;
|
|
1182
|
-
if (g.request !== null) view().cancelAnimationFrame(g.request);
|
|
1183
|
-
const el = element.current;
|
|
1184
|
-
if (el) {
|
|
1185
|
-
el.style.transform = "";
|
|
1186
|
-
el.style.willChange = "";
|
|
1187
|
-
}
|
|
1188
|
-
if (!g.next) return;
|
|
1189
|
-
setReshape(null);
|
|
1190
|
-
setDragging(false);
|
|
1191
|
-
host.dragging(false);
|
|
1192
|
-
host.guides([]);
|
|
1193
|
-
host.commit(clip.id, g.next.frame, g.next.shape);
|
|
1194
|
-
};
|
|
1195
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1196
|
-
"div",
|
|
1197
|
-
{
|
|
1198
|
-
ref: element,
|
|
1199
|
-
className: ui.cn(
|
|
1200
|
-
"absolute origin-top-left",
|
|
1201
|
-
// Lifted off the background (a picture that is part of the slide's design is not).
|
|
1202
|
-
!clip.plain && "rounded-[0.6cqw] shadow-[0_0.5cqw_1.6cqw_rgba(0,0,0,0.5)]",
|
|
1203
|
-
editable && "cursor-move touch-none",
|
|
1204
|
-
selected && "outline outline-2 outline-offset-2 outline-primary",
|
|
1205
|
-
dim && "opacity-30"
|
|
1206
|
-
),
|
|
1207
|
-
style: {
|
|
1208
|
-
left: `${box2.x * 100}%`,
|
|
1209
|
-
top: `${box2.y * 100}%`,
|
|
1210
|
-
width: `${box2.w * 100}%`,
|
|
1211
|
-
height: `${chunk4TTX6ZNS_cjs.frameHeight(box2, shown.aspect) * 100}%`
|
|
1212
|
-
},
|
|
1213
|
-
onPointerDown: (event) => start(event, "move"),
|
|
1214
|
-
onPointerMove: move,
|
|
1215
|
-
onPointerUp: end,
|
|
1216
|
-
onPointerCancel: end,
|
|
1217
|
-
"data-testid": `stage-item-${clip.id}`,
|
|
1218
|
-
children: [
|
|
1219
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("absolute inset-0 overflow-hidden", !clip.plain && "rounded-[0.6cqw]"), children: [
|
|
1220
|
-
/* @__PURE__ */ jsxRuntime.jsx(ClipImage, { clip: shown, live: !editable }),
|
|
1221
|
-
clip.kind === "pdf" && !clip.plain && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1222
|
-
"div",
|
|
1223
|
-
{
|
|
1224
|
-
className: "pointer-events-none absolute inset-0",
|
|
1225
|
-
style: { background: EDGE_CSS },
|
|
1226
|
-
"data-testid": "stage-clip-edge"
|
|
1227
|
-
}
|
|
1228
|
-
),
|
|
1229
|
-
!clip.plain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0 rounded-[0.6cqw] ring-1 ring-inset ring-white/15" })
|
|
1230
|
-
] }),
|
|
1231
|
-
label && !clip.plain && // Under the clip, in the room the layout keeps (CAPTION_SPACE): never over it.
|
|
1232
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1233
|
-
"div",
|
|
1234
|
-
{
|
|
1235
|
-
className: "pointer-events-none absolute left-0 top-full mt-[0.5cqw] max-w-full truncate text-[1.7cqw] leading-tight",
|
|
1236
|
-
style: { color: chunk4TTX6ZNS_cjs.TEXT_COLORS.muted },
|
|
1237
|
-
children: label
|
|
1238
|
-
}
|
|
1239
|
-
),
|
|
1240
|
-
selected && !dragging && /* @__PURE__ */ jsxRuntime.jsx(ClipViewControls, { clip }),
|
|
1241
|
-
selected && CORNERS.map(({ corner, left, top, cursor }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1242
|
-
"div",
|
|
1243
|
-
{
|
|
1244
|
-
className: "absolute flex size-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
|
|
1245
|
-
style: { left, top, cursor, touchAction: "none" },
|
|
1246
|
-
onPointerDown: (event) => start(event, corner),
|
|
1247
|
-
"aria-label": `Resize from the ${corner} corner`,
|
|
1248
|
-
"data-testid": `stage-item-resize-${corner}`,
|
|
1249
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none size-3 rounded-full border-2 border-primary bg-background" })
|
|
1250
|
-
},
|
|
1251
|
-
corner
|
|
1252
|
-
)),
|
|
1253
|
-
selected && EDGES.map(({ edge, left, top, cursor, label: side }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1254
|
-
"div",
|
|
1255
|
-
{
|
|
1256
|
-
className: "absolute flex size-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
|
|
1257
|
-
style: { left, top, cursor, touchAction: "none" },
|
|
1258
|
-
onPointerDown: (event) => start(event, edge),
|
|
1259
|
-
"aria-label": `Show more or less at the ${side}`,
|
|
1260
|
-
title: "Drag to show more or less of the page",
|
|
1261
|
-
"data-testid": `stage-item-reshape-${edge}`,
|
|
1262
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1263
|
-
"span",
|
|
1264
|
-
{
|
|
1265
|
-
className: ui.cn(
|
|
1266
|
-
"pointer-events-none rounded-full border-2 border-primary bg-background",
|
|
1267
|
-
edge === "n" || edge === "s" ? "h-2 w-4" : "h-4 w-2"
|
|
1268
|
-
)
|
|
1269
|
-
}
|
|
1270
|
-
)
|
|
1271
|
-
},
|
|
1272
|
-
edge
|
|
1273
|
-
))
|
|
1274
|
-
]
|
|
1275
|
-
}
|
|
1276
|
-
);
|
|
1277
|
-
});
|
|
1278
|
-
|
|
1279
|
-
// src/presentation/box-style.ts
|
|
1280
|
-
var cqw = (points) => `${chunk4TTX6ZNS_cjs.pointsToStage(points) * 100}cqw`;
|
|
1281
|
-
function runStyle(run, font) {
|
|
1282
|
-
return {
|
|
1283
|
-
fontSize: cqw(run.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE),
|
|
1284
|
-
fontWeight: run.bold ? 700 : 400,
|
|
1285
|
-
fontStyle: run.italic ? "italic" : void 0,
|
|
1286
|
-
textDecoration: run.underline ? "underline" : void 0,
|
|
1287
|
-
color: run.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
|
|
1288
|
-
fontFamily: run.font ? `"${run.font}", ${font}` : font
|
|
1289
|
-
};
|
|
1290
|
-
}
|
|
1291
|
-
var HANDLES = [
|
|
1292
|
-
{ handle: "nw", left: "0%", top: "0%", cursor: "nwse-resize" },
|
|
1293
|
-
{ handle: "n", left: "50%", top: "0%", cursor: "ns-resize" },
|
|
1294
|
-
{ handle: "ne", left: "100%", top: "0%", cursor: "nesw-resize" },
|
|
1295
|
-
{ handle: "e", left: "100%", top: "50%", cursor: "ew-resize" },
|
|
1296
|
-
{ handle: "se", left: "100%", top: "100%", cursor: "nwse-resize" },
|
|
1297
|
-
{ handle: "s", left: "50%", top: "100%", cursor: "ns-resize" },
|
|
1298
|
-
{ handle: "sw", left: "0%", top: "100%", cursor: "nesw-resize" },
|
|
1299
|
-
{ handle: "w", left: "0%", top: "50%", cursor: "ew-resize" }
|
|
1300
|
-
];
|
|
1301
|
-
var withAlpha = (hex3, alpha = 1) => {
|
|
1302
|
-
if (alpha >= 1) return hex3;
|
|
1303
|
-
const n = parseInt(hex3.slice(1), 16);
|
|
1304
|
-
return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${alpha})`;
|
|
1305
|
-
};
|
|
1306
|
-
function shapeStyle(box2) {
|
|
1307
|
-
const { frame } = box2;
|
|
1308
|
-
const line = box2.line;
|
|
1309
|
-
const shorter = Math.min(frame.w, frame.h * 1 / chunk4TTX6ZNS_cjs.STAGE_ASPECT);
|
|
1310
|
-
return {
|
|
1311
|
-
background: box2.fill && box2.shape !== "line" ? withAlpha(box2.fill, box2.fillAlpha) : void 0,
|
|
1312
|
-
border: line && box2.shape !== "line" ? `${cqw(line.width)} ${line.dash ? "dashed" : "solid"} ${line.color}` : void 0,
|
|
1313
|
-
borderRadius: box2.shape === "ellipse" ? "50%" : box2.shape === "roundRect" ? `${shorter * 16.67}cqw` : void 0
|
|
1314
|
-
};
|
|
1315
|
-
}
|
|
1316
|
-
function Paragraphs({
|
|
1317
|
-
paragraphs,
|
|
1318
|
-
font
|
|
1319
|
-
}) {
|
|
1320
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: paragraphs.map((paragraph, index) => {
|
|
1321
|
-
const first = paragraph.runs[0];
|
|
1322
|
-
const size = first?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE;
|
|
1323
|
-
const indent = (paragraph.level ?? 0) * 0.5 * size;
|
|
1324
|
-
const empty = !paragraph.runs.some((run) => run.text);
|
|
1325
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1326
|
-
"div",
|
|
1327
|
-
{
|
|
1328
|
-
className: "whitespace-pre-wrap break-words",
|
|
1329
|
-
style: {
|
|
1330
|
-
textAlign: paragraph.align ?? "left",
|
|
1331
|
-
lineHeight: 1.2,
|
|
1332
|
-
paddingLeft: cqw(indent + (paragraph.bullet ? size * 0.9 : 0)),
|
|
1333
|
-
textIndent: paragraph.bullet ? cqw(-size * 0.9) : void 0,
|
|
1334
|
-
// An empty line keeps its height.
|
|
1335
|
-
fontSize: cqw(size)
|
|
1336
|
-
},
|
|
1337
|
-
children: [
|
|
1338
|
-
paragraph.bullet && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1339
|
-
"span",
|
|
1340
|
-
{
|
|
1341
|
-
style: {
|
|
1342
|
-
...runStyle(first ?? { }, font),
|
|
1343
|
-
display: "inline-block",
|
|
1344
|
-
width: cqw(size * 0.9),
|
|
1345
|
-
textIndent: 0
|
|
1346
|
-
},
|
|
1347
|
-
children: "\u2022"
|
|
1348
|
-
}
|
|
1349
|
-
),
|
|
1350
|
-
empty ? "\u200B" : paragraph.runs.map((run, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: runStyle(run, font), children: run.text }, i))
|
|
1351
|
-
]
|
|
1352
|
-
},
|
|
1353
|
-
index
|
|
1354
|
-
);
|
|
1355
|
-
}) });
|
|
1356
|
-
}
|
|
1357
|
-
var StageBox = react.memo(function StageBox2({
|
|
1358
|
-
box: box2,
|
|
1359
|
-
font,
|
|
1360
|
-
editable,
|
|
1361
|
-
selected,
|
|
1362
|
-
host
|
|
1363
|
-
}) {
|
|
1364
|
-
const element = react.useRef(null);
|
|
1365
|
-
const gesture = react.useRef(null);
|
|
1366
|
-
const [typing, setTyping] = react.useState(false);
|
|
1367
|
-
const [dragging, setDragging] = react.useState(false);
|
|
1368
|
-
const { frame } = box2;
|
|
1369
|
-
const view = () => element.current?.ownerDocument.defaultView ?? window;
|
|
1370
|
-
const apply = () => {
|
|
1371
|
-
const g = gesture.current;
|
|
1372
|
-
const el = element.current;
|
|
1373
|
-
if (!g || !el) return;
|
|
1374
|
-
g.request = null;
|
|
1375
|
-
if (!g.next) return;
|
|
1376
|
-
if (g.handle === "move") {
|
|
1377
|
-
el.style.translate = `${(g.next.x - g.frame.x) * g.stage.width}px ${(g.next.y - g.frame.y) * g.stage.height}px`;
|
|
1378
|
-
} else {
|
|
1379
|
-
el.style.left = `${g.next.x * 100}%`;
|
|
1380
|
-
el.style.top = `${g.next.y * 100}%`;
|
|
1381
|
-
el.style.width = `${g.next.w * 100}%`;
|
|
1382
|
-
el.style.height = `${g.next.h * 100}%`;
|
|
1383
|
-
}
|
|
1384
|
-
};
|
|
1385
|
-
const start = (event, handle) => {
|
|
1386
|
-
if (!editable || typing || event.button !== 0) return;
|
|
1387
|
-
const stage = host.stageBox();
|
|
1388
|
-
if (!stage) return;
|
|
1389
|
-
event.preventDefault();
|
|
1390
|
-
event.stopPropagation();
|
|
1391
|
-
host.select(box2.id);
|
|
1392
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1393
|
-
gesture.current = {
|
|
1394
|
-
handle,
|
|
1395
|
-
pointer: { x: event.clientX, y: event.clientY },
|
|
1396
|
-
frame,
|
|
1397
|
-
stage,
|
|
1398
|
-
next: null,
|
|
1399
|
-
request: null,
|
|
1400
|
-
wasSelected: selected
|
|
1401
|
-
};
|
|
1402
|
-
};
|
|
1403
|
-
const move = (event) => {
|
|
1404
|
-
const g = gesture.current;
|
|
1405
|
-
if (!g) return;
|
|
1406
|
-
const dx = (event.clientX - g.pointer.x) / g.stage.width;
|
|
1407
|
-
const dy = (event.clientY - g.pointer.y) / g.stage.height;
|
|
1408
|
-
if (!g.next) setDragging(true);
|
|
1409
|
-
g.next = g.handle === "move" ? chunk4TTX6ZNS_cjs.moveBox(g.frame, dx, dy) : chunk4TTX6ZNS_cjs.stretchBox(g.frame, g.handle, dx, dy);
|
|
1410
|
-
g.request ??= view().requestAnimationFrame(apply);
|
|
1411
|
-
};
|
|
1412
|
-
const end = () => {
|
|
1413
|
-
const g = gesture.current;
|
|
1414
|
-
gesture.current = null;
|
|
1415
|
-
if (!g) return;
|
|
1416
|
-
if (g.request !== null) view().cancelAnimationFrame(g.request);
|
|
1417
|
-
if (!g.next) {
|
|
1418
|
-
if (g.wasSelected && g.handle === "move" && hasText) setTyping(true);
|
|
1419
|
-
return;
|
|
1420
|
-
}
|
|
1421
|
-
const el = element.current;
|
|
1422
|
-
if (el) {
|
|
1423
|
-
el.style.translate = "";
|
|
1424
|
-
el.style.left = `${g.frame.x * 100}%`;
|
|
1425
|
-
el.style.top = `${g.frame.y * 100}%`;
|
|
1426
|
-
el.style.width = `${g.frame.w * 100}%`;
|
|
1427
|
-
el.style.height = `${g.frame.h * 100}%`;
|
|
1428
|
-
}
|
|
1429
|
-
setDragging(false);
|
|
1430
|
-
host.commit(box2.id, g.next);
|
|
1431
|
-
};
|
|
1432
|
-
const hasText = box2.shape !== "line";
|
|
1433
|
-
const inset = cqw(box2.inset ?? chunk4TTX6ZNS_cjs.DEFAULT_INSET);
|
|
1434
|
-
const run = chunk4TTX6ZNS_cjs.firstRun(box2);
|
|
1435
|
-
const transform = box2.rotation ? `rotate(${box2.rotation}deg)` : void 0;
|
|
1436
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1437
|
-
"div",
|
|
1438
|
-
{
|
|
1439
|
-
ref: element,
|
|
1440
|
-
className: ui.cn(
|
|
1441
|
-
"absolute",
|
|
1442
|
-
editable ? "pointer-events-auto" : "pointer-events-none",
|
|
1443
|
-
editable && !typing && "cursor-move touch-none",
|
|
1444
|
-
editable && !selected && "hover:outline hover:outline-1 hover:outline-white/30",
|
|
1445
|
-
selected && "outline outline-2 outline-offset-1 outline-primary"
|
|
1446
|
-
),
|
|
1447
|
-
style: {
|
|
1448
|
-
left: `${frame.x * 100}%`,
|
|
1449
|
-
top: `${frame.y * 100}%`,
|
|
1450
|
-
width: `${frame.w * 100}%`,
|
|
1451
|
-
height: `${frame.h * 100}%`,
|
|
1452
|
-
transform,
|
|
1453
|
-
willChange: dragging ? "translate" : void 0
|
|
1454
|
-
},
|
|
1455
|
-
onPointerDown: (event) => start(event, "move"),
|
|
1456
|
-
onPointerMove: move,
|
|
1457
|
-
onPointerUp: end,
|
|
1458
|
-
onPointerCancel: end,
|
|
1459
|
-
onDoubleClick: () => editable && hasText && setTyping(true),
|
|
1460
|
-
onKeyDown: (event) => {
|
|
1461
|
-
if (selected && !typing && event.key === "Enter" && hasText) {
|
|
1462
|
-
event.preventDefault();
|
|
1463
|
-
setTyping(true);
|
|
1464
|
-
}
|
|
1465
|
-
},
|
|
1466
|
-
tabIndex: editable ? 0 : void 0,
|
|
1467
|
-
"data-testid": `stage-box-${box2.id}`,
|
|
1468
|
-
children: [
|
|
1469
|
-
box2.shape === "line" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1470
|
-
"svg",
|
|
1471
|
-
{
|
|
1472
|
-
className: "absolute inset-0 size-full overflow-visible",
|
|
1473
|
-
preserveAspectRatio: "none",
|
|
1474
|
-
"aria-hidden": true,
|
|
1475
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1476
|
-
"line",
|
|
1477
|
-
{
|
|
1478
|
-
x1: "0%",
|
|
1479
|
-
y1: box2.flipV ? "100%" : "0%",
|
|
1480
|
-
x2: "100%",
|
|
1481
|
-
y2: box2.flipV ? "0%" : "100%",
|
|
1482
|
-
stroke: box2.line?.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
|
|
1483
|
-
style: { strokeWidth: cqw(box2.line?.width ?? 1) },
|
|
1484
|
-
strokeDasharray: box2.line?.dash ? "6 4" : void 0
|
|
1485
|
-
}
|
|
1486
|
-
)
|
|
1487
|
-
}
|
|
1488
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1489
|
-
"div",
|
|
1490
|
-
{
|
|
1491
|
-
className: ui.cn(
|
|
1492
|
-
"absolute inset-0 box-border flex flex-col overflow-hidden",
|
|
1493
|
-
box2.anchor === "middle" && "justify-center",
|
|
1494
|
-
box2.anchor === "bottom" && "justify-end"
|
|
1495
|
-
),
|
|
1496
|
-
style: { ...shapeStyle(box2), padding: inset },
|
|
1497
|
-
children: typing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1498
|
-
"textarea",
|
|
1499
|
-
{
|
|
1500
|
-
autoFocus: true,
|
|
1501
|
-
defaultValue: chunk4TTX6ZNS_cjs.boxText(box2),
|
|
1502
|
-
className: "pointer-events-auto w-full flex-1 resize-none bg-transparent p-0 outline-none",
|
|
1503
|
-
style: {
|
|
1504
|
-
...runStyle(run ?? { }, font),
|
|
1505
|
-
lineHeight: 1.2,
|
|
1506
|
-
textAlign: box2.paragraphs[0]?.align ?? "left"
|
|
1507
|
-
},
|
|
1508
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
1509
|
-
onBlur: (event) => {
|
|
1510
|
-
host.setText(box2.id, event.currentTarget.value);
|
|
1511
|
-
setTyping(false);
|
|
1512
|
-
},
|
|
1513
|
-
onKeyDown: (event) => {
|
|
1514
|
-
event.stopPropagation();
|
|
1515
|
-
if (event.key === "Escape") event.currentTarget.blur();
|
|
1516
|
-
},
|
|
1517
|
-
"aria-label": "Text",
|
|
1518
|
-
"data-testid": "stage-box-text-input"
|
|
1519
|
-
}
|
|
1520
|
-
) : chunk4TTX6ZNS_cjs.boxText(box2) || !editable ? /* @__PURE__ */ jsxRuntime.jsx(Paragraphs, { paragraphs: box2.paragraphs, font }) : box2.shape === "text" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1521
|
-
"span",
|
|
1522
|
-
{
|
|
1523
|
-
className: "text-white/40",
|
|
1524
|
-
style: { fontSize: cqw(run?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE) },
|
|
1525
|
-
children: "Double-click to type"
|
|
1526
|
-
}
|
|
1527
|
-
)
|
|
1528
|
-
}
|
|
1529
|
-
),
|
|
1530
|
-
selected && !typing && !dragging && HANDLES.filter(
|
|
1531
|
-
({ handle }) => box2.shape !== "line" || handle === "e" || handle === "w" || handle === "n" || handle === "s"
|
|
1532
|
-
).map(({ handle, left, top, cursor }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1533
|
-
"div",
|
|
1534
|
-
{
|
|
1535
|
-
className: "absolute flex size-5 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
|
|
1536
|
-
style: { left, top, cursor, touchAction: "none" },
|
|
1537
|
-
onPointerDown: (event) => start(event, handle),
|
|
1538
|
-
"aria-label": `Resize from ${handle}`,
|
|
1539
|
-
"data-testid": `stage-box-resize-${handle}`,
|
|
1540
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none size-2.5 rounded-full border-2 border-primary bg-background" })
|
|
1541
|
-
},
|
|
1542
|
-
handle
|
|
1543
|
-
))
|
|
1544
|
-
]
|
|
1545
|
-
}
|
|
1546
|
-
);
|
|
1547
|
-
});
|
|
1548
|
-
var SIZE_STEPS = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 44, 54, 66, 80, 96];
|
|
1549
|
-
var nextSize = (size, up) => up ? SIZE_STEPS.find((step) => step > size + 0.5) ?? size : [...SIZE_STEPS].reverse().find((step) => step < size - 0.5) ?? size;
|
|
1550
|
-
var ALIGN_NEXT = {
|
|
1551
|
-
left: "center",
|
|
1552
|
-
center: "right",
|
|
1553
|
-
right: "left",
|
|
1554
|
-
justify: "left"
|
|
1555
|
-
};
|
|
1556
|
-
var ALIGN_ICON = {
|
|
1557
|
-
left: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "size-4" }),
|
|
1558
|
-
center: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenter, { className: "size-4" }),
|
|
1559
|
-
right: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignRight, { className: "size-4" }),
|
|
1560
|
-
justify: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "size-4" })
|
|
1561
|
-
};
|
|
1562
|
-
function ColorAction({
|
|
1563
|
-
label,
|
|
1564
|
-
value,
|
|
1565
|
-
onChange,
|
|
1566
|
-
children
|
|
1567
|
-
}) {
|
|
1568
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: ui.cn(ACTION, "relative cursor-pointer"), title: label, "aria-label": label, children: [
|
|
1569
|
-
children,
|
|
1570
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1571
|
-
"span",
|
|
1572
|
-
{
|
|
1573
|
-
className: "pointer-events-none absolute inset-x-1.5 bottom-0.5 h-0.5 rounded-full",
|
|
1574
|
-
style: { background: value }
|
|
1575
|
-
}
|
|
1576
|
-
),
|
|
1577
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1578
|
-
"input",
|
|
1579
|
-
{
|
|
1580
|
-
type: "color",
|
|
1581
|
-
value,
|
|
1582
|
-
onChange: (event) => onChange(event.target.value),
|
|
1583
|
-
className: "absolute inset-0 size-full cursor-pointer opacity-0",
|
|
1584
|
-
"aria-label": label
|
|
1585
|
-
}
|
|
1586
|
-
)
|
|
1587
|
-
] });
|
|
1588
|
-
}
|
|
1589
|
-
function BoxActionBar({ box: box2, onRemoved }) {
|
|
1590
|
-
const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
1591
|
-
const run = chunk4TTX6ZNS_cjs.firstRun(box2);
|
|
1592
|
-
const size = run?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE;
|
|
1593
|
-
const align = box2.paragraphs[0]?.align ?? "left";
|
|
1594
|
-
const update = (change) => actions.updateBox(box2.id, change);
|
|
1595
|
-
const text = box2.shape !== "line";
|
|
1596
|
-
const top = Math.max(0, box2.frame.y);
|
|
1597
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1598
|
-
"div",
|
|
1599
|
-
{
|
|
1600
|
-
role: "toolbar",
|
|
1601
|
-
"aria-label": "Text box",
|
|
1602
|
-
className: "absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md",
|
|
1603
|
-
style: {
|
|
1604
|
-
left: `${Math.min(Math.max(0, box2.frame.x), 0.6) * 100}%`,
|
|
1605
|
-
top: `calc(${top * 100}% - 40px)`
|
|
1606
|
-
},
|
|
1607
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
1608
|
-
"data-testid": "box-action-bar",
|
|
1609
|
-
children: [
|
|
1610
|
-
text && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1611
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1612
|
-
Action,
|
|
1613
|
-
{
|
|
1614
|
-
label: "Smaller",
|
|
1615
|
-
onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, false) }))),
|
|
1616
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AArrowDown, { className: "size-4" })
|
|
1617
|
-
}
|
|
1618
|
-
),
|
|
1619
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1620
|
-
"span",
|
|
1621
|
-
{
|
|
1622
|
-
className: "w-7 text-center text-xs tabular-nums text-muted-foreground",
|
|
1623
|
-
"data-testid": "box-text-size",
|
|
1624
|
-
children: Math.round(size)
|
|
1625
|
-
}
|
|
1626
|
-
),
|
|
1627
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1628
|
-
Action,
|
|
1629
|
-
{
|
|
1630
|
-
label: "Larger",
|
|
1631
|
-
onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, true) }))),
|
|
1632
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AArrowUp, { className: "size-4" })
|
|
1633
|
-
}
|
|
1634
|
-
),
|
|
1635
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1636
|
-
Action,
|
|
1637
|
-
{
|
|
1638
|
-
label: "Bold",
|
|
1639
|
-
onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, bold: !run?.bold }))),
|
|
1640
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bold, { className: ui.cn("size-4", run?.bold && "text-primary") })
|
|
1641
|
-
}
|
|
1642
|
-
),
|
|
1643
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1644
|
-
Action,
|
|
1645
|
-
{
|
|
1646
|
-
label: "Italic",
|
|
1647
|
-
onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, italic: !run?.italic }))),
|
|
1648
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Italic, { className: ui.cn("size-4", run?.italic && "text-primary") })
|
|
1649
|
-
}
|
|
1650
|
-
),
|
|
1651
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1652
|
-
Action,
|
|
1653
|
-
{
|
|
1654
|
-
label: "Align",
|
|
1655
|
-
onClick: () => update((b) => ({
|
|
1656
|
-
...b,
|
|
1657
|
-
paragraphs: b.paragraphs.map((p) => ({ ...p, align: ALIGN_NEXT[align] }))
|
|
1658
|
-
})),
|
|
1659
|
-
children: ALIGN_ICON[align]
|
|
1660
|
-
}
|
|
1661
|
-
),
|
|
1662
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1663
|
-
ColorAction,
|
|
1664
|
-
{
|
|
1665
|
-
label: "Text colour",
|
|
1666
|
-
value: run?.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
|
|
1667
|
-
onChange: (color) => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, color }))),
|
|
1668
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Baseline, { className: "size-4" })
|
|
1669
|
-
}
|
|
1670
|
-
)
|
|
1671
|
-
] }),
|
|
1672
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1673
|
-
ColorAction,
|
|
1674
|
-
{
|
|
1675
|
-
label: box2.shape === "line" ? "Line colour" : "Fill",
|
|
1676
|
-
value: (box2.shape === "line" ? box2.line?.color : box2.fill) ?? "#ffffff",
|
|
1677
|
-
onChange: (color) => update(
|
|
1678
|
-
(b) => b.shape === "line" ? { ...b, line: { width: b.line?.width ?? 2, ...b.line, color } } : { ...b, fill: color, shape: b.shape === "text" ? "rect" : b.shape }
|
|
1679
|
-
),
|
|
1680
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PaintBucket, { className: "size-4" })
|
|
1681
|
-
}
|
|
1682
|
-
),
|
|
1683
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
1684
|
-
/* @__PURE__ */ jsxRuntime.jsx(Action, { label: "In front of the clips", onClick: () => actions.restackBox(box2.id, "front"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.BringToFront, { className: "size-4" }) }),
|
|
1685
|
-
/* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Behind the clips", onClick: () => actions.restackBox(box2.id, "back"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendToBack, { className: "size-4" }) }),
|
|
1686
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
1687
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1688
|
-
"button",
|
|
1689
|
-
{
|
|
1690
|
-
type: "button",
|
|
1691
|
-
className: ui.cn(ACTION, "text-destructive hover:bg-destructive/10"),
|
|
1692
|
-
title: "Delete (Delete)",
|
|
1693
|
-
"aria-label": "Delete",
|
|
1694
|
-
onClick: () => {
|
|
1695
|
-
actions.removeBox(box2.id);
|
|
1696
|
-
onRemoved();
|
|
1697
|
-
},
|
|
1698
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" })
|
|
1699
|
-
}
|
|
1700
|
-
)
|
|
1701
|
-
]
|
|
1702
|
-
}
|
|
1703
|
-
);
|
|
1704
|
-
}
|
|
1705
|
-
var GuideLayer = react.memo(
|
|
1706
|
-
react.forwardRef(function GuideLayer2(_, ref) {
|
|
1707
|
-
const [guides, setGuides] = react.useState([]);
|
|
1708
|
-
react.useImperativeHandle(ref, () => ({ set: setGuides }), []);
|
|
1709
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: guides.map((guide) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1710
|
-
"div",
|
|
1711
|
-
{
|
|
1712
|
-
className: "pointer-events-none absolute z-10 bg-primary",
|
|
1713
|
-
style: guide.axis === "x" ? { left: `${guide.at * 100}%`, top: 0, bottom: 0, width: 1 } : { top: `${guide.at * 100}%`, left: 0, right: 0, height: 1 },
|
|
1714
|
-
"data-testid": `stage-guide-${guide.axis}`
|
|
1715
|
-
},
|
|
1716
|
-
`${guide.axis}-${guide.at}`
|
|
1717
|
-
)) });
|
|
1718
|
-
})
|
|
1719
|
-
);
|
|
1720
|
-
function PresentationStage({
|
|
1721
|
-
editable = false,
|
|
1722
|
-
slideIndex,
|
|
1723
|
-
selected = null,
|
|
1724
|
-
onSelect,
|
|
1725
|
-
onEditImage,
|
|
1726
|
-
onCropImage,
|
|
1727
|
-
textEditing,
|
|
1728
|
-
overlay,
|
|
1729
|
-
className
|
|
1730
|
-
}) {
|
|
1731
|
-
const index = chunk4TTX6ZNS_cjs.usePresentation((s) => slideIndex ?? s.current);
|
|
1732
|
-
const slide = chunk4TTX6ZNS_cjs.usePresentation((s) => s.slides[index]);
|
|
1733
|
-
const clips = chunk4TTX6ZNS_cjs.usePresentation((s) => s.clips);
|
|
1734
|
-
const blank = chunk4TTX6ZNS_cjs.usePresentation((s) => s.blank && !editable);
|
|
1735
|
-
const captions = chunk4TTX6ZNS_cjs.usePresentation((s) => s.captions);
|
|
1736
|
-
const columnValues = chunk4TTX6ZNS_cjs.usePresentation((s) => s.columnValues);
|
|
1737
|
-
const theme = chunk4TTX6ZNS_cjs.usePresentation((s) => s.theme);
|
|
1738
|
-
const logoImage = chunk4TTX6ZNS_cjs.usePresentation((s) => s.logoImage);
|
|
1739
|
-
const media = chunk4TTX6ZNS_cjs.usePresentation((s) => s.media);
|
|
1740
|
-
const stageRef = react.useRef(null);
|
|
1741
|
-
const guideLayer = react.useRef(null);
|
|
1742
|
-
const dropping = chunk4TTX6ZNS_cjs.usePresentation((s) => editable && s.dragging !== null);
|
|
1743
|
-
const [dragging, setDragging] = react.useState(false);
|
|
1744
|
-
const latest = react.useRef({ slide, clips, index, onSelect });
|
|
1745
|
-
latest.current = { slide, clips, index, onSelect };
|
|
1746
|
-
const host = react.useMemo(
|
|
1747
|
-
() => ({
|
|
1748
|
-
stageBox: () => stageRef.current?.getBoundingClientRect() ?? null,
|
|
1749
|
-
others: (clipId) => {
|
|
1750
|
-
const { slide: current2, clips: all } = latest.current;
|
|
1751
|
-
return (current2?.items ?? []).filter((item) => item.clipId !== clipId).map((item) => ({
|
|
1752
|
-
frame: item.frame,
|
|
1753
|
-
aspect: all.find((clip) => clip.id === item.clipId)?.aspect ?? 1
|
|
1754
|
-
}));
|
|
1755
|
-
},
|
|
1756
|
-
select: (clipId) => {
|
|
1757
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(latest.current.index);
|
|
1758
|
-
latest.current.onSelect?.(clipId);
|
|
1759
|
-
},
|
|
1760
|
-
guides: (guides) => guideLayer.current?.set(guides),
|
|
1761
|
-
dragging: setDragging,
|
|
1762
|
-
commit: (clipId, frame, shape) => {
|
|
1763
|
-
const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
1764
|
-
state.goTo(latest.current.index);
|
|
1765
|
-
if (shape) state.reshapeClip(clipId, frame, shape.rect, shape.aspect);
|
|
1766
|
-
else state.setFrame(clipId, frame);
|
|
1767
|
-
}
|
|
1768
|
-
}),
|
|
1769
|
-
[]
|
|
1770
|
-
);
|
|
1771
|
-
const boxHost = react.useMemo(
|
|
1772
|
-
() => ({
|
|
1773
|
-
stageBox: () => stageRef.current?.getBoundingClientRect() ?? null,
|
|
1774
|
-
select: (boxId) => {
|
|
1775
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(latest.current.index);
|
|
1776
|
-
latest.current.onSelect?.(boxId);
|
|
1777
|
-
},
|
|
1778
|
-
commit: (boxId, frame) => chunk4TTX6ZNS_cjs.usePresentation.getState().updateBox(boxId, (box2) => ({ ...box2, frame })),
|
|
1779
|
-
setText: (boxId, text) => chunk4TTX6ZNS_cjs.usePresentation.getState().setBoxText(boxId, text)
|
|
1780
|
-
}),
|
|
1781
|
-
[]
|
|
1782
|
-
);
|
|
1783
|
-
const font = chunk4TTX6ZNS_cjs.FONTS[theme.font].css;
|
|
1784
|
-
const boxes = slide?.boxes ?? [];
|
|
1785
|
-
const selectedBox = selected ? boxes.find((box2) => box2.id === selected) : void 0;
|
|
1786
|
-
const renderBoxes = (front) => boxes.filter((box2) => !!box2.front === front).map((box2) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1787
|
-
StageBox,
|
|
1788
|
-
{
|
|
1789
|
-
box: box2,
|
|
1790
|
-
font,
|
|
1791
|
-
editable,
|
|
1792
|
-
selected: editable && selected === box2.id,
|
|
1793
|
-
host: boxHost
|
|
1794
|
-
},
|
|
1795
|
-
box2.id
|
|
1796
|
-
));
|
|
1797
|
-
const clipOf = (id) => clips.find((clip) => clip.id === id);
|
|
1798
|
-
const selectedFrame = selected ? slide?.items.find((item) => item.clipId === selected)?.frame : void 0;
|
|
1799
|
-
react.useEffect(() => {
|
|
1800
|
-
const stage = stageRef.current;
|
|
1801
|
-
const view = stage?.ownerDocument.defaultView;
|
|
1802
|
-
if (!editable || !selected || !stage || !view) return;
|
|
1803
|
-
let sum = { x: 0, y: 0 };
|
|
1804
|
-
let request = null;
|
|
1805
|
-
const onWheel = (event) => {
|
|
1806
|
-
const item = event.target?.closest?.(
|
|
1807
|
-
`[data-testid="stage-item-${selected}"]`
|
|
1808
|
-
);
|
|
1809
|
-
const clip = chunk4TTX6ZNS_cjs.usePresentation.getState().clips.find((entry) => entry.id === selected);
|
|
1810
|
-
if (!item || !clip) return;
|
|
1811
|
-
event.preventDefault();
|
|
1812
|
-
const box2 = item.getBoundingClientRect();
|
|
1813
|
-
const horizontal = event.shiftKey && !event.deltaX;
|
|
1814
|
-
const deltaX = horizontal ? event.deltaY : event.deltaX;
|
|
1815
|
-
const deltaY = horizontal ? 0 : event.deltaY;
|
|
1816
|
-
sum = {
|
|
1817
|
-
x: sum.x + deltaX / box2.width * clip.rect.w,
|
|
1818
|
-
y: sum.y + deltaY / box2.height * clip.rect.h
|
|
1819
|
-
};
|
|
1820
|
-
request ??= view.requestAnimationFrame(() => {
|
|
1821
|
-
request = null;
|
|
1822
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().panClip(selected, sum.x, sum.y);
|
|
1823
|
-
sum = { x: 0, y: 0 };
|
|
1824
|
-
});
|
|
1825
|
-
};
|
|
1826
|
-
stage.addEventListener("wheel", onWheel, { passive: false });
|
|
1827
|
-
return () => {
|
|
1828
|
-
stage.removeEventListener("wheel", onWheel);
|
|
1829
|
-
if (request !== null) view.cancelAnimationFrame(request);
|
|
1830
|
-
};
|
|
1831
|
-
}, [editable, selected]);
|
|
1832
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1833
|
-
"div",
|
|
1834
|
-
{
|
|
1835
|
-
className: ui.cn("relative h-full w-full", !editable && "overflow-hidden bg-black", className),
|
|
1836
|
-
style: { containerType: "size" },
|
|
1837
|
-
"data-testid": editable ? "presentation-stage-editor" : "presentation-stage",
|
|
1838
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1839
|
-
"div",
|
|
1840
|
-
{
|
|
1841
|
-
ref: stageRef,
|
|
1842
|
-
className: ui.cn(
|
|
1843
|
-
"absolute inset-0 m-auto",
|
|
1844
|
-
editable ? "shadow-md" : "overflow-hidden",
|
|
1845
|
-
dropping && "outline outline-2 outline-offset-2 outline-primary"
|
|
1846
|
-
),
|
|
1847
|
-
style: {
|
|
1848
|
-
width: "min(100cqw, calc(100cqh * 16 / 9))",
|
|
1849
|
-
height: "min(100cqh, calc(100cqw * 9 / 16))",
|
|
1850
|
-
containerType: "inline-size",
|
|
1851
|
-
background: slide?.background ? chunk4TTX6ZNS_cjs.slideBackgroundCss(slide.background, media) : chunk4TTX6ZNS_cjs.backgroundCss(theme.background),
|
|
1852
|
-
fontFamily: chunk4TTX6ZNS_cjs.FONTS[theme.font].css
|
|
1853
|
-
},
|
|
1854
|
-
onPointerDown: () => {
|
|
1855
|
-
if (!editable) return;
|
|
1856
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(index);
|
|
1857
|
-
onSelect?.(null);
|
|
1858
|
-
},
|
|
1859
|
-
...editable ? { [DROP_ATTRIBUTE]: "stage", "data-slide-index": index } : {},
|
|
1860
|
-
"aria-label": `Slide ${index + 1}`,
|
|
1861
|
-
children: [
|
|
1862
|
-
blank && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-20 bg-black" }),
|
|
1863
|
-
slide && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1864
|
-
SlideDecor,
|
|
1865
|
-
{
|
|
1866
|
-
slide,
|
|
1867
|
-
theme,
|
|
1868
|
-
labels: captions,
|
|
1869
|
-
logoImage,
|
|
1870
|
-
editable,
|
|
1871
|
-
editing: textEditing
|
|
1872
|
-
}
|
|
1873
|
-
),
|
|
1874
|
-
renderBoxes(false),
|
|
1875
|
-
slide?.items.map((item) => {
|
|
1876
|
-
const clip = clipOf(item.clipId);
|
|
1877
|
-
if (!clip) return null;
|
|
1878
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1879
|
-
StageItem,
|
|
1880
|
-
{
|
|
1881
|
-
clip,
|
|
1882
|
-
frame: item.frame,
|
|
1883
|
-
editable,
|
|
1884
|
-
selected: editable && selected === clip.id,
|
|
1885
|
-
dim: false,
|
|
1886
|
-
label: captions ? chunk4TTX6ZNS_cjs.clipLabel(clip, columnValues) : "",
|
|
1887
|
-
host
|
|
1888
|
-
},
|
|
1889
|
-
clip.id
|
|
1890
|
-
);
|
|
1891
|
-
}),
|
|
1892
|
-
renderBoxes(true),
|
|
1893
|
-
editable && /* @__PURE__ */ jsxRuntime.jsx(GuideLayer, { ref: guideLayer }),
|
|
1894
|
-
editable && selectedFrame && selected && !dragging && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1895
|
-
ClipActionBar,
|
|
1896
|
-
{
|
|
1897
|
-
clipId: selected,
|
|
1898
|
-
at: selectedFrame,
|
|
1899
|
-
onRemoved: () => onSelect?.(null),
|
|
1900
|
-
onEditImage: onEditImage && clipOf(selected)?.kind === "image" ? () => onEditImage(selected) : void 0,
|
|
1901
|
-
onCropImage: onCropImage && clipOf(selected)?.kind === "image" ? () => onCropImage(selected) : void 0
|
|
1902
|
-
}
|
|
1903
|
-
),
|
|
1904
|
-
editable && selectedBox && /* @__PURE__ */ jsxRuntime.jsx(BoxActionBar, { box: selectedBox, onRemoved: () => onSelect?.(null) }),
|
|
1905
|
-
overlay
|
|
1906
|
-
]
|
|
1907
|
-
}
|
|
1908
|
-
)
|
|
1909
|
-
}
|
|
1910
|
-
);
|
|
1911
|
-
}
|
|
1912
|
-
function SlideAction({
|
|
1913
|
-
label,
|
|
1914
|
-
onClick,
|
|
1915
|
-
disabled,
|
|
1916
|
-
children
|
|
1917
|
-
}) {
|
|
1918
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1919
|
-
ui.Button,
|
|
1920
|
-
{
|
|
1921
|
-
type: "button",
|
|
1922
|
-
size: "icon",
|
|
1923
|
-
variant: "ghost",
|
|
1924
|
-
className: "size-7 text-muted-foreground hover:text-foreground pointer-coarse:size-10",
|
|
1925
|
-
title: label,
|
|
1926
|
-
"aria-label": label,
|
|
1927
|
-
disabled,
|
|
1928
|
-
onClick,
|
|
1929
|
-
children
|
|
1930
|
-
}
|
|
1931
|
-
);
|
|
1932
|
-
}
|
|
1933
482
|
var SlideCard = react.memo(function SlideCard2({
|
|
1934
483
|
index,
|
|
1935
484
|
count,
|
|
@@ -1939,20 +488,20 @@ var SlideCard = react.memo(function SlideCard2({
|
|
|
1939
488
|
onEditImage,
|
|
1940
489
|
onCropImage
|
|
1941
490
|
}) {
|
|
1942
|
-
const empty =
|
|
491
|
+
const empty = chunkORNLCBNE_cjs.usePresentation((s) => {
|
|
1943
492
|
const slide = s.slides[index];
|
|
1944
|
-
return !!slide && !slide.items.length && !slide.boxes.length && slide.layout !== "title" && slide.layout !== "section";
|
|
493
|
+
return !!slide && !slide.items.length && !slide.boxes.length && !slide.points.trim() && slide.layout !== "title" && slide.layout !== "section";
|
|
1945
494
|
});
|
|
1946
|
-
const notes =
|
|
495
|
+
const notes = chunkORNLCBNE_cjs.usePresentation((s) => s.slides[index]?.notes ?? "");
|
|
1947
496
|
const textEditing = react.useMemo(
|
|
1948
497
|
() => ({
|
|
1949
|
-
onTitle: (title) =>
|
|
1950
|
-
onPoints: (points) =>
|
|
498
|
+
onTitle: (title) => chunkORNLCBNE_cjs.usePresentation.getState().setSlideCaption(title, index),
|
|
499
|
+
onPoints: (points) => chunkORNLCBNE_cjs.usePresentation.getState().setSlidePoints(points, index)
|
|
1951
500
|
}),
|
|
1952
501
|
[index]
|
|
1953
502
|
);
|
|
1954
503
|
const select = react.useCallback((clipId) => onSelect(index, clipId), [onSelect, index]);
|
|
1955
|
-
const actions =
|
|
504
|
+
const actions = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
1956
505
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative flex gap-2", "data-testid": `slide-${index}`, children: [
|
|
1957
506
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-9 shrink-0 flex-col items-center gap-0.5", children: [
|
|
1958
507
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1976,26 +525,61 @@ var SlideCard = react.memo(function SlideCard2({
|
|
|
1976
525
|
"data-testid": `slide-actions-${index}`,
|
|
1977
526
|
children: [
|
|
1978
527
|
/* @__PURE__ */ jsxRuntime.jsx(LayoutMenu, { index, compact: true }),
|
|
1979
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
528
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
529
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
530
|
+
ui.Button,
|
|
531
|
+
{
|
|
532
|
+
type: "button",
|
|
533
|
+
size: "icon",
|
|
534
|
+
variant: "ghost",
|
|
535
|
+
className: "size-7 text-muted-foreground hover:text-foreground pointer-coarse:size-11",
|
|
536
|
+
title: "Slide actions",
|
|
537
|
+
"aria-label": `Slide ${index + 1} actions`,
|
|
538
|
+
"data-testid": `slide-menu-${index}`,
|
|
539
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-3.5" })
|
|
540
|
+
}
|
|
541
|
+
) }),
|
|
542
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "start", children: [
|
|
543
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
544
|
+
ui.DropdownMenuItem,
|
|
545
|
+
{
|
|
546
|
+
disabled: index === 0,
|
|
547
|
+
onSelect: () => actions.moveSlide(index, index - 1),
|
|
548
|
+
children: [
|
|
549
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowUp, { className: "size-4" }),
|
|
550
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Move up" })
|
|
551
|
+
]
|
|
552
|
+
}
|
|
553
|
+
),
|
|
554
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
555
|
+
ui.DropdownMenuItem,
|
|
556
|
+
{
|
|
557
|
+
disabled: index === count - 1,
|
|
558
|
+
onSelect: () => actions.moveSlide(index, index + 1),
|
|
559
|
+
children: [
|
|
560
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowDown, { className: "size-4" }),
|
|
561
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Move down" })
|
|
562
|
+
]
|
|
563
|
+
}
|
|
564
|
+
),
|
|
565
|
+
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.duplicateSlide(index), children: [
|
|
566
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Copy, { className: "size-4" }),
|
|
567
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Duplicate" })
|
|
568
|
+
] }),
|
|
569
|
+
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
|
|
570
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
571
|
+
ui.DropdownMenuItem,
|
|
572
|
+
{
|
|
573
|
+
className: "text-destructive",
|
|
574
|
+
onSelect: () => actions.removeSlide(index),
|
|
575
|
+
children: [
|
|
576
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" }),
|
|
577
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Delete slide" })
|
|
578
|
+
]
|
|
579
|
+
}
|
|
580
|
+
)
|
|
581
|
+
] })
|
|
582
|
+
] })
|
|
1999
583
|
]
|
|
2000
584
|
}
|
|
2001
585
|
)
|
|
@@ -2009,7 +593,7 @@ var SlideCard = react.memo(function SlideCard2({
|
|
|
2009
593
|
),
|
|
2010
594
|
children: [
|
|
2011
595
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2012
|
-
PresentationStage,
|
|
596
|
+
chunkJY7UUZQG_cjs.PresentationStage,
|
|
2013
597
|
{
|
|
2014
598
|
editable: true,
|
|
2015
599
|
slideIndex: index,
|
|
@@ -2027,7 +611,7 @@ var SlideCard = react.memo(function SlideCard2({
|
|
|
2027
611
|
value: notes,
|
|
2028
612
|
rows: notes.split("\n").length,
|
|
2029
613
|
placeholder: "Speaker notes",
|
|
2030
|
-
onChange: (event) =>
|
|
614
|
+
onChange: (event) => chunkORNLCBNE_cjs.usePresentation.getState().setSlideNotes(event.target.value, index),
|
|
2031
615
|
className: "mt-2 block w-full resize-none rounded-sm border-0 bg-transparent px-1 py-0.5 text-xs text-muted-foreground placeholder:text-muted-foreground/50 focus:bg-background focus:text-foreground focus:outline-none focus:ring-1 focus:ring-ring",
|
|
2032
616
|
"aria-label": `Speaker notes for slide ${index + 1}`,
|
|
2033
617
|
"data-testid": `slide-notes-${index}`
|
|
@@ -2051,10 +635,10 @@ var INSERTS = [
|
|
|
2051
635
|
];
|
|
2052
636
|
function InsertMenu({ onInserted }) {
|
|
2053
637
|
const insert = (shape) => {
|
|
2054
|
-
const state =
|
|
638
|
+
const state = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
2055
639
|
const slide = state.slides[state.current];
|
|
2056
|
-
const box2 =
|
|
2057
|
-
const dark =
|
|
640
|
+
const box2 = chunkORNLCBNE_cjs.newBox(shape, chunkORNLCBNE_cjs.accentColor(state.theme.accent));
|
|
641
|
+
const dark = chunkORNLCBNE_cjs.isLightBackground(slide?.background);
|
|
2058
642
|
const { id, ...rest } = dark ? {
|
|
2059
643
|
...box2,
|
|
2060
644
|
paragraphs: box2.paragraphs.map((p) => ({
|
|
@@ -2097,7 +681,7 @@ function InsertSlide({ after, always }) {
|
|
|
2097
681
|
"button",
|
|
2098
682
|
{
|
|
2099
683
|
type: "button",
|
|
2100
|
-
onClick: () =>
|
|
684
|
+
onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().addSlide(void 0, after),
|
|
2101
685
|
className: ui.cn(
|
|
2102
686
|
"flex items-center gap-1 rounded-full border border-dashed border-border bg-background px-2.5 py-0.5 text-xs text-muted-foreground transition-opacity hover:border-solid hover:text-foreground focus-visible:opacity-100",
|
|
2103
687
|
!always && "opacity-0 group-hover/insert:opacity-100 pointer-coarse:opacity-100"
|
|
@@ -2120,11 +704,11 @@ function SlidesEditor({
|
|
|
2120
704
|
onEditImage,
|
|
2121
705
|
onCropImage
|
|
2122
706
|
}) {
|
|
2123
|
-
const ids =
|
|
707
|
+
const ids = chunkORNLCBNE_cjs.usePresentation((s) => s.slides.map((slide) => slide.id).join(" "));
|
|
2124
708
|
const slideIds = react.useMemo(() => ids.split(" "), [ids]);
|
|
2125
|
-
const current2 =
|
|
2126
|
-
const captions =
|
|
2127
|
-
const presenting =
|
|
709
|
+
const current2 = chunkORNLCBNE_cjs.usePresentation((s) => s.current);
|
|
710
|
+
const captions = chunkORNLCBNE_cjs.usePresentation((s) => s.captions);
|
|
711
|
+
const presenting = chunkORNLCBNE_cjs.usePresentation((s) => s.presenting);
|
|
2128
712
|
const [selection, setSelection] = react.useState(null);
|
|
2129
713
|
const [view, setView] = react.useState(null);
|
|
2130
714
|
const list = react.useRef(null);
|
|
@@ -2138,7 +722,7 @@ function SlidesEditor({
|
|
|
2138
722
|
() => ({ clipId: selection?.clipId ?? null, clear: () => setSelection(null) }),
|
|
2139
723
|
[selection]
|
|
2140
724
|
);
|
|
2141
|
-
|
|
725
|
+
chunkADPRIBSH_cjs.usePresenterKeys(view, false, keySelection);
|
|
2142
726
|
react.useEffect(() => {
|
|
2143
727
|
const card = list.current?.querySelector(`[data-testid="slide-${current2}"]`);
|
|
2144
728
|
card?.scrollIntoView?.({ block: "nearest", behavior: "smooth" });
|
|
@@ -2194,7 +778,7 @@ function SlidesEditor({
|
|
|
2194
778
|
ui.DropdownMenuCheckboxItem,
|
|
2195
779
|
{
|
|
2196
780
|
checked: captions,
|
|
2197
|
-
onCheckedChange: (on) =>
|
|
781
|
+
onCheckedChange: (on) => chunkORNLCBNE_cjs.usePresentation.getState().setCaptions(!!on),
|
|
2198
782
|
children: "Show source labels"
|
|
2199
783
|
}
|
|
2200
784
|
)
|
|
@@ -2207,7 +791,7 @@ function SlidesEditor({
|
|
|
2207
791
|
size: "sm",
|
|
2208
792
|
variant: "destructive",
|
|
2209
793
|
className: "ml-0.5 h-8 rounded-full",
|
|
2210
|
-
onClick: () =>
|
|
794
|
+
onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().setPresenting(false),
|
|
2211
795
|
title: "Stop presenting (the presentation window closes)",
|
|
2212
796
|
"data-testid": "presentation-stop-button",
|
|
2213
797
|
children: [
|
|
@@ -2246,7 +830,7 @@ function SlidesEditor({
|
|
|
2246
830
|
// src/presentation/draw-boxes.ts
|
|
2247
831
|
var LINE_HEIGHT = 1.2;
|
|
2248
832
|
function fontOf(run, themeFont, width) {
|
|
2249
|
-
const size =
|
|
833
|
+
const size = chunkORNLCBNE_cjs.pointsToStage(run.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE) * width;
|
|
2250
834
|
const family = run.font ? `"${run.font}", ${themeFont}` : themeFont;
|
|
2251
835
|
return `${run.italic ? "italic " : ""}${run.bold ? 700 : 400} ${size}px ${family}`;
|
|
2252
836
|
}
|
|
@@ -2264,9 +848,9 @@ function drawBox(context, box2, width, height, themeFont) {
|
|
|
2264
848
|
context.translate(frame.x * width + w / 2, frame.y * height + h / 2);
|
|
2265
849
|
if (box2.rotation) context.rotate(box2.rotation * Math.PI / 180);
|
|
2266
850
|
context.translate(-w / 2, -h / 2);
|
|
2267
|
-
const lineWidth = box2.line ? Math.max(1,
|
|
851
|
+
const lineWidth = box2.line ? Math.max(1, chunkORNLCBNE_cjs.pointsToStage(box2.line.width) * width) : 0;
|
|
2268
852
|
if (box2.shape === "line") {
|
|
2269
|
-
context.strokeStyle = box2.line?.color ??
|
|
853
|
+
context.strokeStyle = box2.line?.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
|
|
2270
854
|
context.lineWidth = lineWidth || 1;
|
|
2271
855
|
if (box2.line?.dash) context.setLineDash([lineWidth * 3, lineWidth * 2]);
|
|
2272
856
|
context.beginPath();
|
|
@@ -2291,12 +875,12 @@ function drawBox(context, box2, width, height, themeFont) {
|
|
|
2291
875
|
context.stroke();
|
|
2292
876
|
context.setLineDash([]);
|
|
2293
877
|
}
|
|
2294
|
-
const inset =
|
|
878
|
+
const inset = chunkORNLCBNE_cjs.pointsToStage(box2.inset ?? chunkORNLCBNE_cjs.DEFAULT_INSET) * width;
|
|
2295
879
|
const room = w - 2 * inset;
|
|
2296
880
|
context.textBaseline = "alphabetic";
|
|
2297
881
|
const lines = [];
|
|
2298
882
|
for (const paragraph of box2.paragraphs) {
|
|
2299
|
-
const size =
|
|
883
|
+
const size = chunkORNLCBNE_cjs.pointsToStage(paragraph.runs[0]?.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE) * width;
|
|
2300
884
|
const indent = (paragraph.level ?? 0) * 0.5 * size + (paragraph.bullet ? size * 0.9 : 0);
|
|
2301
885
|
const words = [];
|
|
2302
886
|
for (const run of paragraph.runs) {
|
|
@@ -2342,12 +926,12 @@ function drawBox(context, box2, width, height, themeFont) {
|
|
|
2342
926
|
const baseline = y + line.size * (LINE_HEIGHT - 0.2);
|
|
2343
927
|
if (line.bullet) {
|
|
2344
928
|
context.font = fontOf(line.bullet, themeFont, width);
|
|
2345
|
-
context.fillStyle = line.bullet.color ??
|
|
929
|
+
context.fillStyle = line.bullet.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
|
|
2346
930
|
context.fillText("\u2022", inset + line.indent - line.size * 0.9, baseline);
|
|
2347
931
|
}
|
|
2348
932
|
for (const piece of line.pieces) {
|
|
2349
933
|
context.font = fontOf(piece.run, themeFont, width);
|
|
2350
|
-
context.fillStyle = piece.run.color ??
|
|
934
|
+
context.fillStyle = piece.run.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
|
|
2351
935
|
context.fillText(piece.text, x, baseline);
|
|
2352
936
|
if (piece.run.underline) {
|
|
2353
937
|
context.fillRect(x, baseline + line.size * 0.08, piece.width, Math.max(1, line.size * 0.05));
|
|
@@ -2364,7 +948,7 @@ var boxWords = (box2) => box2.paragraphs.map(
|
|
|
2364
948
|
).filter(Boolean);
|
|
2365
949
|
|
|
2366
950
|
// src/presentation/render-slides.ts
|
|
2367
|
-
var SLIDE_PIXELS = { width: 1920, height: Math.round(1920 /
|
|
951
|
+
var SLIDE_PIXELS = { width: 1920, height: Math.round(1920 / chunkORNLCBNE_cjs.STAGE_ASPECT) };
|
|
2368
952
|
async function videoFrame(source, seconds) {
|
|
2369
953
|
const video = document.createElement("video");
|
|
2370
954
|
video.muted = true;
|
|
@@ -2476,7 +1060,7 @@ async function drawRoundedClip(context, clip, box2, stageWidth, shadow = true) {
|
|
|
2476
1060
|
outline2();
|
|
2477
1061
|
context.clip();
|
|
2478
1062
|
await drawClip(context, clip, box2);
|
|
2479
|
-
if (clip.kind === "pdf")
|
|
1063
|
+
if (clip.kind === "pdf") chunkORNLCBNE_cjs.paintClipEdge(context, box2, stageWidth);
|
|
2480
1064
|
context.restore();
|
|
2481
1065
|
context.save();
|
|
2482
1066
|
context.strokeStyle = "rgba(255,255,255,0.15)";
|
|
@@ -2508,7 +1092,7 @@ function wrapLines(context, text, width, max) {
|
|
|
2508
1092
|
function drawText(context, box2, lines, theme, width, height) {
|
|
2509
1093
|
const size = box2.size * width;
|
|
2510
1094
|
const lineHeight = size * box2.leading;
|
|
2511
|
-
context.font = `${box2.weight} ${size}px ${
|
|
1095
|
+
context.font = `${box2.weight} ${size}px ${chunkORNLCBNE_cjs.FONTS[theme.font].css}`;
|
|
2512
1096
|
context.textBaseline = "top";
|
|
2513
1097
|
const indent = box2.bullets ? size * 1.22 : 0;
|
|
2514
1098
|
const left = box2.x * width;
|
|
@@ -2530,10 +1114,10 @@ function drawText(context, box2, lines, theme, width, height) {
|
|
|
2530
1114
|
for (const wrapped of paragraphs) {
|
|
2531
1115
|
if (box2.bullets) {
|
|
2532
1116
|
const square = size * 0.42;
|
|
2533
|
-
context.fillStyle =
|
|
1117
|
+
context.fillStyle = chunkORNLCBNE_cjs.accentColor(theme.accent);
|
|
2534
1118
|
context.fillRect(left, y + size * 0.5 - square / 2, square, square);
|
|
2535
1119
|
}
|
|
2536
|
-
context.fillStyle =
|
|
1120
|
+
context.fillStyle = chunkORNLCBNE_cjs.TEXT_COLORS[box2.tone];
|
|
2537
1121
|
context.textAlign = box2.align === "center" ? "center" : "left";
|
|
2538
1122
|
for (const line of wrapped) {
|
|
2539
1123
|
const x = box2.align === "center" ? left + box2.w * width / 2 : left + indent;
|
|
@@ -2569,11 +1153,11 @@ async function loadImage(file) {
|
|
|
2569
1153
|
}
|
|
2570
1154
|
}
|
|
2571
1155
|
function slideWords(slide) {
|
|
2572
|
-
const own = slide.layout === "free" ? [] : [slide.caption.trim(), ...
|
|
1156
|
+
const own = slide.layout === "free" ? [] : [slide.caption.trim(), ...chunkORNLCBNE_cjs.textLines(slide.points)];
|
|
2573
1157
|
return [...own, ...slide.boxes.flatMap(boxWords)].filter(Boolean);
|
|
2574
1158
|
}
|
|
2575
1159
|
function drawSlideText(context, slide, look, width, height) {
|
|
2576
|
-
const geometry =
|
|
1160
|
+
const geometry = chunkORNLCBNE_cjs.slideGeometry(slide, {
|
|
2577
1161
|
labels: look.labels,
|
|
2578
1162
|
logo: look.theme.logo?.corner ?? null
|
|
2579
1163
|
});
|
|
@@ -2581,13 +1165,13 @@ function drawSlideText(context, slide, look, width, height) {
|
|
|
2581
1165
|
if (title && geometry.title) {
|
|
2582
1166
|
drawText(context, geometry.title, [title], look.theme, width, height);
|
|
2583
1167
|
if (geometry.rule) {
|
|
2584
|
-
context.fillStyle =
|
|
1168
|
+
context.fillStyle = chunkORNLCBNE_cjs.accentColor(look.theme.accent);
|
|
2585
1169
|
const r = geometry.rule;
|
|
2586
1170
|
context.fillRect(r.x * width, r.y * height, r.w * width, r.h * height);
|
|
2587
1171
|
}
|
|
2588
1172
|
}
|
|
2589
1173
|
if (geometry.text) {
|
|
2590
|
-
drawText(context, geometry.text,
|
|
1174
|
+
drawText(context, geometry.text, chunkORNLCBNE_cjs.textLines(slide.points), look.theme, width, height);
|
|
2591
1175
|
}
|
|
2592
1176
|
return geometry;
|
|
2593
1177
|
}
|
|
@@ -2599,13 +1183,13 @@ async function renderSlide(slide, clips, look) {
|
|
|
2599
1183
|
const context = canvas.getContext("2d");
|
|
2600
1184
|
if (!context) throw new Error("Could not draw the slides");
|
|
2601
1185
|
if (slide.background) {
|
|
2602
|
-
await
|
|
1186
|
+
await chunkORNLCBNE_cjs.paintSlideBackground(context, width, height, slide.background, look.media);
|
|
2603
1187
|
} else {
|
|
2604
|
-
|
|
1188
|
+
chunkORNLCBNE_cjs.paintBackground(context, width, height, look.theme.background);
|
|
2605
1189
|
}
|
|
2606
1190
|
const geometry = drawSlideText(context, slide, look, width, height);
|
|
2607
1191
|
const text = slideWords(slide);
|
|
2608
|
-
const font =
|
|
1192
|
+
const font = chunkORNLCBNE_cjs.FONTS[look.theme.font].css;
|
|
2609
1193
|
const drawBoxes = (front) => {
|
|
2610
1194
|
for (const box2 of slide.boxes) {
|
|
2611
1195
|
if (!!box2.front === front) drawBox(context, box2, width, height, font);
|
|
@@ -2619,16 +1203,16 @@ async function renderSlide(slide, clips, look) {
|
|
|
2619
1203
|
x: item.frame.x * width,
|
|
2620
1204
|
y: item.frame.y * height,
|
|
2621
1205
|
width: item.frame.w * width,
|
|
2622
|
-
height:
|
|
1206
|
+
height: chunkORNLCBNE_cjs.frameHeight(item.frame, clip.aspect) * height
|
|
2623
1207
|
};
|
|
2624
1208
|
if (clip.plain) {
|
|
2625
1209
|
await drawClip(context, clip, box2);
|
|
2626
1210
|
continue;
|
|
2627
1211
|
}
|
|
2628
1212
|
await drawRoundedClip(context, clip, box2, width);
|
|
2629
|
-
const label =
|
|
1213
|
+
const label = chunkORNLCBNE_cjs.clipLabel(clip, look.columnValues);
|
|
2630
1214
|
if (look.labels && label) {
|
|
2631
|
-
context.fillStyle =
|
|
1215
|
+
context.fillStyle = chunkORNLCBNE_cjs.TEXT_COLORS.muted;
|
|
2632
1216
|
context.font = `${Math.round(width * 0.017)}px ${font}`;
|
|
2633
1217
|
context.textAlign = "left";
|
|
2634
1218
|
context.textBaseline = "top";
|
|
@@ -2671,7 +1255,7 @@ function addBox(pptx, page, box2, themeFont) {
|
|
|
2671
1255
|
if (box2.shape === "line") {
|
|
2672
1256
|
page.addShape(pptx.ShapeType.line, {
|
|
2673
1257
|
...place,
|
|
2674
|
-
line: line ?? { color: hex(
|
|
1258
|
+
line: line ?? { color: hex(chunkORNLCBNE_cjs.TEXT_COLORS.body), width: 1 }
|
|
2675
1259
|
});
|
|
2676
1260
|
return;
|
|
2677
1261
|
}
|
|
@@ -2688,9 +1272,9 @@ function addBox(pptx, page, box2, themeFont) {
|
|
|
2688
1272
|
runs.push({
|
|
2689
1273
|
text: run.text,
|
|
2690
1274
|
options: {
|
|
2691
|
-
fontSize: run.size ??
|
|
1275
|
+
fontSize: run.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE,
|
|
2692
1276
|
fontFace: run.font ?? themeFont,
|
|
2693
|
-
color: hex(run.color ??
|
|
1277
|
+
color: hex(run.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body),
|
|
2694
1278
|
...run.bold ? { bold: true } : {},
|
|
2695
1279
|
...run.italic ? { italic: true } : {},
|
|
2696
1280
|
...run.underline ? { underline: { style: "sng" } } : {},
|
|
@@ -2712,7 +1296,7 @@ function addBox(pptx, page, box2, themeFont) {
|
|
|
2712
1296
|
// Its part in the slide (its title, its body), kept by name: read back when imported.
|
|
2713
1297
|
...box2.role ? { objectName: `ARBI ${box2.role}` } : {},
|
|
2714
1298
|
valign: box2.anchor ?? "top",
|
|
2715
|
-
margin: box2.inset ??
|
|
1299
|
+
margin: box2.inset ?? chunkORNLCBNE_cjs.DEFAULT_INSET,
|
|
2716
1300
|
lineSpacingMultiple: 1,
|
|
2717
1301
|
fit: "none"
|
|
2718
1302
|
});
|
|
@@ -2742,10 +1326,10 @@ var box = (b) => ({
|
|
|
2742
1326
|
function textOptions(text, look) {
|
|
2743
1327
|
return {
|
|
2744
1328
|
...box(text),
|
|
2745
|
-
fontFace:
|
|
1329
|
+
fontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
|
|
2746
1330
|
fontSize: toPoints(text.size),
|
|
2747
1331
|
bold: text.weight >= 600,
|
|
2748
|
-
color: hex2(
|
|
1332
|
+
color: hex2(chunkORNLCBNE_cjs.TEXT_COLORS[text.tone]),
|
|
2749
1333
|
align: text.align,
|
|
2750
1334
|
valign: text.anchor ?? "top",
|
|
2751
1335
|
lineSpacingMultiple: text.leading,
|
|
@@ -2758,18 +1342,18 @@ async function buildPptx(deck, look) {
|
|
|
2758
1342
|
pptx.layout = "LAYOUT_WIDE";
|
|
2759
1343
|
pptx.title = deck.title;
|
|
2760
1344
|
pptx.theme = {
|
|
2761
|
-
headFontFace:
|
|
2762
|
-
bodyFontFace:
|
|
1345
|
+
headFontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
|
|
1346
|
+
bodyFontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx
|
|
2763
1347
|
};
|
|
2764
1348
|
const { width, height } = SLIDE_PIXELS;
|
|
2765
1349
|
const background = await canvasImage(
|
|
2766
1350
|
width,
|
|
2767
1351
|
height,
|
|
2768
|
-
(context) =>
|
|
1352
|
+
(context) => chunkORNLCBNE_cjs.paintBackground(context, width, height, look.theme.background)
|
|
2769
1353
|
);
|
|
2770
1354
|
const logo = look.logo ? await loadImage(look.logo) : null;
|
|
2771
1355
|
const logoData = logo ? await canvasImage(logo.width, logo.height, (context) => context.drawImage(logo, 0, 0)) : null;
|
|
2772
|
-
const themeFont =
|
|
1356
|
+
const themeFont = chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx;
|
|
2773
1357
|
for (const slide of deck.slides) {
|
|
2774
1358
|
const page = pptx.addSlide();
|
|
2775
1359
|
if (slide.background?.color && !slide.background.gradient && !slide.background.image) {
|
|
@@ -2780,14 +1364,14 @@ async function buildPptx(deck, look) {
|
|
|
2780
1364
|
data: await canvasImage(
|
|
2781
1365
|
width,
|
|
2782
1366
|
height,
|
|
2783
|
-
(context) =>
|
|
1367
|
+
(context) => chunkORNLCBNE_cjs.paintSlideBackground(context, width, height, own, look.media)
|
|
2784
1368
|
)
|
|
2785
1369
|
};
|
|
2786
1370
|
} else {
|
|
2787
1371
|
page.background = { data: background };
|
|
2788
1372
|
}
|
|
2789
1373
|
if (slide.notes?.trim()) page.addNotes(slide.notes);
|
|
2790
|
-
const geometry =
|
|
1374
|
+
const geometry = chunkORNLCBNE_cjs.slideGeometry(slide, {
|
|
2791
1375
|
labels: look.labels,
|
|
2792
1376
|
logo: look.theme.logo?.corner ?? null
|
|
2793
1377
|
});
|
|
@@ -2795,7 +1379,7 @@ async function buildPptx(deck, look) {
|
|
|
2795
1379
|
for (const item of slide.items) {
|
|
2796
1380
|
const clip = deck.clips.find((entry) => entry.id === item.clipId);
|
|
2797
1381
|
if (!clip) continue;
|
|
2798
|
-
const frame = { ...item.frame, h:
|
|
1382
|
+
const frame = { ...item.frame, h: chunkORNLCBNE_cjs.frameHeight(item.frame, clip.aspect) };
|
|
2799
1383
|
if (clip.plain) {
|
|
2800
1384
|
const source = clip.kind === "image" ? await createImageBitmap(clip.source) : null;
|
|
2801
1385
|
const scale = source ? Math.min(1, 2400 / Math.max(1, clip.rect.w * source.width)) : 1.5;
|
|
@@ -2827,13 +1411,13 @@ async function buildPptx(deck, look) {
|
|
|
2827
1411
|
altText: clip.caption,
|
|
2828
1412
|
shadow: { type: "outer", blur: 10, offset: 3, angle: 90, color: "000000", opacity: 0.45 }
|
|
2829
1413
|
});
|
|
2830
|
-
const label =
|
|
1414
|
+
const label = chunkORNLCBNE_cjs.clipLabel(clip, look.columnValues);
|
|
2831
1415
|
if (look.labels && label) {
|
|
2832
1416
|
page.addText(label, {
|
|
2833
1417
|
...box({ x: frame.x, y: frame.y + frame.h + 8e-3, w: frame.w, h: 0.045 }),
|
|
2834
|
-
fontFace:
|
|
1418
|
+
fontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
|
|
2835
1419
|
fontSize: toPoints(0.017),
|
|
2836
|
-
color: hex2(
|
|
1420
|
+
color: hex2(chunkORNLCBNE_cjs.TEXT_COLORS.muted),
|
|
2837
1421
|
margin: 0,
|
|
2838
1422
|
valign: "top",
|
|
2839
1423
|
fit: "shrink"
|
|
@@ -2846,12 +1430,12 @@ async function buildPptx(deck, look) {
|
|
|
2846
1430
|
if (geometry.rule) {
|
|
2847
1431
|
page.addShape(pptx.ShapeType.rect, {
|
|
2848
1432
|
...box(geometry.rule),
|
|
2849
|
-
fill: { color: hex2(
|
|
2850
|
-
line: { color: hex2(
|
|
1433
|
+
fill: { color: hex2(chunkORNLCBNE_cjs.accentColor(look.theme.accent)) },
|
|
1434
|
+
line: { color: hex2(chunkORNLCBNE_cjs.accentColor(look.theme.accent)), width: 0 }
|
|
2851
1435
|
});
|
|
2852
1436
|
}
|
|
2853
1437
|
}
|
|
2854
|
-
const lines =
|
|
1438
|
+
const lines = chunkORNLCBNE_cjs.textLines(slide.points);
|
|
2855
1439
|
if (geometry.text && lines.length) {
|
|
2856
1440
|
const text = geometry.text;
|
|
2857
1441
|
page.addText(
|
|
@@ -2885,7 +1469,7 @@ async function buildPptx(deck, look) {
|
|
|
2885
1469
|
}
|
|
2886
1470
|
}
|
|
2887
1471
|
const deckFile = await pptx.write({ outputType: "blob" });
|
|
2888
|
-
return accentBullets(deckFile,
|
|
1472
|
+
return accentBullets(deckFile, chunkORNLCBNE_cjs.accentColor(look.theme.accent));
|
|
2889
1473
|
}
|
|
2890
1474
|
async function accentBullets(deck, accent) {
|
|
2891
1475
|
const { default: JSZip } = await import('jszip');
|
|
@@ -3416,7 +2000,7 @@ function renditionClip(deck, part, area, what) {
|
|
|
3416
2000
|
fileName: fileName ?? "Presentation.pptx",
|
|
3417
2001
|
page: part.page,
|
|
3418
2002
|
rect,
|
|
3419
|
-
aspect: frame.w *
|
|
2003
|
+
aspect: frame.w * chunkORNLCBNE_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
|
|
3420
2004
|
caption: "",
|
|
3421
2005
|
plain: true
|
|
3422
2006
|
});
|
|
@@ -3435,7 +2019,7 @@ function readParagraphs(body, chain, deck, defaults, fontScale, fallback = []) {
|
|
|
3435
2019
|
defaults.color ? { color: defaults.color } : {},
|
|
3436
2020
|
levelStyle(fallback, level, theme)
|
|
3437
2021
|
]);
|
|
3438
|
-
const
|
|
2022
|
+
const runStyle = (rPr) => {
|
|
3439
2023
|
const s = merge([readRunProps(rPr, theme), style]);
|
|
3440
2024
|
const color = s.color ?? defaults.base;
|
|
3441
2025
|
return {
|
|
@@ -3458,13 +2042,13 @@ function readParagraphs(body, chain, deck, defaults, fontScale, fallback = []) {
|
|
|
3458
2042
|
for (const child of kids(p)) {
|
|
3459
2043
|
if (child.localName === "r" || child.localName === "fld") {
|
|
3460
2044
|
const text = kid(child, "t")?.textContent ?? "";
|
|
3461
|
-
runs.push({ ...
|
|
2045
|
+
runs.push({ ...runStyle(kid(child, "rPr")), text });
|
|
3462
2046
|
} else if (child.localName === "br") {
|
|
3463
|
-
paragraphs.push(shape(runs.length ? runs : [{ ...
|
|
2047
|
+
paragraphs.push(shape(runs.length ? runs : [{ ...runStyle(kid(child, "rPr")), text: "" }]));
|
|
3464
2048
|
runs = [];
|
|
3465
2049
|
}
|
|
3466
2050
|
}
|
|
3467
|
-
if (!runs.length) runs = [{ ...
|
|
2051
|
+
if (!runs.length) runs = [{ ...runStyle(kid(p, "endParaRPr")), text: "" }];
|
|
3468
2052
|
paragraphs.push(shape(runs));
|
|
3469
2053
|
}
|
|
3470
2054
|
while (paragraphs.length > 1 && !paragraphs[paragraphs.length - 1].runs.some((run) => run.text.trim())) {
|
|
@@ -3555,7 +2139,7 @@ async function readShape(shape, transform, deck, part, inherit, built) {
|
|
|
3555
2139
|
fileName: target?.target.split("/").pop() ?? "Picture",
|
|
3556
2140
|
page: 1,
|
|
3557
2141
|
rect,
|
|
3558
|
-
aspect: frame.w *
|
|
2142
|
+
aspect: frame.w * chunkORNLCBNE_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
|
|
3559
2143
|
caption: "",
|
|
3560
2144
|
media: key,
|
|
3561
2145
|
plain: true
|
|
@@ -3778,7 +2362,7 @@ async function importPptx(bytes, options = {}) {
|
|
|
3778
2362
|
const cx = numAttr(size, "cx", 12192e3);
|
|
3779
2363
|
const cy = numAttr(size, "cy", 6858e3);
|
|
3780
2364
|
const deckAspect = cx / cy;
|
|
3781
|
-
const place = deckAspect <
|
|
2365
|
+
const place = deckAspect < chunkORNLCBNE_cjs.STAGE_ASPECT ? { w: deckAspect / chunkORNLCBNE_cjs.STAGE_ASPECT, h: 1, x: (1 - deckAspect / chunkORNLCBNE_cjs.STAGE_ASPECT) / 2, y: 0 } : { w: 1, h: chunkORNLCBNE_cjs.STAGE_ASPECT / deckAspect, x: 0, y: (1 - chunkORNLCBNE_cjs.STAGE_ASPECT / deckAspect) / 2 };
|
|
3782
2366
|
const slides = await slideParts(pkg);
|
|
3783
2367
|
const firstLayout = slides.length ? await pkg.related(slides[0].part, "/slideLayout") : null;
|
|
3784
2368
|
const firstMaster = firstLayout ? await pkg.related(firstLayout, "/slideMaster") : null;
|
|
@@ -3787,7 +2371,7 @@ async function importPptx(bytes, options = {}) {
|
|
|
3787
2371
|
theme: firstMaster ? await readTheme(pkg, firstMaster) : { scheme: {}, map: {}, majorFont: "Calibri", minorFont: "Calibri", lineWidths: [] },
|
|
3788
2372
|
slideSize: { cx, cy },
|
|
3789
2373
|
place,
|
|
3790
|
-
pointScale:
|
|
2374
|
+
pointScale: chunkORNLCBNE_cjs.SLIDE_POINTS.h * place.h / (cy / EMU_PER_POINT),
|
|
3791
2375
|
defaultText: kid(pres.documentElement, "defaultTextStyle"),
|
|
3792
2376
|
options,
|
|
3793
2377
|
clips: [],
|
|
@@ -3883,7 +2467,7 @@ async function importPptx(bytes, options = {}) {
|
|
|
3883
2467
|
version: 1,
|
|
3884
2468
|
title: options.title ?? (coreTitle?.trim() || "Presentation"),
|
|
3885
2469
|
captions: false,
|
|
3886
|
-
theme:
|
|
2470
|
+
theme: chunkORNLCBNE_cjs.DEFAULT_THEME,
|
|
3887
2471
|
clips: deck.clips,
|
|
3888
2472
|
slides: saved,
|
|
3889
2473
|
...Object.keys(deck.media).length ? { media: deck.media } : {}
|
|
@@ -3971,7 +2555,7 @@ async function presentationData(bytes) {
|
|
|
3971
2555
|
if (isZipBytes(bytes)) return readPptxPresentationData(bytes);
|
|
3972
2556
|
const isPdf = bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70;
|
|
3973
2557
|
if (!isPdf) return new TextDecoder().decode(bytes);
|
|
3974
|
-
const data = await documentTools.readPdfAttachment(bytes,
|
|
2558
|
+
const data = await documentTools.readPdfAttachment(bytes, chunkORNLCBNE_cjs.PRESENTATION_ATTACHMENT);
|
|
3975
2559
|
if (!data) {
|
|
3976
2560
|
throw new Error(
|
|
3977
2561
|
"This PDF has no editable presentation in it (it may have been changed outside ARBI)."
|
|
@@ -3980,7 +2564,7 @@ async function presentationData(bytes) {
|
|
|
3980
2564
|
return new TextDecoder().decode(data);
|
|
3981
2565
|
}
|
|
3982
2566
|
function current(withoutClips) {
|
|
3983
|
-
const state =
|
|
2567
|
+
const state = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
3984
2568
|
return withoutClips ? {
|
|
3985
2569
|
...state,
|
|
3986
2570
|
clips: [],
|
|
@@ -4002,18 +2586,18 @@ function usePresentationFiles() {
|
|
|
4002
2586
|
const state = current(withoutClips);
|
|
4003
2587
|
const deck = await buildPptx({ title, slides: state.slides, clips: state.clips }, lookOf(state));
|
|
4004
2588
|
const fingerprints = await slideFingerprints(deck);
|
|
4005
|
-
const data =
|
|
2589
|
+
const data = chunkORNLCBNE_cjs.serializePresentation({ ...state, title, fingerprints });
|
|
4006
2590
|
return writePptxPresentationData(deck, JSON.stringify(data, null, 2));
|
|
4007
2591
|
}, []);
|
|
4008
2592
|
const save = react.useCallback(
|
|
4009
2593
|
async (title, { asNew = false, template = false } = {}) => {
|
|
4010
2594
|
if (!arbi || !workspaceId) throw new Error("Open a workspace to save the presentation.");
|
|
4011
|
-
const state =
|
|
2595
|
+
const state = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
4012
2596
|
const versionOf = asNew || template ? null : state.savedId;
|
|
4013
2597
|
const deck = await buildFile(title, template);
|
|
4014
|
-
const file = new File([deck],
|
|
2598
|
+
const file = new File([deck], chunkORNLCBNE_cjs.presentationFileName(title), { type: PPTX_TYPE });
|
|
4015
2599
|
const result = await arbi.documents.upload([file], {
|
|
4016
|
-
folder: template ?
|
|
2600
|
+
folder: template ? chunkORNLCBNE_cjs.TEMPLATES_FOLDER : chunkORNLCBNE_cjs.PRESENTATIONS_FOLDER,
|
|
4017
2601
|
workspaceExtId: workspaceId,
|
|
4018
2602
|
...versionOf ? { versionOf } : {}
|
|
4019
2603
|
});
|
|
@@ -4038,8 +2622,8 @@ function usePresentationFiles() {
|
|
|
4038
2622
|
}
|
|
4039
2623
|
const pdf = await documentTools.imagesToPdf(pages, { title });
|
|
4040
2624
|
const result = await arbi.documents.upload(
|
|
4041
|
-
[new File([pdf], `${
|
|
4042
|
-
{ folder:
|
|
2625
|
+
[new File([pdf], `${chunkORNLCBNE_cjs.safeFileStem(title)}.pdf`, { type: "application/pdf" })],
|
|
2626
|
+
{ folder: chunkORNLCBNE_cjs.EXPORTS_FOLDER, workspaceExtId: workspaceId }
|
|
4043
2627
|
);
|
|
4044
2628
|
const id = result.doc_ext_ids?.[0];
|
|
4045
2629
|
if (!id) throw new Error("The PDF could not be saved.");
|
|
@@ -4054,10 +2638,10 @@ function usePresentationFiles() {
|
|
|
4054
2638
|
return docs.filter((doc) => {
|
|
4055
2639
|
const folder = doc.folder ?? "";
|
|
4056
2640
|
if (!ui.isPresentationFileName(doc.file_name, folder)) return false;
|
|
4057
|
-
return scope === "templates" ? folder ===
|
|
2641
|
+
return scope === "templates" ? folder === chunkORNLCBNE_cjs.TEMPLATES_FOLDER : folder.startsWith(chunkORNLCBNE_cjs.PRESENTATIONS_FOLDER) && folder !== chunkORNLCBNE_cjs.TEMPLATES_FOLDER && !folder.startsWith(chunkORNLCBNE_cjs.EXPORTS_FOLDER);
|
|
4058
2642
|
}).map((doc) => ({
|
|
4059
2643
|
id: doc.external_id,
|
|
4060
|
-
title:
|
|
2644
|
+
title: chunkORNLCBNE_cjs.presentationTitle(doc.file_name ?? ""),
|
|
4061
2645
|
updatedAt: doc.updated_at ?? doc.created_at ?? null
|
|
4062
2646
|
})).sort((a, b) => (a.updatedAt ?? "") < (b.updatedAt ?? "") ? 1 : -1);
|
|
4063
2647
|
},
|
|
@@ -4073,7 +2657,7 @@ function usePresentationFiles() {
|
|
|
4073
2657
|
const openedVersion = version ?? doc?.current_version ?? null;
|
|
4074
2658
|
if (text === null) {
|
|
4075
2659
|
const imported = await importPptx(bytes, {
|
|
4076
|
-
title:
|
|
2660
|
+
title: chunkORNLCBNE_cjs.presentationTitle(doc?.file_name ?? "Presentation.pptx"),
|
|
4077
2661
|
documentId: id,
|
|
4078
2662
|
version: version ?? doc?.current_version,
|
|
4079
2663
|
fileName: doc?.file_name ?? void 0
|
|
@@ -4085,7 +2669,7 @@ function usePresentationFiles() {
|
|
|
4085
2669
|
openedVersion
|
|
4086
2670
|
};
|
|
4087
2671
|
}
|
|
4088
|
-
let saved =
|
|
2672
|
+
let saved = chunkORNLCBNE_cjs.parsePresentation(text);
|
|
4089
2673
|
let changedOutside;
|
|
4090
2674
|
if (isZipBytes(bytes) && saved.slides.some((slide) => slide.fingerprint)) {
|
|
4091
2675
|
const now = await slideFingerprints(bytes);
|
|
@@ -4116,7 +2700,7 @@ function usePresentationFiles() {
|
|
|
4116
2700
|
const startFromTemplate = react.useCallback(
|
|
4117
2701
|
async (id) => {
|
|
4118
2702
|
const { saved } = await readSaved(id);
|
|
4119
|
-
|
|
2703
|
+
chunkORNLCBNE_cjs.usePresentation.getState().load({
|
|
4120
2704
|
title: "Untitled presentation",
|
|
4121
2705
|
savedId: null,
|
|
4122
2706
|
captions: saved.captions,
|
|
@@ -4193,7 +2777,7 @@ function usePresentationFiles() {
|
|
|
4193
2777
|
);
|
|
4194
2778
|
const kept = [];
|
|
4195
2779
|
const newIndex = opened.map((clip) => clip ? kept.push(clip) - 1 : -1);
|
|
4196
|
-
|
|
2780
|
+
chunkORNLCBNE_cjs.usePresentation.getState().load({
|
|
4197
2781
|
title: saved.title,
|
|
4198
2782
|
savedId: legacy ? null : id,
|
|
4199
2783
|
version: legacy ? null : openedVersion,
|
|
@@ -4267,7 +2851,7 @@ function useGenerateImageLaunch() {
|
|
|
4267
2851
|
throw new Error(failure || answer.trim() || "The image could not be generated.");
|
|
4268
2852
|
const source = await (await arbi.documents.download(documentId)).blob();
|
|
4269
2853
|
const fileName = `${prompt.split("\n")[0].slice(0, 60)}.png`;
|
|
4270
|
-
|
|
2854
|
+
chunkORNLCBNE_cjs.usePresentation.getState().addClip({
|
|
4271
2855
|
kind: "image",
|
|
4272
2856
|
documentId,
|
|
4273
2857
|
fileName,
|
|
@@ -4276,7 +2860,7 @@ function useGenerateImageLaunch() {
|
|
|
4276
2860
|
aspect: await aspectOf(source),
|
|
4277
2861
|
masks: [],
|
|
4278
2862
|
source,
|
|
4279
|
-
caption:
|
|
2863
|
+
caption: chunkORNLCBNE_cjs.mediaCaption(fileName)
|
|
4280
2864
|
});
|
|
4281
2865
|
},
|
|
4282
2866
|
[arbi, workspaceId]
|
|
@@ -4287,7 +2871,7 @@ function GenerateImageDialog({
|
|
|
4287
2871
|
onOpenChange,
|
|
4288
2872
|
referenceId
|
|
4289
2873
|
}) {
|
|
4290
|
-
const notify =
|
|
2874
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4291
2875
|
const { skills } = chunkUFT22LAB_cjs.useWorkflowDefinitions();
|
|
4292
2876
|
const run = useGenerateImageLaunch();
|
|
4293
2877
|
const workflows = react.useMemo(
|
|
@@ -4347,9 +2931,9 @@ function SavePresentationDialog({
|
|
|
4347
2931
|
onOpenChange,
|
|
4348
2932
|
mode = "save"
|
|
4349
2933
|
}) {
|
|
4350
|
-
const notify =
|
|
2934
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4351
2935
|
const { save, exportPdf } = usePresentationFiles();
|
|
4352
|
-
const current2 =
|
|
2936
|
+
const current2 = chunkORNLCBNE_cjs.usePresentation((s) => s.title);
|
|
4353
2937
|
const [title, setTitle] = react.useState(current2);
|
|
4354
2938
|
const [busy, setBusy] = react.useState(false);
|
|
4355
2939
|
const text = SAVE_TEXT[mode];
|
|
@@ -4419,7 +3003,7 @@ function OpenPresentationDialog({
|
|
|
4419
3003
|
templates = false
|
|
4420
3004
|
}) {
|
|
4421
3005
|
const { confirm } = chunkTKHCIHE2_cjs.useBlocksEnvironment();
|
|
4422
|
-
const notify =
|
|
3006
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4423
3007
|
const { list, startFromTemplate } = usePresentationFiles();
|
|
4424
3008
|
const [entries, setEntries] = react.useState(null);
|
|
4425
3009
|
const [opening, setOpening] = react.useState(null);
|
|
@@ -4434,7 +3018,7 @@ function OpenPresentationDialog({
|
|
|
4434
3018
|
onOpened(entry.id);
|
|
4435
3019
|
return;
|
|
4436
3020
|
}
|
|
4437
|
-
if (
|
|
3021
|
+
if (chunkORNLCBNE_cjs.usePresentation.getState().clips.length) {
|
|
4438
3022
|
const ok = await confirm({
|
|
4439
3023
|
title: "New from template",
|
|
4440
3024
|
message: "Replace the presentation that is open? Save it first to keep it.",
|
|
@@ -4485,8 +3069,8 @@ function OpenPresentationDialog({
|
|
|
4485
3069
|
}
|
|
4486
3070
|
var IMAGE_FILE = /\.(png|jpe?g|gif|webp|svg)$/i;
|
|
4487
3071
|
function ChooseLogoDialog({ open, onOpenChange }) {
|
|
4488
|
-
const setTheme =
|
|
4489
|
-
const corner =
|
|
3072
|
+
const setTheme = chunkORNLCBNE_cjs.usePresentation((s) => s.setTheme);
|
|
3073
|
+
const corner = chunkORNLCBNE_cjs.usePresentation((s) => s.theme.logo?.corner ?? "br");
|
|
4490
3074
|
const { data: documents } = react$1.useDocuments(void 0, { enabled: open });
|
|
4491
3075
|
const [picked, setPicked] = react.useState("");
|
|
4492
3076
|
const groups = react.useMemo(
|
|
@@ -4573,7 +3157,7 @@ function CropClipDialog({ clip, onOpenChange }) {
|
|
|
4573
3157
|
w: Math.min(1, area.width / natural.width),
|
|
4574
3158
|
h: Math.min(1, area.height / natural.height)
|
|
4575
3159
|
};
|
|
4576
|
-
|
|
3160
|
+
chunkORNLCBNE_cjs.usePresentation.getState().cropClip(clip.id, rect, area.width / area.height);
|
|
4577
3161
|
onOpenChange(false);
|
|
4578
3162
|
};
|
|
4579
3163
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -4622,8 +3206,8 @@ function CropClipDialog({ clip, onOpenChange }) {
|
|
|
4622
3206
|
var EMPTY = new Blob();
|
|
4623
3207
|
var NONE = "none";
|
|
4624
3208
|
function LabelColumnMenu({ columns }) {
|
|
4625
|
-
const labelColumn =
|
|
4626
|
-
const setLabelColumn =
|
|
3209
|
+
const labelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.labelColumn);
|
|
3210
|
+
const setLabelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.setLabelColumn);
|
|
4627
3211
|
if (!columns.length) return null;
|
|
4628
3212
|
const chosen = columns.find((column) => column.id === labelColumn);
|
|
4629
3213
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuSub, { children: [
|
|
@@ -4666,8 +3250,8 @@ function useLabelColumns(active) {
|
|
|
4666
3250
|
const workspaceId = react$1.useArbiSessionState((s) => s.workspaceId);
|
|
4667
3251
|
const { data: tags } = react$1.useTags(workspaceId, { enabled: active });
|
|
4668
3252
|
const { data: documents } = react$1.useDocuments(workspaceId, { enabled: active });
|
|
4669
|
-
const labelColumn =
|
|
4670
|
-
const documentIds =
|
|
3253
|
+
const labelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.labelColumn);
|
|
3254
|
+
const documentIds = chunkORNLCBNE_cjs.usePresentation((s) => s.clips.map((clip) => clip.documentId).join(" "));
|
|
4671
3255
|
const columns = react.useMemo(
|
|
4672
3256
|
() => (tags ?? []).filter((tag) => tag.kind !== "search" && VALUE_FORMATS.has(tag.tag_type.type)).map((tag) => ({ id: tag.external_id, name: tag.name })).sort((a, b) => a.name.localeCompare(b.name)),
|
|
4673
3257
|
[tags]
|
|
@@ -4682,23 +3266,23 @@ function useLabelColumns(active) {
|
|
|
4682
3266
|
if (note2) values[doc.external_id] = note2;
|
|
4683
3267
|
}
|
|
4684
3268
|
}
|
|
4685
|
-
|
|
3269
|
+
chunkORNLCBNE_cjs.usePresentation.getState().setColumnValues(values);
|
|
4686
3270
|
}, [labelColumn, documentIds, documents]);
|
|
4687
3271
|
return columns;
|
|
4688
3272
|
}
|
|
4689
3273
|
function usePresentationController(active) {
|
|
4690
3274
|
const session = react$1.useArbiSessionStore();
|
|
4691
|
-
const notify =
|
|
3275
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4692
3276
|
const { save, canSave } = usePresentationFiles();
|
|
4693
3277
|
const labelColumns = useLabelColumns(active);
|
|
4694
3278
|
const [dialog, setDialog] = react.useState(null);
|
|
4695
3279
|
const [reference, setReference] = react.useState(null);
|
|
4696
3280
|
const [cropping, setCropping] = react.useState(null);
|
|
4697
|
-
const cropClip =
|
|
3281
|
+
const cropClip = chunkORNLCBNE_cjs.usePresentation((s) => s.clips.find((c) => c.id === cropping) ?? null);
|
|
4698
3282
|
const [saving, setSaving] = react.useState(false);
|
|
4699
3283
|
const close = (open) => !open && setDialog(null);
|
|
4700
3284
|
const quickSave = react.useCallback(async () => {
|
|
4701
|
-
const { savedId, title } =
|
|
3285
|
+
const { savedId, title } = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
4702
3286
|
if (!savedId) return setDialog("save");
|
|
4703
3287
|
setSaving(true);
|
|
4704
3288
|
try {
|
|
@@ -4732,7 +3316,7 @@ function usePresentationController(active) {
|
|
|
4732
3316
|
{
|
|
4733
3317
|
open: dialog === "open" || dialog === "fromTemplate",
|
|
4734
3318
|
templates: dialog === "fromTemplate",
|
|
4735
|
-
onOpened: (id) =>
|
|
3319
|
+
onOpened: (id) => chunkWVZLAAIZ_cjs.editPresentation(session, id ? { kind: "open", documentId: id } : { kind: "new" }),
|
|
4736
3320
|
onOpenChange: close
|
|
4737
3321
|
}
|
|
4738
3322
|
),
|
|
@@ -4774,7 +3358,7 @@ function usePresentationController(active) {
|
|
|
4774
3358
|
trayStart: canSave && /* @__PURE__ */ jsxRuntime.jsx(GenerateTile, { onClick: () => generate(null) }),
|
|
4775
3359
|
onChooseLogo: canSave ? () => setDialog("logo") : void 0,
|
|
4776
3360
|
onEditImage: (clipId) => {
|
|
4777
|
-
const clip =
|
|
3361
|
+
const clip = chunkORNLCBNE_cjs.usePresentation.getState().clips.find((c) => c.id === clipId);
|
|
4778
3362
|
if (clip) generate(clip.documentId);
|
|
4779
3363
|
},
|
|
4780
3364
|
onCropImage: setCropping
|
|
@@ -4782,9 +3366,8 @@ function usePresentationController(active) {
|
|
|
4782
3366
|
return { editor, dialogs };
|
|
4783
3367
|
}
|
|
4784
3368
|
|
|
4785
|
-
exports.PresentationStage = PresentationStage;
|
|
4786
3369
|
exports.SlidesEditor = SlidesEditor;
|
|
4787
3370
|
exports.usePresentationController = usePresentationController;
|
|
4788
3371
|
exports.usePresentationFiles = usePresentationFiles;
|
|
4789
|
-
//# sourceMappingURL=chunk-
|
|
4790
|
-
//# sourceMappingURL=chunk-
|
|
3372
|
+
//# sourceMappingURL=chunk-H236SNEV.cjs.map
|
|
3373
|
+
//# sourceMappingURL=chunk-H236SNEV.cjs.map
|