@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.js CHANGED
@@ -1,11 +1,11 @@
1
- import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
2
- import { Users, Box, Shirt, Car, Armchair, UserPlus, MapPin, Map as Map$1, CornerDownRight, MessageSquareText, Parentheses, User, AlignLeft, Type, Loader2, Upload, Lock, Unlock, Save, FileDown, RefreshCcw, Cog, Languages, Check, Keyboard, ArrowRight, ChevronRight, Sparkles, Tags, ChevronDown, X, Video, Settings2, Eye, Pencil, BookOpen, Search, Zap, Info, Frame, BookText, AsteriskIcon, Target, Activity, MonitorPlay, Crosshair, Clock, Camera, Aperture, SlidersHorizontal, Sun, Wand2, Volume2, Layers } from 'lucide-react';
1
+ import React4, { useState, useRef, useEffect, useMemo, useCallback } from 'react';
2
+ import { ArrowRight, User, ChevronRight, Sparkles, Check, Users, Box, Shirt, Car, Armchair, UserPlus, MapPin, Map as Map$1, MessageCircle, Parentheses, Clapperboard, Mountain, Loader2, Save, Lock, Unlock, Cog, Upload, FileDown, Languages, Keyboard, AlignLeft, Tags, ChevronDown, X, Video, Settings2, Eye, Pencil, BookOpen, Search, Zap, Info, Frame, BookText, AsteriskIcon, Target, Activity, MonitorPlay, Crosshair, Clock, Camera, Aperture, SlidersHorizontal, Sun, Wand2, Volume2, Layers } from 'lucide-react';
3
3
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
4
4
  import * as pdfjs from 'pdfjs-dist';
5
5
  import jsPDF from 'jspdf';
6
6
  import html2canvas from 'html2canvas-pro';
7
- import * as Yup from 'yup';
8
7
  import { Formik, Form, ErrorMessage, Field, useFormikContext } from 'formik';
8
+ import * as Yup from 'yup';
9
9
 
10
10
  var __defProp = Object.defineProperty;
11
11
  var __defProps = Object.defineProperties;
@@ -49,12 +49,12 @@ var blockTypes = [
49
49
  ];
50
50
  var uuid = () => Math.random().toString(36).slice(2, 9);
51
51
  var icons = {
52
- SCENE_HEADING: /* @__PURE__ */ jsx(Type, { className: "w-5 h-5" }),
53
- ACTION: /* @__PURE__ */ jsx(AlignLeft, { className: "w-5 h-5" }),
54
- CHARACTER: /* @__PURE__ */ jsx(User, { className: "w-5 h-5" }),
55
- PARENTHETICAL: /* @__PURE__ */ jsx(Parentheses, { className: "w-5 h-5" }),
56
- DIALOGUE: /* @__PURE__ */ jsx(MessageSquareText, { className: "w-5 h-5" }),
57
- TRANSITION: /* @__PURE__ */ jsx(CornerDownRight, { className: "w-5 h-5" })
52
+ SCENE_HEADING: /* @__PURE__ */ jsx(Mountain, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
53
+ ACTION: /* @__PURE__ */ jsx(Clapperboard, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
54
+ CHARACTER: /* @__PURE__ */ jsx(User, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
55
+ PARENTHETICAL: /* @__PURE__ */ jsx(Parentheses, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
56
+ DIALOGUE: /* @__PURE__ */ jsx(MessageCircle, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 }),
57
+ TRANSITION: /* @__PURE__ */ jsx(ArrowRight, { className: "w-[18px] h-[18px]", strokeWidth: 1.5 })
58
58
  };
59
59
  var blockStyles = {
60
60
  SCENE_HEADING: {
@@ -789,7 +789,7 @@ function PhoneticSuggestions({
789
789
  ] });
790
790
  }
791
791
  pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
792
- function PdfImporter({ onScriptImported, disabled, children }) {
792
+ function PdfImporter({ onScriptImported, disabled, children, className }) {
793
793
  const [isProcessing, setIsProcessing] = useState(false);
794
794
  const [error, setError] = useState(null);
795
795
  const fileInputRef = useRef(null);
@@ -826,9 +826,9 @@ function PdfImporter({ onScriptImported, disabled, children }) {
826
826
  let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
827
827
  if (!divText) return;
828
828
  let type = "ACTION";
829
- for (const className of Array.from(div.classList)) {
830
- if (typeMap[className]) {
831
- type = typeMap[className];
829
+ for (const className2 of Array.from(div.classList)) {
830
+ if (typeMap[className2]) {
831
+ type = typeMap[className2];
832
832
  break;
833
833
  }
834
834
  }
@@ -932,7 +932,7 @@ function PdfImporter({ onScriptImported, disabled, children }) {
932
932
  {
933
933
  onClick: handleClick,
934
934
  disabled: isProcessing || disabled,
935
- className: `flex items-center justify-center transition-all duration-200 active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 ${isProcessing ? "w-auto px-3 sm:px-4 h-8 sm:h-10 rounded-full text-sm font-semibold bg-zinc-100 text-zinc-500" : "w-8 h-8 sm:w-10 sm:h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
935
+ className: className || `flex items-center justify-center transition-all duration-200 active:scale-95 disabled:cursor-not-allowed disabled:opacity-50 ${isProcessing ? "w-auto px-3 sm:px-4 h-8 sm:h-10 rounded-full text-sm font-semibold bg-zinc-100 text-zinc-500" : "w-8 h-8 sm:w-10 sm:h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
936
936
  "aria-label": "Import Script",
937
937
  children: isProcessing ? /* @__PURE__ */ jsx("span", { className: "text-xs sm:text-sm font-semibold", children: "Processing..." }) : children
938
938
  }
@@ -1216,6 +1216,44 @@ function PhoneticGuide({
1216
1216
  }
1217
1217
  );
1218
1218
  }
1219
+ function Tooltip({
1220
+ children,
1221
+ content,
1222
+ shortcut,
1223
+ align = "center"
1224
+ }) {
1225
+ const alignClasses = {
1226
+ center: "left-1/2 -translate-x-1/2 items-center",
1227
+ left: "left-0 items-start",
1228
+ right: "right-0 items-end"
1229
+ };
1230
+ const arrowClasses = {
1231
+ center: "",
1232
+ left: "left-3.5",
1233
+ right: "right-3.5"
1234
+ };
1235
+ return /* @__PURE__ */ jsxs("div", { className: "group relative flex items-center justify-center", children: [
1236
+ children,
1237
+ /* @__PURE__ */ jsxs(
1238
+ "div",
1239
+ {
1240
+ className: `absolute top-[calc(100%+8px)] scale-95 opacity-0 pointer-events-none group-hover:scale-100 group-hover:opacity-100 transition-all duration-150 ease-out z-[100] flex flex-col ${alignClasses[align]}`,
1241
+ children: [
1242
+ /* @__PURE__ */ jsx(
1243
+ "div",
1244
+ {
1245
+ className: `w-2 h-2 rotate-45 bg-blumine-950 border-l border-t border-white/10 -mb-1 shadow-sm ${align === "center" ? "" : "relative"} ${arrowClasses[align]}`
1246
+ }
1247
+ ),
1248
+ /* @__PURE__ */ jsxs("div", { className: "bg-blumine-950/95 text-white text-[11px] font-medium px-2.5 py-1.5 rounded-lg shadow-xl border border-white/10 backdrop-blur-sm whitespace-nowrap flex items-center gap-1.5", children: [
1249
+ /* @__PURE__ */ jsx("span", { children: content }),
1250
+ shortcut && /* @__PURE__ */ jsx("kbd", { className: "bg-blumine-800 text-[10px] text-blumine-300 px-1.5 py-0.5 rounded border border-zinc-700 font-sans font-semibold", children: shortcut })
1251
+ ] })
1252
+ ]
1253
+ }
1254
+ )
1255
+ ] });
1256
+ }
1219
1257
  function ScreenplayEditorView({
1220
1258
  blocks,
1221
1259
  refs,
@@ -1257,7 +1295,8 @@ function ScreenplayEditorView({
1257
1295
  currentLanguage,
1258
1296
  setCurrentLanguage,
1259
1297
  phoneticSuggestions,
1260
- handleSelectPhoneticSuggestion
1298
+ handleSelectPhoneticSuggestion,
1299
+ autosaveStatus
1261
1300
  }) {
1262
1301
  const [isRulesOpen, setIsRulesOpen] = useState(false);
1263
1302
  const [isLanguageOpen, setIsLanguageOpen] = useState(false);
@@ -1307,168 +1346,299 @@ function ScreenplayEditorView({
1307
1346
  document.head.appendChild(style);
1308
1347
  }
1309
1348
  }, [COURIER_STACK]);
1310
- if (isLoading) {
1311
- return /* @__PURE__ */ jsx("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-white/80 transition-opacity", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center gap-3", children: [
1312
- /* @__PURE__ */ jsx(Loader2, { className: "w-8 h-8 text-zinc-400 animate-spin" }),
1313
- /* @__PURE__ */ jsx("p", { className: "text-zinc-500 text-sm font-medium", children: "Loading script..." })
1314
- ] }) });
1315
- }
1316
1349
  return /* @__PURE__ */ jsxs(Fragment, { children: [
1317
- /* @__PURE__ */ jsxs("div", { className: "sticky top-2 sm:top-6 z-50 mx-auto w-full max-w-[1037px] rounded-[2.5rem] sm:rounded-[2rem] bg-gradient-to-b from-white/90 to-white/70 border border-white/60 shadow-[0_14px_34px_rgba(16,37,54,0.06),0_2px_8px_rgba(16,37,54,0.03)] backdrop-blur-xl flex items-center justify-between px-2 py-1.5 sm:px-3 sm:py-2 mb-6 sm:mb-12 select-none transition-all", children: [
1318
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 overflow-x-auto pr-2 flex-1 no-scrollbar rounded-full p-1 bg-gradient-to-b from-white/80 to-blumine-50 border border-blumine-200 shadow-inner", children: blockTypes.map((type) => {
1350
+ isLoading && /* @__PURE__ */ jsxs("div", { className: "fixed inset-0 z-[100] flex items-center justify-center bg-blumine-500/40 backdrop-blur-md p-6", children: [
1351
+ /* @__PURE__ */ jsx("style", { children: `
1352
+ @keyframes gpu-spin {
1353
+ 0% { transform: rotate(0deg); }
1354
+ 100% { transform: rotate(360deg); }
1355
+ }
1356
+ .gpu-spinner-container {
1357
+ transform: translate3d(0,0,0);
1358
+ will-change: transform;
1359
+ }
1360
+ .gpu-spinner {
1361
+ width: 32px;
1362
+ height: 32px;
1363
+ border: 3.5px solid rgba(255, 255, 255, 0.25);
1364
+ border-top-color: #ffffff;
1365
+ border-radius: 50%;
1366
+ animation: gpu-spin 0.85s linear infinite;
1367
+ will-change: transform;
1368
+ transform: translate3d(0,0,0);
1369
+ }
1370
+ ` }),
1371
+ /* @__PURE__ */ jsx("div", { className: "h-full w-full border-2 border-white border-dashed rounded-[2.5rem] flex items-center justify-center gpu-spinner-container", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col items-center", children: [
1372
+ /* @__PURE__ */ jsx("div", { className: "gpu-spinner" }),
1373
+ /* @__PURE__ */ jsx("p", { className: "text-white text-lg font-semibold mt-4", children: "Preparing Script..." }),
1374
+ /* @__PURE__ */ jsx("p", { className: "text-white text-xs font-medium mt-2", children: "Please wait while we prepare your screenplay." }),
1375
+ /* @__PURE__ */ jsx("span", { className: "text-white/80 text-xs mt-2", children: "Status: Arranging data..." })
1376
+ ] }) })
1377
+ ] }),
1378
+ /* @__PURE__ */ jsxs("div", { className: "sticky top-0 left-0 right-0 z-50 w-full bg-zinc-50/95 backdrop-blur-md border-b border-zinc-200/60 shadow-[0_1px_2px_rgba(0,0,0,0.01)] flex flex-wrap lg:flex-nowrap items-center justify-between px-3 sm:px-6 py-2 mb-8 select-none transition-all gap-y-2", children: [
1379
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3 w-auto shrink-0 order-1", children: [
1380
+ /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold tracking-wider text-blumine-400/80 uppercase", children: "Script Editor" }),
1381
+ autosaveStatus === "saved" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-emerald-50 text-emerald-600 border border-emerald-100/50 animate-in fade-in duration-300", children: [
1382
+ /* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-emerald-500 animate-pulse" }),
1383
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Script synced" })
1384
+ ] }),
1385
+ autosaveStatus === "saving" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-blue-50 text-blue-600 border border-blue-100/50 animate-in fade-in duration-300", children: [
1386
+ /* @__PURE__ */ jsx(Loader2, { className: "w-2.5 h-2.5 animate-spin" }),
1387
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Saving..." })
1388
+ ] }),
1389
+ autosaveStatus === "typing" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-amber-50 text-amber-600 border border-amber-100/50 animate-in fade-in duration-300", children: [
1390
+ /* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-amber-500 animate-pulse" }),
1391
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Drafting..." })
1392
+ ] }),
1393
+ autosaveStatus === "error" && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 px-2.5 py-0.5 rounded-full bg-rose-50 text-rose-600 border border-rose-100/50 animate-in fade-in duration-300", children: [
1394
+ /* @__PURE__ */ jsx("span", { className: "w-1.5 h-1.5 rounded-full bg-rose-500 animate-pulse" }),
1395
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] font-semibold tracking-wide", children: "Error saving" })
1396
+ ] })
1397
+ ] }),
1398
+ /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center gap-1 sm:gap-2 basis-full lg:basis-auto flex-initial min-w-0 py-1 lg:py-0.5 order-3 lg:order-2", children: blockTypes.map((type) => {
1319
1399
  var _a;
1320
1400
  const selected = ((_a = blocks.find((b) => b.id === focusedBlockId)) == null ? void 0 : _a.type) === type;
1321
- return /* @__PURE__ */ jsxs(
1322
- "button",
1401
+ return /* @__PURE__ */ jsx(
1402
+ Tooltip,
1323
1403
  {
1324
- type: "button",
1325
- disabled: isLocked,
1326
- onClick: () => handleBlockTypeChange(type),
1327
- className: `group w-fit flex shrink-0 items-center gap-2 px-3 sm:px-4 h-[40px] sm:h-[42px] rounded-full font-medium text-xs sm:text-sm transition-all duration-200 ease-out active:scale-95 whitespace-nowrap ${selected ? "bg-gradient-to-b from-white to-blumine-100 text-blumine-500 shadow-[0_6px_14px_rgba(24,88,122,0.15)] border border-blumine-200" : "text-blumine-500 hover:bg-white"} ${isLocked ? "opacity-50 cursor-not-allowed" : ""}`,
1328
- children: [
1329
- /* @__PURE__ */ jsx(
1330
- "div",
1331
- {
1332
- className: `flex items-center justify-center transition-opacity duration-200 ${selected ? "opacity-100" : "opacity-70 group-hover:opacity-100"}`,
1333
- children: icons[type]
1334
- }
1335
- ),
1336
- /* @__PURE__ */ jsx("span", { className: "hidden lg:inline tracking-wide", children: blockStyles[type].label })
1337
- ]
1404
+ content: blockStyles[type].label,
1405
+ shortcut: "Ctrl + \u2191/\u2193",
1406
+ children: /* @__PURE__ */ jsx(
1407
+ "button",
1408
+ {
1409
+ type: "button",
1410
+ disabled: isLocked,
1411
+ onClick: () => handleBlockTypeChange(type),
1412
+ className: `w-8 h-8 sm:w-9 sm:h-9 flex shrink-0 items-center justify-center rounded-lg transition-all duration-150 ease-out active:scale-95 whitespace-nowrap ${selected ? "bg-blumine-200/60 text-blumine-800 shadow-sm border border-blumine-200/50" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"} ${isLocked ? "opacity-50 cursor-not-allowed" : ""}`,
1413
+ children: /* @__PURE__ */ jsx(
1414
+ "div",
1415
+ {
1416
+ className: `flex items-center justify-center transition-all duration-150 ${selected ? "scale-105 opacity-100" : "opacity-80 hover:opacity-100"}`,
1417
+ children: icons[type]
1418
+ }
1419
+ )
1420
+ }
1421
+ )
1338
1422
  },
1339
1423
  type
1340
1424
  );
1341
1425
  }) }),
1342
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5 shrink-0 ml-2 sm:ml-0 pl-2 sm:pl-1 border-l sm:border-none border-blumine-200/70", children: [
1343
- /* @__PURE__ */ jsx("div", { className: "hidden sm:block w-[1px] h-6 bg-blumine-200 rounded-full mx-1" }),
1344
- showPdfImport && !isLocked && /* @__PURE__ */ jsx(
1345
- PdfImporter,
1346
- {
1347
- disabled: isLocked,
1348
- onScriptImported: handleScriptImport,
1349
- children: /* @__PURE__ */ jsx("div", { className: "w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-full text-blumine-500 hover:text-blumine-900 hover:bg-white/70 transition active:scale-95", children: /* @__PURE__ */ jsx(Upload, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" }) })
1350
- }
1351
- ),
1352
- onToggleLock && /* @__PURE__ */ jsx(
1353
- "button",
1354
- {
1355
- onClick: onToggleLock,
1356
- className: `w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-full transition-all duration-200 active:scale-95 ${isLocked ? "text-rose-500 bg-rose-50/60" : "text-blumine-500 hover:text-blumine-900 hover:bg-white/70"}`,
1357
- children: isLocked ? /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" }) : /* @__PURE__ */ jsx(Unlock, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
1358
- }
1359
- ),
1360
- onSave && showSaveButton && !isLocked && /* @__PURE__ */ jsx(
1426
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-end gap-1 sm:gap-1.5 w-auto lg:w-[220px] shrink-0 order-2 lg:order-3", children: [
1427
+ onSave && showSaveButton && !isLocked && /* @__PURE__ */ jsx(Tooltip, { content: "Save changes", align: "right", children: /* @__PURE__ */ jsx(
1361
1428
  "button",
1362
1429
  {
1363
1430
  onClick: onSave,
1364
- className: "w-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",
1365
- children: /* @__PURE__ */ jsx(Save, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
1366
- }
1367
- ),
1368
- onSaveAsPdf && showSaveButton && /* @__PURE__ */ jsx(
1369
- "button",
1370
- {
1371
- onClick: onSaveAsPdf,
1372
- className: "w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-full text-blumine-500 hover:text-blumine-900 hover:bg-white/70 transition active:scale-95",
1373
- children: /* @__PURE__ */ jsx(FileDown, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
1431
+ className: "w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700 transition active:scale-95",
1432
+ children: /* @__PURE__ */ jsx(
1433
+ Save,
1434
+ {
1435
+ className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
1436
+ strokeWidth: 1.5
1437
+ }
1438
+ )
1374
1439
  }
1375
- ),
1376
- onSyncWithCloud && showSyncButton && !isLocked && /* @__PURE__ */ jsx(
1377
- "button",
1440
+ ) }),
1441
+ onToggleLock && /* @__PURE__ */ jsx(
1442
+ Tooltip,
1378
1443
  {
1379
- onClick: onSyncWithCloud,
1380
- 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",
1381
- children: /* @__PURE__ */ jsx(RefreshCcw, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
1444
+ content: isLocked ? "Unlock Screenplay" : "Lock Screenplay",
1445
+ align: "right",
1446
+ children: /* @__PURE__ */ jsx(
1447
+ "button",
1448
+ {
1449
+ onClick: onToggleLock,
1450
+ className: `w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg transition active:scale-95 ${isLocked ? "text-rose-500 hover:bg-rose-50 hover:text-rose-700 bg-rose-50/50" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"}`,
1451
+ children: isLocked ? /* @__PURE__ */ jsx(
1452
+ Lock,
1453
+ {
1454
+ className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
1455
+ strokeWidth: 1.5
1456
+ }
1457
+ ) : /* @__PURE__ */ jsx(
1458
+ Unlock,
1459
+ {
1460
+ className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
1461
+ strokeWidth: 1.5
1462
+ }
1463
+ )
1464
+ }
1465
+ )
1382
1466
  }
1383
1467
  ),
1384
1468
  /* @__PURE__ */ jsxs("div", { ref: rulesRef, className: "relative flex items-center", children: [
1385
- /* @__PURE__ */ jsx(
1469
+ /* @__PURE__ */ jsx(Tooltip, { content: "Settings & Actions", align: "right", children: /* @__PURE__ */ jsx(
1386
1470
  "button",
1387
1471
  {
1388
1472
  onClick: () => setIsRulesOpen(!isRulesOpen),
1389
- className: `w-9 h-9 sm:w-10 sm:h-10 flex items-center justify-center rounded-full transition-all duration-200 active:scale-95 ${isRulesOpen ? "bg-gradient-to-b from-white to-blumine-100 text-blumine-500 shadow-md border border-blumine-100" : "text-blumine-500 hover:text-blumine-900 hover:bg-white/70"}`,
1390
- children: /* @__PURE__ */ jsx(Cog, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
1473
+ className: `w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg transition-all duration-200 active:scale-95 ${isRulesOpen ? "bg-blumine-200/60 text-blumine-800 shadow-sm border border-blumine-200/50" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"}`,
1474
+ children: /* @__PURE__ */ jsx(
1475
+ Cog,
1476
+ {
1477
+ className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
1478
+ strokeWidth: 1.5
1479
+ }
1480
+ )
1391
1481
  }
1392
- ),
1393
- isRulesOpen && /* @__PURE__ */ jsxs("div", { className: "absolute -right-2 top-[calc(100%+14px)] w-[332px] max-w-[90vw] p-3 rounded-[24px] bg-white border border-blumine-200/70 shadow-[0_18px_40px_rgba(16,37,54,0.08),0_3px_10px_rgba(16,37,54,0.04)] backdrop-blur-xl origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
1394
- /* @__PURE__ */ jsx("div", { className: "absolute -top-2 right-5 w-4 h-4 rotate-45 bg-white border-l border-t border-blumine-200/70" }),
1395
- /* @__PURE__ */ jsx("div", { className: "flex items-start justify-between mb-3 px-1", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
1396
- /* @__PURE__ */ jsx("div", { className: "w-10 h-10 flex items-center justify-center rounded-xl bg-gradient-to-b from-white to-blumine-50 text-blumine-500 border border-blumine-200/70 shadow-inner", children: /* @__PURE__ */ jsx(Cog, { className: "w-4 h-4" }) }),
1482
+ ) }),
1483
+ isRulesOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-[calc(100%+14px)] w-[360px] max-w-[90vw] p-4 rounded-2xl bg-white border border-blumine-200 shadow-2xl backdrop-blur-xl origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
1484
+ /* @__PURE__ */ jsx("div", { className: "absolute -top-1.5 right-3.5 w-3 h-3 rotate-45 bg-white border-l border-t border-blumine-200" }),
1485
+ /* @__PURE__ */ jsx("div", { className: "flex items-start justify-between mb-4 px-1", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
1486
+ /* @__PURE__ */ jsx("div", { className: "w-10 h-10 flex items-center justify-center rounded-xl bg-gradient-to-b from-white to-blumine-50/50 text-blumine-600 border border-blumine-200 shadow-inner", children: /* @__PURE__ */ jsx(Cog, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
1397
1487
  /* @__PURE__ */ jsxs("div", { children: [
1398
- /* @__PURE__ */ jsx("h4", { className: "text-[15px] font-semibold text-blumine-900 leading-tight", children: "Settings & Shortcuts" }),
1399
- /* @__PURE__ */ jsx("p", { className: "text-xs text-blumine-500 mt-1", children: "Writing flow & editor controls" })
1488
+ /* @__PURE__ */ jsx("h4", { className: "text-[15px] font-semibold text-blumine-800 leading-tight", children: "Settings & Actions" }),
1489
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-blumine-400 mt-1", children: "Screenplay controls & keyboard shortcuts" })
1400
1490
  ] })
1401
1491
  ] }) }),
1402
- /* @__PURE__ */ jsx("div", { className: "space-y-2", children: [
1403
- {
1404
- title: "New Block",
1405
- desc: "Insert the next section",
1406
- key: ["Enter"]
1407
- },
1408
- {
1409
- title: "Delete Block",
1410
- desc: "Remove selected section",
1411
- key: ["Backspace \u{1F860}"]
1412
- },
1413
- {
1414
- title: "Change Type",
1415
- desc: "Cycle block styles",
1416
- key: ["Ctrl", "+", "\u2191/\u2193"]
1417
- }
1418
- ].map((item) => /* @__PURE__ */ jsxs(
1419
- "div",
1420
- {
1421
- className: "flex items-center justify-between gap-4 p-3 rounded-[18px] bg-gradient-to-b from-white to-blumine-50/50 border border-blumine-200/60 shadow-[inset_0_1px_0_rgba(255,255,255,0.8)]",
1422
- children: [
1423
- /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
1424
- /* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blumine-800", children: item.title }),
1425
- /* @__PURE__ */ jsx("span", { className: "text-[11px] text-blumine-500 truncate", children: item.desc })
1426
- ] }),
1427
- /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0", children: item.key.map(
1428
- (k, i) => k === "+" ? /* @__PURE__ */ jsx(
1429
- "span",
1430
- {
1431
- className: "text-blumine-400 text-xs font-semibold",
1432
- children: "+"
1433
- },
1434
- i
1435
- ) : /* @__PURE__ */ jsx(
1436
- "kbd",
1492
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 mb-4", children: [
1493
+ /* @__PURE__ */ jsx("div", { className: "px-1.5 mb-1", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold text-blumine-400 uppercase tracking-wider", children: "Document Actions" }) }),
1494
+ showPdfImport && /* @__PURE__ */ jsx(
1495
+ PdfImporter,
1496
+ {
1497
+ disabled: isLocked,
1498
+ onScriptImported: (title, content, preParsedBlocks) => {
1499
+ handleScriptImport(title, content, preParsedBlocks);
1500
+ setIsRulesOpen(false);
1501
+ },
1502
+ className: "w-full text-left",
1503
+ children: /* @__PURE__ */ jsxs(
1504
+ "div",
1505
+ {
1506
+ className: `w-full flex items-center gap-3 p-3 rounded-xl border border-blumine-100 bg-gradient-to-b from-white to-blumine-50/10 hover:from-blumine-50/40 hover:to-blumine-50/60 hover:border-blumine-200 hover:shadow-sm active:scale-[0.98] transition-all duration-200 cursor-pointer ${isLocked ? "opacity-60 cursor-not-allowed pointer-events-none" : ""}`,
1507
+ children: [
1508
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 flex items-center justify-center rounded-lg bg-blumine-50 text-blumine-600 border border-blumine-100 shrink-0", children: /* @__PURE__ */ jsx(Upload, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
1509
+ /* @__PURE__ */ jsxs("div", { className: "flex-1 text-left", children: [
1510
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: "Import PDF" }),
1511
+ /* @__PURE__ */ jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: isLocked ? "Unlock screenplay to import files" : "Load screenplay from external file" })
1512
+ ] })
1513
+ ]
1514
+ }
1515
+ )
1516
+ }
1517
+ ),
1518
+ onToggleLock && /* @__PURE__ */ jsxs(
1519
+ "button",
1520
+ {
1521
+ onClick: () => {
1522
+ onToggleLock();
1523
+ },
1524
+ className: "w-full text-left flex items-center gap-3 p-3 rounded-xl border border-blumine-100 bg-gradient-to-b from-white to-blumine-50/10 hover:from-blumine-50/40 hover:to-blumine-50/60 hover:border-blumine-200 hover:shadow-sm active:scale-[0.98] transition-all duration-200",
1525
+ children: [
1526
+ /* @__PURE__ */ jsx(
1527
+ "div",
1437
1528
  {
1438
- className: "min-w-[28px] px-2 py-1 text-[11px] font-bold text-primary bg-gradient-to-b from-white to-blumine-100 border border-blumine-200/70 rounded-full text-center shadow-[inset_0_1px_0_rgba(255,255,255,0.9)]",
1439
- children: k
1440
- },
1441
- i
1442
- )
1443
- ) })
1444
- ]
1445
- },
1446
- item.title
1447
- )) })
1529
+ className: `w-8 h-8 flex items-center justify-center rounded-lg shrink-0 border ${isLocked ? "bg-rose-50 text-rose-500 border-rose-100/50" : "bg-blumine-50 text-blumine-600 border-blumine-100/50"}`,
1530
+ children: isLocked ? /* @__PURE__ */ jsx(Lock, { className: "w-4 h-4", strokeWidth: 1.5 }) : /* @__PURE__ */ jsx(Unlock, { className: "w-4 h-4", strokeWidth: 1.5 })
1531
+ }
1532
+ ),
1533
+ /* @__PURE__ */ jsxs("div", { children: [
1534
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: isLocked ? "Unlock Screenplay" : "Lock Screenplay" }),
1535
+ /* @__PURE__ */ jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: isLocked ? "Enable editing controls" : "Prevent accidental editing" })
1536
+ ] })
1537
+ ]
1538
+ }
1539
+ ),
1540
+ onSaveAsPdf && showSaveButton && /* @__PURE__ */ jsxs(
1541
+ "button",
1542
+ {
1543
+ onClick: () => {
1544
+ onSaveAsPdf();
1545
+ setIsRulesOpen(false);
1546
+ },
1547
+ className: "w-full text-left flex items-center gap-3 p-3 rounded-xl border border-blumine-100 bg-gradient-to-b from-white to-blumine-50/10 hover:from-blumine-50/40 hover:to-blumine-50/60 hover:border-blumine-200 hover:shadow-sm active:scale-[0.98] transition-all duration-200",
1548
+ children: [
1549
+ /* @__PURE__ */ jsx("div", { className: "w-8 h-8 flex items-center justify-center rounded-lg bg-blumine-50 text-blumine-600 border border-blumine-100 shrink-0", children: /* @__PURE__ */ jsx(FileDown, { className: "w-4 h-4", strokeWidth: 1.5 }) }),
1550
+ /* @__PURE__ */ jsxs("div", { children: [
1551
+ /* @__PURE__ */ jsx("div", { className: "text-sm font-semibold text-blumine-800 leading-none", children: "Save as PDF" }),
1552
+ /* @__PURE__ */ jsx("div", { className: "text-[11px] text-blumine-400 mt-1", children: "Export screenplay to standard print PDF" })
1553
+ ] })
1554
+ ]
1555
+ }
1556
+ )
1557
+ ] }),
1558
+ /* @__PURE__ */ jsx("div", { className: "border-t border-blumine-100/60 my-4" }),
1559
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2", children: [
1560
+ /* @__PURE__ */ jsx("div", { className: "px-1.5 mb-1", children: /* @__PURE__ */ jsx("span", { className: "text-[11px] font-bold text-blumine-400 uppercase tracking-wider", children: "Keyboard Shortcuts" }) }),
1561
+ [
1562
+ {
1563
+ title: "New Block",
1564
+ desc: "Insert the next section",
1565
+ key: ["Enter"]
1566
+ },
1567
+ {
1568
+ title: "Delete Block",
1569
+ desc: "Remove selected section",
1570
+ key: ["Backspace \u{1F860}"]
1571
+ },
1572
+ {
1573
+ title: "Change Type",
1574
+ desc: "Cycle block styles",
1575
+ key: ["Ctrl", "+", "\u2191/\u2193"]
1576
+ }
1577
+ ].map((item) => /* @__PURE__ */ jsxs(
1578
+ "div",
1579
+ {
1580
+ className: "flex items-center justify-between gap-4 p-2.5 rounded-xl bg-gradient-to-b from-white to-blumine-50/30 border border-blumine-100/80 shadow-[inset_0_1px_0_rgba(255,255,255,0.8)]",
1581
+ children: [
1582
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0 text-left", children: [
1583
+ /* @__PURE__ */ jsx("span", { className: "text-xs font-semibold text-blumine-800", children: item.title }),
1584
+ /* @__PURE__ */ jsx("span", { className: "text-[10px] text-blumine-400 truncate mt-0.5", children: item.desc })
1585
+ ] }),
1586
+ /* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0", children: item.key.map(
1587
+ (k, i) => k === "+" ? /* @__PURE__ */ jsx(
1588
+ "span",
1589
+ {
1590
+ className: "text-blumine-400 text-xs font-semibold",
1591
+ children: "+"
1592
+ },
1593
+ i
1594
+ ) : /* @__PURE__ */ jsx(
1595
+ "kbd",
1596
+ {
1597
+ className: "min-w-[28px] px-2 py-1 text-[11px] font-bold text-blumine-700 bg-gradient-to-b from-white to-blumine-100 border border-blumine-200 rounded-lg text-center shadow-[inset_0_1px_0_rgba(255,255,255,0.9)]",
1598
+ children: k
1599
+ },
1600
+ i
1601
+ )
1602
+ ) })
1603
+ ]
1604
+ },
1605
+ item.title
1606
+ ))
1607
+ ] })
1448
1608
  ] })
1449
1609
  ] }),
1450
1610
  /* @__PURE__ */ jsxs(
1451
1611
  "div",
1452
1612
  {
1453
1613
  ref: languageRef,
1454
- className: "flex items-center pl-1.5 border-l border-blumine-200/70",
1614
+ className: "relative flex items-center pl-1.5 border-l border-blumine-200",
1455
1615
  children: [
1456
- /* @__PURE__ */ jsxs(
1457
- "button",
1616
+ /* @__PURE__ */ jsx(
1617
+ Tooltip,
1458
1618
  {
1459
- onClick: () => setIsLanguageOpen(!isLanguageOpen),
1460
- className: `flex items-center gap-2 pr-4 pl-2 h-9 sm:h-10 rounded-full transition-all duration-200 active:scale-95 ${isLanguageOpen ? "bg-blumine-50 text-blumine-600 shadow-sm" : "text-blumine-500 hover:text-blumine-900 hover:bg-white/70"}`,
1461
- children: [
1462
- /* @__PURE__ */ jsx("div", { className: "w-6 h-6 flex items-center justify-center rounded-full bg-white shadow-sm border border-blumine-100", children: /* @__PURE__ */ jsx(Languages, { className: "w-3.5 h-3.5" }) }),
1463
- /* @__PURE__ */ jsx("span", { className: "text-xs font-bold whitespace-nowrap", children: LANGUAGE_CONFIGS[currentLanguage].name })
1464
- ]
1619
+ content: `Input Language: ${LANGUAGE_CONFIGS[currentLanguage].name}`,
1620
+ align: "right",
1621
+ children: /* @__PURE__ */ jsx(
1622
+ "button",
1623
+ {
1624
+ onClick: () => setIsLanguageOpen(!isLanguageOpen),
1625
+ className: `w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg transition-all duration-200 active:scale-95 ${isLanguageOpen ? "bg-blumine-200/60 text-blumine-800 border border-blumine-200 shadow-sm" : "text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700"}`,
1626
+ children: /* @__PURE__ */ jsx(
1627
+ Languages,
1628
+ {
1629
+ className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
1630
+ strokeWidth: 1.5
1631
+ }
1632
+ )
1633
+ }
1634
+ )
1465
1635
  }
1466
1636
  ),
1467
- isLanguageOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-[calc(100%+14px)] w-[400px] max-w-[90vw] p-3 rounded-[24px] bg-white border border-blumine-200/70 shadow-[0_18px_40px_rgba(16,37,54,0.08)] backdrop-blur-xl origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
1468
- /* @__PURE__ */ jsx("div", { className: "absolute -top-2 right-12 w-4 h-4 rotate-45 bg-white border-l border-t border-blumine-200/70" }),
1637
+ isLanguageOpen && /* @__PURE__ */ jsxs("div", { className: "absolute right-0 top-[calc(100%+14px)] w-[400px] max-w-[90vw] p-3 rounded-2xl bg-white border border-blumine-200 shadow-xl backdrop-blur-xl origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
1638
+ /* @__PURE__ */ jsx("div", { className: "absolute -top-1.5 right-3.5 w-3 h-3 rotate-45 bg-white border-l border-t border-blumine-200" }),
1469
1639
  /* @__PURE__ */ jsxs("div", { className: "px-2 mb-3", children: [
1470
- /* @__PURE__ */ jsx("h4", { className: "text-[13px] font-bold text-blumine-900 uppercase tracking-wider", children: "Select Input Language" }),
1471
- /* @__PURE__ */ jsx("p", { className: "text-[11px] text-blumine-500 mt-0.5", children: "Direct keyboard mapping (InScript logic)" })
1640
+ /* @__PURE__ */ jsx("h4", { className: "text-[13px] font-bold text-blumine-800 uppercase tracking-wider", children: "Select Input Language" }),
1641
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-blumine-400 mt-0.5", children: "Direct keyboard mapping (InScript logic)" })
1472
1642
  ] }),
1473
1643
  /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-1.5 max-h-[300px] overflow-y-auto pr-1 flex-1 custom-scrollbar", children: Object.keys(LANGUAGE_CONFIGS).map(
1474
1644
  (lang) => /* @__PURE__ */ jsxs(
@@ -1478,16 +1648,16 @@ function ScreenplayEditorView({
1478
1648
  setCurrentLanguage(lang);
1479
1649
  setIsLanguageOpen(false);
1480
1650
  },
1481
- className: `group flex items-center justify-between px-3.5 py-2.5 rounded-[16px] transition-all duration-200 ${currentLanguage === lang ? "bg-gradient-to-br from-blumine-50 to-white border border-blumine-200/50 shadow-sm" : "hover:bg-zinc-50 border border-transparent"}`,
1651
+ className: `group flex items-center justify-between px-3.5 py-2.5 rounded-xl transition-all duration-200 ${currentLanguage === lang ? "bg-blumine-100/80 text-blumine-800 border border-blumine-200/50 shadow-sm" : "hover:bg-blumine-50 border border-transparent"}`,
1482
1652
  children: [
1483
1653
  /* @__PURE__ */ jsx(
1484
1654
  "span",
1485
1655
  {
1486
- className: `text-sm font-medium ${currentLanguage === lang ? "text-blumine-600" : "text-zinc-600"}`,
1656
+ className: `text-sm font-medium ${currentLanguage === lang ? "text-blumine-800 font-semibold" : "text-blumine-500"}`,
1487
1657
  children: LANGUAGE_CONFIGS[lang].name
1488
1658
  }
1489
1659
  ),
1490
- currentLanguage === lang && /* @__PURE__ */ jsx("div", { className: "w-5 h-5 rounded-full bg-blumine-500 flex items-center justify-center text-white", children: /* @__PURE__ */ jsx(Check, { className: "w-3 h-3" }) })
1660
+ currentLanguage === lang && /* @__PURE__ */ jsx("div", { className: "w-5 h-5 rounded-full bg-blumine-700 flex items-center justify-center text-white", children: /* @__PURE__ */ jsx(Check, { className: "w-3 h-3", strokeWidth: 2 }) })
1491
1661
  ]
1492
1662
  },
1493
1663
  lang
@@ -1497,15 +1667,20 @@ function ScreenplayEditorView({
1497
1667
  ]
1498
1668
  }
1499
1669
  ),
1500
- LANGUAGE_CONFIGS[currentLanguage].isPhonetic && /* @__PURE__ */ jsx(
1670
+ LANGUAGE_CONFIGS[currentLanguage].isPhonetic && /* @__PURE__ */ jsx(Tooltip, { content: "Phonetic Keyboard Rules", align: "right", children: /* @__PURE__ */ jsx(
1501
1671
  "button",
1502
1672
  {
1503
1673
  onClick: () => setIsPhoneticGuideOpen(true),
1504
- className: "w-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 ml-1",
1505
- title: "Phonetic Keyboard Rules",
1506
- children: /* @__PURE__ */ jsx(Keyboard, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
1674
+ className: "w-8 h-8 sm:w-9 sm:h-9 flex items-center justify-center rounded-lg text-blumine-400 hover:bg-blumine-100 hover:text-blumine-700 transition active:scale-95 ml-1",
1675
+ children: /* @__PURE__ */ jsx(
1676
+ Keyboard,
1677
+ {
1678
+ className: "w-4 h-4 sm:w-[18px] sm:h-[18px]",
1679
+ strokeWidth: 1.5
1680
+ }
1681
+ )
1507
1682
  }
1508
- )
1683
+ ) })
1509
1684
  ] })
1510
1685
  ] }),
1511
1686
  /* @__PURE__ */ jsx(
@@ -1516,7 +1691,7 @@ function ScreenplayEditorView({
1516
1691
  onClose: () => setIsPhoneticGuideOpen(false)
1517
1692
  }
1518
1693
  ),
1519
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-12 pb-24 w-full items-center justify-center", children: /* @__PURE__ */ jsx(
1694
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-12 pb-24 w-full items-center justify-center px-4 sm:px-6 md:px-8", children: /* @__PURE__ */ jsx(
1520
1695
  "div",
1521
1696
  {
1522
1697
  className: "relative bg-[#fdfdfc] shadow-2xl shadow-zinc-300/60 border border-zinc-100 rounded-sm md:rounded-md pl-[1.5in] py-[1in] pr-[1in] flex flex-col w-[210mm] min-h-[297mm] shrink-0",
@@ -1529,346 +1704,370 @@ function ScreenplayEditorView({
1529
1704
  },
1530
1705
  "data-screenplay-editor": "true",
1531
1706
  dir: LANGUAGE_CONFIGS[currentLanguage].dir,
1532
- children: blocks.map((block) => {
1533
- var _a, _b;
1534
- return /* @__PURE__ */ jsx(
1707
+ children: blocks.map((block) => /* @__PURE__ */ jsx(
1708
+ ScreenplayBlockItem,
1709
+ {
1710
+ block,
1711
+ isFocused: focusedBlockId === block.id,
1712
+ isLocked,
1713
+ showSuggestions,
1714
+ showExtensionSuggestions,
1715
+ locations,
1716
+ characters,
1717
+ phoneticSuggestions,
1718
+ characterExtensions,
1719
+ enhancingBlockId,
1720
+ enhancementSuggestion,
1721
+ isEnhancing,
1722
+ currentLanguage,
1723
+ refs,
1724
+ handleSceneNumberChange,
1725
+ handleSceneTypeChange,
1726
+ handleTimeOfDayChange,
1727
+ handleBlockTextChange,
1728
+ handleKeyDown,
1729
+ handleFocus,
1730
+ handleBlur,
1731
+ handleSelectPhoneticSuggestion,
1732
+ handleSelectCharacterExtension,
1733
+ handleEnhance,
1734
+ handleApproveEnhance,
1735
+ handleRejectEnhance
1736
+ },
1737
+ block.id + "-" + block.type
1738
+ ))
1739
+ }
1740
+ ) })
1741
+ ] });
1742
+ }
1743
+ var ScreenplayBlockItem = React4.memo(
1744
+ function ScreenplayBlockItem2({
1745
+ block,
1746
+ isFocused,
1747
+ isLocked,
1748
+ showSuggestions,
1749
+ showExtensionSuggestions,
1750
+ locations,
1751
+ characters,
1752
+ phoneticSuggestions,
1753
+ characterExtensions,
1754
+ enhancingBlockId,
1755
+ enhancementSuggestion,
1756
+ isEnhancing,
1757
+ currentLanguage,
1758
+ refs,
1759
+ handleSceneNumberChange,
1760
+ handleSceneTypeChange,
1761
+ handleTimeOfDayChange,
1762
+ handleBlockTextChange,
1763
+ handleKeyDown,
1764
+ handleFocus,
1765
+ handleBlur,
1766
+ handleSelectPhoneticSuggestion,
1767
+ handleSelectCharacterExtension,
1768
+ handleEnhance,
1769
+ handleApproveEnhance,
1770
+ handleRejectEnhance
1771
+ }) {
1772
+ var _a, _b;
1773
+ return /* @__PURE__ */ jsx(
1774
+ "div",
1775
+ {
1776
+ "data-block-id": block.id,
1777
+ className: `relative rounded-sm transition-all duration-200 outline-none ${isFocused ? "bg-zinc-100/50" : "bg-transparent"}`,
1778
+ "data-block-type": block.type,
1779
+ children: block.type === "SCENE_HEADING" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1780
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-1 bg-transparent", children: [
1781
+ /* @__PURE__ */ jsx(
1782
+ "input",
1783
+ {
1784
+ className: "absolute -left-16 top-2 w-12 text-right text-zinc-400 font-semibold select-none bg-transparent outline-none focus:ring-1 focus:ring-blue-400 rounded-sm",
1785
+ spellCheck: false,
1786
+ disabled: isLocked,
1787
+ value: block.sceneNumber || "",
1788
+ onChange: (e) => handleSceneNumberChange(
1789
+ block.id,
1790
+ e.target.value.toUpperCase()
1791
+ ),
1792
+ onFocus: () => handleFocus(block.id),
1793
+ onBlur: () => handleBlur(block.id),
1794
+ onKeyDown: (e) => {
1795
+ if (e.key === "Enter" || e.key === "Backspace") {
1796
+ e.stopPropagation();
1797
+ }
1798
+ },
1799
+ "aria-label": "Scene Number"
1800
+ }
1801
+ ),
1802
+ /* @__PURE__ */ jsxs(
1803
+ "select",
1804
+ {
1805
+ className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer w-fit transition-colors",
1806
+ "aria-label": "Scene Type",
1807
+ disabled: isLocked,
1808
+ value: (_a = block.sceneType) != null ? _a : "INT.",
1809
+ onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
1810
+ style: {
1811
+ appearance: "none"
1812
+ },
1813
+ children: [
1814
+ /* @__PURE__ */ jsx("option", { children: "INT." }),
1815
+ /* @__PURE__ */ jsx("option", { children: "EXT." }),
1816
+ /* @__PURE__ */ jsx("option", { children: "INT/EXT." })
1817
+ ]
1818
+ }
1819
+ ),
1820
+ /* @__PURE__ */ jsx(
1821
+ "div",
1822
+ {
1823
+ ref: (el) => {
1824
+ if (!el) return;
1825
+ refs.current[block.id] = el;
1826
+ },
1827
+ contentEditable: !isLocked,
1828
+ suppressContentEditableWarning: true,
1829
+ "aria-label": `Scene Heading: ${block.text}`,
1830
+ "aria-haspopup": "listbox",
1831
+ "aria-expanded": isFocused && showSuggestions && locations.length > 0,
1832
+ spellCheck: false,
1833
+ className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
1834
+ style: {
1835
+ minWidth: "3rem"
1836
+ },
1837
+ onInput: (e) => handleBlockTextChange(
1838
+ block.id,
1839
+ e.target.innerText
1840
+ ),
1841
+ onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
1842
+ onFocus: () => handleFocus(block.id),
1843
+ onBlur: () => handleBlur(block.id)
1844
+ }
1845
+ ),
1846
+ /* @__PURE__ */ jsx("span", { className: "text-zinc-400/80 font-bold", children: "-" }),
1847
+ /* @__PURE__ */ jsx(
1848
+ "select",
1849
+ {
1850
+ className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer transition-colors",
1851
+ "aria-label": "Time of Day",
1852
+ disabled: isLocked,
1853
+ value: (_b = block.timeOfDay) != null ? _b : "DAY",
1854
+ style: {
1855
+ appearance: "none"
1856
+ },
1857
+ onChange: (e) => handleTimeOfDayChange(block.id, e.target.value),
1858
+ children: timeOfDayOptions.map((t) => /* @__PURE__ */ jsx("option", { children: t }, t))
1859
+ }
1860
+ )
1861
+ ] }),
1862
+ isFocused && showSuggestions && locations.length > 0 && /* @__PURE__ */ jsx(
1535
1863
  "div",
1536
1864
  {
1537
- "data-block-id": block.id,
1538
- className: `relative rounded-sm transition-all duration-200 outline-none ${focusedBlockId === block.id ? "bg-zinc-100/50" : "bg-transparent"}`,
1539
- "data-block-type": block.type,
1540
- children: block.type === "SCENE_HEADING" ? /* @__PURE__ */ jsxs(Fragment, { children: [
1541
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 px-4 py-1 bg-transparent", children: [
1542
- /* @__PURE__ */ jsx(
1543
- "input",
1544
- {
1545
- 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",
1546
- spellCheck: false,
1547
- disabled: isLocked,
1548
- value: block.sceneNumber || "",
1549
- onChange: (e) => handleSceneNumberChange(
1550
- block.id,
1551
- e.target.value.toUpperCase()
1552
- ),
1553
- onFocus: () => handleFocus(block.id),
1554
- onBlur: () => handleBlur(block.id),
1555
- onKeyDown: (e) => {
1556
- if (e.key === "Enter" || e.key === "Backspace") {
1557
- e.stopPropagation();
1558
- }
1559
- },
1560
- "aria-label": "Scene Number"
1561
- }
1562
- ),
1563
- /* @__PURE__ */ jsxs(
1564
- "select",
1565
- {
1566
- className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer w-fit transition-colors",
1567
- "aria-label": "Scene Type",
1568
- disabled: isLocked,
1569
- value: (_a = block.sceneType) != null ? _a : "INT.",
1570
- onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
1571
- style: {
1572
- appearance: "none"
1573
- },
1574
- children: [
1575
- /* @__PURE__ */ jsx("option", { children: "INT." }),
1576
- /* @__PURE__ */ jsx("option", { children: "EXT." }),
1577
- /* @__PURE__ */ jsx("option", { children: "INT/EXT." })
1578
- ]
1579
- }
1580
- ),
1581
- /* @__PURE__ */ jsx(
1582
- "div",
1583
- {
1584
- ref: (el) => {
1585
- if (!el) return;
1586
- refs.current[block.id] = el;
1587
- },
1588
- contentEditable: !isLocked,
1589
- suppressContentEditableWarning: true,
1590
- "aria-label": `Scene Heading: ${block.text}`,
1591
- "aria-haspopup": "listbox",
1592
- "aria-expanded": focusedBlockId === block.id && showSuggestions && locations.length > 0,
1593
- spellCheck: false,
1594
- className: "min-w-[3rem] py-1 outline-none text-base font-bold uppercase tracking-widest break-all bg-transparent",
1595
- style: {
1596
- minWidth: "3rem"
1597
- },
1598
- onInput: (e) => handleBlockTextChange(
1599
- block.id,
1600
- e.target.innerText
1601
- ),
1602
- onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
1603
- onFocus: () => handleFocus(block.id),
1604
- onBlur: () => handleBlur(block.id)
1865
+ role: "listbox",
1866
+ id: `suggestions-${block.id}`,
1867
+ className: "absolute top-[calc(100%+6px)] left-0 min-w-[240px] z-50 bg-white border border-slate-200/80 shadow-xl shadow-slate-200/40 rounded-xl py-1 overflow-hidden animate-in fade-in zoom-in-95 duration-150",
1868
+ children: /* @__PURE__ */ jsx("div", { className: "max-h-60 overflow-y-auto custom-scrollbar", children: locations.filter(
1869
+ (loc) => loc.startsWith(block.text.toUpperCase()) && loc !== block.text.toUpperCase()
1870
+ ).map((loc) => /* @__PURE__ */ jsxs(
1871
+ "div",
1872
+ {
1873
+ role: "option",
1874
+ className: "group flex items-center justify-between px-4 py-2.5 cursor-pointer transition-all duration-150 hover:bg-slate-50 active:bg-slate-100",
1875
+ onMouseDown: (e) => {
1876
+ e.preventDefault();
1877
+ const element = refs.current[block.id];
1878
+ if (element) {
1879
+ element.innerText = loc;
1880
+ handleBlockTextChange(block.id, loc);
1881
+ element.focus();
1882
+ const range = document.createRange();
1883
+ const sel = window.getSelection();
1884
+ range.selectNodeContents(element);
1885
+ range.collapse(false);
1886
+ sel == null ? void 0 : sel.removeAllRanges();
1887
+ sel == null ? void 0 : sel.addRange(range);
1605
1888
  }
1606
- ),
1607
- /* @__PURE__ */ jsx("span", { className: "text-zinc-400/80 font-bold", children: "-" }),
1608
- /* @__PURE__ */ jsx(
1609
- "select",
1610
- {
1611
- className: "rounded-md text-zinc-800 font-bold px-1.5 py-1 appearance-none bg-transparent hover:bg-zinc-200/50 outline-none cursor-pointer transition-colors",
1612
- "aria-label": "Time of Day",
1613
- disabled: isLocked,
1614
- value: (_b = block.timeOfDay) != null ? _b : "DAY",
1615
- style: {
1616
- appearance: "none"
1617
- },
1618
- onChange: (e) => handleTimeOfDayChange(block.id, e.target.value),
1619
- children: timeOfDayOptions.map((t) => /* @__PURE__ */ jsx("option", { children: t }, t))
1889
+ handleBlur(block.id);
1890
+ },
1891
+ children: [
1892
+ /* @__PURE__ */ jsx("span", { className: "text-[12px] font-semibold tracking-wide text-slate-600 uppercase line-clamp-1", children: loc }),
1893
+ /* @__PURE__ */ jsx(ArrowRight, { className: "w-3.5 h-3.5 text-slate-300 opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" })
1894
+ ]
1895
+ },
1896
+ loc
1897
+ )) })
1898
+ }
1899
+ ),
1900
+ isFocused && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
1901
+ PhoneticSuggestions,
1902
+ {
1903
+ suggestions: phoneticSuggestions,
1904
+ onSelect: handleSelectPhoneticSuggestion
1905
+ }
1906
+ )
1907
+ ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1908
+ /* @__PURE__ */ jsx(
1909
+ "div",
1910
+ {
1911
+ ref: (el) => {
1912
+ if (!el) return;
1913
+ refs.current[block.id] = el;
1914
+ },
1915
+ contentEditable: !isLocked,
1916
+ suppressContentEditableWarning: true,
1917
+ "aria-label": `${blockStyles[block.type].label} text`,
1918
+ "aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
1919
+ spellCheck: false,
1920
+ className: `block outline-none w-full min-h-[2.5rem] px-4 py-2 break-words ${blockStyles[block.type].className}`,
1921
+ onInput: (e) => handleBlockTextChange(
1922
+ block.id,
1923
+ e.target.innerText
1924
+ ),
1925
+ onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
1926
+ onFocus: () => handleFocus(block.id),
1927
+ onBlur: () => handleBlur(block.id),
1928
+ style: blockStyles[block.type].inputStyle
1929
+ }
1930
+ ),
1931
+ isFocused && block.type === "CHARACTER" && showSuggestions && characters.length > 0 && /* @__PURE__ */ jsx(
1932
+ "div",
1933
+ {
1934
+ role: "listbox",
1935
+ id: `suggestions-${block.id}`,
1936
+ className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
1937
+ children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characters.filter(
1938
+ (char) => char.startsWith(block.text.toUpperCase()) && char !== block.text.toUpperCase()
1939
+ ).map((char) => /* @__PURE__ */ jsxs(
1940
+ "div",
1941
+ {
1942
+ role: "option",
1943
+ className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
1944
+ onMouseDown: (e) => {
1945
+ e.preventDefault();
1946
+ const element = refs.current[block.id];
1947
+ if (element) {
1948
+ element.innerText = char;
1949
+ handleBlockTextChange(block.id, char);
1950
+ element.focus();
1951
+ const range = document.createRange();
1952
+ const sel = window.getSelection();
1953
+ range.selectNodeContents(element);
1954
+ range.collapse(false);
1955
+ sel == null ? void 0 : sel.removeAllRanges();
1956
+ sel == null ? void 0 : sel.addRange(range);
1620
1957
  }
1621
- )
1622
- ] }),
1623
- focusedBlockId === block.id && showSuggestions && locations.length > 0 && /* @__PURE__ */ jsx(
1624
- "div",
1625
- {
1626
- role: "listbox",
1627
- id: `suggestions-${block.id}`,
1628
- className: "absolute top-[calc(100%+6px)] left-0 min-w-[240px] z-50 bg-white border border-slate-200/80 shadow-xl shadow-slate-200/40 rounded-xl py-1 overflow-hidden animate-in fade-in zoom-in-95 duration-150",
1629
- children: /* @__PURE__ */ jsx("div", { className: "max-h-60 overflow-y-auto custom-scrollbar", children: locations.filter(
1630
- (loc) => loc.startsWith(block.text.toUpperCase()) && loc !== block.text.toUpperCase()
1631
- ).map((loc) => /* @__PURE__ */ jsxs(
1632
- "div",
1633
- {
1634
- role: "option",
1635
- className: "group flex items-center justify-between px-4 py-2.5 cursor-pointer transition-all duration-150 hover:bg-slate-50 active:bg-slate-100",
1636
- onMouseDown: (e) => {
1637
- e.preventDefault();
1638
- const element = refs.current[block.id];
1639
- if (element) {
1640
- element.innerText = loc;
1641
- handleBlockTextChange(block.id, loc);
1642
- element.focus();
1643
- const range = document.createRange();
1644
- const sel = window.getSelection();
1645
- range.selectNodeContents(element);
1646
- range.collapse(false);
1647
- sel == null ? void 0 : sel.removeAllRanges();
1648
- sel == null ? void 0 : sel.addRange(range);
1649
- }
1650
- handleBlur(block.id);
1651
- },
1652
- children: [
1653
- /* @__PURE__ */ jsx("span", { className: "text-[12px] font-semibold tracking-wide text-slate-600 uppercase line-clamp-1", children: loc }),
1654
- /* @__PURE__ */ jsx(ArrowRight, { className: "w-3.5 h-3.5 text-slate-300 opacity-0 -translate-x-2 group-hover:opacity-100 group-hover:translate-x-0 transition-all duration-200" })
1655
- ]
1656
- },
1657
- loc
1658
- )) })
1659
- }
1660
- ),
1661
- focusedBlockId === block.id && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
1662
- PhoneticSuggestions,
1663
- {
1664
- suggestions: phoneticSuggestions,
1665
- onSelect: handleSelectPhoneticSuggestion
1666
- }
1667
- )
1668
- ] }) : /* @__PURE__ */ jsxs(Fragment, { children: [
1669
- /* @__PURE__ */ jsx(
1670
- "div",
1671
- {
1672
- ref: (el) => {
1673
- if (!el) return;
1674
- refs.current[block.id] = el;
1675
- },
1676
- contentEditable: !isLocked,
1677
- suppressContentEditableWarning: true,
1678
- "aria-label": `${blockStyles[block.type].label} text`,
1679
- "aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
1680
- spellCheck: false,
1681
- className: `block outline-none w-full min-h-[2.5rem] px-4 py-2 break-words ${blockStyles[block.type].className}`,
1682
- onInput: (e) => handleBlockTextChange(
1683
- block.id,
1684
- e.target.innerText
1685
- ),
1686
- onKeyDown: (e) => handleKeyDown(e, block.id, block.text),
1687
- onFocus: () => handleFocus(block.id),
1688
- onBlur: () => handleBlur(block.id),
1689
- style: blockStyles[block.type].inputStyle
1690
- }
1691
- ),
1692
- focusedBlockId === block.id && block.type === "CHARACTER" && showSuggestions && characters.length > 0 && /* @__PURE__ */ jsx(
1693
- "div",
1694
- {
1695
- role: "listbox",
1696
- id: `suggestions-${block.id}`,
1697
- className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
1698
- children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characters.filter(
1699
- (char) => char.startsWith(block.text.toUpperCase()) && char !== block.text.toUpperCase()
1700
- ).map((char) => /* @__PURE__ */ jsxs(
1701
- "div",
1702
- {
1703
- role: "option",
1704
- className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
1705
- onMouseDown: (e) => {
1706
- e.preventDefault();
1707
- const element = refs.current[block.id];
1708
- if (element) {
1709
- element.innerText = char;
1710
- handleBlockTextChange(block.id, char);
1711
- element.focus();
1712
- const range = document.createRange();
1713
- const sel = window.getSelection();
1714
- range.selectNodeContents(element);
1715
- range.collapse(false);
1716
- sel == null ? void 0 : sel.removeAllRanges();
1717
- sel == null ? void 0 : sel.addRange(range);
1718
- }
1719
- handleBlur(block.id);
1720
- },
1721
- children: [
1722
- /* @__PURE__ */ jsx(User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-blumine-500 transition-colors mr-3" }),
1723
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
1724
- /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
1725
- ]
1726
- },
1727
- char
1728
- )) })
1729
- }
1730
- ),
1731
- focusedBlockId === block.id && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsx(
1732
- "div",
1733
- {
1734
- role: "listbox",
1735
- id: `extension-suggestions-${block.id}`,
1736
- className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
1737
- children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
1738
- const openParenIndex = block.text.lastIndexOf("(");
1739
- const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
1740
- return ext.toUpperCase().includes(query);
1741
- }).map((ext) => /* @__PURE__ */ jsxs(
1742
- "div",
1743
- {
1744
- role: "option",
1745
- className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
1746
- onMouseDown: (e) => {
1747
- e.preventDefault();
1748
- handleSelectCharacterExtension(ext);
1749
- },
1750
- children: [
1751
- /* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
1752
- /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
1753
- ]
1754
- },
1755
- ext
1756
- )) })
1757
- }
1758
- ),
1759
- focusedBlockId === block.id && !enhancingBlockId && (block.type === "ACTION" || block.type === "DIALOGUE") && /* @__PURE__ */ jsx(
1760
- "button",
1761
- {
1762
- onClick: () => handleEnhance(block),
1763
- className: "absolute -right-12 top-1/2 -translate-y-1/2 flex items-center justify-center w-8 h-8 rounded-xl border border-blumine-200/50 bg-white text-blumine-500 hover:border-blumine-400/60 hover:bg-blumine-50/90 hover:ring-2 hover:ring-blumine-100 hover:scale-105 active:scale-95 transition-all duration-200 group/enhance animate-in fade-in slide-in-from-left-2",
1764
- title: "Enhance with AI",
1765
- children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 group-hover/enhance:animate-pulse transition-colors" })
1766
- }
1767
- ),
1768
- enhancingBlockId === block.id && (enhancementSuggestion || isEnhancing) && /* @__PURE__ */ jsxs(
1769
- "div",
1770
- {
1771
- className: "absolute left-0 right-0 -top-4 -translate-y-full z-[50] animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-300",
1772
- style: { width: "calc(100% + 2rem)", left: "-1rem" },
1773
- children: [
1774
- /* @__PURE__ */ jsx("div", { className: "mx-auto w-full rounded-[2rem] bg-white border border-white/60 shadow-[0_14px_34px_rgba(16,37,54,0.1),0_2px_8px_rgba(16,37,54,0.05)] backdrop-blur-xl p-2 select-none transition-all", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
1775
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-1", children: [
1776
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1777
- /* @__PURE__ */ jsx("div", { className: "w-9 h-9 flex items-center justify-center rounded-full bg-blumine-50 text-blumine-500 border border-blumine-100 shadow-inner", children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4" }) }),
1778
- /* @__PURE__ */ jsxs("div", { children: [
1779
- /* @__PURE__ */ jsx("p", { className: "text-[11px] font-bold text-zinc-900 uppercase tracking-wider leading-none", children: "AI Suggestion" }),
1780
- !isEnhancing && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-zinc-500 mt-1 font-medium", children: "Refining your screenplay dialogue" })
1781
- ] })
1782
- ] }),
1783
- !isEnhancing && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
1784
- /* @__PURE__ */ jsx(
1785
- "button",
1786
- {
1787
- onClick: handleRejectEnhance,
1788
- className: "px-3 py-2 rounded-full text-xs font-bold text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all active:scale-95",
1789
- children: "Discard"
1790
- }
1791
- ),
1792
- /* @__PURE__ */ jsxs(
1793
- "button",
1794
- {
1795
- onClick: handleApproveEnhance,
1796
- className: "px-4 py-2 rounded-full text-xs font-bold bg-blumine-500 text-white hover:bg-blumine-600 shadow-lg shadow-blumine-500/20 transition-all active:scale-95 flex items-center gap-1.5",
1797
- children: [
1798
- /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5" }),
1799
- "Apply Changes"
1800
- ]
1801
- }
1802
- )
1803
- ] })
1804
- ] }),
1805
- /* @__PURE__ */ jsx("div", { className: "relative overflow-hidden rounded-[1.25rem] bg-zinc-50/50 border border-zinc-100 p-4 min-h-[4rem]", children: isEnhancing ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2.5 py-1", children: [
1806
- /* @__PURE__ */ jsx("div", { className: "h-3.5 w-3/4 bg-zinc-200/60 animate-pulse rounded-full" }),
1807
- /* @__PURE__ */ jsx("div", { className: "h-3.5 w-1/2 bg-zinc-200/60 animate-pulse rounded-full" })
1808
- ] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
1809
- /* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400 line-through decoration-zinc-300 italic", children: block.text }),
1810
- /* @__PURE__ */ jsx("p", { className: "text-sm text-zinc-800 font-medium leading-relaxed", children: enhancementSuggestion })
1811
- ] }) })
1812
- ] }) }),
1813
- /* @__PURE__ */ jsx("div", { className: "absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3.5 h-3.5 bg-white border-r border-b border-zinc-200/50 rotate-45" })
1814
- ]
1815
- }
1816
- ),
1817
- focusedBlockId === block.id && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
1818
- PhoneticSuggestions,
1819
- {
1820
- suggestions: phoneticSuggestions,
1821
- onSelect: handleSelectPhoneticSuggestion
1822
- }
1823
- )
1824
- ] })
1825
- },
1826
- block.id + "-" + block.type
1827
- );
1828
- })
1829
- }
1830
- ) }),
1831
- /* @__PURE__ */ jsx(
1832
- "div",
1833
- {
1834
- 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"}`,
1835
- style: {
1836
- left: savePopOverLeft
1837
- },
1838
- children: /* @__PURE__ */ 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: [
1839
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
1840
- /* @__PURE__ */ jsx("div", { className: "w-10 h-10 flex items-center justify-center rounded-[2.5rem] bg-blumine-50 text-blumine-500 border border-blumine-100 shadow-inner", children: /* @__PURE__ */ jsx(Save, { className: "w-5 h-5" }) }),
1841
- /* @__PURE__ */ jsxs("div", { className: "mr-5", children: [
1842
- /* @__PURE__ */ jsx("p", { className: "text-xs font-bold text-zinc-900 leading-none", children: "Unsaved Changes" }),
1843
- /* @__PURE__ */ jsx("p", { className: "text-[11px] text-zinc-500 mt-1 font-medium", children: "You have changes that haven't been saved yet." })
1844
- ] })
1845
- ] }),
1846
- /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full sm:w-auto", children: [
1847
- /* @__PURE__ */ jsx(
1848
- "button",
1849
- {
1850
- onClick: ignoreChanges,
1851
- 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",
1852
- children: "Ignore"
1853
- }
1854
- ),
1855
- /* @__PURE__ */ jsxs(
1856
- "button",
1857
- {
1858
- onClick: syncScreenplay,
1859
- 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",
1860
- children: [
1861
- /* @__PURE__ */ jsx(RefreshCcw, { className: "w-4 h-4" }),
1862
- "Sync to Cloud"
1863
- ]
1864
- }
1865
- )
1866
- ] })
1958
+ handleBlur(block.id);
1959
+ },
1960
+ children: [
1961
+ /* @__PURE__ */ jsx(User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-blumine-500 transition-colors mr-3" }),
1962
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
1963
+ /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
1964
+ ]
1965
+ },
1966
+ char
1967
+ )) })
1968
+ }
1969
+ ),
1970
+ isFocused && block.type === "CHARACTER" && showExtensionSuggestions && characterExtensions && /* @__PURE__ */ jsx(
1971
+ "div",
1972
+ {
1973
+ role: "listbox",
1974
+ id: `extension-suggestions-${block.id}`,
1975
+ className: "absolute top-[calc(100%+8px)] left-1/2 -translate-x-1/2 w-72 z-50 bg-white border border-slate-200 shadow-2xl shadow-slate-200/60 rounded-xl py-2 overflow-hidden animate-in fade-in zoom-in-95 duration-200",
1976
+ children: /* @__PURE__ */ jsx("div", { className: "max-h-56 overflow-y-auto custom-scrollbar", children: characterExtensions.filter((ext) => {
1977
+ const openParenIndex = block.text.lastIndexOf("(");
1978
+ const query = openParenIndex > -1 ? block.text.substring(openParenIndex + 1).toUpperCase() : "";
1979
+ return ext.toUpperCase().includes(query);
1980
+ }).map((ext) => /* @__PURE__ */ jsxs(
1981
+ "div",
1982
+ {
1983
+ role: "option",
1984
+ className: "group flex items-center px-4 py-2.5 cursor-pointer transition-colors duration-150 hover:bg-slate-50 active:bg-slate-100",
1985
+ onMouseDown: (e) => {
1986
+ e.preventDefault();
1987
+ handleSelectCharacterExtension(ext);
1988
+ },
1989
+ children: [
1990
+ /* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: ext }),
1991
+ /* @__PURE__ */ jsx(ChevronRight, { className: "w-3 h-3 text-slate-200 opacity-0 group-hover:opacity-100 transition-all -translate-x-1 group-hover:translate-x-0" })
1992
+ ]
1993
+ },
1994
+ ext
1995
+ )) })
1996
+ }
1997
+ ),
1998
+ isFocused && !enhancingBlockId && (block.type === "ACTION" || block.type === "DIALOGUE") && /* @__PURE__ */ jsx(
1999
+ "button",
2000
+ {
2001
+ onClick: () => handleEnhance(block),
2002
+ className: "absolute -right-12 top-1/2 -translate-y-1/2 flex items-center justify-center w-8 h-8 rounded-xl border border-blumine-200/50 bg-white text-blumine-500 hover:border-blumine-400/60 hover:bg-blumine-50/90 hover:ring-2 hover:ring-blumine-100 hover:scale-105 active:scale-95 transition-all duration-200 group/enhance animate-in fade-in slide-in-from-left-2",
2003
+ title: "Enhance with AI",
2004
+ children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 group-hover/enhance:animate-pulse transition-colors" })
2005
+ }
2006
+ ),
2007
+ enhancingBlockId === block.id && (enhancementSuggestion || isEnhancing) && /* @__PURE__ */ jsxs(
2008
+ "div",
2009
+ {
2010
+ className: "absolute left-0 right-0 -top-4 -translate-y-full z-[50] animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-300",
2011
+ style: { width: "calc(100% + 2rem)", left: "-1rem" },
2012
+ children: [
2013
+ /* @__PURE__ */ jsx("div", { className: "mx-auto w-full rounded-[2rem] bg-white border border-white/60 shadow-[0_14px_34px_rgba(16,37,54,0.1),0_2px_8px_rgba(16,37,54,0.05)] backdrop-blur-xl p-2 select-none transition-all", children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
2014
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-1", children: [
2015
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
2016
+ /* @__PURE__ */ jsx("div", { className: "w-9 h-9 flex items-center justify-center rounded-full bg-blumine-50 text-blumine-500 border border-blumine-100 shadow-inner", children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4" }) }),
2017
+ /* @__PURE__ */ jsxs("div", { children: [
2018
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] font-bold text-zinc-900 uppercase tracking-wider leading-none", children: "AI Suggestion" }),
2019
+ !isEnhancing && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-zinc-500 mt-1 font-medium", children: "Refining your screenplay dialogue" })
2020
+ ] })
2021
+ ] }),
2022
+ !isEnhancing && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
2023
+ /* @__PURE__ */ jsx(
2024
+ "button",
2025
+ {
2026
+ onClick: handleRejectEnhance,
2027
+ className: "px-3 py-2 rounded-full text-xs font-bold text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all active:scale-95",
2028
+ children: "Discard"
2029
+ }
2030
+ ),
2031
+ /* @__PURE__ */ jsxs(
2032
+ "button",
2033
+ {
2034
+ onClick: handleApproveEnhance,
2035
+ className: "px-4 py-2 rounded-full text-xs font-bold bg-blumine-500 text-white hover:bg-blumine-600 shadow-lg shadow-blumine-500/20 transition-all active:scale-95 flex items-center gap-1.5",
2036
+ children: [
2037
+ /* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5" }),
2038
+ "Apply Changes"
2039
+ ]
2040
+ }
2041
+ )
2042
+ ] })
2043
+ ] }),
2044
+ /* @__PURE__ */ jsx("div", { className: "relative overflow-hidden rounded-[1.25rem] bg-zinc-50/50 border border-zinc-100 p-4 min-h-[4rem]", children: isEnhancing ? /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2.5 py-1", children: [
2045
+ /* @__PURE__ */ jsx("div", { className: "h-3.5 w-3/4 bg-zinc-200/60 animate-pulse rounded-full" }),
2046
+ /* @__PURE__ */ jsx("div", { className: "h-3.5 w-1/2 bg-zinc-200/60 animate-pulse rounded-full" })
2047
+ ] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
2048
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400 line-through decoration-zinc-300 italic", children: block.text }),
2049
+ /* @__PURE__ */ jsx("p", { className: "text-sm text-zinc-800 font-medium leading-relaxed", children: enhancementSuggestion })
2050
+ ] }) })
2051
+ ] }) }),
2052
+ /* @__PURE__ */ jsx("div", { className: "absolute -bottom-1.5 left-1/2 -translate-x-1/2 w-3.5 h-3.5 bg-white border-r border-b border-zinc-200/50 rotate-45" })
2053
+ ]
2054
+ }
2055
+ ),
2056
+ isFocused && phoneticSuggestions.length > 0 && /* @__PURE__ */ jsx(
2057
+ PhoneticSuggestions,
2058
+ {
2059
+ suggestions: phoneticSuggestions,
2060
+ onSelect: handleSelectPhoneticSuggestion
2061
+ }
2062
+ )
1867
2063
  ] })
1868
2064
  }
1869
- )
1870
- ] });
1871
- }
2065
+ );
2066
+ },
2067
+ (prevProps, nextProps) => {
2068
+ return prevProps.isLocked === nextProps.isLocked && prevProps.isFocused === nextProps.isFocused && prevProps.currentLanguage === nextProps.currentLanguage && prevProps.enhancingBlockId === nextProps.enhancingBlockId && prevProps.isEnhancing === nextProps.isEnhancing && prevProps.enhancementSuggestion === nextProps.enhancementSuggestion && prevProps.block.text === nextProps.block.text && prevProps.block.type === nextProps.block.type && prevProps.block.sceneNumber === nextProps.block.sceneNumber && prevProps.block.sceneType === nextProps.block.sceneType && prevProps.block.timeOfDay === nextProps.block.timeOfDay && (!nextProps.isFocused || prevProps.showSuggestions === nextProps.showSuggestions && prevProps.showExtensionSuggestions === nextProps.showExtensionSuggestions && prevProps.phoneticSuggestions === nextProps.phoneticSuggestions && prevProps.locations === nextProps.locations && prevProps.characters === nextProps.characters);
2069
+ }
2070
+ );
1872
2071
 
1873
2072
  // app/service/screenplay-editor.service.ts
1874
2073
  function getNextBlockType(currentType) {
@@ -2196,7 +2395,25 @@ function createRangeFromGlobalOffset(element, startOffset, endOffset) {
2196
2395
  return null;
2197
2396
  }
2198
2397
  function useScreenplayEditor(options) {
2199
- const [blocks, setBlocks] = useState(initialBlocks);
2398
+ var _a;
2399
+ const [blocks, setBlocks] = useState(
2400
+ (options == null ? void 0 : options.blocks) || initialBlocks || []
2401
+ );
2402
+ const hasInitializedRef = useRef(
2403
+ !!((options == null ? void 0 : options.blocks) && options.blocks.length > 0)
2404
+ );
2405
+ useEffect(() => {
2406
+ if ((options == null ? void 0 : options.blocks) && options.blocks.length > 0 && !hasInitializedRef.current) {
2407
+ setIsLoading(true);
2408
+ isWaitingForDOMRef.current = true;
2409
+ skipAutosaveRef.current = true;
2410
+ const timer = setTimeout(() => {
2411
+ setBlocks(options.blocks);
2412
+ hasInitializedRef.current = true;
2413
+ }, 50);
2414
+ return () => clearTimeout(timer);
2415
+ }
2416
+ }, [options == null ? void 0 : options.blocks]);
2200
2417
  const refs = useRef({});
2201
2418
  const [focusedBlockId, setFocusedBlockId] = useState(
2202
2419
  initialBlocks[0].id
@@ -2204,7 +2421,9 @@ function useScreenplayEditor(options) {
2204
2421
  const [newBlockId, setNewBlockId] = useState(null);
2205
2422
  const [showSuggestions, setShowSuggestions] = useState(false);
2206
2423
  const [showExtensionSuggestions, setShowExtensionSuggestions] = useState(false);
2207
- const [isLoading, setIsLoading] = useState(!!(options == null ? void 0 : options.initialUrl));
2424
+ const [isLoading, setIsLoading] = useState(
2425
+ !!((options == null ? void 0 : options.initialUrl) || (options == null ? void 0 : options.blocks) && options.blocks.length > 0)
2426
+ );
2208
2427
  const [enhancingBlockId, setEnhancingBlockId] = useState(null);
2209
2428
  const [enhancementSuggestion, setEnhancementSuggestion] = useState(null);
2210
2429
  const [isEnhancing, setIsEnhancing] = useState(false);
@@ -2213,13 +2432,21 @@ function useScreenplayEditor(options) {
2213
2432
  const popoverTimeoutRef = useRef(null);
2214
2433
  const blurTimeout = useRef(null);
2215
2434
  const isInitialLoadRef = useRef(true);
2435
+ const skipAutosaveRef = useRef(false);
2436
+ const isWaitingForDOMRef = useRef(
2437
+ !!((options == null ? void 0 : options.initialUrl) || (options == null ? void 0 : options.blocks) && options.blocks.length > 0)
2438
+ );
2216
2439
  const loadedUrlRef = useRef(null);
2217
2440
  const lastSavedContent = useRef(null);
2218
2441
  const onSaveRef = useRef(options == null ? void 0 : options.onSave);
2442
+ const onSaveBlobRef = useRef(options == null ? void 0 : options.onSaveBlob);
2219
2443
  const onSyncWithCloudRef = useRef(options == null ? void 0 : options.onSyncWithCloud);
2444
+ const [autosaveStatus, setAutosaveStatus] = useState("idle");
2445
+ const isLocked = (_a = options == null ? void 0 : options.isLocked) != null ? _a : false;
2220
2446
  const [currentLanguage, setCurrentLanguage] = useState("English");
2221
2447
  const [lastPhoneticAction, setLastPhoneticAction] = useState(null);
2222
2448
  const [phoneticSuggestions, setPhoneticSuggestions] = useState([]);
2449
+ const lastSyncedTextRef = useRef({});
2223
2450
  useEffect(() => {
2224
2451
  setLastPhoneticAction(null);
2225
2452
  setPhoneticSuggestions([]);
@@ -2232,8 +2459,75 @@ function useScreenplayEditor(options) {
2232
2459
  }, [currentLanguage]);
2233
2460
  useEffect(() => {
2234
2461
  onSaveRef.current = options == null ? void 0 : options.onSave;
2462
+ onSaveBlobRef.current = options == null ? void 0 : options.onSaveBlob;
2235
2463
  onSyncWithCloudRef.current = options == null ? void 0 : options.onSyncWithCloud;
2236
- }, [options == null ? void 0 : options.onSave, options == null ? void 0 : options.onSyncWithCloud]);
2464
+ }, [options == null ? void 0 : options.onSave, options == null ? void 0 : options.onSaveBlob, options == null ? void 0 : options.onSyncWithCloud]);
2465
+ const isFirstAutosaveRender = useRef(true);
2466
+ const prevBlocksRef = useRef(blocks);
2467
+ useEffect(() => {
2468
+ if (isLocked) {
2469
+ setAutosaveStatus("idle");
2470
+ return;
2471
+ }
2472
+ if (isFirstAutosaveRender.current) {
2473
+ isFirstAutosaveRender.current = false;
2474
+ prevBlocksRef.current = blocks;
2475
+ return;
2476
+ }
2477
+ if (skipAutosaveRef.current) {
2478
+ skipAutosaveRef.current = false;
2479
+ prevBlocksRef.current = blocks;
2480
+ return;
2481
+ }
2482
+ const hasChanged = blocks.length !== prevBlocksRef.current.length || blocks.some((b, i) => b !== prevBlocksRef.current[i]);
2483
+ if (!hasChanged) {
2484
+ return;
2485
+ }
2486
+ setAutosaveStatus("typing");
2487
+ prevBlocksRef.current = blocks;
2488
+ const timer = setTimeout(async () => {
2489
+ if (onSaveRef.current) {
2490
+ setAutosaveStatus("saving");
2491
+ try {
2492
+ await onSaveRef.current(blocks);
2493
+ setAutosaveStatus("saved");
2494
+ setTimeout(() => {
2495
+ setAutosaveStatus((prev) => prev === "saved" ? "idle" : prev);
2496
+ }, 2e3);
2497
+ } catch (error) {
2498
+ console.error("Autosave failed:", error);
2499
+ setAutosaveStatus("error");
2500
+ }
2501
+ } else {
2502
+ setAutosaveStatus("idle");
2503
+ }
2504
+ }, 3e3);
2505
+ return () => clearTimeout(timer);
2506
+ }, [blocks, isLocked]);
2507
+ const latestBlocksRef = useRef(blocks);
2508
+ useEffect(() => {
2509
+ latestBlocksRef.current = blocks;
2510
+ }, [blocks]);
2511
+ useEffect(() => {
2512
+ const handleBeforeUnload = (e) => {
2513
+ if (autosaveStatus === "typing" || autosaveStatus === "saving") {
2514
+ e.preventDefault();
2515
+ e.returnValue = "Changes you made may not be saved.";
2516
+ return e.returnValue;
2517
+ }
2518
+ };
2519
+ window.addEventListener("beforeunload", handleBeforeUnload);
2520
+ return () => {
2521
+ window.removeEventListener("beforeunload", handleBeforeUnload);
2522
+ };
2523
+ }, [autosaveStatus]);
2524
+ useEffect(() => {
2525
+ return () => {
2526
+ if (autosaveStatus === "typing" && onSaveRef.current) {
2527
+ onSaveRef.current(latestBlocksRef.current);
2528
+ }
2529
+ };
2530
+ }, [autosaveStatus]);
2237
2531
  const characterExtensions = useMemo(
2238
2532
  () => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
2239
2533
  []
@@ -2248,37 +2542,43 @@ function useScreenplayEditor(options) {
2248
2542
  },
2249
2543
  []
2250
2544
  );
2251
- const locations = useMemo(() => {
2252
- const locs = blocks.filter((b) => b.type === "SCENE_HEADING" && b.text.trim() !== "").map((b) => b.text.trim().toUpperCase());
2253
- return [...new Set(locs)];
2254
- }, [blocks]);
2255
- const characters = useMemo(() => {
2256
- const chars = blocks.filter((b) => b.type === "CHARACTER" && b.text.trim() !== "").map((b) => {
2257
- const text = b.text.trim().toUpperCase();
2258
- const parenIndex = text.indexOf("(");
2259
- if (parenIndex > -1) {
2260
- return text.substring(0, parenIndex).trim();
2261
- }
2262
- return text;
2263
- }).filter(Boolean);
2264
- return [...new Set(chars)];
2265
- }, [blocks]);
2266
- const sceneNumbers = useMemo(() => {
2267
- const map = {};
2545
+ const { locations, characters, sceneNumbers } = useMemo(() => {
2546
+ const locsSet = /* @__PURE__ */ new Set();
2547
+ const charsSet = /* @__PURE__ */ new Set();
2548
+ const sceneNumMap = {};
2268
2549
  let fallbackCount = 0;
2269
2550
  blocks.forEach((block) => {
2551
+ const textTrim = block.text.trim();
2270
2552
  if (block.type === "SCENE_HEADING") {
2553
+ if (textTrim !== "") {
2554
+ locsSet.add(textTrim.toUpperCase());
2555
+ }
2271
2556
  if (block.sceneNumber) {
2272
- map[block.id] = block.sceneNumber;
2557
+ sceneNumMap[block.id] = block.sceneNumber;
2273
2558
  const base = parseInt(block.sceneNumber);
2274
2559
  if (!isNaN(base)) fallbackCount = Math.max(fallbackCount, base);
2275
2560
  } else {
2276
2561
  fallbackCount++;
2277
- map[block.id] = String(fallbackCount);
2562
+ sceneNumMap[block.id] = String(fallbackCount);
2563
+ }
2564
+ } else if (block.type === "CHARACTER") {
2565
+ if (textTrim !== "") {
2566
+ const textUpper = textTrim.toUpperCase();
2567
+ const parenIndex = textUpper.indexOf("(");
2568
+ if (parenIndex > -1) {
2569
+ const charName = textUpper.substring(0, parenIndex).trim();
2570
+ if (charName) charsSet.add(charName);
2571
+ } else {
2572
+ charsSet.add(textUpper);
2573
+ }
2278
2574
  }
2279
2575
  }
2280
2576
  });
2281
- return map;
2577
+ return {
2578
+ locations: Array.from(locsSet),
2579
+ characters: Array.from(charsSet),
2580
+ sceneNumbers: sceneNumMap
2581
+ };
2282
2582
  }, [blocks]);
2283
2583
  useEffect(() => {
2284
2584
  if (newBlockId && refs.current[newBlockId]) {
@@ -2286,7 +2586,8 @@ function useScreenplayEditor(options) {
2286
2586
  const el = refs.current[newBlockId];
2287
2587
  if (el && block) {
2288
2588
  el.focus();
2289
- el.innerText = block.text;
2589
+ el.textContent = block.text;
2590
+ lastSyncedTextRef.current[newBlockId] = block.text;
2290
2591
  if (block.type === "PARENTHETICAL") {
2291
2592
  setTimeout(() => setCaretPosition(el, 1), 0);
2292
2593
  } else {
@@ -2301,11 +2602,51 @@ function useScreenplayEditor(options) {
2301
2602
  blocks.forEach((block) => {
2302
2603
  const element = refs.current[block.id];
2303
2604
  if (element) {
2304
- if (element.innerText !== block.text && document.activeElement !== element) {
2305
- element.innerText = block.text;
2605
+ if (lastSyncedTextRef.current[block.id] !== block.text && document.activeElement !== element) {
2606
+ element.textContent = block.text;
2607
+ lastSyncedTextRef.current[block.id] = block.text;
2306
2608
  }
2307
2609
  }
2308
2610
  });
2611
+ if (isWaitingForDOMRef.current) {
2612
+ const dismissLoader = () => {
2613
+ if (typeof window !== "undefined") {
2614
+ void document.body.scrollHeight;
2615
+ }
2616
+ setIsLoading(false);
2617
+ isWaitingForDOMRef.current = false;
2618
+ };
2619
+ const waitForAllReady = async () => {
2620
+ if (typeof window !== "undefined") {
2621
+ try {
2622
+ if (document.fonts && document.fonts.ready) {
2623
+ await document.fonts.ready;
2624
+ }
2625
+ } catch (e) {
2626
+ console.error("Font loading detection failed:", e);
2627
+ }
2628
+ }
2629
+ if (typeof window !== "undefined" && "requestIdleCallback" in window) {
2630
+ requestAnimationFrame(() => {
2631
+ requestAnimationFrame(() => {
2632
+ window.requestIdleCallback(
2633
+ () => {
2634
+ setTimeout(dismissLoader, 150);
2635
+ },
2636
+ { timeout: 2e3 }
2637
+ );
2638
+ });
2639
+ });
2640
+ } else {
2641
+ requestAnimationFrame(() => {
2642
+ requestAnimationFrame(() => {
2643
+ setTimeout(dismissLoader, 400);
2644
+ });
2645
+ });
2646
+ }
2647
+ };
2648
+ waitForAllReady();
2649
+ }
2309
2650
  }, [blocks]);
2310
2651
  useEffect(() => {
2311
2652
  const handleClickOutside = (e) => {
@@ -2361,9 +2702,12 @@ function useScreenplayEditor(options) {
2361
2702
  const offset = getCaretCharacterOffsetWithin(el);
2362
2703
  const charsBeforeCaret = text.substring(0, offset).replace(/[()]/g, "").length;
2363
2704
  const newOffset = 1 + charsBeforeCaret;
2364
- el.innerText = processedText;
2705
+ el.textContent = processedText;
2706
+ lastSyncedTextRef.current[id] = processedText;
2365
2707
  setCaretPosition(el, newOffset);
2366
2708
  }
2709
+ } else {
2710
+ lastSyncedTextRef.current[id] = text;
2367
2711
  }
2368
2712
  },
2369
2713
  [blocks, showExtensionSuggestions]
@@ -2374,8 +2718,8 @@ function useScreenplayEditor(options) {
2374
2718
  (bs) => updateBlock(bs, id, "sceneType", sceneType)
2375
2719
  );
2376
2720
  setTimeout(() => {
2377
- var _a;
2378
- (_a = refs.current[id]) == null ? void 0 : _a.focus();
2721
+ var _a2;
2722
+ (_a2 = refs.current[id]) == null ? void 0 : _a2.focus();
2379
2723
  setFocusedBlockId(id);
2380
2724
  }, 10);
2381
2725
  },
@@ -2384,8 +2728,8 @@ function useScreenplayEditor(options) {
2384
2728
  const handleTimeOfDayChange = useCallback((id, time) => {
2385
2729
  setBlocks((bs) => updateBlock(bs, id, "timeOfDay", time));
2386
2730
  setTimeout(() => {
2387
- var _a;
2388
- (_a = refs.current[id]) == null ? void 0 : _a.focus();
2731
+ var _a2;
2732
+ (_a2 = refs.current[id]) == null ? void 0 : _a2.focus();
2389
2733
  setFocusedBlockId(id);
2390
2734
  }, 10);
2391
2735
  }, []);
@@ -2486,7 +2830,7 @@ function useScreenplayEditor(options) {
2486
2830
  };
2487
2831
  const handleKeyDown = useCallback(
2488
2832
  (e, id, text) => {
2489
- var _a;
2833
+ var _a2;
2490
2834
  if (currentLanguage !== "English") {
2491
2835
  const config = LANGUAGE_CONFIGS[currentLanguage];
2492
2836
  const char = getMappedCharacter(
@@ -2653,7 +2997,7 @@ function useScreenplayEditor(options) {
2653
2997
  const range = selection.getRangeAt(0);
2654
2998
  const contentEditable = e.currentTarget;
2655
2999
  const container = range.endContainer;
2656
- const isAtEndOffset = range.endOffset === (container.nodeType === Node.TEXT_NODE ? (_a = container.textContent) == null ? void 0 : _a.length : container.childNodes.length);
3000
+ const isAtEndOffset = range.endOffset === (container.nodeType === Node.TEXT_NODE ? (_a2 = container.textContent) == null ? void 0 : _a2.length : container.childNodes.length);
2657
3001
  if (isAtEndOffset) {
2658
3002
  let atEnd = false;
2659
3003
  let node = container;
@@ -2709,6 +3053,9 @@ function useScreenplayEditor(options) {
2709
3053
  parsedBlocks = parseScreenplayText(content);
2710
3054
  }
2711
3055
  if (parsedBlocks.length > 0) {
3056
+ setIsLoading(true);
3057
+ isWaitingForDOMRef.current = true;
3058
+ skipAutosaveRef.current = true;
2712
3059
  let fallbackCount = 1;
2713
3060
  const finalizedBlocks = parsedBlocks.map((block) => {
2714
3061
  if (block.type === "SCENE_HEADING") {
@@ -2723,25 +3070,30 @@ function useScreenplayEditor(options) {
2723
3070
  }
2724
3071
  return block;
2725
3072
  });
2726
- setBlocks(finalizedBlocks);
2727
- if (onSaveRef.current) {
2728
- const sbxData = serializeToSbx(finalizedBlocks);
2729
- if (sbxData !== lastSavedContent.current) {
2730
- lastSavedContent.current = sbxData;
2731
- if (!isInitialLoad) {
2732
- const blob = new Blob([sbxData], { type: "text/plain" });
2733
- onSaveRef.current(blob);
2734
- }
2735
- }
2736
- }
2737
3073
  setTimeout(() => {
2738
- var _a;
2739
- const firstId = parsedBlocks[0].id;
2740
- if (firstId && refs.current[firstId]) {
2741
- setFocusedBlockId(firstId);
2742
- (_a = refs.current[firstId]) == null ? void 0 : _a.focus();
3074
+ setBlocks(finalizedBlocks);
3075
+ if (onSaveBlobRef.current) {
3076
+ const sbxData = serializeToSbx(finalizedBlocks);
3077
+ if (sbxData !== lastSavedContent.current) {
3078
+ lastSavedContent.current = sbxData;
3079
+ if (!isInitialLoad) {
3080
+ const blob = new Blob([sbxData], { type: "text/plain" });
3081
+ onSaveBlobRef.current(blob);
3082
+ }
3083
+ }
2743
3084
  }
2744
- }, 100);
3085
+ setTimeout(() => {
3086
+ var _a2;
3087
+ const firstId = parsedBlocks[0].id;
3088
+ if (firstId && refs.current[firstId]) {
3089
+ setFocusedBlockId(firstId);
3090
+ (_a2 = refs.current[firstId]) == null ? void 0 : _a2.focus();
3091
+ }
3092
+ }, 100);
3093
+ }, 50);
3094
+ } else {
3095
+ setIsLoading(false);
3096
+ isWaitingForDOMRef.current = false;
2745
3097
  }
2746
3098
  },
2747
3099
  [refs]
@@ -2812,7 +3164,7 @@ function useScreenplayEditor(options) {
2812
3164
  }, []);
2813
3165
  const loadFromUrl = useCallback(
2814
3166
  async (url, fetchOptions = {}, isInitialLoad) => {
2815
- var _a;
3167
+ var _a2;
2816
3168
  setIsLoading(true);
2817
3169
  try {
2818
3170
  const response = await fetch(url, fetchOptions);
@@ -2824,7 +3176,15 @@ function useScreenplayEditor(options) {
2824
3176
  let text = await response.text();
2825
3177
  let preParsedBlocks = void 0;
2826
3178
  let scriptContent = text;
2827
- if (text.includes('class="divtype') || url.toLowerCase().includes(".sbx")) {
3179
+ try {
3180
+ const parsed = JSON.parse(text);
3181
+ if (Array.isArray(parsed)) {
3182
+ preParsedBlocks = parsed;
3183
+ scriptContent = "";
3184
+ }
3185
+ } catch (e) {
3186
+ }
3187
+ if (!preParsedBlocks && (text.includes('class="divtype') || url.toLowerCase().includes(".sbx"))) {
2828
3188
  if (text.includes("<div")) {
2829
3189
  const textarea = document.createElement("textarea");
2830
3190
  textarea.innerHTML = text;
@@ -2843,8 +3203,8 @@ function useScreenplayEditor(options) {
2843
3203
  divtype6: "TRANSITION"
2844
3204
  };
2845
3205
  divs.forEach((div) => {
2846
- var _a2;
2847
- let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
3206
+ var _a3;
3207
+ let divText = ((_a3 = div.textContent) == null ? void 0 : _a3.trim()) || "";
2848
3208
  if (!divText) return;
2849
3209
  let type = "ACTION";
2850
3210
  for (const className of Array.from(div.classList)) {
@@ -2883,15 +3243,18 @@ function useScreenplayEditor(options) {
2883
3243
  scriptContent = "";
2884
3244
  }
2885
3245
  }
2886
- const filename = ((_a = url.split("/").pop()) == null ? void 0 : _a.replace(/\.sbx$/i, "")) || "Imported from URL";
3246
+ const filename = ((_a2 = url.split("/").pop()) == null ? void 0 : _a2.replace(/\.sbx$/i, "")) || "Imported from URL";
3247
+ isWaitingForDOMRef.current = true;
2887
3248
  handleScriptImport(
2888
3249
  filename,
2889
3250
  scriptContent,
2890
3251
  preParsedBlocks,
2891
3252
  isInitialLoad
2892
3253
  );
2893
- } finally {
3254
+ } catch (error) {
3255
+ console.error("Failed to load screenplay from URL:", error);
2894
3256
  setIsLoading(false);
3257
+ isWaitingForDOMRef.current = false;
2895
3258
  }
2896
3259
  },
2897
3260
  [handleScriptImport]
@@ -2901,28 +3264,45 @@ function useScreenplayEditor(options) {
2901
3264
  isInitialLoadRef.current = true;
2902
3265
  return;
2903
3266
  }
2904
- const currentSbx = serializeToSbx(blocks);
2905
- if (isInitialLoadRef.current) {
2906
- if (lastSavedContent.current === null) {
2907
- lastSavedContent.current = currentSbx;
3267
+ const handler = setTimeout(() => {
3268
+ const runSerialization = () => {
3269
+ const currentSbx = serializeToSbx(blocks);
3270
+ if (isInitialLoadRef.current) {
3271
+ if (lastSavedContent.current === null) {
3272
+ lastSavedContent.current = currentSbx;
3273
+ }
3274
+ isInitialLoadRef.current = false;
3275
+ return;
3276
+ }
3277
+ const hasActualChanges = lastSavedContent.current !== null && currentSbx !== lastSavedContent.current;
3278
+ if (hasActualChanges) {
3279
+ setHasUnsavedChanges(true);
3280
+ if (popoverTimeoutRef.current)
3281
+ clearTimeout(popoverTimeoutRef.current);
3282
+ setShowUnsavedPopover(false);
3283
+ popoverTimeoutRef.current = setTimeout(() => {
3284
+ setShowUnsavedPopover(true);
3285
+ }, 1e3);
3286
+ } else {
3287
+ setHasUnsavedChanges(false);
3288
+ setShowUnsavedPopover(false);
3289
+ if (popoverTimeoutRef.current)
3290
+ clearTimeout(popoverTimeoutRef.current);
3291
+ }
3292
+ };
3293
+ if (typeof window !== "undefined" && "requestIdleCallback" in window) {
3294
+ window.requestIdleCallback(
3295
+ () => {
3296
+ runSerialization();
3297
+ },
3298
+ { timeout: 1e3 }
3299
+ );
3300
+ } else {
3301
+ runSerialization();
2908
3302
  }
2909
- isInitialLoadRef.current = false;
2910
- return;
2911
- }
2912
- const hasActualChanges = lastSavedContent.current !== null && currentSbx !== lastSavedContent.current;
2913
- if (hasActualChanges) {
2914
- setHasUnsavedChanges(true);
2915
- if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
2916
- setShowUnsavedPopover(false);
2917
- popoverTimeoutRef.current = setTimeout(() => {
2918
- setShowUnsavedPopover(true);
2919
- }, 1e3);
2920
- } else {
2921
- setHasUnsavedChanges(false);
2922
- setShowUnsavedPopover(false);
2923
- if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
2924
- }
3303
+ }, 250);
2925
3304
  return () => {
3305
+ clearTimeout(handler);
2926
3306
  if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
2927
3307
  };
2928
3308
  }, [blocks, isLoading]);
@@ -3012,7 +3392,9 @@ function useScreenplayEditor(options) {
3012
3392
  currentLanguage,
3013
3393
  setCurrentLanguage,
3014
3394
  phoneticSuggestions,
3015
- handleSelectPhoneticSuggestion
3395
+ handleSelectPhoneticSuggestion,
3396
+ isLocked,
3397
+ autosaveStatus
3016
3398
  };
3017
3399
  }
3018
3400
 
@@ -3297,7 +3679,369 @@ var SummarizeButton = ({
3297
3679
  }
3298
3680
  );
3299
3681
  };
3300
- var summarize_button_default = SummarizeButton;
3682
+ var summarize_button_default = SummarizeButton;
3683
+
3684
+ // data/crowd-data.ts
3685
+ var crowdAgeOption = [
3686
+ { name: "Adult" },
3687
+ { name: "Old" },
3688
+ { name: "Teenage" },
3689
+ { name: "Kid" }
3690
+ ];
3691
+ var crowdTypeOption = [{ name: "Male" }, { name: "Female" }];
3692
+ var FormikSelect = ({
3693
+ label,
3694
+ name,
3695
+ selectedOption,
3696
+ optionData,
3697
+ value,
3698
+ disable,
3699
+ divClasses,
3700
+ valueProperty = "name",
3701
+ labelProperty = "name",
3702
+ label2propery,
3703
+ brackets,
3704
+ className,
3705
+ enableRedAsterick = false,
3706
+ disableOptionProperty = "disable",
3707
+ disabledOptionText = "",
3708
+ onChange
3709
+ }) => {
3710
+ return /* @__PURE__ */ jsxs("div", { className: `w-full ${divClasses}`, children: [
3711
+ label && /* @__PURE__ */ jsxs(
3712
+ "label",
3713
+ {
3714
+ className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
3715
+ children: [
3716
+ label,
3717
+ enableRedAsterick && /* @__PURE__ */ jsx(AsteriskIcon, { className: "size-3 text-red-500" })
3718
+ ]
3719
+ }
3720
+ ),
3721
+ /* @__PURE__ */ jsxs(
3722
+ Field,
3723
+ {
3724
+ name,
3725
+ as: "select",
3726
+ value,
3727
+ disabled: disable,
3728
+ onChange,
3729
+ 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`,
3730
+ children: [
3731
+ /* @__PURE__ */ jsx("option", { selected: true, value: "", disabled: true, className: "capitalize", children: selectedOption }),
3732
+ optionData == null ? void 0 : optionData.map((option, index) => /* @__PURE__ */ jsxs(
3733
+ "option",
3734
+ {
3735
+ value: option[valueProperty],
3736
+ disabled: option[disableOptionProperty],
3737
+ children: [
3738
+ option[labelProperty],
3739
+ label2propery ? brackets ? ` (${option[label2propery]})` : option[label2propery] : "",
3740
+ " ",
3741
+ option[disableOptionProperty] && `(${disabledOptionText})`
3742
+ ]
3743
+ },
3744
+ index
3745
+ ))
3746
+ ]
3747
+ }
3748
+ ),
3749
+ /* @__PURE__ */ jsx(
3750
+ ErrorMessage,
3751
+ {
3752
+ name,
3753
+ className: "text-red-500 text-sm mt-1",
3754
+ component: "div"
3755
+ }
3756
+ )
3757
+ ] });
3758
+ };
3759
+ var FormikInput = (_a) => {
3760
+ var _b = _a, {
3761
+ label,
3762
+ name,
3763
+ type,
3764
+ placeholder,
3765
+ className,
3766
+ labelClassName,
3767
+ readOnly,
3768
+ divClasses,
3769
+ length,
3770
+ disable,
3771
+ min = 0,
3772
+ max,
3773
+ convertToText = false,
3774
+ enableRedAsterick = false,
3775
+ case_sensitivity = "normal"
3776
+ } = _b, props = __objRest(_b, [
3777
+ "label",
3778
+ "name",
3779
+ "type",
3780
+ "placeholder",
3781
+ "className",
3782
+ "labelClassName",
3783
+ "readOnly",
3784
+ "divClasses",
3785
+ "length",
3786
+ "disable",
3787
+ "min",
3788
+ "max",
3789
+ "convertToText",
3790
+ "enableRedAsterick",
3791
+ "case_sensitivity"
3792
+ ]);
3793
+ const { setFieldValue } = useFormikContext();
3794
+ const handleCaseChange = (e) => {
3795
+ let value = e.target.value;
3796
+ if (type === "number" && min !== void 0) {
3797
+ if (value !== "" && Number(value) < min) return;
3798
+ }
3799
+ switch (case_sensitivity) {
3800
+ case "lowercase":
3801
+ value = value.toLowerCase();
3802
+ break;
3803
+ case "uppercase":
3804
+ value = value.toUpperCase();
3805
+ break;
3806
+ }
3807
+ setFieldValue(name, value);
3808
+ };
3809
+ return /* @__PURE__ */ jsxs("div", { className: `w-full ${divClasses}`, children: [
3810
+ /* @__PURE__ */ jsxs(
3811
+ "label",
3812
+ {
3813
+ className: `${labelClassName} mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
3814
+ children: [
3815
+ label,
3816
+ enableRedAsterick && /* @__PURE__ */ jsx(AsteriskIcon, { className: "size-3 text-red-500" })
3817
+ ]
3818
+ }
3819
+ ),
3820
+ /* @__PURE__ */ jsx(
3821
+ Field,
3822
+ __spreadProps(__spreadValues({
3823
+ name,
3824
+ placeholder,
3825
+ readOnly,
3826
+ type,
3827
+ maxLength: length,
3828
+ disabled: disable,
3829
+ max,
3830
+ min,
3831
+ onChange: handleCaseChange
3832
+ }, props), {
3833
+ 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`
3834
+ })
3835
+ ),
3836
+ /* @__PURE__ */ jsx(
3837
+ ErrorMessage,
3838
+ {
3839
+ name,
3840
+ className: "text-red-500 text-sm mt-1",
3841
+ component: "div"
3842
+ }
3843
+ )
3844
+ ] });
3845
+ };
3846
+ var FormikTextarea = ({
3847
+ label,
3848
+ name,
3849
+ placeholder,
3850
+ readOnly,
3851
+ divClasses = "",
3852
+ className = "",
3853
+ length,
3854
+ disable,
3855
+ min,
3856
+ max,
3857
+ enableRedAsterick = false
3858
+ }) => {
3859
+ return /* @__PURE__ */ jsxs("div", { className: `w-full ${divClasses}`, children: [
3860
+ /* @__PURE__ */ jsxs(
3861
+ "label",
3862
+ {
3863
+ className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
3864
+ children: [
3865
+ label,
3866
+ enableRedAsterick && /* @__PURE__ */ jsx(AsteriskIcon, { className: "size-3 text-red-500" })
3867
+ ]
3868
+ }
3869
+ ),
3870
+ /* @__PURE__ */ jsx(
3871
+ Field,
3872
+ {
3873
+ as: "textarea",
3874
+ name,
3875
+ placeholder,
3876
+ readOnly,
3877
+ maxLength: length,
3878
+ disabled: disable,
3879
+ max,
3880
+ min,
3881
+ 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`
3882
+ }
3883
+ ),
3884
+ /* @__PURE__ */ jsx(
3885
+ ErrorMessage,
3886
+ {
3887
+ name,
3888
+ className: "text-red-500 text-sm mt-1",
3889
+ component: "div"
3890
+ }
3891
+ )
3892
+ ] });
3893
+ };
3894
+ var Switch = ({
3895
+ isOn,
3896
+ handleToggle,
3897
+ activeColor = "bg-green-500",
3898
+ inactiveColor = "bg-gray-300",
3899
+ size = "medium",
3900
+ onLabel,
3901
+ offLabel,
3902
+ label,
3903
+ divClasses,
3904
+ labelClasses,
3905
+ disable = false
3906
+ }) => {
3907
+ const sizeClasses = {
3908
+ small: { width: 28, height: 18, handle: 12, labelSize: 12, gap: 4 },
3909
+ medium: { width: 48, height: 28, handle: 20, labelSize: 16, gap: 6 },
3910
+ large: { width: 64, height: 36, handle: 28, labelSize: 20, gap: 10 }
3911
+ };
3912
+ const selectedSize = sizeClasses[size] || sizeClasses.medium;
3913
+ return /* @__PURE__ */ jsxs("div", { className: `w-full ${divClasses}`, children: [
3914
+ label && /* @__PURE__ */ jsx(
3915
+ "label",
3916
+ {
3917
+ className: `block mb-2 text-sm text-gray-600 ${disable && "text-gray-400!"} ${labelClasses}`,
3918
+ children: label
3919
+ }
3920
+ ),
3921
+ /* @__PURE__ */ jsxs("div", { style: { gap: selectedSize.gap }, className: "flex items-center", children: [
3922
+ /* @__PURE__ */ jsx(
3923
+ "div",
3924
+ {
3925
+ className: `flex items-center rounded-full cursor-pointer relative ${isOn ? activeColor : inactiveColor} ${disable && "opacity-50 cursor-not-allowed"}`,
3926
+ onClick: disable ? () => {
3927
+ } : handleToggle,
3928
+ role: "button",
3929
+ "aria-pressed": isOn,
3930
+ style: {
3931
+ width: selectedSize.width,
3932
+ height: selectedSize.height
3933
+ },
3934
+ children: /* @__PURE__ */ jsx(
3935
+ "div",
3936
+ {
3937
+ className: "bg-white rounded-full shadow-sm ease-in duration-200",
3938
+ style: {
3939
+ width: selectedSize.handle,
3940
+ height: selectedSize.handle,
3941
+ transform: `translateX(${isOn ? selectedSize.width - selectedSize.handle - 3 : 3}px)`,
3942
+ transition: "transform 0.2s ease-in-out"
3943
+ }
3944
+ }
3945
+ )
3946
+ }
3947
+ ),
3948
+ onLabel && offLabel && /* @__PURE__ */ jsx("span", { style: { fontSize: selectedSize.labelSize }, children: isOn ? onLabel : offLabel })
3949
+ ] })
3950
+ ] });
3951
+ };
3952
+ var MultiSelect = ({
3953
+ label,
3954
+ options,
3955
+ value,
3956
+ onChange,
3957
+ placeholder = "Select options...",
3958
+ valueProperty = "name",
3959
+ labelProperty = "name",
3960
+ divClasses = "",
3961
+ returnObjects = false
3962
+ }) => {
3963
+ const [isOpen, setIsOpen] = React4.useState(false);
3964
+ const containerRef = React4.useRef(null);
3965
+ const isSelected = (optionValue) => {
3966
+ return value.some(
3967
+ (v) => typeof v === "object" && v !== null ? v[valueProperty] === optionValue : v === optionValue
3968
+ );
3969
+ };
3970
+ const toggleOption = (optionValue) => {
3971
+ let newValues;
3972
+ if (isSelected(optionValue)) {
3973
+ newValues = value.filter(
3974
+ (v) => typeof v === "object" && v !== null ? v[valueProperty] !== optionValue : v !== optionValue
3975
+ );
3976
+ } else {
3977
+ const newValue = returnObjects ? options.find((opt) => opt[valueProperty] === optionValue) : optionValue;
3978
+ newValues = [...value, newValue];
3979
+ }
3980
+ onChange(newValues);
3981
+ };
3982
+ const removeOption = (e, optionValue) => {
3983
+ e.stopPropagation();
3984
+ const newValues = value.filter(
3985
+ (v) => typeof v === "object" && v !== null ? v[valueProperty] !== optionValue : v !== optionValue
3986
+ );
3987
+ onChange(newValues);
3988
+ };
3989
+ React4.useEffect(() => {
3990
+ const handleClickOutside = (event) => {
3991
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
3992
+ setIsOpen(false);
3993
+ }
3994
+ };
3995
+ document.addEventListener("mousedown", handleClickOutside);
3996
+ return () => document.removeEventListener("mousedown", handleClickOutside);
3997
+ }, []);
3998
+ return /* @__PURE__ */ jsxs("div", { className: `w-full relative ${divClasses}`, ref: containerRef, children: [
3999
+ label && /* @__PURE__ */ jsx("label", { className: "mb-1.5 text-xs font-bold text-slate-600 ml-1 uppercase tracking-wider", children: label }),
4000
+ /* @__PURE__ */ jsx(
4001
+ "div",
4002
+ {
4003
+ onClick: () => setIsOpen(!isOpen),
4004
+ 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"}`,
4005
+ children: value.length === 0 ? /* @__PURE__ */ jsx("span", { className: "text-slate-400 text-[13px] ml-1", children: placeholder }) : value.map((val) => {
4006
+ const actualValue = typeof val === "object" && val !== null ? val[valueProperty] : val;
4007
+ const option = options.find(
4008
+ (opt) => opt[valueProperty] === actualValue
4009
+ );
4010
+ return /* @__PURE__ */ jsxs(
4011
+ "div",
4012
+ {
4013
+ 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",
4014
+ children: [
4015
+ option ? option[labelProperty] : actualValue,
4016
+ /* @__PURE__ */ jsx(
4017
+ "button",
4018
+ {
4019
+ type: "button",
4020
+ onClick: (e) => removeOption(e, actualValue),
4021
+ className: "hover:text-red-500 transition-colors ml-0.5",
4022
+ children: "\xD7"
4023
+ }
4024
+ )
4025
+ ]
4026
+ },
4027
+ actualValue
4028
+ );
4029
+ })
4030
+ }
4031
+ ),
4032
+ isOpen && /* @__PURE__ */ 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__ */ jsx("div", { className: "p-1", children: options.filter((opt) => !isSelected(opt[valueProperty])).length > 0 ? options.filter((opt) => !isSelected(opt[valueProperty])).map((option, index) => {
4033
+ return /* @__PURE__ */ jsx(
4034
+ "div",
4035
+ {
4036
+ onClick: () => toggleOption(option[valueProperty]),
4037
+ 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",
4038
+ children: option[labelProperty]
4039
+ },
4040
+ index
4041
+ );
4042
+ }) : /* @__PURE__ */ jsx("div", { className: "px-3 py-3 text-[10px] text-slate-400 text-center font-bold uppercase tracking-wider", children: "All selected" }) }) })
4043
+ ] });
4044
+ };
3301
4045
  function ScriptBreakdownSceneView({
3302
4046
  blocks,
3303
4047
  characters,
@@ -3321,7 +4065,7 @@ function ScriptBreakdownSceneView({
3321
4065
  }) {
3322
4066
  const [expandedCategories, setExpandedCategories] = useState({});
3323
4067
  const [editingTagData, setEditingTagData] = useState(null);
3324
- const [tagForm, setTagForm] = useState({ quantity: 1, look: "", age: "" });
4068
+ const [tagForm, setTagForm] = useState({ quantity: 1, look: "", age: "", age_range: [], crowd_type: [] });
3325
4069
  const [popupPlacement, setPopupPlacement] = useState({
3326
4070
  alignRight: false,
3327
4071
  alignBottom: false
@@ -3682,7 +4426,7 @@ function ScriptBreakdownSceneView({
3682
4426
  title: tag.name,
3683
4427
  onClick: (e) => {
3684
4428
  e.stopPropagation();
3685
- if (cat.id !== "PROP" && cat.id !== "SET_PROP" && cat.id !== "CAST")
4429
+ if (cat.id !== "PROP" && cat.id !== "SET_PROP" && cat.id !== "CAST" && cat.id !== "EXTRA")
3686
4430
  return;
3687
4431
  if ((editingTagData == null ? void 0 : editingTagData.tag.id) === tag.id) {
3688
4432
  setEditingTagData(null);
@@ -3695,7 +4439,9 @@ function ScriptBreakdownSceneView({
3695
4439
  setTagForm({
3696
4440
  quantity: tag.quantity || 1,
3697
4441
  look: tag.look || "",
3698
- age: tag.age || ""
4442
+ age: tag.age || "",
4443
+ age_range: tag.age_range || [],
4444
+ crowd_type: tag.crowd_type || []
3699
4445
  });
3700
4446
  setEditingTagData({
3701
4447
  tag,
@@ -3705,7 +4451,7 @@ function ScriptBreakdownSceneView({
3705
4451
  });
3706
4452
  }
3707
4453
  },
3708
- 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" : ""}`,
4454
+ 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" : ""}`,
3709
4455
  style: {
3710
4456
  color: cat.color,
3711
4457
  background: `linear-gradient(145deg, ${cat.color}18, rgba(255,255,255,0.88))`,
@@ -3829,13 +4575,38 @@ function ScriptBreakdownSceneView({
3829
4575
  )
3830
4576
  ] })
3831
4577
  ] }),
4578
+ editingTagData.catId === "EXTRA" && /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-3", children: [
4579
+ /* @__PURE__ */ jsx(
4580
+ MultiSelect,
4581
+ {
4582
+ label: "Age Range",
4583
+ options: crowdAgeOption,
4584
+ value: tagForm.age_range,
4585
+ returnObjects: true,
4586
+ onChange: (val) => setTagForm((prev) => __spreadProps(__spreadValues({}, prev), { age_range: val }))
4587
+ }
4588
+ ),
4589
+ /* @__PURE__ */ jsx(
4590
+ MultiSelect,
4591
+ {
4592
+ label: "Crowd Type",
4593
+ options: crowdTypeOption,
4594
+ value: tagForm.crowd_type,
4595
+ returnObjects: true,
4596
+ onChange: (val) => setTagForm((prev) => __spreadProps(__spreadValues({}, prev), { crowd_type: val }))
4597
+ }
4598
+ )
4599
+ ] }),
3832
4600
  /* @__PURE__ */ jsx("div", { className: "mt-4", children: /* @__PURE__ */ jsx(
3833
4601
  "button",
3834
4602
  {
3835
4603
  onClick: (e) => {
3836
4604
  e.stopPropagation();
3837
4605
  if (editingTagData.tag.id) {
3838
- 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 } : {}));
4606
+ 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" ? {
4607
+ age_range: tagForm.age_range,
4608
+ crowd_type: tagForm.crowd_type
4609
+ } : {}));
3839
4610
  }
3840
4611
  setEditingTagData(null);
3841
4612
  },
@@ -4376,196 +5147,6 @@ function ModalLayout({
4376
5147
  );
4377
5148
  }
4378
5149
  var modal_layout_default = ModalLayout;
4379
- var FormikSelect = ({
4380
- label,
4381
- name,
4382
- selectedOption,
4383
- optionData,
4384
- value,
4385
- disable,
4386
- divClasses,
4387
- valueProperty = "name",
4388
- labelProperty = "name",
4389
- label2propery,
4390
- brackets,
4391
- className,
4392
- enableRedAsterick = false,
4393
- disableOptionProperty = "disable",
4394
- disabledOptionText = "",
4395
- onChange
4396
- }) => {
4397
- return /* @__PURE__ */ jsxs("div", { className: `w-full ${divClasses}`, children: [
4398
- label && /* @__PURE__ */ jsxs("label", { className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`, children: [
4399
- label,
4400
- enableRedAsterick && /* @__PURE__ */ jsx(AsteriskIcon, { className: "size-3 text-red-500" })
4401
- ] }),
4402
- /* @__PURE__ */ jsxs(
4403
- Field,
4404
- {
4405
- name,
4406
- as: "select",
4407
- value,
4408
- disabled: disable,
4409
- onChange,
4410
- 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`,
4411
- children: [
4412
- /* @__PURE__ */ jsx("option", { selected: true, value: "", disabled: true, className: "capitalize", children: selectedOption }),
4413
- optionData == null ? void 0 : optionData.map((option, index) => /* @__PURE__ */ jsxs(
4414
- "option",
4415
- {
4416
- value: option[valueProperty],
4417
- disabled: option[disableOptionProperty],
4418
- children: [
4419
- option[labelProperty],
4420
- label2propery ? brackets ? ` (${option[label2propery]})` : option[label2propery] : "",
4421
- " ",
4422
- option[disableOptionProperty] && `(${disabledOptionText})`
4423
- ]
4424
- },
4425
- index
4426
- ))
4427
- ]
4428
- }
4429
- ),
4430
- /* @__PURE__ */ jsx(
4431
- ErrorMessage,
4432
- {
4433
- name,
4434
- className: "text-red-500 text-sm mt-1",
4435
- component: "div"
4436
- }
4437
- )
4438
- ] });
4439
- };
4440
- var FormikInput = (_a) => {
4441
- var _b = _a, {
4442
- label,
4443
- name,
4444
- type,
4445
- placeholder,
4446
- className,
4447
- labelClassName,
4448
- readOnly,
4449
- divClasses,
4450
- length,
4451
- disable,
4452
- min = 0,
4453
- max,
4454
- convertToText = false,
4455
- enableRedAsterick = false,
4456
- case_sensitivity = "normal"
4457
- } = _b, props = __objRest(_b, [
4458
- "label",
4459
- "name",
4460
- "type",
4461
- "placeholder",
4462
- "className",
4463
- "labelClassName",
4464
- "readOnly",
4465
- "divClasses",
4466
- "length",
4467
- "disable",
4468
- "min",
4469
- "max",
4470
- "convertToText",
4471
- "enableRedAsterick",
4472
- "case_sensitivity"
4473
- ]);
4474
- const { setFieldValue } = useFormikContext();
4475
- const handleCaseChange = (e) => {
4476
- let value = e.target.value;
4477
- if (type === "number" && min !== void 0) {
4478
- if (value !== "" && Number(value) < min) return;
4479
- }
4480
- switch (case_sensitivity) {
4481
- case "lowercase":
4482
- value = value.toLowerCase();
4483
- break;
4484
- case "uppercase":
4485
- value = value.toUpperCase();
4486
- break;
4487
- }
4488
- setFieldValue(name, value);
4489
- };
4490
- return /* @__PURE__ */ jsxs("div", { className: `w-full ${divClasses}`, children: [
4491
- /* @__PURE__ */ jsxs(
4492
- "label",
4493
- {
4494
- className: `${labelClassName} mb-1.5 text-sm font-medium text-slate-700 capitalize flex`,
4495
- children: [
4496
- label,
4497
- enableRedAsterick && /* @__PURE__ */ jsx(AsteriskIcon, { className: "size-3 text-red-500" })
4498
- ]
4499
- }
4500
- ),
4501
- /* @__PURE__ */ jsx(
4502
- Field,
4503
- __spreadProps(__spreadValues({
4504
- name,
4505
- placeholder,
4506
- readOnly,
4507
- type,
4508
- maxLength: length,
4509
- disabled: disable,
4510
- max,
4511
- min,
4512
- onChange: handleCaseChange
4513
- }, props), {
4514
- 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`
4515
- })
4516
- ),
4517
- /* @__PURE__ */ jsx(
4518
- ErrorMessage,
4519
- {
4520
- name,
4521
- className: "text-red-500 text-sm mt-1",
4522
- component: "div"
4523
- }
4524
- )
4525
- ] });
4526
- };
4527
- var FormikTextarea = ({
4528
- label,
4529
- name,
4530
- placeholder,
4531
- readOnly,
4532
- divClasses = "",
4533
- className = "",
4534
- length,
4535
- disable,
4536
- min,
4537
- max,
4538
- enableRedAsterick = false
4539
- }) => {
4540
- return /* @__PURE__ */ jsxs("div", { className: `w-full ${divClasses}`, children: [
4541
- /* @__PURE__ */ jsxs("label", { className: `mb-1.5 text-sm font-medium text-slate-700 capitalize flex`, children: [
4542
- label,
4543
- enableRedAsterick && /* @__PURE__ */ jsx(AsteriskIcon, { className: "size-3 text-red-500" })
4544
- ] }),
4545
- /* @__PURE__ */ jsx(
4546
- Field,
4547
- {
4548
- as: "textarea",
4549
- name,
4550
- placeholder,
4551
- readOnly,
4552
- maxLength: length,
4553
- disabled: disable,
4554
- max,
4555
- min,
4556
- 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`
4557
- }
4558
- ),
4559
- /* @__PURE__ */ jsx(
4560
- ErrorMessage,
4561
- {
4562
- name,
4563
- className: "text-red-500 text-sm mt-1",
4564
- component: "div"
4565
- }
4566
- )
4567
- ] });
4568
- };
4569
5150
 
4570
5151
  // data/shot-data.ts
4571
5152
  var shot_types = [
@@ -5326,22 +5907,32 @@ var ProductionSetupModal = ({
5326
5907
  initialValues
5327
5908
  }) => {
5328
5909
  return /* @__PURE__ */ jsx("div", { className: "min-h-[80vh] flex items-center justify-center px-6", children: /* @__PURE__ */ jsxs("div", { className: "w-full max-w-lg", children: [
5329
- /* @__PURE__ */ jsxs("div", { className: "mb-8 text-center", children: [
5910
+ /* @__PURE__ */ jsxs("div", { className: "my-8 text-center", children: [
5330
5911
  /* @__PURE__ */ jsx("h1", { className: "text-2xl md:text-3xl font-semibold text-slate-900 tracking-tight", children: "Production Setup for this Scene" }),
5331
5912
  /* @__PURE__ */ jsx("p", { className: "text-sm text-slate-500 mt-2", children: "Configure your scene and camera setup to get started" })
5332
5913
  ] }),
5333
5914
  /* @__PURE__ */ jsx("div", { className: "p-6 md:p-8", children: /* @__PURE__ */ jsx(
5334
5915
  Formik,
5335
5916
  {
5336
- initialValues: initialValues || { numCameras: 1, scene_type: "" },
5917
+ initialValues: initialValues || {
5918
+ numCameras: 1,
5919
+ scene_type: "",
5920
+ dance_choreographer_required: false,
5921
+ action_sequence_required: false
5922
+ },
5337
5923
  validationSchema: Yup.object({
5338
5924
  numCameras: Yup.number().min(1, "Must be at least 1").max(20, "Cannot add more than 20 cameras").required("Number of cameras is required"),
5339
5925
  scene_type: Yup.string().required("Scene type is required")
5340
5926
  }),
5341
5927
  onSubmit: async (values) => {
5342
- await initializeProduction(values.numCameras, values.scene_type);
5928
+ await initializeProduction(
5929
+ values.numCameras,
5930
+ values.scene_type,
5931
+ values.dance_choreographer_required,
5932
+ values.action_sequence_required
5933
+ );
5343
5934
  },
5344
- children: ({ isSubmitting, setFieldValue }) => /* @__PURE__ */ jsxs(Form, { className: "flex flex-col gap-6", children: [
5935
+ children: ({ isSubmitting, setFieldValue, values }) => /* @__PURE__ */ jsxs(Form, { className: "flex flex-col gap-6", children: [
5345
5936
  /* @__PURE__ */ jsxs("div", { className: "grid gap-5", children: [
5346
5937
  /* @__PURE__ */ jsx(
5347
5938
  FormikSelect,
@@ -5364,7 +5955,65 @@ var ProductionSetupModal = ({
5364
5955
  max: 20,
5365
5956
  enableRedAsterick: true
5366
5957
  }
5367
- )
5958
+ ),
5959
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
5960
+ /* @__PURE__ */ jsx(
5961
+ "div",
5962
+ {
5963
+ 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"}`,
5964
+ onClick: () => setFieldValue(
5965
+ "dance_choreographer_required",
5966
+ !values.dance_choreographer_required
5967
+ ),
5968
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between w-full", children: [
5969
+ /* @__PURE__ */ jsxs("div", { children: [
5970
+ /* @__PURE__ */ jsx("p", { className: "text-[15px] font-bold text-slate-800", children: "Dance Sequence" }),
5971
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-slate-500 font-medium mt-0.5", children: "Choreography needed" })
5972
+ ] }),
5973
+ /* @__PURE__ */ jsx(
5974
+ Switch,
5975
+ {
5976
+ isOn: values.dance_choreographer_required || false,
5977
+ handleToggle: () => setFieldValue(
5978
+ "dance_choreographer_required",
5979
+ !values.dance_choreographer_required
5980
+ ),
5981
+ activeColor: "bg-blumine-600",
5982
+ divClasses: "w-fit!"
5983
+ }
5984
+ )
5985
+ ] })
5986
+ }
5987
+ ),
5988
+ /* @__PURE__ */ 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.action_sequence_required ? "bg-rose-50/30 border-rose-200 shadow-sm" : "bg-slate-50/50 border-slate-100 hover:border-slate-200"}`,
5992
+ onClick: () => setFieldValue(
5993
+ "action_sequence_required",
5994
+ !values.action_sequence_required
5995
+ ),
5996
+ children: /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between w-full", children: [
5997
+ /* @__PURE__ */ jsxs("div", { children: [
5998
+ /* @__PURE__ */ jsx("p", { className: "text-[15px] font-bold text-slate-800", children: "Action Sequence" }),
5999
+ /* @__PURE__ */ jsx("p", { className: "text-[11px] text-slate-500 font-medium mt-0.5", children: "Stunt & combat logic" })
6000
+ ] }),
6001
+ /* @__PURE__ */ jsx(
6002
+ Switch,
6003
+ {
6004
+ isOn: values.action_sequence_required || false,
6005
+ handleToggle: () => setFieldValue(
6006
+ "action_sequence_required",
6007
+ !values.action_sequence_required
6008
+ ),
6009
+ activeColor: "bg-rose-500",
6010
+ divClasses: "w-fit!"
6011
+ }
6012
+ )
6013
+ ] })
6014
+ }
6015
+ )
6016
+ ] })
5368
6017
  ] }),
5369
6018
  /* @__PURE__ */ jsxs("div", { className: "flex gap-3 bg-slate-50 border border-slate-100 p-4 rounded-xl", children: [
5370
6019
  /* @__PURE__ */ jsx(Info, { className: "w-5 h-5 text-slate-400 shrink-0 mt-0.5" }),
@@ -5906,14 +6555,21 @@ function ShotBreakdownView({
5906
6555
  children: /* @__PURE__ */ jsx(
5907
6556
  production_setup_modal_default,
5908
6557
  {
5909
- initializeProduction: (count, type) => {
5910
- initializeProduction(count, type).then(() => {
6558
+ initializeProduction: (count, type, dance_choreographer_required, action_sequence_required) => {
6559
+ initializeProduction(
6560
+ count,
6561
+ type,
6562
+ dance_choreographer_required,
6563
+ action_sequence_required
6564
+ ).then(() => {
5911
6565
  setIsInitModalOpen(false);
5912
6566
  });
5913
6567
  },
5914
6568
  initialValues: {
5915
6569
  numCameras: cameras.length || 1,
5916
- scene_type: sceneType
6570
+ scene_type: sceneType,
6571
+ dance_choreographer_required: false,
6572
+ action_sequence_required: false
5917
6573
  }
5918
6574
  }
5919
6575
  )
@@ -6129,13 +6785,19 @@ function useShotBreakdownScene(options) {
6129
6785
  });
6130
6786
  }
6131
6787
  };
6132
- const initializeProduction = async (count, type) => {
6788
+ const initializeProduction = async (count, type, dance_choreographer_required, action_sequence_required) => {
6133
6789
  var _a;
6134
6790
  const newCameras = [];
6135
6791
  for (let i = 1; i <= count; i++) {
6136
6792
  newCameras.push({ name: `Camera ${String.fromCharCode(64 + i)}` });
6137
6793
  }
6138
- const result = (_a = options.onProductionInitialized) == null ? void 0 : _a.call(options, newCameras, type);
6794
+ const result = (_a = options.onProductionInitialized) == null ? void 0 : _a.call(
6795
+ options,
6796
+ newCameras,
6797
+ type,
6798
+ dance_choreographer_required,
6799
+ action_sequence_required
6800
+ );
6139
6801
  if (result instanceof Promise) {
6140
6802
  setCameras(newCameras);
6141
6803
  setSceneType(type);