@stonedeck/core 0.7.2 → 0.7.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/emitter.d.ts.map +1 -1
- package/dist/emitter.js +3 -36
- package/dist/emitter.js.map +1 -1
- package/dist/layouts/registry.json +1 -1
- package/dist/models/ir.d.ts +2 -3
- package/dist/models/ir.d.ts.map +1 -1
- package/dist/parser/tokenizer.js +2 -0
- package/dist/parser/tokenizer.js.map +1 -1
- package/dist/resolver/theme-loader.d.ts +3 -1
- package/dist/resolver/theme-loader.d.ts.map +1 -1
- package/dist/resolver/theme-loader.js +45 -2
- package/dist/resolver/theme-loader.js.map +1 -1
- package/package.json +2 -4
- package/src/emitter.ts +3 -35
- package/src/layouts/registry.json +1 -1
- package/src/models/ir.ts +2 -3
- package/src/parser/tokenizer.ts +2 -0
- package/src/resolver/theme-loader.ts +51 -2
- package/src/themes/academico_v2.yaml +55 -0
- package/src/themes/corporativo_v2.yaml +55 -0
- package/src/themes/dark_mode_v2.yaml +54 -0
- package/src/themes/default_v2.yaml +58 -0
- package/src/themes/minimalista_v2.yaml +56 -0
- package/src/themes/moderno_v2.yaml +56 -0
- package/src/themes/tech_blue.yaml +56 -0
- package/test/verify_clipping.html +338 -0
- package/test/verify_clipping.md +14 -0
- package/test/verify_theme.ts +24 -0
- package/test/verify_theme_runner.js +34 -0
- package/test/verify_variants.html +348 -0
- package/test/verify_variants.md +40 -0
- package/dist/resolver/metrics.d.ts +0 -27
- package/dist/resolver/metrics.d.ts.map +0 -1
- package/dist/resolver/metrics.js +0 -43
- package/dist/resolver/metrics.js.map +0 -1
- package/src/resolver/metrics.ts +0 -64
|
@@ -0,0 +1,348 @@
|
|
|
1
|
+
|
|
2
|
+
<!DOCTYPE html>
|
|
3
|
+
<html lang="en">
|
|
4
|
+
<head>
|
|
5
|
+
<meta charset="UTF-8">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
|
+
<title>Variant Verification</title>
|
|
8
|
+
<style>
|
|
9
|
+
:root {
|
|
10
|
+
--canvas-width: 720pt;
|
|
11
|
+
--canvas-height: 405pt;
|
|
12
|
+
--accent-color: #3b82f6;
|
|
13
|
+
--scale-factor: 1;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
html, body { height: 100%; }
|
|
17
|
+
|
|
18
|
+
body {
|
|
19
|
+
margin: 0;
|
|
20
|
+
padding: 0;
|
|
21
|
+
background-color: #1a1a1a;
|
|
22
|
+
min-height: 100vh;
|
|
23
|
+
display: flex;
|
|
24
|
+
flex-direction: column;
|
|
25
|
+
align-items: center;
|
|
26
|
+
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
|
|
27
|
+
transition: background-color 0.3s;
|
|
28
|
+
overflow-x: hidden;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/* Presentation Mode */
|
|
32
|
+
body.presenting {
|
|
33
|
+
background-color: black;
|
|
34
|
+
overflow: hidden;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
#presentation-container {
|
|
38
|
+
flex-grow: 1;
|
|
39
|
+
display: flex;
|
|
40
|
+
flex-direction: column;
|
|
41
|
+
justify-content: center;
|
|
42
|
+
align-items: center;
|
|
43
|
+
width: 100%;
|
|
44
|
+
padding: 20px 0;
|
|
45
|
+
box-sizing: border-box;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
body.presenting #presentation-container {
|
|
49
|
+
padding: 0;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
.slides-inner {
|
|
53
|
+
display: flex;
|
|
54
|
+
flex-direction: column;
|
|
55
|
+
gap: 20px;
|
|
56
|
+
align-items: center;
|
|
57
|
+
width: 100%;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
body.presenting .slides-inner {
|
|
61
|
+
gap: 0;
|
|
62
|
+
width: auto;
|
|
63
|
+
height: 100%;
|
|
64
|
+
justify-content: center;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
.slide-wrapper {
|
|
68
|
+
position: relative;
|
|
69
|
+
width: var(--canvas-width);
|
|
70
|
+
height: var(--canvas-height);
|
|
71
|
+
transform-origin: top left;
|
|
72
|
+
transform: scale(var(--scale-factor));
|
|
73
|
+
box-shadow: 0 5px 15px rgba(0,0,0,0.3);
|
|
74
|
+
background-color: white;
|
|
75
|
+
overflow: hidden;
|
|
76
|
+
flex-shrink: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
body.presenting .slide-wrapper {
|
|
80
|
+
box-shadow: none;
|
|
81
|
+
display: none; /* Hide inactive */
|
|
82
|
+
/* Do NOT override transform or width/height. Keep them logical 720x405 and let scale work. */
|
|
83
|
+
position: absolute;
|
|
84
|
+
top: 50%;
|
|
85
|
+
left: 50%;
|
|
86
|
+
transform-origin: center center;
|
|
87
|
+
transform: translate(-50%, -50%) scale(var(--scale-factor));
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
body.presenting .slide-wrapper.active {
|
|
91
|
+
display: block;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
.slide {
|
|
95
|
+
position: absolute;
|
|
96
|
+
top: 0;
|
|
97
|
+
left: 0;
|
|
98
|
+
width: 100%;
|
|
99
|
+
height: 100%;
|
|
100
|
+
box-sizing: border-box;
|
|
101
|
+
background-color: white;
|
|
102
|
+
overflow: hidden;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/* Slots */
|
|
106
|
+
.slot {
|
|
107
|
+
position: absolute;
|
|
108
|
+
display: flex;
|
|
109
|
+
flex-direction: column;
|
|
110
|
+
overflow: hidden;
|
|
111
|
+
box-sizing: border-box;
|
|
112
|
+
}
|
|
113
|
+
.slot-title { font-weight: bold; }
|
|
114
|
+
|
|
115
|
+
h1 { font-size: 1.6em; margin-bottom: 0.1em; margin-top: 0; line-height: 1.1; }
|
|
116
|
+
h2 { font-size: 1.3em; margin-bottom: 0.15em; margin-top: 0; line-height: 1.2; }
|
|
117
|
+
h3 { font-size: 1.1em; margin-bottom: 0.1em; margin-top: 0; line-height: 1.2; }
|
|
118
|
+
|
|
119
|
+
ul { padding-left: 1.1em; margin: 0; list-style-type: disc; }
|
|
120
|
+
li { margin-bottom: 0.15em; line-height: 1.25; }
|
|
121
|
+
li::marker { color: var(--accent-color); }
|
|
122
|
+
|
|
123
|
+
table { border-collapse: collapse; width: 100%; margin-top: 0.4em; }
|
|
124
|
+
td, th { border: 1pt solid #ccc; padding: 3pt 5pt; text-align: left; }
|
|
125
|
+
th { background: rgba(0,0,0,0.05); font-weight: bold; }
|
|
126
|
+
|
|
127
|
+
img { max-width: 100%; max-height: 100%; object-fit: contain; display: block; margin: auto; flex-shrink: 0; }
|
|
128
|
+
|
|
129
|
+
.markdown-line { margin-bottom: 2pt; line-height: 1.35; }
|
|
130
|
+
p { margin: 0 0 3pt 0; }
|
|
131
|
+
|
|
132
|
+
/* Navigation */
|
|
133
|
+
#nav-bar {
|
|
134
|
+
position: fixed;
|
|
135
|
+
bottom: 20px;
|
|
136
|
+
left: 50%;
|
|
137
|
+
transform: translateX(-50%);
|
|
138
|
+
background: rgba(0, 0, 0, 0.8);
|
|
139
|
+
color: white;
|
|
140
|
+
padding: 10px 20px;
|
|
141
|
+
border-radius: 30px;
|
|
142
|
+
display: flex;
|
|
143
|
+
gap: 15px;
|
|
144
|
+
align-items: center;
|
|
145
|
+
z-index: 1000;
|
|
146
|
+
backdrop-filter: blur(10px);
|
|
147
|
+
opacity: 1;
|
|
148
|
+
transition: opacity 0.3s;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
body.presenting #nav-bar {
|
|
152
|
+
opacity: 0;
|
|
153
|
+
pointer-events: none;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
body.presenting #nav-bar:hover {
|
|
157
|
+
opacity: 1;
|
|
158
|
+
pointer-events: auto;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
button {
|
|
162
|
+
background: transparent;
|
|
163
|
+
border: 1px solid rgba(255,255,255,0.3);
|
|
164
|
+
color: white;
|
|
165
|
+
padding: 5px 12px;
|
|
166
|
+
border-radius: 15px;
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
font-size: 14px;
|
|
169
|
+
}
|
|
170
|
+
button:hover { background: var(--accent-color); border-color: var(--accent-color); }
|
|
171
|
+
|
|
172
|
+
#slide-index { min-width: 60px; text-align: center; }
|
|
173
|
+
|
|
174
|
+
@media print {
|
|
175
|
+
@page {
|
|
176
|
+
size: 720pt 405pt;
|
|
177
|
+
margin: 0;
|
|
178
|
+
}
|
|
179
|
+
body {
|
|
180
|
+
background: white;
|
|
181
|
+
display: block;
|
|
182
|
+
overflow: visible;
|
|
183
|
+
-webkit-print-color-adjust: exact;
|
|
184
|
+
print-color-adjust: exact;
|
|
185
|
+
}
|
|
186
|
+
#nav-bar {
|
|
187
|
+
display: none !important;
|
|
188
|
+
}
|
|
189
|
+
#presentation-container {
|
|
190
|
+
padding: 0 !important;
|
|
191
|
+
display: block !important;
|
|
192
|
+
}
|
|
193
|
+
.slides-inner {
|
|
194
|
+
display: block !important;
|
|
195
|
+
gap: 0 !important;
|
|
196
|
+
}
|
|
197
|
+
.slide-wrapper {
|
|
198
|
+
display: block !important;
|
|
199
|
+
margin: 0 !important;
|
|
200
|
+
padding: 0 !important;
|
|
201
|
+
box-shadow: none !important;
|
|
202
|
+
page-break-after: always !important;
|
|
203
|
+
break-after: page !important;
|
|
204
|
+
transform: none !important;
|
|
205
|
+
width: 720pt !important;
|
|
206
|
+
height: 405pt !important;
|
|
207
|
+
position: relative !important;
|
|
208
|
+
left: 0 !important;
|
|
209
|
+
top: 0 !important;
|
|
210
|
+
overflow: hidden !important;
|
|
211
|
+
}
|
|
212
|
+
.slide {
|
|
213
|
+
position: absolute !important;
|
|
214
|
+
width: 100% !important;
|
|
215
|
+
height: 100% !important;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
</style>
|
|
219
|
+
</head>
|
|
220
|
+
<body id="body">
|
|
221
|
+
<div id="presentation-container">
|
|
222
|
+
<div class="slides-inner">
|
|
223
|
+
|
|
224
|
+
<div class="slide-wrapper active" id="wrapper-0">
|
|
225
|
+
<div class="slide" id="slide-0" style="background: #E8F4F8; color: #007BFF; font-family: Roboto Slab;">
|
|
226
|
+
|
|
227
|
+
</div>
|
|
228
|
+
</div>
|
|
229
|
+
|
|
230
|
+
<div class="slide-wrapper " id="wrapper-1">
|
|
231
|
+
<div class="slide" id="slide-1" style="background: #E8F4F8; color: #007BFF; font-family: Roboto Slab;">
|
|
232
|
+
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
|
|
236
|
+
<div class="slide-wrapper " id="wrapper-2">
|
|
237
|
+
<div class="slide" id="slide-2" style="background: #FFF5E6; color: #000000; font-family: Merriweather;">
|
|
238
|
+
|
|
239
|
+
</div>
|
|
240
|
+
</div>
|
|
241
|
+
|
|
242
|
+
<div class="slide-wrapper " id="wrapper-3">
|
|
243
|
+
<div class="slide" id="slide-3" style="background: linear-gradient(to bottom, #1a2a6c, #b21f1f, #fdbb2d); color: #FFFFFF; font-family: #000000;">
|
|
244
|
+
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
|
|
248
|
+
</div>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
<div id="nav-bar">
|
|
252
|
+
<button onclick="togglePresent()">Present</button>
|
|
253
|
+
<button onclick="prevSlide()">Prev</button>
|
|
254
|
+
<span id="slide-index">1 / 4</span>
|
|
255
|
+
<button onclick="nextSlide()">Next</button>
|
|
256
|
+
<button onclick="toggleFS()">FS</button>
|
|
257
|
+
</div>
|
|
258
|
+
|
|
259
|
+
<script>
|
|
260
|
+
const totalSlides = 4;
|
|
261
|
+
const body = document.getElementById('body');
|
|
262
|
+
const wrappers = document.querySelectorAll('.slide-wrapper');
|
|
263
|
+
const indexSpan = document.getElementById('slide-index');
|
|
264
|
+
let currentIdx = 0;
|
|
265
|
+
|
|
266
|
+
function resize() {
|
|
267
|
+
const baseWidth = 960;
|
|
268
|
+
const baseHeight = 540;
|
|
269
|
+
const isPresenting = body.classList.contains('presenting');
|
|
270
|
+
|
|
271
|
+
const winW = window.innerWidth || document.documentElement.clientWidth || 1024;
|
|
272
|
+
const winH = window.innerHeight || document.documentElement.clientHeight || 768;
|
|
273
|
+
|
|
274
|
+
const targetWidth = isPresenting ? winW : winW * 0.95;
|
|
275
|
+
const targetHeight = isPresenting ? winH : winH * 0.9;
|
|
276
|
+
|
|
277
|
+
let scale = Math.min(targetWidth / baseWidth, targetHeight / baseHeight);
|
|
278
|
+
|
|
279
|
+
if (!isPresenting) {
|
|
280
|
+
scale = Math.min(scale, 1);
|
|
281
|
+
}
|
|
282
|
+
if (scale <= 0.01) scale = 1;
|
|
283
|
+
|
|
284
|
+
document.documentElement.style.setProperty('--scale-factor', scale);
|
|
285
|
+
|
|
286
|
+
wrappers.forEach(w => {
|
|
287
|
+
if (isPresenting) {
|
|
288
|
+
w.style.height = ''; // Reset to CSS default (var(--canvas-height)) for proper aspect ratio scaling
|
|
289
|
+
} else {
|
|
290
|
+
w.style.height = (baseHeight * scale) + 'px';
|
|
291
|
+
}
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
window.addEventListener('resize', resize);
|
|
296
|
+
window.addEventListener('DOMContentLoaded', resize);
|
|
297
|
+
window.addEventListener('load', resize);
|
|
298
|
+
resize();
|
|
299
|
+
|
|
300
|
+
function updateUI() {
|
|
301
|
+
indexSpan.innerText = (currentIdx + 1) + ' / ' + totalSlides;
|
|
302
|
+
wrappers.forEach((w, i) => {
|
|
303
|
+
w.classList.toggle('active', i === currentIdx);
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
if (!body.classList.contains('presenting')) {
|
|
307
|
+
wrappers[currentIdx].scrollIntoView({ behavior: 'auto', block: 'center' });
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function nextSlide() {
|
|
312
|
+
if (currentIdx < totalSlides - 1) {
|
|
313
|
+
currentIdx++;
|
|
314
|
+
updateUI();
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
function prevSlide() {
|
|
319
|
+
if (currentIdx > 0) {
|
|
320
|
+
currentIdx--;
|
|
321
|
+
updateUI();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
function togglePresent() {
|
|
326
|
+
body.classList.toggle('presenting');
|
|
327
|
+
setTimeout(() => { resize(); updateUI(); }, 50);
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
function toggleFS() {
|
|
331
|
+
if (!document.fullscreenElement) {
|
|
332
|
+
body.requestFullscreen().catch(e => console.warn(e));
|
|
333
|
+
} else {
|
|
334
|
+
document.exitFullscreen();
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
window.addEventListener('keydown', (e) => {
|
|
339
|
+
if (['ArrowRight', ' ', 'PageDown', 'Enter'].includes(e.key)) { e.preventDefault(); nextSlide(); }
|
|
340
|
+
if (['ArrowLeft', 'PageUp', 'Backspace'].includes(e.key)) { e.preventDefault(); prevSlide(); }
|
|
341
|
+
if (e.key === 'p') togglePresent();
|
|
342
|
+
if (e.key === 'f') toggleFS();
|
|
343
|
+
if (e.key === 'Escape' && body.classList.contains('presenting')) togglePresent();
|
|
344
|
+
});
|
|
345
|
+
</script>
|
|
346
|
+
|
|
347
|
+
</body>
|
|
348
|
+
</html>
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
---
|
|
2
|
+
StoneDeck: true
|
|
3
|
+
title: "Variant Verification"
|
|
4
|
+
theme: "../src/themes/default_v2.yaml"
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
:::slide
|
|
8
|
+
---
|
|
9
|
+
layout: title
|
|
10
|
+
---
|
|
11
|
+
# Slide 1 (Dynamic)
|
|
12
|
+
Should pick a random variant.
|
|
13
|
+
:::
|
|
14
|
+
|
|
15
|
+
:::slide
|
|
16
|
+
---
|
|
17
|
+
layout: title
|
|
18
|
+
layout_style: kind_1
|
|
19
|
+
---
|
|
20
|
+
# Slide 2 (Kind 1)
|
|
21
|
+
Should use kind_1 variant.
|
|
22
|
+
:::
|
|
23
|
+
|
|
24
|
+
:::slide
|
|
25
|
+
---
|
|
26
|
+
layout: title
|
|
27
|
+
layout_style: kind_2
|
|
28
|
+
---
|
|
29
|
+
# Slide 3 (Kind 2)
|
|
30
|
+
Should use kind_2 variant.
|
|
31
|
+
:::
|
|
32
|
+
|
|
33
|
+
:::slide
|
|
34
|
+
---
|
|
35
|
+
layout: title
|
|
36
|
+
layout_style: kind_3
|
|
37
|
+
---
|
|
38
|
+
# Slide 4 (Kind 3)
|
|
39
|
+
Should use kind_3 variant.
|
|
40
|
+
:::
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import { SlideStyle } from '../models/ir.js';
|
|
2
|
-
export interface LayoutSlot {
|
|
3
|
-
id: string;
|
|
4
|
-
x: number;
|
|
5
|
-
y: number;
|
|
6
|
-
width: number;
|
|
7
|
-
height: number;
|
|
8
|
-
}
|
|
9
|
-
export interface LayoutDefinition {
|
|
10
|
-
id: string;
|
|
11
|
-
slots: LayoutSlot[];
|
|
12
|
-
}
|
|
13
|
-
export declare class MetricsCalculator {
|
|
14
|
-
private doc;
|
|
15
|
-
constructor();
|
|
16
|
-
/**
|
|
17
|
-
* Calculates the height of a string given a font and width.
|
|
18
|
-
*/
|
|
19
|
-
calculateTextHeight(text: string, style: SlideStyle, maxWidth: number): number;
|
|
20
|
-
/**
|
|
21
|
-
* Estimates height for Markdown content.
|
|
22
|
-
* For now, this is a simplified version that handles basic text and lists.
|
|
23
|
-
*/
|
|
24
|
-
estimateMarkdownHeight(markdown: string, style: SlideStyle, maxWidth: number): number;
|
|
25
|
-
}
|
|
26
|
-
export declare const metricsCalculator: MetricsCalculator;
|
|
27
|
-
//# sourceMappingURL=metrics.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.d.ts","sourceRoot":"","sources":["../../src/resolver/metrics.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAE7C,MAAM,WAAW,UAAU;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,gBAAgB;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,UAAU,EAAE,CAAC;CACvB;AAED,qBAAa,iBAAiB;IAC1B,OAAO,CAAC,GAAG,CAAqB;;IAOhC;;OAEG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAc9E;;;OAGG;IACH,sBAAsB,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;CAgBxF;AAED,eAAO,MAAM,iBAAiB,mBAA0B,CAAC"}
|
package/dist/resolver/metrics.js
DELETED
|
@@ -1,43 +0,0 @@
|
|
|
1
|
-
import PDFDocument from 'pdfkit';
|
|
2
|
-
export class MetricsCalculator {
|
|
3
|
-
constructor() {
|
|
4
|
-
// Create a headless PDF document for measurements
|
|
5
|
-
this.doc = new PDFDocument({ size: [720, 405] });
|
|
6
|
-
}
|
|
7
|
-
/**
|
|
8
|
-
* Calculates the height of a string given a font and width.
|
|
9
|
-
*/
|
|
10
|
-
calculateTextHeight(text, style, maxWidth) {
|
|
11
|
-
const fontSize = style.font_size || 18; // Default font size
|
|
12
|
-
const font = style.font_family || 'Helvetica'; // Default font
|
|
13
|
-
try {
|
|
14
|
-
this.doc.font(font).fontSize(fontSize);
|
|
15
|
-
return this.doc.heightOfString(text, { width: maxWidth });
|
|
16
|
-
}
|
|
17
|
-
catch (_e) {
|
|
18
|
-
// Fallback font if the requested one fails
|
|
19
|
-
this.doc.font('Helvetica').fontSize(fontSize);
|
|
20
|
-
return this.doc.heightOfString(text, { width: maxWidth });
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
/**
|
|
24
|
-
* Estimates height for Markdown content.
|
|
25
|
-
* For now, this is a simplified version that handles basic text and lists.
|
|
26
|
-
*/
|
|
27
|
-
estimateMarkdownHeight(markdown, style, maxWidth) {
|
|
28
|
-
// Simple heuristic: split by lines and sum heights
|
|
29
|
-
// In a real implementation, this would handle actual markdown parsing.
|
|
30
|
-
const lines = markdown.split('\n');
|
|
31
|
-
let totalHeight = 0;
|
|
32
|
-
for (const line of lines) {
|
|
33
|
-
if (!line.trim()) {
|
|
34
|
-
totalHeight += (style.font_size || 18) * 0.5; // Half line height for empty lines
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
totalHeight += this.calculateTextHeight(line, style, maxWidth);
|
|
38
|
-
}
|
|
39
|
-
return totalHeight;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
export const metricsCalculator = new MetricsCalculator();
|
|
43
|
-
//# sourceMappingURL=metrics.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"metrics.js","sourceRoot":"","sources":["../../src/resolver/metrics.ts"],"names":[],"mappings":"AAAA,OAAO,WAAW,MAAM,QAAQ,CAAC;AAgBjC,MAAM,OAAO,iBAAiB;IAG1B;QACI,kDAAkD;QAClD,IAAI,CAAC,GAAG,GAAG,IAAI,WAAW,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;IACrD,CAAC;IAED;;OAEG;IACH,mBAAmB,CAAC,IAAY,EAAE,KAAiB,EAAE,QAAgB;QACjE,MAAM,QAAQ,GAAI,KAAK,CAAC,SAAoB,IAAI,EAAE,CAAC,CAAC,oBAAoB;QACxE,MAAM,IAAI,GAAI,KAAK,CAAC,WAAsB,IAAI,WAAW,CAAC,CAAC,eAAe;QAE1E,IAAI,CAAC;YACD,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YACvC,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,CAAC;QAAC,OAAO,EAAE,EAAE,CAAC;YACV,2CAA2C;YAC3C,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;YAC9C,OAAO,IAAI,CAAC,GAAG,CAAC,cAAc,CAAC,IAAI,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAC9D,CAAC;IACL,CAAC;IAED;;;OAGG;IACH,sBAAsB,CAAC,QAAgB,EAAE,KAAiB,EAAE,QAAgB;QACxE,mDAAmD;QACnD,uEAAuE;QACvE,MAAM,KAAK,GAAG,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;QACnC,IAAI,WAAW,GAAG,CAAC,CAAC;QAEpB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;YACvB,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE,EAAE,CAAC;gBACf,WAAW,IAAI,CAAE,KAAK,CAAC,SAAoB,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,CAAC,mCAAmC;gBAC7F,SAAS;YACb,CAAC;YACD,WAAW,IAAI,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,KAAK,EAAE,QAAQ,CAAC,CAAC;QACnE,CAAC;QAED,OAAO,WAAW,CAAC;IACvB,CAAC;CACJ;AAED,MAAM,CAAC,MAAM,iBAAiB,GAAG,IAAI,iBAAiB,EAAE,CAAC"}
|
package/src/resolver/metrics.ts
DELETED
|
@@ -1,64 +0,0 @@
|
|
|
1
|
-
import PDFDocument from 'pdfkit';
|
|
2
|
-
import { SlideStyle } from '../models/ir.js';
|
|
3
|
-
|
|
4
|
-
export interface LayoutSlot {
|
|
5
|
-
id: string;
|
|
6
|
-
x: number;
|
|
7
|
-
y: number;
|
|
8
|
-
width: number;
|
|
9
|
-
height: number;
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export interface LayoutDefinition {
|
|
13
|
-
id: string;
|
|
14
|
-
slots: LayoutSlot[];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export class MetricsCalculator {
|
|
18
|
-
private doc: PDFKit.PDFDocument;
|
|
19
|
-
|
|
20
|
-
constructor() {
|
|
21
|
-
// Create a headless PDF document for measurements
|
|
22
|
-
this.doc = new PDFDocument({ size: [720, 405] });
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
/**
|
|
26
|
-
* Calculates the height of a string given a font and width.
|
|
27
|
-
*/
|
|
28
|
-
calculateTextHeight(text: string, style: SlideStyle, maxWidth: number): number {
|
|
29
|
-
const fontSize = (style.font_size as number) || 18; // Default font size
|
|
30
|
-
const font = (style.font_family as string) || 'Helvetica'; // Default font
|
|
31
|
-
|
|
32
|
-
try {
|
|
33
|
-
this.doc.font(font).fontSize(fontSize);
|
|
34
|
-
return this.doc.heightOfString(text, { width: maxWidth });
|
|
35
|
-
} catch (_e) {
|
|
36
|
-
// Fallback font if the requested one fails
|
|
37
|
-
this.doc.font('Helvetica').fontSize(fontSize);
|
|
38
|
-
return this.doc.heightOfString(text, { width: maxWidth });
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Estimates height for Markdown content.
|
|
44
|
-
* For now, this is a simplified version that handles basic text and lists.
|
|
45
|
-
*/
|
|
46
|
-
estimateMarkdownHeight(markdown: string, style: SlideStyle, maxWidth: number): number {
|
|
47
|
-
// Simple heuristic: split by lines and sum heights
|
|
48
|
-
// In a real implementation, this would handle actual markdown parsing.
|
|
49
|
-
const lines = markdown.split('\n');
|
|
50
|
-
let totalHeight = 0;
|
|
51
|
-
|
|
52
|
-
for (const line of lines) {
|
|
53
|
-
if (!line.trim()) {
|
|
54
|
-
totalHeight += ((style.font_size as number) || 18) * 0.5; // Half line height for empty lines
|
|
55
|
-
continue;
|
|
56
|
-
}
|
|
57
|
-
totalHeight += this.calculateTextHeight(line, style, maxWidth);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
return totalHeight;
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
export const metricsCalculator = new MetricsCalculator();
|