@vishu1301/script-writing 0.4.6 → 0.4.8
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 +254 -35
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +251 -37
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -37,7 +37,7 @@ declare function useScreenplayEditor(): {
|
|
|
37
37
|
handleBlockTypeChange: (newType: BlockType) => void;
|
|
38
38
|
handleSelectCharacterExtension: (extension: string) => void;
|
|
39
39
|
handleKeyDown: (e: KeyboardEvent<HTMLDivElement>, id: string, text: string) => void;
|
|
40
|
-
handleScriptImport: (title: string, content: string) => void;
|
|
40
|
+
handleScriptImport: (title: string, content: string, preParsedBlocks?: Partial<Block>[]) => void;
|
|
41
41
|
handleSceneNumberChange: (id: string, newNumber: string) => void;
|
|
42
42
|
handleFocus: (id: string) => void;
|
|
43
43
|
handleBlur: (id: string) => void;
|
|
@@ -46,9 +46,13 @@ declare function useScreenplayEditor(): {
|
|
|
46
46
|
type ScreenplayEditorViewProps = ReturnType<typeof useScreenplayEditor> & {
|
|
47
47
|
onSave?: () => void;
|
|
48
48
|
onSaveAsPdf?: () => void;
|
|
49
|
+
onSaveAsSbx?: () => void;
|
|
49
50
|
onSyncWithCloud?: () => void;
|
|
50
51
|
handleSceneNumberChange: (blockId: string, value: string) => void;
|
|
51
52
|
};
|
|
52
|
-
declare function ScreenplayEditorView({ blocks, refs, focusedBlockId, showSuggestions, showExtensionSuggestions, characterExtensions, locations, characters, handleBlockTextChange, handleSceneTypeChange, handleTimeOfDayChange, handleBlockTypeChange, handleSelectCharacterExtension, handleKeyDown, handleFocus, handleBlur, handleScriptImport, onSave, onSaveAsPdf, onSyncWithCloud, handleSceneNumberChange, }: ScreenplayEditorViewProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
declare function ScreenplayEditorView({ blocks, refs, focusedBlockId, showSuggestions, showExtensionSuggestions, characterExtensions, locations, characters, handleBlockTextChange, handleSceneTypeChange, handleTimeOfDayChange, handleBlockTypeChange, handleSelectCharacterExtension, handleKeyDown, handleFocus, handleBlur, handleScriptImport, onSave, onSaveAsPdf, onSaveAsSbx, onSyncWithCloud, handleSceneNumberChange, }: ScreenplayEditorViewProps): react_jsx_runtime.JSX.Element;
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
declare const handleSaveAsPdf: (blocks: Block[], sceneNumbers: Record<string, string>) => void;
|
|
56
|
+
declare const handleSaveAsSbx: (blocks: Block[], sceneNumbers: Record<string, string>, onSaveAsSbx?: (file: File) => void) => void;
|
|
57
|
+
|
|
58
|
+
export { type Block, type BlockType, ScreenplayEditorView, type TimeOfDay, blockStyles, blockTypes, handleSaveAsPdf, handleSaveAsSbx, icons, timeOfDayOptions, useScreenplayEditor, uuid };
|
package/dist/index.d.ts
CHANGED
|
@@ -37,7 +37,7 @@ declare function useScreenplayEditor(): {
|
|
|
37
37
|
handleBlockTypeChange: (newType: BlockType) => void;
|
|
38
38
|
handleSelectCharacterExtension: (extension: string) => void;
|
|
39
39
|
handleKeyDown: (e: KeyboardEvent<HTMLDivElement>, id: string, text: string) => void;
|
|
40
|
-
handleScriptImport: (title: string, content: string) => void;
|
|
40
|
+
handleScriptImport: (title: string, content: string, preParsedBlocks?: Partial<Block>[]) => void;
|
|
41
41
|
handleSceneNumberChange: (id: string, newNumber: string) => void;
|
|
42
42
|
handleFocus: (id: string) => void;
|
|
43
43
|
handleBlur: (id: string) => void;
|
|
@@ -46,9 +46,13 @@ declare function useScreenplayEditor(): {
|
|
|
46
46
|
type ScreenplayEditorViewProps = ReturnType<typeof useScreenplayEditor> & {
|
|
47
47
|
onSave?: () => void;
|
|
48
48
|
onSaveAsPdf?: () => void;
|
|
49
|
+
onSaveAsSbx?: () => void;
|
|
49
50
|
onSyncWithCloud?: () => void;
|
|
50
51
|
handleSceneNumberChange: (blockId: string, value: string) => void;
|
|
51
52
|
};
|
|
52
|
-
declare function ScreenplayEditorView({ blocks, refs, focusedBlockId, showSuggestions, showExtensionSuggestions, characterExtensions, locations, characters, handleBlockTextChange, handleSceneTypeChange, handleTimeOfDayChange, handleBlockTypeChange, handleSelectCharacterExtension, handleKeyDown, handleFocus, handleBlur, handleScriptImport, onSave, onSaveAsPdf, onSyncWithCloud, handleSceneNumberChange, }: ScreenplayEditorViewProps): react_jsx_runtime.JSX.Element;
|
|
53
|
+
declare function ScreenplayEditorView({ blocks, refs, focusedBlockId, showSuggestions, showExtensionSuggestions, characterExtensions, locations, characters, handleBlockTextChange, handleSceneTypeChange, handleTimeOfDayChange, handleBlockTypeChange, handleSelectCharacterExtension, handleKeyDown, handleFocus, handleBlur, handleScriptImport, onSave, onSaveAsPdf, onSaveAsSbx, onSyncWithCloud, handleSceneNumberChange, }: ScreenplayEditorViewProps): react_jsx_runtime.JSX.Element;
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
declare const handleSaveAsPdf: (blocks: Block[], sceneNumbers: Record<string, string>) => void;
|
|
56
|
+
declare const handleSaveAsSbx: (blocks: Block[], sceneNumbers: Record<string, string>, onSaveAsSbx?: (file: File) => void) => void;
|
|
57
|
+
|
|
58
|
+
export { type Block, type BlockType, ScreenplayEditorView, type TimeOfDay, blockStyles, blockTypes, handleSaveAsPdf, handleSaveAsSbx, icons, timeOfDayOptions, useScreenplayEditor, uuid };
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { useState, useRef, useMemo, useCallback, useEffect } from 'react';
|
|
2
|
-
import { ArrowRightLeft, MessageCircle, Brackets, UserRound, Sparkles, Clapperboard, ArrowRight, User, ChevronRight, Upload, Save, FileDown, Cog } from 'lucide-react';
|
|
2
|
+
import { ArrowRightLeft, MessageCircle, Brackets, UserRound, Sparkles, Clapperboard, ArrowRight, User, ChevronRight, Upload, Save, FileDown, RefreshCcw, Cog } from 'lucide-react';
|
|
3
3
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
4
4
|
import * as pdfjs from 'pdfjs-dist';
|
|
5
|
+
import jsPDF from 'jspdf';
|
|
5
6
|
|
|
6
7
|
var __defProp = Object.defineProperty;
|
|
7
8
|
var __defProps = Object.defineProperties;
|
|
@@ -139,45 +140,107 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
139
140
|
setIsProcessing(true);
|
|
140
141
|
setError(null);
|
|
141
142
|
try {
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
143
|
+
if (file.name.toLowerCase().endsWith(".sbx")) {
|
|
144
|
+
let text = await file.text();
|
|
145
|
+
if (text.includes("<div")) {
|
|
146
|
+
const textarea = document.createElement("textarea");
|
|
147
|
+
textarea.innerHTML = text;
|
|
148
|
+
text = textarea.value;
|
|
149
|
+
}
|
|
150
|
+
const parser = new DOMParser();
|
|
151
|
+
const doc = parser.parseFromString(text, "text/html");
|
|
152
|
+
const divs = Array.from(doc.querySelectorAll("div"));
|
|
153
|
+
const preParsedBlocks = [];
|
|
154
|
+
const typeMap = {
|
|
155
|
+
divtype0: "SCENE_HEADING",
|
|
156
|
+
divtype2: "ACTION",
|
|
157
|
+
divtype3: "CHARACTER",
|
|
158
|
+
divtype4: "PARENTHETICAL",
|
|
159
|
+
divtype5: "DIALOGUE",
|
|
160
|
+
divtype6: "TRANSITION"
|
|
161
|
+
};
|
|
162
|
+
divs.forEach((div) => {
|
|
163
|
+
var _a2;
|
|
164
|
+
let divText = ((_a2 = div.textContent) == null ? void 0 : _a2.trim()) || "";
|
|
165
|
+
if (!divText) return;
|
|
166
|
+
let type = "ACTION";
|
|
167
|
+
for (const className of Array.from(div.classList)) {
|
|
168
|
+
if (typeMap[className]) {
|
|
169
|
+
type = typeMap[className];
|
|
156
170
|
break;
|
|
157
171
|
}
|
|
158
172
|
}
|
|
159
|
-
|
|
160
|
-
|
|
173
|
+
const block = { type, text: divText };
|
|
174
|
+
if (type === "SCENE_HEADING") {
|
|
175
|
+
const sceneNum = div.getAttribute("data-scene");
|
|
176
|
+
if (sceneNum) block.sceneNumber = sceneNum;
|
|
177
|
+
let parsedText = divText;
|
|
178
|
+
const typeMatch = parsedText.match(/^(INT\/EXT|INT|EXT)\.?\s+/i);
|
|
179
|
+
if (typeMatch) {
|
|
180
|
+
let sType = typeMatch[1].toUpperCase();
|
|
181
|
+
if (!sType.endsWith(".")) sType += ".";
|
|
182
|
+
block.sceneType = sType;
|
|
183
|
+
parsedText = parsedText.substring(typeMatch[0].length).trim();
|
|
184
|
+
}
|
|
185
|
+
const timeMatch = parsedText.match(/\s+-\s+([^-]+)$/);
|
|
186
|
+
if (timeMatch) {
|
|
187
|
+
block.timeOfDay = timeMatch[1].trim().toUpperCase();
|
|
188
|
+
parsedText = parsedText.substring(0, timeMatch.index).trim();
|
|
189
|
+
}
|
|
190
|
+
block.text = parsedText;
|
|
191
|
+
}
|
|
192
|
+
preParsedBlocks.push(block);
|
|
193
|
+
});
|
|
194
|
+
const title = file.name.replace(/\.sbx$/i, "");
|
|
195
|
+
onScriptImported(title.trim(), "", preParsedBlocks);
|
|
196
|
+
} else {
|
|
197
|
+
const arrayBuffer = await file.arrayBuffer();
|
|
198
|
+
const pdf = await pdfjs.getDocument(arrayBuffer).promise;
|
|
199
|
+
const processPage = async (pageNumber) => {
|
|
200
|
+
const page = await pdf.getPage(pageNumber);
|
|
201
|
+
const content = await page.getTextContent();
|
|
202
|
+
const items = content.items.filter(
|
|
203
|
+
(item) => "str" in item && item.str.trim().length > 0
|
|
204
|
+
);
|
|
205
|
+
if (items.length === 0) return "";
|
|
206
|
+
const lines = [];
|
|
207
|
+
for (const item of items) {
|
|
208
|
+
let found = false;
|
|
209
|
+
for (const line of lines) {
|
|
210
|
+
if (Math.abs(line.y - item.transform[5]) < 5) {
|
|
211
|
+
line.items.push({ x: item.transform[4], text: item.str });
|
|
212
|
+
found = true;
|
|
213
|
+
break;
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
if (!found) {
|
|
217
|
+
lines.push({
|
|
218
|
+
y: item.transform[5],
|
|
219
|
+
items: [{ x: item.transform[4], text: item.str }]
|
|
220
|
+
});
|
|
221
|
+
}
|
|
161
222
|
}
|
|
223
|
+
lines.sort((a, b) => b.y - a.y);
|
|
224
|
+
return lines.map((line) => {
|
|
225
|
+
line.items.sort((a, b) => a.x - b.x);
|
|
226
|
+
return line.items.map((item) => item.text).join(" ");
|
|
227
|
+
}).join("\n");
|
|
228
|
+
};
|
|
229
|
+
let title = "";
|
|
230
|
+
if (pdf.numPages > 0) {
|
|
231
|
+
title = await processPage(1);
|
|
162
232
|
}
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
};
|
|
169
|
-
let title = "";
|
|
170
|
-
if (pdf.numPages > 0) {
|
|
171
|
-
title = await processPage(1);
|
|
172
|
-
}
|
|
173
|
-
let scriptContent = "";
|
|
174
|
-
for (let i = 2; i <= pdf.numPages; i++) {
|
|
175
|
-
scriptContent += await processPage(i) + "\n\n";
|
|
233
|
+
let scriptContent = "";
|
|
234
|
+
for (let i = 2; i <= pdf.numPages; i++) {
|
|
235
|
+
scriptContent += await processPage(i) + "\n\n";
|
|
236
|
+
}
|
|
237
|
+
onScriptImported(title.trim(), scriptContent);
|
|
176
238
|
}
|
|
177
|
-
onScriptImported(title.trim(), scriptContent);
|
|
178
239
|
} catch (err) {
|
|
179
240
|
console.error("Error processing PDF:", err);
|
|
180
|
-
setError(
|
|
241
|
+
setError(
|
|
242
|
+
err instanceof Error ? `Error processing PDF: ${err.message}` : "An unknown error occurred."
|
|
243
|
+
);
|
|
181
244
|
} finally {
|
|
182
245
|
setIsProcessing(false);
|
|
183
246
|
if (event.target) {
|
|
@@ -195,7 +258,7 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
195
258
|
{
|
|
196
259
|
ref: fileInputRef,
|
|
197
260
|
type: "file",
|
|
198
|
-
accept: "application/pdf",
|
|
261
|
+
accept: ".pdf,.sbx,application/pdf",
|
|
199
262
|
onChange: handleFileChange,
|
|
200
263
|
disabled: isProcessing,
|
|
201
264
|
className: "hidden",
|
|
@@ -208,7 +271,7 @@ function PdfImporter({ onScriptImported, children }) {
|
|
|
208
271
|
onClick: handleClick,
|
|
209
272
|
disabled: isProcessing,
|
|
210
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",
|
|
211
|
-
"aria-label": "Import Script
|
|
274
|
+
"aria-label": "Import Script",
|
|
212
275
|
children: isProcessing ? /* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Processing..." }) : children
|
|
213
276
|
}
|
|
214
277
|
),
|
|
@@ -238,6 +301,7 @@ function ScreenplayEditorView({
|
|
|
238
301
|
handleScriptImport,
|
|
239
302
|
onSave,
|
|
240
303
|
onSaveAsPdf,
|
|
304
|
+
onSaveAsSbx,
|
|
241
305
|
onSyncWithCloud,
|
|
242
306
|
handleSceneNumberChange
|
|
243
307
|
}) {
|
|
@@ -531,6 +595,18 @@ function ScreenplayEditorView({
|
|
|
531
595
|
]
|
|
532
596
|
}
|
|
533
597
|
),
|
|
598
|
+
onSaveAsSbx && /* @__PURE__ */ jsxs(
|
|
599
|
+
"button",
|
|
600
|
+
{
|
|
601
|
+
onClick: onSaveAsSbx,
|
|
602
|
+
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",
|
|
603
|
+
"aria-label": "Save Script as SBX",
|
|
604
|
+
children: [
|
|
605
|
+
/* @__PURE__ */ jsx(RefreshCcw, { className: "w-5 h-5" }),
|
|
606
|
+
/* @__PURE__ */ jsx("span", { className: "text-sm font-semibold", children: "Save" })
|
|
607
|
+
]
|
|
608
|
+
}
|
|
609
|
+
),
|
|
534
610
|
isRulesOpen && /* @__PURE__ */ 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: [
|
|
535
611
|
/* @__PURE__ */ jsx("h4", { className: "font-bold text-zinc-800 mb-3 text-sm", children: "Settings & Shortcuts" }),
|
|
536
612
|
/* @__PURE__ */ jsx("div", { className: "space-y-4", children: /* @__PURE__ */ jsx("div", { className: "space-y-1.5", children: /* @__PURE__ */ jsxs("ul", { className: "space-y-1.5", children: [
|
|
@@ -1193,8 +1269,20 @@ function useScreenplayEditor() {
|
|
|
1193
1269
|
[blocks, handleBlockTextChange]
|
|
1194
1270
|
);
|
|
1195
1271
|
const handleScriptImport = useCallback(
|
|
1196
|
-
(title, content) => {
|
|
1197
|
-
|
|
1272
|
+
(title, content, preParsedBlocks) => {
|
|
1273
|
+
let parsedBlocks = [];
|
|
1274
|
+
if (preParsedBlocks && preParsedBlocks.length > 0) {
|
|
1275
|
+
parsedBlocks = preParsedBlocks.map((b) => ({
|
|
1276
|
+
id: uuid(),
|
|
1277
|
+
type: b.type || "ACTION",
|
|
1278
|
+
text: b.text || "",
|
|
1279
|
+
sceneNumber: b.sceneNumber,
|
|
1280
|
+
sceneType: b.sceneType,
|
|
1281
|
+
timeOfDay: b.timeOfDay
|
|
1282
|
+
}));
|
|
1283
|
+
} else {
|
|
1284
|
+
parsedBlocks = parseScreenplayText(content);
|
|
1285
|
+
}
|
|
1198
1286
|
if (parsedBlocks.length > 0) {
|
|
1199
1287
|
let fallbackCount = 1;
|
|
1200
1288
|
const finalizedBlocks = parsedBlocks.map((block) => {
|
|
@@ -1277,7 +1365,133 @@ function useScreenplayEditor() {
|
|
|
1277
1365
|
handleBlur
|
|
1278
1366
|
};
|
|
1279
1367
|
}
|
|
1368
|
+
var handleSaveAsPdf = (blocks, sceneNumbers) => {
|
|
1369
|
+
if (document.activeElement instanceof HTMLElement) {
|
|
1370
|
+
document.activeElement.blur();
|
|
1371
|
+
}
|
|
1372
|
+
const doc = new jsPDF({
|
|
1373
|
+
orientation: "portrait",
|
|
1374
|
+
unit: "mm",
|
|
1375
|
+
format: "letter"
|
|
1376
|
+
});
|
|
1377
|
+
const FONT_SIZE = 12;
|
|
1378
|
+
const LINE_HEIGHT = 4.233;
|
|
1379
|
+
const PAGE_WIDTH = doc.internal.pageSize.getWidth();
|
|
1380
|
+
const PAGE_HEIGHT = doc.internal.pageSize.getHeight();
|
|
1381
|
+
const MARGIN_LEFT = 38.1;
|
|
1382
|
+
const MARGIN_RIGHT = 25.4;
|
|
1383
|
+
const MARGIN_TOP = 25.4;
|
|
1384
|
+
const MARGIN_BOTTOM = 25.4;
|
|
1385
|
+
const blockDimensions = {
|
|
1386
|
+
SCENE_HEADING: { indent: 0, width: 152.4, upper: true, bold: true },
|
|
1387
|
+
ACTION: { indent: 0, width: 152.4, upper: false, bold: false },
|
|
1388
|
+
CHARACTER: { indent: 50.8, width: 101.6, upper: true, bold: false },
|
|
1389
|
+
PARENTHETICAL: { indent: 38.1, width: 50.8, upper: false, bold: false },
|
|
1390
|
+
DIALOGUE: { indent: 25.4, width: 88.9, upper: false, bold: false },
|
|
1391
|
+
TRANSITION: {
|
|
1392
|
+
indent: 0,
|
|
1393
|
+
width: 152.4,
|
|
1394
|
+
upper: true,
|
|
1395
|
+
bold: false,
|
|
1396
|
+
align: "right"
|
|
1397
|
+
},
|
|
1398
|
+
GENERAL: { indent: 0, width: 152.4, upper: false, bold: false }
|
|
1399
|
+
};
|
|
1400
|
+
let y = MARGIN_TOP;
|
|
1401
|
+
let pageNumber = 1;
|
|
1402
|
+
const drawPageNumber = (num) => {
|
|
1403
|
+
if (num > 1) {
|
|
1404
|
+
doc.setFont("Courier", "normal");
|
|
1405
|
+
doc.setFontSize(12);
|
|
1406
|
+
doc.text(`${num}.`, PAGE_WIDTH - MARGIN_RIGHT, 12.7, {
|
|
1407
|
+
align: "right"
|
|
1408
|
+
});
|
|
1409
|
+
}
|
|
1410
|
+
};
|
|
1411
|
+
blocks.forEach((block, index) => {
|
|
1412
|
+
const config = blockDimensions[block.type] || blockDimensions.GENERAL;
|
|
1413
|
+
let text = block.text || "";
|
|
1414
|
+
if (config.upper) text = text.toUpperCase();
|
|
1415
|
+
if (block.type === "SCENE_HEADING") {
|
|
1416
|
+
text = `${block.sceneType || "INT."} ${text} - ${block.timeOfDay || "DAY"}`.toUpperCase();
|
|
1417
|
+
}
|
|
1418
|
+
doc.setFont("Courier", config.bold ? "bold" : "normal");
|
|
1419
|
+
doc.setFontSize(FONT_SIZE);
|
|
1420
|
+
const lines = doc.splitTextToSize(text, config.width);
|
|
1421
|
+
const blockHeight = lines.length * LINE_HEIGHT;
|
|
1422
|
+
let safetyBuffer = 0;
|
|
1423
|
+
if (block.type === "CHARACTER") safetyBuffer = LINE_HEIGHT * 3;
|
|
1424
|
+
if (y + blockHeight + safetyBuffer > PAGE_HEIGHT - MARGIN_BOTTOM) {
|
|
1425
|
+
doc.addPage();
|
|
1426
|
+
pageNumber++;
|
|
1427
|
+
drawPageNumber(pageNumber);
|
|
1428
|
+
y = MARGIN_TOP;
|
|
1429
|
+
doc.setFont("Courier", config.bold ? "bold" : "normal");
|
|
1430
|
+
doc.setFontSize(FONT_SIZE);
|
|
1431
|
+
}
|
|
1432
|
+
if (y > MARGIN_TOP) {
|
|
1433
|
+
if (block.type === "SCENE_HEADING" || block.type === "ACTION" || block.type === "CHARACTER") {
|
|
1434
|
+
y += LINE_HEIGHT;
|
|
1435
|
+
}
|
|
1436
|
+
}
|
|
1437
|
+
const xPos = MARGIN_LEFT + config.indent;
|
|
1438
|
+
if (config.align === "right") {
|
|
1439
|
+
doc.text(lines, PAGE_WIDTH - MARGIN_RIGHT, y, { align: "right" });
|
|
1440
|
+
} else {
|
|
1441
|
+
doc.text(lines, xPos, y);
|
|
1442
|
+
}
|
|
1443
|
+
if (block.type === "SCENE_HEADING" && (sceneNumbers == null ? void 0 : sceneNumbers[block.id])) {
|
|
1444
|
+
const sNum = String(sceneNumbers[block.id]);
|
|
1445
|
+
doc.setFont("Courier", "normal");
|
|
1446
|
+
doc.setFontSize(FONT_SIZE);
|
|
1447
|
+
doc.text(sNum, MARGIN_LEFT - 12, y);
|
|
1448
|
+
doc.text(sNum, PAGE_WIDTH - MARGIN_RIGHT + 5, y);
|
|
1449
|
+
doc.setFont("Courier", config.bold ? "bold" : "normal");
|
|
1450
|
+
}
|
|
1451
|
+
y += blockHeight;
|
|
1452
|
+
});
|
|
1453
|
+
doc.save("screenplay_export.pdf");
|
|
1454
|
+
};
|
|
1455
|
+
var handleSaveAsSbx = (blocks, sceneNumbers, onSaveAsSbx) => {
|
|
1456
|
+
const typeToDivClass = {
|
|
1457
|
+
SCENE_HEADING: "divtype0",
|
|
1458
|
+
ACTION: "divtype2",
|
|
1459
|
+
CHARACTER: "divtype3",
|
|
1460
|
+
PARENTHETICAL: "divtype4",
|
|
1461
|
+
DIALOGUE: "divtype5",
|
|
1462
|
+
TRANSITION: "divtype6",
|
|
1463
|
+
GENERAL: "divtype2"
|
|
1464
|
+
};
|
|
1465
|
+
const sbxData = blocks.map((block) => {
|
|
1466
|
+
const divClass = typeToDivClass[block.type] || "divtype2";
|
|
1467
|
+
let text = block.text || "";
|
|
1468
|
+
let extraAttributes = "";
|
|
1469
|
+
if (block.type === "SCENE_HEADING") {
|
|
1470
|
+
text = `${block.sceneType || "INT."} ${text} - ${block.timeOfDay || "DAY"}`.toUpperCase();
|
|
1471
|
+
const sceneNum = sceneNumbers == null ? void 0 : sceneNumbers[block.id];
|
|
1472
|
+
if (sceneNum) {
|
|
1473
|
+
extraAttributes = ` data-scene="${sceneNum}"`;
|
|
1474
|
+
}
|
|
1475
|
+
} else if (block.type === "CHARACTER" || block.type === "TRANSITION") {
|
|
1476
|
+
text = text.toUpperCase();
|
|
1477
|
+
}
|
|
1478
|
+
return `<div class="${divClass}" id="par${block.id}"${extraAttributes}>${text}</div>`;
|
|
1479
|
+
}).join("");
|
|
1480
|
+
const blob = new Blob([sbxData], { type: "text/plain" });
|
|
1481
|
+
const url = URL.createObjectURL(blob);
|
|
1482
|
+
const a = document.createElement("a");
|
|
1483
|
+
a.href = url;
|
|
1484
|
+
a.download = "screenplay.sbx";
|
|
1485
|
+
document.body.appendChild(a);
|
|
1486
|
+
a.click();
|
|
1487
|
+
document.body.removeChild(a);
|
|
1488
|
+
URL.revokeObjectURL(url);
|
|
1489
|
+
if (onSaveAsSbx) {
|
|
1490
|
+
const file = new File([blob], "screenplay.sbx", { type: "text/plain" });
|
|
1491
|
+
onSaveAsSbx(file);
|
|
1492
|
+
}
|
|
1493
|
+
};
|
|
1280
1494
|
|
|
1281
|
-
export { ScreenplayEditorView, blockStyles, blockTypes, icons, timeOfDayOptions, useScreenplayEditor, uuid };
|
|
1495
|
+
export { ScreenplayEditorView, blockStyles, blockTypes, handleSaveAsPdf, handleSaveAsSbx, icons, timeOfDayOptions, useScreenplayEditor, uuid };
|
|
1282
1496
|
//# sourceMappingURL=index.js.map
|
|
1283
1497
|
//# sourceMappingURL=index.js.map
|