@vishu1301/script-writing 1.0.5 → 1.0.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -359,51 +359,127 @@ function ScreenplayEditorView({
359
359
  }
360
360
  }, [COURIER_STACK]);
361
361
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
362
- /* @__PURE__ */ jsxRuntime.jsx(
362
+ /* @__PURE__ */ jsxRuntime.jsxs(
363
363
  "div",
364
364
  {
365
- className: "sticky top-6 z-50 bg-white backdrop-blur-xl border border-white/10 rounded-full shadow-2xl flex gap-1 p-1.5 mb-12 select-none overflow-x-auto custom-scrollbar",
365
+ className: "sticky top-6 z-50 mx-auto bg-white/70 backdrop-blur-2xl border border-white/60 shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-[2rem] flex items-center justify-between p-2 mb-12 select-none transition-all",
366
366
  style: {
367
- maxWidth: "1024px"
367
+ maxWidth: "1240px"
368
368
  },
369
- children: blockTypes.map((type) => {
370
- var _a;
371
- const selected = ((_a = blocks.find((b) => b.id === focusedBlockId)) == null ? void 0 : _a.type) === type;
372
- return /* @__PURE__ */ jsxRuntime.jsxs(
373
- "button",
374
- {
375
- type: "button",
376
- className: `flex items-center gap-2 px-4 py-2.5 rounded-full font-medium text-sm transition-all duration-300 ${selected ? "bg-zinc-900 text-white shadow-sm" : "text-zinc-400 hover:bg-zinc-800/10 hover:text-zinc-800"}`,
377
- onClick: () => handleBlockTypeChange(type),
378
- children: [
379
- /* @__PURE__ */ jsxRuntime.jsx(
380
- "input",
381
- {
382
- type: "radio",
383
- name: "blockType",
384
- id: `block-type-${type}`,
385
- className: "sr-only",
386
- "aria-label": blockStyles[type].label,
387
- checked: selected,
388
- readOnly: true
389
- }
390
- ),
391
- /* @__PURE__ */ jsxRuntime.jsxs(
392
- "label",
393
- {
394
- htmlFor: `block-type-${type}`,
395
- className: "flex items-center gap-2 cursor-pointer",
396
- children: [
397
- icons[type],
398
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap hidden sm:inline", children: blockStyles[type].label })
399
- ]
400
- }
401
- )
402
- ]
403
- },
404
- type
405
- );
406
- })
369
+ children: [
370
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex gap-1 overflow-x-auto custom-scrollbar pr-2 items-center", children: blockTypes.map((type) => {
371
+ var _a;
372
+ const selected = ((_a = blocks.find((b) => b.id === focusedBlockId)) == null ? void 0 : _a.type) === type;
373
+ return /* @__PURE__ */ jsxRuntime.jsxs(
374
+ "button",
375
+ {
376
+ type: "button",
377
+ className: `group flex items-center gap-2.5 px-4 py-2 rounded-full font-semibold text-sm transition-all duration-300 ease-out active:scale-95 ${selected ? "bg-zinc-900 text-white shadow-md shadow-zinc-900/20" : "text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
378
+ onClick: () => handleBlockTypeChange(type),
379
+ children: [
380
+ /* @__PURE__ */ jsxRuntime.jsx(
381
+ "input",
382
+ {
383
+ type: "radio",
384
+ name: "blockType",
385
+ id: `block-type-${type}`,
386
+ className: "sr-only",
387
+ "aria-label": blockStyles[type].label,
388
+ checked: selected,
389
+ readOnly: true
390
+ }
391
+ ),
392
+ /* @__PURE__ */ jsxRuntime.jsxs(
393
+ "label",
394
+ {
395
+ htmlFor: `block-type-${type}`,
396
+ className: "flex items-center gap-2 cursor-pointer pointer-events-none",
397
+ children: [
398
+ /* @__PURE__ */ jsxRuntime.jsx(
399
+ "div",
400
+ {
401
+ className: `${selected ? "opacity-100" : "opacity-70 group-hover:opacity-100"} transition-opacity duration-200`,
402
+ children: icons[type]
403
+ }
404
+ ),
405
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "whitespace-nowrap hidden sm:inline tracking-wide", children: blockStyles[type].label })
406
+ ]
407
+ }
408
+ )
409
+ ]
410
+ },
411
+ type
412
+ );
413
+ }) }),
414
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1 shrink-0 relative px-1", children: [
415
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-[1px] h-6 bg-zinc-200/80 mx-2 hidden sm:block rounded-full" }),
416
+ /* @__PURE__ */ jsxRuntime.jsx(PdfImporter, { onScriptImported: handleScriptImport, children: /* @__PURE__ */ jsxRuntime.jsx("div", { title: "Import Script", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "w-[18px] h-[18px]" }) }) }),
417
+ onSave && /* @__PURE__ */ jsxRuntime.jsx(
418
+ "button",
419
+ {
420
+ onClick: onSave,
421
+ className: "flex items-center justify-center w-10 h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all duration-200 active:scale-95",
422
+ title: "Save Script",
423
+ "aria-label": "Save Script",
424
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { className: "w-[18px] h-[18px]" })
425
+ }
426
+ ),
427
+ onSaveAsPdf && /* @__PURE__ */ jsxRuntime.jsx(
428
+ "button",
429
+ {
430
+ onClick: onSaveAsPdf,
431
+ className: "flex items-center justify-center w-10 h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all duration-200 active:scale-95",
432
+ title: "Save as PDF",
433
+ "aria-label": "Save Script as PDF",
434
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileDown, { className: "w-[18px] h-[18px]" })
435
+ }
436
+ ),
437
+ onSaveAsSbx && /* @__PURE__ */ jsxRuntime.jsx(
438
+ "button",
439
+ {
440
+ onClick: onSaveAsSbx,
441
+ className: "flex items-center justify-center w-10 h-10 rounded-full text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900 transition-all duration-200 active:scale-95",
442
+ title: "Sync with Cloud (SBX)",
443
+ "aria-label": "Save Script as SBX",
444
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcw, { className: "w-[18px] h-[18px]" })
445
+ }
446
+ ),
447
+ /* @__PURE__ */ jsxRuntime.jsx(
448
+ "button",
449
+ {
450
+ onClick: () => setIsRulesOpen(!isRulesOpen),
451
+ className: `flex items-center justify-center w-10 h-10 rounded-full transition-all duration-200 active:scale-95 ${isRulesOpen ? "bg-zinc-900 text-white shadow-md shadow-zinc-900/20" : "text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
452
+ title: "Settings & Shortcuts",
453
+ "aria-label": "Toggle Settings",
454
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-[18px] h-[18px]" })
455
+ }
456
+ ),
457
+ isRulesOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute top-[calc(100%+1rem)] right-0 bg-white/95 backdrop-blur-3xl rounded-[1.5rem] shadow-[0_20px_60px_-15px_rgba(0,0,0,0.1)] ring-1 ring-zinc-900/5 p-5 text-sm text-zinc-700 select-none font-sans overflow-hidden transition-all duration-300 w-72 origin-top-right animate-in fade-in zoom-in-95 z-50", children: [
458
+ /* @__PURE__ */ jsxRuntime.jsxs("h4", { className: "font-bold text-zinc-900 mb-4 text-sm flex items-center gap-2", children: [
459
+ /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-4 h-4 text-zinc-400" }),
460
+ "Settings & Shortcuts"
461
+ ] }),
462
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-2.5", children: [
463
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
464
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "New Block" }),
465
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Enter" })
466
+ ] }),
467
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
468
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "Delete Block" }),
469
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Backspace" })
470
+ ] }),
471
+ /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
472
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "font-medium text-zinc-600", children: "Change Type" }),
473
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
474
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "Ctrl" }),
475
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-zinc-400 font-medium", children: "+" }),
476
+ /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-[11px] font-bold text-zinc-700 bg-white border border-zinc-200/80 shadow-[0_2px_4px_rgb(0,0,0,0.02)] rounded-md", children: "\u2191/\u2193" })
477
+ ] })
478
+ ] })
479
+ ] }) })
480
+ ] })
481
+ ] })
482
+ ]
407
483
  }
408
484
  ),
409
485
  /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-col gap-12 w-full items-center pb-24", children: /* @__PURE__ */ jsxRuntime.jsx(
@@ -641,79 +717,7 @@ function ScreenplayEditorView({
641
717
  );
642
718
  })
643
719
  }
644
- ) }),
645
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "fixed bottom-6 right-6 flex flex-col items-end gap-4 z-50", children: [
646
- /* @__PURE__ */ jsxRuntime.jsx(PdfImporter, { onScriptImported: handleScriptImport, children: /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
647
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Upload, { className: "w-5 h-5" }),
648
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Import" })
649
- ] }) }),
650
- onSave && /* @__PURE__ */ jsxRuntime.jsxs(
651
- "button",
652
- {
653
- onClick: onSave,
654
- className: "flex items-center justify-center gap-2 w-auto px-4 h-12 rounded-full bg-zinc-950 text-white shadow-xl shadow-zinc-900/20 border border-white/10 hover:bg-zinc-800 hover:scale-105 active:scale-95 transition-all duration-300",
655
- "aria-label": "Save Script",
656
- children: [
657
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Save, { className: "w-5 h-5" }),
658
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Save" })
659
- ]
660
- }
661
- ),
662
- onSaveAsPdf && /* @__PURE__ */ jsxRuntime.jsxs(
663
- "button",
664
- {
665
- onClick: onSaveAsPdf,
666
- className: "flex items-center justify-center gap-2 w-auto px-4 h-12 rounded-full bg-zinc-950 text-white shadow-xl shadow-zinc-900/20 border border-white/10 hover:bg-zinc-800 hover:scale-105 active:scale-95 transition-all duration-300",
667
- "aria-label": "Save Script as PDF",
668
- children: [
669
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.FileDown, { className: "w-5 h-5" }),
670
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Save as PDF" })
671
- ]
672
- }
673
- ),
674
- onSaveAsSbx && /* @__PURE__ */ jsxRuntime.jsxs(
675
- "button",
676
- {
677
- onClick: onSaveAsSbx,
678
- className: "flex items-center justify-center gap-2 w-auto px-4 h-12 rounded-full bg-zinc-950 text-white shadow-xl shadow-zinc-900/20 border border-white/10 hover:bg-zinc-800 hover:scale-105 active:scale-95 transition-all duration-300",
679
- "aria-label": "Save Script as SBX",
680
- children: [
681
- /* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcw, { className: "w-5 h-5" }),
682
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Save" })
683
- ]
684
- }
685
- ),
686
- isRulesOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white/80 backdrop-blur-md rounded-xl shadow-lg border border-zinc-200/50 p-4 text-xs text-zinc-700 select-none font-sans overflow-hidden transition-all duration-300 w-64 origin-bottom-right animate-in fade-in zoom-in-95", children: [
687
- /* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-bold text-zinc-800 mb-3 text-sm", children: "Settings & Shortcuts" }),
688
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-1.5", children: /* @__PURE__ */ jsxRuntime.jsxs("ul", { className: "space-y-1.5", children: [
689
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
690
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "New Block" }),
691
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Enter" })
692
- ] }),
693
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
694
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Delete Block" }),
695
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Backspace" })
696
- ] }),
697
- /* @__PURE__ */ jsxRuntime.jsxs("li", { className: "flex items-center justify-between gap-6", children: [
698
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "Change Type" }),
699
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-1", children: [
700
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "Ctrl" }),
701
- /* @__PURE__ */ jsxRuntime.jsx("span", { children: "+" }),
702
- /* @__PURE__ */ jsxRuntime.jsx("kbd", { className: "px-2 py-1 text-xs font-semibold text-zinc-800 bg-zinc-200/70 border border-zinc-300/70 rounded-md", children: "\u2191/\u2193" })
703
- ] })
704
- ] })
705
- ] }) }) })
706
- ] }),
707
- /* @__PURE__ */ jsxRuntime.jsx(
708
- "button",
709
- {
710
- onClick: () => setIsRulesOpen(!isRulesOpen),
711
- className: `flex items-center justify-center w-12 h-12 rounded-full bg-zinc-950 text-white shadow-xl shadow-zinc-900/20 border border-white/10 hover:bg-zinc-800 hover:scale-105 active:scale-95 transition-all duration-300 ${isRulesOpen ? "rotate-90" : "rotate-0"}`,
712
- "aria-label": "Toggle Settings",
713
- children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Cog, { className: "w-5 h-5" })
714
- }
715
- )
716
- ] })
720
+ ) })
717
721
  ] });
718
722
  }
719
723
 
@@ -1376,6 +1380,33 @@ function useScreenplayEditor(options) {
1376
1380
  return block;
1377
1381
  });
1378
1382
  setBlocks(finalizedBlocks);
1383
+ if (options == null ? void 0 : options.onSave) {
1384
+ options.onSave(content);
1385
+ const typeToDivClass = {
1386
+ SCENE_HEADING: "divtype0",
1387
+ ACTION: "divtype2",
1388
+ CHARACTER: "divtype3",
1389
+ PARENTHETICAL: "divtype4",
1390
+ DIALOGUE: "divtype5",
1391
+ TRANSITION: "divtype6",
1392
+ GENERAL: "divtype2"
1393
+ };
1394
+ const sbxData = finalizedBlocks.map((block) => {
1395
+ const divClass = typeToDivClass[block.type] || "divtype2";
1396
+ let text = block.text || "";
1397
+ let extraAttributes = "";
1398
+ if (block.type === "SCENE_HEADING") {
1399
+ text = `${block.sceneType || "INT."} ${text} - ${block.timeOfDay || "DAY"}`.toUpperCase();
1400
+ if (block.sceneNumber) {
1401
+ extraAttributes = ` data-scene="${block.sceneNumber}"`;
1402
+ }
1403
+ } else if (block.type === "CHARACTER" || block.type === "TRANSITION") {
1404
+ text = text.toUpperCase();
1405
+ }
1406
+ return `<div class="${divClass}" id="par${block.id}"${extraAttributes}>${text}</div>`;
1407
+ }).join("");
1408
+ options.onSave(sbxData);
1409
+ }
1379
1410
  setTimeout(() => {
1380
1411
  var _a;
1381
1412
  const firstId = parsedBlocks[0].id;
@@ -1386,7 +1417,7 @@ function useScreenplayEditor(options) {
1386
1417
  }, 100);
1387
1418
  }
1388
1419
  },
1389
- [refs]
1420
+ [refs, options == null ? void 0 : options.onSave]
1390
1421
  );
1391
1422
  const handleFocus = react.useCallback(
1392
1423
  (id) => {
@@ -1529,7 +1560,7 @@ function useScreenplayEditor(options) {
1529
1560
  loadFromUrl
1530
1561
  };
1531
1562
  }
1532
- var handleSaveAsPdf = (blocks, sceneNumbers) => {
1563
+ var handleSaveAsPdf = (blocks, sceneNumbers, project_name) => {
1533
1564
  if (document.activeElement instanceof HTMLElement) {
1534
1565
  document.activeElement.blur();
1535
1566
  }
@@ -1614,9 +1645,13 @@ var handleSaveAsPdf = (blocks, sceneNumbers) => {
1614
1645
  }
1615
1646
  y += blockHeight;
1616
1647
  });
1617
- doc.save("screenplay_export.pdf");
1648
+ if (project_name) {
1649
+ doc.save(`${project_name}_${(/* @__PURE__ */ new Date()).toISOString()}.pdf`);
1650
+ } else {
1651
+ doc.save("screenplay_export.pdf");
1652
+ }
1618
1653
  };
1619
- var handleSaveAsSbx = (blocks, sceneNumbers, onSaveAsSbx) => {
1654
+ var convertBlocksToSbx = (blocks, sceneNumbers) => {
1620
1655
  const typeToDivClass = {
1621
1656
  SCENE_HEADING: "divtype0",
1622
1657
  ACTION: "divtype2",
@@ -1626,7 +1661,7 @@ var handleSaveAsSbx = (blocks, sceneNumbers, onSaveAsSbx) => {
1626
1661
  TRANSITION: "divtype6",
1627
1662
  GENERAL: "divtype2"
1628
1663
  };
1629
- const sbxData = blocks.map((block) => {
1664
+ return blocks.map((block) => {
1630
1665
  const divClass = typeToDivClass[block.type] || "divtype2";
1631
1666
  let text = block.text || "";
1632
1667
  let extraAttributes = "";
@@ -1641,18 +1676,28 @@ var handleSaveAsSbx = (blocks, sceneNumbers, onSaveAsSbx) => {
1641
1676
  }
1642
1677
  return `<div class="${divClass}" id="par${block.id}"${extraAttributes}>${text}</div>`;
1643
1678
  }).join("");
1679
+ };
1680
+ var handleSaveAsSbx = (blocks, sceneNumbers, onSaveAsSbx, project_name) => {
1681
+ const sbxData = convertBlocksToSbx(blocks, sceneNumbers);
1644
1682
  const blob = new Blob([sbxData], { type: "text/plain" });
1645
- const url = URL.createObjectURL(blob);
1646
- const a = document.createElement("a");
1647
- a.href = url;
1648
- a.download = "screenplay.sbx";
1649
- document.body.appendChild(a);
1650
- a.click();
1651
- document.body.removeChild(a);
1652
- URL.revokeObjectURL(url);
1653
1683
  if (onSaveAsSbx) {
1654
- const file = new File([blob], "screenplay.sbx", { type: "text/plain" });
1655
- onSaveAsSbx(file);
1684
+ if (project_name) {
1685
+ const file = new File(
1686
+ [blob],
1687
+ `${project_name}_${(/* @__PURE__ */ new Date()).toISOString()}.sbx`,
1688
+ { type: "text/plain" }
1689
+ );
1690
+ onSaveAsSbx(file);
1691
+ } else {
1692
+ const file = new File([blob], "screenplay.sbx", { type: "text/plain" });
1693
+ onSaveAsSbx(file);
1694
+ }
1695
+ }
1696
+ };
1697
+ var handleSyncWithCloud = (blocks, sceneNumbers, onSyncWithCloud) => {
1698
+ if (onSyncWithCloud) {
1699
+ const sbxData = convertBlocksToSbx(blocks, sceneNumbers);
1700
+ onSyncWithCloud(sbxData);
1656
1701
  }
1657
1702
  };
1658
1703
 
@@ -1678,9 +1723,26 @@ function ScriptBreakdownSceneView({
1678
1723
  removeTag,
1679
1724
  clearSelection,
1680
1725
  menuPlacement,
1681
- menuRef
1726
+ menuRef,
1727
+ subLocations,
1728
+ addSubLocation,
1729
+ removeSubLocation,
1730
+ sceneBrief,
1731
+ setSceneBrief
1682
1732
  }) {
1683
1733
  const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
1734
+ const [isSubLocOpen, setIsSubLocOpen] = react.useState(false);
1735
+ const [subLocInput, setSubLocInput] = react.useState("");
1736
+ const subLocPopoverRef = react.useRef(null);
1737
+ react.useEffect(() => {
1738
+ const handleClickOutside = (e) => {
1739
+ if (isSubLocOpen && subLocPopoverRef.current && !subLocPopoverRef.current.contains(e.target)) {
1740
+ setIsSubLocOpen(false);
1741
+ }
1742
+ };
1743
+ document.addEventListener("mousedown", handleClickOutside);
1744
+ return () => document.removeEventListener("mousedown", handleClickOutside);
1745
+ }, [isSubLocOpen]);
1684
1746
  react.useEffect(() => {
1685
1747
  const fontId = "google-font-courier-prime";
1686
1748
  const styleId = "screenplay-editor-force-v4";
@@ -1763,117 +1825,137 @@ function ScriptBreakdownSceneView({
1763
1825
  return nodes;
1764
1826
  };
1765
1827
  return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "p-8 md:p-12 mx-auto w-full min-h-screen flex flex-col gap-8", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col lg:flex-row gap-8 items-start", children: [
1766
- /* @__PURE__ */ jsxRuntime.jsx(
1767
- "div",
1768
- {
1769
- 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-auto shrink-0",
1770
- style: {
1771
- fontFamily: COURIER_STACK,
1772
- paddingLeft: "1.5in",
1773
- paddingRight: "1in",
1774
- paddingTop: "1in",
1775
- paddingBottom: "1in",
1776
- lineHeight: "1.2"
1777
- },
1778
- "data-screenplay-editor": "true",
1779
- onMouseUp: handleMouseUp,
1780
- children: blocks.map((block) => /* @__PURE__ */ jsxRuntime.jsxs(
1781
- "div",
1782
- {
1783
- "data-block-id": block.id,
1784
- className: `relative break-words w-full px-4 py-2 ${blockStyles[block.type].className}`,
1785
- style: __spreadProps(__spreadValues({}, blockStyles[block.type].inputStyle), {
1786
- minHeight: "2.5rem"
1787
- }),
1788
- children: [
1789
- renderBlockText(block),
1790
- (selectionMenu == null ? void 0 : selectionMenu.blockId) === block.id && /* @__PURE__ */ jsxRuntime.jsxs(
1791
- "div",
1792
- {
1793
- ref: menuRef,
1794
- "data-screenplay-editor": "false",
1795
- className: `tag-menu absolute z-50 bg-white/70 backdrop-blur-2xl shadow-[0_10px_40px_rgb(0,0,0,0.06)] border border-white rounded-[1.5rem] p-2 flex flex-col w-56 animate-in fade-in zoom-in-95 duration-300 ease-out ${menuPlacement === "top" ? "origin-bottom" : "origin-top"}`,
1796
- style: {
1797
- top: selectionMenu.top,
1798
- left: selectionMenu.left,
1799
- transform: menuPlacement === "top" ? "translate(-50%, calc(-100% - 12px))" : "translate(-50%, 32px)"
1800
- },
1801
- children: [
1802
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10 px-3 py-2.5 border-b border-white/60 mb-1.5", children: [
1803
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[9px] font-extrabold tracking-[0.2em] text-slate-400 uppercase mb-1", children: "Tag Element" }),
1804
- /* @__PURE__ */ jsxRuntime.jsxs(
1805
- "p",
1806
- {
1807
- className: "text-xs font-bold text-slate-700 truncate drop-shadow-sm",
1808
- title: selectionMenu.text,
1809
- children: [
1810
- '"',
1811
- selectionMenu.text,
1812
- '"'
1813
- ]
1814
- }
1815
- )
1816
- ] }),
1817
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10 flex flex-col gap-1", children: [
1818
- CATEGORIES.filter(
1819
- (cat) => !(cat.id === "LOCATION" && hasLocationTag)
1820
- ).map((cat) => /* @__PURE__ */ jsxRuntime.jsxs(
1821
- "button",
1822
- {
1823
- onClick: () => addTag(cat.id),
1824
- className: "group w-full text-[12px] font-bold px-3 py-2 rounded-xl transition-all duration-300 text-left flex items-center justify-between hover:bg-white/80 hover:shadow-[0_2px_10px_rgb(0,0,0,0.02)] active:scale-[0.98]",
1825
- style: { color: cat.color },
1826
- children: [
1827
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1828
- /* @__PURE__ */ jsxRuntime.jsx(
1829
- "div",
1830
- {
1831
- className: "w-2 h-2 rounded-full shadow-sm group-hover:scale-125 transition-transform duration-300",
1832
- style: { backgroundColor: cat.hex }
1833
- }
1834
- ),
1835
- cat.label
1836
- ] }),
1837
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-slate-400 opacity-0 group-hover:opacity-100 transition-all duration-300 translate-x-1 group-hover:translate-x-0", children: "Select" })
1838
- ]
1839
- },
1840
- cat.id
1841
- )),
1842
- tags.some(
1843
- (t) => t.blockId === block.id && t.startIndex === selectionMenu.startIndex && t.endIndex === selectionMenu.endIndex
1844
- ) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 pt-1 border-t border-white/60", children: /* @__PURE__ */ jsxRuntime.jsxs(
1845
- "button",
1846
- {
1847
- onClick: (e) => {
1848
- const tagToRemove = tags.find(
1849
- (t) => t.blockId === block.id && t.startIndex === selectionMenu.startIndex && t.endIndex === selectionMenu.endIndex
1850
- );
1851
- if (tagToRemove) {
1852
- removeTag(e, tagToRemove.id);
1853
- clearSelection();
1854
- }
1855
- },
1856
- className: "group w-full text-[12px] font-bold px-3 py-2 rounded-xl transition-all duration-300 text-left flex items-center justify-between hover:bg-rose-50 hover:text-rose-600 hover:shadow-[0_2px_10px_rgb(225,29,72,0.04)] active:scale-[0.98] text-slate-500 border border-transparent hover:border-rose-100",
1857
- children: [
1858
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1859
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full shadow-sm bg-rose-400 group-hover:scale-125 transition-transform duration-300" }),
1860
- "Remove Tag"
1861
- ] }),
1862
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-rose-400 opacity-0 group-hover:opacity-100 transition-all duration-300 translate-x-1 group-hover:translate-x-0", children: "Remove" })
1863
- ]
1864
- }
1865
- ) })
1866
- ] })
1867
- ]
1868
- }
1869
- )
1870
- ]
1828
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
1829
+ /* @__PURE__ */ jsxRuntime.jsx(
1830
+ "div",
1831
+ {
1832
+ 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-auto shrink-0",
1833
+ style: {
1834
+ fontFamily: COURIER_STACK,
1835
+ paddingLeft: "1.5in",
1836
+ paddingRight: "1in",
1837
+ paddingTop: "1in",
1838
+ paddingBottom: "1in",
1839
+ lineHeight: "1.2"
1871
1840
  },
1872
- block.id
1873
- ))
1874
- }
1875
- ),
1876
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "w-full lg:w-80 flex-shrink-0 bg-white/50 backdrop-blur-2xl border border-white shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-[2.5rem] p-8 sticky top-6", children: [
1841
+ "data-screenplay-editor": "true",
1842
+ onMouseUp: handleMouseUp,
1843
+ children: blocks.map((block) => /* @__PURE__ */ jsxRuntime.jsxs(
1844
+ "div",
1845
+ {
1846
+ "data-block-id": block.id,
1847
+ className: `relative break-words w-full px-4 py-2 ${blockStyles[block.type].className}`,
1848
+ style: __spreadProps(__spreadValues({}, blockStyles[block.type].inputStyle), {
1849
+ minHeight: "2.5rem"
1850
+ }),
1851
+ children: [
1852
+ renderBlockText(block),
1853
+ (selectionMenu == null ? void 0 : selectionMenu.blockId) === block.id && /* @__PURE__ */ jsxRuntime.jsxs(
1854
+ "div",
1855
+ {
1856
+ ref: menuRef,
1857
+ "data-screenplay-editor": "false",
1858
+ className: `tag-menu absolute z-50 bg-white/70 backdrop-blur-2xl shadow-[0_10px_40px_rgb(0,0,0,0.06)] border border-white rounded-[1.5rem] p-2 flex flex-col w-56 animate-in fade-in zoom-in-95 duration-300 ease-out ${menuPlacement === "top" ? "origin-bottom" : "origin-top"}`,
1859
+ style: {
1860
+ top: selectionMenu.top,
1861
+ left: selectionMenu.left,
1862
+ transform: menuPlacement === "top" ? "translate(-50%, calc(-100% - 12px))" : "translate(-50%, 32px)"
1863
+ },
1864
+ children: [
1865
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10 px-3 py-2.5 border-b border-white/60 mb-1.5", children: [
1866
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[9px] font-extrabold tracking-[0.2em] text-slate-400 uppercase mb-1", children: "Tag Element" }),
1867
+ /* @__PURE__ */ jsxRuntime.jsxs(
1868
+ "p",
1869
+ {
1870
+ className: "text-xs font-bold text-slate-700 truncate drop-shadow-sm",
1871
+ title: selectionMenu.text,
1872
+ children: [
1873
+ '"',
1874
+ selectionMenu.text,
1875
+ '"'
1876
+ ]
1877
+ }
1878
+ )
1879
+ ] }),
1880
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative z-10 flex flex-col gap-1", children: [
1881
+ CATEGORIES.filter(
1882
+ (cat) => !(cat.id === "LOCATION" && hasLocationTag)
1883
+ ).map((cat) => /* @__PURE__ */ jsxRuntime.jsxs(
1884
+ "button",
1885
+ {
1886
+ onClick: () => addTag(cat.id),
1887
+ className: "group w-full text-[12px] font-bold px-3 py-2 rounded-xl transition-all duration-300 text-left flex items-center justify-between hover:bg-white/80 hover:shadow-[0_2px_10px_rgb(0,0,0,0.02)] active:scale-[0.98]",
1888
+ style: { color: cat.color },
1889
+ children: [
1890
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1891
+ /* @__PURE__ */ jsxRuntime.jsx(
1892
+ "div",
1893
+ {
1894
+ className: "w-2 h-2 rounded-full shadow-sm group-hover:scale-125 transition-transform duration-300",
1895
+ style: { backgroundColor: cat.hex }
1896
+ }
1897
+ ),
1898
+ cat.label
1899
+ ] }),
1900
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-slate-400 opacity-0 group-hover:opacity-100 transition-all duration-300 translate-x-1 group-hover:translate-x-0", children: "Select" })
1901
+ ]
1902
+ },
1903
+ cat.id
1904
+ )),
1905
+ tags.some(
1906
+ (t) => t.blockId === block.id && t.startIndex === selectionMenu.startIndex && t.endIndex === selectionMenu.endIndex
1907
+ ) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mt-1 pt-1 border-t border-white/60", children: /* @__PURE__ */ jsxRuntime.jsxs(
1908
+ "button",
1909
+ {
1910
+ onClick: (e) => {
1911
+ const tagToRemove = tags.find(
1912
+ (t) => t.blockId === block.id && t.startIndex === selectionMenu.startIndex && t.endIndex === selectionMenu.endIndex
1913
+ );
1914
+ if (tagToRemove) {
1915
+ removeTag(e, tagToRemove.id);
1916
+ clearSelection();
1917
+ }
1918
+ },
1919
+ className: "group w-full text-[12px] font-bold px-3 py-2 rounded-xl transition-all duration-300 text-left flex items-center justify-between hover:bg-rose-50 hover:text-rose-600 hover:shadow-[0_2px_10px_rgb(225,29,72,0.04)] active:scale-[0.98] text-slate-500 border border-transparent hover:border-rose-100",
1920
+ children: [
1921
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-center gap-3", children: [
1922
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-2 h-2 rounded-full shadow-sm bg-rose-400 group-hover:scale-125 transition-transform duration-300" }),
1923
+ "Remove Tag"
1924
+ ] }),
1925
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-[10px] font-bold text-rose-400 opacity-0 group-hover:opacity-100 transition-all duration-300 translate-x-1 group-hover:translate-x-0", children: "Remove" })
1926
+ ]
1927
+ }
1928
+ ) })
1929
+ ] })
1930
+ ]
1931
+ }
1932
+ )
1933
+ ]
1934
+ },
1935
+ block.id
1936
+ ))
1937
+ }
1938
+ ),
1939
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative bg-[#fdfdfc] shadow-2xl shadow-zinc-300/60 border border-zinc-100 rounded-sm md:rounded-md flex flex-col w-[210mm] shrink-0 p-8 md:p-12 lg:p-16", children: [
1940
+ /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-xs font-extrabold text-slate-800 uppercase tracking-[0.25em] mb-6 flex items-center gap-3 font-sans", children: [
1941
+ /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-8 h-8 rounded-full bg-slate-100/80 shadow-inner border border-slate-200/50", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.AlignLeft, { className: "w-3.5 h-3.5 text-slate-500" }) }),
1942
+ "Scene Brief"
1943
+ ] }),
1944
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "relative bg-zinc-50/50 border border-zinc-200/60 rounded-xl p-4 md:p-6 shadow-inner focus-within:bg-white focus-within:border-zinc-300 focus-within:shadow-[0_8px_30px_rgb(0,0,0,0.04)] transition-all duration-300", children: /* @__PURE__ */ jsxRuntime.jsx(
1945
+ "textarea",
1946
+ {
1947
+ value: sceneBrief,
1948
+ onChange: (e) => setSceneBrief(e.target.value),
1949
+ placeholder: "Write a brief description or notes for this scene...",
1950
+ className: "w-full min-h-[120px] bg-transparent outline-none resize-y text-zinc-700 placeholder:text-zinc-400 text-sm md:text-base custom-scrollbar font-sans",
1951
+ style: {
1952
+ lineHeight: "1.6"
1953
+ }
1954
+ }
1955
+ ) })
1956
+ ] })
1957
+ ] }),
1958
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: "w-full lg:w-80 flex-shrink-0 flex flex-col gap-6 sticky top-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "bg-white/50 backdrop-blur-2xl border border-white shadow-[0_8px_30px_rgb(0,0,0,0.04)] rounded-[2.5rem] p-8", children: [
1877
1959
  /* @__PURE__ */ jsxRuntime.jsxs("h3", { className: "text-xs font-extrabold text-slate-800 uppercase tracking-[0.25em] mb-8 flex items-center gap-3", children: [
1878
1960
  /* @__PURE__ */ jsxRuntime.jsx("span", { className: "flex items-center justify-center w-8 h-8 rounded-full bg-white/80 shadow-[0_4px_15px_rgb(0,0,0,0.04)] border border-white", children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Tags, { className: "w-3.5 h-3.5 text-slate-500" }) }),
1879
1961
  "Tags",
@@ -1895,20 +1977,93 @@ function ScriptBreakdownSceneView({
1895
1977
  style: { backgroundColor: cat.hex }
1896
1978
  }
1897
1979
  ),
1898
- cat.label
1980
+ cat.label,
1981
+ cat.id === "LOCATION" && /* @__PURE__ */ jsxRuntime.jsxs(
1982
+ "div",
1983
+ {
1984
+ className: "ml-auto relative",
1985
+ ref: subLocPopoverRef,
1986
+ children: [
1987
+ /* @__PURE__ */ jsxRuntime.jsx(
1988
+ "button",
1989
+ {
1990
+ onClick: () => setIsSubLocOpen(!isSubLocOpen),
1991
+ className: "flex items-center justify-center w-5 h-5 rounded-full hover:bg-slate-200 transition-colors",
1992
+ title: "Add Sub Location",
1993
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.Plus, { className: "w-3 h-3 text-slate-500" })
1994
+ }
1995
+ ),
1996
+ isSubLocOpen && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "absolute right-0 top-full mt-2 w-56 bg-white backdrop-blur-2xl shadow-[0_10px_40px_rgb(0,0,0,0.06)] border border-white rounded-[1.5rem] p-3 z-50 animate-in fade-in zoom-in-95", children: [
1997
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-[9px] font-extrabold tracking-[0.2em] text-slate-400 uppercase mb-2 px-1", children: "Add Sub Location" }),
1998
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex gap-2 items-center", children: [
1999
+ /* @__PURE__ */ jsxRuntime.jsx(
2000
+ "input",
2001
+ {
2002
+ type: "text",
2003
+ value: subLocInput,
2004
+ onChange: (e) => setSubLocInput(e.target.value),
2005
+ onKeyDown: (e) => {
2006
+ if (e.key === "Enter") {
2007
+ addSubLocation(subLocInput);
2008
+ setSubLocInput("");
2009
+ setIsSubLocOpen(false);
2010
+ }
2011
+ },
2012
+ className: "w-full text-xs px-3 py-2 bg-white/50 border border-white/60 rounded-xl outline-none focus:bg-white/80 focus:border-white transition-all text-slate-700 font-bold shadow-[0_2px_10px_rgb(0,0,0,0.02)] placeholder:font-medium placeholder:text-slate-400",
2013
+ placeholder: "Sub location...",
2014
+ autoFocus: true
2015
+ }
2016
+ ),
2017
+ /* @__PURE__ */ jsxRuntime.jsx(
2018
+ "button",
2019
+ {
2020
+ onClick: () => {
2021
+ addSubLocation(subLocInput);
2022
+ setSubLocInput("");
2023
+ setIsSubLocOpen(false);
2024
+ },
2025
+ className: "flex items-center justify-center shrink-0 bg-slate-800 text-white px-3.5 py-2 rounded-xl text-[11px] font-bold hover:bg-slate-700 hover:shadow-md transition-all active:scale-95",
2026
+ children: "Add"
2027
+ }
2028
+ )
2029
+ ] })
2030
+ ] })
2031
+ ]
2032
+ }
2033
+ )
1899
2034
  ] }),
1900
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex flex-wrap gap-2", children: catTags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx(
1901
- "span",
1902
- {
1903
- className: "text-[11px] font-bold px-3 py-1.5 rounded-xl bg-white/80 backdrop-blur-md border border-white shadow-[0_4px_15px_rgb(0,0,0,0.03)] hover:shadow-[0_4px_20px_rgb(0,0,0,0.06)] hover:-translate-y-0.5 transition-all duration-300 cursor-default",
1904
- style: { color: cat.color },
1905
- children: tag.text
1906
- },
1907
- tag.id
1908
- )) })
2035
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-wrap gap-2", children: [
2036
+ catTags.map((tag) => /* @__PURE__ */ jsxRuntime.jsx(
2037
+ "span",
2038
+ {
2039
+ className: "text-[11px] font-bold px-3 py-1.5 rounded-xl bg-white/80 backdrop-blur-md border border-white shadow-[0_4px_15px_rgb(0,0,0,0.03)] hover:shadow-[0_4px_20px_rgb(0,0,0,0.06)] hover:-translate-y-0.5 transition-all duration-300 cursor-default",
2040
+ style: { color: cat.color },
2041
+ children: tag.text
2042
+ },
2043
+ tag.id
2044
+ )),
2045
+ cat.id === "LOCATION" && subLocations.map((subLoc) => /* @__PURE__ */ jsxRuntime.jsxs(
2046
+ "span",
2047
+ {
2048
+ className: "group flex items-center gap-1.5 text-[11px] font-bold px-3 py-1.5 rounded-xl bg-white backdrop-blur-md border border-slate-200/50 shadow-[0_4px_15px_rgb(0,0,0,0.03)] transition-all duration-300 cursor-default text-slate-500",
2049
+ children: [
2050
+ subLoc,
2051
+ /* @__PURE__ */ jsxRuntime.jsx(
2052
+ "button",
2053
+ {
2054
+ onClick: () => removeSubLocation(subLoc),
2055
+ className: "w-3.5 h-3.5 rounded-full hover:bg-slate-300/50 flex items-center justify-center transition-colors opacity-0 group-hover:opacity-100",
2056
+ children: /* @__PURE__ */ jsxRuntime.jsx(lucideReact.X, { className: "w-2.5 h-2.5" })
2057
+ }
2058
+ )
2059
+ ]
2060
+ },
2061
+ `sub-${subLoc}`
2062
+ ))
2063
+ ] })
1909
2064
  ] }, cat.id);
1910
2065
  }) }) : /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs font-medium text-slate-400 italic bg-white/40 p-6 rounded-[2rem] border border-white border-dashed text-center shadow-[0_4px_20px_rgb(0,0,0,0.02)]", children: "Highlight text to tag elements." })
1911
- ] })
2066
+ ] }) })
1912
2067
  ] }) });
1913
2068
  }
1914
2069
  function useScriptBreakdown({
@@ -2035,8 +2190,24 @@ function useScriptBreakdownScene(sceneNumber) {
2035
2190
  const autoTaggedSceneRef = react.useRef(null);
2036
2191
  const [menuPlacement, setMenuPlacement] = react.useState("top");
2037
2192
  const menuRef = react.useRef(null);
2193
+ const [subLocations, setSubLocations] = react.useState([]);
2194
+ const addSubLocation = react.useCallback(
2195
+ (subLocation) => {
2196
+ const trimmed = subLocation.trim();
2197
+ if (trimmed && !subLocations.includes(trimmed)) {
2198
+ setSubLocations((prev) => [...prev, trimmed]);
2199
+ }
2200
+ },
2201
+ [subLocations]
2202
+ );
2203
+ const removeSubLocation = react.useCallback((subLocation) => {
2204
+ setSubLocations((prev) => prev.filter((loc) => loc !== subLocation));
2205
+ }, []);
2206
+ const [sceneBrief, setSceneBrief] = react.useState("");
2038
2207
  react.useEffect(() => {
2039
2208
  setTags([]);
2209
+ setSubLocations([]);
2210
+ setSceneBrief("");
2040
2211
  autoTaggedSceneRef.current = null;
2041
2212
  }, [sceneNumber]);
2042
2213
  react.useEffect(() => {
@@ -2051,14 +2222,17 @@ function useScriptBreakdownScene(sceneNumber) {
2051
2222
  let match;
2052
2223
  while ((match = regex.exec(block.text)) !== null) {
2053
2224
  const isOverlapping = autoTags.some(
2054
- (t) => t.blockId === block.id && (match.index + char.length > t.startIndex && match.index < t.endIndex)
2225
+ (t) => t.blockId === block.id && match.index + char.length > t.startIndex && match.index < t.endIndex
2055
2226
  );
2056
2227
  if (!isOverlapping) {
2057
2228
  autoTags.push({
2058
2229
  id: uuid(),
2059
2230
  blockId: block.id,
2060
2231
  categoryId: "CAST",
2061
- text: block.text.substring(match.index, match.index + char.length),
2232
+ text: block.text.substring(
2233
+ match.index,
2234
+ match.index + char.length
2235
+ ),
2062
2236
  startIndex: match.index,
2063
2237
  endIndex: match.index + char.length
2064
2238
  });
@@ -2124,15 +2298,25 @@ function useScriptBreakdownScene(sceneNumber) {
2124
2298
  };
2125
2299
  const handleMouseUp = () => {
2126
2300
  const selection = window.getSelection();
2127
- if (!selection || selection.isCollapsed || !selection.toString().trim()) return;
2301
+ if (!selection || selection.isCollapsed || !selection.toString().trim())
2302
+ return;
2128
2303
  const range = selection.getRangeAt(0);
2129
2304
  let container = range.commonAncestorContainer;
2130
- if (container.nodeType === Node.TEXT_NODE) container = container.parentElement;
2305
+ if (container.nodeType === Node.TEXT_NODE)
2306
+ container = container.parentElement;
2131
2307
  const blockElem = container.closest("[data-block-id]");
2132
2308
  if (!blockElem) return;
2133
2309
  const blockId = blockElem.getAttribute("data-block-id");
2134
- const startOffset = getAbsoluteOffset(blockElem, range.startContainer, range.startOffset);
2135
- const endOffset = getAbsoluteOffset(blockElem, range.endContainer, range.endOffset);
2310
+ const startOffset = getAbsoluteOffset(
2311
+ blockElem,
2312
+ range.startContainer,
2313
+ range.startOffset
2314
+ );
2315
+ const endOffset = getAbsoluteOffset(
2316
+ blockElem,
2317
+ range.endContainer,
2318
+ range.endOffset
2319
+ );
2136
2320
  if (startOffset !== null && endOffset !== null) {
2137
2321
  const rect = range.getBoundingClientRect();
2138
2322
  const blockRect = blockElem.getBoundingClientRect();
@@ -2183,7 +2367,12 @@ function useScriptBreakdownScene(sceneNumber) {
2183
2367
  removeTag,
2184
2368
  clearSelection,
2185
2369
  menuPlacement,
2186
- menuRef
2370
+ menuRef,
2371
+ subLocations,
2372
+ addSubLocation,
2373
+ removeSubLocation,
2374
+ sceneBrief,
2375
+ setSceneBrief
2187
2376
  };
2188
2377
  }
2189
2378
 
@@ -2192,8 +2381,10 @@ exports.ScreenplayEditorView = ScreenplayEditorView;
2192
2381
  exports.ScriptBreakdownSceneView = ScriptBreakdownSceneView;
2193
2382
  exports.blockStyles = blockStyles;
2194
2383
  exports.blockTypes = blockTypes;
2384
+ exports.convertBlocksToSbx = convertBlocksToSbx;
2195
2385
  exports.handleSaveAsPdf = handleSaveAsPdf;
2196
2386
  exports.handleSaveAsSbx = handleSaveAsSbx;
2387
+ exports.handleSyncWithCloud = handleSyncWithCloud;
2197
2388
  exports.icons = icons;
2198
2389
  exports.timeOfDayOptions = timeOfDayOptions;
2199
2390
  exports.useScreenplayEditor = useScreenplayEditor;