@vishu1301/script-writing 0.4.6 → 0.4.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 +122 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +3 -2
- package/dist/index.d.ts +3 -2
- package/dist/index.js +123 -36
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -161,45 +161,107 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
161
161
|
setIsProcessing(true);
|
|
162
162
|
setError(null);
|
|
163
163
|
try {
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
const
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
164
|
+
if (file.name.toLowerCase().endsWith(".sbx")) {
|
|
165
|
+
let text = await file.text();
|
|
166
|
+
if (text.includes("<div")) {
|
|
167
|
+
const textarea = document.createElement("textarea");
|
|
168
|
+
textarea.innerHTML = text;
|
|
169
|
+
text = textarea.value;
|
|
170
|
+
}
|
|
171
|
+
const parser = new DOMParser();
|
|
172
|
+
const doc = parser.parseFromString(text, "text/html");
|
|
173
|
+
const divs = Array.from(doc.querySelectorAll("div"));
|
|
174
|
+
const preParsedBlocks = [];
|
|
175
|
+
const typeMap = {
|
|
176
|
+
divtype0: "SCENE_HEADING",
|
|
177
|
+
divtype2: "ACTION",
|
|
178
|
+
divtype3: "CHARACTER",
|
|
179
|
+
divtype4: "PARENTHETICAL",
|
|
180
|
+
divtype5: "DIALOGUE",
|
|
181
|
+
divtype6: "TRANSITION"
|
|
182
|
+
};
|
|
183
|
+
divs.forEach((div) => {
|
|
184
|
+
var _a2;
|
|
185
|
+
let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
186
|
+
if (!divText) return;
|
|
187
|
+
let type = "ACTION";
|
|
188
|
+
for (const className of Array.from(div.classList)) {
|
|
189
|
+
if (typeMap[className]) {
|
|
190
|
+
type = typeMap[className];
|
|
178
191
|
break;
|
|
179
192
|
}
|
|
180
193
|
}
|
|
181
|
-
|
|
182
|
-
|
|
194
|
+
const block = { type, text: divText };
|
|
195
|
+
if (type === "SCENE_HEADING") {
|
|
196
|
+
const sceneNum = div.getAttribute("data-scene");
|
|
197
|
+
if (sceneNum) block.sceneNumber = sceneNum;
|
|
198
|
+
let parsedText = divText;
|
|
199
|
+
const typeMatch = parsedText.match(/^(INT\/EXT|INT|EXT)\.?\s+/i);
|
|
200
|
+
if (typeMatch) {
|
|
201
|
+
let sType = typeMatch[1].toUpperCase();
|
|
202
|
+
if (!sType.endsWith(".")) sType += ".";
|
|
203
|
+
block.sceneType = sType;
|
|
204
|
+
parsedText = parsedText.substring(typeMatch[0].length).trim();
|
|
205
|
+
}
|
|
206
|
+
const timeMatch = parsedText.match(/\s+-\s+([^-]+)$/);
|
|
207
|
+
if (timeMatch) {
|
|
208
|
+
block.timeOfDay = timeMatch[1].trim().toUpperCase();
|
|
209
|
+
parsedText = parsedText.substring(0, timeMatch.index).trim();
|
|
210
|
+
}
|
|
211
|
+
block.text = parsedText;
|
|
212
|
+
}
|
|
213
|
+
preParsedBlocks.push(block);
|
|
214
|
+
});
|
|
215
|
+
const title = file.name.replace(/\.sbx$/i, "");
|
|
216
|
+
onScriptImported(title.trim(), "", preParsedBlocks);
|
|
217
|
+
} else {
|
|
218
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
219
|
+
const pdf = await pdfjs__namespace.getDocument(arrayBuffer).promise;
|
|
220
|
+
const processPage = async (pageNumber) => {
|
|
221
|
+
const page = await pdf.getPage(pageNumber);
|
|
222
|
+
const content = await page.getTextContent();
|
|
223
|
+
const items = content.items.filter(
|
|
224
|
+
(item) => "str" in item && item.str.trim().length > 0
|
|
225
|
+
);
|
|
226
|
+
if (items.length === 0) return "";
|
|
227
|
+
const lines = [];
|
|
228
|
+
for (const item of items) {
|
|
229
|
+
let found = false;
|
|
230
|
+
for (const line of lines) {
|
|
231
|
+
if (Math.abs(line.y - item.transform[5]) < 5) {
|
|
232
|
+
line.items.push({ x: item.transform[4], text: item.str });
|
|
233
|
+
found = true;
|
|
234
|
+
break;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
if (!found) {
|
|
238
|
+
lines.push({
|
|
239
|
+
y: item.transform[5],
|
|
240
|
+
items: [{ x: item.transform[4], text: item.str }]
|
|
241
|
+
});
|
|
242
|
+
}
|
|
183
243
|
}
|
|
244
|
+
lines.sort((a, b) => b.y - a.y);
|
|
245
|
+
return lines.map((line) => {
|
|
246
|
+
line.items.sort((a, b) => a.x - b.x);
|
|
247
|
+
return line.items.map((item) => item.text).join(" ");
|
|
248
|
+
}).join("\n");
|
|
249
|
+
};
|
|
250
|
+
let title = "";
|
|
251
|
+
if (pdf.numPages > 0) {
|
|
252
|
+
title = await processPage(1);
|
|
184
253
|
}
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
};
|
|
191
|
-
let title = "";
|
|
192
|
-
if (pdf.numPages > 0) {
|
|
193
|
-
title = await processPage(1);
|
|
194
|
-
}
|
|
195
|
-
let scriptContent = "";
|
|
196
|
-
for (let i = 2; i <= pdf.numPages; i++) {
|
|
197
|
-
scriptContent += await processPage(i) + "\n\n";
|
|
254
|
+
let scriptContent = "";
|
|
255
|
+
for (let i = 2; i <= pdf.numPages; i++) {
|
|
256
|
+
scriptContent += await processPage(i) + "\n\n";
|
|
257
|
+
}
|
|
258
|
+
onScriptImported(title.trim(), scriptContent);
|
|
198
259
|
}
|
|
199
|
-
onScriptImported(title.trim(), scriptContent);
|
|
200
260
|
} catch (err) {
|
|
201
261
|
console.error("Error processing PDF:", err);
|
|
202
|
-
setError(
|
|
262
|
+
setError(
|
|
263
|
+
err instanceof Error ? `Error processing PDF: ${err.message}` : "An unknown error occurred."
|
|
264
|
+
);
|
|
203
265
|
} finally {
|
|
204
266
|
setIsProcessing(false);
|
|
205
267
|
if (event.target) {
|
|
@@ -217,7 +279,7 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
217
279
|
{
|
|
218
280
|
ref: fileInputRef,
|
|
219
281
|
type: "file",
|
|
220
|
-
accept: "application/pdf",
|
|
282
|
+
accept: ".pdf,.sbx,application/pdf",
|
|
221
283
|
onChange: handleFileChange,
|
|
222
284
|
disabled: isProcessing,
|
|
223
285
|
className: "hidden",
|
|
@@ -230,7 +292,7 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
230
292
|
onClick: handleClick,
|
|
231
293
|
disabled: isProcessing,
|
|
232
294
|
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",
|
|
233
|
-
"aria-label": "Import Script
|
|
295
|
+
"aria-label": "Import Script",
|
|
234
296
|
children: isProcessing ? /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Processing..." }) : children
|
|
235
297
|
}
|
|
236
298
|
),
|
|
@@ -260,6 +322,7 @@ function ScreenplayEditorView({
|
|
|
260
322
|
handleScriptImport,
|
|
261
323
|
onSave,
|
|
262
324
|
onSaveAsPdf,
|
|
325
|
+
onSaveAsSbx,
|
|
263
326
|
onSyncWithCloud,
|
|
264
327
|
handleSceneNumberChange
|
|
265
328
|
}) {
|
|
@@ -553,6 +616,18 @@ function ScreenplayEditorView({
|
|
|
553
616
|
]
|
|
554
617
|
}
|
|
555
618
|
),
|
|
619
|
+
onSaveAsSbx && /* @__PURE__ */ jsxRuntime.jsxs(
|
|
620
|
+
"button",
|
|
621
|
+
{
|
|
622
|
+
onClick: onSaveAsSbx,
|
|
623
|
+
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",
|
|
624
|
+
"aria-label": "Save Script as SBX",
|
|
625
|
+
children: [
|
|
626
|
+
/* @__PURE__ */ jsxRuntime.jsx(lucideReact.RefreshCcw, { className: "w-5 h-5" }),
|
|
627
|
+
/* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-sm font-semibold", children: "Save" })
|
|
628
|
+
]
|
|
629
|
+
}
|
|
630
|
+
),
|
|
556
631
|
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: [
|
|
557
632
|
/* @__PURE__ */ jsxRuntime.jsx("h4", { className: "font-bold text-zinc-800 mb-3 text-sm", children: "Settings & Shortcuts" }),
|
|
558
633
|
/* @__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: [
|
|
@@ -1215,8 +1290,20 @@ function useScreenplayEditor() {
|
|
|
1215
1290
|
[blocks, handleBlockTextChange]
|
|
1216
1291
|
);
|
|
1217
1292
|
const handleScriptImport = react.useCallback(
|
|
1218
|
-
(title, content) => {
|
|
1219
|
-
|
|
1293
|
+
(title, content, preParsedBlocks) => {
|
|
1294
|
+
let parsedBlocks = [];
|
|
1295
|
+
if (preParsedBlocks && preParsedBlocks.length > 0) {
|
|
1296
|
+
parsedBlocks = preParsedBlocks.map((b) => ({
|
|
1297
|
+
id: uuid(),
|
|
1298
|
+
type: b.type || "ACTION",
|
|
1299
|
+
text: b.text || "",
|
|
1300
|
+
sceneNumber: b.sceneNumber,
|
|
1301
|
+
sceneType: b.sceneType,
|
|
1302
|
+
timeOfDay: b.timeOfDay
|
|
1303
|
+
}));
|
|
1304
|
+
} else {
|
|
1305
|
+
parsedBlocks = parseScreenplayText(content);
|
|
1306
|
+
}
|
|
1220
1307
|
if (parsedBlocks.length > 0) {
|
|
1221
1308
|
let fallbackCount = 1;
|
|
1222
1309
|
const finalizedBlocks = parsedBlocks.map((block) => {
|