cvdl-ts 1.0.13 → 1.0.14
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/AnyLayout.d.ts +1 -1
- package/dist/AnyLayout.js +8 -9
- package/dist/Elem.d.ts +3 -1
- package/dist/Elem.js +17 -15
- package/dist/Layout.d.ts +4 -2
- package/dist/Layout.js +14 -13
- package/dist/PdfLayout.d.ts +3 -1
- package/dist/PdfLayout.js +43 -40
- package/dist/Utils.d.ts +1 -0
- package/dist/Utils.js +2 -1
- package/package.json +1 -1
package/dist/AnyLayout.d.ts
CHANGED
|
@@ -34,4 +34,4 @@ export declare class FontDict {
|
|
|
34
34
|
load_fonts_from_schema(schema: LayoutSchema, storage: Storage): Promise<void>;
|
|
35
35
|
get_font(name: string): fontkit.Font;
|
|
36
36
|
}
|
|
37
|
-
export declare function render({ resume, layout_schemas, data_schemas, resume_layout, storage, fontDict }: RenderProps): Promise<
|
|
37
|
+
export declare function render({ resume, layout_schemas, data_schemas, resume_layout, storage, fontDict }: RenderProps): Promise<Layout.RenderedLayout[]>;
|
package/dist/AnyLayout.js
CHANGED
|
@@ -54,8 +54,6 @@ class FontDict {
|
|
|
54
54
|
}
|
|
55
55
|
exports.FontDict = FontDict;
|
|
56
56
|
async function render({ resume, layout_schemas, data_schemas, resume_layout, storage, fontDict }) {
|
|
57
|
-
// Each box contains a set of elements(positioned by 0x0 and projected into its bounding box)
|
|
58
|
-
const font_dict = fontDict !== null && fontDict !== void 0 ? fontDict : new FontDict();
|
|
59
57
|
// Compute the total usable width by subtracting the margins from the document width
|
|
60
58
|
const width = resume_layout.width - (resume_layout.margin.left + resume_layout.margin.right);
|
|
61
59
|
// If the resume is double column, then the usable width is halved
|
|
@@ -65,7 +63,6 @@ async function render({ resume, layout_schemas, data_schemas, resume_layout, sto
|
|
|
65
63
|
const layouts = [];
|
|
66
64
|
console.error("Rendering sections...");
|
|
67
65
|
for (const section of resume.sections) {
|
|
68
|
-
console.error("Print section:", section);
|
|
69
66
|
// Render Section Header
|
|
70
67
|
// 1. Find the layout schema for the section
|
|
71
68
|
console.info("Computing section: ", section.section_name);
|
|
@@ -75,7 +72,7 @@ async function render({ resume, layout_schemas, data_schemas, resume_layout, sto
|
|
|
75
72
|
throw new Error(`Could not find layout schema ${section.layout_schema}`);
|
|
76
73
|
}
|
|
77
74
|
let start_time = Date.now();
|
|
78
|
-
await
|
|
75
|
+
await fontDict.load_fonts_from_schema(layout_schema, storage);
|
|
79
76
|
let end_time = Date.now();
|
|
80
77
|
console.info(`Font loading time: ${end_time - start_time}ms for section ${section.section_name}`);
|
|
81
78
|
// 2. Find the data schema for the section
|
|
@@ -85,22 +82,24 @@ async function render({ resume, layout_schemas, data_schemas, resume_layout, sto
|
|
|
85
82
|
}
|
|
86
83
|
start_time = Date.now();
|
|
87
84
|
// 3. Render the header
|
|
88
|
-
const layout = _1.Layout.computeBoxes(_1.Layout.normalize(_1.Layout.instantiate(layout_schema.header_layout_schema, section.data, data_schema.header_schema), column_width,
|
|
89
|
-
|
|
85
|
+
const layout = _1.Layout.computeBoxes(_1.Layout.normalize(_1.Layout.instantiate(layout_schema.header_layout_schema, section.data, data_schema.header_schema), column_width, fontDict), fontDict);
|
|
86
|
+
layout.path = { tag: 'section', section: section.section_name };
|
|
87
|
+
console.info("Header is computed");
|
|
90
88
|
layouts.push(layout);
|
|
91
89
|
end_time = Date.now();
|
|
92
90
|
console.info(`Header rendering time: ${end_time - start_time}ms for section ${section.section_name}`);
|
|
93
91
|
start_time = Date.now();
|
|
94
92
|
// Render Section Items
|
|
95
|
-
for (const [, item] of section.items.entries()) {
|
|
93
|
+
for (const [index, item] of section.items.entries()) {
|
|
96
94
|
// 3. Render the item
|
|
97
|
-
const layout = _1.Layout.computeBoxes(_1.Layout.normalize(_1.Layout.instantiate(layout_schema.item_layout_schema, item.fields, data_schema.item_schema), column_width,
|
|
95
|
+
const layout = _1.Layout.computeBoxes(_1.Layout.normalize(_1.Layout.instantiate(layout_schema.item_layout_schema, item.fields, data_schema.item_schema), column_width, fontDict), fontDict);
|
|
96
|
+
layout.path = { tag: 'item', section: section.section_name, item: index };
|
|
98
97
|
layouts.push(layout);
|
|
99
98
|
}
|
|
100
99
|
end_time = Date.now();
|
|
101
100
|
console.info(`Item rendering time: ${end_time - start_time}ms for section ${section.section_name}`);
|
|
102
101
|
}
|
|
103
102
|
console.log("Position calculations are completed.");
|
|
104
|
-
return
|
|
103
|
+
return layouts;
|
|
105
104
|
}
|
|
106
105
|
exports.render = render;
|
package/dist/Elem.d.ts
CHANGED
|
@@ -7,7 +7,7 @@ import { ItemContent } from "./Resume";
|
|
|
7
7
|
import { Field } from "./DataSchema";
|
|
8
8
|
import { Optional } from "./Utils";
|
|
9
9
|
import { Box } from "./Box";
|
|
10
|
-
type Span = {
|
|
10
|
+
export type Span = {
|
|
11
11
|
is_italic: boolean;
|
|
12
12
|
is_bold: boolean;
|
|
13
13
|
is_code: boolean;
|
|
@@ -21,6 +21,7 @@ type Span = {
|
|
|
21
21
|
export type t = {
|
|
22
22
|
tag: "Elem";
|
|
23
23
|
item: string;
|
|
24
|
+
text?: string;
|
|
24
25
|
spans?: Span[];
|
|
25
26
|
url: string | null;
|
|
26
27
|
is_ref: boolean;
|
|
@@ -38,6 +39,7 @@ export declare function elem(item: string, url: string | null, is_ref: boolean,
|
|
|
38
39
|
export declare function copy(e: Elem): {
|
|
39
40
|
tag: "Elem";
|
|
40
41
|
item: string;
|
|
42
|
+
text?: string;
|
|
41
43
|
spans?: Span[];
|
|
42
44
|
url: string;
|
|
43
45
|
is_ref: boolean;
|
package/dist/Elem.js
CHANGED
|
@@ -140,19 +140,15 @@ function flattenToken(t, sp) {
|
|
|
140
140
|
return (0, ts_pattern_1.match)(t)
|
|
141
141
|
.returnType()
|
|
142
142
|
.with({ type: "paragraph", tokens: ts_pattern_1.P.select("tokens") }, ({ tokens }) => {
|
|
143
|
-
// console.log("[paragraph]", tokens);
|
|
144
143
|
return flatten(tokens, sp);
|
|
145
144
|
})
|
|
146
145
|
.with({ type: "strong", tokens: ts_pattern_1.P.select("tokens") }, ({ tokens }) => {
|
|
147
|
-
// console.log("[strong]", tokens);
|
|
148
146
|
return flatten(tokens, { ...sp, is_bold: true });
|
|
149
147
|
})
|
|
150
148
|
.with({ type: "em", tokens: ts_pattern_1.P.select("tokens") }, ({ tokens }) => {
|
|
151
|
-
// console.log("[em]", tokens);
|
|
152
149
|
return flatten(tokens, { ...sp, is_italic: true });
|
|
153
150
|
})
|
|
154
151
|
.with({ type: "codespan", text: ts_pattern_1.P.select("text") }, ({ text }) => {
|
|
155
|
-
// console.log("[codespan]", text);
|
|
156
152
|
return [{ ...sp, is_code: true, text, link: null }];
|
|
157
153
|
})
|
|
158
154
|
.with({ type: "text", tokens: ts_pattern_1.P.select("tokens") }, ({ tokens }) => {
|
|
@@ -186,22 +182,29 @@ function parseMarkdownItem(item) {
|
|
|
186
182
|
}
|
|
187
183
|
exports.parseMarkdownItem = parseMarkdownItem;
|
|
188
184
|
function fillFonts(e, fonts) {
|
|
189
|
-
const simpleSpans = e.is_markdown ? parseMarkdownItem(e.
|
|
185
|
+
const simpleSpans = e.is_markdown ? parseMarkdownItem(e.text) : [{ ...defaultSpanProps(), text: e.text, font: e.font, link: null }];
|
|
190
186
|
const spans = [];
|
|
191
187
|
for (const span of simpleSpans) {
|
|
192
188
|
const font = e.is_markdown ? (0, Utils_1.with_)(e.font, ({
|
|
193
189
|
// style: span.is_italic ? "Italic" : "Normal",
|
|
194
190
|
weight: span.is_bold ? "Bold" : "Medium",
|
|
195
191
|
})) : e.font;
|
|
196
|
-
if (span.text === " "
|
|
197
|
-
const width = Font.get_width(font,
|
|
192
|
+
if (span.text === " ") {
|
|
193
|
+
const width = Font.get_width(font, "-", fonts);
|
|
198
194
|
spans.push({ ...span, font, width });
|
|
199
195
|
continue;
|
|
200
196
|
}
|
|
201
|
-
span.text
|
|
197
|
+
if (span.text === "\n\n") {
|
|
198
|
+
spans.push({ ...span, font, width: 0 });
|
|
199
|
+
continue;
|
|
200
|
+
}
|
|
201
|
+
const words = span.text.split(/\s+/);
|
|
202
|
+
words.forEach((word, index) => {
|
|
202
203
|
const width = Font.get_width(font, word, fonts);
|
|
203
204
|
spans.push({ ...span, text: word, font, width });
|
|
204
|
-
|
|
205
|
+
if (index < words.length - 1) {
|
|
206
|
+
spans.push({ ...span, text: " ", font, width: Font.get_width(font, " ", fonts) });
|
|
207
|
+
}
|
|
205
208
|
});
|
|
206
209
|
}
|
|
207
210
|
const text_width = spans.reduce((acc, span) => acc + span.width, 0);
|
|
@@ -239,7 +242,7 @@ function break_lines(e, font_dict) {
|
|
|
239
242
|
const lines = [];
|
|
240
243
|
// todo: I'm sure this implementation is pretty buggy. Note to future me, fix
|
|
241
244
|
// this.
|
|
242
|
-
const words = e.
|
|
245
|
+
const words = e.text.split(/\s+/);
|
|
243
246
|
const widths = words.map((word) => Font.get_width(e.font, word, font_dict));
|
|
244
247
|
const space_width = Font.get_width(e.font, " ", font_dict);
|
|
245
248
|
let start = 0;
|
|
@@ -281,21 +284,20 @@ function instantiate(e, section, fields) {
|
|
|
281
284
|
return e;
|
|
282
285
|
}
|
|
283
286
|
const itemType = fields.find(f => f.name === e.item);
|
|
284
|
-
console.log(`Found item type: ${JSON.stringify(itemType)}`);
|
|
285
287
|
if (itemType.type.tag === "MarkdownString") {
|
|
286
|
-
console.log(`Found markdown string: ${e.item}`);
|
|
287
288
|
e.is_markdown = true;
|
|
288
289
|
}
|
|
289
290
|
const text = section.get(e.item);
|
|
291
|
+
console.log(`Instantiating ${e.item} with ${JSON.stringify(text)}`);
|
|
290
292
|
if (text === undefined) {
|
|
291
|
-
return
|
|
293
|
+
return (0, Utils_1.with_)(e, { is_ref: false, text: "" });
|
|
292
294
|
}
|
|
293
295
|
else {
|
|
294
296
|
if (text.tag === "Url") {
|
|
295
|
-
return
|
|
297
|
+
return (0, Utils_1.with_)(e, { is_ref: false, text: text.value.text, url: text.value.url });
|
|
296
298
|
}
|
|
297
299
|
else {
|
|
298
|
-
return
|
|
300
|
+
return (0, Utils_1.with_)(e, { is_ref: false, text: Resume_1.ItemContent.toString(text) });
|
|
299
301
|
}
|
|
300
302
|
}
|
|
301
303
|
}
|
package/dist/Layout.d.ts
CHANGED
|
@@ -4,7 +4,7 @@ import * as Width from "./Width";
|
|
|
4
4
|
import * as Font from "./Font";
|
|
5
5
|
import { ItemContent } from "./Resume";
|
|
6
6
|
import { Box } from "./Box";
|
|
7
|
-
import { FontDict } from "./AnyLayout";
|
|
7
|
+
import { ElementPath, FontDict } from "./AnyLayout";
|
|
8
8
|
import { Point } from "./Point";
|
|
9
9
|
import * as Stack from "./Stack";
|
|
10
10
|
import * as Row from "./Row";
|
|
@@ -24,7 +24,9 @@ export type RenderedRow = Row.t & {
|
|
|
24
24
|
export type RenderedElem = Elem.t & {
|
|
25
25
|
bounding_box: Box;
|
|
26
26
|
};
|
|
27
|
-
export type RenderedLayout = RenderedStack | RenderedRow | RenderedElem
|
|
27
|
+
export type RenderedLayout = (RenderedStack | RenderedRow | RenderedElem) & {
|
|
28
|
+
path?: ElementPath;
|
|
29
|
+
};
|
|
28
30
|
export declare function default_(tag: string): Stack.t | Row.t | Elem.t;
|
|
29
31
|
export declare function empty(): Layout;
|
|
30
32
|
export declare function fromJson(json: unknown): Layout;
|
package/dist/Layout.js
CHANGED
|
@@ -63,6 +63,7 @@ function fromJson(json) {
|
|
|
63
63
|
case 'Text': {
|
|
64
64
|
const inner = default_(key);
|
|
65
65
|
inner.item = json[key].item;
|
|
66
|
+
inner.text = json[key].item;
|
|
66
67
|
inner.margin = json[key].margin;
|
|
67
68
|
inner.alignment = json[key].alignment;
|
|
68
69
|
inner.width = Width.fromJson(json[key].width);
|
|
@@ -402,24 +403,24 @@ function computeTextboxPositions(l, top_left, font_dict) {
|
|
|
402
403
|
let line = 1;
|
|
403
404
|
let cursor = top_left.x;
|
|
404
405
|
elem.spans.forEach(span => {
|
|
405
|
-
if (cursor + span.width > Width.get_fixed_unchecked(elem.width) - elem.margin.right) {
|
|
406
|
+
if (cursor - top_left.x + span.width > Width.get_fixed_unchecked(elem.width) - elem.margin.right || span.text === "\n\n") {
|
|
406
407
|
cursor = top_left.x;
|
|
407
408
|
line += 1;
|
|
408
409
|
}
|
|
409
|
-
span.bbox = new Box_1.Box(new Point_1.Point(cursor, (line - 1) * height), new Point_1.Point(cursor + span.width, line * height));
|
|
410
|
+
span.bbox = new Box_1.Box(new Point_1.Point(cursor - top_left.x, (line - 1) * height), new Point_1.Point(cursor + span.width, line * height));
|
|
411
|
+
span.line = line;
|
|
410
412
|
cursor += span.width;
|
|
411
|
-
console.log(span);
|
|
412
413
|
});
|
|
413
|
-
switch (elem.alignment) {
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
const textbox = new Box_1.Box(top_left, top_left.move_x_by(width).move_y_by(height));
|
|
422
|
-
return { depth: top_left.y + height, renderedLayout: { ...l, bounding_box: textbox } };
|
|
414
|
+
// switch (elem.alignment) {
|
|
415
|
+
// case "Center":
|
|
416
|
+
// top_left = top_left.move_x_by((Width.get_fixed_unchecked(elem.width) - width) / 2.0);
|
|
417
|
+
// break;
|
|
418
|
+
// case "Right":
|
|
419
|
+
// top_left = top_left.move_x_by(Width.get_fixed_unchecked(elem.width) - width);
|
|
420
|
+
// break;
|
|
421
|
+
// }
|
|
422
|
+
const textbox = new Box_1.Box(top_left, top_left.move_x_by(width).move_y_by(height * line));
|
|
423
|
+
return { depth: top_left.y + height * line, renderedLayout: { ...l, bounding_box: textbox } };
|
|
423
424
|
}
|
|
424
425
|
}
|
|
425
426
|
}
|
package/dist/PdfLayout.d.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { DataSchema } from "./DataSchema";
|
|
|
5
5
|
import { LayoutSchema } from "./LayoutSchema";
|
|
6
6
|
import { ResumeLayout } from "./ResumeLayout";
|
|
7
7
|
import { Storage } from "./Storage";
|
|
8
|
+
import * as Elem from "./Elem";
|
|
8
9
|
import { Layout } from ".";
|
|
9
10
|
export type RenderResult = {
|
|
10
11
|
blob: Blob;
|
|
@@ -20,5 +21,6 @@ export type RenderProps = {
|
|
|
20
21
|
fontDict?: FontDict;
|
|
21
22
|
debug: boolean;
|
|
22
23
|
};
|
|
23
|
-
export declare const render: ({ resume_name, resume, data_schemas, layout_schemas, resume_layout, storage, fontDict
|
|
24
|
+
export declare const render: ({ resume_name, resume, data_schemas, layout_schemas, resume_layout, storage, fontDict }: RenderProps) => Promise<RenderResult>;
|
|
25
|
+
export declare const mergeSpans: (spans: Elem.Span[]) => Elem.Span[];
|
|
24
26
|
export declare const renderSectionLayout: (layout: Layout.RenderedLayout, resume_layout: ResumeLayout, current_height: number, doc: PDFKit.PDFDocument) => void;
|
package/dist/PdfLayout.js
CHANGED
|
@@ -3,12 +3,12 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.renderSectionLayout = exports.render = void 0;
|
|
6
|
+
exports.renderSectionLayout = exports.mergeSpans = exports.render = void 0;
|
|
7
7
|
const blob_stream_1 = __importDefault(require("blob-stream"));
|
|
8
8
|
const AnyLayout_1 = require("./AnyLayout");
|
|
9
9
|
const pdfkit_1 = __importDefault(require("pdfkit"));
|
|
10
10
|
const _1 = require(".");
|
|
11
|
-
const render = async ({ resume_name, resume, data_schemas, layout_schemas, resume_layout, storage, fontDict
|
|
11
|
+
const render = async ({ resume_name, resume, data_schemas, layout_schemas, resume_layout, storage, fontDict }) => {
|
|
12
12
|
let start_time = Date.now();
|
|
13
13
|
if (!resume && !resume_name) {
|
|
14
14
|
throw "Rendering requires either resume_name or resume";
|
|
@@ -37,7 +37,7 @@ const render = async ({ resume_name, resume, data_schemas, layout_schemas, resum
|
|
|
37
37
|
// doc.pipe(fs.createWriteStream('output.pdf'));
|
|
38
38
|
const stream = doc.pipe((0, blob_stream_1.default)());
|
|
39
39
|
start_time = Date.now();
|
|
40
|
-
const
|
|
40
|
+
const layouts = await (0, AnyLayout_1.render)({ layout_schemas, resume, data_schemas, resume_layout, storage, fontDict });
|
|
41
41
|
end_time = Date.now();
|
|
42
42
|
console.info(`Rendering time: ${end_time - start_time}ms`);
|
|
43
43
|
console.log("Constructing printpdf font dictionary...");
|
|
@@ -46,7 +46,7 @@ const render = async ({ resume_name, resume, data_schemas, layout_schemas, resum
|
|
|
46
46
|
// "/Users/akeles/Programming/projects/cvdl/cvdl/assets/Exo/static/Exo-Medium.ttf");
|
|
47
47
|
try {
|
|
48
48
|
console.log("Registering fonts...");
|
|
49
|
-
for (const [font_name, font] of
|
|
49
|
+
for (const [font_name, font] of fontDict.fonts.entries()) {
|
|
50
50
|
console.log(`Registering font ${font_name}`);
|
|
51
51
|
// @ts-ignore
|
|
52
52
|
doc.registerFont(font_name, font.stream.buffer);
|
|
@@ -56,36 +56,16 @@ const render = async ({ resume_name, resume, data_schemas, layout_schemas, resum
|
|
|
56
56
|
console.error(e);
|
|
57
57
|
}
|
|
58
58
|
console.log("Rendering the document...");
|
|
59
|
-
// Render the boxes
|
|
60
|
-
// for (const [index, boxes] of pages.entries()) {
|
|
61
|
-
// if (index > 0) {
|
|
62
|
-
// doc.addPage();
|
|
63
|
-
// }
|
|
64
|
-
// boxes.forEach((box) => {
|
|
65
|
-
// const elements = box.elements;
|
|
66
|
-
// // if (debug) {
|
|
67
|
-
// // doc.rect(box.bounding_box.top_left.x, box.bounding_box.top_left.y, box.bounding_box.width(), box.bounding_box.height()).stroke();
|
|
68
|
-
// // }
|
|
69
|
-
// for (const [box_, element] of elements) {
|
|
70
|
-
// console.log(
|
|
71
|
-
// `(${box_.top_left.x}, ${box_.top_left.y})(${box_.bottom_right.x}, ${box_.bottom_right.y}): ${element.item}`
|
|
72
|
-
// );
|
|
73
|
-
// if (element.background_color !== "Transparent") {
|
|
74
|
-
// doc.rect(box_.top_left.x, box_.top_left.y, box_.width(), box_.height()).fillAndStroke(ColorMap[element.background_color], ColorMap[element.background_color]);
|
|
75
|
-
// }
|
|
76
|
-
// // Make this more generic
|
|
77
|
-
// doc.fillColor("black");
|
|
78
|
-
// doc.
|
|
79
|
-
// font(element.font.full_name()).
|
|
80
|
-
// fontSize(element.font.size).
|
|
81
|
-
// text(element.item, box_.top_left.x, box_.top_left.y, { lineBreak: false });
|
|
82
|
-
// if (debug) {
|
|
83
|
-
// // doc.rect(box_.top_left.x, box_.top_left.y, box_.width(), box_.height()).stroke();
|
|
84
|
-
// }
|
|
85
|
-
// }
|
|
86
|
-
// });
|
|
87
|
-
// }
|
|
88
59
|
let current_height = 0;
|
|
60
|
+
// Add rulers to the document at every 10 pixels
|
|
61
|
+
doc.strokeColor("grey");
|
|
62
|
+
for (let i = 0; i < resume_layout.height; i += 10) {
|
|
63
|
+
doc.moveTo(0, i).lineTo(resume_layout.width, i).stroke();
|
|
64
|
+
}
|
|
65
|
+
for (let i = 0; i < resume_layout.width; i += 10) {
|
|
66
|
+
doc.moveTo(i, 0).lineTo(i, resume_layout.height).stroke();
|
|
67
|
+
}
|
|
68
|
+
doc.strokeColor("black");
|
|
89
69
|
for (const layout of layouts) {
|
|
90
70
|
(0, exports.renderSectionLayout)(layout, resume_layout, current_height, doc);
|
|
91
71
|
current_height += layout.bounding_box.height() + layout.margin.top + layout.margin.bottom;
|
|
@@ -103,6 +83,27 @@ const render = async ({ resume_name, resume, data_schemas, layout_schemas, resum
|
|
|
103
83
|
});
|
|
104
84
|
};
|
|
105
85
|
exports.render = render;
|
|
86
|
+
const mergeSpans = (spans) => {
|
|
87
|
+
const merged_spans = [];
|
|
88
|
+
let currentSpan = spans[0];
|
|
89
|
+
for (let i = 1; i < spans.length; i++) {
|
|
90
|
+
if (currentSpan.bbox.top_left.y === spans[i].bbox.top_left.y
|
|
91
|
+
&& currentSpan.font === spans[i].font
|
|
92
|
+
&& currentSpan.is_code === spans[i].is_code
|
|
93
|
+
&& currentSpan.is_bold === spans[i].is_bold
|
|
94
|
+
&& currentSpan.is_italic === spans[i].is_italic) {
|
|
95
|
+
currentSpan.text += spans[i].text;
|
|
96
|
+
currentSpan.bbox.bottom_right = spans[i].bbox.bottom_right;
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
merged_spans.push(currentSpan);
|
|
100
|
+
currentSpan = spans[i];
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
merged_spans.push(currentSpan);
|
|
104
|
+
return merged_spans;
|
|
105
|
+
};
|
|
106
|
+
exports.mergeSpans = mergeSpans;
|
|
106
107
|
const renderSectionLayout = (layout, resume_layout, current_height, doc) => {
|
|
107
108
|
switch (layout.tag) {
|
|
108
109
|
case "Stack": {
|
|
@@ -122,21 +123,23 @@ const renderSectionLayout = (layout, resume_layout, current_height, doc) => {
|
|
|
122
123
|
case "Elem": {
|
|
123
124
|
const elem = layout;
|
|
124
125
|
elem.spans.forEach((span) => {
|
|
125
|
-
console.log(span);
|
|
126
|
-
if (span.text === "") {
|
|
127
|
-
return;
|
|
128
|
-
}
|
|
126
|
+
console.log("Rendering span:", span);
|
|
129
127
|
doc.
|
|
130
128
|
font(_1.Font.full_name(span.font)).
|
|
131
129
|
fontSize(span.font.size).
|
|
132
|
-
text(span.text, layout.bounding_box.top_left.x
|
|
130
|
+
text(span.text, layout.bounding_box.top_left.x
|
|
131
|
+
+ resume_layout.margin.left
|
|
132
|
+
+ span.bbox.top_left.x, layout.bounding_box.top_left.y
|
|
133
|
+
+ resume_layout.margin.top
|
|
134
|
+
+ current_height
|
|
135
|
+
+ span.bbox.top_left.y, { lineBreak: false });
|
|
133
136
|
if (span.is_code) {
|
|
134
137
|
// Add a rounded rectangle around the code
|
|
135
|
-
doc.roundedRect(layout.bounding_box.top_left.x + resume_layout.margin.left + span.bbox.top_left.x - span.font.size /
|
|
138
|
+
doc.roundedRect(layout.bounding_box.top_left.x + resume_layout.margin.left + span.bbox.top_left.x - span.font.size / 5, layout.bounding_box.top_left.y + resume_layout.margin.top + current_height + span.bbox.top_left.y, span.bbox.width() + span.font.size / 5 * 2, span.bbox.height(), 5).stroke();
|
|
136
139
|
// Add a background color to the code
|
|
137
140
|
doc.fillColor("black");
|
|
138
141
|
doc.fillOpacity(0.05);
|
|
139
|
-
doc.rect(layout.bounding_box.top_left.x + resume_layout.margin.left + span.bbox.top_left.x - span.font.size /
|
|
142
|
+
doc.rect(layout.bounding_box.top_left.x + resume_layout.margin.left + span.bbox.top_left.x - span.font.size / 5, layout.bounding_box.top_left.y + resume_layout.margin.top + current_height + span.bbox.top_left.y, span.bbox.width() + span.font.size / 5 * 2, span.bbox.height()).fill();
|
|
140
143
|
doc.fillOpacity(1);
|
|
141
144
|
}
|
|
142
145
|
});
|
package/dist/Utils.d.ts
CHANGED
package/dist/Utils.js
CHANGED