@vishu1301/script-writing 1.1.3 → 1.1.4
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 +283 -180
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +18 -9
- package/dist/index.d.ts +18 -9
- package/dist/index.js +284 -181
- 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 { ArrowRightLeft, MessageCircle, Brackets, UserRound, Sparkles, Clapperboard, Upload, Save, FileDown, RefreshCcw, Cog, ArrowRight, User, ChevronRight, Loader2, AlignLeft, Tags, Plus, X } from 'lucide-react';
|
|
2
|
+
import { ArrowRightLeft, MessageCircle, Brackets, UserRound, Sparkles, Clapperboard, Upload, Lock, Unlock, Save, FileDown, RefreshCcw, Cog, ArrowRight, User, ChevronRight, Loader2, AlignLeft, Tags, Plus, X } 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';
|
|
@@ -127,7 +127,7 @@ var blockStyles = {
|
|
|
127
127
|
}
|
|
128
128
|
};
|
|
129
129
|
pdfjs.GlobalWorkerOptions.workerSrc = `//unpkg.com/pdfjs-dist@${pdfjs.version}/build/pdf.worker.min.mjs`;
|
|
130
|
-
function PdfImporter({ onScriptImported, children }) {
|
|
130
|
+
function PdfImporter({ onScriptImported, disabled, children }) {
|
|
131
131
|
const [isProcessing, setIsProcessing] = useState(false);
|
|
132
132
|
const [error, setError] = useState(null);
|
|
133
133
|
const fileInputRef = useRef(null);
|
|
@@ -260,7 +260,7 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
260
260
|
type: "file",
|
|
261
261
|
accept: ".pdf,application/pdf",
|
|
262
262
|
onChange: handleFileChange,
|
|
263
|
-
disabled: isProcessing,
|
|
263
|
+
disabled: isProcessing || disabled,
|
|
264
264
|
className: "hidden",
|
|
265
265
|
id: "pdf-importer-input"
|
|
266
266
|
}
|
|
@@ -269,8 +269,8 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
269
269
|
"button",
|
|
270
270
|
{
|
|
271
271
|
onClick: handleClick,
|
|
272
|
-
disabled: isProcessing,
|
|
273
|
-
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",
|
|
272
|
+
disabled: isProcessing || disabled,
|
|
273
|
+
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 disabled:cursor-not-allowed disabled:bg-zinc-700 disabled:shadow-none disabled:border-zinc-600/50",
|
|
274
274
|
"aria-label": "Import Script",
|
|
275
275
|
children: isProcessing ? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Processing..." }) : children
|
|
276
276
|
}
|
|
@@ -293,6 +293,8 @@ function ScreenplayEditorView({
|
|
|
293
293
|
showPdfImport = false,
|
|
294
294
|
showSaveButton = false,
|
|
295
295
|
showSyncButton = false,
|
|
296
|
+
isLocked = false,
|
|
297
|
+
onToggleLock,
|
|
296
298
|
handleBlockTextChange,
|
|
297
299
|
handleSceneTypeChange,
|
|
298
300
|
handleTimeOfDayChange,
|
|
@@ -366,7 +368,8 @@ function ScreenplayEditorView({
|
|
|
366
368
|
"button",
|
|
367
369
|
{
|
|
368
370
|
type: "button",
|
|
369
|
-
|
|
371
|
+
disabled: isLocked,
|
|
372
|
+
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"} ${isLocked ? "opacity-50 cursor-not-allowed" : ""}`,
|
|
370
373
|
onClick: () => handleBlockTypeChange(type),
|
|
371
374
|
children: [
|
|
372
375
|
/* @__PURE__ */ jsx(
|
|
@@ -405,8 +408,18 @@ function ScreenplayEditorView({
|
|
|
405
408
|
}) }),
|
|
406
409
|
/* @__PURE__ */ jsxs("div", { className: "flex items-center gap-1 shrink-0 relative px-1", children: [
|
|
407
410
|
/* @__PURE__ */ jsx("div", { className: "w-[1px] h-6 bg-zinc-200/80 mx-2 hidden sm:block rounded-full" }),
|
|
408
|
-
showPdfImport && /* @__PURE__ */ jsx(PdfImporter, { onScriptImported: handleScriptImport, children: /* @__PURE__ */ jsx("div", { title: "Import Script", children: /* @__PURE__ */ jsx(Upload, { className: "w-[18px] h-[18px]" }) }) }),
|
|
409
|
-
|
|
411
|
+
showPdfImport && /* @__PURE__ */ jsx(PdfImporter, { disabled: isLocked, onScriptImported: handleScriptImport, children: /* @__PURE__ */ jsx("div", { title: "Import Script", children: /* @__PURE__ */ jsx(Upload, { className: "w-[18px] h-[18px]" }) }) }),
|
|
412
|
+
onToggleLock && /* @__PURE__ */ jsx(
|
|
413
|
+
"button",
|
|
414
|
+
{
|
|
415
|
+
onClick: onToggleLock,
|
|
416
|
+
className: `flex items-center justify-center w-10 h-10 rounded-full transition-all duration-200 active:scale-95 ${isLocked ? "text-rose-500 hover:bg-rose-50" : "text-zinc-500 hover:bg-zinc-100 hover:text-zinc-900"}`,
|
|
417
|
+
title: isLocked ? "Unlock Script" : "Lock Script",
|
|
418
|
+
"aria-label": isLocked ? "Unlock Script" : "Lock Script",
|
|
419
|
+
children: isLocked ? /* @__PURE__ */ jsx(Lock, { className: "w-[18px] h-[18px]" }) : /* @__PURE__ */ jsx(Unlock, { className: "w-[18px] h-[18px]" })
|
|
420
|
+
}
|
|
421
|
+
),
|
|
422
|
+
onSave && showSaveButton && !isLocked && /* @__PURE__ */ jsx(
|
|
410
423
|
"button",
|
|
411
424
|
{
|
|
412
425
|
onClick: onSave,
|
|
@@ -426,7 +439,7 @@ function ScreenplayEditorView({
|
|
|
426
439
|
children: /* @__PURE__ */ jsx(FileDown, { className: "w-[18px] h-[18px]" })
|
|
427
440
|
}
|
|
428
441
|
),
|
|
429
|
-
onSyncWithCloud && showSyncButton && /* @__PURE__ */ jsx(
|
|
442
|
+
onSyncWithCloud && showSyncButton && !isLocked && /* @__PURE__ */ jsx(
|
|
430
443
|
"button",
|
|
431
444
|
{
|
|
432
445
|
onClick: onSyncWithCloud,
|
|
@@ -503,6 +516,7 @@ function ScreenplayEditorView({
|
|
|
503
516
|
{
|
|
504
517
|
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",
|
|
505
518
|
spellCheck: false,
|
|
519
|
+
disabled: isLocked,
|
|
506
520
|
value: block.sceneNumber || "",
|
|
507
521
|
onChange: (e) => handleSceneNumberChange(
|
|
508
522
|
block.id,
|
|
@@ -523,6 +537,7 @@ function ScreenplayEditorView({
|
|
|
523
537
|
{
|
|
524
538
|
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",
|
|
525
539
|
"aria-label": "Scene Type",
|
|
540
|
+
disabled: isLocked,
|
|
526
541
|
value: (_a = block.sceneType) != null ? _a : "INT.",
|
|
527
542
|
onChange: (e) => handleSceneTypeChange(block.id, e.target.value),
|
|
528
543
|
style: {
|
|
@@ -542,7 +557,7 @@ function ScreenplayEditorView({
|
|
|
542
557
|
if (!el) return;
|
|
543
558
|
refs.current[block.id] = el;
|
|
544
559
|
},
|
|
545
|
-
contentEditable:
|
|
560
|
+
contentEditable: !isLocked,
|
|
546
561
|
suppressContentEditableWarning: true,
|
|
547
562
|
"aria-label": `Scene Heading: ${block.text}`,
|
|
548
563
|
"aria-haspopup": "listbox",
|
|
@@ -567,6 +582,7 @@ function ScreenplayEditorView({
|
|
|
567
582
|
{
|
|
568
583
|
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",
|
|
569
584
|
"aria-label": "Time of Day",
|
|
585
|
+
disabled: isLocked,
|
|
570
586
|
value: (_b = block.timeOfDay) != null ? _b : "DAY",
|
|
571
587
|
style: {
|
|
572
588
|
appearance: "none"
|
|
@@ -622,7 +638,7 @@ function ScreenplayEditorView({
|
|
|
622
638
|
if (!el) return;
|
|
623
639
|
refs.current[block.id] = el;
|
|
624
640
|
},
|
|
625
|
-
contentEditable:
|
|
641
|
+
contentEditable: !isLocked,
|
|
626
642
|
suppressContentEditableWarning: true,
|
|
627
643
|
"aria-label": `${blockStyles[block.type].label} text`,
|
|
628
644
|
"aria-multiline": block.type === "ACTION" || block.type === "DIALOGUE",
|
|
@@ -1703,13 +1719,14 @@ var handleSyncWithCloud = (blocks, sceneNumbers, onSaveAsSbx, project_name) => {
|
|
|
1703
1719
|
|
|
1704
1720
|
// app/types/script-breakdown.types.tsx
|
|
1705
1721
|
var CATEGORIES = [
|
|
1706
|
-
{ id: "CAST", label: "Cast", color: "#
|
|
1707
|
-
{ id: "PROP", label: "Prop", color: "#
|
|
1708
|
-
{ id: "COSTUME", label: "Costume", color: "#
|
|
1709
|
-
{ id: "VEHICLE", label: "Vehicle", color: "#
|
|
1710
|
-
{ id: "SET_PROP", label: "Set Prop", color: "#
|
|
1711
|
-
{ id: "EXTRA", label: "Extra", color: "#
|
|
1712
|
-
{ id: "LOCATION", label: "Location", color: "#
|
|
1722
|
+
{ id: "CAST", label: "Cast", color: "#7C3AED", hex: "#A78BFA" },
|
|
1723
|
+
{ id: "PROP", label: "Prop", color: "#FF6A00", hex: "#FFB86B" },
|
|
1724
|
+
{ id: "COSTUME", label: "Costume", color: "#FF2E93", hex: "#FF8AC2" },
|
|
1725
|
+
{ id: "VEHICLE", label: "Vehicle", color: "#00A6FF", hex: "#6ED6FF" },
|
|
1726
|
+
{ id: "SET_PROP", label: "Set Prop", color: "#00C853", hex: "#69F0AE" },
|
|
1727
|
+
{ id: "EXTRA", label: "Extra", color: "#00B8D4", hex: "#62EFFF" },
|
|
1728
|
+
{ id: "LOCATION", label: "Location", color: "#FFB300", hex: "#FFE082" },
|
|
1729
|
+
{ id: "OTHER", label: "Other", color: "#9E9E9E", hex: "#E0E0E0" }
|
|
1713
1730
|
];
|
|
1714
1731
|
function ScriptBreakdownSceneView({
|
|
1715
1732
|
blocks,
|
|
@@ -1728,7 +1745,9 @@ function ScriptBreakdownSceneView({
|
|
|
1728
1745
|
addSubLocation,
|
|
1729
1746
|
removeSubLocation,
|
|
1730
1747
|
sceneBrief,
|
|
1731
|
-
setSceneBrief
|
|
1748
|
+
setSceneBrief,
|
|
1749
|
+
onSummarize,
|
|
1750
|
+
isSummarizing
|
|
1732
1751
|
}) {
|
|
1733
1752
|
const COURIER_STACK = "'Courier Prime', 'Courier', monospace";
|
|
1734
1753
|
const [isSubLocOpen, setIsSubLocOpen] = useState(false);
|
|
@@ -1775,47 +1794,54 @@ function ScriptBreakdownSceneView({
|
|
|
1775
1794
|
/* @__PURE__ */ jsx("p", { className: "text-sm font-medium text-zinc-500 animate-pulse", children: "Loading scene details..." })
|
|
1776
1795
|
] });
|
|
1777
1796
|
}
|
|
1778
|
-
const hasLocationTag = tags.some((t) => t.
|
|
1797
|
+
const hasLocationTag = tags.some((t) => t.category_id === "LOCATION");
|
|
1779
1798
|
const renderBlockText = (block) => {
|
|
1780
|
-
const blockTags = tags.filter((t) => t.
|
|
1799
|
+
const blockTags = tags.filter((t) => t.block_id === block.id).sort((a, b) => a.start_index - b.start_index);
|
|
1781
1800
|
if (blockTags.length === 0) return block.text;
|
|
1782
1801
|
const nodes = [];
|
|
1783
1802
|
let currentIndex = 0;
|
|
1784
1803
|
blockTags.forEach((tag) => {
|
|
1785
|
-
|
|
1804
|
+
const actualStart = Math.max(tag.start_index, currentIndex);
|
|
1805
|
+
if (actualStart > currentIndex) {
|
|
1786
1806
|
nodes.push(
|
|
1787
|
-
/* @__PURE__ */ jsx("span", { children: block.text.slice(currentIndex,
|
|
1807
|
+
/* @__PURE__ */ jsx("span", { children: block.text.slice(currentIndex, actualStart) }, `text-${currentIndex}`)
|
|
1788
1808
|
);
|
|
1789
1809
|
}
|
|
1790
|
-
const category = CATEGORIES.find((c) => c.id === tag.
|
|
1791
|
-
|
|
1792
|
-
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
e
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
+
const category = CATEGORIES.find((c) => c.id === tag.category_id);
|
|
1811
|
+
if (actualStart < tag.end_index) {
|
|
1812
|
+
nodes.push(
|
|
1813
|
+
/* @__PURE__ */ jsx(
|
|
1814
|
+
"span",
|
|
1815
|
+
{
|
|
1816
|
+
title: `${category == null ? void 0 : category.label} (Click to edit)`,
|
|
1817
|
+
onClick: (e) => {
|
|
1818
|
+
e.stopPropagation();
|
|
1819
|
+
const selection = window.getSelection();
|
|
1820
|
+
if (!selection) return;
|
|
1821
|
+
const range = document.createRange();
|
|
1822
|
+
const textNode = e.currentTarget.firstChild;
|
|
1823
|
+
if (textNode && textNode.nodeType === Node.TEXT_NODE) {
|
|
1824
|
+
range.selectNodeContents(textNode);
|
|
1825
|
+
} else {
|
|
1826
|
+
range.selectNodeContents(e.currentTarget);
|
|
1827
|
+
}
|
|
1828
|
+
selection.removeAllRanges();
|
|
1829
|
+
selection.addRange(range);
|
|
1830
|
+
setTimeout(() => handleMouseUp(), 0);
|
|
1831
|
+
},
|
|
1832
|
+
className: "cursor-pointer font-bold transition-all hover:opacity-80 rounded-[3px]",
|
|
1833
|
+
style: {
|
|
1834
|
+
color: category == null ? void 0 : category.color,
|
|
1835
|
+
padding: "0.125rem 0.25rem",
|
|
1836
|
+
margin: "0 -0.125rem"
|
|
1837
|
+
},
|
|
1838
|
+
children: block.text.slice(actualStart, tag.end_index)
|
|
1810
1839
|
},
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
)
|
|
1817
|
-
);
|
|
1818
|
-
currentIndex = tag.endIndex;
|
|
1840
|
+
tag.id || `tag-${actualStart}-${tag.end_index}`
|
|
1841
|
+
)
|
|
1842
|
+
);
|
|
1843
|
+
}
|
|
1844
|
+
currentIndex = Math.max(currentIndex, tag.end_index);
|
|
1819
1845
|
});
|
|
1820
1846
|
if (currentIndex < block.text.length) {
|
|
1821
1847
|
nodes.push(
|
|
@@ -1903,16 +1929,16 @@ function ScriptBreakdownSceneView({
|
|
|
1903
1929
|
cat.id
|
|
1904
1930
|
)),
|
|
1905
1931
|
tags.some(
|
|
1906
|
-
(t) => t.
|
|
1932
|
+
(t) => t.block_id === block.id && t.start_index === selectionMenu.startIndex && t.end_index === selectionMenu.endIndex
|
|
1907
1933
|
) && /* @__PURE__ */ jsx("div", { className: "mt-1 pt-1 border-t border-white/60", children: /* @__PURE__ */ jsxs(
|
|
1908
1934
|
"button",
|
|
1909
1935
|
{
|
|
1910
1936
|
onClick: (e) => {
|
|
1911
1937
|
const tagToRemove = tags.find(
|
|
1912
|
-
(t) => t.
|
|
1938
|
+
(t) => t.block_id === block.id && t.start_index === selectionMenu.startIndex && t.end_index === selectionMenu.endIndex
|
|
1913
1939
|
);
|
|
1914
|
-
if (tagToRemove) {
|
|
1915
|
-
removeTag(e, tagToRemove.id);
|
|
1940
|
+
if (tagToRemove && tagToRemove.id) {
|
|
1941
|
+
removeTag(e, tagToRemove == null ? void 0 : tagToRemove.id);
|
|
1916
1942
|
clearSelection();
|
|
1917
1943
|
}
|
|
1918
1944
|
},
|
|
@@ -1955,115 +1981,136 @@ function ScriptBreakdownSceneView({
|
|
|
1955
1981
|
) })
|
|
1956
1982
|
] })
|
|
1957
1983
|
] }),
|
|
1958
|
-
/* @__PURE__ */
|
|
1959
|
-
/* @__PURE__ */ jsxs(
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
1984
|
+
/* @__PURE__ */ jsxs("div", { className: "w-full lg:w-80 flex-shrink-0 flex flex-col gap-6 sticky top-6", children: [
|
|
1985
|
+
/* @__PURE__ */ jsxs(
|
|
1986
|
+
"button",
|
|
1987
|
+
{
|
|
1988
|
+
onClick: onSummarize,
|
|
1989
|
+
disabled: isSummarizing,
|
|
1990
|
+
className: `group relative w-full py-4 px-6 rounded-[3rem] overflow-hidden bg-gradient-to-b from-white via-zinc-50 to-zinc-100 border border-white/70 shadow-[0_10px_30px_-10px_rgba(0,0,0,0.15),inset_0_1px_0_rgba(255,255,255,0.9)] transition-all duration-500 ease-[cubic-bezier(0.22,1,0.36,1)] ${isSummarizing ? "opacity-70 cursor-wait" : "hover:shadow-[0_20px_50px_-15px_rgba(139,92,246,0.35)] hover:-translate-y-[2px] active:scale-[0.97]"}`,
|
|
1991
|
+
children: [
|
|
1992
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition duration-700", children: /* @__PURE__ */ jsx("span", { className: "absolute inset-0 bg-[conic-gradient(from_180deg_at_50%_50%,#8b5cf6,transparent_40%,#d946ef,transparent_70%)] blur-2xl opacity-30 animate-[spin_6s_linear_infinite]" }) }),
|
|
1993
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-0 opacity-0 group-hover:opacity-100 transition duration-500 bg-[radial-gradient(circle_at_50%_40%,rgba(139,92,246,0.18),transparent_70%)]" }),
|
|
1994
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-[1px] rounded-[inherit] bg-gradient-to-b from-white/90 to-transparent pointer-events-none" }),
|
|
1995
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-0 overflow-hidden", children: /* @__PURE__ */ jsx("span", { className: "absolute -left-[100%] top-0 h-full w-[60%] bg-gradient-to-r from-transparent via-white/60 to-transparent skew-x-[-20deg] group-hover:left-[120%] transition-all duration-[1200ms]" }) }),
|
|
1996
|
+
/* @__PURE__ */ jsx("span", { className: "absolute inset-[2px] rounded-[inherit] opacity-0 group-hover:opacity-100 bg-gradient-to-r from-violet-200/40 via-white/40 to-fuchsia-200/40 blur-md transition duration-500" }),
|
|
1997
|
+
/* @__PURE__ */ jsxs("div", { className: "relative flex items-center justify-center gap-3", children: [
|
|
1998
|
+
isSummarizing ? /* @__PURE__ */ jsx(Loader2, { className: "w-4 h-4 text-violet-500 animate-spin" }) : /* @__PURE__ */ jsx(Sparkles, { className: "w-4 h-4 text-violet-500 transition-all duration-500 group-hover:-rotate-12 group-hover:scale-125" }),
|
|
1999
|
+
/* @__PURE__ */ jsx("span", { className: "text-[11px] font-semibold tracking-[0.32em] uppercase text-zinc-800 group-hover:text-zinc-950 transition-all duration-300", children: isSummarizing ? "Summarizing..." : "Summarize Scene" })
|
|
2000
|
+
] })
|
|
2001
|
+
]
|
|
2002
|
+
}
|
|
2003
|
+
),
|
|
2004
|
+
/* @__PURE__ */ 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: [
|
|
2005
|
+
/* @__PURE__ */ jsxs("h3", { className: "text-xs font-extrabold text-slate-800 uppercase tracking-[0.25em] mb-8 flex items-center gap-3", children: [
|
|
2006
|
+
/* @__PURE__ */ 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__ */ jsx(Tags, { className: "w-3.5 h-3.5 text-slate-500" }) }),
|
|
2007
|
+
"Tags",
|
|
2008
|
+
/* @__PURE__ */ jsx("span", { className: "ml-auto bg-slate-100/80 text-slate-500 px-2.5 py-1 rounded-lg text-[10px] font-bold tracking-widest border border-slate-200/50 shadow-inner", children: tags.length })
|
|
2009
|
+
] }),
|
|
2010
|
+
tags.length > 0 ? /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-8", children: CATEGORIES.map((cat) => {
|
|
2011
|
+
const catTags = Array.from(
|
|
2012
|
+
new Map(
|
|
2013
|
+
tags.filter((t) => t.category_id === cat.id).map((tag) => [tag.name.toLowerCase(), tag])
|
|
2014
|
+
).values()
|
|
2015
|
+
);
|
|
2016
|
+
if (catTags.length === 0) return null;
|
|
2017
|
+
return /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-4", children: [
|
|
2018
|
+
/* @__PURE__ */ jsxs("h4", { className: "text-[10px] font-bold text-slate-400 uppercase tracking-[0.2em] flex items-center gap-2 border-b border-white/60 pb-2", children: [
|
|
2019
|
+
/* @__PURE__ */ jsx(
|
|
2020
|
+
"div",
|
|
2021
|
+
{
|
|
2022
|
+
className: "w-2 h-2 rounded-full shadow-sm",
|
|
2023
|
+
style: { backgroundColor: cat.hex }
|
|
2024
|
+
}
|
|
2025
|
+
),
|
|
2026
|
+
cat.label
|
|
2027
|
+
] }),
|
|
2028
|
+
/* @__PURE__ */ jsxs("div", { className: "flex flex-wrap gap-2", children: [
|
|
2029
|
+
catTags.map((tag, index) => /* @__PURE__ */ jsx(
|
|
2030
|
+
"span",
|
|
2031
|
+
{
|
|
2032
|
+
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",
|
|
2033
|
+
style: { color: cat.color },
|
|
2034
|
+
children: tag.name
|
|
2035
|
+
},
|
|
2036
|
+
index
|
|
2037
|
+
)),
|
|
2038
|
+
cat.id === "LOCATION" && /* @__PURE__ */ jsxs(
|
|
2039
|
+
"div",
|
|
2040
|
+
{
|
|
2041
|
+
className: "relative flex items-center",
|
|
2042
|
+
ref: subLocPopoverRef,
|
|
2043
|
+
children: [
|
|
2044
|
+
/* @__PURE__ */ jsx(
|
|
2045
|
+
"button",
|
|
2046
|
+
{
|
|
2047
|
+
onClick: () => setIsSubLocOpen(!isSubLocOpen),
|
|
2048
|
+
className: "flex items-center justify-center w-5 h-5 rounded-full hover:bg-slate-200 transition-colors",
|
|
2049
|
+
title: "Add Sub Location",
|
|
2050
|
+
children: /* @__PURE__ */ jsx(Plus, { className: "w-3 h-3 text-slate-500" })
|
|
2051
|
+
}
|
|
2052
|
+
),
|
|
2053
|
+
isSubLocOpen && /* @__PURE__ */ jsxs("div", { className: "absolute left-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: [
|
|
2054
|
+
/* @__PURE__ */ jsx("p", { className: "text-[9px] font-extrabold tracking-[0.2em] text-slate-400 uppercase mb-2 px-1", children: "Add Sub Location" }),
|
|
2055
|
+
/* @__PURE__ */ jsxs("div", { className: "flex gap-2 items-center", children: [
|
|
2056
|
+
/* @__PURE__ */ jsx(
|
|
2057
|
+
"input",
|
|
2058
|
+
{
|
|
2059
|
+
type: "text",
|
|
2060
|
+
value: subLocInput,
|
|
2061
|
+
onChange: (e) => setSubLocInput(e.target.value),
|
|
2062
|
+
onKeyDown: (e) => {
|
|
2063
|
+
if (e.key === "Enter") {
|
|
2064
|
+
addSubLocation(subLocInput);
|
|
2065
|
+
setSubLocInput("");
|
|
2066
|
+
setIsSubLocOpen(false);
|
|
2067
|
+
}
|
|
2068
|
+
},
|
|
2069
|
+
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",
|
|
2070
|
+
placeholder: "Sub location...",
|
|
2071
|
+
autoFocus: true
|
|
2072
|
+
}
|
|
2073
|
+
),
|
|
2074
|
+
/* @__PURE__ */ jsx(
|
|
2075
|
+
"button",
|
|
2076
|
+
{
|
|
2077
|
+
onClick: () => {
|
|
2007
2078
|
addSubLocation(subLocInput);
|
|
2008
2079
|
setSubLocInput("");
|
|
2009
2080
|
setIsSubLocOpen(false);
|
|
2010
|
-
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
|
|
2016
|
-
),
|
|
2017
|
-
/* @__PURE__ */ 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
|
-
)
|
|
2081
|
+
},
|
|
2082
|
+
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",
|
|
2083
|
+
children: "Add"
|
|
2084
|
+
}
|
|
2085
|
+
)
|
|
2086
|
+
] })
|
|
2029
2087
|
] })
|
|
2030
|
-
]
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
|
|
2052
|
-
|
|
2053
|
-
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
children: /* @__PURE__ */ jsx(X, { className: "w-2.5 h-2.5" })
|
|
2057
|
-
}
|
|
2058
|
-
)
|
|
2059
|
-
]
|
|
2060
|
-
},
|
|
2061
|
-
`sub-${subLoc}`
|
|
2062
|
-
))
|
|
2063
|
-
] })
|
|
2064
|
-
] }, cat.id);
|
|
2065
|
-
}) }) : /* @__PURE__ */ 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." })
|
|
2066
|
-
] }) })
|
|
2088
|
+
]
|
|
2089
|
+
}
|
|
2090
|
+
),
|
|
2091
|
+
cat.id === "LOCATION" && subLocations.map((subLoc) => /* @__PURE__ */ jsxs(
|
|
2092
|
+
"span",
|
|
2093
|
+
{
|
|
2094
|
+
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",
|
|
2095
|
+
children: [
|
|
2096
|
+
subLoc,
|
|
2097
|
+
/* @__PURE__ */ jsx(
|
|
2098
|
+
"button",
|
|
2099
|
+
{
|
|
2100
|
+
onClick: () => removeSubLocation(subLoc),
|
|
2101
|
+
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",
|
|
2102
|
+
children: /* @__PURE__ */ jsx(X, { className: "w-2.5 h-2.5" })
|
|
2103
|
+
}
|
|
2104
|
+
)
|
|
2105
|
+
]
|
|
2106
|
+
},
|
|
2107
|
+
`sub-${subLoc}`
|
|
2108
|
+
))
|
|
2109
|
+
] })
|
|
2110
|
+
] }, cat.id);
|
|
2111
|
+
}) }) : /* @__PURE__ */ 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." })
|
|
2112
|
+
] })
|
|
2113
|
+
] })
|
|
2067
2114
|
] }) });
|
|
2068
2115
|
}
|
|
2069
2116
|
function useScriptBreakdown({
|
|
@@ -2145,6 +2192,14 @@ var use_script_breakdown_default = useScriptBreakdown;
|
|
|
2145
2192
|
// app/hook/use-script-breakdown-scene.ts
|
|
2146
2193
|
function useScriptBreakdownScene(sceneNumber) {
|
|
2147
2194
|
const { scenes, isLoading, error } = use_script_breakdown_default({ scenes: [] });
|
|
2195
|
+
const [tags, setTags] = useState([]);
|
|
2196
|
+
const [selectionMenu, setSelectionMenu] = useState(null);
|
|
2197
|
+
const autoTaggedSceneRef = useRef(null);
|
|
2198
|
+
const [menuPlacement, setMenuPlacement] = useState("top");
|
|
2199
|
+
const [subLocations, setSubLocations] = useState([]);
|
|
2200
|
+
const [sceneBrief, setSceneBrief] = useState("");
|
|
2201
|
+
const [isSummarizing, setIsSummarizing] = useState(false);
|
|
2202
|
+
const menuRef = useRef(null);
|
|
2148
2203
|
const scene = useMemo(() => {
|
|
2149
2204
|
return scenes.find((s) => s.scene_number === sceneNumber);
|
|
2150
2205
|
}, [scenes, sceneNumber]);
|
|
@@ -2173,7 +2228,9 @@ function useScriptBreakdownScene(sceneNumber) {
|
|
|
2173
2228
|
break;
|
|
2174
2229
|
}
|
|
2175
2230
|
}
|
|
2176
|
-
|
|
2231
|
+
const idAttr = div.getAttribute("id");
|
|
2232
|
+
const blockId = idAttr && idAttr.startsWith("par") ? idAttr.substring(3) : idAttr || uuid();
|
|
2233
|
+
parsedBlocks.push({ id: blockId, type, text: divText });
|
|
2177
2234
|
});
|
|
2178
2235
|
return parsedBlocks;
|
|
2179
2236
|
}, [scene]);
|
|
@@ -2185,12 +2242,57 @@ function useScriptBreakdownScene(sceneNumber) {
|
|
|
2185
2242
|
}).filter(Boolean);
|
|
2186
2243
|
return [...new Set(chars)];
|
|
2187
2244
|
}, [blocks]);
|
|
2188
|
-
const
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
|
|
2192
|
-
|
|
2193
|
-
|
|
2245
|
+
const handleAISummarize = async () => {
|
|
2246
|
+
setIsSummarizing(true);
|
|
2247
|
+
const res = await fetch(
|
|
2248
|
+
"https://nonfibrous-extrafloral-verlene.ngrok-free.dev/extract",
|
|
2249
|
+
{
|
|
2250
|
+
method: "POST",
|
|
2251
|
+
headers: {
|
|
2252
|
+
"Content-Type": "application/json",
|
|
2253
|
+
"ngrok-skip-browser-warning": "true"
|
|
2254
|
+
},
|
|
2255
|
+
body: JSON.stringify({
|
|
2256
|
+
script: (scene == null ? void 0 : scene.content) || ""
|
|
2257
|
+
})
|
|
2258
|
+
}
|
|
2259
|
+
);
|
|
2260
|
+
if (res.ok) {
|
|
2261
|
+
const data = await res.json();
|
|
2262
|
+
setIsSummarizing(false);
|
|
2263
|
+
const parsedData = JSON.parse(data.data) || [];
|
|
2264
|
+
console.log("AI Tags:", parsedData);
|
|
2265
|
+
const newTags = [];
|
|
2266
|
+
parsedData.forEach((aiTag) => {
|
|
2267
|
+
if (!aiTag.block_id || !aiTag.category_id || typeof aiTag.start_index !== "number" || typeof aiTag.end_index !== "number") {
|
|
2268
|
+
return;
|
|
2269
|
+
}
|
|
2270
|
+
newTags.push({
|
|
2271
|
+
block_id: String(aiTag.block_id).startsWith("par") ? String(aiTag.block_id).substring(3) : String(aiTag.block_id),
|
|
2272
|
+
category_id: aiTag.category_id,
|
|
2273
|
+
name: aiTag.name,
|
|
2274
|
+
start_index: aiTag.start_index,
|
|
2275
|
+
end_index: aiTag.end_index
|
|
2276
|
+
});
|
|
2277
|
+
});
|
|
2278
|
+
setTags((prev) => {
|
|
2279
|
+
const merged = [...prev];
|
|
2280
|
+
newTags.forEach((newTag) => {
|
|
2281
|
+
const isOverlapping = merged.some(
|
|
2282
|
+
(t) => t.block_id === newTag.block_id && newTag.end_index > t.start_index && newTag.start_index < t.end_index
|
|
2283
|
+
);
|
|
2284
|
+
if (!isOverlapping) {
|
|
2285
|
+
merged.push(newTag);
|
|
2286
|
+
}
|
|
2287
|
+
});
|
|
2288
|
+
return merged;
|
|
2289
|
+
});
|
|
2290
|
+
return data;
|
|
2291
|
+
} else {
|
|
2292
|
+
setIsSummarizing(false);
|
|
2293
|
+
console.error("Failed to summarize scene:", res);
|
|
2294
|
+
}
|
|
2295
|
+
};
|
|
2194
2296
|
const addSubLocation = useCallback(
|
|
2195
2297
|
(subLocation) => {
|
|
2196
2298
|
const trimmed = subLocation.trim();
|
|
@@ -2203,7 +2305,6 @@ function useScriptBreakdownScene(sceneNumber) {
|
|
|
2203
2305
|
const removeSubLocation = useCallback((subLocation) => {
|
|
2204
2306
|
setSubLocations((prev) => prev.filter((loc) => loc !== subLocation));
|
|
2205
2307
|
}, []);
|
|
2206
|
-
const [sceneBrief, setSceneBrief] = useState("");
|
|
2207
2308
|
useEffect(() => {
|
|
2208
2309
|
setTags([]);
|
|
2209
2310
|
setSubLocations([]);
|
|
@@ -2222,19 +2323,19 @@ function useScriptBreakdownScene(sceneNumber) {
|
|
|
2222
2323
|
let match;
|
|
2223
2324
|
while ((match = regex.exec(block.text)) !== null) {
|
|
2224
2325
|
const isOverlapping = autoTags.some(
|
|
2225
|
-
(t) => t.
|
|
2326
|
+
(t) => t.block_id === block.id && match.index + char.length > t.start_index && match.index < t.end_index
|
|
2226
2327
|
);
|
|
2227
2328
|
if (!isOverlapping) {
|
|
2228
2329
|
autoTags.push({
|
|
2229
2330
|
id: uuid(),
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2331
|
+
block_id: block.id,
|
|
2332
|
+
category_id: "CAST",
|
|
2333
|
+
name: block.text.substring(
|
|
2233
2334
|
match.index,
|
|
2234
2335
|
match.index + char.length
|
|
2235
2336
|
),
|
|
2236
|
-
|
|
2237
|
-
|
|
2337
|
+
start_index: match.index,
|
|
2338
|
+
end_index: match.index + char.length
|
|
2238
2339
|
});
|
|
2239
2340
|
}
|
|
2240
2341
|
}
|
|
@@ -2334,15 +2435,15 @@ function useScriptBreakdownScene(sceneNumber) {
|
|
|
2334
2435
|
if (!selectionMenu) return;
|
|
2335
2436
|
const newTag = {
|
|
2336
2437
|
id: uuid(),
|
|
2337
|
-
|
|
2338
|
-
categoryId,
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2438
|
+
block_id: selectionMenu.blockId,
|
|
2439
|
+
category_id: categoryId,
|
|
2440
|
+
name: selectionMenu.text,
|
|
2441
|
+
start_index: selectionMenu.startIndex,
|
|
2442
|
+
end_index: selectionMenu.endIndex
|
|
2342
2443
|
};
|
|
2343
2444
|
setTags((prev) => {
|
|
2344
2445
|
const filtered = prev.filter(
|
|
2345
|
-
(t) => t.
|
|
2446
|
+
(t) => t.block_id !== newTag.block_id || !(newTag.end_index > t.start_index && newTag.start_index < t.end_index)
|
|
2346
2447
|
);
|
|
2347
2448
|
return [...filtered, newTag];
|
|
2348
2449
|
});
|
|
@@ -2372,7 +2473,9 @@ function useScriptBreakdownScene(sceneNumber) {
|
|
|
2372
2473
|
addSubLocation,
|
|
2373
2474
|
removeSubLocation,
|
|
2374
2475
|
sceneBrief,
|
|
2375
|
-
setSceneBrief
|
|
2476
|
+
setSceneBrief,
|
|
2477
|
+
handleAISummarize,
|
|
2478
|
+
isSummarizing
|
|
2376
2479
|
};
|
|
2377
2480
|
}
|
|
2378
2481
|
|