@vishu1301/script-writing 1.5.9 → 1.6.1
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/index.cjs +936 -550
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -2
- package/dist/index.d.ts +7 -2
- package/dist/index.js +937 -551
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React4, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
|
2
|
-
import { Users, Box, Shirt, Car, Armchair, UserPlus, MapPin, Map as Map$1,
|
|
2
|
+
import { ArrowRight, User, ChevronRight, Sparkles, Check, Users, Box, Shirt, Car, Armchair, UserPlus, MapPin, Map as Map$1, MessageCircle, Parentheses, Clapperboard, Mountain, Loader2, Save, Lock, Unlock, Cog, Upload, FileDown, Languages, Keyboard, AlignLeft, Tags, ChevronDown, X, Video, Settings2, Eye, Pencil, BookOpen, Search, Zap, Info, Frame, BookText, AsteriskIcon, Target, Activity, MonitorPlay, Crosshair, Clock, Camera, Aperture, SlidersHorizontal, Sun, Wand2, Volume2, Layers } from 'lucide-react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import * as pdfjs from 'pdfjs-dist';
|
|
5
5
|
import jsPDF from 'jspdf';
|
|
@@ -49,12 +49,12 @@ var blockTypes = [
|
|
|
49
49
|
];
|
|
50
50
|
var uuid = () => Math.random().toString(36).slice(2, 9);
|
|
51
51
|
var icons = {
|
|
52
|
-
SCENE_HEADING: /* @__PURE__ */ jsx(
|
|
53
|
-
ACTION: /* @__PURE__ */ jsx(
|
|
54
|
-
CHARACTER: /* @__PURE__ */ jsx(User, { className: "w-
|
|
55
|
-
PARENTHETICAL: /* @__PURE__ */ jsx(Parentheses, { className: "w-
|
|
56
|
-
DIALOGUE: /* @__PURE__ */ jsx(
|
|
57
|
-
TRANSITION: /* @__PURE__ */ jsx(
|
|
52
|
+
SCENE_HEADING: /* @__PURE__ */ jsx(Mountain, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
53
|
+
ACTION: /* @__PURE__ */ jsx(Clapperboard, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
54
|
+
CHARACTER: /* @__PURE__ */ jsx(User, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
55
|
+
PARENTHETICAL: /* @__PURE__ */ jsx(Parentheses, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
56
|
+
DIALOGUE: /* @__PURE__ */ jsx(MessageCircle, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
57
|
+
TRANSITION: /* @__PURE__ */ jsx(ArrowRight, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 })
|
|
58
58
|
};
|
|
59
59
|
var blockStyles = {
|
|
60
60
|
SCENE_HEADING: {
|
|
@@ -789,7 +789,7 @@ function PhoneticSuggestions({
|
|
|
789
789
|
] });
|
|
790
790
|
}
|
|
791
791
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
|
792
|
-
function PdfImporter({ onScriptImported, disabled, children }) {
|
|
792
|
+
function PdfImporter({ onScriptImported, disabled, children, className }) {
|
|
793
793
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
794
794
|
const [error, setError] = useState(null);
|
|
795
795
|
const fileInputRef = useRef(null);
|
|
@@ -826,9 +826,9 @@ function PdfImporter({ onScriptImported, disabled, children }) {
|
|
|
826
826
|
let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
827
827
|
if (!divText) return;
|
|
828
828
|
let type = "ACTION";
|
|
829
|
-
for (const
|
|
830
|
-
if (typeMap[
|
|
831
|
-
type = typeMap[
|
|
829
|
+
for (const className2 of Array.from(div.classList)) {
|
|
830
|
+
if (typeMap[className2]) {
|
|
831
|
+
type = typeMap[className2];
|
|
832
832
|
break;
|
|
833
833
|
}
|
|
834
834
|
}
|
|
@@ -932,7 +932,7 @@ function PdfImporter({ onScriptImported, disabled, children }) {
|
|
|
932
932
|
{
|
|
933
933
|
onClick: handleClick,
|
|
934
934
|
disabled: isProcessing || disabled,
|
|
935
|
-
className: `flex items-center justify-center transition-all duration-200 active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 ${isProcessing ? "w-auto px-3 sm:px-4 h-8 sm:h-10 rounded-full text-sm font-semibold bg-zinc-100 text-zinc-500" : "w-8 h-8 sm:w-10 sm:h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
|
|
935
|
+
className: className || `flex items-center justify-center transition-all duration-200 active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 ${isProcessing ? "w-auto px-3 sm:px-4 h-8 sm:h-10 rounded-full text-sm font-semibold bg-zinc-100 text-zinc-500" : "w-8 h-8 sm:w-10 sm:h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
|
|
936
936
|
"aria-label": "Import Script",
|
|
937
937
|
children: isProcessing ? /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-semibold", children: "Processing..." }) : children
|
|
938
938
|
}
|
|
@@ -1216,6 +1216,44 @@ function PhoneticGuide({
|
|
|
1216
1216
|
}
|
|
1217
1217
|
);
|
|
1218
1218
|
}
|
|
1219
|
+
function Tooltip({
|
|
1220
|
+
children,
|
|
1221
|
+
content,
|
|
1222
|
+
shortcut,
|
|
1223
|
+
align = "center"
|
|
1224
|
+
}) {
|
|
1225
|
+
const alignClasses = {
|
|
1226
|
+
center: "left-1/2 -translate-x-1/2 items-center",
|
|
1227
|
+
left: "left-0 items-start",
|
|
1228
|
+
right: "right-0 items-end"
|
|
1229
|
+
};
|
|
1230
|
+
const arrowClasses = {
|
|
1231
|
+
center: "",
|
|
1232
|
+
left: "left-3.5",
|
|
1233
|
+
right: "right-3.5"
|
|
1234
|
+
};
|
|
1235
|
+
return /* @__PURE__ */ jsxs("div", { className: "group relative flex items-center justify-center", children: [
|
|
1236
|
+
children,
|
|
1237
|
+
/* @__PURE__ */ jsxs(
|
|
1238
|
+
"div",
|
|
1239
|
+
{
|
|
1240
|
+
className: `absolute top-[calc(100%+8px)] scale-95 opacity-0 pointer-events-none group-hover:scale-100 group-hover:opacity-100 transition-all duration-150 ease-out z-[100] flex flex-col ${alignClasses[align]}`,
|
|
1241
|
+
children: [
|
|
1242
|
+
/* @__PURE__ */ jsx(
|
|
1243
|
+
"div",
|
|
1244
|
+
{
|
|
1245
|
+
className: `w-2 h-2 rotate-45 bg-blumine-950 border-l border-t border-white/10 -mb-1 shadow-sm ${align === "center" ? "" : "relative"} ${arrowClasses[align]}`
|
|
1246
|
+
}
|
|
1247
|
+
),
|
|
1248
|
+
/* @__PURE__ */ jsxs("div", { className: "bg-blumine-950/95 text-white text-[11px] font-medium px-2.5 py-1.5 rounded-lg shadow-xl border border-white/10 backdrop-blur-sm whitespace-nowrap flex items-center gap-1.5", children: [
|
|
1249
|
+
/* @__PURE__ */ jsx("span", { children: content }),
|
|
1250
|
+
shortcut && /* @__PURE__ */ jsx("kbd", { className: "bg-blumine-800 text-[10px] text-blumine-300 px-1.5 py-0.5 rounded border border-zinc-700 font-sans font-semibold", children: shortcut })
|
|
1251
|
+
] })
|
|
1252
|
+
]
|
|
1253
|
+
}
|
|
1254
|
+
)
|
|
1255
|
+
] });
|
|
1256
|
+
}
|
|
1219
1257
|
function ScreenplayEditorView({
|
|
1220
1258
|
blocks,
|
|
1221
1259
|
refs,
|
|
@@ -1257,7 +1295,8 @@ function ScreenplayEditorView({
|
|
|
1257
1295
|
currentLanguage,
|
|
1258
1296
|
setCurrentLanguage,
|
|
1259
1297
|
phoneticSuggestions,
|
|
1260
|
-
handleSelectPhoneticSuggestion
|
|
1298
|
+
handleSelectPhoneticSuggestion,
|
|
1299
|
+
autosaveStatus
|
|
1261
1300
|
}) {
|
|
1262
1301
|
const [isRulesOpen, setIsRulesOpen] = useState(false);
|
|
1263
1302
|
const [isLanguageOpen, setIsLanguageOpen] = useState(false);
|
|
@@ -1307,168 +1346,299 @@ function ScreenplayEditorView({
|
|
|
1307
1346
|
document.head.appendChild(style);
|
|
1308
1347
|
}
|
|
1309
1348
|
}, [COURIER_STACK]);
|
|
1310
|
-
if (isLoading) {
|
|
1311
|
-
return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-white/80 transition-opacity", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
|
|
1312
|
-
/* @__PURE__ */ jsx(Loader2, { className: "w-8 h-8 text-zinc-400 animate-spin" }),
|
|
1313
|
-
/* @__PURE__ */ jsx("p", { className: "text-zinc-500 text-sm font-medium", children: "Loading script..." })
|
|
1314
|
-
] }) });
|
|
1315
|
-
}
|
|
1316
1349
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1317
|
-
/* @__PURE__ */ jsxs("div", { className: "
|
|
1318
|
-
/* @__PURE__ */ jsx("
|
|
1350
|
+
isLoading && /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-blumine-500/40 backdrop-blur-md p-6", children: [
|
|
1351
|
+
/* @__PURE__ */ jsx("style", { children: `
|
|
1352
|
+
@keyframes gpu-spin {
|
|
1353
|
+
0% { transform: rotate(0deg); }
|
|
1354
|
+
100% { transform: rotate(360deg); }
|
|
1355
|
+
}
|
|
1356
|
+
.gpu-spinner-container {
|
|
1357
|
+
transform: translate3d(0,0,0);
|
|
1358
|
+
will-change: transform;
|
|
1359
|
+
}
|
|
1360
|
+
.gpu-spinner {
|
|
1361
|
+
width: 32px;
|
|
1362
|
+
height: 32px;
|
|
1363
|
+
border: 3.5px solid rgba(255, 255, 255, 0.25);
|
|
1364
|
+
border-top-color: #ffffff;
|
|
1365
|
+
border-radius: 50%;
|
|
1366
|
+
animation: gpu-spin 0.85s linear infinite;
|
|
1367
|
+
will-change: transform;
|
|
1368
|
+
transform: translate3d(0,0,0);
|
|
1369
|
+
}
|
|
1370
|
+
` }),
|
|
1371
|
+
/* @__PURE__ */ jsx("div", { className: "h-full w-full border-2 border-white border-dashed rounded-[2.5rem] flex items-center justify-center gpu-spinner-container", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
|
|
1372
|
+
/* @__PURE__ */ jsx("div", { className: "gpu-spinner" }),
|
|
1373
|
+
/* @__PURE__ */ jsx("p", { className: "text-white text-lg font-semibold mt-4", children: "Preparing Script..." }),
|
|
1374
|
+
/* @__PURE__ */ jsx("p", { className: "text-white text-xs font-medium mt-2", children: "Please wait while we prepare your screenplay." }),
|
|
1375
|
+
/* @__PURE__ */ jsx("span", { className: "text-white/80 text-xs mt-2", children: "Status: Arranging data..." })
|
|
1376
|
+
] }) })
|
|
1377
|
+
] }),
|
|
1378
|
+
/* @__PURE__ */ jsxs("div", { className: "sticky top-0 left-0 right-0 z-50 w-full bg-zinc-50/95 backdrop-blur-md border-b border-zinc-200/60 shadow-[0_1px_2px_rgba(0,0,0,0.01)] flex flex-wrap lg:flex-nowrap items-center justify-between px-3 sm:px-6 py-2 mb-8 select-none transition-all gap-y-2", children: [
|
|
1379
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 w-auto shrink-0 order-1", children: [
|
|
1380
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold tracking-wider text-blumine-400/80 uppercase", children: "Script Editor" }),
|
|
1381
|
+
autosaveStatus === "saved" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-emerald-50 text-emerald-600 border border-emerald-100/50 animate-in fade-in duration-300", children: [
|
|
1382
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" }),
|
|
1383
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Script synced" })
|
|
1384
|
+
] }),
|
|
1385
|
+
autosaveStatus === "saving" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-blue-50 text-blue-600 border border-blue-100/50 animate-in fade-in duration-300", children: [
|
|
1386
|
+
/* @__PURE__ */ jsx(Loader2, { className: "w-2.5 h-2.5 animate-spin" }),
|
|
1387
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Saving..." })
|
|
1388
|
+
] }),
|
|
1389
|
+
autosaveStatus === "typing" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-amber-50 text-amber-600 border border-amber-100/50 animate-in fade-in duration-300", children: [
|
|
1390
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-amber-500 animate-pulse" }),
|
|
1391
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Drafting..." })
|
|
1392
|
+
] }),
|
|
1393
|
+
autosaveStatus === "error" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-rose-50 text-rose-600 border border-rose-100/50 animate-in fade-in duration-300", children: [
|
|
1394
|
+
/* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-rose-500 animate-pulse" }),
|
|
1395
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Error saving" })
|
|
1396
|
+
] })
|
|
1397
|
+
] }),
|
|
1398
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center justify-center gap-1 sm:gap-2 basis-full lg:basis-auto flex-initial min-w-0 py-1 lg:py-0.5 order-3 lg:order-2", children: blockTypes.map((type) => {
|
|
1319
1399
|
var _a;
|
|
1320
1400
|
const selected = ((_a = blocks.find((b) => b.id === focusedBlockId)) == null ? void 0 : _a.type) === type;
|
|
1321
|
-
return /* @__PURE__ */
|
|
1322
|
-
|
|
1401
|
+
return /* @__PURE__ */ jsx(
|
|
1402
|
+
Tooltip,
|
|
1323
1403
|
{
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1404
|
+
content: blockStyles[type].label,
|
|
1405
|
+
shortcut: "Ctrl + \u2191/\u2193",
|
|
1406
|
+
children: /* @__PURE__ */ jsx(
|
|
1407
|
+
"button",
|
|
1408
|
+
{
|
|
1409
|
+
type: "button",
|
|
1410
|
+
disabled: isLocked,
|
|
1411
|
+
onClick: () => handleBlockTypeChange(type),
|
|
1412
|
+
className: `w-8 h-8 sm:w-9 sm:h-9 flex shrink-0 items-center justify-center rounded-lg transition-all duration-150 ease-out active:scale-95 whitespace-nowrap ${selected ? "bg-blumine-200/60 text-blumine-800 shadow-sm border border-blumine-200/50" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"} ${isLocked ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
1413
|
+
children: /* @__PURE__ */ jsx(
|
|
1414
|
+
"div",
|
|
1415
|
+
{
|
|
1416
|
+
className: `flex items-center justify-center transition-all duration-150 ${selected ? "scale-105 opacity-100" : "opacity-80 hover:opacity-100"}`,
|
|
1417
|
+
children: icons[type]
|
|
1418
|
+
}
|
|
1419
|
+
)
|
|
1420
|
+
}
|
|
1421
|
+
)
|
|
1338
1422
|
},
|
|
1339
1423
|
type
|
|
1340
1424
|
);
|
|
1341
1425
|
}) }),
|
|
1342
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5
|
|
1343
|
-
/* @__PURE__ */ jsx(
|
|
1344
|
-
showPdfImport && !isLocked && /* @__PURE__ */ jsx(
|
|
1345
|
-
PdfImporter,
|
|
1346
|
-
{
|
|
1347
|
-
disabled: isLocked,
|
|
1348
|
-
onScriptImported: handleScriptImport,
|
|
1349
|
-
children: /* @__PURE__ */ jsx("div", { className: "w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-full text-blumine-500 hover:text-blumine-900 hover:bg-white/70 transition active:scale-95", children: /* @__PURE__ */ jsx(Upload, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" }) })
|
|
1350
|
-
}
|
|
1351
|
-
),
|
|
1352
|
-
onToggleLock && /* @__PURE__ */ jsx(
|
|
1353
|
-
"button",
|
|
1354
|
-
{
|
|
1355
|
-
onClick: onToggleLock,
|
|
1356
|
-
className: `w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-full transition-all duration-200 active:scale-95 ${isLocked ? "text-rose-500 bg-rose-50/60" : "text-blumine-500 hover:text-blumine-900 hover:bg-white/70"}`,
|
|
1357
|
-
children: isLocked ? /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" }) : /* @__PURE__ */ jsx(Unlock, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
1358
|
-
}
|
|
1359
|
-
),
|
|
1360
|
-
onSave && showSaveButton && !isLocked && /* @__PURE__ */ jsx(
|
|
1426
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1 sm:gap-1.5 w-auto lg:w-[220px] shrink-0 order-2 lg:order-3", children: [
|
|
1427
|
+
onSave && showSaveButton && !isLocked && /* @__PURE__ */ jsx(Tooltip, { content: "Save changes", align: "right", children: /* @__PURE__ */ jsx(
|
|
1361
1428
|
"button",
|
|
1362
1429
|
{
|
|
1363
1430
|
onClick: onSave,
|
|
1364
|
-
className: "w-
|
|
1365
|
-
children: /* @__PURE__ */ jsx(
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1371
|
-
|
|
1372
|
-
className: "w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-full text-blumine-500 hover:text-blumine-900 hover:bg-white/70 transition active:scale-95",
|
|
1373
|
-
children: /* @__PURE__ */ jsx(FileDown, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
1431
|
+
className: "w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700 transition active:scale-95",
|
|
1432
|
+
children: /* @__PURE__ */ jsx(
|
|
1433
|
+
Save,
|
|
1434
|
+
{
|
|
1435
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1436
|
+
strokeWidth: 1.5
|
|
1437
|
+
}
|
|
1438
|
+
)
|
|
1374
1439
|
}
|
|
1375
|
-
),
|
|
1376
|
-
|
|
1377
|
-
|
|
1440
|
+
) }),
|
|
1441
|
+
onToggleLock && /* @__PURE__ */ jsx(
|
|
1442
|
+
Tooltip,
|
|
1378
1443
|
{
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
children: /* @__PURE__ */ jsx(
|
|
1444
|
+
content: isLocked ? "Unlock Screenplay" : "Lock Screenplay",
|
|
1445
|
+
align: "right",
|
|
1446
|
+
children: /* @__PURE__ */ jsx(
|
|
1447
|
+
"button",
|
|
1448
|
+
{
|
|
1449
|
+
onClick: onToggleLock,
|
|
1450
|
+
className: `w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg transition active:scale-95 ${isLocked ? "text-rose-500 hover:bg-rose-50 hover:text-rose-700 bg-rose-50/50" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"}`,
|
|
1451
|
+
children: isLocked ? /* @__PURE__ */ jsx(
|
|
1452
|
+
Lock,
|
|
1453
|
+
{
|
|
1454
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1455
|
+
strokeWidth: 1.5
|
|
1456
|
+
}
|
|
1457
|
+
) : /* @__PURE__ */ jsx(
|
|
1458
|
+
Unlock,
|
|
1459
|
+
{
|
|
1460
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1461
|
+
strokeWidth: 1.5
|
|
1462
|
+
}
|
|
1463
|
+
)
|
|
1464
|
+
}
|
|
1465
|
+
)
|
|
1382
1466
|
}
|
|
1383
1467
|
),
|
|
1384
1468
|
/* @__PURE__ */ jsxs("div", { ref: rulesRef, className: "relative flex items-center", children: [
|
|
1385
|
-
/* @__PURE__ */ jsx(
|
|
1469
|
+
/* @__PURE__ */ jsx(Tooltip, { content: "Settings & Actions", align: "right", children: /* @__PURE__ */ jsx(
|
|
1386
1470
|
"button",
|
|
1387
1471
|
{
|
|
1388
1472
|
onClick: () => setIsRulesOpen(!isRulesOpen),
|
|
1389
|
-
className: `w-
|
|
1390
|
-
children: /* @__PURE__ */ jsx(
|
|
1473
|
+
className: `w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg transition-all duration-200 active:scale-95 ${isRulesOpen ? "bg-blumine-200/60 text-blumine-800 shadow-sm border border-blumine-200/50" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"}`,
|
|
1474
|
+
children: /* @__PURE__ */ jsx(
|
|
1475
|
+
Cog,
|
|
1476
|
+
{
|
|
1477
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1478
|
+
strokeWidth: 1.5
|
|
1479
|
+
}
|
|
1480
|
+
)
|
|
1391
1481
|
}
|
|
1392
|
-
),
|
|
1393
|
-
isRulesOpen && /* @__PURE__ */ jsxs("div", { className: "absolute
|
|
1394
|
-
/* @__PURE__ */ jsx("div", { className: "absolute -top-
|
|
1395
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-start justify-between mb-
|
|
1396
|
-
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 flex items-center justify-center rounded-xl bg-gradient-to-b from-white to-blumine-50 text-blumine-
|
|
1482
|
+
) }),
|
|
1483
|
+
isRulesOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-[calc(100%+14px)] w-[360px] max-w-[90vw] p-4 rounded-2xl bg-white border border-blumine-200 shadow-2xl backdrop-blur-xl origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
|
|
1484
|
+
/* @__PURE__ */ jsx("div", { className: "absolute -top-1.5 right-3.5 w-3 h-3 rotate-45 bg-white border-l border-t border-blumine-200" }),
|
|
1485
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-start justify-between mb-4 px-1", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
1486
|
+
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 flex items-center justify-center rounded-xl bg-gradient-to-b from-white to-blumine-50/50 text-blumine-600 border border-blumine-200 shadow-inner", children: /* @__PURE__ */ jsx(Cog, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
|
|
1397
1487
|
/* @__PURE__ */ jsxs("div", { children: [
|
|
1398
|
-
/* @__PURE__ */ jsx("h4", { className: "text-[15px] font-semibold text-blumine-
|
|
1399
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-blumine-
|
|
1488
|
+
/* @__PURE__ */ jsx("h4", { className: "text-[15px] font-semibold text-blumine-800 leading-tight", children: "Settings & Actions" }),
|
|
1489
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-blumine-400 mt-1", children: "Screenplay controls & keyboard shortcuts" })
|
|
1400
1490
|
] })
|
|
1401
1491
|
] }) }),
|
|
1402
|
-
/* @__PURE__ */
|
|
1403
|
-
{
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1492
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2 mb-4", children: [
|
|
1493
|
+
/* @__PURE__ */ jsx("div", { className: "px-1.5 mb-1", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold text-blumine-400 uppercase tracking-wider", children: "Document Actions" }) }),
|
|
1494
|
+
showPdfImport && /* @__PURE__ */ jsx(
|
|
1495
|
+
PdfImporter,
|
|
1496
|
+
{
|
|
1497
|
+
disabled: isLocked,
|
|
1498
|
+
onScriptImported: (title, content, preParsedBlocks) => {
|
|
1499
|
+
handleScriptImport(title, content, preParsedBlocks);
|
|
1500
|
+
setIsRulesOpen(false);
|
|
1501
|
+
},
|
|
1502
|
+
className: "w-full text-left",
|
|
1503
|
+
children: /* @__PURE__ */ jsxs(
|
|
1504
|
+
"div",
|
|
1505
|
+
{
|
|
1506
|
+
className: `w-full flex items-center gap-3 p-3 rounded-xl border border-blumine-100 bg-gradient-to-b from-white to-blumine-50/10 hover:from-blumine-50/40 hover:to-blumine-50/60 hover:border-blumine-200 hover:shadow-sm active:scale-[0.98] transition-all duration-200 cursor-pointer ${isLocked ? "opacity-60 cursor-not-allowed pointer-events-none" : ""}`,
|
|
1507
|
+
children: [
|
|
1508
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 flex items-center justify-center rounded-lg bg-blumine-50 text-blumine-600 border border-blumine-100 shrink-0", children: /* @__PURE__ */ jsx(Upload, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
|
|
1509
|
+
/* @__PURE__ */ jsxs("div", { className: "flex-1 text-left", children: [
|
|
1510
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: "Import PDF" }),
|
|
1511
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: isLocked ? "Unlock screenplay to import files" : "Load screenplay from external file" })
|
|
1512
|
+
] })
|
|
1513
|
+
]
|
|
1514
|
+
}
|
|
1515
|
+
)
|
|
1516
|
+
}
|
|
1517
|
+
),
|
|
1518
|
+
onToggleLock && /* @__PURE__ */ jsxs(
|
|
1519
|
+
"button",
|
|
1520
|
+
{
|
|
1521
|
+
onClick: () => {
|
|
1522
|
+
onToggleLock();
|
|
1523
|
+
},
|
|
1524
|
+
className: "w-full text-left flex items-center gap-3 p-3 rounded-xl border border-blumine-100 bg-gradient-to-b from-white to-blumine-50/10 hover:from-blumine-50/40 hover:to-blumine-50/60 hover:border-blumine-200 hover:shadow-sm active:scale-[0.98] transition-all duration-200",
|
|
1525
|
+
children: [
|
|
1526
|
+
/* @__PURE__ */ jsx(
|
|
1527
|
+
"div",
|
|
1437
1528
|
{
|
|
1438
|
-
className:
|
|
1439
|
-
children:
|
|
1440
|
-
}
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1529
|
+
className: `w-8 h-8 flex items-center justify-center rounded-lg shrink-0 border ${isLocked ? "bg-rose-50 text-rose-500 border-rose-100/50" : "bg-blumine-50 text-blumine-600 border-blumine-100/50"}`,
|
|
1530
|
+
children: isLocked ? /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4", strokeWidth: 1.5 }) : /* @__PURE__ */ jsx(Unlock, { className: "w-4 h-4", strokeWidth: 1.5 })
|
|
1531
|
+
}
|
|
1532
|
+
),
|
|
1533
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1534
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: isLocked ? "Unlock Screenplay" : "Lock Screenplay" }),
|
|
1535
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: isLocked ? "Enable editing controls" : "Prevent accidental editing" })
|
|
1536
|
+
] })
|
|
1537
|
+
]
|
|
1538
|
+
}
|
|
1539
|
+
),
|
|
1540
|
+
onSaveAsPdf && showSaveButton && /* @__PURE__ */ jsxs(
|
|
1541
|
+
"button",
|
|
1542
|
+
{
|
|
1543
|
+
onClick: () => {
|
|
1544
|
+
onSaveAsPdf();
|
|
1545
|
+
setIsRulesOpen(false);
|
|
1546
|
+
},
|
|
1547
|
+
className: "w-full text-left flex items-center gap-3 p-3 rounded-xl border border-blumine-100 bg-gradient-to-b from-white to-blumine-50/10 hover:from-blumine-50/40 hover:to-blumine-50/60 hover:border-blumine-200 hover:shadow-sm active:scale-[0.98] transition-all duration-200",
|
|
1548
|
+
children: [
|
|
1549
|
+
/* @__PURE__ */ jsx("div", { className: "w-8 h-8 flex items-center justify-center rounded-lg bg-blumine-50 text-blumine-600 border border-blumine-100 shrink-0", children: /* @__PURE__ */ jsx(FileDown, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
|
|
1550
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
1551
|
+
/* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: "Save as PDF" }),
|
|
1552
|
+
/* @__PURE__ */ jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: "Export screenplay to standard print PDF" })
|
|
1553
|
+
] })
|
|
1554
|
+
]
|
|
1555
|
+
}
|
|
1556
|
+
)
|
|
1557
|
+
] }),
|
|
1558
|
+
/* @__PURE__ */ jsx("div", { className: "border-t border-blumine-100/60 my-4" }),
|
|
1559
|
+
/* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
|
|
1560
|
+
/* @__PURE__ */ jsx("div", { className: "px-1.5 mb-1", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold text-blumine-400 uppercase tracking-wider", children: "Keyboard Shortcuts" }) }),
|
|
1561
|
+
[
|
|
1562
|
+
{
|
|
1563
|
+
title: "New Block",
|
|
1564
|
+
desc: "Insert the next section",
|
|
1565
|
+
key: ["Enter"]
|
|
1566
|
+
},
|
|
1567
|
+
{
|
|
1568
|
+
title: "Delete Block",
|
|
1569
|
+
desc: "Remove selected section",
|
|
1570
|
+
key: ["Backspace \u{1F860}"]
|
|
1571
|
+
},
|
|
1572
|
+
{
|
|
1573
|
+
title: "Change Type",
|
|
1574
|
+
desc: "Cycle block styles",
|
|
1575
|
+
key: ["Ctrl", "+", "\u2191/\u2193"]
|
|
1576
|
+
}
|
|
1577
|
+
].map((item) => /* @__PURE__ */ jsxs(
|
|
1578
|
+
"div",
|
|
1579
|
+
{
|
|
1580
|
+
className: "flex items-center justify-between gap-4 p-2.5 rounded-xl bg-gradient-to-b from-white to-blumine-50/30 border border-blumine-100/80 shadow-[inset_0_1px_0_rgba(255,255,255,0.8)]",
|
|
1581
|
+
children: [
|
|
1582
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 text-left", children: [
|
|
1583
|
+
/* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-blumine-800", children: item.title }),
|
|
1584
|
+
/* @__PURE__ */ jsx("span", { className: "text-[10px] text-blumine-400 truncate mt-0.5", children: item.desc })
|
|
1585
|
+
] }),
|
|
1586
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0", children: item.key.map(
|
|
1587
|
+
(k, i) => k === "+" ? /* @__PURE__ */ jsx(
|
|
1588
|
+
"span",
|
|
1589
|
+
{
|
|
1590
|
+
className: "text-blumine-400 text-xs font-semibold",
|
|
1591
|
+
children: "+"
|
|
1592
|
+
},
|
|
1593
|
+
i
|
|
1594
|
+
) : /* @__PURE__ */ jsx(
|
|
1595
|
+
"kbd",
|
|
1596
|
+
{
|
|
1597
|
+
className: "min-w-[28px] px-2 py-1 text-[11px] font-bold text-blumine-700 bg-gradient-to-b from-white to-blumine-100 border border-blumine-200 rounded-lg text-center shadow-[inset_0_1px_0_rgba(255,255,255,0.9)]",
|
|
1598
|
+
children: k
|
|
1599
|
+
},
|
|
1600
|
+
i
|
|
1601
|
+
)
|
|
1602
|
+
) })
|
|
1603
|
+
]
|
|
1604
|
+
},
|
|
1605
|
+
item.title
|
|
1606
|
+
))
|
|
1607
|
+
] })
|
|
1448
1608
|
] })
|
|
1449
1609
|
] }),
|
|
1450
1610
|
/* @__PURE__ */ jsxs(
|
|
1451
1611
|
"div",
|
|
1452
1612
|
{
|
|
1453
1613
|
ref: languageRef,
|
|
1454
|
-
className: "flex items-center pl-1.5 border-l border-blumine-200
|
|
1614
|
+
className: "relative flex items-center pl-1.5 border-l border-blumine-200",
|
|
1455
1615
|
children: [
|
|
1456
|
-
/* @__PURE__ */
|
|
1457
|
-
|
|
1616
|
+
/* @__PURE__ */ jsx(
|
|
1617
|
+
Tooltip,
|
|
1458
1618
|
{
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
children:
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1619
|
+
content: `Input Language: ${LANGUAGE_CONFIGS[currentLanguage].name}`,
|
|
1620
|
+
align: "right",
|
|
1621
|
+
children: /* @__PURE__ */ jsx(
|
|
1622
|
+
"button",
|
|
1623
|
+
{
|
|
1624
|
+
onClick: () => setIsLanguageOpen(!isLanguageOpen),
|
|
1625
|
+
className: `w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg transition-all duration-200 active:scale-95 ${isLanguageOpen ? "bg-blumine-200/60 text-blumine-800 border border-blumine-200 shadow-sm" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"}`,
|
|
1626
|
+
children: /* @__PURE__ */ jsx(
|
|
1627
|
+
Languages,
|
|
1628
|
+
{
|
|
1629
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1630
|
+
strokeWidth: 1.5
|
|
1631
|
+
}
|
|
1632
|
+
)
|
|
1633
|
+
}
|
|
1634
|
+
)
|
|
1465
1635
|
}
|
|
1466
1636
|
),
|
|
1467
|
-
isLanguageOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-[calc(100%+14px)] w-[400px] max-w-[90vw] p-3 rounded-
|
|
1468
|
-
/* @__PURE__ */ jsx("div", { className: "absolute -top-
|
|
1637
|
+
isLanguageOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-[calc(100%+14px)] w-[400px] max-w-[90vw] p-3 rounded-2xl bg-white border border-blumine-200 shadow-xl backdrop-blur-xl origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
|
|
1638
|
+
/* @__PURE__ */ jsx("div", { className: "absolute -top-1.5 right-3.5 w-3 h-3 rotate-45 bg-white border-l border-t border-blumine-200" }),
|
|
1469
1639
|
/* @__PURE__ */ jsxs("div", { className: "px-2 mb-3", children: [
|
|
1470
|
-
/* @__PURE__ */ jsx("h4", { className: "text-[13px] font-bold text-blumine-
|
|
1471
|
-
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-blumine-
|
|
1640
|
+
/* @__PURE__ */ jsx("h4", { className: "text-[13px] font-bold text-blumine-800 uppercase tracking-wider", children: "Select Input Language" }),
|
|
1641
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-blumine-400 mt-0.5", children: "Direct keyboard mapping (InScript logic)" })
|
|
1472
1642
|
] }),
|
|
1473
1643
|
/* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1.5 max-h-[300px] overflow-y-auto pr-1 flex-1 custom-scrollbar", children: Object.keys(LANGUAGE_CONFIGS).map(
|
|
1474
1644
|
(lang) => /* @__PURE__ */ jsxs(
|
|
@@ -1478,16 +1648,16 @@ function ScreenplayEditorView({
|
|
|
1478
1648
|
setCurrentLanguage(lang);
|
|
1479
1649
|
setIsLanguageOpen(false);
|
|
1480
1650
|
},
|
|
1481
|
-
className: `group flex items-center justify-between px-3.5 py-2.5 rounded-
|
|
1651
|
+
className: `group flex items-center justify-between px-3.5 py-2.5 rounded-xl transition-all duration-200 ${currentLanguage === lang ? "bg-blumine-100/80 text-blumine-800 border border-blumine-200/50 shadow-sm" : "hover:bg-blumine-50 border border-transparent"}`,
|
|
1482
1652
|
children: [
|
|
1483
1653
|
/* @__PURE__ */ jsx(
|
|
1484
1654
|
"span",
|
|
1485
1655
|
{
|
|
1486
|
-
className: `text-sm font-medium ${currentLanguage === lang ? "text-blumine-
|
|
1656
|
+
className: `text-sm font-medium ${currentLanguage === lang ? "text-blumine-800 font-semibold" : "text-blumine-500"}`,
|
|
1487
1657
|
children: LANGUAGE_CONFIGS[lang].name
|
|
1488
1658
|
}
|
|
1489
1659
|
),
|
|
1490
|
-
currentLanguage === lang && /* @__PURE__ */ jsx("div", { className: "w-5 h-5 rounded-full bg-blumine-
|
|
1660
|
+
currentLanguage === lang && /* @__PURE__ */ jsx("div", { className: "w-5 h-5 rounded-full bg-blumine-700 flex items-center justify-center text-white", children: /* @__PURE__ */ jsx(Check, { className: "w-3 h-3", strokeWidth: 2 }) })
|
|
1491
1661
|
]
|
|
1492
1662
|
},
|
|
1493
1663
|
lang
|
|
@@ -1497,15 +1667,20 @@ function ScreenplayEditorView({
|
|
|
1497
1667
|
]
|
|
1498
1668
|
}
|
|
1499
1669
|
),
|
|
1500
|
-
LANGUAGE_CONFIGS[currentLanguage].isPhonetic && /* @__PURE__ */ jsx(
|
|
1670
|
+
LANGUAGE_CONFIGS[currentLanguage].isPhonetic && /* @__PURE__ */ jsx(Tooltip, { content: "Phonetic Keyboard Rules", align: "right", children: /* @__PURE__ */ jsx(
|
|
1501
1671
|
"button",
|
|
1502
1672
|
{
|
|
1503
1673
|
onClick: () => setIsPhoneticGuideOpen(true),
|
|
1504
|
-
className: "w-
|
|
1505
|
-
|
|
1506
|
-
|
|
1674
|
+
className: "w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700 transition active:scale-95 ml-1",
|
|
1675
|
+
children: /* @__PURE__ */ jsx(
|
|
1676
|
+
Keyboard,
|
|
1677
|
+
{
|
|
1678
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1679
|
+
strokeWidth: 1.5
|
|
1680
|
+
}
|
|
1681
|
+
)
|
|
1507
1682
|
}
|
|
1508
|
-
)
|
|
1683
|
+
) })
|
|
1509
1684
|
] })
|
|
1510
1685
|
] }),
|
|
1511
1686
|
/* @__PURE__ */ jsx(
|
|
@@ -1516,7 +1691,7 @@ function ScreenplayEditorView({
|
|
|
1516
1691
|
onClose: () => setIsPhoneticGuideOpen(false)
|
|
1517
1692
|
}
|
|
1518
1693
|
),
|
|
1519
|
-
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-12 pb-24 w-full items-center justify-center", children: /* @__PURE__ */ jsx(
|
|
1694
|
+
/* @__PURE__ */ jsx("div", { className: "flex flex-col gap-12 pb-24 w-full items-center justify-center px-4 sm:px-6 md:px-8", children: /* @__PURE__ */ jsx(
|
|
1520
1695
|
"div",
|
|
1521
1696
|
{
|
|
1522
1697
|
className: "relative bg-[#fdfdfc] shadow-2xl shadow-zinc-300/60 border border-zinc-100 rounded-sm md:rounded-md pl-[1.5in] py-[1in] pr-[1in] flex flex-col w-[210mm] min-h-[297mm] shrink-0",
|
|
@@ -1529,346 +1704,370 @@ function ScreenplayEditorView({
|
|
|
1529
1704
|
},
|
|
1530
1705
|
"data-screenplay-editor": "true",
|
|
1531
1706
|
dir: LANGUAGE_CONFIGS[currentLanguage].dir,
|
|
1532
|
-
children: blocks.map((block) =>
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
"select",
|
|
1565
|
-
{
|
|
1566
|
-
className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer w-fit transition-colors",
|
|
1567
|
-
"aria-label": "Scene Type",
|
|
1568
|
-
disabled: isLocked,
|
|
1569
|
-
value: (_a = block.sceneType) != null ? _a : "INT.",
|
|
1570
|
-
onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
|
|
1571
|
-
style: {
|
|
1572
|
-
appearance: "none"
|
|
1573
|
-
},
|
|
1574
|
-
children: [
|
|
1575
|
-
/* @__PURE__ */ jsx("option", { children: "INT." }),
|
|
1576
|
-
/* @__PURE__ */ jsx("option", { children: "EXT." }),
|
|
1577
|
-
/* @__PURE__ */ jsx("option", { children: "INT/EXT." })
|
|
1578
|
-
]
|
|
1579
|
-
}
|
|
1580
|
-
),
|
|
1581
|
-
/* @__PURE__ */ jsx(
|
|
1582
|
-
"div",
|
|
1583
|
-
{
|
|
1584
|
-
ref: (el) => {
|
|
1585
|
-
if (!el) return;
|
|
1586
|
-
refs.current[block.id] = el;
|
|
1587
|
-
},
|
|
1588
|
-
contentEditable: !isLocked,
|
|
1589
|
-
suppressContentEditableWarning: true,
|
|
1590
|
-
"aria-label": `Scene Heading: ${block.text}`,
|
|
1591
|
-
"aria-haspopup": "listbox",
|
|
1592
|
-
"aria-expanded": focusedBlockId === block.id && showSuggestions && locations.length > 0,
|
|
1593
|
-
spellCheck: false,
|
|
1594
|
-
className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
|
|
1595
|
-
style: {
|
|
1596
|
-
minWidth: "3rem"
|
|
1597
|
-
},
|
|
1598
|
-
onInput: (e) => handleBlockTextChange(
|
|
1599
|
-
block.id,
|
|
1600
|
-
e.target.innerText
|
|
1601
|
-
),
|
|
1602
|
-
onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
|
|
1603
|
-
onFocus: () => handleFocus(block.id),
|
|
1604
|
-
onBlur: () => handleBlur(block.id)
|
|
1605
|
-
}
|
|
1606
|
-
),
|
|
1607
|
-
/* @__PURE__ */ jsx("span", { className: "text-zinc-400/80 font-bold", children: "-" }),
|
|
1608
|
-
/* @__PURE__ */ jsx(
|
|
1609
|
-
"select",
|
|
1610
|
-
{
|
|
1611
|
-
className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer transition-colors",
|
|
1612
|
-
"aria-label": "Time of Day",
|
|
1613
|
-
disabled: isLocked,
|
|
1614
|
-
value: (_b = block.timeOfDay) != null ? _b : "DAY",
|
|
1615
|
-
style: {
|
|
1616
|
-
appearance: "none"
|
|
1617
|
-
},
|
|
1618
|
-
onChange: (e) => handleTimeOfDayChange(block.id, e.target.value),
|
|
1619
|
-
children: timeOfDayOptions.map((t) => /* @__PURE__ */ jsx("option", { children: t }, t))
|
|
1620
|
-
}
|
|
1621
|
-
)
|
|
1622
|
-
] }),
|
|
1623
|
-
focusedBlockId === block.id && showSuggestions && locations.length > 0 && /* @__PURE__ */ jsx(
|
|
1624
|
-
"div",
|
|
1625
|
-
{
|
|
1626
|
-
role: "listbox",
|
|
1627
|
-
id: `suggestions-${block.id}`,
|
|
1628
|
-
className: "absolute top-[calc(100%+6px)] left-0 min-w-[240px] z-50 bg-white border border-slate-200/80 shadow-xl shadow-slate-200/40 rounded-xl py-1 overflow-hidden animate-in fade-in zoom-in-95 duration-150",
|
|
1629
|
-
children: /* @__PURE__ */ jsx("div", { className: "max-h-60 overflow-y-auto custom-scrollbar", children: locations.filter(
|
|
1630
|
-
(loc) => loc.startsWith(block.text.toUpperCase()) && loc !== block.text.toUpperCase()
|
|
1631
|
-
).map((loc) => /* @__PURE__ */ jsxs(
|
|
1632
|
-
"div",
|
|
1633
|
-
{
|
|
1634
|
-
role: "option",
|
|
1635
|
-
className: "group flex items-center justify-between px-4 py-2.5 cursor-pointer transition-all duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1636
|
-
onMouseDown: (e) => {
|
|
1637
|
-
e.preventDefault();
|
|
1638
|
-
const element = refs.current[block.id];
|
|
1639
|
-
if (element) {
|
|
1640
|
-
element.innerText = loc;
|
|
1641
|
-
handleBlockTextChange(block.id, loc);
|
|
1642
|
-
element.focus();
|
|
1643
|
-
const range = document.createRange();
|
|
1644
|
-
const sel = window.getSelection();
|
|
1645
|
-
range.selectNodeContents(element);
|
|
1646
|
-
range.collapse(false);
|
|
1647
|
-
sel == null ? void 0 : sel.removeAllRanges();
|
|
1648
|
-
sel == null ? void 0 : sel.addRange(range);
|
|
1649
|
-
}
|
|
1650
|
-
handleBlur(block.id);
|
|
1651
|
-
},
|
|
1652
|
-
children: [
|
|
1653
|
-
/* @__PURE__ */ jsx("span", { className: "text-[12px] font-semibold tracking-wide text-slate-600 uppercase line-clamp-1", children: loc }),
|
|
1654
|
-
/* @__PURE__ */ jsx(ArrowRight, { className: "w-3.5 h-3.5 text-slate-300 opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" })
|
|
1655
|
-
]
|
|
1656
|
-
},
|
|
1657
|
-
loc
|
|
1658
|
-
)) })
|
|
1659
|
-
}
|
|
1660
|
-
),
|
|
1661
|
-
focusedBlockId === block.id && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
1662
|
-
PhoneticSuggestions,
|
|
1663
|
-
{
|
|
1664
|
-
suggestions: phoneticSuggestions,
|
|
1665
|
-
onSelect: handleSelectPhoneticSuggestion
|
|
1666
|
-
}
|
|
1667
|
-
)
|
|
1668
|
-
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1669
|
-
/* @__PURE__ */ jsx(
|
|
1670
|
-
"div",
|
|
1671
|
-
{
|
|
1672
|
-
ref: (el) => {
|
|
1673
|
-
if (!el) return;
|
|
1674
|
-
refs.current[block.id] = el;
|
|
1675
|
-
},
|
|
1676
|
-
contentEditable: !isLocked,
|
|
1677
|
-
suppressContentEditableWarning: true,
|
|
1678
|
-
"aria-label": `${blockStyles[block.type].label} text`,
|
|
1679
|
-
"aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
|
|
1680
|
-
spellCheck: false,
|
|
1681
|
-
className: `block outline-none w-full min-h-[2.5rem] px-4 py-2 break-words ${blockStyles[block.type].className}`,
|
|
1682
|
-
onInput: (e) => handleBlockTextChange(
|
|
1683
|
-
block.id,
|
|
1684
|
-
e.target.innerText
|
|
1685
|
-
),
|
|
1686
|
-
onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
|
|
1687
|
-
onFocus: () => handleFocus(block.id),
|
|
1688
|
-
onBlur: () => handleBlur(block.id),
|
|
1689
|
-
style: blockStyles[block.type].inputStyle
|
|
1690
|
-
}
|
|
1691
|
-
),
|
|
1692
|
-
focusedBlockId === block.id && block.type === "CHARACTER" && showSuggestions && characters.length > 0 && /* @__PURE__ */ jsx(
|
|
1693
|
-
"div",
|
|
1694
|
-
{
|
|
1695
|
-
role: "listbox",
|
|
1696
|
-
id: `suggestions-${block.id}`,
|
|
1697
|
-
className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
|
|
1698
|
-
children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characters.filter(
|
|
1699
|
-
(char) => char.startsWith(block.text.toUpperCase()) && char !== block.text.toUpperCase()
|
|
1700
|
-
).map((char) => /* @__PURE__ */ jsxs(
|
|
1701
|
-
"div",
|
|
1702
|
-
{
|
|
1703
|
-
role: "option",
|
|
1704
|
-
className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1705
|
-
onMouseDown: (e) => {
|
|
1706
|
-
e.preventDefault();
|
|
1707
|
-
const element = refs.current[block.id];
|
|
1708
|
-
if (element) {
|
|
1709
|
-
element.innerText = char;
|
|
1710
|
-
handleBlockTextChange(block.id, char);
|
|
1711
|
-
element.focus();
|
|
1712
|
-
const range = document.createRange();
|
|
1713
|
-
const sel = window.getSelection();
|
|
1714
|
-
range.selectNodeContents(element);
|
|
1715
|
-
range.collapse(false);
|
|
1716
|
-
sel == null ? void 0 : sel.removeAllRanges();
|
|
1717
|
-
sel == null ? void 0 : sel.addRange(range);
|
|
1718
|
-
}
|
|
1719
|
-
handleBlur(block.id);
|
|
1720
|
-
},
|
|
1721
|
-
children: [
|
|
1722
|
-
/* @__PURE__ */ jsx(User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-blumine-500 transition-colors mr-3" }),
|
|
1723
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
|
|
1724
|
-
/* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
|
|
1725
|
-
]
|
|
1726
|
-
},
|
|
1727
|
-
char
|
|
1728
|
-
)) })
|
|
1729
|
-
}
|
|
1730
|
-
),
|
|
1731
|
-
focusedBlockId === block.id && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsx(
|
|
1732
|
-
"div",
|
|
1733
|
-
{
|
|
1734
|
-
role: "listbox",
|
|
1735
|
-
id: `extension-suggestions-${block.id}`,
|
|
1736
|
-
className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
|
|
1737
|
-
children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
|
|
1738
|
-
const openParenIndex = block.text.lastIndexOf("(");
|
|
1739
|
-
const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
|
|
1740
|
-
return ext.toUpperCase().includes(query);
|
|
1741
|
-
}).map((ext) => /* @__PURE__ */ jsxs(
|
|
1742
|
-
"div",
|
|
1743
|
-
{
|
|
1744
|
-
role: "option",
|
|
1745
|
-
className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1746
|
-
onMouseDown: (e) => {
|
|
1747
|
-
e.preventDefault();
|
|
1748
|
-
handleSelectCharacterExtension(ext);
|
|
1749
|
-
},
|
|
1750
|
-
children: [
|
|
1751
|
-
/* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
|
|
1752
|
-
/* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
|
|
1753
|
-
]
|
|
1754
|
-
},
|
|
1755
|
-
ext
|
|
1756
|
-
)) })
|
|
1757
|
-
}
|
|
1758
|
-
),
|
|
1759
|
-
focusedBlockId === block.id && !enhancingBlockId && (block.type === "ACTION" || block.type === "DIALOGUE") && /* @__PURE__ */ jsx(
|
|
1760
|
-
"button",
|
|
1761
|
-
{
|
|
1762
|
-
onClick: () => handleEnhance(block),
|
|
1763
|
-
className: "absolute -right-12 top-1/2 -translate-y-1/2 flex items-center justify-center w-8 h-8 rounded-xl border border-blumine-200/50 bg-white text-blumine-500 hover:border-blumine-400/60 hover:bg-blumine-50/90 hover:ring-2 hover:ring-blumine-100 hover:scale-105 active:scale-95 transition-all duration-200 group/enhance animate-in fade-in slide-in-from-left-2",
|
|
1764
|
-
title: "Enhance with AI",
|
|
1765
|
-
children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 group-hover/enhance:animate-pulse transition-colors" })
|
|
1766
|
-
}
|
|
1767
|
-
),
|
|
1768
|
-
enhancingBlockId === block.id && (enhancementSuggestion || isEnhancing) && /* @__PURE__ */ jsxs(
|
|
1769
|
-
"div",
|
|
1770
|
-
{
|
|
1771
|
-
className: "absolute left-0 right-0 -top-4 -translate-y-full z-[50] animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-300",
|
|
1772
|
-
style: { width: "calc(100% + 2rem)", left: "-1rem" },
|
|
1773
|
-
children: [
|
|
1774
|
-
/* @__PURE__ */ jsx("div", { className: "mx-auto w-full rounded-[2rem] bg-white border border-white/60 shadow-[0_14px_34px_rgba(16,37,54,0.1),0_2px_8px_rgba(16,37,54,0.05)] backdrop-blur-xl p-2 select-none transition-all", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
1775
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-1", children: [
|
|
1776
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1777
|
-
/* @__PURE__ */ jsx("div", { className: "w-9 h-9 flex items-center justify-center rounded-full bg-blumine-50 text-blumine-500 border border-blumine-100 shadow-inner", children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4" }) }),
|
|
1778
|
-
/* @__PURE__ */ jsxs("div", { children: [
|
|
1779
|
-
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-bold text-zinc-900 uppercase tracking-wider leading-none", children: "AI Suggestion" }),
|
|
1780
|
-
!isEnhancing && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-zinc-500 mt-1 font-medium", children: "Refining your screenplay dialogue" })
|
|
1781
|
-
] })
|
|
1782
|
-
] }),
|
|
1783
|
-
!isEnhancing && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
1784
|
-
/* @__PURE__ */ jsx(
|
|
1785
|
-
"button",
|
|
1786
|
-
{
|
|
1787
|
-
onClick: handleRejectEnhance,
|
|
1788
|
-
className: "px-3 py-2 rounded-full text-xs font-bold text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all active:scale-95",
|
|
1789
|
-
children: "Discard"
|
|
1790
|
-
}
|
|
1791
|
-
),
|
|
1792
|
-
/* @__PURE__ */ jsxs(
|
|
1793
|
-
"button",
|
|
1794
|
-
{
|
|
1795
|
-
onClick: handleApproveEnhance,
|
|
1796
|
-
className: "px-4 py-2 rounded-full text-xs font-bold bg-blumine-500 text-white hover:bg-blumine-600 shadow-lg shadow-blumine-500/20 transition-all active:scale-95 flex items-center gap-1.5",
|
|
1797
|
-
children: [
|
|
1798
|
-
/* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5" }),
|
|
1799
|
-
"Apply Changes"
|
|
1800
|
-
]
|
|
1801
|
-
}
|
|
1802
|
-
)
|
|
1803
|
-
] })
|
|
1804
|
-
] }),
|
|
1805
|
-
/* @__PURE__ */ jsx("div", { className: "relative overflow-hidden rounded-[1.25rem] bg-zinc-50/50 border border-zinc-100 p-4 min-h-[4rem]", children: isEnhancing ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2.5 py-1", children: [
|
|
1806
|
-
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-3/4 bg-zinc-200/60 animate-pulse rounded-full" }),
|
|
1807
|
-
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-1/2 bg-zinc-200/60 animate-pulse rounded-full" })
|
|
1808
|
-
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1809
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400 line-through decoration-zinc-300 italic", children: block.text }),
|
|
1810
|
-
/* @__PURE__ */ jsx("p", { className: "text-sm text-zinc-800 font-medium leading-relaxed", children: enhancementSuggestion })
|
|
1811
|
-
] }) })
|
|
1812
|
-
] }) }),
|
|
1813
|
-
/* @__PURE__ */ jsx("div", { className: "absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3.5 h-3.5 bg-white border-r border-b border-zinc-200/50 rotate-45" })
|
|
1814
|
-
]
|
|
1815
|
-
}
|
|
1816
|
-
),
|
|
1817
|
-
focusedBlockId === block.id && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
1818
|
-
PhoneticSuggestions,
|
|
1819
|
-
{
|
|
1820
|
-
suggestions: phoneticSuggestions,
|
|
1821
|
-
onSelect: handleSelectPhoneticSuggestion
|
|
1822
|
-
}
|
|
1823
|
-
)
|
|
1824
|
-
] })
|
|
1825
|
-
},
|
|
1826
|
-
block.id + "-" + block.type
|
|
1827
|
-
);
|
|
1828
|
-
})
|
|
1707
|
+
children: blocks.map((block) => /* @__PURE__ */ jsx(
|
|
1708
|
+
ScreenplayBlockItem,
|
|
1709
|
+
{
|
|
1710
|
+
block,
|
|
1711
|
+
isFocused: focusedBlockId === block.id,
|
|
1712
|
+
isLocked,
|
|
1713
|
+
showSuggestions,
|
|
1714
|
+
showExtensionSuggestions,
|
|
1715
|
+
locations,
|
|
1716
|
+
characters,
|
|
1717
|
+
phoneticSuggestions,
|
|
1718
|
+
characterExtensions,
|
|
1719
|
+
enhancingBlockId,
|
|
1720
|
+
enhancementSuggestion,
|
|
1721
|
+
isEnhancing,
|
|
1722
|
+
currentLanguage,
|
|
1723
|
+
refs,
|
|
1724
|
+
handleSceneNumberChange,
|
|
1725
|
+
handleSceneTypeChange,
|
|
1726
|
+
handleTimeOfDayChange,
|
|
1727
|
+
handleBlockTextChange,
|
|
1728
|
+
handleKeyDown,
|
|
1729
|
+
handleFocus,
|
|
1730
|
+
handleBlur,
|
|
1731
|
+
handleSelectPhoneticSuggestion,
|
|
1732
|
+
handleSelectCharacterExtension,
|
|
1733
|
+
handleEnhance,
|
|
1734
|
+
handleApproveEnhance,
|
|
1735
|
+
handleRejectEnhance
|
|
1736
|
+
},
|
|
1737
|
+
block.id + "-" + block.type
|
|
1738
|
+
))
|
|
1829
1739
|
}
|
|
1830
|
-
) })
|
|
1831
|
-
|
|
1740
|
+
) })
|
|
1741
|
+
] });
|
|
1742
|
+
}
|
|
1743
|
+
var ScreenplayBlockItem = React4.memo(
|
|
1744
|
+
function ScreenplayBlockItem2({
|
|
1745
|
+
block,
|
|
1746
|
+
isFocused,
|
|
1747
|
+
isLocked,
|
|
1748
|
+
showSuggestions,
|
|
1749
|
+
showExtensionSuggestions,
|
|
1750
|
+
locations,
|
|
1751
|
+
characters,
|
|
1752
|
+
phoneticSuggestions,
|
|
1753
|
+
characterExtensions,
|
|
1754
|
+
enhancingBlockId,
|
|
1755
|
+
enhancementSuggestion,
|
|
1756
|
+
isEnhancing,
|
|
1757
|
+
currentLanguage,
|
|
1758
|
+
refs,
|
|
1759
|
+
handleSceneNumberChange,
|
|
1760
|
+
handleSceneTypeChange,
|
|
1761
|
+
handleTimeOfDayChange,
|
|
1762
|
+
handleBlockTextChange,
|
|
1763
|
+
handleKeyDown,
|
|
1764
|
+
handleFocus,
|
|
1765
|
+
handleBlur,
|
|
1766
|
+
handleSelectPhoneticSuggestion,
|
|
1767
|
+
handleSelectCharacterExtension,
|
|
1768
|
+
handleEnhance,
|
|
1769
|
+
handleApproveEnhance,
|
|
1770
|
+
handleRejectEnhance
|
|
1771
|
+
}) {
|
|
1772
|
+
var _a, _b;
|
|
1773
|
+
return /* @__PURE__ */ jsx(
|
|
1832
1774
|
"div",
|
|
1833
1775
|
{
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1840
|
-
/* @__PURE__ */ jsx("div", { className: "w-10 h-10 flex items-center justify-center rounded-[2.5rem] bg-blumine-50 text-blumine-500 border border-blumine-100 shadow-inner", children: /* @__PURE__ */ jsx(Save, { className: "w-5 h-5" }) }),
|
|
1841
|
-
/* @__PURE__ */ jsxs("div", { className: "mr-5", children: [
|
|
1842
|
-
/* @__PURE__ */ jsx("p", { className: "text-xs font-bold text-zinc-900 leading-none", children: "Unsaved Changes" }),
|
|
1843
|
-
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-zinc-500 mt-1 font-medium", children: "You have changes that haven't been saved yet." })
|
|
1844
|
-
] })
|
|
1845
|
-
] }),
|
|
1846
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full sm:w-auto", children: [
|
|
1776
|
+
"data-block-id": block.id,
|
|
1777
|
+
className: `relative rounded-sm transition-all duration-200 outline-none ${isFocused ? "bg-zinc-100/50" : "bg-transparent"}`,
|
|
1778
|
+
"data-block-type": block.type,
|
|
1779
|
+
children: block.type === "SCENE_HEADING" ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1780
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-1 bg-transparent", children: [
|
|
1847
1781
|
/* @__PURE__ */ jsx(
|
|
1848
|
-
"
|
|
1782
|
+
"input",
|
|
1849
1783
|
{
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1784
|
+
className: "absolute -left-16 top-2 w-12 text-right text-zinc-400 font-semibold select-none bg-transparent outline-none focus:ring-1 focus:ring-blue-400 rounded-sm",
|
|
1785
|
+
spellCheck: false,
|
|
1786
|
+
disabled: isLocked,
|
|
1787
|
+
value: block.sceneNumber || "",
|
|
1788
|
+
onChange: (e) => handleSceneNumberChange(
|
|
1789
|
+
block.id,
|
|
1790
|
+
e.target.value.toUpperCase()
|
|
1791
|
+
),
|
|
1792
|
+
onFocus: () => handleFocus(block.id),
|
|
1793
|
+
onBlur: () => handleBlur(block.id),
|
|
1794
|
+
onKeyDown: (e) => {
|
|
1795
|
+
if (e.key === "Enter" || e.key === "Backspace") {
|
|
1796
|
+
e.stopPropagation();
|
|
1797
|
+
}
|
|
1798
|
+
},
|
|
1799
|
+
"aria-label": "Scene Number"
|
|
1853
1800
|
}
|
|
1854
1801
|
),
|
|
1855
1802
|
/* @__PURE__ */ jsxs(
|
|
1856
|
-
"
|
|
1803
|
+
"select",
|
|
1857
1804
|
{
|
|
1858
|
-
|
|
1859
|
-
|
|
1805
|
+
className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer w-fit transition-colors",
|
|
1806
|
+
"aria-label": "Scene Type",
|
|
1807
|
+
disabled: isLocked,
|
|
1808
|
+
value: (_a = block.sceneType) != null ? _a : "INT.",
|
|
1809
|
+
onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
|
|
1810
|
+
style: {
|
|
1811
|
+
appearance: "none"
|
|
1812
|
+
},
|
|
1860
1813
|
children: [
|
|
1861
|
-
/* @__PURE__ */ jsx(
|
|
1862
|
-
"
|
|
1814
|
+
/* @__PURE__ */ jsx("option", { children: "INT." }),
|
|
1815
|
+
/* @__PURE__ */ jsx("option", { children: "EXT." }),
|
|
1816
|
+
/* @__PURE__ */ jsx("option", { children: "INT/EXT." })
|
|
1863
1817
|
]
|
|
1864
1818
|
}
|
|
1819
|
+
),
|
|
1820
|
+
/* @__PURE__ */ jsx(
|
|
1821
|
+
"div",
|
|
1822
|
+
{
|
|
1823
|
+
ref: (el) => {
|
|
1824
|
+
if (!el) return;
|
|
1825
|
+
refs.current[block.id] = el;
|
|
1826
|
+
},
|
|
1827
|
+
contentEditable: !isLocked,
|
|
1828
|
+
suppressContentEditableWarning: true,
|
|
1829
|
+
"aria-label": `Scene Heading: ${block.text}`,
|
|
1830
|
+
"aria-haspopup": "listbox",
|
|
1831
|
+
"aria-expanded": isFocused && showSuggestions && locations.length > 0,
|
|
1832
|
+
spellCheck: false,
|
|
1833
|
+
className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
|
|
1834
|
+
style: {
|
|
1835
|
+
minWidth: "3rem"
|
|
1836
|
+
},
|
|
1837
|
+
onInput: (e) => handleBlockTextChange(
|
|
1838
|
+
block.id,
|
|
1839
|
+
e.target.innerText
|
|
1840
|
+
),
|
|
1841
|
+
onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
|
|
1842
|
+
onFocus: () => handleFocus(block.id),
|
|
1843
|
+
onBlur: () => handleBlur(block.id)
|
|
1844
|
+
}
|
|
1845
|
+
),
|
|
1846
|
+
/* @__PURE__ */ jsx("span", { className: "text-zinc-400/80 font-bold", children: "-" }),
|
|
1847
|
+
/* @__PURE__ */ jsx(
|
|
1848
|
+
"select",
|
|
1849
|
+
{
|
|
1850
|
+
className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer transition-colors",
|
|
1851
|
+
"aria-label": "Time of Day",
|
|
1852
|
+
disabled: isLocked,
|
|
1853
|
+
value: (_b = block.timeOfDay) != null ? _b : "DAY",
|
|
1854
|
+
style: {
|
|
1855
|
+
appearance: "none"
|
|
1856
|
+
},
|
|
1857
|
+
onChange: (e) => handleTimeOfDayChange(block.id, e.target.value),
|
|
1858
|
+
children: timeOfDayOptions.map((t) => /* @__PURE__ */ jsx("option", { children: t }, t))
|
|
1859
|
+
}
|
|
1865
1860
|
)
|
|
1866
|
-
] })
|
|
1861
|
+
] }),
|
|
1862
|
+
isFocused && showSuggestions && locations.length > 0 && /* @__PURE__ */ jsx(
|
|
1863
|
+
"div",
|
|
1864
|
+
{
|
|
1865
|
+
role: "listbox",
|
|
1866
|
+
id: `suggestions-${block.id}`,
|
|
1867
|
+
className: "absolute top-[calc(100%+6px)] left-0 min-w-[240px] z-50 bg-white border border-slate-200/80 shadow-xl shadow-slate-200/40 rounded-xl py-1 overflow-hidden animate-in fade-in zoom-in-95 duration-150",
|
|
1868
|
+
children: /* @__PURE__ */ jsx("div", { className: "max-h-60 overflow-y-auto custom-scrollbar", children: locations.filter(
|
|
1869
|
+
(loc) => loc.startsWith(block.text.toUpperCase()) && loc !== block.text.toUpperCase()
|
|
1870
|
+
).map((loc) => /* @__PURE__ */ jsxs(
|
|
1871
|
+
"div",
|
|
1872
|
+
{
|
|
1873
|
+
role: "option",
|
|
1874
|
+
className: "group flex items-center justify-between px-4 py-2.5 cursor-pointer transition-all duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1875
|
+
onMouseDown: (e) => {
|
|
1876
|
+
e.preventDefault();
|
|
1877
|
+
const element = refs.current[block.id];
|
|
1878
|
+
if (element) {
|
|
1879
|
+
element.innerText = loc;
|
|
1880
|
+
handleBlockTextChange(block.id, loc);
|
|
1881
|
+
element.focus();
|
|
1882
|
+
const range = document.createRange();
|
|
1883
|
+
const sel = window.getSelection();
|
|
1884
|
+
range.selectNodeContents(element);
|
|
1885
|
+
range.collapse(false);
|
|
1886
|
+
sel == null ? void 0 : sel.removeAllRanges();
|
|
1887
|
+
sel == null ? void 0 : sel.addRange(range);
|
|
1888
|
+
}
|
|
1889
|
+
handleBlur(block.id);
|
|
1890
|
+
},
|
|
1891
|
+
children: [
|
|
1892
|
+
/* @__PURE__ */ jsx("span", { className: "text-[12px] font-semibold tracking-wide text-slate-600 uppercase line-clamp-1", children: loc }),
|
|
1893
|
+
/* @__PURE__ */ jsx(ArrowRight, { className: "w-3.5 h-3.5 text-slate-300 opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" })
|
|
1894
|
+
]
|
|
1895
|
+
},
|
|
1896
|
+
loc
|
|
1897
|
+
)) })
|
|
1898
|
+
}
|
|
1899
|
+
),
|
|
1900
|
+
isFocused && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
1901
|
+
PhoneticSuggestions,
|
|
1902
|
+
{
|
|
1903
|
+
suggestions: phoneticSuggestions,
|
|
1904
|
+
onSelect: handleSelectPhoneticSuggestion
|
|
1905
|
+
}
|
|
1906
|
+
)
|
|
1907
|
+
] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
1908
|
+
/* @__PURE__ */ jsx(
|
|
1909
|
+
"div",
|
|
1910
|
+
{
|
|
1911
|
+
ref: (el) => {
|
|
1912
|
+
if (!el) return;
|
|
1913
|
+
refs.current[block.id] = el;
|
|
1914
|
+
},
|
|
1915
|
+
contentEditable: !isLocked,
|
|
1916
|
+
suppressContentEditableWarning: true,
|
|
1917
|
+
"aria-label": `${blockStyles[block.type].label} text`,
|
|
1918
|
+
"aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
|
|
1919
|
+
spellCheck: false,
|
|
1920
|
+
className: `block outline-none w-full min-h-[2.5rem] px-4 py-2 break-words ${blockStyles[block.type].className}`,
|
|
1921
|
+
onInput: (e) => handleBlockTextChange(
|
|
1922
|
+
block.id,
|
|
1923
|
+
e.target.innerText
|
|
1924
|
+
),
|
|
1925
|
+
onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
|
|
1926
|
+
onFocus: () => handleFocus(block.id),
|
|
1927
|
+
onBlur: () => handleBlur(block.id),
|
|
1928
|
+
style: blockStyles[block.type].inputStyle
|
|
1929
|
+
}
|
|
1930
|
+
),
|
|
1931
|
+
isFocused && block.type === "CHARACTER" && showSuggestions && characters.length > 0 && /* @__PURE__ */ jsx(
|
|
1932
|
+
"div",
|
|
1933
|
+
{
|
|
1934
|
+
role: "listbox",
|
|
1935
|
+
id: `suggestions-${block.id}`,
|
|
1936
|
+
className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
|
|
1937
|
+
children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characters.filter(
|
|
1938
|
+
(char) => char.startsWith(block.text.toUpperCase()) && char !== block.text.toUpperCase()
|
|
1939
|
+
).map((char) => /* @__PURE__ */ jsxs(
|
|
1940
|
+
"div",
|
|
1941
|
+
{
|
|
1942
|
+
role: "option",
|
|
1943
|
+
className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1944
|
+
onMouseDown: (e) => {
|
|
1945
|
+
e.preventDefault();
|
|
1946
|
+
const element = refs.current[block.id];
|
|
1947
|
+
if (element) {
|
|
1948
|
+
element.innerText = char;
|
|
1949
|
+
handleBlockTextChange(block.id, char);
|
|
1950
|
+
element.focus();
|
|
1951
|
+
const range = document.createRange();
|
|
1952
|
+
const sel = window.getSelection();
|
|
1953
|
+
range.selectNodeContents(element);
|
|
1954
|
+
range.collapse(false);
|
|
1955
|
+
sel == null ? void 0 : sel.removeAllRanges();
|
|
1956
|
+
sel == null ? void 0 : sel.addRange(range);
|
|
1957
|
+
}
|
|
1958
|
+
handleBlur(block.id);
|
|
1959
|
+
},
|
|
1960
|
+
children: [
|
|
1961
|
+
/* @__PURE__ */ jsx(User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-blumine-500 transition-colors mr-3" }),
|
|
1962
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
|
|
1963
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
|
|
1964
|
+
]
|
|
1965
|
+
},
|
|
1966
|
+
char
|
|
1967
|
+
)) })
|
|
1968
|
+
}
|
|
1969
|
+
),
|
|
1970
|
+
isFocused && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsx(
|
|
1971
|
+
"div",
|
|
1972
|
+
{
|
|
1973
|
+
role: "listbox",
|
|
1974
|
+
id: `extension-suggestions-${block.id}`,
|
|
1975
|
+
className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
|
|
1976
|
+
children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
|
|
1977
|
+
const openParenIndex = block.text.lastIndexOf("(");
|
|
1978
|
+
const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
|
|
1979
|
+
return ext.toUpperCase().includes(query);
|
|
1980
|
+
}).map((ext) => /* @__PURE__ */ jsxs(
|
|
1981
|
+
"div",
|
|
1982
|
+
{
|
|
1983
|
+
role: "option",
|
|
1984
|
+
className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1985
|
+
onMouseDown: (e) => {
|
|
1986
|
+
e.preventDefault();
|
|
1987
|
+
handleSelectCharacterExtension(ext);
|
|
1988
|
+
},
|
|
1989
|
+
children: [
|
|
1990
|
+
/* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
|
|
1991
|
+
/* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
|
|
1992
|
+
]
|
|
1993
|
+
},
|
|
1994
|
+
ext
|
|
1995
|
+
)) })
|
|
1996
|
+
}
|
|
1997
|
+
),
|
|
1998
|
+
isFocused && !enhancingBlockId && (block.type === "ACTION" || block.type === "DIALOGUE") && /* @__PURE__ */ jsx(
|
|
1999
|
+
"button",
|
|
2000
|
+
{
|
|
2001
|
+
onClick: () => handleEnhance(block),
|
|
2002
|
+
className: "absolute -right-12 top-1/2 -translate-y-1/2 flex items-center justify-center w-8 h-8 rounded-xl border border-blumine-200/50 bg-white text-blumine-500 hover:border-blumine-400/60 hover:bg-blumine-50/90 hover:ring-2 hover:ring-blumine-100 hover:scale-105 active:scale-95 transition-all duration-200 group/enhance animate-in fade-in slide-in-from-left-2",
|
|
2003
|
+
title: "Enhance with AI",
|
|
2004
|
+
children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 group-hover/enhance:animate-pulse transition-colors" })
|
|
2005
|
+
}
|
|
2006
|
+
),
|
|
2007
|
+
enhancingBlockId === block.id && (enhancementSuggestion || isEnhancing) && /* @__PURE__ */ jsxs(
|
|
2008
|
+
"div",
|
|
2009
|
+
{
|
|
2010
|
+
className: "absolute left-0 right-0 -top-4 -translate-y-full z-[50] animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-300",
|
|
2011
|
+
style: { width: "calc(100% + 2rem)", left: "-1rem" },
|
|
2012
|
+
children: [
|
|
2013
|
+
/* @__PURE__ */ jsx("div", { className: "mx-auto w-full rounded-[2rem] bg-white border border-white/60 shadow-[0_14px_34px_rgba(16,37,54,0.1),0_2px_8px_rgba(16,37,54,0.05)] backdrop-blur-xl p-2 select-none transition-all", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
2014
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-1", children: [
|
|
2015
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2016
|
+
/* @__PURE__ */ jsx("div", { className: "w-9 h-9 flex items-center justify-center rounded-full bg-blumine-50 text-blumine-500 border border-blumine-100 shadow-inner", children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4" }) }),
|
|
2017
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
2018
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-bold text-zinc-900 uppercase tracking-wider leading-none", children: "AI Suggestion" }),
|
|
2019
|
+
!isEnhancing && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-zinc-500 mt-1 font-medium", children: "Refining your screenplay dialogue" })
|
|
2020
|
+
] })
|
|
2021
|
+
] }),
|
|
2022
|
+
!isEnhancing && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
2023
|
+
/* @__PURE__ */ jsx(
|
|
2024
|
+
"button",
|
|
2025
|
+
{
|
|
2026
|
+
onClick: handleRejectEnhance,
|
|
2027
|
+
className: "px-3 py-2 rounded-full text-xs font-bold text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all active:scale-95",
|
|
2028
|
+
children: "Discard"
|
|
2029
|
+
}
|
|
2030
|
+
),
|
|
2031
|
+
/* @__PURE__ */ jsxs(
|
|
2032
|
+
"button",
|
|
2033
|
+
{
|
|
2034
|
+
onClick: handleApproveEnhance,
|
|
2035
|
+
className: "px-4 py-2 rounded-full text-xs font-bold bg-blumine-500 text-white hover:bg-blumine-600 shadow-lg shadow-blumine-500/20 transition-all active:scale-95 flex items-center gap-1.5",
|
|
2036
|
+
children: [
|
|
2037
|
+
/* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5" }),
|
|
2038
|
+
"Apply Changes"
|
|
2039
|
+
]
|
|
2040
|
+
}
|
|
2041
|
+
)
|
|
2042
|
+
] })
|
|
2043
|
+
] }),
|
|
2044
|
+
/* @__PURE__ */ jsx("div", { className: "relative overflow-hidden rounded-[1.25rem] bg-zinc-50/50 border border-zinc-100 p-4 min-h-[4rem]", children: isEnhancing ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2.5 py-1", children: [
|
|
2045
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-3/4 bg-zinc-200/60 animate-pulse rounded-full" }),
|
|
2046
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-1/2 bg-zinc-200/60 animate-pulse rounded-full" })
|
|
2047
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2048
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400 line-through decoration-zinc-300 italic", children: block.text }),
|
|
2049
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-zinc-800 font-medium leading-relaxed", children: enhancementSuggestion })
|
|
2050
|
+
] }) })
|
|
2051
|
+
] }) }),
|
|
2052
|
+
/* @__PURE__ */ jsx("div", { className: "absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3.5 h-3.5 bg-white border-r border-b border-zinc-200/50 rotate-45" })
|
|
2053
|
+
]
|
|
2054
|
+
}
|
|
2055
|
+
),
|
|
2056
|
+
isFocused && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
|
|
2057
|
+
PhoneticSuggestions,
|
|
2058
|
+
{
|
|
2059
|
+
suggestions: phoneticSuggestions,
|
|
2060
|
+
onSelect: handleSelectPhoneticSuggestion
|
|
2061
|
+
}
|
|
2062
|
+
)
|
|
1867
2063
|
] })
|
|
1868
2064
|
}
|
|
1869
|
-
)
|
|
1870
|
-
|
|
1871
|
-
|
|
2065
|
+
);
|
|
2066
|
+
},
|
|
2067
|
+
(prevProps, nextProps) => {
|
|
2068
|
+
return prevProps.isLocked === nextProps.isLocked && prevProps.isFocused === nextProps.isFocused && prevProps.currentLanguage === nextProps.currentLanguage && prevProps.enhancingBlockId === nextProps.enhancingBlockId && prevProps.isEnhancing === nextProps.isEnhancing && prevProps.enhancementSuggestion === nextProps.enhancementSuggestion && prevProps.block.text === nextProps.block.text && prevProps.block.type === nextProps.block.type && prevProps.block.sceneNumber === nextProps.block.sceneNumber && prevProps.block.sceneType === nextProps.block.sceneType && prevProps.block.timeOfDay === nextProps.block.timeOfDay && (!nextProps.isFocused || prevProps.showSuggestions === nextProps.showSuggestions && prevProps.showExtensionSuggestions === nextProps.showExtensionSuggestions && prevProps.phoneticSuggestions === nextProps.phoneticSuggestions && prevProps.locations === nextProps.locations && prevProps.characters === nextProps.characters);
|
|
2069
|
+
}
|
|
2070
|
+
);
|
|
1872
2071
|
|
|
1873
2072
|
// app/service/screenplay-editor.service.ts
|
|
1874
2073
|
function getNextBlockType(currentType) {
|
|
@@ -2196,7 +2395,25 @@ function createRangeFromGlobalOffset(element, startOffset, endOffset) {
|
|
|
2196
2395
|
return null;
|
|
2197
2396
|
}
|
|
2198
2397
|
function useScreenplayEditor(options) {
|
|
2199
|
-
|
|
2398
|
+
var _a;
|
|
2399
|
+
const [blocks, setBlocks] = useState(
|
|
2400
|
+
(options == null ? void 0 : options.blocks) || initialBlocks
|
|
2401
|
+
);
|
|
2402
|
+
const hasInitializedRef = useRef(
|
|
2403
|
+
!!((options == null ? void 0 : options.blocks) && options.blocks.length > 0)
|
|
2404
|
+
);
|
|
2405
|
+
useEffect(() => {
|
|
2406
|
+
if ((options == null ? void 0 : options.blocks) && options.blocks.length > 0 && !hasInitializedRef.current) {
|
|
2407
|
+
setIsLoading(true);
|
|
2408
|
+
isWaitingForDOMRef.current = true;
|
|
2409
|
+
skipAutosaveRef.current = true;
|
|
2410
|
+
const timer = setTimeout(() => {
|
|
2411
|
+
setBlocks(options.blocks);
|
|
2412
|
+
hasInitializedRef.current = true;
|
|
2413
|
+
}, 50);
|
|
2414
|
+
return () => clearTimeout(timer);
|
|
2415
|
+
}
|
|
2416
|
+
}, [options == null ? void 0 : options.blocks]);
|
|
2200
2417
|
const refs = useRef({});
|
|
2201
2418
|
const [focusedBlockId, setFocusedBlockId] = useState(
|
|
2202
2419
|
initialBlocks[0].id
|
|
@@ -2204,7 +2421,9 @@ function useScreenplayEditor(options) {
|
|
|
2204
2421
|
const [newBlockId, setNewBlockId] = useState(null);
|
|
2205
2422
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
|
2206
2423
|
const [showExtensionSuggestions, setShowExtensionSuggestions] = useState(false);
|
|
2207
|
-
const [isLoading, setIsLoading] = useState(
|
|
2424
|
+
const [isLoading, setIsLoading] = useState(
|
|
2425
|
+
!!((options == null ? void 0 : options.initialUrl) || (options == null ? void 0 : options.blocks) && options.blocks.length > 0)
|
|
2426
|
+
);
|
|
2208
2427
|
const [enhancingBlockId, setEnhancingBlockId] = useState(null);
|
|
2209
2428
|
const [enhancementSuggestion, setEnhancementSuggestion] = useState(null);
|
|
2210
2429
|
const [isEnhancing, setIsEnhancing] = useState(false);
|
|
@@ -2213,13 +2432,21 @@ function useScreenplayEditor(options) {
|
|
|
2213
2432
|
const popoverTimeoutRef = useRef(null);
|
|
2214
2433
|
const blurTimeout = useRef(null);
|
|
2215
2434
|
const isInitialLoadRef = useRef(true);
|
|
2435
|
+
const skipAutosaveRef = useRef(false);
|
|
2436
|
+
const isWaitingForDOMRef = useRef(
|
|
2437
|
+
!!((options == null ? void 0 : options.initialUrl) || (options == null ? void 0 : options.blocks) && options.blocks.length > 0)
|
|
2438
|
+
);
|
|
2216
2439
|
const loadedUrlRef = useRef(null);
|
|
2217
2440
|
const lastSavedContent = useRef(null);
|
|
2218
2441
|
const onSaveRef = useRef(options == null ? void 0 : options.onSave);
|
|
2442
|
+
const onSaveBlobRef = useRef(options == null ? void 0 : options.onSaveBlob);
|
|
2219
2443
|
const onSyncWithCloudRef = useRef(options == null ? void 0 : options.onSyncWithCloud);
|
|
2444
|
+
const [autosaveStatus, setAutosaveStatus] = useState("idle");
|
|
2445
|
+
const isLocked = (_a = options == null ? void 0 : options.isLocked) != null ? _a : false;
|
|
2220
2446
|
const [currentLanguage, setCurrentLanguage] = useState("English");
|
|
2221
2447
|
const [lastPhoneticAction, setLastPhoneticAction] = useState(null);
|
|
2222
2448
|
const [phoneticSuggestions, setPhoneticSuggestions] = useState([]);
|
|
2449
|
+
const lastSyncedTextRef = useRef({});
|
|
2223
2450
|
useEffect(() => {
|
|
2224
2451
|
setLastPhoneticAction(null);
|
|
2225
2452
|
setPhoneticSuggestions([]);
|
|
@@ -2232,8 +2459,79 @@ function useScreenplayEditor(options) {
|
|
|
2232
2459
|
}, [currentLanguage]);
|
|
2233
2460
|
useEffect(() => {
|
|
2234
2461
|
onSaveRef.current = options == null ? void 0 : options.onSave;
|
|
2462
|
+
onSaveBlobRef.current = options == null ? void 0 : options.onSaveBlob;
|
|
2235
2463
|
onSyncWithCloudRef.current = options == null ? void 0 : options.onSyncWithCloud;
|
|
2236
|
-
}, [options == null ? void 0 : options.onSave, options == null ? void 0 : options.onSyncWithCloud]);
|
|
2464
|
+
}, [options == null ? void 0 : options.onSave, options == null ? void 0 : options.onSaveBlob, options == null ? void 0 : options.onSyncWithCloud]);
|
|
2465
|
+
const isFirstAutosaveRender = useRef(true);
|
|
2466
|
+
const prevBlocksRef = useRef(blocks);
|
|
2467
|
+
useEffect(() => {
|
|
2468
|
+
if (isLocked) {
|
|
2469
|
+
setAutosaveStatus("idle");
|
|
2470
|
+
return;
|
|
2471
|
+
}
|
|
2472
|
+
if (isFirstAutosaveRender.current) {
|
|
2473
|
+
isFirstAutosaveRender.current = false;
|
|
2474
|
+
prevBlocksRef.current = blocks;
|
|
2475
|
+
return;
|
|
2476
|
+
}
|
|
2477
|
+
if (skipAutosaveRef.current) {
|
|
2478
|
+
skipAutosaveRef.current = false;
|
|
2479
|
+
prevBlocksRef.current = blocks;
|
|
2480
|
+
return;
|
|
2481
|
+
}
|
|
2482
|
+
const hasChanged = blocks.length !== prevBlocksRef.current.length || blocks.some((b, i) => b !== prevBlocksRef.current[i]);
|
|
2483
|
+
if (!hasChanged) {
|
|
2484
|
+
return;
|
|
2485
|
+
}
|
|
2486
|
+
setAutosaveStatus("typing");
|
|
2487
|
+
prevBlocksRef.current = blocks;
|
|
2488
|
+
const timer = setTimeout(async () => {
|
|
2489
|
+
if (onSaveRef.current) {
|
|
2490
|
+
setAutosaveStatus("saving");
|
|
2491
|
+
try {
|
|
2492
|
+
await onSaveRef.current(blocks);
|
|
2493
|
+
setAutosaveStatus("saved");
|
|
2494
|
+
setTimeout(() => {
|
|
2495
|
+
setAutosaveStatus((prev) => prev === "saved" ? "idle" : prev);
|
|
2496
|
+
}, 2e3);
|
|
2497
|
+
} catch (error) {
|
|
2498
|
+
console.error("Autosave failed:", error);
|
|
2499
|
+
setAutosaveStatus("error");
|
|
2500
|
+
}
|
|
2501
|
+
} else {
|
|
2502
|
+
setAutosaveStatus("idle");
|
|
2503
|
+
}
|
|
2504
|
+
}, 3e3);
|
|
2505
|
+
return () => clearTimeout(timer);
|
|
2506
|
+
}, [blocks, isLocked]);
|
|
2507
|
+
const latestBlocksRef = useRef(blocks);
|
|
2508
|
+
useEffect(() => {
|
|
2509
|
+
latestBlocksRef.current = blocks;
|
|
2510
|
+
}, [blocks]);
|
|
2511
|
+
useEffect(() => {
|
|
2512
|
+
const handleBeforeUnload = (e) => {
|
|
2513
|
+
if (autosaveStatus === "typing" || autosaveStatus === "saving") {
|
|
2514
|
+
e.preventDefault();
|
|
2515
|
+
e.returnValue = "Changes you made may not be saved.";
|
|
2516
|
+
return e.returnValue;
|
|
2517
|
+
}
|
|
2518
|
+
};
|
|
2519
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
2520
|
+
return () => {
|
|
2521
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
2522
|
+
};
|
|
2523
|
+
}, [autosaveStatus]);
|
|
2524
|
+
const autosaveStatusRef = useRef(autosaveStatus);
|
|
2525
|
+
useEffect(() => {
|
|
2526
|
+
autosaveStatusRef.current = autosaveStatus;
|
|
2527
|
+
}, [autosaveStatus]);
|
|
2528
|
+
useEffect(() => {
|
|
2529
|
+
return () => {
|
|
2530
|
+
if (autosaveStatusRef.current === "typing" && onSaveRef.current) {
|
|
2531
|
+
onSaveRef.current(latestBlocksRef.current);
|
|
2532
|
+
}
|
|
2533
|
+
};
|
|
2534
|
+
}, []);
|
|
2237
2535
|
const characterExtensions = useMemo(
|
|
2238
2536
|
() => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
|
|
2239
2537
|
[]
|
|
@@ -2248,37 +2546,43 @@ function useScreenplayEditor(options) {
|
|
|
2248
2546
|
},
|
|
2249
2547
|
[]
|
|
2250
2548
|
);
|
|
2251
|
-
const locations = useMemo(() => {
|
|
2252
|
-
const
|
|
2253
|
-
|
|
2254
|
-
|
|
2255
|
-
const characters = useMemo(() => {
|
|
2256
|
-
const chars = blocks.filter((b) => b.type === "CHARACTER" && b.text.trim() !== "").map((b) => {
|
|
2257
|
-
const text = b.text.trim().toUpperCase();
|
|
2258
|
-
const parenIndex = text.indexOf("(");
|
|
2259
|
-
if (parenIndex > -1) {
|
|
2260
|
-
return text.substring(0, parenIndex).trim();
|
|
2261
|
-
}
|
|
2262
|
-
return text;
|
|
2263
|
-
}).filter(Boolean);
|
|
2264
|
-
return [...new Set(chars)];
|
|
2265
|
-
}, [blocks]);
|
|
2266
|
-
const sceneNumbers = useMemo(() => {
|
|
2267
|
-
const map = {};
|
|
2549
|
+
const { locations, characters, sceneNumbers } = useMemo(() => {
|
|
2550
|
+
const locsSet = /* @__PURE__ */ new Set();
|
|
2551
|
+
const charsSet = /* @__PURE__ */ new Set();
|
|
2552
|
+
const sceneNumMap = {};
|
|
2268
2553
|
let fallbackCount = 0;
|
|
2269
2554
|
blocks.forEach((block) => {
|
|
2555
|
+
const textTrim = block.text.trim();
|
|
2270
2556
|
if (block.type === "SCENE_HEADING") {
|
|
2557
|
+
if (textTrim !== "") {
|
|
2558
|
+
locsSet.add(textTrim.toUpperCase());
|
|
2559
|
+
}
|
|
2271
2560
|
if (block.sceneNumber) {
|
|
2272
|
-
|
|
2561
|
+
sceneNumMap[block.id] = block.sceneNumber;
|
|
2273
2562
|
const base = parseInt(block.sceneNumber);
|
|
2274
2563
|
if (!isNaN(base)) fallbackCount = Math.max(fallbackCount, base);
|
|
2275
2564
|
} else {
|
|
2276
2565
|
fallbackCount++;
|
|
2277
|
-
|
|
2566
|
+
sceneNumMap[block.id] = String(fallbackCount);
|
|
2567
|
+
}
|
|
2568
|
+
} else if (block.type === "CHARACTER") {
|
|
2569
|
+
if (textTrim !== "") {
|
|
2570
|
+
const textUpper = textTrim.toUpperCase();
|
|
2571
|
+
const parenIndex = textUpper.indexOf("(");
|
|
2572
|
+
if (parenIndex > -1) {
|
|
2573
|
+
const charName = textUpper.substring(0, parenIndex).trim();
|
|
2574
|
+
if (charName) charsSet.add(charName);
|
|
2575
|
+
} else {
|
|
2576
|
+
charsSet.add(textUpper);
|
|
2577
|
+
}
|
|
2278
2578
|
}
|
|
2279
2579
|
}
|
|
2280
2580
|
});
|
|
2281
|
-
return
|
|
2581
|
+
return {
|
|
2582
|
+
locations: Array.from(locsSet),
|
|
2583
|
+
characters: Array.from(charsSet),
|
|
2584
|
+
sceneNumbers: sceneNumMap
|
|
2585
|
+
};
|
|
2282
2586
|
}, [blocks]);
|
|
2283
2587
|
useEffect(() => {
|
|
2284
2588
|
if (newBlockId && refs.current[newBlockId]) {
|
|
@@ -2286,7 +2590,8 @@ function useScreenplayEditor(options) {
|
|
|
2286
2590
|
const el = refs.current[newBlockId];
|
|
2287
2591
|
if (el && block) {
|
|
2288
2592
|
el.focus();
|
|
2289
|
-
el.
|
|
2593
|
+
el.textContent = block.text;
|
|
2594
|
+
lastSyncedTextRef.current[newBlockId] = block.text;
|
|
2290
2595
|
if (block.type === "PARENTHETICAL") {
|
|
2291
2596
|
setTimeout(() => setCaretPosition(el, 1), 0);
|
|
2292
2597
|
} else {
|
|
@@ -2301,11 +2606,51 @@ function useScreenplayEditor(options) {
|
|
|
2301
2606
|
blocks.forEach((block) => {
|
|
2302
2607
|
const element = refs.current[block.id];
|
|
2303
2608
|
if (element) {
|
|
2304
|
-
if (
|
|
2305
|
-
element.
|
|
2609
|
+
if (lastSyncedTextRef.current[block.id] !== block.text && document.activeElement !== element) {
|
|
2610
|
+
element.textContent = block.text;
|
|
2611
|
+
lastSyncedTextRef.current[block.id] = block.text;
|
|
2306
2612
|
}
|
|
2307
2613
|
}
|
|
2308
2614
|
});
|
|
2615
|
+
if (isWaitingForDOMRef.current) {
|
|
2616
|
+
const dismissLoader = () => {
|
|
2617
|
+
if (typeof window !== "undefined") {
|
|
2618
|
+
void document.body.scrollHeight;
|
|
2619
|
+
}
|
|
2620
|
+
setIsLoading(false);
|
|
2621
|
+
isWaitingForDOMRef.current = false;
|
|
2622
|
+
};
|
|
2623
|
+
const waitForAllReady = async () => {
|
|
2624
|
+
if (typeof window !== "undefined") {
|
|
2625
|
+
try {
|
|
2626
|
+
if (document.fonts && document.fonts.ready) {
|
|
2627
|
+
await document.fonts.ready;
|
|
2628
|
+
}
|
|
2629
|
+
} catch (e) {
|
|
2630
|
+
console.error("Font loading detection failed:", e);
|
|
2631
|
+
}
|
|
2632
|
+
}
|
|
2633
|
+
if (typeof window !== "undefined" && "requestIdleCallback" in window) {
|
|
2634
|
+
requestAnimationFrame(() => {
|
|
2635
|
+
requestAnimationFrame(() => {
|
|
2636
|
+
window.requestIdleCallback(
|
|
2637
|
+
() => {
|
|
2638
|
+
setTimeout(dismissLoader, 150);
|
|
2639
|
+
},
|
|
2640
|
+
{ timeout: 2e3 }
|
|
2641
|
+
);
|
|
2642
|
+
});
|
|
2643
|
+
});
|
|
2644
|
+
} else {
|
|
2645
|
+
requestAnimationFrame(() => {
|
|
2646
|
+
requestAnimationFrame(() => {
|
|
2647
|
+
setTimeout(dismissLoader, 400);
|
|
2648
|
+
});
|
|
2649
|
+
});
|
|
2650
|
+
}
|
|
2651
|
+
};
|
|
2652
|
+
waitForAllReady();
|
|
2653
|
+
}
|
|
2309
2654
|
}, [blocks]);
|
|
2310
2655
|
useEffect(() => {
|
|
2311
2656
|
const handleClickOutside = (e) => {
|
|
@@ -2361,9 +2706,12 @@ function useScreenplayEditor(options) {
|
|
|
2361
2706
|
const offset = getCaretCharacterOffsetWithin(el);
|
|
2362
2707
|
const charsBeforeCaret = text.substring(0, offset).replace(/[()]/g, "").length;
|
|
2363
2708
|
const newOffset = 1 + charsBeforeCaret;
|
|
2364
|
-
el.
|
|
2709
|
+
el.textContent = processedText;
|
|
2710
|
+
lastSyncedTextRef.current[id] = processedText;
|
|
2365
2711
|
setCaretPosition(el, newOffset);
|
|
2366
2712
|
}
|
|
2713
|
+
} else {
|
|
2714
|
+
lastSyncedTextRef.current[id] = text;
|
|
2367
2715
|
}
|
|
2368
2716
|
},
|
|
2369
2717
|
[blocks, showExtensionSuggestions]
|
|
@@ -2374,8 +2722,8 @@ function useScreenplayEditor(options) {
|
|
|
2374
2722
|
(bs) => updateBlock(bs, id, "sceneType", sceneType)
|
|
2375
2723
|
);
|
|
2376
2724
|
setTimeout(() => {
|
|
2377
|
-
var
|
|
2378
|
-
(
|
|
2725
|
+
var _a2;
|
|
2726
|
+
(_a2 = refs.current[id]) == null ? void 0 : _a2.focus();
|
|
2379
2727
|
setFocusedBlockId(id);
|
|
2380
2728
|
}, 10);
|
|
2381
2729
|
},
|
|
@@ -2384,8 +2732,8 @@ function useScreenplayEditor(options) {
|
|
|
2384
2732
|
const handleTimeOfDayChange = useCallback((id, time) => {
|
|
2385
2733
|
setBlocks((bs) => updateBlock(bs, id, "timeOfDay", time));
|
|
2386
2734
|
setTimeout(() => {
|
|
2387
|
-
var
|
|
2388
|
-
(
|
|
2735
|
+
var _a2;
|
|
2736
|
+
(_a2 = refs.current[id]) == null ? void 0 : _a2.focus();
|
|
2389
2737
|
setFocusedBlockId(id);
|
|
2390
2738
|
}, 10);
|
|
2391
2739
|
}, []);
|
|
@@ -2486,7 +2834,7 @@ function useScreenplayEditor(options) {
|
|
|
2486
2834
|
};
|
|
2487
2835
|
const handleKeyDown = useCallback(
|
|
2488
2836
|
(e, id, text) => {
|
|
2489
|
-
var
|
|
2837
|
+
var _a2;
|
|
2490
2838
|
if (currentLanguage !== "English") {
|
|
2491
2839
|
const config = LANGUAGE_CONFIGS[currentLanguage];
|
|
2492
2840
|
const char = getMappedCharacter(
|
|
@@ -2653,7 +3001,7 @@ function useScreenplayEditor(options) {
|
|
|
2653
3001
|
const range = selection.getRangeAt(0);
|
|
2654
3002
|
const contentEditable = e.currentTarget;
|
|
2655
3003
|
const container = range.endContainer;
|
|
2656
|
-
const isAtEndOffset = range.endOffset === (container.nodeType === Node.TEXT_NODE ? (
|
|
3004
|
+
const isAtEndOffset = range.endOffset === (container.nodeType === Node.TEXT_NODE ? (_a2 = container.textContent) == null ? void 0 : _a2.length : container.childNodes.length);
|
|
2657
3005
|
if (isAtEndOffset) {
|
|
2658
3006
|
let atEnd = false;
|
|
2659
3007
|
let node = container;
|
|
@@ -2709,6 +3057,9 @@ function useScreenplayEditor(options) {
|
|
|
2709
3057
|
parsedBlocks = parseScreenplayText(content);
|
|
2710
3058
|
}
|
|
2711
3059
|
if (parsedBlocks.length > 0) {
|
|
3060
|
+
setIsLoading(true);
|
|
3061
|
+
isWaitingForDOMRef.current = true;
|
|
3062
|
+
skipAutosaveRef.current = true;
|
|
2712
3063
|
let fallbackCount = 1;
|
|
2713
3064
|
const finalizedBlocks = parsedBlocks.map((block) => {
|
|
2714
3065
|
if (block.type === "SCENE_HEADING") {
|
|
@@ -2723,25 +3074,30 @@ function useScreenplayEditor(options) {
|
|
|
2723
3074
|
}
|
|
2724
3075
|
return block;
|
|
2725
3076
|
});
|
|
2726
|
-
setBlocks(finalizedBlocks);
|
|
2727
|
-
if (onSaveRef.current) {
|
|
2728
|
-
const sbxData = serializeToSbx(finalizedBlocks);
|
|
2729
|
-
if (sbxData !== lastSavedContent.current) {
|
|
2730
|
-
lastSavedContent.current = sbxData;
|
|
2731
|
-
if (!isInitialLoad) {
|
|
2732
|
-
const blob = new Blob([sbxData], { type: "text/plain" });
|
|
2733
|
-
onSaveRef.current(blob);
|
|
2734
|
-
}
|
|
2735
|
-
}
|
|
2736
|
-
}
|
|
2737
3077
|
setTimeout(() => {
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
3078
|
+
setBlocks(finalizedBlocks);
|
|
3079
|
+
if (onSaveBlobRef.current) {
|
|
3080
|
+
const sbxData = serializeToSbx(finalizedBlocks);
|
|
3081
|
+
if (sbxData !== lastSavedContent.current) {
|
|
3082
|
+
lastSavedContent.current = sbxData;
|
|
3083
|
+
if (!isInitialLoad) {
|
|
3084
|
+
const blob = new Blob([sbxData], { type: "text/plain" });
|
|
3085
|
+
onSaveBlobRef.current(blob);
|
|
3086
|
+
}
|
|
3087
|
+
}
|
|
2743
3088
|
}
|
|
2744
|
-
|
|
3089
|
+
setTimeout(() => {
|
|
3090
|
+
var _a2;
|
|
3091
|
+
const firstId = parsedBlocks[0].id;
|
|
3092
|
+
if (firstId && refs.current[firstId]) {
|
|
3093
|
+
setFocusedBlockId(firstId);
|
|
3094
|
+
(_a2 = refs.current[firstId]) == null ? void 0 : _a2.focus();
|
|
3095
|
+
}
|
|
3096
|
+
}, 100);
|
|
3097
|
+
}, 50);
|
|
3098
|
+
} else {
|
|
3099
|
+
setIsLoading(false);
|
|
3100
|
+
isWaitingForDOMRef.current = false;
|
|
2745
3101
|
}
|
|
2746
3102
|
},
|
|
2747
3103
|
[refs]
|
|
@@ -2812,7 +3168,7 @@ function useScreenplayEditor(options) {
|
|
|
2812
3168
|
}, []);
|
|
2813
3169
|
const loadFromUrl = useCallback(
|
|
2814
3170
|
async (url, fetchOptions = {}, isInitialLoad) => {
|
|
2815
|
-
var
|
|
3171
|
+
var _a2;
|
|
2816
3172
|
setIsLoading(true);
|
|
2817
3173
|
try {
|
|
2818
3174
|
const response = await fetch(url, fetchOptions);
|
|
@@ -2824,7 +3180,15 @@ function useScreenplayEditor(options) {
|
|
|
2824
3180
|
let text = await response.text();
|
|
2825
3181
|
let preParsedBlocks = void 0;
|
|
2826
3182
|
let scriptContent = text;
|
|
2827
|
-
|
|
3183
|
+
try {
|
|
3184
|
+
const parsed = JSON.parse(text);
|
|
3185
|
+
if (Array.isArray(parsed)) {
|
|
3186
|
+
preParsedBlocks = parsed;
|
|
3187
|
+
scriptContent = "";
|
|
3188
|
+
}
|
|
3189
|
+
} catch (e) {
|
|
3190
|
+
}
|
|
3191
|
+
if (!preParsedBlocks && (text.includes('class="divtype') || url.toLowerCase().includes(".sbx"))) {
|
|
2828
3192
|
if (text.includes("<div")) {
|
|
2829
3193
|
const textarea = document.createElement("textarea");
|
|
2830
3194
|
textarea.innerHTML = text;
|
|
@@ -2843,8 +3207,8 @@ function useScreenplayEditor(options) {
|
|
|
2843
3207
|
divtype6: "TRANSITION"
|
|
2844
3208
|
};
|
|
2845
3209
|
divs.forEach((div) => {
|
|
2846
|
-
var
|
|
2847
|
-
let divText = ((
|
|
3210
|
+
var _a3;
|
|
3211
|
+
let divText = ((_a3 = div.textContent) == null ? void 0 : _a3.trim()) || "";
|
|
2848
3212
|
if (!divText) return;
|
|
2849
3213
|
let type = "ACTION";
|
|
2850
3214
|
for (const className of Array.from(div.classList)) {
|
|
@@ -2883,15 +3247,18 @@ function useScreenplayEditor(options) {
|
|
|
2883
3247
|
scriptContent = "";
|
|
2884
3248
|
}
|
|
2885
3249
|
}
|
|
2886
|
-
const filename = ((
|
|
3250
|
+
const filename = ((_a2 = url.split("/").pop()) == null ? void 0 : _a2.replace(/\.sbx$/i, "")) || "Imported from URL";
|
|
3251
|
+
isWaitingForDOMRef.current = true;
|
|
2887
3252
|
handleScriptImport(
|
|
2888
3253
|
filename,
|
|
2889
3254
|
scriptContent,
|
|
2890
3255
|
preParsedBlocks,
|
|
2891
3256
|
isInitialLoad
|
|
2892
3257
|
);
|
|
2893
|
-
}
|
|
3258
|
+
} catch (error) {
|
|
3259
|
+
console.error("Failed to load screenplay from URL:", error);
|
|
2894
3260
|
setIsLoading(false);
|
|
3261
|
+
isWaitingForDOMRef.current = false;
|
|
2895
3262
|
}
|
|
2896
3263
|
},
|
|
2897
3264
|
[handleScriptImport]
|
|
@@ -2901,28 +3268,45 @@ function useScreenplayEditor(options) {
|
|
|
2901
3268
|
isInitialLoadRef.current = true;
|
|
2902
3269
|
return;
|
|
2903
3270
|
}
|
|
2904
|
-
const
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
3271
|
+
const handler = setTimeout(() => {
|
|
3272
|
+
const runSerialization = () => {
|
|
3273
|
+
const currentSbx = serializeToSbx(blocks);
|
|
3274
|
+
if (isInitialLoadRef.current) {
|
|
3275
|
+
if (lastSavedContent.current === null) {
|
|
3276
|
+
lastSavedContent.current = currentSbx;
|
|
3277
|
+
}
|
|
3278
|
+
isInitialLoadRef.current = false;
|
|
3279
|
+
return;
|
|
3280
|
+
}
|
|
3281
|
+
const hasActualChanges = lastSavedContent.current !== null && currentSbx !== lastSavedContent.current;
|
|
3282
|
+
if (hasActualChanges) {
|
|
3283
|
+
setHasUnsavedChanges(true);
|
|
3284
|
+
if (popoverTimeoutRef.current)
|
|
3285
|
+
clearTimeout(popoverTimeoutRef.current);
|
|
3286
|
+
setShowUnsavedPopover(false);
|
|
3287
|
+
popoverTimeoutRef.current = setTimeout(() => {
|
|
3288
|
+
setShowUnsavedPopover(true);
|
|
3289
|
+
}, 1e3);
|
|
3290
|
+
} else {
|
|
3291
|
+
setHasUnsavedChanges(false);
|
|
3292
|
+
setShowUnsavedPopover(false);
|
|
3293
|
+
if (popoverTimeoutRef.current)
|
|
3294
|
+
clearTimeout(popoverTimeoutRef.current);
|
|
3295
|
+
}
|
|
3296
|
+
};
|
|
3297
|
+
if (typeof window !== "undefined" && "requestIdleCallback" in window) {
|
|
3298
|
+
window.requestIdleCallback(
|
|
3299
|
+
() => {
|
|
3300
|
+
runSerialization();
|
|
3301
|
+
},
|
|
3302
|
+
{ timeout: 1e3 }
|
|
3303
|
+
);
|
|
3304
|
+
} else {
|
|
3305
|
+
runSerialization();
|
|
2908
3306
|
}
|
|
2909
|
-
|
|
2910
|
-
return;
|
|
2911
|
-
}
|
|
2912
|
-
const hasActualChanges = lastSavedContent.current !== null && currentSbx !== lastSavedContent.current;
|
|
2913
|
-
if (hasActualChanges) {
|
|
2914
|
-
setHasUnsavedChanges(true);
|
|
2915
|
-
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2916
|
-
setShowUnsavedPopover(false);
|
|
2917
|
-
popoverTimeoutRef.current = setTimeout(() => {
|
|
2918
|
-
setShowUnsavedPopover(true);
|
|
2919
|
-
}, 1e3);
|
|
2920
|
-
} else {
|
|
2921
|
-
setHasUnsavedChanges(false);
|
|
2922
|
-
setShowUnsavedPopover(false);
|
|
2923
|
-
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2924
|
-
}
|
|
3307
|
+
}, 250);
|
|
2925
3308
|
return () => {
|
|
3309
|
+
clearTimeout(handler);
|
|
2926
3310
|
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2927
3311
|
};
|
|
2928
3312
|
}, [blocks, isLoading]);
|
|
@@ -3012,7 +3396,9 @@ function useScreenplayEditor(options) {
|
|
|
3012
3396
|
currentLanguage,
|
|
3013
3397
|
setCurrentLanguage,
|
|
3014
3398
|
phoneticSuggestions,
|
|
3015
|
-
handleSelectPhoneticSuggestion
|
|
3399
|
+
handleSelectPhoneticSuggestion,
|
|
3400
|
+
isLocked,
|
|
3401
|
+
autosaveStatus
|
|
3016
3402
|
};
|
|
3017
3403
|
}
|
|
3018
3404
|
|