@vishu1301/script-writing 1.5.8 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +1544 -881
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +16 -5
- package/dist/index.d.ts +16 -5
- package/dist/index.js +1430 -768
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var
|
|
3
|
+
var React4 = require('react');
|
|
4
4
|
var lucideReact = require('lucide-react');
|
|
5
5
|
var jsxRuntime = require('react/jsx-runtime');
|
|
6
6
|
var pdfjs = require('pdfjs-dist');
|
|
7
7
|
var jsPDF = require('jspdf');
|
|
8
8
|
var html2canvas = require('html2canvas-pro');
|
|
9
|
-
var Yup = require('yup');
|
|
10
9
|
var formik = require('formik');
|
|
10
|
+
var Yup = require('yup');
|
|
11
11
|
|
|
12
12
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
13
13
|
|
|
@@ -29,6 +29,7 @@ function _interopNamespace(e) {
|
|
|
29
29
|
return Object.freeze(n);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
var React4__default = /*#__PURE__*/_interopDefault(React4);
|
|
32
33
|
var pdfjs__namespace = /*#__PURE__*/_interopNamespace(pdfjs);
|
|
33
34
|
var jsPDF__default = /*#__PURE__*/_interopDefault(jsPDF);
|
|
34
35
|
var html2canvas__default = /*#__PURE__*/_interopDefault(html2canvas);
|
|
@@ -76,12 +77,12 @@ var blockTypes = [
|
|
|
76
77
|
];
|
|
77
78
|
var uuid = () => Math.random().toString(36).slice(2, 9);
|
|
78
79
|
var icons = {
|
|
79
|
-
SCENE_HEADING: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
80
|
-
ACTION: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
81
|
-
CHARACTER: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-
|
|
82
|
-
PARENTHETICAL: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Parentheses, { className: "w-
|
|
83
|
-
DIALOGUE: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
84
|
-
TRANSITION: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.
|
|
80
|
+
SCENE_HEADING: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Mountain, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
81
|
+
ACTION: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Clapperboard, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
82
|
+
CHARACTER: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
83
|
+
PARENTHETICAL: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Parentheses, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
84
|
+
DIALOGUE: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.MessageCircle, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
|
|
85
|
+
TRANSITION: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.ArrowRight, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 })
|
|
85
86
|
};
|
|
86
87
|
var blockStyles = {
|
|
87
88
|
SCENE_HEADING: {
|
|
@@ -816,10 +817,10 @@ function PhoneticSuggestions({
|
|
|
816
817
|
] });
|
|
817
818
|
}
|
|
818
819
|
pdfjs__namespace.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs__namespace.version}/build/pdf.worker.min.mjs`;
|
|
819
|
-
function PdfImporter({ onScriptImported, disabled, children }) {
|
|
820
|
-
const [isProcessing, setIsProcessing] =
|
|
821
|
-
const [error, setError] =
|
|
822
|
-
const fileInputRef =
|
|
820
|
+
function PdfImporter({ onScriptImported, disabled, children, className }) {
|
|
821
|
+
const [isProcessing, setIsProcessing] = React4.useState(false);
|
|
822
|
+
const [error, setError] = React4.useState(null);
|
|
823
|
+
const fileInputRef = React4.useRef(null);
|
|
823
824
|
const handleFileChange = async (event) => {
|
|
824
825
|
var _a;
|
|
825
826
|
const file = (_a = event.target.files) == null ? void 0 : _a[0];
|
|
@@ -853,9 +854,9 @@ function PdfImporter({ onScriptImported, disabled, children }) {
|
|
|
853
854
|
let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
854
855
|
if (!divText) return;
|
|
855
856
|
let type = "ACTION";
|
|
856
|
-
for (const
|
|
857
|
-
if (typeMap[
|
|
858
|
-
type = typeMap[
|
|
857
|
+
for (const className2 of Array.from(div.classList)) {
|
|
858
|
+
if (typeMap[className2]) {
|
|
859
|
+
type = typeMap[className2];
|
|
859
860
|
break;
|
|
860
861
|
}
|
|
861
862
|
}
|
|
@@ -959,7 +960,7 @@ function PdfImporter({ onScriptImported, disabled, children }) {
|
|
|
959
960
|
{
|
|
960
961
|
onClick: handleClick,
|
|
961
962
|
disabled: isProcessing || disabled,
|
|
962
|
-
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"}`,
|
|
963
|
+
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"}`,
|
|
963
964
|
"aria-label": "Import Script",
|
|
964
965
|
children: isProcessing ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs sm:text-sm font-semibold", children: "Processing..." }) : children
|
|
965
966
|
}
|
|
@@ -975,12 +976,12 @@ function PhoneticGuide({
|
|
|
975
976
|
isOpen,
|
|
976
977
|
onClose
|
|
977
978
|
}) {
|
|
978
|
-
const [activeTab, setActiveTab] =
|
|
979
|
-
const [searchQuery, setSearchQuery] =
|
|
979
|
+
const [activeTab, setActiveTab] = React4.useState("vowels");
|
|
980
|
+
const [searchQuery, setSearchQuery] = React4.useState("");
|
|
980
981
|
const script = language.includes("Hindi") ? "Hindi" : "Gujarati";
|
|
981
982
|
const vowelsData = VOWEL_FORMS[script] || {};
|
|
982
983
|
const config = LANGUAGE_CONFIGS[language];
|
|
983
|
-
const consonants =
|
|
984
|
+
const consonants = React4.useMemo(() => {
|
|
984
985
|
if (!config || language === "English") return [];
|
|
985
986
|
return Object.entries(config.mapping).filter(([_, val]) => {
|
|
986
987
|
const isVowelMatra = Object.values(vowelsData).some(
|
|
@@ -994,7 +995,7 @@ function PhoneticGuide({
|
|
|
994
995
|
shiftChar: val.shift
|
|
995
996
|
}));
|
|
996
997
|
}, [language, vowelsData, config]);
|
|
997
|
-
const symbols =
|
|
998
|
+
const symbols = React4.useMemo(() => {
|
|
998
999
|
if (!config || language === "English") return [];
|
|
999
1000
|
return Object.entries(config.mapping).filter(([_, val]) => /[.,/;:'"\[\]{}\\=`\-_]/.test(val.default)).map(([key, val]) => ({
|
|
1000
1001
|
key: key.replace("Key", "").toLowerCase(),
|
|
@@ -1243,6 +1244,44 @@ function PhoneticGuide({
|
|
|
1243
1244
|
}
|
|
1244
1245
|
);
|
|
1245
1246
|
}
|
|
1247
|
+
function Tooltip({
|
|
1248
|
+
children,
|
|
1249
|
+
content,
|
|
1250
|
+
shortcut,
|
|
1251
|
+
align = "center"
|
|
1252
|
+
}) {
|
|
1253
|
+
const alignClasses = {
|
|
1254
|
+
center: "left-1/2 -translate-x-1/2 items-center",
|
|
1255
|
+
left: "left-0 items-start",
|
|
1256
|
+
right: "right-0 items-end"
|
|
1257
|
+
};
|
|
1258
|
+
const arrowClasses = {
|
|
1259
|
+
center: "",
|
|
1260
|
+
left: "left-3.5",
|
|
1261
|
+
right: "right-3.5"
|
|
1262
|
+
};
|
|
1263
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "group relative flex items-center justify-center", children: [
|
|
1264
|
+
children,
|
|
1265
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1266
|
+
"div",
|
|
1267
|
+
{
|
|
1268
|
+
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]}`,
|
|
1269
|
+
children: [
|
|
1270
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1271
|
+
"div",
|
|
1272
|
+
{
|
|
1273
|
+
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]}`
|
|
1274
|
+
}
|
|
1275
|
+
),
|
|
1276
|
+
/* @__PURE__ */ jsxRuntime.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: [
|
|
1277
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { children: content }),
|
|
1278
|
+
shortcut && /* @__PURE__ */ jsxRuntime.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 })
|
|
1279
|
+
] })
|
|
1280
|
+
]
|
|
1281
|
+
}
|
|
1282
|
+
)
|
|
1283
|
+
] });
|
|
1284
|
+
}
|
|
1246
1285
|
function ScreenplayEditorView({
|
|
1247
1286
|
blocks,
|
|
1248
1287
|
refs,
|
|
@@ -1284,15 +1323,16 @@ function ScreenplayEditorView({
|
|
|
1284
1323
|
currentLanguage,
|
|
1285
1324
|
setCurrentLanguage,
|
|
1286
1325
|
phoneticSuggestions,
|
|
1287
|
-
handleSelectPhoneticSuggestion
|
|
1326
|
+
handleSelectPhoneticSuggestion,
|
|
1327
|
+
autosaveStatus
|
|
1288
1328
|
}) {
|
|
1289
|
-
const [isRulesOpen, setIsRulesOpen] =
|
|
1290
|
-
const [isLanguageOpen, setIsLanguageOpen] =
|
|
1291
|
-
const [isPhoneticGuideOpen, setIsPhoneticGuideOpen] =
|
|
1292
|
-
const rulesRef =
|
|
1293
|
-
const languageRef =
|
|
1329
|
+
const [isRulesOpen, setIsRulesOpen] = React4.useState(false);
|
|
1330
|
+
const [isLanguageOpen, setIsLanguageOpen] = React4.useState(false);
|
|
1331
|
+
const [isPhoneticGuideOpen, setIsPhoneticGuideOpen] = React4.useState(false);
|
|
1332
|
+
const rulesRef = React4.useRef(null);
|
|
1333
|
+
const languageRef = React4.useRef(null);
|
|
1294
1334
|
const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
|
|
1295
|
-
|
|
1335
|
+
React4.useEffect(() => {
|
|
1296
1336
|
const handleClickOutside = (event) => {
|
|
1297
1337
|
if (rulesRef.current && !rulesRef.current.contains(event.target)) {
|
|
1298
1338
|
setIsRulesOpen(false);
|
|
@@ -1308,7 +1348,7 @@ function ScreenplayEditorView({
|
|
|
1308
1348
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
1309
1349
|
};
|
|
1310
1350
|
}, [isRulesOpen, isLanguageOpen]);
|
|
1311
|
-
|
|
1351
|
+
React4.useEffect(() => {
|
|
1312
1352
|
const fontId = "google-font-courier-prime";
|
|
1313
1353
|
const styleId = "screenplay-editor-force-v4";
|
|
1314
1354
|
if (!document.getElementById(fontId)) {
|
|
@@ -1334,168 +1374,299 @@ function ScreenplayEditorView({
|
|
|
1334
1374
|
document.head.appendChild(style);
|
|
1335
1375
|
}
|
|
1336
1376
|
}, [COURIER_STACK]);
|
|
1337
|
-
if (isLoading) {
|
|
1338
|
-
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-white/80 transition-opacity", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center gap-3", children: [
|
|
1339
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-8 h-8 text-zinc-400 animate-spin" }),
|
|
1340
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-zinc-500 text-sm font-medium", children: "Loading script..." })
|
|
1341
|
-
] }) });
|
|
1342
|
-
}
|
|
1343
1377
|
return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1344
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
1345
|
-
/* @__PURE__ */ jsxRuntime.jsx("
|
|
1378
|
+
isLoading && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-blumine-500/40 backdrop-blur-md p-6", children: [
|
|
1379
|
+
/* @__PURE__ */ jsxRuntime.jsx("style", { children: `
|
|
1380
|
+
@keyframes gpu-spin {
|
|
1381
|
+
0% { transform: rotate(0deg); }
|
|
1382
|
+
100% { transform: rotate(360deg); }
|
|
1383
|
+
}
|
|
1384
|
+
.gpu-spinner-container {
|
|
1385
|
+
transform: translate3d(0,0,0);
|
|
1386
|
+
will-change: transform;
|
|
1387
|
+
}
|
|
1388
|
+
.gpu-spinner {
|
|
1389
|
+
width: 32px;
|
|
1390
|
+
height: 32px;
|
|
1391
|
+
border: 3.5px solid rgba(255, 255, 255, 0.25);
|
|
1392
|
+
border-top-color: #ffffff;
|
|
1393
|
+
border-radius: 50%;
|
|
1394
|
+
animation: gpu-spin 0.85s linear infinite;
|
|
1395
|
+
will-change: transform;
|
|
1396
|
+
transform: translate3d(0,0,0);
|
|
1397
|
+
}
|
|
1398
|
+
` }),
|
|
1399
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-center", children: [
|
|
1400
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "gpu-spinner" }),
|
|
1401
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white text-lg font-semibold mt-4", children: "Preparing Script..." }),
|
|
1402
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-white text-xs font-medium mt-2", children: "Please wait while we prepare your screenplay." }),
|
|
1403
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-white/80 text-xs mt-2", children: "Status: Arranging data..." })
|
|
1404
|
+
] }) })
|
|
1405
|
+
] }),
|
|
1406
|
+
/* @__PURE__ */ jsxRuntime.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: [
|
|
1407
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3 w-auto shrink-0 order-1", children: [
|
|
1408
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-bold tracking-wider text-blumine-400/80 uppercase", children: "Script Editor" }),
|
|
1409
|
+
autosaveStatus === "saved" && /* @__PURE__ */ jsxRuntime.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: [
|
|
1410
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" }),
|
|
1411
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Script synced" })
|
|
1412
|
+
] }),
|
|
1413
|
+
autosaveStatus === "saving" && /* @__PURE__ */ jsxRuntime.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: [
|
|
1414
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Loader2, { className: "w-2.5 h-2.5 animate-spin" }),
|
|
1415
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Saving..." })
|
|
1416
|
+
] }),
|
|
1417
|
+
autosaveStatus === "typing" && /* @__PURE__ */ jsxRuntime.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: [
|
|
1418
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-amber-500 animate-pulse" }),
|
|
1419
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Drafting..." })
|
|
1420
|
+
] }),
|
|
1421
|
+
autosaveStatus === "error" && /* @__PURE__ */ jsxRuntime.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: [
|
|
1422
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-rose-500 animate-pulse" }),
|
|
1423
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Error saving" })
|
|
1424
|
+
] })
|
|
1425
|
+
] }),
|
|
1426
|
+
/* @__PURE__ */ jsxRuntime.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) => {
|
|
1346
1427
|
var _a;
|
|
1347
1428
|
const selected = ((_a = blocks.find((b) => b.id === focusedBlockId)) == null ? void 0 : _a.type) === type;
|
|
1348
|
-
return /* @__PURE__ */ jsxRuntime.
|
|
1349
|
-
|
|
1429
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1430
|
+
Tooltip,
|
|
1350
1431
|
{
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
1432
|
+
content: blockStyles[type].label,
|
|
1433
|
+
shortcut: "Ctrl + \u2191/\u2193",
|
|
1434
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1435
|
+
"button",
|
|
1436
|
+
{
|
|
1437
|
+
type: "button",
|
|
1438
|
+
disabled: isLocked,
|
|
1439
|
+
onClick: () => handleBlockTypeChange(type),
|
|
1440
|
+
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" : ""}`,
|
|
1441
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1442
|
+
"div",
|
|
1443
|
+
{
|
|
1444
|
+
className: `flex items-center justify-center transition-all duration-150 ${selected ? "scale-105 opacity-100" : "opacity-80 hover:opacity-100"}`,
|
|
1445
|
+
children: icons[type]
|
|
1446
|
+
}
|
|
1447
|
+
)
|
|
1448
|
+
}
|
|
1449
|
+
)
|
|
1365
1450
|
},
|
|
1366
1451
|
type
|
|
1367
1452
|
);
|
|
1368
1453
|
}) }),
|
|
1369
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5
|
|
1370
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1371
|
-
showPdfImport && !isLocked && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1372
|
-
PdfImporter,
|
|
1373
|
-
{
|
|
1374
|
-
disabled: isLocked,
|
|
1375
|
-
onScriptImported: handleScriptImport,
|
|
1376
|
-
children: /* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" }) })
|
|
1377
|
-
}
|
|
1378
|
-
),
|
|
1379
|
-
onToggleLock && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1380
|
-
"button",
|
|
1381
|
-
{
|
|
1382
|
-
onClick: onToggleLock,
|
|
1383
|
-
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"}`,
|
|
1384
|
-
children: isLocked ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Unlock, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
1385
|
-
}
|
|
1386
|
-
),
|
|
1387
|
-
onSave && showSaveButton && !isLocked && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1454
|
+
/* @__PURE__ */ jsxRuntime.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: [
|
|
1455
|
+
onSave && showSaveButton && !isLocked && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: "Save changes", align: "right", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1388
1456
|
"button",
|
|
1389
1457
|
{
|
|
1390
1458
|
onClick: onSave,
|
|
1391
|
-
className: "w-
|
|
1392
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
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",
|
|
1400
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileDown, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
1459
|
+
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",
|
|
1460
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1461
|
+
lucideReact.Save,
|
|
1462
|
+
{
|
|
1463
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1464
|
+
strokeWidth: 1.5
|
|
1465
|
+
}
|
|
1466
|
+
)
|
|
1401
1467
|
}
|
|
1402
|
-
),
|
|
1403
|
-
|
|
1404
|
-
|
|
1468
|
+
) }),
|
|
1469
|
+
onToggleLock && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1470
|
+
Tooltip,
|
|
1405
1471
|
{
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1472
|
+
content: isLocked ? "Unlock Screenplay" : "Lock Screenplay",
|
|
1473
|
+
align: "right",
|
|
1474
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1475
|
+
"button",
|
|
1476
|
+
{
|
|
1477
|
+
onClick: onToggleLock,
|
|
1478
|
+
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"}`,
|
|
1479
|
+
children: isLocked ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1480
|
+
lucideReact.Lock,
|
|
1481
|
+
{
|
|
1482
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1483
|
+
strokeWidth: 1.5
|
|
1484
|
+
}
|
|
1485
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1486
|
+
lucideReact.Unlock,
|
|
1487
|
+
{
|
|
1488
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1489
|
+
strokeWidth: 1.5
|
|
1490
|
+
}
|
|
1491
|
+
)
|
|
1492
|
+
}
|
|
1493
|
+
)
|
|
1409
1494
|
}
|
|
1410
1495
|
),
|
|
1411
1496
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { ref: rulesRef, className: "relative flex items-center", children: [
|
|
1412
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1497
|
+
/* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: "Settings & Actions", align: "right", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1413
1498
|
"button",
|
|
1414
1499
|
{
|
|
1415
1500
|
onClick: () => setIsRulesOpen(!isRulesOpen),
|
|
1416
|
-
className: `w-
|
|
1417
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1501
|
+
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"}`,
|
|
1502
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1503
|
+
lucideReact.Cog,
|
|
1504
|
+
{
|
|
1505
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1506
|
+
strokeWidth: 1.5
|
|
1507
|
+
}
|
|
1508
|
+
)
|
|
1418
1509
|
}
|
|
1419
|
-
),
|
|
1420
|
-
isRulesOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute
|
|
1421
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-
|
|
1422
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between mb-
|
|
1423
|
-
/* @__PURE__ */ jsxRuntime.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-
|
|
1510
|
+
) }),
|
|
1511
|
+
isRulesOpen && /* @__PURE__ */ jsxRuntime.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: [
|
|
1512
|
+
/* @__PURE__ */ jsxRuntime.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" }),
|
|
1513
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-start justify-between mb-4 px-1", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3", children: [
|
|
1514
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
|
|
1424
1515
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1425
|
-
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[15px] font-semibold text-blumine-
|
|
1426
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-blumine-
|
|
1516
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[15px] font-semibold text-blumine-800 leading-tight", children: "Settings & Actions" }),
|
|
1517
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-blumine-400 mt-1", children: "Screenplay controls & keyboard shortcuts" })
|
|
1427
1518
|
] })
|
|
1428
1519
|
] }) }),
|
|
1429
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1430
|
-
{
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1520
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2 mb-4", children: [
|
|
1521
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1.5 mb-1", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-bold text-blumine-400 uppercase tracking-wider", children: "Document Actions" }) }),
|
|
1522
|
+
showPdfImport && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1523
|
+
PdfImporter,
|
|
1524
|
+
{
|
|
1525
|
+
disabled: isLocked,
|
|
1526
|
+
onScriptImported: (title, content, preParsedBlocks) => {
|
|
1527
|
+
handleScriptImport(title, content, preParsedBlocks);
|
|
1528
|
+
setIsRulesOpen(false);
|
|
1529
|
+
},
|
|
1530
|
+
className: "w-full text-left",
|
|
1531
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1532
|
+
"div",
|
|
1533
|
+
{
|
|
1534
|
+
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" : ""}`,
|
|
1535
|
+
children: [
|
|
1536
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
|
|
1537
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex-1 text-left", children: [
|
|
1538
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: "Import PDF" }),
|
|
1539
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: isLocked ? "Unlock screenplay to import files" : "Load screenplay from external file" })
|
|
1540
|
+
] })
|
|
1541
|
+
]
|
|
1542
|
+
}
|
|
1543
|
+
)
|
|
1544
|
+
}
|
|
1545
|
+
),
|
|
1546
|
+
onToggleLock && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1547
|
+
"button",
|
|
1548
|
+
{
|
|
1549
|
+
onClick: () => {
|
|
1550
|
+
onToggleLock();
|
|
1551
|
+
},
|
|
1552
|
+
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",
|
|
1553
|
+
children: [
|
|
1554
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1555
|
+
"div",
|
|
1464
1556
|
{
|
|
1465
|
-
className:
|
|
1466
|
-
children:
|
|
1467
|
-
}
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1557
|
+
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"}`,
|
|
1558
|
+
children: isLocked ? /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Lock, { className: "w-4 h-4", strokeWidth: 1.5 }) : /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Unlock, { className: "w-4 h-4", strokeWidth: 1.5 })
|
|
1559
|
+
}
|
|
1560
|
+
),
|
|
1561
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1562
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: isLocked ? "Unlock Screenplay" : "Lock Screenplay" }),
|
|
1563
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: isLocked ? "Enable editing controls" : "Prevent accidental editing" })
|
|
1564
|
+
] })
|
|
1565
|
+
]
|
|
1566
|
+
}
|
|
1567
|
+
),
|
|
1568
|
+
onSaveAsPdf && showSaveButton && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1569
|
+
"button",
|
|
1570
|
+
{
|
|
1571
|
+
onClick: () => {
|
|
1572
|
+
onSaveAsPdf();
|
|
1573
|
+
setIsRulesOpen(false);
|
|
1574
|
+
},
|
|
1575
|
+
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",
|
|
1576
|
+
children: [
|
|
1577
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.FileDown, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
|
|
1578
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1579
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: "Save as PDF" }),
|
|
1580
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: "Export screenplay to standard print PDF" })
|
|
1581
|
+
] })
|
|
1582
|
+
]
|
|
1583
|
+
}
|
|
1584
|
+
)
|
|
1585
|
+
] }),
|
|
1586
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "border-t border-blumine-100/60 my-4" }),
|
|
1587
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
|
|
1588
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-1.5 mb-1", children: /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[11px] font-bold text-blumine-400 uppercase tracking-wider", children: "Keyboard Shortcuts" }) }),
|
|
1589
|
+
[
|
|
1590
|
+
{
|
|
1591
|
+
title: "New Block",
|
|
1592
|
+
desc: "Insert the next section",
|
|
1593
|
+
key: ["Enter"]
|
|
1594
|
+
},
|
|
1595
|
+
{
|
|
1596
|
+
title: "Delete Block",
|
|
1597
|
+
desc: "Remove selected section",
|
|
1598
|
+
key: ["Backspace \u{1F860}"]
|
|
1599
|
+
},
|
|
1600
|
+
{
|
|
1601
|
+
title: "Change Type",
|
|
1602
|
+
desc: "Cycle block styles",
|
|
1603
|
+
key: ["Ctrl", "+", "\u2191/\u2193"]
|
|
1604
|
+
}
|
|
1605
|
+
].map((item) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1606
|
+
"div",
|
|
1607
|
+
{
|
|
1608
|
+
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)]",
|
|
1609
|
+
children: [
|
|
1610
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col min-w-0 text-left", children: [
|
|
1611
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-xs font-semibold text-blumine-800", children: item.title }),
|
|
1612
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] text-blumine-400 truncate mt-0.5", children: item.desc })
|
|
1613
|
+
] }),
|
|
1614
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center gap-1 shrink-0", children: item.key.map(
|
|
1615
|
+
(k, i) => k === "+" ? /* @__PURE__ */ jsxRuntime.jsx(
|
|
1616
|
+
"span",
|
|
1617
|
+
{
|
|
1618
|
+
className: "text-blumine-400 text-xs font-semibold",
|
|
1619
|
+
children: "+"
|
|
1620
|
+
},
|
|
1621
|
+
i
|
|
1622
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
1623
|
+
"kbd",
|
|
1624
|
+
{
|
|
1625
|
+
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)]",
|
|
1626
|
+
children: k
|
|
1627
|
+
},
|
|
1628
|
+
i
|
|
1629
|
+
)
|
|
1630
|
+
) })
|
|
1631
|
+
]
|
|
1632
|
+
},
|
|
1633
|
+
item.title
|
|
1634
|
+
))
|
|
1635
|
+
] })
|
|
1475
1636
|
] })
|
|
1476
1637
|
] }),
|
|
1477
1638
|
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1478
1639
|
"div",
|
|
1479
1640
|
{
|
|
1480
1641
|
ref: languageRef,
|
|
1481
|
-
className: "flex items-center pl-1.5 border-l border-blumine-200
|
|
1642
|
+
className: "relative flex items-center pl-1.5 border-l border-blumine-200",
|
|
1482
1643
|
children: [
|
|
1483
|
-
/* @__PURE__ */ jsxRuntime.
|
|
1484
|
-
|
|
1644
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1645
|
+
Tooltip,
|
|
1485
1646
|
{
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
children:
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1647
|
+
content: `Input Language: ${LANGUAGE_CONFIGS[currentLanguage].name}`,
|
|
1648
|
+
align: "right",
|
|
1649
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1650
|
+
"button",
|
|
1651
|
+
{
|
|
1652
|
+
onClick: () => setIsLanguageOpen(!isLanguageOpen),
|
|
1653
|
+
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"}`,
|
|
1654
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1655
|
+
lucideReact.Languages,
|
|
1656
|
+
{
|
|
1657
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1658
|
+
strokeWidth: 1.5
|
|
1659
|
+
}
|
|
1660
|
+
)
|
|
1661
|
+
}
|
|
1662
|
+
)
|
|
1492
1663
|
}
|
|
1493
1664
|
),
|
|
1494
|
-
isLanguageOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-[calc(100%+14px)] w-[400px] max-w-[90vw] p-3 rounded-
|
|
1495
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute -top-
|
|
1665
|
+
isLanguageOpen && /* @__PURE__ */ jsxRuntime.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: [
|
|
1666
|
+
/* @__PURE__ */ jsxRuntime.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" }),
|
|
1496
1667
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "px-2 mb-3", children: [
|
|
1497
|
-
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[13px] font-bold text-blumine-
|
|
1498
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-blumine-
|
|
1668
|
+
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "text-[13px] font-bold text-blumine-800 uppercase tracking-wider", children: "Select Input Language" }),
|
|
1669
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-blumine-400 mt-0.5", children: "Direct keyboard mapping (InScript logic)" })
|
|
1499
1670
|
] }),
|
|
1500
1671
|
/* @__PURE__ */ jsxRuntime.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(
|
|
1501
1672
|
(lang) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
@@ -1505,16 +1676,16 @@ function ScreenplayEditorView({
|
|
|
1505
1676
|
setCurrentLanguage(lang);
|
|
1506
1677
|
setIsLanguageOpen(false);
|
|
1507
1678
|
},
|
|
1508
|
-
className: `group flex items-center justify-between px-3.5 py-2.5 rounded-
|
|
1679
|
+
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"}`,
|
|
1509
1680
|
children: [
|
|
1510
1681
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1511
1682
|
"span",
|
|
1512
1683
|
{
|
|
1513
|
-
className: `text-sm font-medium ${currentLanguage === lang ? "text-blumine-
|
|
1684
|
+
className: `text-sm font-medium ${currentLanguage === lang ? "text-blumine-800 font-semibold" : "text-blumine-500"}`,
|
|
1514
1685
|
children: LANGUAGE_CONFIGS[lang].name
|
|
1515
1686
|
}
|
|
1516
1687
|
),
|
|
1517
|
-
currentLanguage === lang && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-5 rounded-full bg-blumine-
|
|
1688
|
+
currentLanguage === lang && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-5 h-5 rounded-full bg-blumine-700 flex items-center justify-center text-white", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-3 h-3", strokeWidth: 2 }) })
|
|
1518
1689
|
]
|
|
1519
1690
|
},
|
|
1520
1691
|
lang
|
|
@@ -1524,15 +1695,20 @@ function ScreenplayEditorView({
|
|
|
1524
1695
|
]
|
|
1525
1696
|
}
|
|
1526
1697
|
),
|
|
1527
|
-
LANGUAGE_CONFIGS[currentLanguage].isPhonetic && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1698
|
+
LANGUAGE_CONFIGS[currentLanguage].isPhonetic && /* @__PURE__ */ jsxRuntime.jsx(Tooltip, { content: "Phonetic Keyboard Rules", align: "right", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1528
1699
|
"button",
|
|
1529
1700
|
{
|
|
1530
1701
|
onClick: () => setIsPhoneticGuideOpen(true),
|
|
1531
|
-
className: "w-
|
|
1532
|
-
|
|
1533
|
-
|
|
1702
|
+
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",
|
|
1703
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1704
|
+
lucideReact.Keyboard,
|
|
1705
|
+
{
|
|
1706
|
+
className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
|
|
1707
|
+
strokeWidth: 1.5
|
|
1708
|
+
}
|
|
1709
|
+
)
|
|
1534
1710
|
}
|
|
1535
|
-
)
|
|
1711
|
+
) })
|
|
1536
1712
|
] })
|
|
1537
1713
|
] }),
|
|
1538
1714
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
@@ -1543,7 +1719,7 @@ function ScreenplayEditorView({
|
|
|
1543
1719
|
onClose: () => setIsPhoneticGuideOpen(false)
|
|
1544
1720
|
}
|
|
1545
1721
|
),
|
|
1546
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-12 pb-24 w-full items-center justify-center", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
1722
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(
|
|
1547
1723
|
"div",
|
|
1548
1724
|
{
|
|
1549
1725
|
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",
|
|
@@ -1556,346 +1732,370 @@ function ScreenplayEditorView({
|
|
|
1556
1732
|
},
|
|
1557
1733
|
"data-screenplay-editor": "true",
|
|
1558
1734
|
dir: LANGUAGE_CONFIGS[currentLanguage].dir,
|
|
1559
|
-
children: blocks.map((block) =>
|
|
1560
|
-
|
|
1561
|
-
|
|
1735
|
+
children: blocks.map((block) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
1736
|
+
ScreenplayBlockItem,
|
|
1737
|
+
{
|
|
1738
|
+
block,
|
|
1739
|
+
isFocused: focusedBlockId === block.id,
|
|
1740
|
+
isLocked,
|
|
1741
|
+
showSuggestions,
|
|
1742
|
+
showExtensionSuggestions,
|
|
1743
|
+
locations,
|
|
1744
|
+
characters,
|
|
1745
|
+
phoneticSuggestions,
|
|
1746
|
+
characterExtensions,
|
|
1747
|
+
enhancingBlockId,
|
|
1748
|
+
enhancementSuggestion,
|
|
1749
|
+
isEnhancing,
|
|
1750
|
+
currentLanguage,
|
|
1751
|
+
refs,
|
|
1752
|
+
handleSceneNumberChange,
|
|
1753
|
+
handleSceneTypeChange,
|
|
1754
|
+
handleTimeOfDayChange,
|
|
1755
|
+
handleBlockTextChange,
|
|
1756
|
+
handleKeyDown,
|
|
1757
|
+
handleFocus,
|
|
1758
|
+
handleBlur,
|
|
1759
|
+
handleSelectPhoneticSuggestion,
|
|
1760
|
+
handleSelectCharacterExtension,
|
|
1761
|
+
handleEnhance,
|
|
1762
|
+
handleApproveEnhance,
|
|
1763
|
+
handleRejectEnhance
|
|
1764
|
+
},
|
|
1765
|
+
block.id + "-" + block.type
|
|
1766
|
+
))
|
|
1767
|
+
}
|
|
1768
|
+
) })
|
|
1769
|
+
] });
|
|
1770
|
+
}
|
|
1771
|
+
var ScreenplayBlockItem = React4__default.default.memo(
|
|
1772
|
+
function ScreenplayBlockItem2({
|
|
1773
|
+
block,
|
|
1774
|
+
isFocused,
|
|
1775
|
+
isLocked,
|
|
1776
|
+
showSuggestions,
|
|
1777
|
+
showExtensionSuggestions,
|
|
1778
|
+
locations,
|
|
1779
|
+
characters,
|
|
1780
|
+
phoneticSuggestions,
|
|
1781
|
+
characterExtensions,
|
|
1782
|
+
enhancingBlockId,
|
|
1783
|
+
enhancementSuggestion,
|
|
1784
|
+
isEnhancing,
|
|
1785
|
+
currentLanguage,
|
|
1786
|
+
refs,
|
|
1787
|
+
handleSceneNumberChange,
|
|
1788
|
+
handleSceneTypeChange,
|
|
1789
|
+
handleTimeOfDayChange,
|
|
1790
|
+
handleBlockTextChange,
|
|
1791
|
+
handleKeyDown,
|
|
1792
|
+
handleFocus,
|
|
1793
|
+
handleBlur,
|
|
1794
|
+
handleSelectPhoneticSuggestion,
|
|
1795
|
+
handleSelectCharacterExtension,
|
|
1796
|
+
handleEnhance,
|
|
1797
|
+
handleApproveEnhance,
|
|
1798
|
+
handleRejectEnhance
|
|
1799
|
+
}) {
|
|
1800
|
+
var _a, _b;
|
|
1801
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
1802
|
+
"div",
|
|
1803
|
+
{
|
|
1804
|
+
"data-block-id": block.id,
|
|
1805
|
+
className: `relative rounded-sm transition-all duration-200 outline-none ${isFocused ? "bg-zinc-100/50" : "bg-transparent"}`,
|
|
1806
|
+
"data-block-type": block.type,
|
|
1807
|
+
children: block.type === "SCENE_HEADING" ? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1808
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 px-4 py-1 bg-transparent", children: [
|
|
1809
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1810
|
+
"input",
|
|
1811
|
+
{
|
|
1812
|
+
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",
|
|
1813
|
+
spellCheck: false,
|
|
1814
|
+
disabled: isLocked,
|
|
1815
|
+
value: block.sceneNumber || "",
|
|
1816
|
+
onChange: (e) => handleSceneNumberChange(
|
|
1817
|
+
block.id,
|
|
1818
|
+
e.target.value.toUpperCase()
|
|
1819
|
+
),
|
|
1820
|
+
onFocus: () => handleFocus(block.id),
|
|
1821
|
+
onBlur: () => handleBlur(block.id),
|
|
1822
|
+
onKeyDown: (e) => {
|
|
1823
|
+
if (e.key === "Enter" || e.key === "Backspace") {
|
|
1824
|
+
e.stopPropagation();
|
|
1825
|
+
}
|
|
1826
|
+
},
|
|
1827
|
+
"aria-label": "Scene Number"
|
|
1828
|
+
}
|
|
1829
|
+
),
|
|
1830
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1831
|
+
"select",
|
|
1832
|
+
{
|
|
1833
|
+
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",
|
|
1834
|
+
"aria-label": "Scene Type",
|
|
1835
|
+
disabled: isLocked,
|
|
1836
|
+
value: (_a = block.sceneType) != null ? _a : "INT.",
|
|
1837
|
+
onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
|
|
1838
|
+
style: {
|
|
1839
|
+
appearance: "none"
|
|
1840
|
+
},
|
|
1841
|
+
children: [
|
|
1842
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT." }),
|
|
1843
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "EXT." }),
|
|
1844
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT/EXT." })
|
|
1845
|
+
]
|
|
1846
|
+
}
|
|
1847
|
+
),
|
|
1848
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1849
|
+
"div",
|
|
1850
|
+
{
|
|
1851
|
+
ref: (el) => {
|
|
1852
|
+
if (!el) return;
|
|
1853
|
+
refs.current[block.id] = el;
|
|
1854
|
+
},
|
|
1855
|
+
contentEditable: !isLocked,
|
|
1856
|
+
suppressContentEditableWarning: true,
|
|
1857
|
+
"aria-label": `Scene Heading: ${block.text}`,
|
|
1858
|
+
"aria-haspopup": "listbox",
|
|
1859
|
+
"aria-expanded": isFocused && showSuggestions && locations.length > 0,
|
|
1860
|
+
spellCheck: false,
|
|
1861
|
+
className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
|
|
1862
|
+
style: {
|
|
1863
|
+
minWidth: "3rem"
|
|
1864
|
+
},
|
|
1865
|
+
onInput: (e) => handleBlockTextChange(
|
|
1866
|
+
block.id,
|
|
1867
|
+
e.target.innerText
|
|
1868
|
+
),
|
|
1869
|
+
onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
|
|
1870
|
+
onFocus: () => handleFocus(block.id),
|
|
1871
|
+
onBlur: () => handleBlur(block.id)
|
|
1872
|
+
}
|
|
1873
|
+
),
|
|
1874
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400/80 font-bold", children: "-" }),
|
|
1875
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1876
|
+
"select",
|
|
1877
|
+
{
|
|
1878
|
+
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",
|
|
1879
|
+
"aria-label": "Time of Day",
|
|
1880
|
+
disabled: isLocked,
|
|
1881
|
+
value: (_b = block.timeOfDay) != null ? _b : "DAY",
|
|
1882
|
+
style: {
|
|
1883
|
+
appearance: "none"
|
|
1884
|
+
},
|
|
1885
|
+
onChange: (e) => handleTimeOfDayChange(block.id, e.target.value),
|
|
1886
|
+
children: timeOfDayOptions.map((t) => /* @__PURE__ */ jsxRuntime.jsx("option", { children: t }, t))
|
|
1887
|
+
}
|
|
1888
|
+
)
|
|
1889
|
+
] }),
|
|
1890
|
+
isFocused && showSuggestions && locations.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1562
1891
|
"div",
|
|
1563
1892
|
{
|
|
1564
|
-
"
|
|
1565
|
-
|
|
1566
|
-
"
|
|
1567
|
-
children:
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
)
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
|
|
1584
|
-
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
"aria-label": "Scene Number"
|
|
1588
|
-
}
|
|
1589
|
-
),
|
|
1590
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1591
|
-
"select",
|
|
1592
|
-
{
|
|
1593
|
-
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",
|
|
1594
|
-
"aria-label": "Scene Type",
|
|
1595
|
-
disabled: isLocked,
|
|
1596
|
-
value: (_a = block.sceneType) != null ? _a : "INT.",
|
|
1597
|
-
onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
|
|
1598
|
-
style: {
|
|
1599
|
-
appearance: "none"
|
|
1600
|
-
},
|
|
1601
|
-
children: [
|
|
1602
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT." }),
|
|
1603
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "EXT." }),
|
|
1604
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { children: "INT/EXT." })
|
|
1605
|
-
]
|
|
1606
|
-
}
|
|
1607
|
-
),
|
|
1608
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1609
|
-
"div",
|
|
1610
|
-
{
|
|
1611
|
-
ref: (el) => {
|
|
1612
|
-
if (!el) return;
|
|
1613
|
-
refs.current[block.id] = el;
|
|
1614
|
-
},
|
|
1615
|
-
contentEditable: !isLocked,
|
|
1616
|
-
suppressContentEditableWarning: true,
|
|
1617
|
-
"aria-label": `Scene Heading: ${block.text}`,
|
|
1618
|
-
"aria-haspopup": "listbox",
|
|
1619
|
-
"aria-expanded": focusedBlockId === block.id && showSuggestions && locations.length > 0,
|
|
1620
|
-
spellCheck: false,
|
|
1621
|
-
className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
|
|
1622
|
-
style: {
|
|
1623
|
-
minWidth: "3rem"
|
|
1624
|
-
},
|
|
1625
|
-
onInput: (e) => handleBlockTextChange(
|
|
1626
|
-
block.id,
|
|
1627
|
-
e.target.innerText
|
|
1628
|
-
),
|
|
1629
|
-
onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
|
|
1630
|
-
onFocus: () => handleFocus(block.id),
|
|
1631
|
-
onBlur: () => handleBlur(block.id)
|
|
1893
|
+
role: "listbox",
|
|
1894
|
+
id: `suggestions-${block.id}`,
|
|
1895
|
+
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",
|
|
1896
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-60 overflow-y-auto custom-scrollbar", children: locations.filter(
|
|
1897
|
+
(loc) => loc.startsWith(block.text.toUpperCase()) && loc !== block.text.toUpperCase()
|
|
1898
|
+
).map((loc) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1899
|
+
"div",
|
|
1900
|
+
{
|
|
1901
|
+
role: "option",
|
|
1902
|
+
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",
|
|
1903
|
+
onMouseDown: (e) => {
|
|
1904
|
+
e.preventDefault();
|
|
1905
|
+
const element = refs.current[block.id];
|
|
1906
|
+
if (element) {
|
|
1907
|
+
element.innerText = loc;
|
|
1908
|
+
handleBlockTextChange(block.id, loc);
|
|
1909
|
+
element.focus();
|
|
1910
|
+
const range = document.createRange();
|
|
1911
|
+
const sel = window.getSelection();
|
|
1912
|
+
range.selectNodeContents(element);
|
|
1913
|
+
range.collapse(false);
|
|
1914
|
+
sel == null ? void 0 : sel.removeAllRanges();
|
|
1915
|
+
sel == null ? void 0 : sel.addRange(range);
|
|
1632
1916
|
}
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
"
|
|
1637
|
-
{
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
1641
|
-
|
|
1642
|
-
|
|
1643
|
-
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1917
|
+
handleBlur(block.id);
|
|
1918
|
+
},
|
|
1919
|
+
children: [
|
|
1920
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[12px] font-semibold tracking-wide text-slate-600 uppercase line-clamp-1", children: loc }),
|
|
1921
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.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" })
|
|
1922
|
+
]
|
|
1923
|
+
},
|
|
1924
|
+
loc
|
|
1925
|
+
)) })
|
|
1926
|
+
}
|
|
1927
|
+
),
|
|
1928
|
+
isFocused && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1929
|
+
PhoneticSuggestions,
|
|
1930
|
+
{
|
|
1931
|
+
suggestions: phoneticSuggestions,
|
|
1932
|
+
onSelect: handleSelectPhoneticSuggestion
|
|
1933
|
+
}
|
|
1934
|
+
)
|
|
1935
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
1936
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1937
|
+
"div",
|
|
1938
|
+
{
|
|
1939
|
+
ref: (el) => {
|
|
1940
|
+
if (!el) return;
|
|
1941
|
+
refs.current[block.id] = el;
|
|
1942
|
+
},
|
|
1943
|
+
contentEditable: !isLocked,
|
|
1944
|
+
suppressContentEditableWarning: true,
|
|
1945
|
+
"aria-label": `${blockStyles[block.type].label} text`,
|
|
1946
|
+
"aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
|
|
1947
|
+
spellCheck: false,
|
|
1948
|
+
className: `block outline-none w-full min-h-[2.5rem] px-4 py-2 break-words ${blockStyles[block.type].className}`,
|
|
1949
|
+
onInput: (e) => handleBlockTextChange(
|
|
1950
|
+
block.id,
|
|
1951
|
+
e.target.innerText
|
|
1952
|
+
),
|
|
1953
|
+
onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
|
|
1954
|
+
onFocus: () => handleFocus(block.id),
|
|
1955
|
+
onBlur: () => handleBlur(block.id),
|
|
1956
|
+
style: blockStyles[block.type].inputStyle
|
|
1957
|
+
}
|
|
1958
|
+
),
|
|
1959
|
+
isFocused && block.type === "CHARACTER" && showSuggestions && characters.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1960
|
+
"div",
|
|
1961
|
+
{
|
|
1962
|
+
role: "listbox",
|
|
1963
|
+
id: `suggestions-${block.id}`,
|
|
1964
|
+
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",
|
|
1965
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characters.filter(
|
|
1966
|
+
(char) => char.startsWith(block.text.toUpperCase()) && char !== block.text.toUpperCase()
|
|
1967
|
+
).map((char) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1968
|
+
"div",
|
|
1969
|
+
{
|
|
1970
|
+
role: "option",
|
|
1971
|
+
className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1972
|
+
onMouseDown: (e) => {
|
|
1973
|
+
e.preventDefault();
|
|
1974
|
+
const element = refs.current[block.id];
|
|
1975
|
+
if (element) {
|
|
1976
|
+
element.innerText = char;
|
|
1977
|
+
handleBlockTextChange(block.id, char);
|
|
1978
|
+
element.focus();
|
|
1979
|
+
const range = document.createRange();
|
|
1980
|
+
const sel = window.getSelection();
|
|
1981
|
+
range.selectNodeContents(element);
|
|
1982
|
+
range.collapse(false);
|
|
1983
|
+
sel == null ? void 0 : sel.removeAllRanges();
|
|
1984
|
+
sel == null ? void 0 : sel.addRange(range);
|
|
1647
1985
|
}
|
|
1648
|
-
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
|
|
1655
|
-
|
|
1656
|
-
|
|
1657
|
-
|
|
1658
|
-
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
|
|
1675
|
-
|
|
1676
|
-
|
|
1677
|
-
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1681
|
-
|
|
1682
|
-
|
|
1683
|
-
|
|
1684
|
-
|
|
1685
|
-
|
|
1686
|
-
|
|
1687
|
-
|
|
1688
|
-
|
|
1689
|
-
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
"
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1713
|
-
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
},
|
|
1754
|
-
char
|
|
1755
|
-
)) })
|
|
1756
|
-
}
|
|
1757
|
-
),
|
|
1758
|
-
focusedBlockId === block.id && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1759
|
-
"div",
|
|
1760
|
-
{
|
|
1761
|
-
role: "listbox",
|
|
1762
|
-
id: `extension-suggestions-${block.id}`,
|
|
1763
|
-
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",
|
|
1764
|
-
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
|
|
1765
|
-
const openParenIndex = block.text.lastIndexOf("(");
|
|
1766
|
-
const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
|
|
1767
|
-
return ext.toUpperCase().includes(query);
|
|
1768
|
-
}).map((ext) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1769
|
-
"div",
|
|
1770
|
-
{
|
|
1771
|
-
role: "option",
|
|
1772
|
-
className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
1773
|
-
onMouseDown: (e) => {
|
|
1774
|
-
e.preventDefault();
|
|
1775
|
-
handleSelectCharacterExtension(ext);
|
|
1776
|
-
},
|
|
1777
|
-
children: [
|
|
1778
|
-
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
|
|
1779
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.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" })
|
|
1780
|
-
]
|
|
1781
|
-
},
|
|
1782
|
-
ext
|
|
1783
|
-
)) })
|
|
1784
|
-
}
|
|
1785
|
-
),
|
|
1786
|
-
focusedBlockId === block.id && !enhancingBlockId && (block.type === "ACTION" || block.type === "DIALOGUE") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1787
|
-
"button",
|
|
1788
|
-
{
|
|
1789
|
-
onClick: () => handleEnhance(block),
|
|
1790
|
-
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",
|
|
1791
|
-
title: "Enhance with AI",
|
|
1792
|
-
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-4 h-4 group-hover/enhance:animate-pulse transition-colors" })
|
|
1793
|
-
}
|
|
1794
|
-
),
|
|
1795
|
-
enhancingBlockId === block.id && (enhancementSuggestion || isEnhancing) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
1796
|
-
"div",
|
|
1797
|
-
{
|
|
1798
|
-
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",
|
|
1799
|
-
style: { width: "calc(100% + 2rem)", left: "-1rem" },
|
|
1800
|
-
children: [
|
|
1801
|
-
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
1802
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pl-1", children: [
|
|
1803
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1804
|
-
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-4 h-4" }) }),
|
|
1805
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
1806
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-bold text-zinc-900 uppercase tracking-wider leading-none", children: "AI Suggestion" }),
|
|
1807
|
-
!isEnhancing && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-zinc-500 mt-1 font-medium", children: "Refining your screenplay dialogue" })
|
|
1808
|
-
] })
|
|
1809
|
-
] }),
|
|
1810
|
-
!isEnhancing && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
1811
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1812
|
-
"button",
|
|
1813
|
-
{
|
|
1814
|
-
onClick: handleRejectEnhance,
|
|
1815
|
-
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",
|
|
1816
|
-
children: "Discard"
|
|
1817
|
-
}
|
|
1818
|
-
),
|
|
1819
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1820
|
-
"button",
|
|
1821
|
-
{
|
|
1822
|
-
onClick: handleApproveEnhance,
|
|
1823
|
-
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",
|
|
1824
|
-
children: [
|
|
1825
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-3.5 h-3.5" }),
|
|
1826
|
-
"Apply Changes"
|
|
1827
|
-
]
|
|
1828
|
-
}
|
|
1829
|
-
)
|
|
1830
|
-
] })
|
|
1831
|
-
] }),
|
|
1832
|
-
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2.5 py-1", children: [
|
|
1833
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-3/4 bg-zinc-200/60 animate-pulse rounded-full" }),
|
|
1834
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-1/2 bg-zinc-200/60 animate-pulse rounded-full" })
|
|
1835
|
-
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
1836
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-400 line-through decoration-zinc-300 italic", children: block.text }),
|
|
1837
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-zinc-800 font-medium leading-relaxed", children: enhancementSuggestion })
|
|
1838
|
-
] }) })
|
|
1839
|
-
] }) }),
|
|
1840
|
-
/* @__PURE__ */ jsxRuntime.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" })
|
|
1841
|
-
]
|
|
1842
|
-
}
|
|
1843
|
-
),
|
|
1844
|
-
focusedBlockId === block.id && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1845
|
-
PhoneticSuggestions,
|
|
1846
|
-
{
|
|
1847
|
-
suggestions: phoneticSuggestions,
|
|
1848
|
-
onSelect: handleSelectPhoneticSuggestion
|
|
1849
|
-
}
|
|
1850
|
-
)
|
|
1851
|
-
] })
|
|
1852
|
-
},
|
|
1853
|
-
block.id + "-" + block.type
|
|
1854
|
-
);
|
|
1855
|
-
})
|
|
1856
|
-
}
|
|
1857
|
-
) }),
|
|
1858
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1859
|
-
"div",
|
|
1860
|
-
{
|
|
1861
|
-
className: `fixed bottom-10 -translate-x-1/2 z-[100] w-full max-w-[95%] sm:max-w-2xl transition-all duration-500 ease-in-out ${showUnsavedPopover ? "translate-y-0 opacity-100 scale-100" : "translate-y-12 opacity-0 scale-95 pointer-events-none"}`,
|
|
1862
|
-
style: {
|
|
1863
|
-
left: savePopOverLeft
|
|
1864
|
-
},
|
|
1865
|
-
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mx-auto rounded-[2.5rem] bg-white/95 border border-white/60 shadow-[0_20px_50px_rgba(16,37,54,0.12),0_4px_12px_rgba(16,37,54,0.05)] backdrop-blur-2xl flex items-center justify-between px-2 py-1.5 sm:px-4 sm:py-2.5 select-none transition-all hover:shadow-[0_25px_60px_rgba(16,37,54,0.18)]", children: [
|
|
1866
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
1867
|
-
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.Save, { className: "w-5 h-5" }) }),
|
|
1868
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mr-5", children: [
|
|
1869
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-bold text-zinc-900 leading-none", children: "Unsaved Changes" }),
|
|
1870
|
-
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-zinc-500 mt-1 font-medium", children: "You have changes that haven't been saved yet." })
|
|
1871
|
-
] })
|
|
1872
|
-
] }),
|
|
1873
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-2 w-full sm:w-auto", children: [
|
|
1874
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1875
|
-
"button",
|
|
1876
|
-
{
|
|
1877
|
-
onClick: ignoreChanges,
|
|
1878
|
-
className: "flex-1 sm:flex-none px-4 py-2 rounded-[2.5rem] text-xs font-bold text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all active:scale-95 whitespace-nowrap",
|
|
1879
|
-
children: "Ignore"
|
|
1880
|
-
}
|
|
1881
|
-
),
|
|
1882
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
1883
|
-
"button",
|
|
1884
|
-
{
|
|
1885
|
-
onClick: syncScreenplay,
|
|
1886
|
-
className: "flex-1 sm:flex-none px-5 py-2 rounded-[2.5rem] text-xs font-bold bg-blumine-500 text-white hover:bg-blumine-600 shadow-lg shadow-blumine-500/25 transition-all active:scale-95 flex items-center justify-center gap-2 whitespace-nowrap",
|
|
1887
|
-
children: [
|
|
1888
|
-
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcw, { className: "w-4 h-4" }),
|
|
1889
|
-
"Sync to Cloud"
|
|
1890
|
-
]
|
|
1891
|
-
}
|
|
1892
|
-
)
|
|
1893
|
-
] })
|
|
1986
|
+
handleBlur(block.id);
|
|
1987
|
+
},
|
|
1988
|
+
children: [
|
|
1989
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-blumine-500 transition-colors mr-3" }),
|
|
1990
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
|
|
1991
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.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
|
+
char
|
|
1995
|
+
)) })
|
|
1996
|
+
}
|
|
1997
|
+
),
|
|
1998
|
+
isFocused && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsxRuntime.jsx(
|
|
1999
|
+
"div",
|
|
2000
|
+
{
|
|
2001
|
+
role: "listbox",
|
|
2002
|
+
id: `extension-suggestions-${block.id}`,
|
|
2003
|
+
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",
|
|
2004
|
+
children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
|
|
2005
|
+
const openParenIndex = block.text.lastIndexOf("(");
|
|
2006
|
+
const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
|
|
2007
|
+
return ext.toUpperCase().includes(query);
|
|
2008
|
+
}).map((ext) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2009
|
+
"div",
|
|
2010
|
+
{
|
|
2011
|
+
role: "option",
|
|
2012
|
+
className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
|
|
2013
|
+
onMouseDown: (e) => {
|
|
2014
|
+
e.preventDefault();
|
|
2015
|
+
handleSelectCharacterExtension(ext);
|
|
2016
|
+
},
|
|
2017
|
+
children: [
|
|
2018
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
|
|
2019
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.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" })
|
|
2020
|
+
]
|
|
2021
|
+
},
|
|
2022
|
+
ext
|
|
2023
|
+
)) })
|
|
2024
|
+
}
|
|
2025
|
+
),
|
|
2026
|
+
isFocused && !enhancingBlockId && (block.type === "ACTION" || block.type === "DIALOGUE") && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2027
|
+
"button",
|
|
2028
|
+
{
|
|
2029
|
+
onClick: () => handleEnhance(block),
|
|
2030
|
+
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",
|
|
2031
|
+
title: "Enhance with AI",
|
|
2032
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-4 h-4 group-hover/enhance:animate-pulse transition-colors" })
|
|
2033
|
+
}
|
|
2034
|
+
),
|
|
2035
|
+
enhancingBlockId === block.id && (enhancementSuggestion || isEnhancing) && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
2036
|
+
"div",
|
|
2037
|
+
{
|
|
2038
|
+
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",
|
|
2039
|
+
style: { width: "calc(100% + 2rem)", left: "-1rem" },
|
|
2040
|
+
children: [
|
|
2041
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
2042
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between pl-1", children: [
|
|
2043
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
|
|
2044
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsx(lucideReact.Sparkles, { className: "w-4 h-4" }) }),
|
|
2045
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
2046
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] font-bold text-zinc-900 uppercase tracking-wider leading-none", children: "AI Suggestion" }),
|
|
2047
|
+
!isEnhancing && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[10px] text-zinc-500 mt-1 font-medium", children: "Refining your screenplay dialogue" })
|
|
2048
|
+
] })
|
|
2049
|
+
] }),
|
|
2050
|
+
!isEnhancing && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
2051
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
2052
|
+
"button",
|
|
2053
|
+
{
|
|
2054
|
+
onClick: handleRejectEnhance,
|
|
2055
|
+
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",
|
|
2056
|
+
children: "Discard"
|
|
2057
|
+
}
|
|
2058
|
+
),
|
|
2059
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
2060
|
+
"button",
|
|
2061
|
+
{
|
|
2062
|
+
onClick: handleApproveEnhance,
|
|
2063
|
+
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",
|
|
2064
|
+
children: [
|
|
2065
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Check, { className: "w-3.5 h-3.5" }),
|
|
2066
|
+
"Apply Changes"
|
|
2067
|
+
]
|
|
2068
|
+
}
|
|
2069
|
+
)
|
|
2070
|
+
] })
|
|
2071
|
+
] }),
|
|
2072
|
+
/* @__PURE__ */ jsxRuntime.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__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2.5 py-1", children: [
|
|
2073
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-3/4 bg-zinc-200/60 animate-pulse rounded-full" }),
|
|
2074
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "h-3.5 w-1/2 bg-zinc-200/60 animate-pulse rounded-full" })
|
|
2075
|
+
] }) : /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
2076
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-zinc-400 line-through decoration-zinc-300 italic", children: block.text }),
|
|
2077
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-zinc-800 font-medium leading-relaxed", children: enhancementSuggestion })
|
|
2078
|
+
] }) })
|
|
2079
|
+
] }) }),
|
|
2080
|
+
/* @__PURE__ */ jsxRuntime.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" })
|
|
2081
|
+
]
|
|
2082
|
+
}
|
|
2083
|
+
),
|
|
2084
|
+
isFocused && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
|
|
2085
|
+
PhoneticSuggestions,
|
|
2086
|
+
{
|
|
2087
|
+
suggestions: phoneticSuggestions,
|
|
2088
|
+
onSelect: handleSelectPhoneticSuggestion
|
|
2089
|
+
}
|
|
2090
|
+
)
|
|
1894
2091
|
] })
|
|
1895
2092
|
}
|
|
1896
|
-
)
|
|
1897
|
-
|
|
1898
|
-
|
|
2093
|
+
);
|
|
2094
|
+
},
|
|
2095
|
+
(prevProps, nextProps) => {
|
|
2096
|
+
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);
|
|
2097
|
+
}
|
|
2098
|
+
);
|
|
1899
2099
|
|
|
1900
2100
|
// app/service/screenplay-editor.service.ts
|
|
1901
2101
|
function getNextBlockType(currentType) {
|
|
@@ -2223,49 +2423,144 @@ function createRangeFromGlobalOffset(element, startOffset, endOffset) {
|
|
|
2223
2423
|
return null;
|
|
2224
2424
|
}
|
|
2225
2425
|
function useScreenplayEditor(options) {
|
|
2226
|
-
|
|
2227
|
-
const
|
|
2228
|
-
|
|
2426
|
+
var _a;
|
|
2427
|
+
const [blocks, setBlocks] = React4.useState(
|
|
2428
|
+
(options == null ? void 0 : options.blocks) || initialBlocks || []
|
|
2429
|
+
);
|
|
2430
|
+
const hasInitializedRef = React4.useRef(
|
|
2431
|
+
!!((options == null ? void 0 : options.blocks) && options.blocks.length > 0)
|
|
2432
|
+
);
|
|
2433
|
+
React4.useEffect(() => {
|
|
2434
|
+
if ((options == null ? void 0 : options.blocks) && options.blocks.length > 0 && !hasInitializedRef.current) {
|
|
2435
|
+
setIsLoading(true);
|
|
2436
|
+
isWaitingForDOMRef.current = true;
|
|
2437
|
+
skipAutosaveRef.current = true;
|
|
2438
|
+
const timer = setTimeout(() => {
|
|
2439
|
+
setBlocks(options.blocks);
|
|
2440
|
+
hasInitializedRef.current = true;
|
|
2441
|
+
}, 50);
|
|
2442
|
+
return () => clearTimeout(timer);
|
|
2443
|
+
}
|
|
2444
|
+
}, [options == null ? void 0 : options.blocks]);
|
|
2445
|
+
const refs = React4.useRef({});
|
|
2446
|
+
const [focusedBlockId, setFocusedBlockId] = React4.useState(
|
|
2229
2447
|
initialBlocks[0].id
|
|
2230
2448
|
);
|
|
2231
|
-
const [newBlockId, setNewBlockId] =
|
|
2232
|
-
const [showSuggestions, setShowSuggestions] =
|
|
2233
|
-
const [showExtensionSuggestions, setShowExtensionSuggestions] =
|
|
2234
|
-
const [isLoading, setIsLoading] =
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
const [
|
|
2238
|
-
const [
|
|
2239
|
-
const [
|
|
2240
|
-
const
|
|
2241
|
-
const
|
|
2242
|
-
const
|
|
2243
|
-
const
|
|
2244
|
-
const
|
|
2245
|
-
const
|
|
2246
|
-
const
|
|
2247
|
-
|
|
2248
|
-
|
|
2249
|
-
const
|
|
2250
|
-
|
|
2449
|
+
const [newBlockId, setNewBlockId] = React4.useState(null);
|
|
2450
|
+
const [showSuggestions, setShowSuggestions] = React4.useState(false);
|
|
2451
|
+
const [showExtensionSuggestions, setShowExtensionSuggestions] = React4.useState(false);
|
|
2452
|
+
const [isLoading, setIsLoading] = React4.useState(
|
|
2453
|
+
!!((options == null ? void 0 : options.initialUrl) || (options == null ? void 0 : options.blocks) && options.blocks.length > 0)
|
|
2454
|
+
);
|
|
2455
|
+
const [enhancingBlockId, setEnhancingBlockId] = React4.useState(null);
|
|
2456
|
+
const [enhancementSuggestion, setEnhancementSuggestion] = React4.useState(null);
|
|
2457
|
+
const [isEnhancing, setIsEnhancing] = React4.useState(false);
|
|
2458
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = React4.useState(false);
|
|
2459
|
+
const [showUnsavedPopover, setShowUnsavedPopover] = React4.useState(false);
|
|
2460
|
+
const popoverTimeoutRef = React4.useRef(null);
|
|
2461
|
+
const blurTimeout = React4.useRef(null);
|
|
2462
|
+
const isInitialLoadRef = React4.useRef(true);
|
|
2463
|
+
const skipAutosaveRef = React4.useRef(false);
|
|
2464
|
+
const isWaitingForDOMRef = React4.useRef(
|
|
2465
|
+
!!((options == null ? void 0 : options.initialUrl) || (options == null ? void 0 : options.blocks) && options.blocks.length > 0)
|
|
2466
|
+
);
|
|
2467
|
+
const loadedUrlRef = React4.useRef(null);
|
|
2468
|
+
const lastSavedContent = React4.useRef(null);
|
|
2469
|
+
const onSaveRef = React4.useRef(options == null ? void 0 : options.onSave);
|
|
2470
|
+
const onSaveBlobRef = React4.useRef(options == null ? void 0 : options.onSaveBlob);
|
|
2471
|
+
const onSyncWithCloudRef = React4.useRef(options == null ? void 0 : options.onSyncWithCloud);
|
|
2472
|
+
const [autosaveStatus, setAutosaveStatus] = React4.useState("idle");
|
|
2473
|
+
const isLocked = (_a = options == null ? void 0 : options.isLocked) != null ? _a : false;
|
|
2474
|
+
const [currentLanguage, setCurrentLanguage] = React4.useState("English");
|
|
2475
|
+
const [lastPhoneticAction, setLastPhoneticAction] = React4.useState(null);
|
|
2476
|
+
const [phoneticSuggestions, setPhoneticSuggestions] = React4.useState([]);
|
|
2477
|
+
const lastSyncedTextRef = React4.useRef({});
|
|
2478
|
+
React4.useEffect(() => {
|
|
2251
2479
|
setLastPhoneticAction(null);
|
|
2252
2480
|
setPhoneticSuggestions([]);
|
|
2253
2481
|
}, [currentLanguage]);
|
|
2254
|
-
const phoneticEngine =
|
|
2482
|
+
const phoneticEngine = React4.useMemo(() => {
|
|
2255
2483
|
if (currentLanguage.includes("Phonetic")) {
|
|
2256
2484
|
return new PhoneticEngine(currentLanguage);
|
|
2257
2485
|
}
|
|
2258
2486
|
return null;
|
|
2259
2487
|
}, [currentLanguage]);
|
|
2260
|
-
|
|
2488
|
+
React4.useEffect(() => {
|
|
2261
2489
|
onSaveRef.current = options == null ? void 0 : options.onSave;
|
|
2490
|
+
onSaveBlobRef.current = options == null ? void 0 : options.onSaveBlob;
|
|
2262
2491
|
onSyncWithCloudRef.current = options == null ? void 0 : options.onSyncWithCloud;
|
|
2263
|
-
}, [options == null ? void 0 : options.onSave, options == null ? void 0 : options.onSyncWithCloud]);
|
|
2264
|
-
const
|
|
2492
|
+
}, [options == null ? void 0 : options.onSave, options == null ? void 0 : options.onSaveBlob, options == null ? void 0 : options.onSyncWithCloud]);
|
|
2493
|
+
const isFirstAutosaveRender = React4.useRef(true);
|
|
2494
|
+
const prevBlocksRef = React4.useRef(blocks);
|
|
2495
|
+
React4.useEffect(() => {
|
|
2496
|
+
if (isLocked) {
|
|
2497
|
+
setAutosaveStatus("idle");
|
|
2498
|
+
return;
|
|
2499
|
+
}
|
|
2500
|
+
if (isFirstAutosaveRender.current) {
|
|
2501
|
+
isFirstAutosaveRender.current = false;
|
|
2502
|
+
prevBlocksRef.current = blocks;
|
|
2503
|
+
return;
|
|
2504
|
+
}
|
|
2505
|
+
if (skipAutosaveRef.current) {
|
|
2506
|
+
skipAutosaveRef.current = false;
|
|
2507
|
+
prevBlocksRef.current = blocks;
|
|
2508
|
+
return;
|
|
2509
|
+
}
|
|
2510
|
+
const hasChanged = blocks.length !== prevBlocksRef.current.length || blocks.some((b, i) => b !== prevBlocksRef.current[i]);
|
|
2511
|
+
if (!hasChanged) {
|
|
2512
|
+
return;
|
|
2513
|
+
}
|
|
2514
|
+
setAutosaveStatus("typing");
|
|
2515
|
+
prevBlocksRef.current = blocks;
|
|
2516
|
+
const timer = setTimeout(async () => {
|
|
2517
|
+
if (onSaveRef.current) {
|
|
2518
|
+
setAutosaveStatus("saving");
|
|
2519
|
+
try {
|
|
2520
|
+
await onSaveRef.current(blocks);
|
|
2521
|
+
setAutosaveStatus("saved");
|
|
2522
|
+
setTimeout(() => {
|
|
2523
|
+
setAutosaveStatus((prev) => prev === "saved" ? "idle" : prev);
|
|
2524
|
+
}, 2e3);
|
|
2525
|
+
} catch (error) {
|
|
2526
|
+
console.error("Autosave failed:", error);
|
|
2527
|
+
setAutosaveStatus("error");
|
|
2528
|
+
}
|
|
2529
|
+
} else {
|
|
2530
|
+
setAutosaveStatus("idle");
|
|
2531
|
+
}
|
|
2532
|
+
}, 3e3);
|
|
2533
|
+
return () => clearTimeout(timer);
|
|
2534
|
+
}, [blocks, isLocked]);
|
|
2535
|
+
const latestBlocksRef = React4.useRef(blocks);
|
|
2536
|
+
React4.useEffect(() => {
|
|
2537
|
+
latestBlocksRef.current = blocks;
|
|
2538
|
+
}, [blocks]);
|
|
2539
|
+
React4.useEffect(() => {
|
|
2540
|
+
const handleBeforeUnload = (e) => {
|
|
2541
|
+
if (autosaveStatus === "typing" || autosaveStatus === "saving") {
|
|
2542
|
+
e.preventDefault();
|
|
2543
|
+
e.returnValue = "Changes you made may not be saved.";
|
|
2544
|
+
return e.returnValue;
|
|
2545
|
+
}
|
|
2546
|
+
};
|
|
2547
|
+
window.addEventListener("beforeunload", handleBeforeUnload);
|
|
2548
|
+
return () => {
|
|
2549
|
+
window.removeEventListener("beforeunload", handleBeforeUnload);
|
|
2550
|
+
};
|
|
2551
|
+
}, [autosaveStatus]);
|
|
2552
|
+
React4.useEffect(() => {
|
|
2553
|
+
return () => {
|
|
2554
|
+
if (autosaveStatus === "typing" && onSaveRef.current) {
|
|
2555
|
+
onSaveRef.current(latestBlocksRef.current);
|
|
2556
|
+
}
|
|
2557
|
+
};
|
|
2558
|
+
}, [autosaveStatus]);
|
|
2559
|
+
const characterExtensions = React4.useMemo(
|
|
2265
2560
|
() => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
|
|
2266
2561
|
[]
|
|
2267
2562
|
);
|
|
2268
|
-
const handleSceneNumberChange =
|
|
2563
|
+
const handleSceneNumberChange = React4.useCallback(
|
|
2269
2564
|
(id, newNumber) => {
|
|
2270
2565
|
setBlocks(
|
|
2271
2566
|
(prevBlocks) => prevBlocks.map(
|
|
@@ -2275,45 +2570,52 @@ function useScreenplayEditor(options) {
|
|
|
2275
2570
|
},
|
|
2276
2571
|
[]
|
|
2277
2572
|
);
|
|
2278
|
-
const locations =
|
|
2279
|
-
const
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
const characters = react.useMemo(() => {
|
|
2283
|
-
const chars = blocks.filter((b) => b.type === "CHARACTER" && b.text.trim() !== "").map((b) => {
|
|
2284
|
-
const text = b.text.trim().toUpperCase();
|
|
2285
|
-
const parenIndex = text.indexOf("(");
|
|
2286
|
-
if (parenIndex > -1) {
|
|
2287
|
-
return text.substring(0, parenIndex).trim();
|
|
2288
|
-
}
|
|
2289
|
-
return text;
|
|
2290
|
-
}).filter(Boolean);
|
|
2291
|
-
return [...new Set(chars)];
|
|
2292
|
-
}, [blocks]);
|
|
2293
|
-
const sceneNumbers = react.useMemo(() => {
|
|
2294
|
-
const map = {};
|
|
2573
|
+
const { locations, characters, sceneNumbers } = React4.useMemo(() => {
|
|
2574
|
+
const locsSet = /* @__PURE__ */ new Set();
|
|
2575
|
+
const charsSet = /* @__PURE__ */ new Set();
|
|
2576
|
+
const sceneNumMap = {};
|
|
2295
2577
|
let fallbackCount = 0;
|
|
2296
2578
|
blocks.forEach((block) => {
|
|
2579
|
+
const textTrim = block.text.trim();
|
|
2297
2580
|
if (block.type === "SCENE_HEADING") {
|
|
2581
|
+
if (textTrim !== "") {
|
|
2582
|
+
locsSet.add(textTrim.toUpperCase());
|
|
2583
|
+
}
|
|
2298
2584
|
if (block.sceneNumber) {
|
|
2299
|
-
|
|
2585
|
+
sceneNumMap[block.id] = block.sceneNumber;
|
|
2300
2586
|
const base = parseInt(block.sceneNumber);
|
|
2301
2587
|
if (!isNaN(base)) fallbackCount = Math.max(fallbackCount, base);
|
|
2302
2588
|
} else {
|
|
2303
2589
|
fallbackCount++;
|
|
2304
|
-
|
|
2590
|
+
sceneNumMap[block.id] = String(fallbackCount);
|
|
2591
|
+
}
|
|
2592
|
+
} else if (block.type === "CHARACTER") {
|
|
2593
|
+
if (textTrim !== "") {
|
|
2594
|
+
const textUpper = textTrim.toUpperCase();
|
|
2595
|
+
const parenIndex = textUpper.indexOf("(");
|
|
2596
|
+
if (parenIndex > -1) {
|
|
2597
|
+
const charName = textUpper.substring(0, parenIndex).trim();
|
|
2598
|
+
if (charName) charsSet.add(charName);
|
|
2599
|
+
} else {
|
|
2600
|
+
charsSet.add(textUpper);
|
|
2601
|
+
}
|
|
2305
2602
|
}
|
|
2306
2603
|
}
|
|
2307
2604
|
});
|
|
2308
|
-
return
|
|
2605
|
+
return {
|
|
2606
|
+
locations: Array.from(locsSet),
|
|
2607
|
+
characters: Array.from(charsSet),
|
|
2608
|
+
sceneNumbers: sceneNumMap
|
|
2609
|
+
};
|
|
2309
2610
|
}, [blocks]);
|
|
2310
|
-
|
|
2611
|
+
React4.useEffect(() => {
|
|
2311
2612
|
if (newBlockId && refs.current[newBlockId]) {
|
|
2312
2613
|
const block = blocks.find((b) => b.id === newBlockId);
|
|
2313
2614
|
const el = refs.current[newBlockId];
|
|
2314
2615
|
if (el && block) {
|
|
2315
2616
|
el.focus();
|
|
2316
|
-
el.
|
|
2617
|
+
el.textContent = block.text;
|
|
2618
|
+
lastSyncedTextRef.current[newBlockId] = block.text;
|
|
2317
2619
|
if (block.type === "PARENTHETICAL") {
|
|
2318
2620
|
setTimeout(() => setCaretPosition(el, 1), 0);
|
|
2319
2621
|
} else {
|
|
@@ -2324,17 +2626,57 @@ function useScreenplayEditor(options) {
|
|
|
2324
2626
|
setNewBlockId(null);
|
|
2325
2627
|
}
|
|
2326
2628
|
}, [newBlockId, blocks]);
|
|
2327
|
-
|
|
2629
|
+
React4.useEffect(() => {
|
|
2328
2630
|
blocks.forEach((block) => {
|
|
2329
2631
|
const element = refs.current[block.id];
|
|
2330
2632
|
if (element) {
|
|
2331
|
-
if (
|
|
2332
|
-
element.
|
|
2633
|
+
if (lastSyncedTextRef.current[block.id] !== block.text && document.activeElement !== element) {
|
|
2634
|
+
element.textContent = block.text;
|
|
2635
|
+
lastSyncedTextRef.current[block.id] = block.text;
|
|
2333
2636
|
}
|
|
2334
2637
|
}
|
|
2335
2638
|
});
|
|
2639
|
+
if (isWaitingForDOMRef.current) {
|
|
2640
|
+
const dismissLoader = () => {
|
|
2641
|
+
if (typeof window !== "undefined") {
|
|
2642
|
+
void document.body.scrollHeight;
|
|
2643
|
+
}
|
|
2644
|
+
setIsLoading(false);
|
|
2645
|
+
isWaitingForDOMRef.current = false;
|
|
2646
|
+
};
|
|
2647
|
+
const waitForAllReady = async () => {
|
|
2648
|
+
if (typeof window !== "undefined") {
|
|
2649
|
+
try {
|
|
2650
|
+
if (document.fonts && document.fonts.ready) {
|
|
2651
|
+
await document.fonts.ready;
|
|
2652
|
+
}
|
|
2653
|
+
} catch (e) {
|
|
2654
|
+
console.error("Font loading detection failed:", e);
|
|
2655
|
+
}
|
|
2656
|
+
}
|
|
2657
|
+
if (typeof window !== "undefined" && "requestIdleCallback" in window) {
|
|
2658
|
+
requestAnimationFrame(() => {
|
|
2659
|
+
requestAnimationFrame(() => {
|
|
2660
|
+
window.requestIdleCallback(
|
|
2661
|
+
() => {
|
|
2662
|
+
setTimeout(dismissLoader, 150);
|
|
2663
|
+
},
|
|
2664
|
+
{ timeout: 2e3 }
|
|
2665
|
+
);
|
|
2666
|
+
});
|
|
2667
|
+
});
|
|
2668
|
+
} else {
|
|
2669
|
+
requestAnimationFrame(() => {
|
|
2670
|
+
requestAnimationFrame(() => {
|
|
2671
|
+
setTimeout(dismissLoader, 400);
|
|
2672
|
+
});
|
|
2673
|
+
});
|
|
2674
|
+
}
|
|
2675
|
+
};
|
|
2676
|
+
waitForAllReady();
|
|
2677
|
+
}
|
|
2336
2678
|
}, [blocks]);
|
|
2337
|
-
|
|
2679
|
+
React4.useEffect(() => {
|
|
2338
2680
|
const handleClickOutside = (e) => {
|
|
2339
2681
|
const target = e.target;
|
|
2340
2682
|
const isInsideBlock = target.closest("[data-block-id]");
|
|
@@ -2352,7 +2694,7 @@ function useScreenplayEditor(options) {
|
|
|
2352
2694
|
document.removeEventListener("mousedown", handleClickOutside);
|
|
2353
2695
|
};
|
|
2354
2696
|
}, []);
|
|
2355
|
-
const handleBlockTextChange =
|
|
2697
|
+
const handleBlockTextChange = React4.useCallback(
|
|
2356
2698
|
(id, text) => {
|
|
2357
2699
|
const block = blocks.find((b) => b.id === id);
|
|
2358
2700
|
if (!block) return;
|
|
@@ -2388,35 +2730,38 @@ function useScreenplayEditor(options) {
|
|
|
2388
2730
|
const offset = getCaretCharacterOffsetWithin(el);
|
|
2389
2731
|
const charsBeforeCaret = text.substring(0, offset).replace(/[()]/g, "").length;
|
|
2390
2732
|
const newOffset = 1 + charsBeforeCaret;
|
|
2391
|
-
el.
|
|
2733
|
+
el.textContent = processedText;
|
|
2734
|
+
lastSyncedTextRef.current[id] = processedText;
|
|
2392
2735
|
setCaretPosition(el, newOffset);
|
|
2393
2736
|
}
|
|
2737
|
+
} else {
|
|
2738
|
+
lastSyncedTextRef.current[id] = text;
|
|
2394
2739
|
}
|
|
2395
2740
|
},
|
|
2396
2741
|
[blocks, showExtensionSuggestions]
|
|
2397
2742
|
);
|
|
2398
|
-
const handleSceneTypeChange =
|
|
2743
|
+
const handleSceneTypeChange = React4.useCallback(
|
|
2399
2744
|
(id, sceneType) => {
|
|
2400
2745
|
setBlocks(
|
|
2401
2746
|
(bs) => updateBlock(bs, id, "sceneType", sceneType)
|
|
2402
2747
|
);
|
|
2403
2748
|
setTimeout(() => {
|
|
2404
|
-
var
|
|
2405
|
-
(
|
|
2749
|
+
var _a2;
|
|
2750
|
+
(_a2 = refs.current[id]) == null ? void 0 : _a2.focus();
|
|
2406
2751
|
setFocusedBlockId(id);
|
|
2407
2752
|
}, 10);
|
|
2408
2753
|
},
|
|
2409
2754
|
[]
|
|
2410
2755
|
);
|
|
2411
|
-
const handleTimeOfDayChange =
|
|
2756
|
+
const handleTimeOfDayChange = React4.useCallback((id, time) => {
|
|
2412
2757
|
setBlocks((bs) => updateBlock(bs, id, "timeOfDay", time));
|
|
2413
2758
|
setTimeout(() => {
|
|
2414
|
-
var
|
|
2415
|
-
(
|
|
2759
|
+
var _a2;
|
|
2760
|
+
(_a2 = refs.current[id]) == null ? void 0 : _a2.focus();
|
|
2416
2761
|
setFocusedBlockId(id);
|
|
2417
2762
|
}, 10);
|
|
2418
2763
|
}, []);
|
|
2419
|
-
const handleBlockTypeChange =
|
|
2764
|
+
const handleBlockTypeChange = React4.useCallback(
|
|
2420
2765
|
(newType) => {
|
|
2421
2766
|
if (!focusedBlockId) return;
|
|
2422
2767
|
setBlocks(
|
|
@@ -2442,7 +2787,7 @@ function useScreenplayEditor(options) {
|
|
|
2442
2787
|
},
|
|
2443
2788
|
[focusedBlockId, blocks]
|
|
2444
2789
|
);
|
|
2445
|
-
const handleSelectCharacterExtension =
|
|
2790
|
+
const handleSelectCharacterExtension = React4.useCallback(
|
|
2446
2791
|
(extension) => {
|
|
2447
2792
|
if (!focusedBlockId) return;
|
|
2448
2793
|
setBlocks((currentBlocks) => {
|
|
@@ -2511,9 +2856,9 @@ function useScreenplayEditor(options) {
|
|
|
2511
2856
|
}
|
|
2512
2857
|
}, 10);
|
|
2513
2858
|
};
|
|
2514
|
-
const handleKeyDown =
|
|
2859
|
+
const handleKeyDown = React4.useCallback(
|
|
2515
2860
|
(e, id, text) => {
|
|
2516
|
-
var
|
|
2861
|
+
var _a2;
|
|
2517
2862
|
if (currentLanguage !== "English") {
|
|
2518
2863
|
const config = LANGUAGE_CONFIGS[currentLanguage];
|
|
2519
2864
|
const char = getMappedCharacter(
|
|
@@ -2680,7 +3025,7 @@ function useScreenplayEditor(options) {
|
|
|
2680
3025
|
const range = selection.getRangeAt(0);
|
|
2681
3026
|
const contentEditable = e.currentTarget;
|
|
2682
3027
|
const container = range.endContainer;
|
|
2683
|
-
const isAtEndOffset = range.endOffset === (container.nodeType === Node.TEXT_NODE ? (
|
|
3028
|
+
const isAtEndOffset = range.endOffset === (container.nodeType === Node.TEXT_NODE ? (_a2 = container.textContent) == null ? void 0 : _a2.length : container.childNodes.length);
|
|
2684
3029
|
if (isAtEndOffset) {
|
|
2685
3030
|
let atEnd = false;
|
|
2686
3031
|
let node = container;
|
|
@@ -2720,7 +3065,7 @@ function useScreenplayEditor(options) {
|
|
|
2720
3065
|
lastPhoneticAction
|
|
2721
3066
|
]
|
|
2722
3067
|
);
|
|
2723
|
-
const handleScriptImport =
|
|
3068
|
+
const handleScriptImport = React4.useCallback(
|
|
2724
3069
|
(title, content, preParsedBlocks, isInitialLoad) => {
|
|
2725
3070
|
let parsedBlocks = [];
|
|
2726
3071
|
if (preParsedBlocks && preParsedBlocks.length > 0) {
|
|
@@ -2736,6 +3081,9 @@ function useScreenplayEditor(options) {
|
|
|
2736
3081
|
parsedBlocks = parseScreenplayText(content);
|
|
2737
3082
|
}
|
|
2738
3083
|
if (parsedBlocks.length > 0) {
|
|
3084
|
+
setIsLoading(true);
|
|
3085
|
+
isWaitingForDOMRef.current = true;
|
|
3086
|
+
skipAutosaveRef.current = true;
|
|
2739
3087
|
let fallbackCount = 1;
|
|
2740
3088
|
const finalizedBlocks = parsedBlocks.map((block) => {
|
|
2741
3089
|
if (block.type === "SCENE_HEADING") {
|
|
@@ -2750,30 +3098,35 @@ function useScreenplayEditor(options) {
|
|
|
2750
3098
|
}
|
|
2751
3099
|
return block;
|
|
2752
3100
|
});
|
|
2753
|
-
setBlocks(finalizedBlocks);
|
|
2754
|
-
if (onSaveRef.current) {
|
|
2755
|
-
const sbxData = serializeToSbx(finalizedBlocks);
|
|
2756
|
-
if (sbxData !== lastSavedContent.current) {
|
|
2757
|
-
lastSavedContent.current = sbxData;
|
|
2758
|
-
if (!isInitialLoad) {
|
|
2759
|
-
const blob = new Blob([sbxData], { type: "text/plain" });
|
|
2760
|
-
onSaveRef.current(blob);
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
3101
|
setTimeout(() => {
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
3102
|
+
setBlocks(finalizedBlocks);
|
|
3103
|
+
if (onSaveBlobRef.current) {
|
|
3104
|
+
const sbxData = serializeToSbx(finalizedBlocks);
|
|
3105
|
+
if (sbxData !== lastSavedContent.current) {
|
|
3106
|
+
lastSavedContent.current = sbxData;
|
|
3107
|
+
if (!isInitialLoad) {
|
|
3108
|
+
const blob = new Blob([sbxData], { type: "text/plain" });
|
|
3109
|
+
onSaveBlobRef.current(blob);
|
|
3110
|
+
}
|
|
3111
|
+
}
|
|
2770
3112
|
}
|
|
2771
|
-
|
|
3113
|
+
setTimeout(() => {
|
|
3114
|
+
var _a2;
|
|
3115
|
+
const firstId = parsedBlocks[0].id;
|
|
3116
|
+
if (firstId && refs.current[firstId]) {
|
|
3117
|
+
setFocusedBlockId(firstId);
|
|
3118
|
+
(_a2 = refs.current[firstId]) == null ? void 0 : _a2.focus();
|
|
3119
|
+
}
|
|
3120
|
+
}, 100);
|
|
3121
|
+
}, 50);
|
|
3122
|
+
} else {
|
|
3123
|
+
setIsLoading(false);
|
|
3124
|
+
isWaitingForDOMRef.current = false;
|
|
2772
3125
|
}
|
|
2773
3126
|
},
|
|
2774
3127
|
[refs]
|
|
2775
3128
|
);
|
|
2776
|
-
const handleSelectPhoneticSuggestion =
|
|
3129
|
+
const handleSelectPhoneticSuggestion = React4.useCallback(
|
|
2777
3130
|
(suggestion) => {
|
|
2778
3131
|
if (!focusedBlockId) return;
|
|
2779
3132
|
const el = refs.current[focusedBlockId];
|
|
@@ -2793,7 +3146,7 @@ function useScreenplayEditor(options) {
|
|
|
2793
3146
|
},
|
|
2794
3147
|
[focusedBlockId, handleBlockTextChange]
|
|
2795
3148
|
);
|
|
2796
|
-
const handleFocus =
|
|
3149
|
+
const handleFocus = React4.useCallback(
|
|
2797
3150
|
(id) => {
|
|
2798
3151
|
if (blurTimeout.current) {
|
|
2799
3152
|
clearTimeout(blurTimeout.current);
|
|
@@ -2818,14 +3171,14 @@ function useScreenplayEditor(options) {
|
|
|
2818
3171
|
},
|
|
2819
3172
|
[blocks]
|
|
2820
3173
|
);
|
|
2821
|
-
const handleBlur =
|
|
3174
|
+
const handleBlur = React4.useCallback((id) => {
|
|
2822
3175
|
if (document.activeElement === refs.current[id]) return;
|
|
2823
3176
|
blurTimeout.current = setTimeout(() => {
|
|
2824
3177
|
setShowSuggestions(false);
|
|
2825
3178
|
setShowExtensionSuggestions(false);
|
|
2826
3179
|
}, 200);
|
|
2827
3180
|
}, []);
|
|
2828
|
-
const syncScreenplay =
|
|
3181
|
+
const syncScreenplay = React4.useCallback(() => {
|
|
2829
3182
|
if (!onSyncWithCloudRef.current) return;
|
|
2830
3183
|
onSyncWithCloudRef.current(blocks, sceneNumbers);
|
|
2831
3184
|
lastSavedContent.current = serializeToSbx(blocks);
|
|
@@ -2833,13 +3186,13 @@ function useScreenplayEditor(options) {
|
|
|
2833
3186
|
setShowUnsavedPopover(false);
|
|
2834
3187
|
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2835
3188
|
}, [blocks, sceneNumbers]);
|
|
2836
|
-
const ignoreChanges =
|
|
3189
|
+
const ignoreChanges = React4.useCallback(() => {
|
|
2837
3190
|
setShowUnsavedPopover(false);
|
|
2838
3191
|
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2839
3192
|
}, []);
|
|
2840
|
-
const loadFromUrl =
|
|
3193
|
+
const loadFromUrl = React4.useCallback(
|
|
2841
3194
|
async (url, fetchOptions = {}, isInitialLoad) => {
|
|
2842
|
-
var
|
|
3195
|
+
var _a2;
|
|
2843
3196
|
setIsLoading(true);
|
|
2844
3197
|
try {
|
|
2845
3198
|
const response = await fetch(url, fetchOptions);
|
|
@@ -2851,7 +3204,15 @@ function useScreenplayEditor(options) {
|
|
|
2851
3204
|
let text = await response.text();
|
|
2852
3205
|
let preParsedBlocks = void 0;
|
|
2853
3206
|
let scriptContent = text;
|
|
2854
|
-
|
|
3207
|
+
try {
|
|
3208
|
+
const parsed = JSON.parse(text);
|
|
3209
|
+
if (Array.isArray(parsed)) {
|
|
3210
|
+
preParsedBlocks = parsed;
|
|
3211
|
+
scriptContent = "";
|
|
3212
|
+
}
|
|
3213
|
+
} catch (e) {
|
|
3214
|
+
}
|
|
3215
|
+
if (!preParsedBlocks && (text.includes('class="divtype') || url.toLowerCase().includes(".sbx"))) {
|
|
2855
3216
|
if (text.includes("<div")) {
|
|
2856
3217
|
const textarea = document.createElement("textarea");
|
|
2857
3218
|
textarea.innerHTML = text;
|
|
@@ -2870,8 +3231,8 @@ function useScreenplayEditor(options) {
|
|
|
2870
3231
|
divtype6: "TRANSITION"
|
|
2871
3232
|
};
|
|
2872
3233
|
divs.forEach((div) => {
|
|
2873
|
-
var
|
|
2874
|
-
let divText = ((
|
|
3234
|
+
var _a3;
|
|
3235
|
+
let divText = ((_a3 = div.textContent) == null ? void 0 : _a3.trim()) || "";
|
|
2875
3236
|
if (!divText) return;
|
|
2876
3237
|
let type = "ACTION";
|
|
2877
3238
|
for (const className of Array.from(div.classList)) {
|
|
@@ -2910,50 +3271,70 @@ function useScreenplayEditor(options) {
|
|
|
2910
3271
|
scriptContent = "";
|
|
2911
3272
|
}
|
|
2912
3273
|
}
|
|
2913
|
-
const filename = ((
|
|
3274
|
+
const filename = ((_a2 = url.split("/").pop()) == null ? void 0 : _a2.replace(/\.sbx$/i, "")) || "Imported from URL";
|
|
3275
|
+
isWaitingForDOMRef.current = true;
|
|
2914
3276
|
handleScriptImport(
|
|
2915
3277
|
filename,
|
|
2916
3278
|
scriptContent,
|
|
2917
3279
|
preParsedBlocks,
|
|
2918
3280
|
isInitialLoad
|
|
2919
3281
|
);
|
|
2920
|
-
}
|
|
3282
|
+
} catch (error) {
|
|
3283
|
+
console.error("Failed to load screenplay from URL:", error);
|
|
2921
3284
|
setIsLoading(false);
|
|
3285
|
+
isWaitingForDOMRef.current = false;
|
|
2922
3286
|
}
|
|
2923
3287
|
},
|
|
2924
3288
|
[handleScriptImport]
|
|
2925
3289
|
);
|
|
2926
|
-
|
|
3290
|
+
React4.useEffect(() => {
|
|
2927
3291
|
if (isLoading) {
|
|
2928
3292
|
isInitialLoadRef.current = true;
|
|
2929
3293
|
return;
|
|
2930
3294
|
}
|
|
2931
|
-
const
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
|
|
3295
|
+
const handler = setTimeout(() => {
|
|
3296
|
+
const runSerialization = () => {
|
|
3297
|
+
const currentSbx = serializeToSbx(blocks);
|
|
3298
|
+
if (isInitialLoadRef.current) {
|
|
3299
|
+
if (lastSavedContent.current === null) {
|
|
3300
|
+
lastSavedContent.current = currentSbx;
|
|
3301
|
+
}
|
|
3302
|
+
isInitialLoadRef.current = false;
|
|
3303
|
+
return;
|
|
3304
|
+
}
|
|
3305
|
+
const hasActualChanges = lastSavedContent.current !== null && currentSbx !== lastSavedContent.current;
|
|
3306
|
+
if (hasActualChanges) {
|
|
3307
|
+
setHasUnsavedChanges(true);
|
|
3308
|
+
if (popoverTimeoutRef.current)
|
|
3309
|
+
clearTimeout(popoverTimeoutRef.current);
|
|
3310
|
+
setShowUnsavedPopover(false);
|
|
3311
|
+
popoverTimeoutRef.current = setTimeout(() => {
|
|
3312
|
+
setShowUnsavedPopover(true);
|
|
3313
|
+
}, 1e3);
|
|
3314
|
+
} else {
|
|
3315
|
+
setHasUnsavedChanges(false);
|
|
3316
|
+
setShowUnsavedPopover(false);
|
|
3317
|
+
if (popoverTimeoutRef.current)
|
|
3318
|
+
clearTimeout(popoverTimeoutRef.current);
|
|
3319
|
+
}
|
|
3320
|
+
};
|
|
3321
|
+
if (typeof window !== "undefined" && "requestIdleCallback" in window) {
|
|
3322
|
+
window.requestIdleCallback(
|
|
3323
|
+
() => {
|
|
3324
|
+
runSerialization();
|
|
3325
|
+
},
|
|
3326
|
+
{ timeout: 1e3 }
|
|
3327
|
+
);
|
|
3328
|
+
} else {
|
|
3329
|
+
runSerialization();
|
|
2935
3330
|
}
|
|
2936
|
-
|
|
2937
|
-
return;
|
|
2938
|
-
}
|
|
2939
|
-
const hasActualChanges = lastSavedContent.current !== null && currentSbx !== lastSavedContent.current;
|
|
2940
|
-
if (hasActualChanges) {
|
|
2941
|
-
setHasUnsavedChanges(true);
|
|
2942
|
-
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2943
|
-
setShowUnsavedPopover(false);
|
|
2944
|
-
popoverTimeoutRef.current = setTimeout(() => {
|
|
2945
|
-
setShowUnsavedPopover(true);
|
|
2946
|
-
}, 1e3);
|
|
2947
|
-
} else {
|
|
2948
|
-
setHasUnsavedChanges(false);
|
|
2949
|
-
setShowUnsavedPopover(false);
|
|
2950
|
-
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2951
|
-
}
|
|
3331
|
+
}, 250);
|
|
2952
3332
|
return () => {
|
|
3333
|
+
clearTimeout(handler);
|
|
2953
3334
|
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
2954
3335
|
};
|
|
2955
3336
|
}, [blocks, isLoading]);
|
|
2956
|
-
|
|
3337
|
+
React4.useEffect(() => {
|
|
2957
3338
|
if ((options == null ? void 0 : options.initialUrl) && options.initialUrl !== loadedUrlRef.current) {
|
|
2958
3339
|
loadedUrlRef.current = options.initialUrl;
|
|
2959
3340
|
loadFromUrl(options.initialUrl, options.fetchOptions, true);
|
|
@@ -3039,7 +3420,9 @@ function useScreenplayEditor(options) {
|
|
|
3039
3420
|
currentLanguage,
|
|
3040
3421
|
setCurrentLanguage,
|
|
3041
3422
|
phoneticSuggestions,
|
|
3042
|
-
handleSelectPhoneticSuggestion
|
|
3423
|
+
handleSelectPhoneticSuggestion,
|
|
3424
|
+
isLocked,
|
|
3425
|
+
autosaveStatus
|
|
3043
3426
|
};
|
|
3044
3427
|
}
|
|
3045
3428
|
|
|
@@ -3324,7 +3707,369 @@ var SummarizeButton = ({
|
|
|
3324
3707
|
}
|
|
3325
3708
|
);
|
|
3326
3709
|
};
|
|
3327
|
-
var summarize_button_default = SummarizeButton;
|
|
3710
|
+
var summarize_button_default = SummarizeButton;
|
|
3711
|
+
|
|
3712
|
+
// data/crowd-data.ts
|
|
3713
|
+
var crowdAgeOption = [
|
|
3714
|
+
{ name: "Adult" },
|
|
3715
|
+
{ name: "Old" },
|
|
3716
|
+
{ name: "Teenage" },
|
|
3717
|
+
{ name: "Kid" }
|
|
3718
|
+
];
|
|
3719
|
+
var crowdTypeOption = [{ name: "Male" }, { name: "Female" }];
|
|
3720
|
+
var FormikSelect = ({
|
|
3721
|
+
label,
|
|
3722
|
+
name,
|
|
3723
|
+
selectedOption,
|
|
3724
|
+
optionData,
|
|
3725
|
+
value,
|
|
3726
|
+
disable,
|
|
3727
|
+
divClasses,
|
|
3728
|
+
valueProperty = "name",
|
|
3729
|
+
labelProperty = "name",
|
|
3730
|
+
label2propery,
|
|
3731
|
+
brackets,
|
|
3732
|
+
className,
|
|
3733
|
+
enableRedAsterick = false,
|
|
3734
|
+
disableOptionProperty = "disable",
|
|
3735
|
+
disabledOptionText = "",
|
|
3736
|
+
onChange
|
|
3737
|
+
}) => {
|
|
3738
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${divClasses}`, children: [
|
|
3739
|
+
label && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3740
|
+
"label",
|
|
3741
|
+
{
|
|
3742
|
+
className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
|
|
3743
|
+
children: [
|
|
3744
|
+
label,
|
|
3745
|
+
enableRedAsterick && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AsteriskIcon, { className: "size-3 text-red-500" })
|
|
3746
|
+
]
|
|
3747
|
+
}
|
|
3748
|
+
),
|
|
3749
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3750
|
+
formik.Field,
|
|
3751
|
+
{
|
|
3752
|
+
name,
|
|
3753
|
+
as: "select",
|
|
3754
|
+
value,
|
|
3755
|
+
disabled: disable,
|
|
3756
|
+
onChange,
|
|
3757
|
+
className: `${className} rounded-[2.5rem] block w-full px-3 py-2.5 text-slate-700 placeholder-slate-400 placeholder:capitalize bg-white border border-slate-300/80 focus:border-blumine-500 focus:ring-2 focus:ring-blumine-500/50 focus:outline-none transition-all`,
|
|
3758
|
+
children: [
|
|
3759
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { selected: true, value: "", disabled: true, className: "capitalize", children: selectedOption }),
|
|
3760
|
+
optionData == null ? void 0 : optionData.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
3761
|
+
"option",
|
|
3762
|
+
{
|
|
3763
|
+
value: option[valueProperty],
|
|
3764
|
+
disabled: option[disableOptionProperty],
|
|
3765
|
+
children: [
|
|
3766
|
+
option[labelProperty],
|
|
3767
|
+
label2propery ? brackets ? ` (${option[label2propery]})` : option[label2propery] : "",
|
|
3768
|
+
" ",
|
|
3769
|
+
option[disableOptionProperty] && `(${disabledOptionText})`
|
|
3770
|
+
]
|
|
3771
|
+
},
|
|
3772
|
+
index
|
|
3773
|
+
))
|
|
3774
|
+
]
|
|
3775
|
+
}
|
|
3776
|
+
),
|
|
3777
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3778
|
+
formik.ErrorMessage,
|
|
3779
|
+
{
|
|
3780
|
+
name,
|
|
3781
|
+
className: "text-red-500 text-sm mt-1",
|
|
3782
|
+
component: "div"
|
|
3783
|
+
}
|
|
3784
|
+
)
|
|
3785
|
+
] });
|
|
3786
|
+
};
|
|
3787
|
+
var FormikInput = (_a) => {
|
|
3788
|
+
var _b = _a, {
|
|
3789
|
+
label,
|
|
3790
|
+
name,
|
|
3791
|
+
type,
|
|
3792
|
+
placeholder,
|
|
3793
|
+
className,
|
|
3794
|
+
labelClassName,
|
|
3795
|
+
readOnly,
|
|
3796
|
+
divClasses,
|
|
3797
|
+
length,
|
|
3798
|
+
disable,
|
|
3799
|
+
min = 0,
|
|
3800
|
+
max,
|
|
3801
|
+
convertToText = false,
|
|
3802
|
+
enableRedAsterick = false,
|
|
3803
|
+
case_sensitivity = "normal"
|
|
3804
|
+
} = _b, props = __objRest(_b, [
|
|
3805
|
+
"label",
|
|
3806
|
+
"name",
|
|
3807
|
+
"type",
|
|
3808
|
+
"placeholder",
|
|
3809
|
+
"className",
|
|
3810
|
+
"labelClassName",
|
|
3811
|
+
"readOnly",
|
|
3812
|
+
"divClasses",
|
|
3813
|
+
"length",
|
|
3814
|
+
"disable",
|
|
3815
|
+
"min",
|
|
3816
|
+
"max",
|
|
3817
|
+
"convertToText",
|
|
3818
|
+
"enableRedAsterick",
|
|
3819
|
+
"case_sensitivity"
|
|
3820
|
+
]);
|
|
3821
|
+
const { setFieldValue } = formik.useFormikContext();
|
|
3822
|
+
const handleCaseChange = (e) => {
|
|
3823
|
+
let value = e.target.value;
|
|
3824
|
+
if (type === "number" && min !== void 0) {
|
|
3825
|
+
if (value !== "" && Number(value) < min) return;
|
|
3826
|
+
}
|
|
3827
|
+
switch (case_sensitivity) {
|
|
3828
|
+
case "lowercase":
|
|
3829
|
+
value = value.toLowerCase();
|
|
3830
|
+
break;
|
|
3831
|
+
case "uppercase":
|
|
3832
|
+
value = value.toUpperCase();
|
|
3833
|
+
break;
|
|
3834
|
+
}
|
|
3835
|
+
setFieldValue(name, value);
|
|
3836
|
+
};
|
|
3837
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${divClasses}`, children: [
|
|
3838
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3839
|
+
"label",
|
|
3840
|
+
{
|
|
3841
|
+
className: `${labelClassName} mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
|
|
3842
|
+
children: [
|
|
3843
|
+
label,
|
|
3844
|
+
enableRedAsterick && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AsteriskIcon, { className: "size-3 text-red-500" })
|
|
3845
|
+
]
|
|
3846
|
+
}
|
|
3847
|
+
),
|
|
3848
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3849
|
+
formik.Field,
|
|
3850
|
+
__spreadProps(__spreadValues({
|
|
3851
|
+
name,
|
|
3852
|
+
placeholder,
|
|
3853
|
+
readOnly,
|
|
3854
|
+
type,
|
|
3855
|
+
maxLength: length,
|
|
3856
|
+
disabled: disable,
|
|
3857
|
+
max,
|
|
3858
|
+
min,
|
|
3859
|
+
onChange: handleCaseChange
|
|
3860
|
+
}, props), {
|
|
3861
|
+
className: `${className} rounded-[2.5rem] block w-full px-3 py-2.5 text-slate-700 placeholder-slate-400 placeholder:capitalize bg-white border border-slate-300/80 focus:border-blumine-500 focus:ring-2 focus:ring-blumine-500/50 focus:outline-none transition-all disabled:opacity-70`
|
|
3862
|
+
})
|
|
3863
|
+
),
|
|
3864
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3865
|
+
formik.ErrorMessage,
|
|
3866
|
+
{
|
|
3867
|
+
name,
|
|
3868
|
+
className: "text-red-500 text-sm mt-1",
|
|
3869
|
+
component: "div"
|
|
3870
|
+
}
|
|
3871
|
+
)
|
|
3872
|
+
] });
|
|
3873
|
+
};
|
|
3874
|
+
var FormikTextarea = ({
|
|
3875
|
+
label,
|
|
3876
|
+
name,
|
|
3877
|
+
placeholder,
|
|
3878
|
+
readOnly,
|
|
3879
|
+
divClasses = "",
|
|
3880
|
+
className = "",
|
|
3881
|
+
length,
|
|
3882
|
+
disable,
|
|
3883
|
+
min,
|
|
3884
|
+
max,
|
|
3885
|
+
enableRedAsterick = false
|
|
3886
|
+
}) => {
|
|
3887
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${divClasses}`, children: [
|
|
3888
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
3889
|
+
"label",
|
|
3890
|
+
{
|
|
3891
|
+
className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
|
|
3892
|
+
children: [
|
|
3893
|
+
label,
|
|
3894
|
+
enableRedAsterick && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AsteriskIcon, { className: "size-3 text-red-500" })
|
|
3895
|
+
]
|
|
3896
|
+
}
|
|
3897
|
+
),
|
|
3898
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3899
|
+
formik.Field,
|
|
3900
|
+
{
|
|
3901
|
+
as: "textarea",
|
|
3902
|
+
name,
|
|
3903
|
+
placeholder,
|
|
3904
|
+
readOnly,
|
|
3905
|
+
maxLength: length,
|
|
3906
|
+
disabled: disable,
|
|
3907
|
+
max,
|
|
3908
|
+
min,
|
|
3909
|
+
className: `${className} block w-full px-4 py-3 text-slate-700 placeholder-slate-400 placeholder:capitalize bg-white border border-slate-300/80 rounded-2xl focus:border-blumine-500 focus:ring-2 focus:ring-blumine-500/50 focus:outline-none transition-all disabled:opacity-70`
|
|
3910
|
+
}
|
|
3911
|
+
),
|
|
3912
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3913
|
+
formik.ErrorMessage,
|
|
3914
|
+
{
|
|
3915
|
+
name,
|
|
3916
|
+
className: "text-red-500 text-sm mt-1",
|
|
3917
|
+
component: "div"
|
|
3918
|
+
}
|
|
3919
|
+
)
|
|
3920
|
+
] });
|
|
3921
|
+
};
|
|
3922
|
+
var Switch = ({
|
|
3923
|
+
isOn,
|
|
3924
|
+
handleToggle,
|
|
3925
|
+
activeColor = "bg-green-500",
|
|
3926
|
+
inactiveColor = "bg-gray-300",
|
|
3927
|
+
size = "medium",
|
|
3928
|
+
onLabel,
|
|
3929
|
+
offLabel,
|
|
3930
|
+
label,
|
|
3931
|
+
divClasses,
|
|
3932
|
+
labelClasses,
|
|
3933
|
+
disable = false
|
|
3934
|
+
}) => {
|
|
3935
|
+
const sizeClasses = {
|
|
3936
|
+
small: { width: 28, height: 18, handle: 12, labelSize: 12, gap: 4 },
|
|
3937
|
+
medium: { width: 48, height: 28, handle: 20, labelSize: 16, gap: 6 },
|
|
3938
|
+
large: { width: 64, height: 36, handle: 28, labelSize: 20, gap: 10 }
|
|
3939
|
+
};
|
|
3940
|
+
const selectedSize = sizeClasses[size] || sizeClasses.medium;
|
|
3941
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${divClasses}`, children: [
|
|
3942
|
+
label && /* @__PURE__ */ jsxRuntime.jsx(
|
|
3943
|
+
"label",
|
|
3944
|
+
{
|
|
3945
|
+
className: `block mb-2 text-sm text-gray-600 ${disable && "text-gray-400!"} ${labelClasses}`,
|
|
3946
|
+
children: label
|
|
3947
|
+
}
|
|
3948
|
+
),
|
|
3949
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { style: { gap: selectedSize.gap }, className: "flex items-center", children: [
|
|
3950
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
3951
|
+
"div",
|
|
3952
|
+
{
|
|
3953
|
+
className: `flex items-center rounded-full cursor-pointer relative ${isOn ? activeColor : inactiveColor} ${disable && "opacity-50 cursor-not-allowed"}`,
|
|
3954
|
+
onClick: disable ? () => {
|
|
3955
|
+
} : handleToggle,
|
|
3956
|
+
role: "button",
|
|
3957
|
+
"aria-pressed": isOn,
|
|
3958
|
+
style: {
|
|
3959
|
+
width: selectedSize.width,
|
|
3960
|
+
height: selectedSize.height
|
|
3961
|
+
},
|
|
3962
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3963
|
+
"div",
|
|
3964
|
+
{
|
|
3965
|
+
className: "bg-white rounded-full shadow-sm ease-in duration-200",
|
|
3966
|
+
style: {
|
|
3967
|
+
width: selectedSize.handle,
|
|
3968
|
+
height: selectedSize.handle,
|
|
3969
|
+
transform: `translateX(${isOn ? selectedSize.width - selectedSize.handle - 3 : 3}px)`,
|
|
3970
|
+
transition: "transform 0.2s ease-in-out"
|
|
3971
|
+
}
|
|
3972
|
+
}
|
|
3973
|
+
)
|
|
3974
|
+
}
|
|
3975
|
+
),
|
|
3976
|
+
onLabel && offLabel && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { fontSize: selectedSize.labelSize }, children: isOn ? onLabel : offLabel })
|
|
3977
|
+
] })
|
|
3978
|
+
] });
|
|
3979
|
+
};
|
|
3980
|
+
var MultiSelect = ({
|
|
3981
|
+
label,
|
|
3982
|
+
options,
|
|
3983
|
+
value,
|
|
3984
|
+
onChange,
|
|
3985
|
+
placeholder = "Select options...",
|
|
3986
|
+
valueProperty = "name",
|
|
3987
|
+
labelProperty = "name",
|
|
3988
|
+
divClasses = "",
|
|
3989
|
+
returnObjects = false
|
|
3990
|
+
}) => {
|
|
3991
|
+
const [isOpen, setIsOpen] = React4__default.default.useState(false);
|
|
3992
|
+
const containerRef = React4__default.default.useRef(null);
|
|
3993
|
+
const isSelected = (optionValue) => {
|
|
3994
|
+
return value.some(
|
|
3995
|
+
(v) => typeof v === "object" && v !== null ? v[valueProperty] === optionValue : v === optionValue
|
|
3996
|
+
);
|
|
3997
|
+
};
|
|
3998
|
+
const toggleOption = (optionValue) => {
|
|
3999
|
+
let newValues;
|
|
4000
|
+
if (isSelected(optionValue)) {
|
|
4001
|
+
newValues = value.filter(
|
|
4002
|
+
(v) => typeof v === "object" && v !== null ? v[valueProperty] !== optionValue : v !== optionValue
|
|
4003
|
+
);
|
|
4004
|
+
} else {
|
|
4005
|
+
const newValue = returnObjects ? options.find((opt) => opt[valueProperty] === optionValue) : optionValue;
|
|
4006
|
+
newValues = [...value, newValue];
|
|
4007
|
+
}
|
|
4008
|
+
onChange(newValues);
|
|
4009
|
+
};
|
|
4010
|
+
const removeOption = (e, optionValue) => {
|
|
4011
|
+
e.stopPropagation();
|
|
4012
|
+
const newValues = value.filter(
|
|
4013
|
+
(v) => typeof v === "object" && v !== null ? v[valueProperty] !== optionValue : v !== optionValue
|
|
4014
|
+
);
|
|
4015
|
+
onChange(newValues);
|
|
4016
|
+
};
|
|
4017
|
+
React4__default.default.useEffect(() => {
|
|
4018
|
+
const handleClickOutside = (event) => {
|
|
4019
|
+
if (containerRef.current && !containerRef.current.contains(event.target)) {
|
|
4020
|
+
setIsOpen(false);
|
|
4021
|
+
}
|
|
4022
|
+
};
|
|
4023
|
+
document.addEventListener("mousedown", handleClickOutside);
|
|
4024
|
+
return () => document.removeEventListener("mousedown", handleClickOutside);
|
|
4025
|
+
}, []);
|
|
4026
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full relative ${divClasses}`, ref: containerRef, children: [
|
|
4027
|
+
label && /* @__PURE__ */ jsxRuntime.jsx("label", { className: "mb-1.5 text-xs font-bold text-slate-600 ml-1 uppercase tracking-wider", children: label }),
|
|
4028
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4029
|
+
"div",
|
|
4030
|
+
{
|
|
4031
|
+
onClick: () => setIsOpen(!isOpen),
|
|
4032
|
+
className: `min-h-[40px] w-full px-3 py-1.5 bg-slate-50/50 border border-slate-200/80 rounded-xl transition-all cursor-pointer flex flex-wrap gap-1.5 items-center ${isOpen ? "border-blumine-500 bg-white shadow-sm ring-2 ring-blumine-500/10" : "hover:border-slate-300"}`,
|
|
4033
|
+
children: value.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-slate-400 text-[13px] ml-1", children: placeholder }) : value.map((val) => {
|
|
4034
|
+
const actualValue = typeof val === "object" && val !== null ? val[valueProperty] : val;
|
|
4035
|
+
const option = options.find(
|
|
4036
|
+
(opt) => opt[valueProperty] === actualValue
|
|
4037
|
+
);
|
|
4038
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4039
|
+
"div",
|
|
4040
|
+
{
|
|
4041
|
+
className: "flex items-center gap-1 bg-white text-slate-700 px-2 py-0.5 rounded-lg border border-slate-200 text-[11px] font-bold shadow-sm animate-in zoom-in-95 duration-150",
|
|
4042
|
+
children: [
|
|
4043
|
+
option ? option[labelProperty] : actualValue,
|
|
4044
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4045
|
+
"button",
|
|
4046
|
+
{
|
|
4047
|
+
type: "button",
|
|
4048
|
+
onClick: (e) => removeOption(e, actualValue),
|
|
4049
|
+
className: "hover:text-red-500 transition-colors ml-0.5",
|
|
4050
|
+
children: "\xD7"
|
|
4051
|
+
}
|
|
4052
|
+
)
|
|
4053
|
+
]
|
|
4054
|
+
},
|
|
4055
|
+
actualValue
|
|
4056
|
+
);
|
|
4057
|
+
})
|
|
4058
|
+
}
|
|
4059
|
+
),
|
|
4060
|
+
isOpen && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "absolute z-[110] w-full mt-1.5 bg-white border border-slate-200 rounded-xl shadow-xl max-h-48 overflow-y-auto animate-in fade-in slide-in-from-top-1 duration-200 custom-scrollbar", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-1", children: options.filter((opt) => !isSelected(opt[valueProperty])).length > 0 ? options.filter((opt) => !isSelected(opt[valueProperty])).map((option, index) => {
|
|
4061
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4062
|
+
"div",
|
|
4063
|
+
{
|
|
4064
|
+
onClick: () => toggleOption(option[valueProperty]),
|
|
4065
|
+
className: "px-3 py-2 text-[12px] rounded-lg cursor-pointer transition-colors flex items-center justify-between text-slate-600 hover:bg-slate-50",
|
|
4066
|
+
children: option[labelProperty]
|
|
4067
|
+
},
|
|
4068
|
+
index
|
|
4069
|
+
);
|
|
4070
|
+
}) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "px-3 py-3 text-[10px] text-slate-400 text-center font-bold uppercase tracking-wider", children: "All selected" }) }) })
|
|
4071
|
+
] });
|
|
4072
|
+
};
|
|
3328
4073
|
function ScriptBreakdownSceneView({
|
|
3329
4074
|
blocks,
|
|
3330
4075
|
characters,
|
|
@@ -3346,16 +4091,16 @@ function ScriptBreakdownSceneView({
|
|
|
3346
4091
|
aiSummarized = false,
|
|
3347
4092
|
onUpdateBrief
|
|
3348
4093
|
}) {
|
|
3349
|
-
const [expandedCategories, setExpandedCategories] =
|
|
3350
|
-
const [editingTagData, setEditingTagData] =
|
|
3351
|
-
const [tagForm, setTagForm] =
|
|
3352
|
-
const [popupPlacement, setPopupPlacement] =
|
|
4094
|
+
const [expandedCategories, setExpandedCategories] = React4.useState({});
|
|
4095
|
+
const [editingTagData, setEditingTagData] = React4.useState(null);
|
|
4096
|
+
const [tagForm, setTagForm] = React4.useState({ quantity: 1, look: "", age: "", age_range: [], crowd_type: [] });
|
|
4097
|
+
const [popupPlacement, setPopupPlacement] = React4.useState({
|
|
3353
4098
|
alignRight: false,
|
|
3354
4099
|
alignBottom: false
|
|
3355
4100
|
});
|
|
3356
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
4101
|
+
const [isSidebarOpen, setIsSidebarOpen] = React4.useState(false);
|
|
3357
4102
|
const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
|
|
3358
|
-
|
|
4103
|
+
React4.useEffect(() => {
|
|
3359
4104
|
const fontId = "google-font-courier-prime";
|
|
3360
4105
|
const styleId = "screenplay-editor-force-v4";
|
|
3361
4106
|
if (!document.getElementById(fontId)) {
|
|
@@ -3709,7 +4454,7 @@ function ScriptBreakdownSceneView({
|
|
|
3709
4454
|
title: tag.name,
|
|
3710
4455
|
onClick: (e) => {
|
|
3711
4456
|
e.stopPropagation();
|
|
3712
|
-
if (cat.id !== "PROP" && cat.id !== "SET_PROP" && cat.id !== "CAST")
|
|
4457
|
+
if (cat.id !== "PROP" && cat.id !== "SET_PROP" && cat.id !== "CAST" && cat.id !== "EXTRA")
|
|
3713
4458
|
return;
|
|
3714
4459
|
if ((editingTagData == null ? void 0 : editingTagData.tag.id) === tag.id) {
|
|
3715
4460
|
setEditingTagData(null);
|
|
@@ -3722,7 +4467,9 @@ function ScriptBreakdownSceneView({
|
|
|
3722
4467
|
setTagForm({
|
|
3723
4468
|
quantity: tag.quantity || 1,
|
|
3724
4469
|
look: tag.look || "",
|
|
3725
|
-
age: tag.age || ""
|
|
4470
|
+
age: tag.age || "",
|
|
4471
|
+
age_range: tag.age_range || [],
|
|
4472
|
+
crowd_type: tag.crowd_type || []
|
|
3726
4473
|
});
|
|
3727
4474
|
setEditingTagData({
|
|
3728
4475
|
tag,
|
|
@@ -3732,7 +4479,7 @@ function ScriptBreakdownSceneView({
|
|
|
3732
4479
|
});
|
|
3733
4480
|
}
|
|
3734
4481
|
},
|
|
3735
|
-
className: `inline-block max-w-full truncate text-[11px] font-semibold px-3 py-1.5 rounded-full border backdrop-blur-md transition-all duration-300 ${cat.id === "PROP" || cat.id === "SET_PROP" || cat.id === "CAST" ? "cursor-pointer hover:scale-105 shadow-sm" : ""}`,
|
|
4482
|
+
className: `inline-block max-w-full truncate text-[11px] font-semibold px-3 py-1.5 rounded-full border backdrop-blur-md transition-all duration-300 cursor-pointer! ${cat.id === "PROP" || cat.id === "SET_PROP" || cat.id === "CAST" ? "cursor-pointer hover:scale-105 shadow-sm" : ""}`,
|
|
3736
4483
|
style: {
|
|
3737
4484
|
color: cat.color,
|
|
3738
4485
|
background: `linear-gradient(145deg, ${cat.color}18, rgba(255,255,255,0.88))`,
|
|
@@ -3856,13 +4603,38 @@ function ScriptBreakdownSceneView({
|
|
|
3856
4603
|
)
|
|
3857
4604
|
] })
|
|
3858
4605
|
] }),
|
|
4606
|
+
editingTagData.catId === "EXTRA" && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-3", children: [
|
|
4607
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4608
|
+
MultiSelect,
|
|
4609
|
+
{
|
|
4610
|
+
label: "Age Range",
|
|
4611
|
+
options: crowdAgeOption,
|
|
4612
|
+
value: tagForm.age_range,
|
|
4613
|
+
returnObjects: true,
|
|
4614
|
+
onChange: (val) => setTagForm((prev) => __spreadProps(__spreadValues({}, prev), { age_range: val }))
|
|
4615
|
+
}
|
|
4616
|
+
),
|
|
4617
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4618
|
+
MultiSelect,
|
|
4619
|
+
{
|
|
4620
|
+
label: "Crowd Type",
|
|
4621
|
+
options: crowdTypeOption,
|
|
4622
|
+
value: tagForm.crowd_type,
|
|
4623
|
+
returnObjects: true,
|
|
4624
|
+
onChange: (val) => setTagForm((prev) => __spreadProps(__spreadValues({}, prev), { crowd_type: val }))
|
|
4625
|
+
}
|
|
4626
|
+
)
|
|
4627
|
+
] }),
|
|
3859
4628
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
3860
4629
|
"button",
|
|
3861
4630
|
{
|
|
3862
4631
|
onClick: (e) => {
|
|
3863
4632
|
e.stopPropagation();
|
|
3864
4633
|
if (editingTagData.tag.id) {
|
|
3865
|
-
updateTag == null ? void 0 : updateTag(editingTagData.tag.id, editingTagData.catId, __spreadValues(__spreadValues({}, editingTagData.catId === "PROP" || editingTagData.catId === "SET_PROP" ? { quantity: tagForm.quantity } : {}), editingTagData.catId === "CAST" ? { look: tagForm.look, age: tagForm.age } : {})
|
|
4634
|
+
updateTag == null ? void 0 : updateTag(editingTagData.tag.id, editingTagData.catId, __spreadValues(__spreadValues(__spreadValues({}, editingTagData.catId === "PROP" || editingTagData.catId === "SET_PROP" ? { quantity: tagForm.quantity } : {}), editingTagData.catId === "CAST" ? { look: tagForm.look, age: tagForm.age } : {}), editingTagData.catId === "EXTRA" ? {
|
|
4635
|
+
age_range: tagForm.age_range,
|
|
4636
|
+
crowd_type: tagForm.crowd_type
|
|
4637
|
+
} : {}));
|
|
3866
4638
|
}
|
|
3867
4639
|
setEditingTagData(null);
|
|
3868
4640
|
},
|
|
@@ -3877,17 +4649,17 @@ function ScriptBreakdownSceneView({
|
|
|
3877
4649
|
] });
|
|
3878
4650
|
}
|
|
3879
4651
|
function useScriptBreakdownScene(options) {
|
|
3880
|
-
const [tags, setTags] =
|
|
3881
|
-
const [selectionMenu, setSelectionMenu] =
|
|
3882
|
-
const autoTaggedSceneRef =
|
|
3883
|
-
const [scene, setScene] =
|
|
3884
|
-
const [menuPlacement, setMenuPlacement] =
|
|
3885
|
-
const [sceneBrief, setSceneBrief] =
|
|
3886
|
-
const [isSummarizing, setIsSummarizing] =
|
|
3887
|
-
const [isLoading, setIsLoading] =
|
|
3888
|
-
const [error, setError] =
|
|
3889
|
-
const menuRef =
|
|
3890
|
-
|
|
4652
|
+
const [tags, setTags] = React4.useState(options.preLoadedTags || []);
|
|
4653
|
+
const [selectionMenu, setSelectionMenu] = React4.useState(null);
|
|
4654
|
+
const autoTaggedSceneRef = React4.useRef(null);
|
|
4655
|
+
const [scene, setScene] = React4.useState(null);
|
|
4656
|
+
const [menuPlacement, setMenuPlacement] = React4.useState("top");
|
|
4657
|
+
const [sceneBrief, setSceneBrief] = React4.useState("");
|
|
4658
|
+
const [isSummarizing, setIsSummarizing] = React4.useState(false);
|
|
4659
|
+
const [isLoading, setIsLoading] = React4.useState(true);
|
|
4660
|
+
const [error, setError] = React4.useState(false);
|
|
4661
|
+
const menuRef = React4.useRef(null);
|
|
4662
|
+
React4.useEffect(() => {
|
|
3891
4663
|
setIsLoading(true);
|
|
3892
4664
|
const fetchScene = async () => {
|
|
3893
4665
|
try {
|
|
@@ -3908,7 +4680,7 @@ function useScriptBreakdownScene(options) {
|
|
|
3908
4680
|
};
|
|
3909
4681
|
fetchScene();
|
|
3910
4682
|
}, []);
|
|
3911
|
-
const blocks =
|
|
4683
|
+
const blocks = React4.useMemo(() => {
|
|
3912
4684
|
if (!scene || !scene.content) return [];
|
|
3913
4685
|
const parser = new DOMParser();
|
|
3914
4686
|
const doc = parser.parseFromString(scene.content, "text/html");
|
|
@@ -3939,7 +4711,7 @@ function useScriptBreakdownScene(options) {
|
|
|
3939
4711
|
});
|
|
3940
4712
|
return parsedBlocks;
|
|
3941
4713
|
}, [scene]);
|
|
3942
|
-
const characters =
|
|
4714
|
+
const characters = React4.useMemo(() => {
|
|
3943
4715
|
const chars = blocks.filter((b) => b.type === "CHARACTER").map((b) => {
|
|
3944
4716
|
const text = b.text.trim().toUpperCase();
|
|
3945
4717
|
const parenIndex = text.indexOf("(");
|
|
@@ -4017,7 +4789,7 @@ function useScriptBreakdownScene(options) {
|
|
|
4017
4789
|
console.error("Failed to summarize scene:", res);
|
|
4018
4790
|
}
|
|
4019
4791
|
};
|
|
4020
|
-
const bulkCreateTags =
|
|
4792
|
+
const bulkCreateTags = React4.useCallback(async () => {
|
|
4021
4793
|
if (blocks.length === 0) return;
|
|
4022
4794
|
const newTags = [];
|
|
4023
4795
|
const seenCharacters = /* @__PURE__ */ new Set();
|
|
@@ -4125,11 +4897,11 @@ function useScriptBreakdownScene(options) {
|
|
|
4125
4897
|
}
|
|
4126
4898
|
}
|
|
4127
4899
|
}, [blocks, tags, options.onTagsBulkAdded]);
|
|
4128
|
-
|
|
4900
|
+
React4.useEffect(() => {
|
|
4129
4901
|
setSceneBrief("");
|
|
4130
4902
|
autoTaggedSceneRef.current = null;
|
|
4131
4903
|
}, [options.scene_url]);
|
|
4132
|
-
|
|
4904
|
+
React4.useEffect(() => {
|
|
4133
4905
|
if (options.preLoadedTags && options.preLoadedTags.length > 0) {
|
|
4134
4906
|
setTags((prev) => {
|
|
4135
4907
|
if (JSON.stringify(prev) === JSON.stringify(options.preLoadedTags)) {
|
|
@@ -4139,7 +4911,7 @@ function useScriptBreakdownScene(options) {
|
|
|
4139
4911
|
});
|
|
4140
4912
|
}
|
|
4141
4913
|
}, [options.preLoadedTags]);
|
|
4142
|
-
|
|
4914
|
+
React4.useEffect(() => {
|
|
4143
4915
|
const doBulkCreate = async () => {
|
|
4144
4916
|
if (blocks.length === 0) return;
|
|
4145
4917
|
if (options.preLoadedTagsLoading) return;
|
|
@@ -4156,17 +4928,17 @@ function useScriptBreakdownScene(options) {
|
|
|
4156
4928
|
options.preLoadedTags,
|
|
4157
4929
|
options.preLoadedTagsLoading
|
|
4158
4930
|
]);
|
|
4159
|
-
const clearSelection =
|
|
4931
|
+
const clearSelection = React4.useCallback(() => {
|
|
4160
4932
|
var _a;
|
|
4161
4933
|
setSelectionMenu(null);
|
|
4162
4934
|
(_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
|
|
4163
4935
|
}, []);
|
|
4164
|
-
|
|
4936
|
+
React4.useEffect(() => {
|
|
4165
4937
|
if (!selectionMenu) {
|
|
4166
4938
|
setMenuPlacement("top");
|
|
4167
4939
|
}
|
|
4168
4940
|
}, [selectionMenu]);
|
|
4169
|
-
|
|
4941
|
+
React4.useEffect(() => {
|
|
4170
4942
|
if (selectionMenu && menuRef.current) {
|
|
4171
4943
|
const rect = menuRef.current.getBoundingClientRect();
|
|
4172
4944
|
if (menuPlacement === "top" && rect.top < 100) {
|
|
@@ -4176,7 +4948,7 @@ function useScriptBreakdownScene(options) {
|
|
|
4176
4948
|
}
|
|
4177
4949
|
}
|
|
4178
4950
|
}, [selectionMenu, menuPlacement]);
|
|
4179
|
-
|
|
4951
|
+
React4.useEffect(() => {
|
|
4180
4952
|
const handleClickOutside = (e) => {
|
|
4181
4953
|
if (selectionMenu && !e.target.closest(".tag-menu")) {
|
|
4182
4954
|
clearSelection();
|
|
@@ -4347,7 +5119,7 @@ function ModalLayout({
|
|
|
4347
5119
|
maxWidth = "max-w-4xl",
|
|
4348
5120
|
menuRef
|
|
4349
5121
|
}) {
|
|
4350
|
-
|
|
5122
|
+
React4.useEffect(() => {
|
|
4351
5123
|
document.body.style.overflow = "hidden";
|
|
4352
5124
|
return () => {
|
|
4353
5125
|
document.body.style.overflow = "";
|
|
@@ -4403,196 +5175,6 @@ function ModalLayout({
|
|
|
4403
5175
|
);
|
|
4404
5176
|
}
|
|
4405
5177
|
var modal_layout_default = ModalLayout;
|
|
4406
|
-
var FormikSelect = ({
|
|
4407
|
-
label,
|
|
4408
|
-
name,
|
|
4409
|
-
selectedOption,
|
|
4410
|
-
optionData,
|
|
4411
|
-
value,
|
|
4412
|
-
disable,
|
|
4413
|
-
divClasses,
|
|
4414
|
-
valueProperty = "name",
|
|
4415
|
-
labelProperty = "name",
|
|
4416
|
-
label2propery,
|
|
4417
|
-
brackets,
|
|
4418
|
-
className,
|
|
4419
|
-
enableRedAsterick = false,
|
|
4420
|
-
disableOptionProperty = "disable",
|
|
4421
|
-
disabledOptionText = "",
|
|
4422
|
-
onChange
|
|
4423
|
-
}) => {
|
|
4424
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${divClasses}`, children: [
|
|
4425
|
-
label && /* @__PURE__ */ jsxRuntime.jsxs("label", { className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`, children: [
|
|
4426
|
-
label,
|
|
4427
|
-
enableRedAsterick && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AsteriskIcon, { className: "size-3 text-red-500" })
|
|
4428
|
-
] }),
|
|
4429
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4430
|
-
formik.Field,
|
|
4431
|
-
{
|
|
4432
|
-
name,
|
|
4433
|
-
as: "select",
|
|
4434
|
-
value,
|
|
4435
|
-
disabled: disable,
|
|
4436
|
-
onChange,
|
|
4437
|
-
className: `${className} rounded-[2.5rem] block w-full px-3 py-2.5 text-slate-700 placeholder-slate-400 placeholder:capitalize bg-white border border-slate-300/80 focus:border-blumine-500 focus:ring-2 focus:ring-blumine-500/50 focus:outline-none transition-all`,
|
|
4438
|
-
children: [
|
|
4439
|
-
/* @__PURE__ */ jsxRuntime.jsx("option", { selected: true, value: "", disabled: true, className: "capitalize", children: selectedOption }),
|
|
4440
|
-
optionData == null ? void 0 : optionData.map((option, index) => /* @__PURE__ */ jsxRuntime.jsxs(
|
|
4441
|
-
"option",
|
|
4442
|
-
{
|
|
4443
|
-
value: option[valueProperty],
|
|
4444
|
-
disabled: option[disableOptionProperty],
|
|
4445
|
-
children: [
|
|
4446
|
-
option[labelProperty],
|
|
4447
|
-
label2propery ? brackets ? ` (${option[label2propery]})` : option[label2propery] : "",
|
|
4448
|
-
" ",
|
|
4449
|
-
option[disableOptionProperty] && `(${disabledOptionText})`
|
|
4450
|
-
]
|
|
4451
|
-
},
|
|
4452
|
-
index
|
|
4453
|
-
))
|
|
4454
|
-
]
|
|
4455
|
-
}
|
|
4456
|
-
),
|
|
4457
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4458
|
-
formik.ErrorMessage,
|
|
4459
|
-
{
|
|
4460
|
-
name,
|
|
4461
|
-
className: "text-red-500 text-sm mt-1",
|
|
4462
|
-
component: "div"
|
|
4463
|
-
}
|
|
4464
|
-
)
|
|
4465
|
-
] });
|
|
4466
|
-
};
|
|
4467
|
-
var FormikInput = (_a) => {
|
|
4468
|
-
var _b = _a, {
|
|
4469
|
-
label,
|
|
4470
|
-
name,
|
|
4471
|
-
type,
|
|
4472
|
-
placeholder,
|
|
4473
|
-
className,
|
|
4474
|
-
labelClassName,
|
|
4475
|
-
readOnly,
|
|
4476
|
-
divClasses,
|
|
4477
|
-
length,
|
|
4478
|
-
disable,
|
|
4479
|
-
min = 0,
|
|
4480
|
-
max,
|
|
4481
|
-
convertToText = false,
|
|
4482
|
-
enableRedAsterick = false,
|
|
4483
|
-
case_sensitivity = "normal"
|
|
4484
|
-
} = _b, props = __objRest(_b, [
|
|
4485
|
-
"label",
|
|
4486
|
-
"name",
|
|
4487
|
-
"type",
|
|
4488
|
-
"placeholder",
|
|
4489
|
-
"className",
|
|
4490
|
-
"labelClassName",
|
|
4491
|
-
"readOnly",
|
|
4492
|
-
"divClasses",
|
|
4493
|
-
"length",
|
|
4494
|
-
"disable",
|
|
4495
|
-
"min",
|
|
4496
|
-
"max",
|
|
4497
|
-
"convertToText",
|
|
4498
|
-
"enableRedAsterick",
|
|
4499
|
-
"case_sensitivity"
|
|
4500
|
-
]);
|
|
4501
|
-
const { setFieldValue } = formik.useFormikContext();
|
|
4502
|
-
const handleCaseChange = (e) => {
|
|
4503
|
-
let value = e.target.value;
|
|
4504
|
-
if (type === "number" && min !== void 0) {
|
|
4505
|
-
if (value !== "" && Number(value) < min) return;
|
|
4506
|
-
}
|
|
4507
|
-
switch (case_sensitivity) {
|
|
4508
|
-
case "lowercase":
|
|
4509
|
-
value = value.toLowerCase();
|
|
4510
|
-
break;
|
|
4511
|
-
case "uppercase":
|
|
4512
|
-
value = value.toUpperCase();
|
|
4513
|
-
break;
|
|
4514
|
-
}
|
|
4515
|
-
setFieldValue(name, value);
|
|
4516
|
-
};
|
|
4517
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${divClasses}`, children: [
|
|
4518
|
-
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
4519
|
-
"label",
|
|
4520
|
-
{
|
|
4521
|
-
className: `${labelClassName} mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
|
|
4522
|
-
children: [
|
|
4523
|
-
label,
|
|
4524
|
-
enableRedAsterick && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AsteriskIcon, { className: "size-3 text-red-500" })
|
|
4525
|
-
]
|
|
4526
|
-
}
|
|
4527
|
-
),
|
|
4528
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4529
|
-
formik.Field,
|
|
4530
|
-
__spreadProps(__spreadValues({
|
|
4531
|
-
name,
|
|
4532
|
-
placeholder,
|
|
4533
|
-
readOnly,
|
|
4534
|
-
type,
|
|
4535
|
-
maxLength: length,
|
|
4536
|
-
disabled: disable,
|
|
4537
|
-
max,
|
|
4538
|
-
min,
|
|
4539
|
-
onChange: handleCaseChange
|
|
4540
|
-
}, props), {
|
|
4541
|
-
className: `${className} rounded-[2.5rem] block w-full px-3 py-2.5 text-slate-700 placeholder-slate-400 placeholder:capitalize bg-white border border-slate-300/80 focus:border-blumine-500 focus:ring-2 focus:ring-blumine-500/50 focus:outline-none transition-all disabled:opacity-70`
|
|
4542
|
-
})
|
|
4543
|
-
),
|
|
4544
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4545
|
-
formik.ErrorMessage,
|
|
4546
|
-
{
|
|
4547
|
-
name,
|
|
4548
|
-
className: "text-red-500 text-sm mt-1",
|
|
4549
|
-
component: "div"
|
|
4550
|
-
}
|
|
4551
|
-
)
|
|
4552
|
-
] });
|
|
4553
|
-
};
|
|
4554
|
-
var FormikTextarea = ({
|
|
4555
|
-
label,
|
|
4556
|
-
name,
|
|
4557
|
-
placeholder,
|
|
4558
|
-
readOnly,
|
|
4559
|
-
divClasses = "",
|
|
4560
|
-
className = "",
|
|
4561
|
-
length,
|
|
4562
|
-
disable,
|
|
4563
|
-
min,
|
|
4564
|
-
max,
|
|
4565
|
-
enableRedAsterick = false
|
|
4566
|
-
}) => {
|
|
4567
|
-
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: `w-full ${divClasses}`, children: [
|
|
4568
|
-
/* @__PURE__ */ jsxRuntime.jsxs("label", { className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`, children: [
|
|
4569
|
-
label,
|
|
4570
|
-
enableRedAsterick && /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AsteriskIcon, { className: "size-3 text-red-500" })
|
|
4571
|
-
] }),
|
|
4572
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4573
|
-
formik.Field,
|
|
4574
|
-
{
|
|
4575
|
-
as: "textarea",
|
|
4576
|
-
name,
|
|
4577
|
-
placeholder,
|
|
4578
|
-
readOnly,
|
|
4579
|
-
maxLength: length,
|
|
4580
|
-
disabled: disable,
|
|
4581
|
-
max,
|
|
4582
|
-
min,
|
|
4583
|
-
className: `${className} block w-full px-4 py-3 text-slate-700 placeholder-slate-400 placeholder:capitalize bg-white border border-slate-300/80 rounded-2xl focus:border-blumine-500 focus:ring-2 focus:ring-blumine-500/50 focus:outline-none transition-all disabled:opacity-70`
|
|
4584
|
-
}
|
|
4585
|
-
),
|
|
4586
|
-
/* @__PURE__ */ jsxRuntime.jsx(
|
|
4587
|
-
formik.ErrorMessage,
|
|
4588
|
-
{
|
|
4589
|
-
name,
|
|
4590
|
-
className: "text-red-500 text-sm mt-1",
|
|
4591
|
-
component: "div"
|
|
4592
|
-
}
|
|
4593
|
-
)
|
|
4594
|
-
] });
|
|
4595
|
-
};
|
|
4596
5178
|
|
|
4597
5179
|
// data/shot-data.ts
|
|
4598
5180
|
var shot_types = [
|
|
@@ -4863,8 +5445,8 @@ var AddShotForm = ({
|
|
|
4863
5445
|
duration_seconds: Yup__namespace.number().min(0).required("Required"),
|
|
4864
5446
|
camera_name: Yup__namespace.string().required("Required")
|
|
4865
5447
|
});
|
|
4866
|
-
const [step, setStep] =
|
|
4867
|
-
const [highestStep, setHighestStep] =
|
|
5448
|
+
const [step, setStep] = React4.useState(1);
|
|
5449
|
+
const [highestStep, setHighestStep] = React4.useState(1);
|
|
4868
5450
|
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
4869
5451
|
formik.Formik,
|
|
4870
5452
|
{
|
|
@@ -5353,22 +5935,32 @@ var ProductionSetupModal = ({
|
|
|
5353
5935
|
initialValues
|
|
5354
5936
|
}) => {
|
|
5355
5937
|
return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "min-h-[80vh] flex items-center justify-center px-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full max-w-lg", children: [
|
|
5356
|
-
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "
|
|
5938
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "my-8 text-center", children: [
|
|
5357
5939
|
/* @__PURE__ */ jsxRuntime.jsx("h1", { className: "text-2xl md:text-3xl font-semibold text-slate-900 tracking-tight", children: "Production Setup for this Scene" }),
|
|
5358
5940
|
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm text-slate-500 mt-2", children: "Configure your scene and camera setup to get started" })
|
|
5359
5941
|
] }),
|
|
5360
5942
|
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-6 md:p-8", children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5361
5943
|
formik.Formik,
|
|
5362
5944
|
{
|
|
5363
|
-
initialValues: initialValues || {
|
|
5945
|
+
initialValues: initialValues || {
|
|
5946
|
+
numCameras: 1,
|
|
5947
|
+
scene_type: "",
|
|
5948
|
+
dance_choreographer_required: false,
|
|
5949
|
+
action_sequence_required: false
|
|
5950
|
+
},
|
|
5364
5951
|
validationSchema: Yup__namespace.object({
|
|
5365
5952
|
numCameras: Yup__namespace.number().min(1, "Must be at least 1").max(20, "Cannot add more than 20 cameras").required("Number of cameras is required"),
|
|
5366
5953
|
scene_type: Yup__namespace.string().required("Scene type is required")
|
|
5367
5954
|
}),
|
|
5368
5955
|
onSubmit: async (values) => {
|
|
5369
|
-
await initializeProduction(
|
|
5956
|
+
await initializeProduction(
|
|
5957
|
+
values.numCameras,
|
|
5958
|
+
values.scene_type,
|
|
5959
|
+
values.dance_choreographer_required,
|
|
5960
|
+
values.action_sequence_required
|
|
5961
|
+
);
|
|
5370
5962
|
},
|
|
5371
|
-
children: ({ isSubmitting, setFieldValue }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { className: "flex flex-col gap-6", children: [
|
|
5963
|
+
children: ({ isSubmitting, setFieldValue, values }) => /* @__PURE__ */ jsxRuntime.jsxs(formik.Form, { className: "flex flex-col gap-6", children: [
|
|
5372
5964
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid gap-5", children: [
|
|
5373
5965
|
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5374
5966
|
FormikSelect,
|
|
@@ -5391,7 +5983,65 @@ var ProductionSetupModal = ({
|
|
|
5391
5983
|
max: 20,
|
|
5392
5984
|
enableRedAsterick: true
|
|
5393
5985
|
}
|
|
5394
|
-
)
|
|
5986
|
+
),
|
|
5987
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
5988
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
5989
|
+
"div",
|
|
5990
|
+
{
|
|
5991
|
+
className: `relative p-5 rounded-3xl border transition-all duration-300 flex flex-col gap-4 group cursor-pointer ${values.dance_choreographer_required ? "bg-blumine-50/30 border-blumine-200 shadow-sm" : "bg-slate-50/50 border-slate-100 hover:border-slate-200"}`,
|
|
5992
|
+
onClick: () => setFieldValue(
|
|
5993
|
+
"dance_choreographer_required",
|
|
5994
|
+
!values.dance_choreographer_required
|
|
5995
|
+
),
|
|
5996
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between w-full", children: [
|
|
5997
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
5998
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[15px] font-bold text-slate-800", children: "Dance Sequence" }),
|
|
5999
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-slate-500 font-medium mt-0.5", children: "Choreography needed" })
|
|
6000
|
+
] }),
|
|
6001
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6002
|
+
Switch,
|
|
6003
|
+
{
|
|
6004
|
+
isOn: values.dance_choreographer_required || false,
|
|
6005
|
+
handleToggle: () => setFieldValue(
|
|
6006
|
+
"dance_choreographer_required",
|
|
6007
|
+
!values.dance_choreographer_required
|
|
6008
|
+
),
|
|
6009
|
+
activeColor: "bg-blumine-600",
|
|
6010
|
+
divClasses: "w-fit!"
|
|
6011
|
+
}
|
|
6012
|
+
)
|
|
6013
|
+
] })
|
|
6014
|
+
}
|
|
6015
|
+
),
|
|
6016
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6017
|
+
"div",
|
|
6018
|
+
{
|
|
6019
|
+
className: `relative p-5 rounded-3xl border transition-all duration-300 flex flex-col gap-4 group cursor-pointer ${values.action_sequence_required ? "bg-rose-50/30 border-rose-200 shadow-sm" : "bg-slate-50/50 border-slate-100 hover:border-slate-200"}`,
|
|
6020
|
+
onClick: () => setFieldValue(
|
|
6021
|
+
"action_sequence_required",
|
|
6022
|
+
!values.action_sequence_required
|
|
6023
|
+
),
|
|
6024
|
+
children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center justify-between w-full", children: [
|
|
6025
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
|
|
6026
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[15px] font-bold text-slate-800", children: "Action Sequence" }),
|
|
6027
|
+
/* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[11px] text-slate-500 font-medium mt-0.5", children: "Stunt & combat logic" })
|
|
6028
|
+
] }),
|
|
6029
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
6030
|
+
Switch,
|
|
6031
|
+
{
|
|
6032
|
+
isOn: values.action_sequence_required || false,
|
|
6033
|
+
handleToggle: () => setFieldValue(
|
|
6034
|
+
"action_sequence_required",
|
|
6035
|
+
!values.action_sequence_required
|
|
6036
|
+
),
|
|
6037
|
+
activeColor: "bg-rose-500",
|
|
6038
|
+
divClasses: "w-fit!"
|
|
6039
|
+
}
|
|
6040
|
+
)
|
|
6041
|
+
] })
|
|
6042
|
+
}
|
|
6043
|
+
)
|
|
6044
|
+
] })
|
|
5395
6045
|
] }),
|
|
5396
6046
|
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-3 bg-slate-50 border border-slate-100 p-4 rounded-xl", children: [
|
|
5397
6047
|
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.Info, { className: "w-5 h-5 text-slate-400 shrink-0 mt-0.5" }),
|
|
@@ -5625,18 +6275,18 @@ function ShotBreakdownView({
|
|
|
5625
6275
|
}) {
|
|
5626
6276
|
var _a, _b, _c;
|
|
5627
6277
|
const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
|
|
5628
|
-
const containerRef =
|
|
5629
|
-
const [isSidebarOpen, setIsSidebarOpen] =
|
|
5630
|
-
const [toggledShotId, setToggledShotId] =
|
|
6278
|
+
const containerRef = React4.useRef(null);
|
|
6279
|
+
const [isSidebarOpen, setIsSidebarOpen] = React4.useState(false);
|
|
6280
|
+
const [toggledShotId, setToggledShotId] = React4.useState(
|
|
5631
6281
|
null
|
|
5632
6282
|
);
|
|
5633
|
-
const [viewingShotId, setViewingShotId] =
|
|
6283
|
+
const [viewingShotId, setViewingShotId] = React4.useState(
|
|
5634
6284
|
null
|
|
5635
6285
|
);
|
|
5636
|
-
const [updatingShotId, setUpdatingShotId] =
|
|
6286
|
+
const [updatingShotId, setUpdatingShotId] = React4.useState(
|
|
5637
6287
|
null
|
|
5638
6288
|
);
|
|
5639
|
-
const [isInitModalOpen, setIsInitModalOpen] =
|
|
6289
|
+
const [isInitModalOpen, setIsInitModalOpen] = React4.useState(false);
|
|
5640
6290
|
const handleCloseModal = () => {
|
|
5641
6291
|
clearSelection();
|
|
5642
6292
|
};
|
|
@@ -5687,7 +6337,7 @@ function ShotBreakdownView({
|
|
|
5687
6337
|
}
|
|
5688
6338
|
return nodes;
|
|
5689
6339
|
};
|
|
5690
|
-
|
|
6340
|
+
React4.useEffect(() => {
|
|
5691
6341
|
const fontId = "google-font-courier-prime";
|
|
5692
6342
|
const styleId = "screenplay-editor-force-v4";
|
|
5693
6343
|
if (!document.getElementById(fontId)) {
|
|
@@ -5933,14 +6583,21 @@ function ShotBreakdownView({
|
|
|
5933
6583
|
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
5934
6584
|
production_setup_modal_default,
|
|
5935
6585
|
{
|
|
5936
|
-
initializeProduction: (count, type) => {
|
|
5937
|
-
initializeProduction(
|
|
6586
|
+
initializeProduction: (count, type, dance_choreographer_required, action_sequence_required) => {
|
|
6587
|
+
initializeProduction(
|
|
6588
|
+
count,
|
|
6589
|
+
type,
|
|
6590
|
+
dance_choreographer_required,
|
|
6591
|
+
action_sequence_required
|
|
6592
|
+
).then(() => {
|
|
5938
6593
|
setIsInitModalOpen(false);
|
|
5939
6594
|
});
|
|
5940
6595
|
},
|
|
5941
6596
|
initialValues: {
|
|
5942
6597
|
numCameras: cameras.length || 1,
|
|
5943
|
-
scene_type: sceneType
|
|
6598
|
+
scene_type: sceneType,
|
|
6599
|
+
dance_choreographer_required: false,
|
|
6600
|
+
action_sequence_required: false
|
|
5944
6601
|
}
|
|
5945
6602
|
}
|
|
5946
6603
|
)
|
|
@@ -5983,20 +6640,20 @@ function ShotBreakdownView({
|
|
|
5983
6640
|
);
|
|
5984
6641
|
}
|
|
5985
6642
|
function useShotBreakdownScene(options) {
|
|
5986
|
-
const [shots, setShots] =
|
|
5987
|
-
const [cameras, setCameras] =
|
|
6643
|
+
const [shots, setShots] = React4.useState(options.preloadedShots || []);
|
|
6644
|
+
const [cameras, setCameras] = React4.useState(
|
|
5988
6645
|
options.preloadedCameras || []
|
|
5989
6646
|
);
|
|
5990
|
-
const [sceneType, setSceneType] =
|
|
6647
|
+
const [sceneType, setSceneType] = React4.useState(
|
|
5991
6648
|
options.preloadedSceneType || ""
|
|
5992
6649
|
);
|
|
5993
|
-
const [scene, setScene] =
|
|
5994
|
-
const [isLoading, setIsLoading] =
|
|
5995
|
-
const [isSummarizing, setIsSummarizing] =
|
|
5996
|
-
const [error, setError] =
|
|
5997
|
-
const [selectionMenu, setSelectionMenu] =
|
|
5998
|
-
const menuRef =
|
|
5999
|
-
|
|
6650
|
+
const [scene, setScene] = React4.useState(null);
|
|
6651
|
+
const [isLoading, setIsLoading] = React4.useState(true);
|
|
6652
|
+
const [isSummarizing, setIsSummarizing] = React4.useState(false);
|
|
6653
|
+
const [error, setError] = React4.useState(false);
|
|
6654
|
+
const [selectionMenu, setSelectionMenu] = React4.useState(null);
|
|
6655
|
+
const menuRef = React4.useRef(null);
|
|
6656
|
+
React4.useEffect(() => {
|
|
6000
6657
|
if (options.preloadedShots && options.preloadedShots.length > 0) {
|
|
6001
6658
|
setShots((prev) => {
|
|
6002
6659
|
if (JSON.stringify(prev) === JSON.stringify(options.preloadedShots)) {
|
|
@@ -6006,7 +6663,7 @@ function useShotBreakdownScene(options) {
|
|
|
6006
6663
|
});
|
|
6007
6664
|
}
|
|
6008
6665
|
}, [options.preloadedShots]);
|
|
6009
|
-
|
|
6666
|
+
React4.useEffect(() => {
|
|
6010
6667
|
if (options.preloadedCameras && options.preloadedCameras.length > 0) {
|
|
6011
6668
|
setCameras((prev) => {
|
|
6012
6669
|
if (JSON.stringify(prev) === JSON.stringify(options.preloadedCameras)) {
|
|
@@ -6016,7 +6673,7 @@ function useShotBreakdownScene(options) {
|
|
|
6016
6673
|
});
|
|
6017
6674
|
}
|
|
6018
6675
|
}, [options.preloadedCameras]);
|
|
6019
|
-
|
|
6676
|
+
React4.useEffect(() => {
|
|
6020
6677
|
if (options.preloadedSceneType) {
|
|
6021
6678
|
setSceneType((prev) => {
|
|
6022
6679
|
if (prev === options.preloadedSceneType) return prev;
|
|
@@ -6024,7 +6681,7 @@ function useShotBreakdownScene(options) {
|
|
|
6024
6681
|
});
|
|
6025
6682
|
}
|
|
6026
6683
|
}, [options.preloadedSceneType]);
|
|
6027
|
-
|
|
6684
|
+
React4.useEffect(() => {
|
|
6028
6685
|
setIsLoading(true);
|
|
6029
6686
|
const fetchScene = async () => {
|
|
6030
6687
|
try {
|
|
@@ -6045,7 +6702,7 @@ function useShotBreakdownScene(options) {
|
|
|
6045
6702
|
};
|
|
6046
6703
|
fetchScene();
|
|
6047
6704
|
}, []);
|
|
6048
|
-
const blocks =
|
|
6705
|
+
const blocks = React4.useMemo(() => {
|
|
6049
6706
|
if (!scene || !scene.content) return [];
|
|
6050
6707
|
const parser = new DOMParser();
|
|
6051
6708
|
const doc = parser.parseFromString(scene.content, "text/html");
|
|
@@ -6081,7 +6738,7 @@ function useShotBreakdownScene(options) {
|
|
|
6081
6738
|
setSelectionMenu(null);
|
|
6082
6739
|
(_a = window.getSelection()) == null ? void 0 : _a.removeAllRanges();
|
|
6083
6740
|
};
|
|
6084
|
-
|
|
6741
|
+
React4.useEffect(() => {
|
|
6085
6742
|
const handleClickOutside = (e) => {
|
|
6086
6743
|
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
6087
6744
|
clearSelection();
|
|
@@ -6156,13 +6813,19 @@ function useShotBreakdownScene(options) {
|
|
|
6156
6813
|
});
|
|
6157
6814
|
}
|
|
6158
6815
|
};
|
|
6159
|
-
const initializeProduction = async (count, type) => {
|
|
6816
|
+
const initializeProduction = async (count, type, dance_choreographer_required, action_sequence_required) => {
|
|
6160
6817
|
var _a;
|
|
6161
6818
|
const newCameras = [];
|
|
6162
6819
|
for (let i = 1; i <= count; i++) {
|
|
6163
6820
|
newCameras.push({ name: `Camera ${String.fromCharCode(64 + i)}` });
|
|
6164
6821
|
}
|
|
6165
|
-
const result = (_a = options.onProductionInitialized) == null ? void 0 : _a.call(
|
|
6822
|
+
const result = (_a = options.onProductionInitialized) == null ? void 0 : _a.call(
|
|
6823
|
+
options,
|
|
6824
|
+
newCameras,
|
|
6825
|
+
type,
|
|
6826
|
+
dance_choreographer_required,
|
|
6827
|
+
action_sequence_required
|
|
6828
|
+
);
|
|
6166
6829
|
if (result instanceof Promise) {
|
|
6167
6830
|
setCameras(newCameras);
|
|
6168
6831
|
setSceneType(type);
|
|
@@ -6293,7 +6956,7 @@ function SceneScriptView({
|
|
|
6293
6956
|
title
|
|
6294
6957
|
}) {
|
|
6295
6958
|
const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
|
|
6296
|
-
|
|
6959
|
+
React4.useEffect(() => {
|
|
6297
6960
|
const fontId = "google-font-courier-prime";
|
|
6298
6961
|
const styleId = "screenplay-editor-force-v4";
|
|
6299
6962
|
if (!document.getElementById(fontId)) {
|
|
@@ -6359,10 +7022,10 @@ function SceneScriptView({
|
|
|
6359
7022
|
);
|
|
6360
7023
|
}
|
|
6361
7024
|
function useSceneScript(options) {
|
|
6362
|
-
const [sceneContent, setSceneContent] =
|
|
6363
|
-
const [isLoading, setIsLoading] =
|
|
6364
|
-
const [error, setError] =
|
|
6365
|
-
|
|
7025
|
+
const [sceneContent, setSceneContent] = React4.useState(null);
|
|
7026
|
+
const [isLoading, setIsLoading] = React4.useState(true);
|
|
7027
|
+
const [error, setError] = React4.useState(null);
|
|
7028
|
+
React4.useEffect(() => {
|
|
6366
7029
|
let isMounted = true;
|
|
6367
7030
|
setIsLoading(true);
|
|
6368
7031
|
setError(null);
|
|
@@ -6394,7 +7057,7 @@ function useSceneScript(options) {
|
|
|
6394
7057
|
isMounted = false;
|
|
6395
7058
|
};
|
|
6396
7059
|
}, [options.scene_url]);
|
|
6397
|
-
const blocks =
|
|
7060
|
+
const blocks = React4.useMemo(() => {
|
|
6398
7061
|
if (!sceneContent) return [];
|
|
6399
7062
|
const parser = new DOMParser();
|
|
6400
7063
|
const doc = parser.parseFromString(sceneContent, "text/html");
|