@arbidocs/blocks 0.5.123 → 0.5.125
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/ConnectedCallDock-XJOYVVAH.cjs +6 -6
- package/dist/ConnectedCallRoom-CUDYAPQK.cjs +6 -6
- package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs → ConnectedNativeDocxComparison-7QQ55JIO.cjs} +13 -13
- package/dist/{ConnectedNativeDocxComparison-QKHCYD6W.cjs.map → ConnectedNativeDocxComparison-7QQ55JIO.cjs.map} +1 -1
- package/dist/{ConnectedPresentation-5DOJ35XL.cjs → ConnectedPresentation-L32JPRFI.cjs} +30 -156
- package/dist/ConnectedPresentation-L32JPRFI.cjs.map +1 -0
- package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs → ConnectedProductionSetDialog-4EAY6KAZ.cjs} +3 -3
- package/dist/{ConnectedProductionSetDialog-LHB4VQWC.cjs.map → ConnectedProductionSetDialog-4EAY6KAZ.cjs.map} +1 -1
- package/dist/{ConnectedSlidesTab-7YMEDGUU.cjs → ConnectedSlidesTab-P7GGNUTO.cjs} +31 -29
- package/dist/ConnectedSlidesTab-P7GGNUTO.cjs.map +1 -0
- package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs → ConnectedStreamedWordArtifact-7NJ3N52V.cjs} +13 -13
- package/dist/{ConnectedStreamedWordArtifact-AG62232A.cjs.map → ConnectedStreamedWordArtifact-7NJ3N52V.cjs.map} +1 -1
- package/dist/{DocumentReviewCard-M53XFLI2.cjs → DocumentReviewCard-BFPOFQXI.cjs} +16 -16
- package/dist/{DocumentReviewCard-M53XFLI2.cjs.map → DocumentReviewCard-BFPOFQXI.cjs.map} +1 -1
- package/dist/{FilesViewerDialog-2QCCRWF2.cjs → FilesViewerDialog-MHUVEZ7M.cjs} +35 -32
- package/dist/FilesViewerDialog-MHUVEZ7M.cjs.map +1 -0
- package/dist/{NativeDocxEditor-2LQY2CTV.cjs → NativeDocxEditor-SIRYPMBN.cjs} +6 -6
- package/dist/{NativeDocxEditor-2LQY2CTV.cjs.map → NativeDocxEditor-SIRYPMBN.cjs.map} +1 -1
- package/dist/SpotlightStrip-ED22UYTM.cjs +398 -0
- package/dist/SpotlightStrip-ED22UYTM.cjs.map +1 -0
- package/dist/{WorkspaceTableView-3XYAV4BV.cjs → WorkspaceTableView-MIFYXV3G.cjs} +8 -8
- package/dist/{WorkspaceTableView-3XYAV4BV.cjs.map → WorkspaceTableView-MIFYXV3G.cjs.map} +1 -1
- package/dist/agents/index.cjs +216 -216
- package/dist/ai-IEIR7SC2.cjs +3 -3
- package/dist/auth/index.cjs +1 -1
- package/dist/calls/index.cjs +2 -2
- package/dist/chat/index.cjs +6 -6
- package/dist/{chunk-GNZAH6UI.cjs → chunk-2K6IMIVL.cjs} +3 -3
- package/dist/{chunk-GNZAH6UI.cjs.map → chunk-2K6IMIVL.cjs.map} +1 -1
- package/dist/{chunk-NQML7IUC.cjs → chunk-3UP32FM3.cjs} +6 -6
- package/dist/{chunk-NQML7IUC.cjs.map → chunk-3UP32FM3.cjs.map} +1 -1
- package/dist/chunk-3ZZZO4F7.cjs +145 -0
- package/dist/chunk-3ZZZO4F7.cjs.map +1 -0
- package/dist/{chunk-L4CIFLCU.cjs → chunk-4LP5MJGQ.cjs} +4 -4
- package/dist/{chunk-L4CIFLCU.cjs.map → chunk-4LP5MJGQ.cjs.map} +1 -1
- package/dist/{chunk-JD2HX2BR.cjs → chunk-6JMW3IJ2.cjs} +152 -155
- package/dist/chunk-6JMW3IJ2.cjs.map +1 -0
- package/dist/{chunk-WV7BCGCK.cjs → chunk-7RJZIPLE.cjs} +33 -33
- package/dist/{chunk-WV7BCGCK.cjs.map → chunk-7RJZIPLE.cjs.map} +1 -1
- package/dist/{chunk-WFMWKPGY.cjs → chunk-ADPRIBSH.cjs} +9 -33
- package/dist/chunk-ADPRIBSH.cjs.map +1 -0
- package/dist/{chunk-7NLO7ASW.cjs → chunk-AISYXX4M.cjs} +4 -4
- package/dist/{chunk-7NLO7ASW.cjs.map → chunk-AISYXX4M.cjs.map} +1 -1
- package/dist/{chunk-5QERK4PK.cjs → chunk-AS6QZETU.cjs} +35 -35
- package/dist/{chunk-5QERK4PK.cjs.map → chunk-AS6QZETU.cjs.map} +1 -1
- package/dist/{chunk-V6MW7B4B.cjs → chunk-B3R62764.cjs} +6 -6
- package/dist/{chunk-V6MW7B4B.cjs.map → chunk-B3R62764.cjs.map} +1 -1
- package/dist/{chunk-VKH3BEZE.cjs → chunk-BLIO3B7Z.cjs} +3 -3
- package/dist/{chunk-VKH3BEZE.cjs.map → chunk-BLIO3B7Z.cjs.map} +1 -1
- package/dist/{chunk-46P7IDBX.cjs → chunk-CQ2RJYE2.cjs} +4 -4
- package/dist/chunk-CQ2RJYE2.cjs.map +1 -0
- package/dist/{chunk-MXBXZXXQ.cjs → chunk-ENOPKX7E.cjs} +3 -3
- package/dist/{chunk-MXBXZXXQ.cjs.map → chunk-ENOPKX7E.cjs.map} +1 -1
- package/dist/{chunk-2CSLFAGF.cjs → chunk-GAMRVB3I.cjs} +4 -3
- package/dist/chunk-GAMRVB3I.cjs.map +1 -0
- package/dist/chunk-IRGRMJPP.cjs +18 -0
- package/dist/{chunk-SDRYSLOX.cjs.map → chunk-IRGRMJPP.cjs.map} +1 -1
- package/dist/{chunk-ADDQKZ5I.cjs → chunk-J3FFSEKO.cjs} +4 -4
- package/dist/{chunk-ADDQKZ5I.cjs.map → chunk-J3FFSEKO.cjs.map} +1 -1
- 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-ALK3PUUB.cjs → chunk-L6HTZIBD.cjs} +3 -3
- package/dist/{chunk-ALK3PUUB.cjs.map → chunk-L6HTZIBD.cjs.map} +1 -1
- package/dist/chunk-MVXHTAJ4.cjs +111 -0
- package/dist/chunk-MVXHTAJ4.cjs.map +1 -0
- package/dist/{chunk-OHHKBURG.cjs → chunk-OGK377NL.cjs} +33 -33
- package/dist/{chunk-OHHKBURG.cjs.map → chunk-OGK377NL.cjs.map} +1 -1
- package/dist/{chunk-T73BHNQX.cjs → chunk-OHWHYVKG.cjs} +3 -3
- package/dist/{chunk-T73BHNQX.cjs.map → chunk-OHWHYVKG.cjs.map} +1 -1
- package/dist/{chunk-4TTX6ZNS.cjs → chunk-ORNLCBNE.cjs} +24 -2
- package/dist/chunk-ORNLCBNE.cjs.map +1 -0
- package/dist/{chunk-MLA2BJ2Y.cjs → chunk-PSB64T43.cjs} +28 -28
- package/dist/{chunk-MLA2BJ2Y.cjs.map → chunk-PSB64T43.cjs.map} +1 -1
- package/dist/{chunk-COD5ENHK.cjs → chunk-PVJ5ODDB.cjs} +4 -4
- package/dist/{chunk-COD5ENHK.cjs.map → chunk-PVJ5ODDB.cjs.map} +1 -1
- package/dist/{chunk-7557LDAN.cjs → chunk-PWBRE7JA.cjs} +5 -5
- package/dist/{chunk-7557LDAN.cjs.map → chunk-PWBRE7JA.cjs.map} +1 -1
- package/dist/{chunk-7PN3YENO.cjs → chunk-QIK7E6VF.cjs} +4 -4
- package/dist/{chunk-7PN3YENO.cjs.map → chunk-QIK7E6VF.cjs.map} +1 -1
- package/dist/{chunk-DWMWEALB.cjs → chunk-TSFNLY3K.cjs} +143 -1634
- package/dist/chunk-TSFNLY3K.cjs.map +1 -0
- package/dist/{chunk-YGBHY67W.cjs → chunk-UA7HOLAZ.cjs} +5 -5
- package/dist/{chunk-YGBHY67W.cjs.map → chunk-UA7HOLAZ.cjs.map} +1 -1
- package/dist/{chunk-KXIRVKCJ.cjs → chunk-UUENH4BJ.cjs} +3 -3
- package/dist/{chunk-KXIRVKCJ.cjs.map → chunk-UUENH4BJ.cjs.map} +1 -1
- package/dist/chunk-WVZLAAIZ.cjs +31 -0
- package/dist/chunk-WVZLAAIZ.cjs.map +1 -0
- package/dist/{chunk-E3L5DB5F.cjs → chunk-YOEP3I4V.cjs} +5 -5
- package/dist/{chunk-E3L5DB5F.cjs.map → chunk-YOEP3I4V.cjs.map} +1 -1
- package/dist/{chunk-SNPK3R3O.cjs → chunk-YVO6Z5BS.cjs} +10 -10
- package/dist/{chunk-SNPK3R3O.cjs.map → chunk-YVO6Z5BS.cjs.map} +1 -1
- package/dist/chunk-ZZZITHGK.cjs +119 -0
- package/dist/chunk-ZZZITHGK.cjs.map +1 -0
- package/dist/connect/docx.cjs +17 -17
- package/dist/connect/index.cjs +994 -994
- package/dist/connect/viewer.cjs +28 -25
- 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/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 +1 -1
- package/dist/connection/viewer/ConnectedDocumentViewer.js.map +2 -2
- package/dist/connection/viewer/VersionDropdown.js +1 -1
- package/dist/connection/viewer/VersionDropdown.js.map +1 -1
- package/dist/connection/viewer/ViewerPdfPane.js +2 -0
- package/dist/connection/viewer/ViewerPdfPane.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/pdf/usePassageTextFallback.d.ts +12 -0
- package/dist/connection/viewer/pdf/usePassageTextFallback.js +30 -0
- package/dist/connection/viewer/pdf/usePassageTextFallback.js.map +7 -0
- package/dist/connection/viewer/pdf/usePdfPassageHighlights.js +2 -11
- package/dist/connection/viewer/pdf/usePdfPassageHighlights.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/connection/viewer/useViewerTabs.js +13 -1
- package/dist/connection/viewer/useViewerTabs.js.map +2 -2
- package/dist/document-tools/DocumentToolButtons.js +1 -1
- package/dist/document-tools/DocumentToolButtons.js.map +1 -1
- package/dist/document-tools/index.cjs +20 -20
- package/dist/docx/DocxCommandMenu.js +2 -1
- package/dist/docx/DocxCommandMenu.js.map +2 -2
- package/dist/docx/index.cjs +38 -38
- package/dist/embed/index.cjs +20 -20
- package/dist/facts/index.cjs +64 -64
- package/dist/files/index.cjs +223 -223
- package/dist/index.cjs +521 -521
- 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/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/SpotlightView.d.ts +19 -0
- package/dist/presentation/SpotlightView.js +180 -0
- package/dist/presentation/SpotlightView.js.map +7 -0
- 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/settings/index.cjs +146 -146
- package/dist/site/index.cjs +6 -6
- package/dist/studio/index.cjs +9 -9
- package/dist/styles.css +1 -1
- package/dist/workflow-canvas/index.cjs +35 -35
- 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-5DOJ35XL.cjs.map +0 -1
- package/dist/ConnectedSlidesTab-7YMEDGUU.cjs.map +0 -1
- package/dist/FilesViewerDialog-2QCCRWF2.cjs.map +0 -1
- package/dist/chunk-2CSLFAGF.cjs.map +0 -1
- package/dist/chunk-46P7IDBX.cjs.map +0 -1
- package/dist/chunk-4TTX6ZNS.cjs.map +0 -1
- package/dist/chunk-DWMWEALB.cjs.map +0 -1
- package/dist/chunk-JD2HX2BR.cjs.map +0 -1
- package/dist/chunk-SDRYSLOX.cjs +0 -18
- 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
|
|
6
|
+
var chunkWVZLAAIZ_cjs = require('./chunk-WVZLAAIZ.cjs');
|
|
7
|
+
var chunkADPRIBSH_cjs = require('./chunk-ADPRIBSH.cjs');
|
|
8
|
+
var chunkORNLCBNE_cjs = require('./chunk-ORNLCBNE.cjs');
|
|
6
9
|
var chunk2F57IO7S_cjs = require('./chunk-2F57IO7S.cjs');
|
|
7
10
|
var chunkUFT22LAB_cjs = require('./chunk-UFT22LAB.cjs');
|
|
8
|
-
var chunkWFMWKPGY_cjs = require('./chunk-WFMWKPGY.cjs');
|
|
9
|
-
var chunk4TTX6ZNS_cjs = require('./chunk-4TTX6ZNS.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,1274 +479,6 @@ function Notice() {
|
|
|
701
479
|
}
|
|
702
480
|
);
|
|
703
481
|
}
|
|
704
|
-
var PAN_STEP = 0.1;
|
|
705
|
-
var MAX_ZOOM = 800;
|
|
706
|
-
var HOLD_DELAY = 350;
|
|
707
|
-
var HOLD_EVERY = 90;
|
|
708
|
-
var BUTTON = "flex size-7 items-center justify-center rounded-full border border-border bg-background text-foreground hover:bg-muted focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:opacity-30 pointer-coarse:size-11";
|
|
709
|
-
function HoldButton({
|
|
710
|
-
label,
|
|
711
|
-
disabled,
|
|
712
|
-
onStep,
|
|
713
|
-
className,
|
|
714
|
-
children
|
|
715
|
-
}) {
|
|
716
|
-
const timer = react.useRef(null);
|
|
717
|
-
const stop = () => {
|
|
718
|
-
if (timer.current) clearTimeout(timer.current);
|
|
719
|
-
timer.current = null;
|
|
720
|
-
};
|
|
721
|
-
react.useEffect(() => stop, []);
|
|
722
|
-
react.useEffect(() => {
|
|
723
|
-
if (disabled) stop();
|
|
724
|
-
}, [disabled]);
|
|
725
|
-
const start = (event) => {
|
|
726
|
-
event.stopPropagation();
|
|
727
|
-
if (disabled || event.button !== 0) return;
|
|
728
|
-
onStep();
|
|
729
|
-
const repeat = () => {
|
|
730
|
-
onStep();
|
|
731
|
-
timer.current = setTimeout(repeat, HOLD_EVERY);
|
|
732
|
-
};
|
|
733
|
-
timer.current = setTimeout(repeat, HOLD_DELAY);
|
|
734
|
-
};
|
|
735
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
736
|
-
"button",
|
|
737
|
-
{
|
|
738
|
-
type: "button",
|
|
739
|
-
className: ui.cn(BUTTON, className),
|
|
740
|
-
title: label,
|
|
741
|
-
"aria-label": label,
|
|
742
|
-
disabled,
|
|
743
|
-
onPointerDown: start,
|
|
744
|
-
onPointerUp: stop,
|
|
745
|
-
onPointerLeave: stop,
|
|
746
|
-
onPointerCancel: stop,
|
|
747
|
-
onClick: (event) => event.detail === 0 && onStep(),
|
|
748
|
-
children
|
|
749
|
-
}
|
|
750
|
-
);
|
|
751
|
-
}
|
|
752
|
-
function ClipViewControls({ clip }) {
|
|
753
|
-
const { panClip, setClipZoom } = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
754
|
-
const { rect } = clip;
|
|
755
|
-
const zoomBase = clip.zoomBase ?? rect.w;
|
|
756
|
-
const minZoom = Math.min(100, Math.floor(zoomBase / Math.min(1, rect.w / rect.h) * 100));
|
|
757
|
-
const pan = (dx, dy) => () => panClip(clip.id, dx * rect.w, dy * rect.h);
|
|
758
|
-
const zoom = Math.round(zoomBase / rect.w * 100);
|
|
759
|
-
const edge = 1e-6;
|
|
760
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
761
|
-
"div",
|
|
762
|
-
{
|
|
763
|
-
className: "flex flex-col items-center gap-2 p-1",
|
|
764
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
765
|
-
"data-testid": "clip-view-controls",
|
|
766
|
-
children: [
|
|
767
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-3 grid-rows-3 place-items-center gap-0.5", children: [
|
|
768
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
769
|
-
HoldButton,
|
|
770
|
-
{
|
|
771
|
-
label: "Show more above",
|
|
772
|
-
disabled: rect.y <= edge,
|
|
773
|
-
onStep: pan(0, -PAN_STEP),
|
|
774
|
-
className: "col-start-2 row-start-1",
|
|
775
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronUp, { className: "size-4" })
|
|
776
|
-
}
|
|
777
|
-
),
|
|
778
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
779
|
-
HoldButton,
|
|
780
|
-
{
|
|
781
|
-
label: "Show more on the left",
|
|
782
|
-
disabled: rect.x <= edge,
|
|
783
|
-
onStep: pan(-PAN_STEP, 0),
|
|
784
|
-
className: "col-start-1 row-start-2",
|
|
785
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronLeft, { className: "size-4" })
|
|
786
|
-
}
|
|
787
|
-
),
|
|
788
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
789
|
-
HoldButton,
|
|
790
|
-
{
|
|
791
|
-
label: "Show more on the right",
|
|
792
|
-
disabled: rect.x + rect.w >= 1 - edge,
|
|
793
|
-
onStep: pan(PAN_STEP, 0),
|
|
794
|
-
className: "col-start-3 row-start-2",
|
|
795
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronRight, { className: "size-4" })
|
|
796
|
-
}
|
|
797
|
-
),
|
|
798
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
799
|
-
HoldButton,
|
|
800
|
-
{
|
|
801
|
-
label: "Show more below",
|
|
802
|
-
disabled: rect.y + rect.h >= 1 - edge,
|
|
803
|
-
onStep: pan(0, PAN_STEP),
|
|
804
|
-
className: "col-start-2 row-start-3",
|
|
805
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ChevronDown, { className: "size-4" })
|
|
806
|
-
}
|
|
807
|
-
)
|
|
808
|
-
] }),
|
|
809
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { "data-testid": "clip-zoom-control", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
810
|
-
chunk5GCCUXMT_cjs.ZoomSlider,
|
|
811
|
-
{
|
|
812
|
-
value: zoom,
|
|
813
|
-
min: minZoom,
|
|
814
|
-
max: Math.max(MAX_ZOOM, zoom),
|
|
815
|
-
zoomOutStep: 25,
|
|
816
|
-
onChange: (value) => setClipZoom(clip.id, value),
|
|
817
|
-
label: "Zoom",
|
|
818
|
-
valueLabel: /* @__PURE__ */ jsxRuntime.jsxs("span", { "data-testid": "clip-zoom", children: [
|
|
819
|
-
zoom,
|
|
820
|
-
"%"
|
|
821
|
-
] }),
|
|
822
|
-
className: "pointer-coarse:h-11",
|
|
823
|
-
sliderClassName: "w-28"
|
|
824
|
-
}
|
|
825
|
-
) })
|
|
826
|
-
]
|
|
827
|
-
}
|
|
828
|
-
);
|
|
829
|
-
}
|
|
830
|
-
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";
|
|
831
|
-
var SIZES = [
|
|
832
|
-
{ command: "fit", label: "Fit the slide", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "size-4" }) },
|
|
833
|
-
{ command: "fullWidth", label: "Full width", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoveHorizontal, { className: "size-4" }) },
|
|
834
|
-
{ command: "fullHeight", label: "Full height", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoveVertical, { className: "size-4" }) }
|
|
835
|
-
];
|
|
836
|
-
var ALIGNMENTS = [
|
|
837
|
-
{ alignment: "left", label: "Left", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignStartVertical, { className: "size-4" }) },
|
|
838
|
-
{ alignment: "centre", label: "Centre", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterVertical, { className: "size-4" }) },
|
|
839
|
-
{ alignment: "right", label: "Right", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignEndVertical, { className: "size-4" }) },
|
|
840
|
-
{ alignment: "top", label: "Top", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignStartHorizontal, { className: "size-4" }) },
|
|
841
|
-
{ alignment: "middle", label: "Middle", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenterHorizontal, { className: "size-4" }) },
|
|
842
|
-
{ alignment: "bottom", label: "Bottom", icon: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignEndHorizontal, { className: "size-4" }) }
|
|
843
|
-
];
|
|
844
|
-
function Action({
|
|
845
|
-
label,
|
|
846
|
-
onClick,
|
|
847
|
-
children
|
|
848
|
-
}) {
|
|
849
|
-
return /* @__PURE__ */ jsxRuntime.jsx("button", { type: "button", className: ACTION, title: label, "aria-label": label, onClick, children });
|
|
850
|
-
}
|
|
851
|
-
function ClipActionBar({
|
|
852
|
-
clipId,
|
|
853
|
-
at: at2,
|
|
854
|
-
onRemoved,
|
|
855
|
-
onEditImage,
|
|
856
|
-
onCropImage
|
|
857
|
-
}) {
|
|
858
|
-
const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
859
|
-
const clip = chunk4TTX6ZNS_cjs.usePresentation((state) => state.clips.find((entry) => entry.id === clipId));
|
|
860
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
861
|
-
"div",
|
|
862
|
-
{
|
|
863
|
-
role: "toolbar",
|
|
864
|
-
"aria-label": "Clip",
|
|
865
|
-
className: "absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md",
|
|
866
|
-
style: { left: `${at2.x * 100}%`, top: `calc(${at2.y * 100}% - 40px)` },
|
|
867
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
868
|
-
"data-testid": "clip-action-bar",
|
|
869
|
-
children: [
|
|
870
|
-
/* @__PURE__ */ jsxRuntime.jsx(Action, { label: "Fit the slide", onClick: () => actions.applyFrame(clipId, "fit"), children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Maximize2, { className: "size-4" }) }),
|
|
871
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
872
|
-
/* @__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" }) }) }),
|
|
873
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuContent, { align: "start", children: ALIGNMENTS.map(({ alignment, label, icon }) => /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.align(clipId, alignment), children: [
|
|
874
|
-
icon,
|
|
875
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: label })
|
|
876
|
-
] }, alignment)) })
|
|
877
|
-
] }),
|
|
878
|
-
clip && /* @__PURE__ */ jsxRuntime.jsxs(ui.Popover, { children: [
|
|
879
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.PopoverTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
880
|
-
"button",
|
|
881
|
-
{
|
|
882
|
-
type: "button",
|
|
883
|
-
className: ACTION,
|
|
884
|
-
title: "View: scroll or zoom what the clip shows (or scroll over it)",
|
|
885
|
-
"aria-label": "View",
|
|
886
|
-
"data-testid": "clip-view-button",
|
|
887
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ZoomIn, { className: "size-4" })
|
|
888
|
-
}
|
|
889
|
-
) }),
|
|
890
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.PopoverContent, { align: "start", className: "w-auto p-2", children: /* @__PURE__ */ jsxRuntime.jsx(ClipViewControls, { clip }) })
|
|
891
|
-
] }),
|
|
892
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
893
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
894
|
-
"button",
|
|
895
|
-
{
|
|
896
|
-
type: "button",
|
|
897
|
-
className: ACTION,
|
|
898
|
-
title: "More",
|
|
899
|
-
"aria-label": "More",
|
|
900
|
-
"data-testid": "clip-more-menu",
|
|
901
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4" })
|
|
902
|
-
}
|
|
903
|
-
) }),
|
|
904
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "start", children: [
|
|
905
|
-
SIZES.filter(({ command }) => command !== "fit").map(({ command, label, icon }) => /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.applyFrame(clipId, command), children: [
|
|
906
|
-
icon,
|
|
907
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: label })
|
|
908
|
-
] }, command)),
|
|
909
|
-
onCropImage && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onCropImage, children: [
|
|
910
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Crop, { className: "size-4" }),
|
|
911
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Crop" })
|
|
912
|
-
] }),
|
|
913
|
-
onEditImage && /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: onEditImage, children: [
|
|
914
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "size-4" }),
|
|
915
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Edit image" })
|
|
916
|
-
] }),
|
|
917
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {}),
|
|
918
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.bringToFront(clipId), children: [
|
|
919
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.BringToFront, { className: "size-4" }),
|
|
920
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Bring to front" })
|
|
921
|
-
] }),
|
|
922
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.sendToBack(clipId), children: [
|
|
923
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendToBack, { className: "size-4" }),
|
|
924
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Send to back" })
|
|
925
|
-
] })
|
|
926
|
-
] })
|
|
927
|
-
] }),
|
|
928
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mx-0.5 h-5 w-px bg-border" }),
|
|
929
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
930
|
-
"button",
|
|
931
|
-
{
|
|
932
|
-
type: "button",
|
|
933
|
-
className: ui.cn(ACTION, "text-destructive hover:bg-destructive/10"),
|
|
934
|
-
title: "Remove from slide (Delete)",
|
|
935
|
-
"aria-label": "Remove from slide",
|
|
936
|
-
onClick: () => {
|
|
937
|
-
actions.unplace(clipId);
|
|
938
|
-
onRemoved();
|
|
939
|
-
},
|
|
940
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" })
|
|
941
|
-
}
|
|
942
|
-
)
|
|
943
|
-
]
|
|
944
|
-
}
|
|
945
|
-
);
|
|
946
|
-
}
|
|
947
|
-
var boxStyle = (box2) => ({
|
|
948
|
-
left: `${box2.x * 100}%`,
|
|
949
|
-
top: `${box2.y * 100}%`,
|
|
950
|
-
width: `${box2.w * 100}%`,
|
|
951
|
-
height: `${box2.h * 100}%`
|
|
952
|
-
});
|
|
953
|
-
var textStyle = (box2, color) => ({
|
|
954
|
-
...boxStyle(box2),
|
|
955
|
-
fontSize: `${box2.size * 100}cqw`,
|
|
956
|
-
fontWeight: box2.weight,
|
|
957
|
-
lineHeight: box2.leading,
|
|
958
|
-
color,
|
|
959
|
-
letterSpacing: box2.tone === "title" ? "-0.01em" : void 0
|
|
960
|
-
});
|
|
961
|
-
var PLACEHOLDER_COLOR = "rgba(255,255,255,0.32)";
|
|
962
|
-
function Text({
|
|
963
|
-
box: box2,
|
|
964
|
-
lines,
|
|
965
|
-
accent,
|
|
966
|
-
placeholder,
|
|
967
|
-
onEdit,
|
|
968
|
-
testId
|
|
969
|
-
}) {
|
|
970
|
-
const empty = lines.length === 0;
|
|
971
|
-
if (empty && !placeholder) return null;
|
|
972
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
973
|
-
"div",
|
|
974
|
-
{
|
|
975
|
-
className: ui.cn(
|
|
976
|
-
"absolute flex flex-col overflow-hidden",
|
|
977
|
-
onEdit ? "pointer-events-auto cursor-text rounded-[0.3cqw] hover:outline hover:outline-1 hover:outline-white/25" : "pointer-events-none",
|
|
978
|
-
box2.align === "center" && "text-center",
|
|
979
|
-
box2.bullets && "gap-[0.6cqw]",
|
|
980
|
-
box2.anchor === "middle" && "justify-center",
|
|
981
|
-
box2.anchor === "bottom" && "justify-end"
|
|
982
|
-
),
|
|
983
|
-
style: textStyle(box2, empty ? PLACEHOLDER_COLOR : chunk4TTX6ZNS_cjs.TEXT_COLORS[box2.tone]),
|
|
984
|
-
onPointerDown: onEdit ? (event) => event.stopPropagation() : void 0,
|
|
985
|
-
onClick: onEdit,
|
|
986
|
-
"data-testid": testId,
|
|
987
|
-
children: (empty ? [placeholder] : lines).map(
|
|
988
|
-
(line, index) => box2.bullets ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-baseline gap-[0.8em]", children: [
|
|
989
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
990
|
-
"span",
|
|
991
|
-
{
|
|
992
|
-
"aria-hidden": true,
|
|
993
|
-
className: "inline-block size-[0.42em] shrink-0 -translate-y-[0.12em]",
|
|
994
|
-
style: { background: empty ? "currentColor" : accent }
|
|
995
|
-
}
|
|
996
|
-
),
|
|
997
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { children: line })
|
|
998
|
-
] }, index) : /* @__PURE__ */ jsxRuntime.jsx("div", { children: line }, index)
|
|
999
|
-
)
|
|
1000
|
-
}
|
|
1001
|
-
);
|
|
1002
|
-
}
|
|
1003
|
-
function TextField({
|
|
1004
|
-
box: box2,
|
|
1005
|
-
value,
|
|
1006
|
-
placeholder,
|
|
1007
|
-
multiline,
|
|
1008
|
-
onChange,
|
|
1009
|
-
onDone,
|
|
1010
|
-
testId
|
|
1011
|
-
}) {
|
|
1012
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1013
|
-
"textarea",
|
|
1014
|
-
{
|
|
1015
|
-
autoFocus: true,
|
|
1016
|
-
value,
|
|
1017
|
-
placeholder,
|
|
1018
|
-
onChange: (event) => onChange(multiline ? event.target.value : event.target.value.replace(/\n/g, " ")),
|
|
1019
|
-
onBlur: onDone,
|
|
1020
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
1021
|
-
onKeyDown: (event) => {
|
|
1022
|
-
if (event.key === "Escape" || !multiline && event.key === "Enter") {
|
|
1023
|
-
event.preventDefault();
|
|
1024
|
-
event.currentTarget.blur();
|
|
1025
|
-
}
|
|
1026
|
-
},
|
|
1027
|
-
className: ui.cn(
|
|
1028
|
-
"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",
|
|
1029
|
-
box2.align === "center" && "text-center"
|
|
1030
|
-
),
|
|
1031
|
-
style: {
|
|
1032
|
-
...textStyle(box2, chunk4TTX6ZNS_cjs.TEXT_COLORS[box2.tone]),
|
|
1033
|
-
fontFamily: "inherit",
|
|
1034
|
-
// Bulleted lines keep their indent while typed.
|
|
1035
|
-
paddingLeft: box2.bullets ? "1.22em" : void 0
|
|
1036
|
-
},
|
|
1037
|
-
"aria-label": placeholder,
|
|
1038
|
-
"data-testid": testId
|
|
1039
|
-
}
|
|
1040
|
-
);
|
|
1041
|
-
}
|
|
1042
|
-
function Logo({ image, box: box2 }) {
|
|
1043
|
-
const url = chunkWOOOMTTA_cjs.useObjectUrl(image);
|
|
1044
|
-
if (!url) return null;
|
|
1045
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1046
|
-
"img",
|
|
1047
|
-
{
|
|
1048
|
-
src: url,
|
|
1049
|
-
alt: "",
|
|
1050
|
-
className: "pointer-events-none absolute object-contain opacity-90",
|
|
1051
|
-
style: { ...boxStyle(box2), objectPosition: box2.x < 0.5 ? "left bottom" : "right bottom" },
|
|
1052
|
-
"data-testid": "stage-logo"
|
|
1053
|
-
}
|
|
1054
|
-
);
|
|
1055
|
-
}
|
|
1056
|
-
var SlideDecor = react.memo(function SlideDecor2({
|
|
1057
|
-
slide,
|
|
1058
|
-
theme,
|
|
1059
|
-
labels,
|
|
1060
|
-
logoImage,
|
|
1061
|
-
editable,
|
|
1062
|
-
editing,
|
|
1063
|
-
dim
|
|
1064
|
-
}) {
|
|
1065
|
-
const [typing, setTyping] = react.useState(null);
|
|
1066
|
-
const geometry = chunk4TTX6ZNS_cjs.slideGeometry(slide, { labels, logo: theme.logo?.corner ?? null });
|
|
1067
|
-
const title = slide.caption.trim();
|
|
1068
|
-
const titled = slide.layout === "title" || slide.layout === "section";
|
|
1069
|
-
const info = chunk4TTX6ZNS_cjs.LAYOUT_INFO[slide.layout];
|
|
1070
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("pointer-events-none absolute inset-0", dim && "opacity-30"), children: [
|
|
1071
|
-
!geometry.title ? null : editing && typing === "title" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1072
|
-
TextField,
|
|
1073
|
-
{
|
|
1074
|
-
box: geometry.title,
|
|
1075
|
-
value: slide.caption,
|
|
1076
|
-
placeholder: "Title",
|
|
1077
|
-
multiline: false,
|
|
1078
|
-
onChange: editing.onTitle,
|
|
1079
|
-
onDone: () => setTyping(null),
|
|
1080
|
-
testId: "stage-slide-caption-input"
|
|
1081
|
-
}
|
|
1082
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1083
|
-
Text,
|
|
1084
|
-
{
|
|
1085
|
-
box: geometry.title,
|
|
1086
|
-
lines: title ? [title] : [],
|
|
1087
|
-
accent: chunk4TTX6ZNS_cjs.accentColor(theme.accent),
|
|
1088
|
-
placeholder: editable && (titled || editing) ? "Click to add a title" : void 0,
|
|
1089
|
-
onEdit: editing ? () => setTyping("title") : void 0,
|
|
1090
|
-
testId: "stage-slide-caption"
|
|
1091
|
-
}
|
|
1092
|
-
),
|
|
1093
|
-
geometry.rule && (title || editable && titled) && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1094
|
-
"div",
|
|
1095
|
-
{
|
|
1096
|
-
className: "absolute",
|
|
1097
|
-
style: { ...boxStyle(geometry.rule), background: chunk4TTX6ZNS_cjs.accentColor(theme.accent) }
|
|
1098
|
-
}
|
|
1099
|
-
),
|
|
1100
|
-
geometry.text && (editing && typing === "text" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1101
|
-
TextField,
|
|
1102
|
-
{
|
|
1103
|
-
box: geometry.text,
|
|
1104
|
-
value: slide.points,
|
|
1105
|
-
placeholder: info.text ?? "",
|
|
1106
|
-
multiline: true,
|
|
1107
|
-
onChange: editing.onPoints,
|
|
1108
|
-
onDone: () => setTyping(null),
|
|
1109
|
-
testId: "stage-slide-points-input"
|
|
1110
|
-
}
|
|
1111
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1112
|
-
Text,
|
|
1113
|
-
{
|
|
1114
|
-
box: geometry.text,
|
|
1115
|
-
lines: chunk4TTX6ZNS_cjs.textLines(slide.points),
|
|
1116
|
-
accent: chunk4TTX6ZNS_cjs.accentColor(theme.accent),
|
|
1117
|
-
placeholder: editable ? info.text : void 0,
|
|
1118
|
-
onEdit: editing ? () => setTyping("text") : void 0,
|
|
1119
|
-
testId: "stage-slide-points"
|
|
1120
|
-
}
|
|
1121
|
-
)),
|
|
1122
|
-
geometry.logo && logoImage && /* @__PURE__ */ jsxRuntime.jsx(Logo, { image: logoImage, box: geometry.logo })
|
|
1123
|
-
] });
|
|
1124
|
-
});
|
|
1125
|
-
var isEdge = (kind) => kind === "n" || kind === "e" || kind === "s" || kind === "w";
|
|
1126
|
-
var EDGES = [
|
|
1127
|
-
{ edge: "n", left: "50%", top: "0%", cursor: "ns-resize", label: "top" },
|
|
1128
|
-
{ edge: "e", left: "100%", top: "50%", cursor: "ew-resize", label: "right" },
|
|
1129
|
-
{ edge: "s", left: "50%", top: "100%", cursor: "ns-resize", label: "bottom" },
|
|
1130
|
-
{ edge: "w", left: "0%", top: "50%", cursor: "ew-resize", label: "left" }
|
|
1131
|
-
];
|
|
1132
|
-
var CORNERS = [
|
|
1133
|
-
{ corner: "nw", left: "0%", top: "0%", cursor: "nwse-resize" },
|
|
1134
|
-
{ corner: "ne", left: "100%", top: "0%", cursor: "nesw-resize" },
|
|
1135
|
-
{ corner: "sw", left: "0%", top: "100%", cursor: "nesw-resize" },
|
|
1136
|
-
{ corner: "se", left: "100%", top: "100%", cursor: "nwse-resize" }
|
|
1137
|
-
];
|
|
1138
|
-
var EDGE_CSS = chunk4TTX6ZNS_cjs.clipEdgeCss();
|
|
1139
|
-
var StageItem = react.memo(function StageItem2({
|
|
1140
|
-
clip,
|
|
1141
|
-
frame,
|
|
1142
|
-
editable,
|
|
1143
|
-
selected,
|
|
1144
|
-
dim,
|
|
1145
|
-
label,
|
|
1146
|
-
host
|
|
1147
|
-
}) {
|
|
1148
|
-
const element = react.useRef(null);
|
|
1149
|
-
const gesture = react.useRef(null);
|
|
1150
|
-
const [reshape, setReshape] = react.useState(null);
|
|
1151
|
-
const shown = reshape ? { ...clip, ...reshape.shape } : clip;
|
|
1152
|
-
const box2 = reshape?.frame ?? frame;
|
|
1153
|
-
const view = () => element.current?.ownerDocument.defaultView ?? window;
|
|
1154
|
-
const apply = () => {
|
|
1155
|
-
const g = gesture.current;
|
|
1156
|
-
const el = element.current;
|
|
1157
|
-
if (!g) return;
|
|
1158
|
-
g.request = null;
|
|
1159
|
-
const next = g.next;
|
|
1160
|
-
if (!next || !el) return;
|
|
1161
|
-
if (next.shape) {
|
|
1162
|
-
setReshape({ frame: next.frame, shape: next.shape });
|
|
1163
|
-
} else {
|
|
1164
|
-
const dx = (next.frame.x - g.frame.x) * g.stage.width;
|
|
1165
|
-
const dy = (next.frame.y - g.frame.y) * g.stage.height;
|
|
1166
|
-
const scale = next.frame.w / g.frame.w;
|
|
1167
|
-
el.style.transform = `translate3d(${dx}px, ${dy}px, 0) scale(${scale})`;
|
|
1168
|
-
}
|
|
1169
|
-
const key = next.guides.map((guide) => `${guide.axis}${guide.at}`).join();
|
|
1170
|
-
if (key !== g.guidesKey) {
|
|
1171
|
-
g.guidesKey = key;
|
|
1172
|
-
host.guides(next.guides);
|
|
1173
|
-
}
|
|
1174
|
-
};
|
|
1175
|
-
const start = (event, kind) => {
|
|
1176
|
-
if (!editable || event.button !== 0) return;
|
|
1177
|
-
const stage = host.stageBox();
|
|
1178
|
-
if (!stage) return;
|
|
1179
|
-
event.preventDefault();
|
|
1180
|
-
event.stopPropagation();
|
|
1181
|
-
host.select(clip.id);
|
|
1182
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1183
|
-
gesture.current = {
|
|
1184
|
-
kind,
|
|
1185
|
-
pointer: { x: event.clientX, y: event.clientY },
|
|
1186
|
-
frame,
|
|
1187
|
-
shape: { rect: clip.rect, aspect: clip.aspect },
|
|
1188
|
-
stage,
|
|
1189
|
-
others: host.others(clip.id),
|
|
1190
|
-
next: null,
|
|
1191
|
-
request: null,
|
|
1192
|
-
guidesKey: ""
|
|
1193
|
-
};
|
|
1194
|
-
};
|
|
1195
|
-
const move = (event) => {
|
|
1196
|
-
const g = gesture.current;
|
|
1197
|
-
if (!g) return;
|
|
1198
|
-
if (!g.next) {
|
|
1199
|
-
host.dragging(true);
|
|
1200
|
-
if (element.current) element.current.style.willChange = "transform";
|
|
1201
|
-
}
|
|
1202
|
-
const dx = (event.clientX - g.pointer.x) / g.stage.width;
|
|
1203
|
-
const dy = (event.clientY - g.pointer.y) / g.stage.height;
|
|
1204
|
-
const free = event.altKey;
|
|
1205
|
-
if (isEdge(g.kind)) {
|
|
1206
|
-
const result = chunk4TTX6ZNS_cjs.reshapeFrame(g.frame, g.shape, g.kind, dx, dy, g.others, free);
|
|
1207
|
-
g.next = {
|
|
1208
|
-
frame: result.frame,
|
|
1209
|
-
shape: { rect: result.rect, aspect: result.aspect },
|
|
1210
|
-
guides: result.guides
|
|
1211
|
-
};
|
|
1212
|
-
} else {
|
|
1213
|
-
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);
|
|
1214
|
-
}
|
|
1215
|
-
g.request ??= view().requestAnimationFrame(apply);
|
|
1216
|
-
};
|
|
1217
|
-
const end = () => {
|
|
1218
|
-
const g = gesture.current;
|
|
1219
|
-
gesture.current = null;
|
|
1220
|
-
if (!g) return;
|
|
1221
|
-
if (g.request !== null) view().cancelAnimationFrame(g.request);
|
|
1222
|
-
const el = element.current;
|
|
1223
|
-
if (el) {
|
|
1224
|
-
el.style.transform = "";
|
|
1225
|
-
el.style.willChange = "";
|
|
1226
|
-
}
|
|
1227
|
-
if (!g.next) return;
|
|
1228
|
-
setReshape(null);
|
|
1229
|
-
host.dragging(false);
|
|
1230
|
-
host.guides([]);
|
|
1231
|
-
host.commit(clip.id, g.next.frame, g.next.shape);
|
|
1232
|
-
};
|
|
1233
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1234
|
-
"div",
|
|
1235
|
-
{
|
|
1236
|
-
ref: element,
|
|
1237
|
-
className: ui.cn(
|
|
1238
|
-
"absolute origin-top-left",
|
|
1239
|
-
// Lifted off the background (a picture that is part of the slide's design is not).
|
|
1240
|
-
!clip.plain && "rounded-[0.6cqw] shadow-[0_0.5cqw_1.6cqw_rgba(0,0,0,0.5)]",
|
|
1241
|
-
editable && "cursor-move touch-none",
|
|
1242
|
-
selected && "outline outline-2 outline-offset-2 outline-primary",
|
|
1243
|
-
dim && "opacity-30"
|
|
1244
|
-
),
|
|
1245
|
-
style: {
|
|
1246
|
-
left: `${box2.x * 100}%`,
|
|
1247
|
-
top: `${box2.y * 100}%`,
|
|
1248
|
-
width: `${box2.w * 100}%`,
|
|
1249
|
-
height: `${chunk4TTX6ZNS_cjs.frameHeight(box2, shown.aspect) * 100}%`
|
|
1250
|
-
},
|
|
1251
|
-
onPointerDown: (event) => start(event, "move"),
|
|
1252
|
-
onPointerMove: move,
|
|
1253
|
-
onPointerUp: end,
|
|
1254
|
-
onPointerCancel: end,
|
|
1255
|
-
"data-testid": `stage-item-${clip.id}`,
|
|
1256
|
-
children: [
|
|
1257
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: ui.cn("absolute inset-0 overflow-hidden", !clip.plain && "rounded-[0.6cqw]"), children: [
|
|
1258
|
-
/* @__PURE__ */ jsxRuntime.jsx(ClipImage, { clip: shown, live: !editable }),
|
|
1259
|
-
clip.kind === "pdf" && !clip.plain && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1260
|
-
"div",
|
|
1261
|
-
{
|
|
1262
|
-
className: "pointer-events-none absolute inset-0",
|
|
1263
|
-
style: { background: EDGE_CSS },
|
|
1264
|
-
"data-testid": "stage-clip-edge"
|
|
1265
|
-
}
|
|
1266
|
-
),
|
|
1267
|
-
!clip.plain && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "pointer-events-none absolute inset-0 rounded-[0.6cqw] ring-1 ring-inset ring-white/15" })
|
|
1268
|
-
] }),
|
|
1269
|
-
label && !clip.plain && // Under the clip, in the room the layout keeps (CAPTION_SPACE): never over it.
|
|
1270
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1271
|
-
"div",
|
|
1272
|
-
{
|
|
1273
|
-
className: "pointer-events-none absolute left-0 top-full mt-[0.5cqw] max-w-full truncate text-[1.7cqw] leading-tight",
|
|
1274
|
-
style: { color: chunk4TTX6ZNS_cjs.TEXT_COLORS.muted },
|
|
1275
|
-
children: label
|
|
1276
|
-
}
|
|
1277
|
-
),
|
|
1278
|
-
selected && CORNERS.map(({ corner, left, top, cursor }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1279
|
-
"div",
|
|
1280
|
-
{
|
|
1281
|
-
className: "absolute flex size-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
|
|
1282
|
-
style: { left, top, cursor, touchAction: "none" },
|
|
1283
|
-
onPointerDown: (event) => start(event, corner),
|
|
1284
|
-
"aria-label": `Resize from the ${corner} corner`,
|
|
1285
|
-
"data-testid": `stage-item-resize-${corner}`,
|
|
1286
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none size-3 rounded-full border-2 border-primary bg-background" })
|
|
1287
|
-
},
|
|
1288
|
-
corner
|
|
1289
|
-
)),
|
|
1290
|
-
selected && EDGES.map(({ edge, left, top, cursor, label: side }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1291
|
-
"div",
|
|
1292
|
-
{
|
|
1293
|
-
className: "absolute flex size-6 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
|
|
1294
|
-
style: { left, top, cursor, touchAction: "none" },
|
|
1295
|
-
onPointerDown: (event) => start(event, edge),
|
|
1296
|
-
"aria-label": `Show more or less at the ${side}`,
|
|
1297
|
-
title: "Drag to show more or less of the page",
|
|
1298
|
-
"data-testid": `stage-item-reshape-${edge}`,
|
|
1299
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1300
|
-
"span",
|
|
1301
|
-
{
|
|
1302
|
-
className: ui.cn(
|
|
1303
|
-
"pointer-events-none rounded-full border-2 border-primary bg-background",
|
|
1304
|
-
edge === "n" || edge === "s" ? "h-2 w-4" : "h-4 w-2"
|
|
1305
|
-
)
|
|
1306
|
-
}
|
|
1307
|
-
)
|
|
1308
|
-
},
|
|
1309
|
-
edge
|
|
1310
|
-
))
|
|
1311
|
-
]
|
|
1312
|
-
}
|
|
1313
|
-
);
|
|
1314
|
-
});
|
|
1315
|
-
|
|
1316
|
-
// src/presentation/box-style.ts
|
|
1317
|
-
var cqw = (points) => `${chunk4TTX6ZNS_cjs.pointsToStage(points) * 100}cqw`;
|
|
1318
|
-
function runStyle(run, font) {
|
|
1319
|
-
return {
|
|
1320
|
-
fontSize: cqw(run.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE),
|
|
1321
|
-
fontWeight: run.bold ? 700 : 400,
|
|
1322
|
-
fontStyle: run.italic ? "italic" : void 0,
|
|
1323
|
-
textDecoration: run.underline ? "underline" : void 0,
|
|
1324
|
-
color: run.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
|
|
1325
|
-
fontFamily: run.font ? `"${run.font}", ${font}` : font
|
|
1326
|
-
};
|
|
1327
|
-
}
|
|
1328
|
-
var HANDLES = [
|
|
1329
|
-
{ handle: "nw", left: "0%", top: "0%", cursor: "nwse-resize" },
|
|
1330
|
-
{ handle: "n", left: "50%", top: "0%", cursor: "ns-resize" },
|
|
1331
|
-
{ handle: "ne", left: "100%", top: "0%", cursor: "nesw-resize" },
|
|
1332
|
-
{ handle: "e", left: "100%", top: "50%", cursor: "ew-resize" },
|
|
1333
|
-
{ handle: "se", left: "100%", top: "100%", cursor: "nwse-resize" },
|
|
1334
|
-
{ handle: "s", left: "50%", top: "100%", cursor: "ns-resize" },
|
|
1335
|
-
{ handle: "sw", left: "0%", top: "100%", cursor: "nesw-resize" },
|
|
1336
|
-
{ handle: "w", left: "0%", top: "50%", cursor: "ew-resize" }
|
|
1337
|
-
];
|
|
1338
|
-
var withAlpha = (hex3, alpha = 1) => {
|
|
1339
|
-
if (alpha >= 1) return hex3;
|
|
1340
|
-
const n = parseInt(hex3.slice(1), 16);
|
|
1341
|
-
return `rgba(${n >> 16 & 255}, ${n >> 8 & 255}, ${n & 255}, ${alpha})`;
|
|
1342
|
-
};
|
|
1343
|
-
function shapeStyle(box2) {
|
|
1344
|
-
const { frame } = box2;
|
|
1345
|
-
const line = box2.line;
|
|
1346
|
-
const shorter = Math.min(frame.w, frame.h * 1 / chunk4TTX6ZNS_cjs.STAGE_ASPECT);
|
|
1347
|
-
return {
|
|
1348
|
-
background: box2.fill && box2.shape !== "line" ? withAlpha(box2.fill, box2.fillAlpha) : void 0,
|
|
1349
|
-
border: line && box2.shape !== "line" ? `${cqw(line.width)} ${line.dash ? "dashed" : "solid"} ${line.color}` : void 0,
|
|
1350
|
-
borderRadius: box2.shape === "ellipse" ? "50%" : box2.shape === "roundRect" ? `${shorter * 16.67}cqw` : void 0
|
|
1351
|
-
};
|
|
1352
|
-
}
|
|
1353
|
-
function Paragraphs({
|
|
1354
|
-
paragraphs,
|
|
1355
|
-
font
|
|
1356
|
-
}) {
|
|
1357
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: paragraphs.map((paragraph, index) => {
|
|
1358
|
-
const first = paragraph.runs[0];
|
|
1359
|
-
const size = first?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE;
|
|
1360
|
-
const indent = (paragraph.level ?? 0) * 0.5 * size;
|
|
1361
|
-
const empty = !paragraph.runs.some((run) => run.text);
|
|
1362
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1363
|
-
"div",
|
|
1364
|
-
{
|
|
1365
|
-
className: "whitespace-pre-wrap break-words",
|
|
1366
|
-
style: {
|
|
1367
|
-
textAlign: paragraph.align ?? "left",
|
|
1368
|
-
lineHeight: 1.2,
|
|
1369
|
-
paddingLeft: cqw(indent + (paragraph.bullet ? size * 0.9 : 0)),
|
|
1370
|
-
textIndent: paragraph.bullet ? cqw(-size * 0.9) : void 0,
|
|
1371
|
-
// An empty line keeps its height.
|
|
1372
|
-
fontSize: cqw(size)
|
|
1373
|
-
},
|
|
1374
|
-
children: [
|
|
1375
|
-
paragraph.bullet && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1376
|
-
"span",
|
|
1377
|
-
{
|
|
1378
|
-
style: {
|
|
1379
|
-
...runStyle(first ?? { }, font),
|
|
1380
|
-
display: "inline-block",
|
|
1381
|
-
width: cqw(size * 0.9),
|
|
1382
|
-
textIndent: 0
|
|
1383
|
-
},
|
|
1384
|
-
children: "\u2022"
|
|
1385
|
-
}
|
|
1386
|
-
),
|
|
1387
|
-
empty ? "\u200B" : paragraph.runs.map((run, i) => /* @__PURE__ */ jsxRuntime.jsx("span", { style: runStyle(run, font), children: run.text }, i))
|
|
1388
|
-
]
|
|
1389
|
-
},
|
|
1390
|
-
index
|
|
1391
|
-
);
|
|
1392
|
-
}) });
|
|
1393
|
-
}
|
|
1394
|
-
var StageBox = react.memo(function StageBox2({
|
|
1395
|
-
box: box2,
|
|
1396
|
-
font,
|
|
1397
|
-
editable,
|
|
1398
|
-
selected,
|
|
1399
|
-
host
|
|
1400
|
-
}) {
|
|
1401
|
-
const element = react.useRef(null);
|
|
1402
|
-
const gesture = react.useRef(null);
|
|
1403
|
-
const [typing, setTyping] = react.useState(false);
|
|
1404
|
-
const [dragging, setDragging] = react.useState(false);
|
|
1405
|
-
const { frame } = box2;
|
|
1406
|
-
const view = () => element.current?.ownerDocument.defaultView ?? window;
|
|
1407
|
-
const apply = () => {
|
|
1408
|
-
const g = gesture.current;
|
|
1409
|
-
const el = element.current;
|
|
1410
|
-
if (!g || !el) return;
|
|
1411
|
-
g.request = null;
|
|
1412
|
-
if (!g.next) return;
|
|
1413
|
-
if (g.handle === "move") {
|
|
1414
|
-
el.style.translate = `${(g.next.x - g.frame.x) * g.stage.width}px ${(g.next.y - g.frame.y) * g.stage.height}px`;
|
|
1415
|
-
} else {
|
|
1416
|
-
el.style.left = `${g.next.x * 100}%`;
|
|
1417
|
-
el.style.top = `${g.next.y * 100}%`;
|
|
1418
|
-
el.style.width = `${g.next.w * 100}%`;
|
|
1419
|
-
el.style.height = `${g.next.h * 100}%`;
|
|
1420
|
-
}
|
|
1421
|
-
};
|
|
1422
|
-
const start = (event, handle) => {
|
|
1423
|
-
if (!editable || typing || event.button !== 0) return;
|
|
1424
|
-
const stage = host.stageBox();
|
|
1425
|
-
if (!stage) return;
|
|
1426
|
-
event.preventDefault();
|
|
1427
|
-
event.stopPropagation();
|
|
1428
|
-
host.select(box2.id);
|
|
1429
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
1430
|
-
gesture.current = {
|
|
1431
|
-
handle,
|
|
1432
|
-
pointer: { x: event.clientX, y: event.clientY },
|
|
1433
|
-
frame,
|
|
1434
|
-
stage,
|
|
1435
|
-
next: null,
|
|
1436
|
-
request: null,
|
|
1437
|
-
wasSelected: selected
|
|
1438
|
-
};
|
|
1439
|
-
};
|
|
1440
|
-
const move = (event) => {
|
|
1441
|
-
const g = gesture.current;
|
|
1442
|
-
if (!g) return;
|
|
1443
|
-
const dx = (event.clientX - g.pointer.x) / g.stage.width;
|
|
1444
|
-
const dy = (event.clientY - g.pointer.y) / g.stage.height;
|
|
1445
|
-
if (!g.next) setDragging(true);
|
|
1446
|
-
g.next = g.handle === "move" ? chunk4TTX6ZNS_cjs.moveBox(g.frame, dx, dy) : chunk4TTX6ZNS_cjs.stretchBox(g.frame, g.handle, dx, dy);
|
|
1447
|
-
g.request ??= view().requestAnimationFrame(apply);
|
|
1448
|
-
};
|
|
1449
|
-
const end = () => {
|
|
1450
|
-
const g = gesture.current;
|
|
1451
|
-
gesture.current = null;
|
|
1452
|
-
if (!g) return;
|
|
1453
|
-
if (g.request !== null) view().cancelAnimationFrame(g.request);
|
|
1454
|
-
if (!g.next) {
|
|
1455
|
-
if (g.wasSelected && g.handle === "move" && hasText) setTyping(true);
|
|
1456
|
-
return;
|
|
1457
|
-
}
|
|
1458
|
-
const el = element.current;
|
|
1459
|
-
if (el) {
|
|
1460
|
-
el.style.translate = "";
|
|
1461
|
-
el.style.left = `${g.frame.x * 100}%`;
|
|
1462
|
-
el.style.top = `${g.frame.y * 100}%`;
|
|
1463
|
-
el.style.width = `${g.frame.w * 100}%`;
|
|
1464
|
-
el.style.height = `${g.frame.h * 100}%`;
|
|
1465
|
-
}
|
|
1466
|
-
setDragging(false);
|
|
1467
|
-
host.commit(box2.id, g.next);
|
|
1468
|
-
};
|
|
1469
|
-
const hasText = box2.shape !== "line";
|
|
1470
|
-
const inset = cqw(box2.inset ?? chunk4TTX6ZNS_cjs.DEFAULT_INSET);
|
|
1471
|
-
const run = chunk4TTX6ZNS_cjs.firstRun(box2);
|
|
1472
|
-
const transform = box2.rotation ? `rotate(${box2.rotation}deg)` : void 0;
|
|
1473
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1474
|
-
"div",
|
|
1475
|
-
{
|
|
1476
|
-
ref: element,
|
|
1477
|
-
className: ui.cn(
|
|
1478
|
-
"absolute",
|
|
1479
|
-
editable ? "pointer-events-auto" : "pointer-events-none",
|
|
1480
|
-
editable && !typing && "cursor-move touch-none",
|
|
1481
|
-
editable && !selected && "hover:outline hover:outline-1 hover:outline-white/30",
|
|
1482
|
-
selected && "outline outline-2 outline-offset-1 outline-primary"
|
|
1483
|
-
),
|
|
1484
|
-
style: {
|
|
1485
|
-
left: `${frame.x * 100}%`,
|
|
1486
|
-
top: `${frame.y * 100}%`,
|
|
1487
|
-
width: `${frame.w * 100}%`,
|
|
1488
|
-
height: `${frame.h * 100}%`,
|
|
1489
|
-
transform,
|
|
1490
|
-
willChange: dragging ? "translate" : void 0
|
|
1491
|
-
},
|
|
1492
|
-
onPointerDown: (event) => start(event, "move"),
|
|
1493
|
-
onPointerMove: move,
|
|
1494
|
-
onPointerUp: end,
|
|
1495
|
-
onPointerCancel: end,
|
|
1496
|
-
onDoubleClick: () => editable && hasText && setTyping(true),
|
|
1497
|
-
onKeyDown: (event) => {
|
|
1498
|
-
if (selected && !typing && event.key === "Enter" && hasText) {
|
|
1499
|
-
event.preventDefault();
|
|
1500
|
-
setTyping(true);
|
|
1501
|
-
}
|
|
1502
|
-
},
|
|
1503
|
-
tabIndex: editable ? 0 : void 0,
|
|
1504
|
-
"data-testid": `stage-box-${box2.id}`,
|
|
1505
|
-
children: [
|
|
1506
|
-
box2.shape === "line" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1507
|
-
"svg",
|
|
1508
|
-
{
|
|
1509
|
-
className: "absolute inset-0 size-full overflow-visible",
|
|
1510
|
-
preserveAspectRatio: "none",
|
|
1511
|
-
"aria-hidden": true,
|
|
1512
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1513
|
-
"line",
|
|
1514
|
-
{
|
|
1515
|
-
x1: "0%",
|
|
1516
|
-
y1: box2.flipV ? "100%" : "0%",
|
|
1517
|
-
x2: "100%",
|
|
1518
|
-
y2: box2.flipV ? "0%" : "100%",
|
|
1519
|
-
stroke: box2.line?.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
|
|
1520
|
-
style: { strokeWidth: cqw(box2.line?.width ?? 1) },
|
|
1521
|
-
strokeDasharray: box2.line?.dash ? "6 4" : void 0
|
|
1522
|
-
}
|
|
1523
|
-
)
|
|
1524
|
-
}
|
|
1525
|
-
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1526
|
-
"div",
|
|
1527
|
-
{
|
|
1528
|
-
className: ui.cn(
|
|
1529
|
-
"absolute inset-0 box-border flex flex-col overflow-hidden",
|
|
1530
|
-
box2.anchor === "middle" && "justify-center",
|
|
1531
|
-
box2.anchor === "bottom" && "justify-end"
|
|
1532
|
-
),
|
|
1533
|
-
style: { ...shapeStyle(box2), padding: inset },
|
|
1534
|
-
children: typing ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1535
|
-
"textarea",
|
|
1536
|
-
{
|
|
1537
|
-
autoFocus: true,
|
|
1538
|
-
defaultValue: chunk4TTX6ZNS_cjs.boxText(box2),
|
|
1539
|
-
className: "pointer-events-auto w-full flex-1 resize-none bg-transparent p-0 outline-none",
|
|
1540
|
-
style: {
|
|
1541
|
-
...runStyle(run ?? { }, font),
|
|
1542
|
-
lineHeight: 1.2,
|
|
1543
|
-
textAlign: box2.paragraphs[0]?.align ?? "left"
|
|
1544
|
-
},
|
|
1545
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
1546
|
-
onBlur: (event) => {
|
|
1547
|
-
host.setText(box2.id, event.currentTarget.value);
|
|
1548
|
-
setTyping(false);
|
|
1549
|
-
},
|
|
1550
|
-
onKeyDown: (event) => {
|
|
1551
|
-
event.stopPropagation();
|
|
1552
|
-
if (event.key === "Escape") event.currentTarget.blur();
|
|
1553
|
-
},
|
|
1554
|
-
"aria-label": "Text",
|
|
1555
|
-
"data-testid": "stage-box-text-input"
|
|
1556
|
-
}
|
|
1557
|
-
) : chunk4TTX6ZNS_cjs.boxText(box2) || !editable ? /* @__PURE__ */ jsxRuntime.jsx(Paragraphs, { paragraphs: box2.paragraphs, font }) : box2.shape === "text" && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1558
|
-
"span",
|
|
1559
|
-
{
|
|
1560
|
-
className: "text-white/40",
|
|
1561
|
-
style: { fontSize: cqw(run?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE) },
|
|
1562
|
-
children: "Double-click to type"
|
|
1563
|
-
}
|
|
1564
|
-
)
|
|
1565
|
-
}
|
|
1566
|
-
),
|
|
1567
|
-
selected && !typing && !dragging && HANDLES.filter(
|
|
1568
|
-
({ handle }) => box2.shape !== "line" || handle === "e" || handle === "w" || handle === "n" || handle === "s"
|
|
1569
|
-
).map(({ handle, left, top, cursor }) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1570
|
-
"div",
|
|
1571
|
-
{
|
|
1572
|
-
className: "absolute flex size-5 -translate-x-1/2 -translate-y-1/2 items-center justify-center pointer-coarse:size-11",
|
|
1573
|
-
style: { left, top, cursor, touchAction: "none" },
|
|
1574
|
-
onPointerDown: (event) => start(event, handle),
|
|
1575
|
-
"aria-label": `Resize from ${handle}`,
|
|
1576
|
-
"data-testid": `stage-box-resize-${handle}`,
|
|
1577
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "pointer-events-none size-2.5 rounded-full border-2 border-primary bg-background" })
|
|
1578
|
-
},
|
|
1579
|
-
handle
|
|
1580
|
-
))
|
|
1581
|
-
]
|
|
1582
|
-
}
|
|
1583
|
-
);
|
|
1584
|
-
});
|
|
1585
|
-
var SIZE_STEPS = [8, 10, 12, 14, 16, 18, 20, 24, 28, 32, 36, 44, 54, 66, 80, 96];
|
|
1586
|
-
var nextSize = (size, up) => up ? SIZE_STEPS.find((step) => step > size + 0.5) ?? size : [...SIZE_STEPS].reverse().find((step) => step < size - 0.5) ?? size;
|
|
1587
|
-
var ALIGN_ICON = {
|
|
1588
|
-
left: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "size-4" }),
|
|
1589
|
-
center: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignCenter, { className: "size-4" }),
|
|
1590
|
-
right: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignRight, { className: "size-4" }),
|
|
1591
|
-
justify: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "size-4" })
|
|
1592
|
-
};
|
|
1593
|
-
function ColorAction({
|
|
1594
|
-
label,
|
|
1595
|
-
value,
|
|
1596
|
-
onChange,
|
|
1597
|
-
children
|
|
1598
|
-
}) {
|
|
1599
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("label", { className: ui.cn(ACTION, "relative cursor-pointer"), title: label, "aria-label": label, children: [
|
|
1600
|
-
children,
|
|
1601
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1602
|
-
"span",
|
|
1603
|
-
{
|
|
1604
|
-
className: "pointer-events-none absolute inset-x-1.5 bottom-0.5 h-0.5 rounded-full",
|
|
1605
|
-
style: { background: value }
|
|
1606
|
-
}
|
|
1607
|
-
),
|
|
1608
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1609
|
-
"input",
|
|
1610
|
-
{
|
|
1611
|
-
type: "color",
|
|
1612
|
-
value,
|
|
1613
|
-
onChange: (event) => onChange(event.target.value),
|
|
1614
|
-
className: "absolute inset-0 size-full cursor-pointer opacity-0",
|
|
1615
|
-
"aria-label": label
|
|
1616
|
-
}
|
|
1617
|
-
)
|
|
1618
|
-
] });
|
|
1619
|
-
}
|
|
1620
|
-
function BoxActionBar({ box: box2, onRemoved }) {
|
|
1621
|
-
const actions = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
1622
|
-
const run = chunk4TTX6ZNS_cjs.firstRun(box2);
|
|
1623
|
-
const size = run?.size ?? chunk4TTX6ZNS_cjs.DEFAULT_TEXT_SIZE;
|
|
1624
|
-
const align = box2.paragraphs[0]?.align ?? "left";
|
|
1625
|
-
const update = (change) => actions.updateBox(box2.id, change);
|
|
1626
|
-
const text = box2.shape !== "line";
|
|
1627
|
-
const top = Math.max(0, box2.frame.y);
|
|
1628
|
-
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1629
|
-
"div",
|
|
1630
|
-
{
|
|
1631
|
-
role: "toolbar",
|
|
1632
|
-
"aria-label": "Text box",
|
|
1633
|
-
className: "absolute z-20 flex items-center gap-0.5 rounded-md border border-border bg-background p-0.5 shadow-md",
|
|
1634
|
-
style: {
|
|
1635
|
-
left: `${Math.min(Math.max(0, box2.frame.x), 0.6) * 100}%`,
|
|
1636
|
-
top: `calc(${top * 100}% - 40px)`
|
|
1637
|
-
},
|
|
1638
|
-
onPointerDown: (event) => event.stopPropagation(),
|
|
1639
|
-
"data-testid": "box-action-bar",
|
|
1640
|
-
children: [
|
|
1641
|
-
text && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1642
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1643
|
-
Action,
|
|
1644
|
-
{
|
|
1645
|
-
label: "Smaller",
|
|
1646
|
-
onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, false) }))),
|
|
1647
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AArrowDown, { className: "size-4" })
|
|
1648
|
-
}
|
|
1649
|
-
),
|
|
1650
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1651
|
-
"span",
|
|
1652
|
-
{
|
|
1653
|
-
className: "w-7 text-center text-xs tabular-nums text-muted-foreground",
|
|
1654
|
-
"data-testid": "box-text-size",
|
|
1655
|
-
children: Math.round(size)
|
|
1656
|
-
}
|
|
1657
|
-
),
|
|
1658
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1659
|
-
Action,
|
|
1660
|
-
{
|
|
1661
|
-
label: "Larger",
|
|
1662
|
-
onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, size: nextSize(r.size ?? size, true) }))),
|
|
1663
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AArrowUp, { className: "size-4" })
|
|
1664
|
-
}
|
|
1665
|
-
),
|
|
1666
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1667
|
-
Action,
|
|
1668
|
-
{
|
|
1669
|
-
label: "Bold",
|
|
1670
|
-
onClick: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, bold: !run?.bold }))),
|
|
1671
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Bold, { className: ui.cn("size-4", run?.bold && "text-primary") })
|
|
1672
|
-
}
|
|
1673
|
-
),
|
|
1674
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1675
|
-
ColorAction,
|
|
1676
|
-
{
|
|
1677
|
-
label: "Text colour",
|
|
1678
|
-
value: run?.color ?? chunk4TTX6ZNS_cjs.TEXT_COLORS.body,
|
|
1679
|
-
onChange: (color) => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, color }))),
|
|
1680
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Baseline, { className: "size-4" })
|
|
1681
|
-
}
|
|
1682
|
-
)
|
|
1683
|
-
] }),
|
|
1684
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1685
|
-
ColorAction,
|
|
1686
|
-
{
|
|
1687
|
-
label: box2.shape === "line" ? "Line colour" : "Fill",
|
|
1688
|
-
value: (box2.shape === "line" ? box2.line?.color : box2.fill) ?? "#ffffff",
|
|
1689
|
-
onChange: (color) => update(
|
|
1690
|
-
(b) => b.shape === "line" ? { ...b, line: { width: b.line?.width ?? 2, ...b.line, color } } : { ...b, fill: color, shape: b.shape === "text" ? "rect" : b.shape }
|
|
1691
|
-
),
|
|
1692
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.PaintBucket, { className: "size-4" })
|
|
1693
|
-
}
|
|
1694
|
-
),
|
|
1695
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenu, { children: [
|
|
1696
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1697
|
-
"button",
|
|
1698
|
-
{
|
|
1699
|
-
type: "button",
|
|
1700
|
-
className: ACTION,
|
|
1701
|
-
title: "More",
|
|
1702
|
-
"aria-label": "More",
|
|
1703
|
-
"data-testid": "box-more-menu",
|
|
1704
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MoreHorizontal, { className: "size-4" })
|
|
1705
|
-
}
|
|
1706
|
-
) }),
|
|
1707
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuContent, { align: "start", children: [
|
|
1708
|
-
text && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1709
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1710
|
-
ui.DropdownMenuCheckboxItem,
|
|
1711
|
-
{
|
|
1712
|
-
checked: !!run?.italic,
|
|
1713
|
-
onCheckedChange: () => update((b) => chunk4TTX6ZNS_cjs.styleRuns(b, (r) => ({ ...r, italic: !run?.italic }))),
|
|
1714
|
-
children: [
|
|
1715
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Italic, { className: "size-4" }),
|
|
1716
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Italic" })
|
|
1717
|
-
]
|
|
1718
|
-
}
|
|
1719
|
-
),
|
|
1720
|
-
["left", "center", "right"].map((value) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1721
|
-
ui.DropdownMenuCheckboxItem,
|
|
1722
|
-
{
|
|
1723
|
-
checked: align === value,
|
|
1724
|
-
onCheckedChange: () => update((b) => ({
|
|
1725
|
-
...b,
|
|
1726
|
-
paragraphs: b.paragraphs.map((p) => ({ ...p, align: value }))
|
|
1727
|
-
})),
|
|
1728
|
-
children: [
|
|
1729
|
-
ALIGN_ICON[value],
|
|
1730
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: value === "left" ? "Align left" : value === "center" ? "Centre" : "Align right" })
|
|
1731
|
-
]
|
|
1732
|
-
},
|
|
1733
|
-
value
|
|
1734
|
-
)),
|
|
1735
|
-
/* @__PURE__ */ jsxRuntime.jsx(ui.DropdownMenuSeparator, {})
|
|
1736
|
-
] }),
|
|
1737
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.restackBox(box2.id, "front"), children: [
|
|
1738
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.BringToFront, { className: "size-4" }),
|
|
1739
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "In front of the clips" })
|
|
1740
|
-
] }),
|
|
1741
|
-
/* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuItem, { onSelect: () => actions.restackBox(box2.id, "back"), children: [
|
|
1742
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.SendToBack, { className: "size-4" }),
|
|
1743
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "ml-2", children: "Behind the clips" })
|
|
1744
|
-
] })
|
|
1745
|
-
] })
|
|
1746
|
-
] }),
|
|
1747
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1748
|
-
"button",
|
|
1749
|
-
{
|
|
1750
|
-
type: "button",
|
|
1751
|
-
className: ui.cn(ACTION, "text-destructive hover:bg-destructive/10"),
|
|
1752
|
-
title: "Delete (Delete)",
|
|
1753
|
-
"aria-label": "Delete",
|
|
1754
|
-
onClick: () => {
|
|
1755
|
-
actions.removeBox(box2.id);
|
|
1756
|
-
onRemoved();
|
|
1757
|
-
},
|
|
1758
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Trash2, { className: "size-4" })
|
|
1759
|
-
}
|
|
1760
|
-
)
|
|
1761
|
-
]
|
|
1762
|
-
}
|
|
1763
|
-
);
|
|
1764
|
-
}
|
|
1765
|
-
var GuideLayer = react.memo(
|
|
1766
|
-
react.forwardRef(function GuideLayer2(_, ref) {
|
|
1767
|
-
const [guides, setGuides] = react.useState([]);
|
|
1768
|
-
react.useImperativeHandle(ref, () => ({ set: setGuides }), []);
|
|
1769
|
-
return /* @__PURE__ */ jsxRuntime.jsx(jsxRuntime.Fragment, { children: guides.map((guide) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1770
|
-
"div",
|
|
1771
|
-
{
|
|
1772
|
-
className: "pointer-events-none absolute z-10 bg-primary",
|
|
1773
|
-
style: guide.axis === "x" ? { left: `${guide.at * 100}%`, top: 0, bottom: 0, width: 1 } : { top: `${guide.at * 100}%`, left: 0, right: 0, height: 1 },
|
|
1774
|
-
"data-testid": `stage-guide-${guide.axis}`
|
|
1775
|
-
},
|
|
1776
|
-
`${guide.axis}-${guide.at}`
|
|
1777
|
-
)) });
|
|
1778
|
-
})
|
|
1779
|
-
);
|
|
1780
|
-
function PresentationStage({
|
|
1781
|
-
editable = false,
|
|
1782
|
-
slideIndex,
|
|
1783
|
-
selected = null,
|
|
1784
|
-
onSelect,
|
|
1785
|
-
onEditImage,
|
|
1786
|
-
onCropImage,
|
|
1787
|
-
textEditing,
|
|
1788
|
-
overlay,
|
|
1789
|
-
className
|
|
1790
|
-
}) {
|
|
1791
|
-
const index = chunk4TTX6ZNS_cjs.usePresentation((s) => slideIndex ?? s.current);
|
|
1792
|
-
const slide = chunk4TTX6ZNS_cjs.usePresentation((s) => s.slides[index]);
|
|
1793
|
-
const clips = chunk4TTX6ZNS_cjs.usePresentation((s) => s.clips);
|
|
1794
|
-
const blank = chunk4TTX6ZNS_cjs.usePresentation((s) => s.blank && !editable);
|
|
1795
|
-
const captions = chunk4TTX6ZNS_cjs.usePresentation((s) => s.captions);
|
|
1796
|
-
const columnValues = chunk4TTX6ZNS_cjs.usePresentation((s) => s.columnValues);
|
|
1797
|
-
const theme = chunk4TTX6ZNS_cjs.usePresentation((s) => s.theme);
|
|
1798
|
-
const logoImage = chunk4TTX6ZNS_cjs.usePresentation((s) => s.logoImage);
|
|
1799
|
-
const media = chunk4TTX6ZNS_cjs.usePresentation((s) => s.media);
|
|
1800
|
-
const stageRef = react.useRef(null);
|
|
1801
|
-
const guideLayer = react.useRef(null);
|
|
1802
|
-
const dropping = chunk4TTX6ZNS_cjs.usePresentation((s) => editable && s.dragging !== null);
|
|
1803
|
-
const [dragging, setDragging] = react.useState(false);
|
|
1804
|
-
const latest = react.useRef({ slide, clips, index, onSelect });
|
|
1805
|
-
latest.current = { slide, clips, index, onSelect };
|
|
1806
|
-
const host = react.useMemo(
|
|
1807
|
-
() => ({
|
|
1808
|
-
stageBox: () => stageRef.current?.getBoundingClientRect() ?? null,
|
|
1809
|
-
others: (clipId) => {
|
|
1810
|
-
const { slide: current2, clips: all } = latest.current;
|
|
1811
|
-
return (current2?.items ?? []).filter((item) => item.clipId !== clipId).map((item) => ({
|
|
1812
|
-
frame: item.frame,
|
|
1813
|
-
aspect: all.find((clip) => clip.id === item.clipId)?.aspect ?? 1
|
|
1814
|
-
}));
|
|
1815
|
-
},
|
|
1816
|
-
select: (clipId) => {
|
|
1817
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(latest.current.index);
|
|
1818
|
-
latest.current.onSelect?.(clipId);
|
|
1819
|
-
},
|
|
1820
|
-
guides: (guides) => guideLayer.current?.set(guides),
|
|
1821
|
-
dragging: setDragging,
|
|
1822
|
-
commit: (clipId, frame, shape) => {
|
|
1823
|
-
const state = chunk4TTX6ZNS_cjs.usePresentation.getState();
|
|
1824
|
-
state.goTo(latest.current.index);
|
|
1825
|
-
if (shape) state.reshapeClip(clipId, frame, shape.rect, shape.aspect);
|
|
1826
|
-
else state.setFrame(clipId, frame);
|
|
1827
|
-
}
|
|
1828
|
-
}),
|
|
1829
|
-
[]
|
|
1830
|
-
);
|
|
1831
|
-
const boxHost = react.useMemo(
|
|
1832
|
-
() => ({
|
|
1833
|
-
stageBox: () => stageRef.current?.getBoundingClientRect() ?? null,
|
|
1834
|
-
select: (boxId) => {
|
|
1835
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(latest.current.index);
|
|
1836
|
-
latest.current.onSelect?.(boxId);
|
|
1837
|
-
},
|
|
1838
|
-
commit: (boxId, frame) => chunk4TTX6ZNS_cjs.usePresentation.getState().updateBox(boxId, (box2) => ({ ...box2, frame })),
|
|
1839
|
-
setText: (boxId, text) => chunk4TTX6ZNS_cjs.usePresentation.getState().setBoxText(boxId, text)
|
|
1840
|
-
}),
|
|
1841
|
-
[]
|
|
1842
|
-
);
|
|
1843
|
-
const font = chunk4TTX6ZNS_cjs.FONTS[theme.font].css;
|
|
1844
|
-
const boxes = slide?.boxes ?? [];
|
|
1845
|
-
const selectedBox = selected ? boxes.find((box2) => box2.id === selected) : void 0;
|
|
1846
|
-
const renderBoxes = (front) => boxes.filter((box2) => !!box2.front === front).map((box2) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1847
|
-
StageBox,
|
|
1848
|
-
{
|
|
1849
|
-
box: box2,
|
|
1850
|
-
font,
|
|
1851
|
-
editable,
|
|
1852
|
-
selected: editable && selected === box2.id,
|
|
1853
|
-
host: boxHost
|
|
1854
|
-
},
|
|
1855
|
-
box2.id
|
|
1856
|
-
));
|
|
1857
|
-
const clipOf = (id) => clips.find((clip) => clip.id === id);
|
|
1858
|
-
const selectedFrame = selected ? slide?.items.find((item) => item.clipId === selected)?.frame : void 0;
|
|
1859
|
-
react.useEffect(() => {
|
|
1860
|
-
const stage = stageRef.current;
|
|
1861
|
-
const view = stage?.ownerDocument.defaultView;
|
|
1862
|
-
if (!editable || !selected || !stage || !view) return;
|
|
1863
|
-
let sum = { x: 0, y: 0 };
|
|
1864
|
-
let request = null;
|
|
1865
|
-
const onWheel = (event) => {
|
|
1866
|
-
const item = event.target?.closest?.(
|
|
1867
|
-
`[data-testid="stage-item-${selected}"]`
|
|
1868
|
-
);
|
|
1869
|
-
const clip = chunk4TTX6ZNS_cjs.usePresentation.getState().clips.find((entry) => entry.id === selected);
|
|
1870
|
-
if (!item || !clip) return;
|
|
1871
|
-
event.preventDefault();
|
|
1872
|
-
const box2 = item.getBoundingClientRect();
|
|
1873
|
-
const horizontal = event.shiftKey && !event.deltaX;
|
|
1874
|
-
const deltaX = horizontal ? event.deltaY : event.deltaX;
|
|
1875
|
-
const deltaY = horizontal ? 0 : event.deltaY;
|
|
1876
|
-
sum = {
|
|
1877
|
-
x: sum.x + deltaX / box2.width * clip.rect.w,
|
|
1878
|
-
y: sum.y + deltaY / box2.height * clip.rect.h
|
|
1879
|
-
};
|
|
1880
|
-
request ??= view.requestAnimationFrame(() => {
|
|
1881
|
-
request = null;
|
|
1882
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().panClip(selected, sum.x, sum.y);
|
|
1883
|
-
sum = { x: 0, y: 0 };
|
|
1884
|
-
});
|
|
1885
|
-
};
|
|
1886
|
-
stage.addEventListener("wheel", onWheel, { passive: false });
|
|
1887
|
-
return () => {
|
|
1888
|
-
stage.removeEventListener("wheel", onWheel);
|
|
1889
|
-
if (request !== null) view.cancelAnimationFrame(request);
|
|
1890
|
-
};
|
|
1891
|
-
}, [editable, selected]);
|
|
1892
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1893
|
-
"div",
|
|
1894
|
-
{
|
|
1895
|
-
className: ui.cn("relative h-full w-full", !editable && "overflow-hidden bg-black", className),
|
|
1896
|
-
style: { containerType: "size" },
|
|
1897
|
-
"data-testid": editable ? "presentation-stage-editor" : "presentation-stage",
|
|
1898
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1899
|
-
"div",
|
|
1900
|
-
{
|
|
1901
|
-
ref: stageRef,
|
|
1902
|
-
className: ui.cn(
|
|
1903
|
-
"absolute inset-0 m-auto",
|
|
1904
|
-
editable ? "shadow-md" : "overflow-hidden",
|
|
1905
|
-
dropping && "outline outline-2 outline-offset-2 outline-primary"
|
|
1906
|
-
),
|
|
1907
|
-
style: {
|
|
1908
|
-
width: "min(100cqw, calc(100cqh * 16 / 9))",
|
|
1909
|
-
height: "min(100cqh, calc(100cqw * 9 / 16))",
|
|
1910
|
-
containerType: "inline-size",
|
|
1911
|
-
background: slide?.background ? chunk4TTX6ZNS_cjs.slideBackgroundCss(slide.background, media) : chunk4TTX6ZNS_cjs.backgroundCss(theme.background),
|
|
1912
|
-
fontFamily: chunk4TTX6ZNS_cjs.FONTS[theme.font].css
|
|
1913
|
-
},
|
|
1914
|
-
onPointerDown: () => {
|
|
1915
|
-
if (!editable) return;
|
|
1916
|
-
chunk4TTX6ZNS_cjs.usePresentation.getState().goTo(index);
|
|
1917
|
-
onSelect?.(null);
|
|
1918
|
-
},
|
|
1919
|
-
...editable ? { [DROP_ATTRIBUTE]: "stage", "data-slide-index": index } : {},
|
|
1920
|
-
"aria-label": `Slide ${index + 1}`,
|
|
1921
|
-
children: [
|
|
1922
|
-
blank && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute inset-0 z-20 bg-black" }),
|
|
1923
|
-
slide && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1924
|
-
SlideDecor,
|
|
1925
|
-
{
|
|
1926
|
-
slide,
|
|
1927
|
-
theme,
|
|
1928
|
-
labels: captions,
|
|
1929
|
-
logoImage,
|
|
1930
|
-
editable,
|
|
1931
|
-
editing: textEditing
|
|
1932
|
-
}
|
|
1933
|
-
),
|
|
1934
|
-
renderBoxes(false),
|
|
1935
|
-
slide?.items.map((item) => {
|
|
1936
|
-
const clip = clipOf(item.clipId);
|
|
1937
|
-
if (!clip) return null;
|
|
1938
|
-
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1939
|
-
StageItem,
|
|
1940
|
-
{
|
|
1941
|
-
clip,
|
|
1942
|
-
frame: item.frame,
|
|
1943
|
-
editable,
|
|
1944
|
-
selected: editable && selected === clip.id,
|
|
1945
|
-
dim: false,
|
|
1946
|
-
label: captions ? chunk4TTX6ZNS_cjs.clipLabel(clip, columnValues) : "",
|
|
1947
|
-
host
|
|
1948
|
-
},
|
|
1949
|
-
clip.id
|
|
1950
|
-
);
|
|
1951
|
-
}),
|
|
1952
|
-
renderBoxes(true),
|
|
1953
|
-
editable && /* @__PURE__ */ jsxRuntime.jsx(GuideLayer, { ref: guideLayer }),
|
|
1954
|
-
editable && selectedFrame && selected && !dragging && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1955
|
-
ClipActionBar,
|
|
1956
|
-
{
|
|
1957
|
-
clipId: selected,
|
|
1958
|
-
at: selectedFrame,
|
|
1959
|
-
onRemoved: () => onSelect?.(null),
|
|
1960
|
-
onEditImage: onEditImage && clipOf(selected)?.kind === "image" ? () => onEditImage(selected) : void 0,
|
|
1961
|
-
onCropImage: onCropImage && clipOf(selected)?.kind === "image" ? () => onCropImage(selected) : void 0
|
|
1962
|
-
}
|
|
1963
|
-
),
|
|
1964
|
-
editable && selectedBox && /* @__PURE__ */ jsxRuntime.jsx(BoxActionBar, { box: selectedBox, onRemoved: () => onSelect?.(null) }),
|
|
1965
|
-
overlay
|
|
1966
|
-
]
|
|
1967
|
-
}
|
|
1968
|
-
)
|
|
1969
|
-
}
|
|
1970
|
-
);
|
|
1971
|
-
}
|
|
1972
482
|
var SlideCard = react.memo(function SlideCard2({
|
|
1973
483
|
index,
|
|
1974
484
|
count,
|
|
@@ -1978,20 +488,20 @@ var SlideCard = react.memo(function SlideCard2({
|
|
|
1978
488
|
onEditImage,
|
|
1979
489
|
onCropImage
|
|
1980
490
|
}) {
|
|
1981
|
-
const empty =
|
|
491
|
+
const empty = chunkORNLCBNE_cjs.usePresentation((s) => {
|
|
1982
492
|
const slide = s.slides[index];
|
|
1983
493
|
return !!slide && !slide.items.length && !slide.boxes.length && !slide.points.trim() && slide.layout !== "title" && slide.layout !== "section";
|
|
1984
494
|
});
|
|
1985
|
-
const notes =
|
|
495
|
+
const notes = chunkORNLCBNE_cjs.usePresentation((s) => s.slides[index]?.notes ?? "");
|
|
1986
496
|
const textEditing = react.useMemo(
|
|
1987
497
|
() => ({
|
|
1988
|
-
onTitle: (title) =>
|
|
1989
|
-
onPoints: (points) =>
|
|
498
|
+
onTitle: (title) => chunkORNLCBNE_cjs.usePresentation.getState().setSlideCaption(title, index),
|
|
499
|
+
onPoints: (points) => chunkORNLCBNE_cjs.usePresentation.getState().setSlidePoints(points, index)
|
|
1990
500
|
}),
|
|
1991
501
|
[index]
|
|
1992
502
|
);
|
|
1993
503
|
const select = react.useCallback((clipId) => onSelect(index, clipId), [onSelect, index]);
|
|
1994
|
-
const actions =
|
|
504
|
+
const actions = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
1995
505
|
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative flex gap-2", "data-testid": `slide-${index}`, children: [
|
|
1996
506
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex w-9 shrink-0 flex-col items-center gap-0.5", children: [
|
|
1997
507
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -2083,7 +593,7 @@ var SlideCard = react.memo(function SlideCard2({
|
|
|
2083
593
|
),
|
|
2084
594
|
children: [
|
|
2085
595
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2086
|
-
PresentationStage,
|
|
596
|
+
chunkJY7UUZQG_cjs.PresentationStage,
|
|
2087
597
|
{
|
|
2088
598
|
editable: true,
|
|
2089
599
|
slideIndex: index,
|
|
@@ -2101,7 +611,7 @@ var SlideCard = react.memo(function SlideCard2({
|
|
|
2101
611
|
value: notes,
|
|
2102
612
|
rows: notes.split("\n").length,
|
|
2103
613
|
placeholder: "Speaker notes",
|
|
2104
|
-
onChange: (event) =>
|
|
614
|
+
onChange: (event) => chunkORNLCBNE_cjs.usePresentation.getState().setSlideNotes(event.target.value, index),
|
|
2105
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",
|
|
2106
616
|
"aria-label": `Speaker notes for slide ${index + 1}`,
|
|
2107
617
|
"data-testid": `slide-notes-${index}`
|
|
@@ -2125,10 +635,10 @@ var INSERTS = [
|
|
|
2125
635
|
];
|
|
2126
636
|
function InsertMenu({ onInserted }) {
|
|
2127
637
|
const insert = (shape) => {
|
|
2128
|
-
const state =
|
|
638
|
+
const state = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
2129
639
|
const slide = state.slides[state.current];
|
|
2130
|
-
const box2 =
|
|
2131
|
-
const dark =
|
|
640
|
+
const box2 = chunkORNLCBNE_cjs.newBox(shape, chunkORNLCBNE_cjs.accentColor(state.theme.accent));
|
|
641
|
+
const dark = chunkORNLCBNE_cjs.isLightBackground(slide?.background);
|
|
2132
642
|
const { id, ...rest } = dark ? {
|
|
2133
643
|
...box2,
|
|
2134
644
|
paragraphs: box2.paragraphs.map((p) => ({
|
|
@@ -2171,7 +681,7 @@ function InsertSlide({ after, always }) {
|
|
|
2171
681
|
"button",
|
|
2172
682
|
{
|
|
2173
683
|
type: "button",
|
|
2174
|
-
onClick: () =>
|
|
684
|
+
onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().addSlide(void 0, after),
|
|
2175
685
|
className: ui.cn(
|
|
2176
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",
|
|
2177
687
|
!always && "opacity-0 group-hover/insert:opacity-100 pointer-coarse:opacity-100"
|
|
@@ -2194,11 +704,11 @@ function SlidesEditor({
|
|
|
2194
704
|
onEditImage,
|
|
2195
705
|
onCropImage
|
|
2196
706
|
}) {
|
|
2197
|
-
const ids =
|
|
707
|
+
const ids = chunkORNLCBNE_cjs.usePresentation((s) => s.slides.map((slide) => slide.id).join(" "));
|
|
2198
708
|
const slideIds = react.useMemo(() => ids.split(" "), [ids]);
|
|
2199
|
-
const current2 =
|
|
2200
|
-
const captions =
|
|
2201
|
-
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);
|
|
2202
712
|
const [selection, setSelection] = react.useState(null);
|
|
2203
713
|
const [view, setView] = react.useState(null);
|
|
2204
714
|
const list = react.useRef(null);
|
|
@@ -2212,7 +722,7 @@ function SlidesEditor({
|
|
|
2212
722
|
() => ({ clipId: selection?.clipId ?? null, clear: () => setSelection(null) }),
|
|
2213
723
|
[selection]
|
|
2214
724
|
);
|
|
2215
|
-
|
|
725
|
+
chunkADPRIBSH_cjs.usePresenterKeys(view, false, keySelection);
|
|
2216
726
|
react.useEffect(() => {
|
|
2217
727
|
const card = list.current?.querySelector(`[data-testid="slide-${current2}"]`);
|
|
2218
728
|
card?.scrollIntoView?.({ block: "nearest", behavior: "smooth" });
|
|
@@ -2268,7 +778,7 @@ function SlidesEditor({
|
|
|
2268
778
|
ui.DropdownMenuCheckboxItem,
|
|
2269
779
|
{
|
|
2270
780
|
checked: captions,
|
|
2271
|
-
onCheckedChange: (on) =>
|
|
781
|
+
onCheckedChange: (on) => chunkORNLCBNE_cjs.usePresentation.getState().setCaptions(!!on),
|
|
2272
782
|
children: "Show source labels"
|
|
2273
783
|
}
|
|
2274
784
|
)
|
|
@@ -2281,7 +791,7 @@ function SlidesEditor({
|
|
|
2281
791
|
size: "sm",
|
|
2282
792
|
variant: "destructive",
|
|
2283
793
|
className: "ml-0.5 h-8 rounded-full",
|
|
2284
|
-
onClick: () =>
|
|
794
|
+
onClick: () => chunkORNLCBNE_cjs.usePresentation.getState().setPresenting(false),
|
|
2285
795
|
title: "Stop presenting (the presentation window closes)",
|
|
2286
796
|
"data-testid": "presentation-stop-button",
|
|
2287
797
|
children: [
|
|
@@ -2320,7 +830,7 @@ function SlidesEditor({
|
|
|
2320
830
|
// src/presentation/draw-boxes.ts
|
|
2321
831
|
var LINE_HEIGHT = 1.2;
|
|
2322
832
|
function fontOf(run, themeFont, width) {
|
|
2323
|
-
const size =
|
|
833
|
+
const size = chunkORNLCBNE_cjs.pointsToStage(run.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE) * width;
|
|
2324
834
|
const family = run.font ? `"${run.font}", ${themeFont}` : themeFont;
|
|
2325
835
|
return `${run.italic ? "italic " : ""}${run.bold ? 700 : 400} ${size}px ${family}`;
|
|
2326
836
|
}
|
|
@@ -2338,9 +848,9 @@ function drawBox(context, box2, width, height, themeFont) {
|
|
|
2338
848
|
context.translate(frame.x * width + w / 2, frame.y * height + h / 2);
|
|
2339
849
|
if (box2.rotation) context.rotate(box2.rotation * Math.PI / 180);
|
|
2340
850
|
context.translate(-w / 2, -h / 2);
|
|
2341
|
-
const lineWidth = box2.line ? Math.max(1,
|
|
851
|
+
const lineWidth = box2.line ? Math.max(1, chunkORNLCBNE_cjs.pointsToStage(box2.line.width) * width) : 0;
|
|
2342
852
|
if (box2.shape === "line") {
|
|
2343
|
-
context.strokeStyle = box2.line?.color ??
|
|
853
|
+
context.strokeStyle = box2.line?.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
|
|
2344
854
|
context.lineWidth = lineWidth || 1;
|
|
2345
855
|
if (box2.line?.dash) context.setLineDash([lineWidth * 3, lineWidth * 2]);
|
|
2346
856
|
context.beginPath();
|
|
@@ -2365,12 +875,12 @@ function drawBox(context, box2, width, height, themeFont) {
|
|
|
2365
875
|
context.stroke();
|
|
2366
876
|
context.setLineDash([]);
|
|
2367
877
|
}
|
|
2368
|
-
const inset =
|
|
878
|
+
const inset = chunkORNLCBNE_cjs.pointsToStage(box2.inset ?? chunkORNLCBNE_cjs.DEFAULT_INSET) * width;
|
|
2369
879
|
const room = w - 2 * inset;
|
|
2370
880
|
context.textBaseline = "alphabetic";
|
|
2371
881
|
const lines = [];
|
|
2372
882
|
for (const paragraph of box2.paragraphs) {
|
|
2373
|
-
const size =
|
|
883
|
+
const size = chunkORNLCBNE_cjs.pointsToStage(paragraph.runs[0]?.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE) * width;
|
|
2374
884
|
const indent = (paragraph.level ?? 0) * 0.5 * size + (paragraph.bullet ? size * 0.9 : 0);
|
|
2375
885
|
const words = [];
|
|
2376
886
|
for (const run of paragraph.runs) {
|
|
@@ -2416,12 +926,12 @@ function drawBox(context, box2, width, height, themeFont) {
|
|
|
2416
926
|
const baseline = y + line.size * (LINE_HEIGHT - 0.2);
|
|
2417
927
|
if (line.bullet) {
|
|
2418
928
|
context.font = fontOf(line.bullet, themeFont, width);
|
|
2419
|
-
context.fillStyle = line.bullet.color ??
|
|
929
|
+
context.fillStyle = line.bullet.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
|
|
2420
930
|
context.fillText("\u2022", inset + line.indent - line.size * 0.9, baseline);
|
|
2421
931
|
}
|
|
2422
932
|
for (const piece of line.pieces) {
|
|
2423
933
|
context.font = fontOf(piece.run, themeFont, width);
|
|
2424
|
-
context.fillStyle = piece.run.color ??
|
|
934
|
+
context.fillStyle = piece.run.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body;
|
|
2425
935
|
context.fillText(piece.text, x, baseline);
|
|
2426
936
|
if (piece.run.underline) {
|
|
2427
937
|
context.fillRect(x, baseline + line.size * 0.08, piece.width, Math.max(1, line.size * 0.05));
|
|
@@ -2438,7 +948,7 @@ var boxWords = (box2) => box2.paragraphs.map(
|
|
|
2438
948
|
).filter(Boolean);
|
|
2439
949
|
|
|
2440
950
|
// src/presentation/render-slides.ts
|
|
2441
|
-
var SLIDE_PIXELS = { width: 1920, height: Math.round(1920 /
|
|
951
|
+
var SLIDE_PIXELS = { width: 1920, height: Math.round(1920 / chunkORNLCBNE_cjs.STAGE_ASPECT) };
|
|
2442
952
|
async function videoFrame(source, seconds) {
|
|
2443
953
|
const video = document.createElement("video");
|
|
2444
954
|
video.muted = true;
|
|
@@ -2550,7 +1060,7 @@ async function drawRoundedClip(context, clip, box2, stageWidth, shadow = true) {
|
|
|
2550
1060
|
outline2();
|
|
2551
1061
|
context.clip();
|
|
2552
1062
|
await drawClip(context, clip, box2);
|
|
2553
|
-
if (clip.kind === "pdf")
|
|
1063
|
+
if (clip.kind === "pdf") chunkORNLCBNE_cjs.paintClipEdge(context, box2, stageWidth);
|
|
2554
1064
|
context.restore();
|
|
2555
1065
|
context.save();
|
|
2556
1066
|
context.strokeStyle = "rgba(255,255,255,0.15)";
|
|
@@ -2582,7 +1092,7 @@ function wrapLines(context, text, width, max) {
|
|
|
2582
1092
|
function drawText(context, box2, lines, theme, width, height) {
|
|
2583
1093
|
const size = box2.size * width;
|
|
2584
1094
|
const lineHeight = size * box2.leading;
|
|
2585
|
-
context.font = `${box2.weight} ${size}px ${
|
|
1095
|
+
context.font = `${box2.weight} ${size}px ${chunkORNLCBNE_cjs.FONTS[theme.font].css}`;
|
|
2586
1096
|
context.textBaseline = "top";
|
|
2587
1097
|
const indent = box2.bullets ? size * 1.22 : 0;
|
|
2588
1098
|
const left = box2.x * width;
|
|
@@ -2604,10 +1114,10 @@ function drawText(context, box2, lines, theme, width, height) {
|
|
|
2604
1114
|
for (const wrapped of paragraphs) {
|
|
2605
1115
|
if (box2.bullets) {
|
|
2606
1116
|
const square = size * 0.42;
|
|
2607
|
-
context.fillStyle =
|
|
1117
|
+
context.fillStyle = chunkORNLCBNE_cjs.accentColor(theme.accent);
|
|
2608
1118
|
context.fillRect(left, y + size * 0.5 - square / 2, square, square);
|
|
2609
1119
|
}
|
|
2610
|
-
context.fillStyle =
|
|
1120
|
+
context.fillStyle = chunkORNLCBNE_cjs.TEXT_COLORS[box2.tone];
|
|
2611
1121
|
context.textAlign = box2.align === "center" ? "center" : "left";
|
|
2612
1122
|
for (const line of wrapped) {
|
|
2613
1123
|
const x = box2.align === "center" ? left + box2.w * width / 2 : left + indent;
|
|
@@ -2643,11 +1153,11 @@ async function loadImage(file) {
|
|
|
2643
1153
|
}
|
|
2644
1154
|
}
|
|
2645
1155
|
function slideWords(slide) {
|
|
2646
|
-
const own = slide.layout === "free" ? [] : [slide.caption.trim(), ...
|
|
1156
|
+
const own = slide.layout === "free" ? [] : [slide.caption.trim(), ...chunkORNLCBNE_cjs.textLines(slide.points)];
|
|
2647
1157
|
return [...own, ...slide.boxes.flatMap(boxWords)].filter(Boolean);
|
|
2648
1158
|
}
|
|
2649
1159
|
function drawSlideText(context, slide, look, width, height) {
|
|
2650
|
-
const geometry =
|
|
1160
|
+
const geometry = chunkORNLCBNE_cjs.slideGeometry(slide, {
|
|
2651
1161
|
labels: look.labels,
|
|
2652
1162
|
logo: look.theme.logo?.corner ?? null
|
|
2653
1163
|
});
|
|
@@ -2655,13 +1165,13 @@ function drawSlideText(context, slide, look, width, height) {
|
|
|
2655
1165
|
if (title && geometry.title) {
|
|
2656
1166
|
drawText(context, geometry.title, [title], look.theme, width, height);
|
|
2657
1167
|
if (geometry.rule) {
|
|
2658
|
-
context.fillStyle =
|
|
1168
|
+
context.fillStyle = chunkORNLCBNE_cjs.accentColor(look.theme.accent);
|
|
2659
1169
|
const r = geometry.rule;
|
|
2660
1170
|
context.fillRect(r.x * width, r.y * height, r.w * width, r.h * height);
|
|
2661
1171
|
}
|
|
2662
1172
|
}
|
|
2663
1173
|
if (geometry.text) {
|
|
2664
|
-
drawText(context, geometry.text,
|
|
1174
|
+
drawText(context, geometry.text, chunkORNLCBNE_cjs.textLines(slide.points), look.theme, width, height);
|
|
2665
1175
|
}
|
|
2666
1176
|
return geometry;
|
|
2667
1177
|
}
|
|
@@ -2673,13 +1183,13 @@ async function renderSlide(slide, clips, look) {
|
|
|
2673
1183
|
const context = canvas.getContext("2d");
|
|
2674
1184
|
if (!context) throw new Error("Could not draw the slides");
|
|
2675
1185
|
if (slide.background) {
|
|
2676
|
-
await
|
|
1186
|
+
await chunkORNLCBNE_cjs.paintSlideBackground(context, width, height, slide.background, look.media);
|
|
2677
1187
|
} else {
|
|
2678
|
-
|
|
1188
|
+
chunkORNLCBNE_cjs.paintBackground(context, width, height, look.theme.background);
|
|
2679
1189
|
}
|
|
2680
1190
|
const geometry = drawSlideText(context, slide, look, width, height);
|
|
2681
1191
|
const text = slideWords(slide);
|
|
2682
|
-
const font =
|
|
1192
|
+
const font = chunkORNLCBNE_cjs.FONTS[look.theme.font].css;
|
|
2683
1193
|
const drawBoxes = (front) => {
|
|
2684
1194
|
for (const box2 of slide.boxes) {
|
|
2685
1195
|
if (!!box2.front === front) drawBox(context, box2, width, height, font);
|
|
@@ -2693,16 +1203,16 @@ async function renderSlide(slide, clips, look) {
|
|
|
2693
1203
|
x: item.frame.x * width,
|
|
2694
1204
|
y: item.frame.y * height,
|
|
2695
1205
|
width: item.frame.w * width,
|
|
2696
|
-
height:
|
|
1206
|
+
height: chunkORNLCBNE_cjs.frameHeight(item.frame, clip.aspect) * height
|
|
2697
1207
|
};
|
|
2698
1208
|
if (clip.plain) {
|
|
2699
1209
|
await drawClip(context, clip, box2);
|
|
2700
1210
|
continue;
|
|
2701
1211
|
}
|
|
2702
1212
|
await drawRoundedClip(context, clip, box2, width);
|
|
2703
|
-
const label =
|
|
1213
|
+
const label = chunkORNLCBNE_cjs.clipLabel(clip, look.columnValues);
|
|
2704
1214
|
if (look.labels && label) {
|
|
2705
|
-
context.fillStyle =
|
|
1215
|
+
context.fillStyle = chunkORNLCBNE_cjs.TEXT_COLORS.muted;
|
|
2706
1216
|
context.font = `${Math.round(width * 0.017)}px ${font}`;
|
|
2707
1217
|
context.textAlign = "left";
|
|
2708
1218
|
context.textBaseline = "top";
|
|
@@ -2745,7 +1255,7 @@ function addBox(pptx, page, box2, themeFont) {
|
|
|
2745
1255
|
if (box2.shape === "line") {
|
|
2746
1256
|
page.addShape(pptx.ShapeType.line, {
|
|
2747
1257
|
...place,
|
|
2748
|
-
line: line ?? { color: hex(
|
|
1258
|
+
line: line ?? { color: hex(chunkORNLCBNE_cjs.TEXT_COLORS.body), width: 1 }
|
|
2749
1259
|
});
|
|
2750
1260
|
return;
|
|
2751
1261
|
}
|
|
@@ -2762,9 +1272,9 @@ function addBox(pptx, page, box2, themeFont) {
|
|
|
2762
1272
|
runs.push({
|
|
2763
1273
|
text: run.text,
|
|
2764
1274
|
options: {
|
|
2765
|
-
fontSize: run.size ??
|
|
1275
|
+
fontSize: run.size ?? chunkORNLCBNE_cjs.DEFAULT_TEXT_SIZE,
|
|
2766
1276
|
fontFace: run.font ?? themeFont,
|
|
2767
|
-
color: hex(run.color ??
|
|
1277
|
+
color: hex(run.color ?? chunkORNLCBNE_cjs.TEXT_COLORS.body),
|
|
2768
1278
|
...run.bold ? { bold: true } : {},
|
|
2769
1279
|
...run.italic ? { italic: true } : {},
|
|
2770
1280
|
...run.underline ? { underline: { style: "sng" } } : {},
|
|
@@ -2786,7 +1296,7 @@ function addBox(pptx, page, box2, themeFont) {
|
|
|
2786
1296
|
// Its part in the slide (its title, its body), kept by name: read back when imported.
|
|
2787
1297
|
...box2.role ? { objectName: `ARBI ${box2.role}` } : {},
|
|
2788
1298
|
valign: box2.anchor ?? "top",
|
|
2789
|
-
margin: box2.inset ??
|
|
1299
|
+
margin: box2.inset ?? chunkORNLCBNE_cjs.DEFAULT_INSET,
|
|
2790
1300
|
lineSpacingMultiple: 1,
|
|
2791
1301
|
fit: "none"
|
|
2792
1302
|
});
|
|
@@ -2816,10 +1326,10 @@ var box = (b) => ({
|
|
|
2816
1326
|
function textOptions(text, look) {
|
|
2817
1327
|
return {
|
|
2818
1328
|
...box(text),
|
|
2819
|
-
fontFace:
|
|
1329
|
+
fontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
|
|
2820
1330
|
fontSize: toPoints(text.size),
|
|
2821
1331
|
bold: text.weight >= 600,
|
|
2822
|
-
color: hex2(
|
|
1332
|
+
color: hex2(chunkORNLCBNE_cjs.TEXT_COLORS[text.tone]),
|
|
2823
1333
|
align: text.align,
|
|
2824
1334
|
valign: text.anchor ?? "top",
|
|
2825
1335
|
lineSpacingMultiple: text.leading,
|
|
@@ -2832,18 +1342,18 @@ async function buildPptx(deck, look) {
|
|
|
2832
1342
|
pptx.layout = "LAYOUT_WIDE";
|
|
2833
1343
|
pptx.title = deck.title;
|
|
2834
1344
|
pptx.theme = {
|
|
2835
|
-
headFontFace:
|
|
2836
|
-
bodyFontFace:
|
|
1345
|
+
headFontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
|
|
1346
|
+
bodyFontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx
|
|
2837
1347
|
};
|
|
2838
1348
|
const { width, height } = SLIDE_PIXELS;
|
|
2839
1349
|
const background = await canvasImage(
|
|
2840
1350
|
width,
|
|
2841
1351
|
height,
|
|
2842
|
-
(context) =>
|
|
1352
|
+
(context) => chunkORNLCBNE_cjs.paintBackground(context, width, height, look.theme.background)
|
|
2843
1353
|
);
|
|
2844
1354
|
const logo = look.logo ? await loadImage(look.logo) : null;
|
|
2845
1355
|
const logoData = logo ? await canvasImage(logo.width, logo.height, (context) => context.drawImage(logo, 0, 0)) : null;
|
|
2846
|
-
const themeFont =
|
|
1356
|
+
const themeFont = chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx;
|
|
2847
1357
|
for (const slide of deck.slides) {
|
|
2848
1358
|
const page = pptx.addSlide();
|
|
2849
1359
|
if (slide.background?.color && !slide.background.gradient && !slide.background.image) {
|
|
@@ -2854,14 +1364,14 @@ async function buildPptx(deck, look) {
|
|
|
2854
1364
|
data: await canvasImage(
|
|
2855
1365
|
width,
|
|
2856
1366
|
height,
|
|
2857
|
-
(context) =>
|
|
1367
|
+
(context) => chunkORNLCBNE_cjs.paintSlideBackground(context, width, height, own, look.media)
|
|
2858
1368
|
)
|
|
2859
1369
|
};
|
|
2860
1370
|
} else {
|
|
2861
1371
|
page.background = { data: background };
|
|
2862
1372
|
}
|
|
2863
1373
|
if (slide.notes?.trim()) page.addNotes(slide.notes);
|
|
2864
|
-
const geometry =
|
|
1374
|
+
const geometry = chunkORNLCBNE_cjs.slideGeometry(slide, {
|
|
2865
1375
|
labels: look.labels,
|
|
2866
1376
|
logo: look.theme.logo?.corner ?? null
|
|
2867
1377
|
});
|
|
@@ -2869,7 +1379,7 @@ async function buildPptx(deck, look) {
|
|
|
2869
1379
|
for (const item of slide.items) {
|
|
2870
1380
|
const clip = deck.clips.find((entry) => entry.id === item.clipId);
|
|
2871
1381
|
if (!clip) continue;
|
|
2872
|
-
const frame = { ...item.frame, h:
|
|
1382
|
+
const frame = { ...item.frame, h: chunkORNLCBNE_cjs.frameHeight(item.frame, clip.aspect) };
|
|
2873
1383
|
if (clip.plain) {
|
|
2874
1384
|
const source = clip.kind === "image" ? await createImageBitmap(clip.source) : null;
|
|
2875
1385
|
const scale = source ? Math.min(1, 2400 / Math.max(1, clip.rect.w * source.width)) : 1.5;
|
|
@@ -2901,13 +1411,13 @@ async function buildPptx(deck, look) {
|
|
|
2901
1411
|
altText: clip.caption,
|
|
2902
1412
|
shadow: { type: "outer", blur: 10, offset: 3, angle: 90, color: "000000", opacity: 0.45 }
|
|
2903
1413
|
});
|
|
2904
|
-
const label =
|
|
1414
|
+
const label = chunkORNLCBNE_cjs.clipLabel(clip, look.columnValues);
|
|
2905
1415
|
if (look.labels && label) {
|
|
2906
1416
|
page.addText(label, {
|
|
2907
1417
|
...box({ x: frame.x, y: frame.y + frame.h + 8e-3, w: frame.w, h: 0.045 }),
|
|
2908
|
-
fontFace:
|
|
1418
|
+
fontFace: chunkORNLCBNE_cjs.FONTS[look.theme.font].pptx,
|
|
2909
1419
|
fontSize: toPoints(0.017),
|
|
2910
|
-
color: hex2(
|
|
1420
|
+
color: hex2(chunkORNLCBNE_cjs.TEXT_COLORS.muted),
|
|
2911
1421
|
margin: 0,
|
|
2912
1422
|
valign: "top",
|
|
2913
1423
|
fit: "shrink"
|
|
@@ -2920,12 +1430,12 @@ async function buildPptx(deck, look) {
|
|
|
2920
1430
|
if (geometry.rule) {
|
|
2921
1431
|
page.addShape(pptx.ShapeType.rect, {
|
|
2922
1432
|
...box(geometry.rule),
|
|
2923
|
-
fill: { color: hex2(
|
|
2924
|
-
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 }
|
|
2925
1435
|
});
|
|
2926
1436
|
}
|
|
2927
1437
|
}
|
|
2928
|
-
const lines =
|
|
1438
|
+
const lines = chunkORNLCBNE_cjs.textLines(slide.points);
|
|
2929
1439
|
if (geometry.text && lines.length) {
|
|
2930
1440
|
const text = geometry.text;
|
|
2931
1441
|
page.addText(
|
|
@@ -2959,7 +1469,7 @@ async function buildPptx(deck, look) {
|
|
|
2959
1469
|
}
|
|
2960
1470
|
}
|
|
2961
1471
|
const deckFile = await pptx.write({ outputType: "blob" });
|
|
2962
|
-
return accentBullets(deckFile,
|
|
1472
|
+
return accentBullets(deckFile, chunkORNLCBNE_cjs.accentColor(look.theme.accent));
|
|
2963
1473
|
}
|
|
2964
1474
|
async function accentBullets(deck, accent) {
|
|
2965
1475
|
const { default: JSZip } = await import('jszip');
|
|
@@ -3490,7 +2000,7 @@ function renditionClip(deck, part, area, what) {
|
|
|
3490
2000
|
fileName: fileName ?? "Presentation.pptx",
|
|
3491
2001
|
page: part.page,
|
|
3492
2002
|
rect,
|
|
3493
|
-
aspect: frame.w *
|
|
2003
|
+
aspect: frame.w * chunkORNLCBNE_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
|
|
3494
2004
|
caption: "",
|
|
3495
2005
|
plain: true
|
|
3496
2006
|
});
|
|
@@ -3509,7 +2019,7 @@ function readParagraphs(body, chain, deck, defaults, fontScale, fallback = []) {
|
|
|
3509
2019
|
defaults.color ? { color: defaults.color } : {},
|
|
3510
2020
|
levelStyle(fallback, level, theme)
|
|
3511
2021
|
]);
|
|
3512
|
-
const
|
|
2022
|
+
const runStyle = (rPr) => {
|
|
3513
2023
|
const s = merge([readRunProps(rPr, theme), style]);
|
|
3514
2024
|
const color = s.color ?? defaults.base;
|
|
3515
2025
|
return {
|
|
@@ -3532,13 +2042,13 @@ function readParagraphs(body, chain, deck, defaults, fontScale, fallback = []) {
|
|
|
3532
2042
|
for (const child of kids(p)) {
|
|
3533
2043
|
if (child.localName === "r" || child.localName === "fld") {
|
|
3534
2044
|
const text = kid(child, "t")?.textContent ?? "";
|
|
3535
|
-
runs.push({ ...
|
|
2045
|
+
runs.push({ ...runStyle(kid(child, "rPr")), text });
|
|
3536
2046
|
} else if (child.localName === "br") {
|
|
3537
|
-
paragraphs.push(shape(runs.length ? runs : [{ ...
|
|
2047
|
+
paragraphs.push(shape(runs.length ? runs : [{ ...runStyle(kid(child, "rPr")), text: "" }]));
|
|
3538
2048
|
runs = [];
|
|
3539
2049
|
}
|
|
3540
2050
|
}
|
|
3541
|
-
if (!runs.length) runs = [{ ...
|
|
2051
|
+
if (!runs.length) runs = [{ ...runStyle(kid(p, "endParaRPr")), text: "" }];
|
|
3542
2052
|
paragraphs.push(shape(runs));
|
|
3543
2053
|
}
|
|
3544
2054
|
while (paragraphs.length > 1 && !paragraphs[paragraphs.length - 1].runs.some((run) => run.text.trim())) {
|
|
@@ -3629,7 +2139,7 @@ async function readShape(shape, transform, deck, part, inherit, built) {
|
|
|
3629
2139
|
fileName: target?.target.split("/").pop() ?? "Picture",
|
|
3630
2140
|
page: 1,
|
|
3631
2141
|
rect,
|
|
3632
|
-
aspect: frame.w *
|
|
2142
|
+
aspect: frame.w * chunkORNLCBNE_cjs.STAGE_ASPECT / Math.max(frame.h, 1e-6),
|
|
3633
2143
|
caption: "",
|
|
3634
2144
|
media: key,
|
|
3635
2145
|
plain: true
|
|
@@ -3852,7 +2362,7 @@ async function importPptx(bytes, options = {}) {
|
|
|
3852
2362
|
const cx = numAttr(size, "cx", 12192e3);
|
|
3853
2363
|
const cy = numAttr(size, "cy", 6858e3);
|
|
3854
2364
|
const deckAspect = cx / cy;
|
|
3855
|
-
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 };
|
|
3856
2366
|
const slides = await slideParts(pkg);
|
|
3857
2367
|
const firstLayout = slides.length ? await pkg.related(slides[0].part, "/slideLayout") : null;
|
|
3858
2368
|
const firstMaster = firstLayout ? await pkg.related(firstLayout, "/slideMaster") : null;
|
|
@@ -3861,7 +2371,7 @@ async function importPptx(bytes, options = {}) {
|
|
|
3861
2371
|
theme: firstMaster ? await readTheme(pkg, firstMaster) : { scheme: {}, map: {}, majorFont: "Calibri", minorFont: "Calibri", lineWidths: [] },
|
|
3862
2372
|
slideSize: { cx, cy },
|
|
3863
2373
|
place,
|
|
3864
|
-
pointScale:
|
|
2374
|
+
pointScale: chunkORNLCBNE_cjs.SLIDE_POINTS.h * place.h / (cy / EMU_PER_POINT),
|
|
3865
2375
|
defaultText: kid(pres.documentElement, "defaultTextStyle"),
|
|
3866
2376
|
options,
|
|
3867
2377
|
clips: [],
|
|
@@ -3957,7 +2467,7 @@ async function importPptx(bytes, options = {}) {
|
|
|
3957
2467
|
version: 1,
|
|
3958
2468
|
title: options.title ?? (coreTitle?.trim() || "Presentation"),
|
|
3959
2469
|
captions: false,
|
|
3960
|
-
theme:
|
|
2470
|
+
theme: chunkORNLCBNE_cjs.DEFAULT_THEME,
|
|
3961
2471
|
clips: deck.clips,
|
|
3962
2472
|
slides: saved,
|
|
3963
2473
|
...Object.keys(deck.media).length ? { media: deck.media } : {}
|
|
@@ -4045,7 +2555,7 @@ async function presentationData(bytes) {
|
|
|
4045
2555
|
if (isZipBytes(bytes)) return readPptxPresentationData(bytes);
|
|
4046
2556
|
const isPdf = bytes[0] === 37 && bytes[1] === 80 && bytes[2] === 68 && bytes[3] === 70;
|
|
4047
2557
|
if (!isPdf) return new TextDecoder().decode(bytes);
|
|
4048
|
-
const data = await documentTools.readPdfAttachment(bytes,
|
|
2558
|
+
const data = await documentTools.readPdfAttachment(bytes, chunkORNLCBNE_cjs.PRESENTATION_ATTACHMENT);
|
|
4049
2559
|
if (!data) {
|
|
4050
2560
|
throw new Error(
|
|
4051
2561
|
"This PDF has no editable presentation in it (it may have been changed outside ARBI)."
|
|
@@ -4054,7 +2564,7 @@ async function presentationData(bytes) {
|
|
|
4054
2564
|
return new TextDecoder().decode(data);
|
|
4055
2565
|
}
|
|
4056
2566
|
function current(withoutClips) {
|
|
4057
|
-
const state =
|
|
2567
|
+
const state = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
4058
2568
|
return withoutClips ? {
|
|
4059
2569
|
...state,
|
|
4060
2570
|
clips: [],
|
|
@@ -4076,18 +2586,18 @@ function usePresentationFiles() {
|
|
|
4076
2586
|
const state = current(withoutClips);
|
|
4077
2587
|
const deck = await buildPptx({ title, slides: state.slides, clips: state.clips }, lookOf(state));
|
|
4078
2588
|
const fingerprints = await slideFingerprints(deck);
|
|
4079
|
-
const data =
|
|
2589
|
+
const data = chunkORNLCBNE_cjs.serializePresentation({ ...state, title, fingerprints });
|
|
4080
2590
|
return writePptxPresentationData(deck, JSON.stringify(data, null, 2));
|
|
4081
2591
|
}, []);
|
|
4082
2592
|
const save = react.useCallback(
|
|
4083
2593
|
async (title, { asNew = false, template = false } = {}) => {
|
|
4084
2594
|
if (!arbi || !workspaceId) throw new Error("Open a workspace to save the presentation.");
|
|
4085
|
-
const state =
|
|
2595
|
+
const state = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
4086
2596
|
const versionOf = asNew || template ? null : state.savedId;
|
|
4087
2597
|
const deck = await buildFile(title, template);
|
|
4088
|
-
const file = new File([deck],
|
|
2598
|
+
const file = new File([deck], chunkORNLCBNE_cjs.presentationFileName(title), { type: PPTX_TYPE });
|
|
4089
2599
|
const result = await arbi.documents.upload([file], {
|
|
4090
|
-
folder: template ?
|
|
2600
|
+
folder: template ? chunkORNLCBNE_cjs.TEMPLATES_FOLDER : chunkORNLCBNE_cjs.PRESENTATIONS_FOLDER,
|
|
4091
2601
|
workspaceExtId: workspaceId,
|
|
4092
2602
|
...versionOf ? { versionOf } : {}
|
|
4093
2603
|
});
|
|
@@ -4112,8 +2622,8 @@ function usePresentationFiles() {
|
|
|
4112
2622
|
}
|
|
4113
2623
|
const pdf = await documentTools.imagesToPdf(pages, { title });
|
|
4114
2624
|
const result = await arbi.documents.upload(
|
|
4115
|
-
[new File([pdf], `${
|
|
4116
|
-
{ folder:
|
|
2625
|
+
[new File([pdf], `${chunkORNLCBNE_cjs.safeFileStem(title)}.pdf`, { type: "application/pdf" })],
|
|
2626
|
+
{ folder: chunkORNLCBNE_cjs.EXPORTS_FOLDER, workspaceExtId: workspaceId }
|
|
4117
2627
|
);
|
|
4118
2628
|
const id = result.doc_ext_ids?.[0];
|
|
4119
2629
|
if (!id) throw new Error("The PDF could not be saved.");
|
|
@@ -4128,10 +2638,10 @@ function usePresentationFiles() {
|
|
|
4128
2638
|
return docs.filter((doc) => {
|
|
4129
2639
|
const folder = doc.folder ?? "";
|
|
4130
2640
|
if (!ui.isPresentationFileName(doc.file_name, folder)) return false;
|
|
4131
|
-
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);
|
|
4132
2642
|
}).map((doc) => ({
|
|
4133
2643
|
id: doc.external_id,
|
|
4134
|
-
title:
|
|
2644
|
+
title: chunkORNLCBNE_cjs.presentationTitle(doc.file_name ?? ""),
|
|
4135
2645
|
updatedAt: doc.updated_at ?? doc.created_at ?? null
|
|
4136
2646
|
})).sort((a, b) => (a.updatedAt ?? "") < (b.updatedAt ?? "") ? 1 : -1);
|
|
4137
2647
|
},
|
|
@@ -4147,7 +2657,7 @@ function usePresentationFiles() {
|
|
|
4147
2657
|
const openedVersion = version ?? doc?.current_version ?? null;
|
|
4148
2658
|
if (text === null) {
|
|
4149
2659
|
const imported = await importPptx(bytes, {
|
|
4150
|
-
title:
|
|
2660
|
+
title: chunkORNLCBNE_cjs.presentationTitle(doc?.file_name ?? "Presentation.pptx"),
|
|
4151
2661
|
documentId: id,
|
|
4152
2662
|
version: version ?? doc?.current_version,
|
|
4153
2663
|
fileName: doc?.file_name ?? void 0
|
|
@@ -4159,7 +2669,7 @@ function usePresentationFiles() {
|
|
|
4159
2669
|
openedVersion
|
|
4160
2670
|
};
|
|
4161
2671
|
}
|
|
4162
|
-
let saved =
|
|
2672
|
+
let saved = chunkORNLCBNE_cjs.parsePresentation(text);
|
|
4163
2673
|
let changedOutside;
|
|
4164
2674
|
if (isZipBytes(bytes) && saved.slides.some((slide) => slide.fingerprint)) {
|
|
4165
2675
|
const now = await slideFingerprints(bytes);
|
|
@@ -4190,7 +2700,7 @@ function usePresentationFiles() {
|
|
|
4190
2700
|
const startFromTemplate = react.useCallback(
|
|
4191
2701
|
async (id) => {
|
|
4192
2702
|
const { saved } = await readSaved(id);
|
|
4193
|
-
|
|
2703
|
+
chunkORNLCBNE_cjs.usePresentation.getState().load({
|
|
4194
2704
|
title: "Untitled presentation",
|
|
4195
2705
|
savedId: null,
|
|
4196
2706
|
captions: saved.captions,
|
|
@@ -4267,7 +2777,7 @@ function usePresentationFiles() {
|
|
|
4267
2777
|
);
|
|
4268
2778
|
const kept = [];
|
|
4269
2779
|
const newIndex = opened.map((clip) => clip ? kept.push(clip) - 1 : -1);
|
|
4270
|
-
|
|
2780
|
+
chunkORNLCBNE_cjs.usePresentation.getState().load({
|
|
4271
2781
|
title: saved.title,
|
|
4272
2782
|
savedId: legacy ? null : id,
|
|
4273
2783
|
version: legacy ? null : openedVersion,
|
|
@@ -4341,7 +2851,7 @@ function useGenerateImageLaunch() {
|
|
|
4341
2851
|
throw new Error(failure || answer.trim() || "The image could not be generated.");
|
|
4342
2852
|
const source = await (await arbi.documents.download(documentId)).blob();
|
|
4343
2853
|
const fileName = `${prompt.split("\n")[0].slice(0, 60)}.png`;
|
|
4344
|
-
|
|
2854
|
+
chunkORNLCBNE_cjs.usePresentation.getState().addClip({
|
|
4345
2855
|
kind: "image",
|
|
4346
2856
|
documentId,
|
|
4347
2857
|
fileName,
|
|
@@ -4350,7 +2860,7 @@ function useGenerateImageLaunch() {
|
|
|
4350
2860
|
aspect: await aspectOf(source),
|
|
4351
2861
|
masks: [],
|
|
4352
2862
|
source,
|
|
4353
|
-
caption:
|
|
2863
|
+
caption: chunkORNLCBNE_cjs.mediaCaption(fileName)
|
|
4354
2864
|
});
|
|
4355
2865
|
},
|
|
4356
2866
|
[arbi, workspaceId]
|
|
@@ -4361,7 +2871,7 @@ function GenerateImageDialog({
|
|
|
4361
2871
|
onOpenChange,
|
|
4362
2872
|
referenceId
|
|
4363
2873
|
}) {
|
|
4364
|
-
const notify =
|
|
2874
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4365
2875
|
const { skills } = chunkUFT22LAB_cjs.useWorkflowDefinitions();
|
|
4366
2876
|
const run = useGenerateImageLaunch();
|
|
4367
2877
|
const workflows = react.useMemo(
|
|
@@ -4421,9 +2931,9 @@ function SavePresentationDialog({
|
|
|
4421
2931
|
onOpenChange,
|
|
4422
2932
|
mode = "save"
|
|
4423
2933
|
}) {
|
|
4424
|
-
const notify =
|
|
2934
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4425
2935
|
const { save, exportPdf } = usePresentationFiles();
|
|
4426
|
-
const current2 =
|
|
2936
|
+
const current2 = chunkORNLCBNE_cjs.usePresentation((s) => s.title);
|
|
4427
2937
|
const [title, setTitle] = react.useState(current2);
|
|
4428
2938
|
const [busy, setBusy] = react.useState(false);
|
|
4429
2939
|
const text = SAVE_TEXT[mode];
|
|
@@ -4493,7 +3003,7 @@ function OpenPresentationDialog({
|
|
|
4493
3003
|
templates = false
|
|
4494
3004
|
}) {
|
|
4495
3005
|
const { confirm } = chunkTKHCIHE2_cjs.useBlocksEnvironment();
|
|
4496
|
-
const notify =
|
|
3006
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4497
3007
|
const { list, startFromTemplate } = usePresentationFiles();
|
|
4498
3008
|
const [entries, setEntries] = react.useState(null);
|
|
4499
3009
|
const [opening, setOpening] = react.useState(null);
|
|
@@ -4508,7 +3018,7 @@ function OpenPresentationDialog({
|
|
|
4508
3018
|
onOpened(entry.id);
|
|
4509
3019
|
return;
|
|
4510
3020
|
}
|
|
4511
|
-
if (
|
|
3021
|
+
if (chunkORNLCBNE_cjs.usePresentation.getState().clips.length) {
|
|
4512
3022
|
const ok = await confirm({
|
|
4513
3023
|
title: "New from template",
|
|
4514
3024
|
message: "Replace the presentation that is open? Save it first to keep it.",
|
|
@@ -4559,8 +3069,8 @@ function OpenPresentationDialog({
|
|
|
4559
3069
|
}
|
|
4560
3070
|
var IMAGE_FILE = /\.(png|jpe?g|gif|webp|svg)$/i;
|
|
4561
3071
|
function ChooseLogoDialog({ open, onOpenChange }) {
|
|
4562
|
-
const setTheme =
|
|
4563
|
-
const corner =
|
|
3072
|
+
const setTheme = chunkORNLCBNE_cjs.usePresentation((s) => s.setTheme);
|
|
3073
|
+
const corner = chunkORNLCBNE_cjs.usePresentation((s) => s.theme.logo?.corner ?? "br");
|
|
4564
3074
|
const { data: documents } = react$1.useDocuments(void 0, { enabled: open });
|
|
4565
3075
|
const [picked, setPicked] = react.useState("");
|
|
4566
3076
|
const groups = react.useMemo(
|
|
@@ -4647,7 +3157,7 @@ function CropClipDialog({ clip, onOpenChange }) {
|
|
|
4647
3157
|
w: Math.min(1, area.width / natural.width),
|
|
4648
3158
|
h: Math.min(1, area.height / natural.height)
|
|
4649
3159
|
};
|
|
4650
|
-
|
|
3160
|
+
chunkORNLCBNE_cjs.usePresentation.getState().cropClip(clip.id, rect, area.width / area.height);
|
|
4651
3161
|
onOpenChange(false);
|
|
4652
3162
|
};
|
|
4653
3163
|
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -4696,8 +3206,8 @@ function CropClipDialog({ clip, onOpenChange }) {
|
|
|
4696
3206
|
var EMPTY = new Blob();
|
|
4697
3207
|
var NONE = "none";
|
|
4698
3208
|
function LabelColumnMenu({ columns }) {
|
|
4699
|
-
const labelColumn =
|
|
4700
|
-
const setLabelColumn =
|
|
3209
|
+
const labelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.labelColumn);
|
|
3210
|
+
const setLabelColumn = chunkORNLCBNE_cjs.usePresentation((s) => s.setLabelColumn);
|
|
4701
3211
|
if (!columns.length) return null;
|
|
4702
3212
|
const chosen = columns.find((column) => column.id === labelColumn);
|
|
4703
3213
|
return /* @__PURE__ */ jsxRuntime.jsxs(ui.DropdownMenuSub, { children: [
|
|
@@ -4740,8 +3250,8 @@ function useLabelColumns(active) {
|
|
|
4740
3250
|
const workspaceId = react$1.useArbiSessionState((s) => s.workspaceId);
|
|
4741
3251
|
const { data: tags } = react$1.useTags(workspaceId, { enabled: active });
|
|
4742
3252
|
const { data: documents } = react$1.useDocuments(workspaceId, { enabled: active });
|
|
4743
|
-
const labelColumn =
|
|
4744
|
-
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(" "));
|
|
4745
3255
|
const columns = react.useMemo(
|
|
4746
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)),
|
|
4747
3257
|
[tags]
|
|
@@ -4756,23 +3266,23 @@ function useLabelColumns(active) {
|
|
|
4756
3266
|
if (note2) values[doc.external_id] = note2;
|
|
4757
3267
|
}
|
|
4758
3268
|
}
|
|
4759
|
-
|
|
3269
|
+
chunkORNLCBNE_cjs.usePresentation.getState().setColumnValues(values);
|
|
4760
3270
|
}, [labelColumn, documentIds, documents]);
|
|
4761
3271
|
return columns;
|
|
4762
3272
|
}
|
|
4763
3273
|
function usePresentationController(active) {
|
|
4764
3274
|
const session = react$1.useArbiSessionStore();
|
|
4765
|
-
const notify =
|
|
3275
|
+
const notify = chunkORNLCBNE_cjs.usePresentation((s) => s.notify);
|
|
4766
3276
|
const { save, canSave } = usePresentationFiles();
|
|
4767
3277
|
const labelColumns = useLabelColumns(active);
|
|
4768
3278
|
const [dialog, setDialog] = react.useState(null);
|
|
4769
3279
|
const [reference, setReference] = react.useState(null);
|
|
4770
3280
|
const [cropping, setCropping] = react.useState(null);
|
|
4771
|
-
const cropClip =
|
|
3281
|
+
const cropClip = chunkORNLCBNE_cjs.usePresentation((s) => s.clips.find((c) => c.id === cropping) ?? null);
|
|
4772
3282
|
const [saving, setSaving] = react.useState(false);
|
|
4773
3283
|
const close = (open) => !open && setDialog(null);
|
|
4774
3284
|
const quickSave = react.useCallback(async () => {
|
|
4775
|
-
const { savedId, title } =
|
|
3285
|
+
const { savedId, title } = chunkORNLCBNE_cjs.usePresentation.getState();
|
|
4776
3286
|
if (!savedId) return setDialog("save");
|
|
4777
3287
|
setSaving(true);
|
|
4778
3288
|
try {
|
|
@@ -4806,7 +3316,7 @@ function usePresentationController(active) {
|
|
|
4806
3316
|
{
|
|
4807
3317
|
open: dialog === "open" || dialog === "fromTemplate",
|
|
4808
3318
|
templates: dialog === "fromTemplate",
|
|
4809
|
-
onOpened: (id) =>
|
|
3319
|
+
onOpened: (id) => chunkWVZLAAIZ_cjs.editPresentation(session, id ? { kind: "open", documentId: id } : { kind: "new" }),
|
|
4810
3320
|
onOpenChange: close
|
|
4811
3321
|
}
|
|
4812
3322
|
),
|
|
@@ -4848,7 +3358,7 @@ function usePresentationController(active) {
|
|
|
4848
3358
|
trayStart: canSave && /* @__PURE__ */ jsxRuntime.jsx(GenerateTile, { onClick: () => generate(null) }),
|
|
4849
3359
|
onChooseLogo: canSave ? () => setDialog("logo") : void 0,
|
|
4850
3360
|
onEditImage: (clipId) => {
|
|
4851
|
-
const clip =
|
|
3361
|
+
const clip = chunkORNLCBNE_cjs.usePresentation.getState().clips.find((c) => c.id === clipId);
|
|
4852
3362
|
if (clip) generate(clip.documentId);
|
|
4853
3363
|
},
|
|
4854
3364
|
onCropImage: setCropping
|
|
@@ -4856,9 +3366,8 @@ function usePresentationController(active) {
|
|
|
4856
3366
|
return { editor, dialogs };
|
|
4857
3367
|
}
|
|
4858
3368
|
|
|
4859
|
-
exports.PresentationStage = PresentationStage;
|
|
4860
3369
|
exports.SlidesEditor = SlidesEditor;
|
|
4861
3370
|
exports.usePresentationController = usePresentationController;
|
|
4862
3371
|
exports.usePresentationFiles = usePresentationFiles;
|
|
4863
|
-
//# sourceMappingURL=chunk-
|
|
4864
|
-
//# sourceMappingURL=chunk-
|
|
3372
|
+
//# sourceMappingURL=chunk-TSFNLY3K.cjs.map
|
|
3373
|
+
//# sourceMappingURL=chunk-TSFNLY3K.cjs.map
|