@vishu1301/script-writing 1.4.3 → 1.4.5
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 +326 -115
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -1
- package/dist/index.d.ts +20 -1
- package/dist/index.js +327 -116
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { useState, useRef, useEffect, useMemo, useCallback } from 'react';
|
|
2
|
-
import { Users, Box, Shirt, Car, Armchair, UserPlus, MapPin, Map as Map$1,
|
|
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, ArrowRight, ChevronRight, Sparkles, Check, Tags, ChevronDown, X, Video, Settings2, Eye, Pencil, Info, Frame, BookText, AsteriskIcon, Target, Activity, MonitorPlay, Crosshair, Clock, Camera, Aperture, SlidersHorizontal, Sun, Wand2, Volume2 } 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';
|
|
@@ -48,12 +48,12 @@ var blockTypes = [
|
|
|
48
48
|
];
|
|
49
49
|
var uuid = () => Math.random().toString(36).slice(2, 9);
|
|
50
50
|
var icons = {
|
|
51
|
-
SCENE_HEADING: /* @__PURE__ */ jsx(
|
|
52
|
-
ACTION: /* @__PURE__ */ jsx(
|
|
53
|
-
CHARACTER: /* @__PURE__ */ jsx(
|
|
54
|
-
PARENTHETICAL: /* @__PURE__ */ jsx(
|
|
55
|
-
DIALOGUE: /* @__PURE__ */ jsx(
|
|
56
|
-
TRANSITION: /* @__PURE__ */ jsx(
|
|
51
|
+
SCENE_HEADING: /* @__PURE__ */ jsx(Type, { className: "w-5 h-5" }),
|
|
52
|
+
ACTION: /* @__PURE__ */ jsx(AlignLeft, { className: "w-5 h-5" }),
|
|
53
|
+
CHARACTER: /* @__PURE__ */ jsx(User, { className: "w-5 h-5" }),
|
|
54
|
+
PARENTHETICAL: /* @__PURE__ */ jsx(Parentheses, { className: "w-5 h-5" }),
|
|
55
|
+
DIALOGUE: /* @__PURE__ */ jsx(MessageSquareText, { className: "w-5 h-5" }),
|
|
56
|
+
TRANSITION: /* @__PURE__ */ jsx(CornerDownRight, { className: "w-5 h-5" })
|
|
57
57
|
};
|
|
58
58
|
var blockStyles = {
|
|
59
59
|
SCENE_HEADING: {
|
|
@@ -320,9 +320,18 @@ function ScreenplayEditorView({
|
|
|
320
320
|
handleScriptImport,
|
|
321
321
|
onSave,
|
|
322
322
|
onSaveAsPdf,
|
|
323
|
-
onSaveAsSbx,
|
|
324
323
|
onSyncWithCloud,
|
|
325
|
-
handleSceneNumberChange
|
|
324
|
+
handleSceneNumberChange,
|
|
325
|
+
handleEnhance,
|
|
326
|
+
handleApproveEnhance,
|
|
327
|
+
handleRejectEnhance,
|
|
328
|
+
enhancingBlockId,
|
|
329
|
+
enhancementSuggestion,
|
|
330
|
+
isEnhancing,
|
|
331
|
+
showUnsavedPopover,
|
|
332
|
+
syncScreenplay,
|
|
333
|
+
ignoreChanges,
|
|
334
|
+
isLoading = false
|
|
326
335
|
}) {
|
|
327
336
|
const [isRulesOpen, setIsRulesOpen] = useState(false);
|
|
328
337
|
const rulesRef = useRef(null);
|
|
@@ -366,9 +375,15 @@ function ScreenplayEditorView({
|
|
|
366
375
|
document.head.appendChild(style);
|
|
367
376
|
}
|
|
368
377
|
}, [COURIER_STACK]);
|
|
378
|
+
if (isLoading) {
|
|
379
|
+
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: [
|
|
380
|
+
/* @__PURE__ */ jsx(Loader2, { className: "w-8 h-8 text-zinc-400 animate-spin" }),
|
|
381
|
+
/* @__PURE__ */ jsx("p", { className: "text-zinc-500 text-sm font-medium", children: "Loading script..." })
|
|
382
|
+
] }) });
|
|
383
|
+
}
|
|
369
384
|
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
370
|
-
/* @__PURE__ */ jsxs("div", { className: "sticky top-2 sm:top-6 z-50 mx-auto w-full max-w-
|
|
371
|
-
/* @__PURE__ */ jsx("div", { className: "flex items-center
|
|
385
|
+
/* @__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: [
|
|
386
|
+
/* @__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) => {
|
|
372
387
|
var _a;
|
|
373
388
|
const selected = ((_a = blocks.find((b) => b.id === focusedBlockId)) == null ? void 0 : _a.type) === type;
|
|
374
389
|
return /* @__PURE__ */ jsxs(
|
|
@@ -376,67 +391,37 @@ function ScreenplayEditorView({
|
|
|
376
391
|
{
|
|
377
392
|
type: "button",
|
|
378
393
|
disabled: isLocked,
|
|
379
|
-
className: `group flex shrink-0 items-center gap-2 sm:gap-2.5 px-3 py-1.5 sm:px-4 sm:py-2 rounded-full font-semibold text-xs sm: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"} ${isLocked ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
380
394
|
onClick: () => handleBlockTypeChange(type),
|
|
395
|
+
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" : ""}`,
|
|
381
396
|
children: [
|
|
382
397
|
/* @__PURE__ */ jsx(
|
|
383
|
-
"
|
|
398
|
+
"div",
|
|
384
399
|
{
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
id: `block-type-${type}`,
|
|
388
|
-
className: "sr-only",
|
|
389
|
-
"aria-label": blockStyles[type].label,
|
|
390
|
-
checked: selected,
|
|
391
|
-
readOnly: true
|
|
400
|
+
className: `flex items-center justify-center transition-opacity duration-200 ${selected ? "opacity-100" : "opacity-70 group-hover:opacity-100"}`,
|
|
401
|
+
children: icons[type]
|
|
392
402
|
}
|
|
393
403
|
),
|
|
394
|
-
/* @__PURE__ */
|
|
395
|
-
"label",
|
|
396
|
-
{
|
|
397
|
-
htmlFor: `block-type-${type}`,
|
|
398
|
-
className: "flex items-center gap-2 cursor-pointer pointer-events-none",
|
|
399
|
-
children: [
|
|
400
|
-
/* @__PURE__ */ jsx(
|
|
401
|
-
"div",
|
|
402
|
-
{
|
|
403
|
-
className: `${selected ? "opacity-100" : "opacity-70 group-hover:opacity-100"} transition-opacity duration-200 flex items-center justify-center`,
|
|
404
|
-
children: icons[type]
|
|
405
|
-
}
|
|
406
|
-
),
|
|
407
|
-
/* @__PURE__ */ jsx("span", { className: "whitespace-nowrap hidden lg:inline tracking-wide", children: blockStyles[type].label })
|
|
408
|
-
]
|
|
409
|
-
}
|
|
410
|
-
)
|
|
404
|
+
/* @__PURE__ */ jsx("span", { className: "hidden lg:inline tracking-wide", children: blockStyles[type].label })
|
|
411
405
|
]
|
|
412
406
|
},
|
|
413
407
|
type
|
|
414
408
|
);
|
|
415
409
|
}) }),
|
|
416
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-
|
|
417
|
-
/* @__PURE__ */ jsx("div", { className: "w-[1px] h-6 bg-
|
|
410
|
+
/* @__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: [
|
|
411
|
+
/* @__PURE__ */ jsx("div", { className: "hidden sm:block w-[1px] h-6 bg-blumine-200 rounded-full mx-1" }),
|
|
418
412
|
showPdfImport && !isLocked && /* @__PURE__ */ jsx(
|
|
419
413
|
PdfImporter,
|
|
420
414
|
{
|
|
421
415
|
disabled: isLocked,
|
|
422
416
|
onScriptImported: handleScriptImport,
|
|
423
|
-
children: /* @__PURE__ */ jsx(
|
|
424
|
-
"div",
|
|
425
|
-
{
|
|
426
|
-
title: "Import Script",
|
|
427
|
-
className: "flex items-center justify-center",
|
|
428
|
-
children: /* @__PURE__ */ jsx(Upload, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
429
|
-
}
|
|
430
|
-
)
|
|
417
|
+
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]" }) })
|
|
431
418
|
}
|
|
432
419
|
),
|
|
433
420
|
onToggleLock && /* @__PURE__ */ jsx(
|
|
434
421
|
"button",
|
|
435
422
|
{
|
|
436
423
|
onClick: onToggleLock,
|
|
437
|
-
className: `
|
|
438
|
-
title: isLocked ? "Unlock Script" : "Lock Script",
|
|
439
|
-
"aria-label": isLocked ? "Unlock Script" : "Lock Script",
|
|
424
|
+
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"}`,
|
|
440
425
|
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]" })
|
|
441
426
|
}
|
|
442
427
|
),
|
|
@@ -444,9 +429,7 @@ function ScreenplayEditorView({
|
|
|
444
429
|
"button",
|
|
445
430
|
{
|
|
446
431
|
onClick: onSave,
|
|
447
|
-
className: "
|
|
448
|
-
title: "Save Script",
|
|
449
|
-
"aria-label": "Save Script",
|
|
432
|
+
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",
|
|
450
433
|
children: /* @__PURE__ */ jsx(Save, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
451
434
|
}
|
|
452
435
|
),
|
|
@@ -454,9 +437,7 @@ function ScreenplayEditorView({
|
|
|
454
437
|
"button",
|
|
455
438
|
{
|
|
456
439
|
onClick: onSaveAsPdf,
|
|
457
|
-
className: "
|
|
458
|
-
title: "Save as PDF",
|
|
459
|
-
"aria-label": "Save Script as PDF",
|
|
440
|
+
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",
|
|
460
441
|
children: /* @__PURE__ */ jsx(FileDown, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
461
442
|
}
|
|
462
443
|
),
|
|
@@ -464,9 +445,7 @@ function ScreenplayEditorView({
|
|
|
464
445
|
"button",
|
|
465
446
|
{
|
|
466
447
|
onClick: onSyncWithCloud,
|
|
467
|
-
className: "
|
|
468
|
-
title: "Sync with Cloud",
|
|
469
|
-
"aria-label": "Sync with Cloud",
|
|
448
|
+
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",
|
|
470
449
|
children: /* @__PURE__ */ jsx(RefreshCcw, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
471
450
|
}
|
|
472
451
|
),
|
|
@@ -475,35 +454,65 @@ function ScreenplayEditorView({
|
|
|
475
454
|
"button",
|
|
476
455
|
{
|
|
477
456
|
onClick: () => setIsRulesOpen(!isRulesOpen),
|
|
478
|
-
className: `
|
|
479
|
-
title: "Settings & Shortcuts",
|
|
480
|
-
"aria-label": "Toggle Settings",
|
|
457
|
+
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"}`,
|
|
481
458
|
children: /* @__PURE__ */ jsx(Cog, { className: "w-4 h-4 sm:w-[18px] sm:h-[18px]" })
|
|
482
459
|
}
|
|
483
460
|
),
|
|
484
|
-
isRulesOpen && /* @__PURE__ */ jsxs("div", { className: "absolute
|
|
485
|
-
/* @__PURE__ */
|
|
486
|
-
|
|
487
|
-
"
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-zinc-600", children: "New Block" }),
|
|
492
|
-
/* @__PURE__ */ 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" })
|
|
493
|
-
] }),
|
|
494
|
-
/* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-6", children: [
|
|
495
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-zinc-600", children: "Delete Block" }),
|
|
496
|
-
/* @__PURE__ */ 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" })
|
|
497
|
-
] }),
|
|
498
|
-
/* @__PURE__ */ jsxs("li", { className: "flex items-center justify-between gap-6", children: [
|
|
499
|
-
/* @__PURE__ */ jsx("span", { className: "font-medium text-zinc-600", children: "Change Type" }),
|
|
500
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1", children: [
|
|
501
|
-
/* @__PURE__ */ 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" }),
|
|
502
|
-
/* @__PURE__ */ jsx("span", { className: "text-zinc-400 font-medium", children: "+" }),
|
|
503
|
-
/* @__PURE__ */ 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" })
|
|
504
|
-
] })
|
|
461
|
+
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: [
|
|
462
|
+
/* @__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" }),
|
|
463
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-start justify-between mb-3 px-1", children: /* @__PURE__ */ jsxs("div", { className: "flex gap-3", children: [
|
|
464
|
+
/* @__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" }) }),
|
|
465
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
466
|
+
/* @__PURE__ */ jsx("h4", { className: "text-[15px] font-semibold text-blumine-900 leading-tight", children: "Settings & Shortcuts" }),
|
|
467
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-blumine-500 mt-1", children: "Writing flow & editor controls" })
|
|
505
468
|
] })
|
|
506
|
-
] }) })
|
|
469
|
+
] }) }),
|
|
470
|
+
/* @__PURE__ */ jsx("div", { className: "space-y-2", children: [
|
|
471
|
+
{
|
|
472
|
+
title: "New Block",
|
|
473
|
+
desc: "Insert the next section",
|
|
474
|
+
key: ["Enter"]
|
|
475
|
+
},
|
|
476
|
+
{
|
|
477
|
+
title: "Delete Block",
|
|
478
|
+
desc: "Remove selected section",
|
|
479
|
+
key: ["Backspace \u{1F860}"]
|
|
480
|
+
},
|
|
481
|
+
{
|
|
482
|
+
title: "Change Type",
|
|
483
|
+
desc: "Cycle block styles",
|
|
484
|
+
key: ["Ctrl", "+", "\u2191/\u2193"]
|
|
485
|
+
}
|
|
486
|
+
].map((item) => /* @__PURE__ */ jsxs(
|
|
487
|
+
"div",
|
|
488
|
+
{
|
|
489
|
+
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)]",
|
|
490
|
+
children: [
|
|
491
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-col min-w-0", children: [
|
|
492
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-medium text-blumine-800", children: item.title }),
|
|
493
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] text-blumine-500 truncate", children: item.desc })
|
|
494
|
+
] }),
|
|
495
|
+
/* @__PURE__ */ jsx("div", { className: "flex items-center gap-1 shrink-0", children: item.key.map(
|
|
496
|
+
(k, i) => k === "+" ? /* @__PURE__ */ jsx(
|
|
497
|
+
"span",
|
|
498
|
+
{
|
|
499
|
+
className: "text-blumine-400 text-xs font-semibold",
|
|
500
|
+
children: "+"
|
|
501
|
+
},
|
|
502
|
+
i
|
|
503
|
+
) : /* @__PURE__ */ jsx(
|
|
504
|
+
"kbd",
|
|
505
|
+
{
|
|
506
|
+
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)]",
|
|
507
|
+
children: k
|
|
508
|
+
},
|
|
509
|
+
i
|
|
510
|
+
)
|
|
511
|
+
) })
|
|
512
|
+
]
|
|
513
|
+
},
|
|
514
|
+
item.title
|
|
515
|
+
)) })
|
|
507
516
|
] })
|
|
508
517
|
] })
|
|
509
518
|
] })
|
|
@@ -703,7 +712,7 @@ function ScreenplayEditorView({
|
|
|
703
712
|
handleBlur(block.id);
|
|
704
713
|
},
|
|
705
714
|
children: [
|
|
706
|
-
/* @__PURE__ */ jsx(User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-
|
|
715
|
+
/* @__PURE__ */ jsx(User, { className: "w-3.5 h-3.5 text-slate-300 group-hover:text-blumine-500 transition-colors mr-3" }),
|
|
707
716
|
/* @__PURE__ */ jsx("span", { className: "flex-1 text-[11px] font-bold tracking-[0.1em] text-slate-600 uppercase text-left", children: char }),
|
|
708
717
|
/* @__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" })
|
|
709
718
|
]
|
|
@@ -739,6 +748,64 @@ function ScreenplayEditorView({
|
|
|
739
748
|
ext
|
|
740
749
|
)) })
|
|
741
750
|
}
|
|
751
|
+
),
|
|
752
|
+
focusedBlockId === block.id && !enhancingBlockId && (block.type === "ACTION" || block.type === "DIALOGUE") && /* @__PURE__ */ jsx(
|
|
753
|
+
"button",
|
|
754
|
+
{
|
|
755
|
+
onClick: () => handleEnhance(block),
|
|
756
|
+
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",
|
|
757
|
+
title: "Enhance with AI",
|
|
758
|
+
children: /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 group-hover/enhance:animate-pulse transition-colors" })
|
|
759
|
+
}
|
|
760
|
+
),
|
|
761
|
+
enhancingBlockId === block.id && (enhancementSuggestion || isEnhancing) && /* @__PURE__ */ jsxs(
|
|
762
|
+
"div",
|
|
763
|
+
{
|
|
764
|
+
className: "absolute left-0 right-0 -top-4 -translate-y-full z-[30] animate-in fade-in zoom-in-95 slide-in-from-bottom-4 duration-300",
|
|
765
|
+
style: { width: "calc(100% + 2rem)", left: "-1rem" },
|
|
766
|
+
children: [
|
|
767
|
+
/* @__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: [
|
|
768
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between pl-1", children: [
|
|
769
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
770
|
+
/* @__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" }) }),
|
|
771
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
772
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] font-bold text-zinc-900 uppercase tracking-wider leading-none", children: "AI Suggestion" }),
|
|
773
|
+
!isEnhancing && /* @__PURE__ */ jsx("p", { className: "text-[10px] text-zinc-500 mt-1 font-medium", children: "Refining your screenplay dialogue" })
|
|
774
|
+
] })
|
|
775
|
+
] }),
|
|
776
|
+
!isEnhancing && /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1.5", children: [
|
|
777
|
+
/* @__PURE__ */ jsx(
|
|
778
|
+
"button",
|
|
779
|
+
{
|
|
780
|
+
onClick: handleRejectEnhance,
|
|
781
|
+
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",
|
|
782
|
+
children: "Discard"
|
|
783
|
+
}
|
|
784
|
+
),
|
|
785
|
+
/* @__PURE__ */ jsxs(
|
|
786
|
+
"button",
|
|
787
|
+
{
|
|
788
|
+
onClick: handleApproveEnhance,
|
|
789
|
+
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",
|
|
790
|
+
children: [
|
|
791
|
+
/* @__PURE__ */ jsx(Check, { className: "w-3.5 h-3.5" }),
|
|
792
|
+
"Apply Changes"
|
|
793
|
+
]
|
|
794
|
+
}
|
|
795
|
+
)
|
|
796
|
+
] })
|
|
797
|
+
] }),
|
|
798
|
+
/* @__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: [
|
|
799
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-3/4 bg-zinc-200/60 animate-pulse rounded-full" }),
|
|
800
|
+
/* @__PURE__ */ jsx("div", { className: "h-3.5 w-1/2 bg-zinc-200/60 animate-pulse rounded-full" })
|
|
801
|
+
] }) : /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2", children: [
|
|
802
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs text-zinc-400 line-through decoration-zinc-300 italic", children: block.text }),
|
|
803
|
+
/* @__PURE__ */ jsx("p", { className: "text-sm text-zinc-800 font-medium leading-relaxed", children: enhancementSuggestion })
|
|
804
|
+
] }) })
|
|
805
|
+
] }) }),
|
|
806
|
+
/* @__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" })
|
|
807
|
+
]
|
|
808
|
+
}
|
|
742
809
|
)
|
|
743
810
|
] })
|
|
744
811
|
},
|
|
@@ -746,7 +813,43 @@ function ScreenplayEditorView({
|
|
|
746
813
|
);
|
|
747
814
|
})
|
|
748
815
|
}
|
|
749
|
-
) })
|
|
816
|
+
) }),
|
|
817
|
+
/* @__PURE__ */ jsx(
|
|
818
|
+
"div",
|
|
819
|
+
{
|
|
820
|
+
className: `sticky bottom-0 left-1/2 -translate-x-1/2 z-[100] transition-all duration-500 ease-in-out ${showUnsavedPopover ? "translate-y-0 opacity-100 scale-100" : "translate-y-full opacity-0 scale-95 pointer-events-none"}`,
|
|
821
|
+
children: /* @__PURE__ */ jsxs("div", { className: "mx-auto w-full max-w-full rounded-[2.5rem] bg-white 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: [
|
|
822
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
|
|
823
|
+
/* @__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" }) }),
|
|
824
|
+
/* @__PURE__ */ jsxs("div", { className: "mr-5", children: [
|
|
825
|
+
/* @__PURE__ */ jsx("p", { className: "text-xs font-bold text-zinc-900 leading-none", children: "Unsaved Changes" }),
|
|
826
|
+
/* @__PURE__ */ jsx("p", { className: "text-[11px] text-zinc-500 mt-1 font-medium", children: "You have changes that haven't been saved yet." })
|
|
827
|
+
] })
|
|
828
|
+
] }),
|
|
829
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-2 w-full sm:w-auto", children: [
|
|
830
|
+
/* @__PURE__ */ jsx(
|
|
831
|
+
"button",
|
|
832
|
+
{
|
|
833
|
+
onClick: ignoreChanges,
|
|
834
|
+
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",
|
|
835
|
+
children: "Ignore"
|
|
836
|
+
}
|
|
837
|
+
),
|
|
838
|
+
/* @__PURE__ */ jsxs(
|
|
839
|
+
"button",
|
|
840
|
+
{
|
|
841
|
+
onClick: syncScreenplay,
|
|
842
|
+
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",
|
|
843
|
+
children: [
|
|
844
|
+
/* @__PURE__ */ jsx(RefreshCcw, { className: "w-4 h-4" }),
|
|
845
|
+
"Sync to Cloud"
|
|
846
|
+
]
|
|
847
|
+
}
|
|
848
|
+
)
|
|
849
|
+
] })
|
|
850
|
+
] })
|
|
851
|
+
}
|
|
852
|
+
)
|
|
750
853
|
] });
|
|
751
854
|
}
|
|
752
855
|
|
|
@@ -954,6 +1057,31 @@ function parseScreenplayText(content) {
|
|
|
954
1057
|
}
|
|
955
1058
|
return blocks.length > 0 ? blocks : [createNewBlock("SCENE_HEADING")];
|
|
956
1059
|
}
|
|
1060
|
+
function serializeToSbx(blocks) {
|
|
1061
|
+
const typeToDivClass = {
|
|
1062
|
+
SCENE_HEADING: "divtype0",
|
|
1063
|
+
ACTION: "divtype2",
|
|
1064
|
+
CHARACTER: "divtype3",
|
|
1065
|
+
PARENTHETICAL: "divtype4",
|
|
1066
|
+
DIALOGUE: "divtype5",
|
|
1067
|
+
TRANSITION: "divtype6",
|
|
1068
|
+
GENERAL: "divtype2"
|
|
1069
|
+
};
|
|
1070
|
+
return blocks.map((block) => {
|
|
1071
|
+
const divClass = typeToDivClass[block.type] || "divtype2";
|
|
1072
|
+
let text = block.text || "";
|
|
1073
|
+
let extraAttributes = "";
|
|
1074
|
+
if (block.type === "SCENE_HEADING") {
|
|
1075
|
+
text = `${block.sceneType || "INT."} ${text} - ${block.timeOfDay || "DAY"}`.toUpperCase();
|
|
1076
|
+
if (block.sceneNumber) {
|
|
1077
|
+
extraAttributes = ` data-scene="${block.sceneNumber}"`;
|
|
1078
|
+
}
|
|
1079
|
+
} else if (block.type === "CHARACTER" || block.type === "TRANSITION") {
|
|
1080
|
+
text = text.toUpperCase();
|
|
1081
|
+
}
|
|
1082
|
+
return `<div class="${divClass}" id="par${block.id}"${extraAttributes}>${text}</div>`;
|
|
1083
|
+
}).join("");
|
|
1084
|
+
}
|
|
957
1085
|
|
|
958
1086
|
// app/hook/use-screenplay-editor.ts
|
|
959
1087
|
var initialBlocks = [
|
|
@@ -1022,13 +1150,23 @@ function useScreenplayEditor(options) {
|
|
|
1022
1150
|
const [newBlockId, setNewBlockId] = useState(null);
|
|
1023
1151
|
const [showSuggestions, setShowSuggestions] = useState(false);
|
|
1024
1152
|
const [showExtensionSuggestions, setShowExtensionSuggestions] = useState(false);
|
|
1153
|
+
const [isLoading, setIsLoading] = useState(!!(options == null ? void 0 : options.initialUrl));
|
|
1154
|
+
const [enhancingBlockId, setEnhancingBlockId] = useState(null);
|
|
1155
|
+
const [enhancementSuggestion, setEnhancementSuggestion] = useState(null);
|
|
1156
|
+
const [isEnhancing, setIsEnhancing] = useState(false);
|
|
1157
|
+
const [hasUnsavedChanges, setHasUnsavedChanges] = useState(false);
|
|
1158
|
+
const [showUnsavedPopover, setShowUnsavedPopover] = useState(false);
|
|
1159
|
+
const popoverTimeoutRef = useRef(null);
|
|
1025
1160
|
const blurTimeout = useRef(null);
|
|
1161
|
+
const isInitialLoadRef = useRef(true);
|
|
1026
1162
|
const loadedUrlRef = useRef(null);
|
|
1027
1163
|
const lastSavedContent = useRef(null);
|
|
1028
1164
|
const onSaveRef = useRef(options == null ? void 0 : options.onSave);
|
|
1165
|
+
const onSyncWithCloudRef = useRef(options == null ? void 0 : options.onSyncWithCloud);
|
|
1029
1166
|
useEffect(() => {
|
|
1030
1167
|
onSaveRef.current = options == null ? void 0 : options.onSave;
|
|
1031
|
-
|
|
1168
|
+
onSyncWithCloudRef.current = options == null ? void 0 : options.onSyncWithCloud;
|
|
1169
|
+
}, [options == null ? void 0 : options.onSave, options == null ? void 0 : options.onSyncWithCloud]);
|
|
1032
1170
|
const characterExtensions = useMemo(
|
|
1033
1171
|
() => ["(V.O.)", "(O.S.)", "(O.C.)", "(SUBTITLE)", "(CONT'D)"],
|
|
1034
1172
|
[]
|
|
@@ -1415,29 +1553,7 @@ function useScreenplayEditor(options) {
|
|
|
1415
1553
|
});
|
|
1416
1554
|
setBlocks(finalizedBlocks);
|
|
1417
1555
|
if (onSaveRef.current) {
|
|
1418
|
-
const
|
|
1419
|
-
SCENE_HEADING: "divtype0",
|
|
1420
|
-
ACTION: "divtype2",
|
|
1421
|
-
CHARACTER: "divtype3",
|
|
1422
|
-
PARENTHETICAL: "divtype4",
|
|
1423
|
-
DIALOGUE: "divtype5",
|
|
1424
|
-
TRANSITION: "divtype6",
|
|
1425
|
-
GENERAL: "divtype2"
|
|
1426
|
-
};
|
|
1427
|
-
const sbxData = finalizedBlocks.map((block) => {
|
|
1428
|
-
const divClass = typeToDivClass[block.type] || "divtype2";
|
|
1429
|
-
let text = block.text || "";
|
|
1430
|
-
let extraAttributes = "";
|
|
1431
|
-
if (block.type === "SCENE_HEADING") {
|
|
1432
|
-
text = `${block.sceneType || "INT."} ${text} - ${block.timeOfDay || "DAY"}`.toUpperCase();
|
|
1433
|
-
if (block.sceneNumber) {
|
|
1434
|
-
extraAttributes = ` data-scene="${block.sceneNumber}"`;
|
|
1435
|
-
}
|
|
1436
|
-
} else if (block.type === "CHARACTER" || block.type === "TRANSITION") {
|
|
1437
|
-
text = text.toUpperCase();
|
|
1438
|
-
}
|
|
1439
|
-
return `<div class="${divClass}" id="par${block.id}"${extraAttributes}>${text}</div>`;
|
|
1440
|
-
}).join("");
|
|
1556
|
+
const sbxData = serializeToSbx(finalizedBlocks);
|
|
1441
1557
|
if (sbxData !== lastSavedContent.current) {
|
|
1442
1558
|
lastSavedContent.current = sbxData;
|
|
1443
1559
|
if (!isInitialLoad) {
|
|
@@ -1490,9 +1606,22 @@ function useScreenplayEditor(options) {
|
|
|
1490
1606
|
setShowExtensionSuggestions(false);
|
|
1491
1607
|
}, 200);
|
|
1492
1608
|
}, []);
|
|
1609
|
+
const syncScreenplay = useCallback(() => {
|
|
1610
|
+
if (!onSyncWithCloudRef.current) return;
|
|
1611
|
+
onSyncWithCloudRef.current(blocks, sceneNumbers);
|
|
1612
|
+
lastSavedContent.current = serializeToSbx(blocks);
|
|
1613
|
+
setHasUnsavedChanges(false);
|
|
1614
|
+
setShowUnsavedPopover(false);
|
|
1615
|
+
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
1616
|
+
}, [blocks, sceneNumbers]);
|
|
1617
|
+
const ignoreChanges = useCallback(() => {
|
|
1618
|
+
setShowUnsavedPopover(false);
|
|
1619
|
+
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
1620
|
+
}, []);
|
|
1493
1621
|
const loadFromUrl = useCallback(
|
|
1494
1622
|
async (url, fetchOptions = {}, isInitialLoad) => {
|
|
1495
1623
|
var _a;
|
|
1624
|
+
setIsLoading(true);
|
|
1496
1625
|
try {
|
|
1497
1626
|
const response = await fetch(url, fetchOptions);
|
|
1498
1627
|
if (!response.ok) {
|
|
@@ -1569,16 +1698,42 @@ function useScreenplayEditor(options) {
|
|
|
1569
1698
|
preParsedBlocks,
|
|
1570
1699
|
isInitialLoad
|
|
1571
1700
|
);
|
|
1572
|
-
}
|
|
1573
|
-
|
|
1574
|
-
"[useScreenplayEditor] Error loading script from URL:",
|
|
1575
|
-
error
|
|
1576
|
-
);
|
|
1577
|
-
throw error;
|
|
1701
|
+
} finally {
|
|
1702
|
+
setIsLoading(false);
|
|
1578
1703
|
}
|
|
1579
1704
|
},
|
|
1580
1705
|
[handleScriptImport]
|
|
1581
1706
|
);
|
|
1707
|
+
useEffect(() => {
|
|
1708
|
+
if (isLoading) {
|
|
1709
|
+
isInitialLoadRef.current = true;
|
|
1710
|
+
return;
|
|
1711
|
+
}
|
|
1712
|
+
const currentSbx = serializeToSbx(blocks);
|
|
1713
|
+
if (isInitialLoadRef.current) {
|
|
1714
|
+
if (lastSavedContent.current === null) {
|
|
1715
|
+
lastSavedContent.current = currentSbx;
|
|
1716
|
+
}
|
|
1717
|
+
isInitialLoadRef.current = false;
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1720
|
+
const hasActualChanges = lastSavedContent.current !== null && currentSbx !== lastSavedContent.current;
|
|
1721
|
+
if (hasActualChanges) {
|
|
1722
|
+
setHasUnsavedChanges(true);
|
|
1723
|
+
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
1724
|
+
setShowUnsavedPopover(false);
|
|
1725
|
+
popoverTimeoutRef.current = setTimeout(() => {
|
|
1726
|
+
setShowUnsavedPopover(true);
|
|
1727
|
+
}, 1e3);
|
|
1728
|
+
} else {
|
|
1729
|
+
setHasUnsavedChanges(false);
|
|
1730
|
+
setShowUnsavedPopover(false);
|
|
1731
|
+
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
1732
|
+
}
|
|
1733
|
+
return () => {
|
|
1734
|
+
if (popoverTimeoutRef.current) clearTimeout(popoverTimeoutRef.current);
|
|
1735
|
+
};
|
|
1736
|
+
}, [blocks, isLoading]);
|
|
1582
1737
|
useEffect(() => {
|
|
1583
1738
|
if ((options == null ? void 0 : options.initialUrl) && options.initialUrl !== loadedUrlRef.current) {
|
|
1584
1739
|
loadedUrlRef.current = options.initialUrl;
|
|
@@ -1595,6 +1750,7 @@ function useScreenplayEditor(options) {
|
|
|
1595
1750
|
locations,
|
|
1596
1751
|
characters,
|
|
1597
1752
|
sceneNumbers,
|
|
1753
|
+
isLoading,
|
|
1598
1754
|
handleBlockTextChange,
|
|
1599
1755
|
handleSceneTypeChange,
|
|
1600
1756
|
handleTimeOfDayChange,
|
|
@@ -1605,6 +1761,61 @@ function useScreenplayEditor(options) {
|
|
|
1605
1761
|
handleSceneNumberChange,
|
|
1606
1762
|
handleFocus,
|
|
1607
1763
|
handleBlur,
|
|
1764
|
+
handleEnhance: async (block) => {
|
|
1765
|
+
if (isEnhancing || enhancingBlockId || !(options == null ? void 0 : options.enhanceContentUrl))
|
|
1766
|
+
return;
|
|
1767
|
+
setEnhancingBlockId(block.id);
|
|
1768
|
+
setIsEnhancing(true);
|
|
1769
|
+
setEnhancementSuggestion(null);
|
|
1770
|
+
try {
|
|
1771
|
+
const res = await fetch(options == null ? void 0 : options.enhanceContentUrl, {
|
|
1772
|
+
method: "POST",
|
|
1773
|
+
headers: {
|
|
1774
|
+
"Content-Type": "application/json"
|
|
1775
|
+
},
|
|
1776
|
+
body: JSON.stringify({
|
|
1777
|
+
mode: block.type.toLowerCase(),
|
|
1778
|
+
script: block.text,
|
|
1779
|
+
language: "English"
|
|
1780
|
+
})
|
|
1781
|
+
});
|
|
1782
|
+
const data = await res.json();
|
|
1783
|
+
const content = data.data;
|
|
1784
|
+
setEnhancementSuggestion(content);
|
|
1785
|
+
} catch (error) {
|
|
1786
|
+
console.error("Failed to enhance block:", error);
|
|
1787
|
+
if (error) {
|
|
1788
|
+
setIsEnhancing(false);
|
|
1789
|
+
}
|
|
1790
|
+
} finally {
|
|
1791
|
+
setIsEnhancing(false);
|
|
1792
|
+
}
|
|
1793
|
+
},
|
|
1794
|
+
handleApproveEnhance: () => {
|
|
1795
|
+
if (enhancingBlockId && enhancementSuggestion) {
|
|
1796
|
+
setBlocks(
|
|
1797
|
+
(bs) => updateBlock(
|
|
1798
|
+
bs,
|
|
1799
|
+
enhancingBlockId,
|
|
1800
|
+
"text",
|
|
1801
|
+
enhancementSuggestion
|
|
1802
|
+
)
|
|
1803
|
+
);
|
|
1804
|
+
}
|
|
1805
|
+
setEnhancingBlockId(null);
|
|
1806
|
+
setEnhancementSuggestion(null);
|
|
1807
|
+
},
|
|
1808
|
+
handleRejectEnhance: () => {
|
|
1809
|
+
setEnhancingBlockId(null);
|
|
1810
|
+
setEnhancementSuggestion(null);
|
|
1811
|
+
},
|
|
1812
|
+
enhancingBlockId,
|
|
1813
|
+
enhancementSuggestion,
|
|
1814
|
+
isEnhancing,
|
|
1815
|
+
hasUnsavedChanges,
|
|
1816
|
+
showUnsavedPopover,
|
|
1817
|
+
syncScreenplay,
|
|
1818
|
+
ignoreChanges,
|
|
1608
1819
|
loadFromUrl
|
|
1609
1820
|
};
|
|
1610
1821
|
}
|