@thanh01.pmt/presentation-kit 0.1.1 → 0.2.0

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.
@@ -1,7 +1,12 @@
1
1
  'use strict';
2
2
 
3
+ var yaml = require('js-yaml');
3
4
  var marpCore = require('@marp-team/marp-core');
4
5
 
6
+ function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
7
+
8
+ var yaml__default = /*#__PURE__*/_interopDefault(yaml);
9
+
5
10
  // src/core/arrow-converter.ts
6
11
  function convertTextArrows(text) {
7
12
  if (!text) return "";
@@ -390,9 +395,13 @@ function generateScopedCss(tokens, containerId = "marp-container") {
390
395
  }
391
396
 
392
397
  /* Slide Inner Section (1280x720 Canvas Coordinate Scale) */
398
+ #${safeId} section:not([data-background-color]):not([style*="background"]),
399
+ #${safeId} foreignObject > section:not([data-background-color]):not([style*="background"]) {
400
+ background-color: ${tokens.background} !important;
401
+ }
402
+
393
403
  #${safeId} section,
394
404
  #${safeId} foreignObject > section {
395
- background-color: ${tokens.background} !important;
396
405
  color: ${tokens.text} !important;
397
406
  font-family: var(--font-sans), Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
398
407
  padding: 50px 60px !important;
@@ -638,6 +647,43 @@ div#${safeId} svg foreignObject section table tr:hover td,
638
647
  padding-top: 6px !important;
639
648
  }
640
649
 
650
+ /* Multi-column Grid & Flex Layout Utilities */
651
+ #${safeId} section .columns,
652
+ #${safeId} section .grid-2 {
653
+ display: grid !important;
654
+ grid-template-columns: 1fr 1fr !important;
655
+ gap: 28px !important;
656
+ width: 100% !important;
657
+ margin: 16px 0 !important;
658
+ align-items: start !important;
659
+ }
660
+
661
+ #${safeId} section .columns > div,
662
+ #${safeId} section .grid-2 > div {
663
+ min-width: 0 !important;
664
+ }
665
+
666
+ #${safeId} section .card {
667
+ background: ${tokens.quoteBg} !important;
668
+ border: 1px solid ${tokens.cardBorder} !important;
669
+ border-radius: 10px !important;
670
+ padding: 18px 22px !important;
671
+ margin: 12px 0 !important;
672
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15) !important;
673
+ }
674
+
675
+ #${safeId} section .card.highlight {
676
+ border-left: 4px solid ${tokens.link} !important;
677
+ }
678
+
679
+ #${safeId} section .card.warning {
680
+ border-left: 4px solid #f59e0b !important;
681
+ }
682
+
683
+ #${safeId} section .card.success {
684
+ border-left: 4px solid #10b981 !important;
685
+ }
686
+
641
687
  /* Marp Split Layout Container */
642
688
  #${safeId} section[data-marpit-advanced-background="background"] {
643
689
  display: flex !important;
@@ -1163,6 +1209,207 @@ ${prefix}[data-click-group].visible {
1163
1209
 
1164
1210
  `;
1165
1211
  }
1212
+ function isLayoutComment(comment) {
1213
+ const trimmed = comment.trim();
1214
+ return trimmed.startsWith("layout:") || trimmed.startsWith("layout :");
1215
+ }
1216
+ function parseLayoutFromComment(comment) {
1217
+ try {
1218
+ const trimmed = comment.trim();
1219
+ if (!isLayoutComment(trimmed)) return null;
1220
+ const parsed = yaml__default.default.load(trimmed);
1221
+ if (!parsed || typeof parsed !== "object") return null;
1222
+ const boxes = parsed.boxes ?? parsed.layout?.boxes;
1223
+ if (Array.isArray(boxes)) {
1224
+ return { boxes };
1225
+ }
1226
+ return null;
1227
+ } catch (err) {
1228
+ console.warn("[presentation-kit] Failed to parse layout comment YAML:", err);
1229
+ return null;
1230
+ }
1231
+ }
1232
+ function filterPresenterNotes(comments) {
1233
+ return comments.map((c) => c.trim()).filter((c) => {
1234
+ if (!c) return false;
1235
+ if (isLayoutComment(c)) return false;
1236
+ if (/^_?[a-zA-Z0-9_-]+\s*:/i.test(c) && !c.toLowerCase().startsWith("note:")) {
1237
+ return false;
1238
+ }
1239
+ return true;
1240
+ }).map((c) => {
1241
+ return c.replace(/^_?note:\s*/i, "").trim();
1242
+ });
1243
+ }
1244
+ function extractLayoutsAndNotes(rawComments) {
1245
+ const layouts = [];
1246
+ const notes = [];
1247
+ for (const slideComments of rawComments) {
1248
+ if (!slideComments || slideComments.length === 0) {
1249
+ layouts.push(null);
1250
+ notes.push([]);
1251
+ continue;
1252
+ }
1253
+ let slideLayout = null;
1254
+ for (const comment of slideComments) {
1255
+ if (isLayoutComment(comment)) {
1256
+ const parsed = parseLayoutFromComment(comment);
1257
+ if (parsed) {
1258
+ slideLayout = parsed;
1259
+ }
1260
+ }
1261
+ }
1262
+ layouts.push(slideLayout);
1263
+ notes.push(filterPresenterNotes(slideComments));
1264
+ }
1265
+ return { layouts, notes };
1266
+ }
1267
+ function serializeLayoutToComment(layout) {
1268
+ if (!layout.boxes || layout.boxes.length === 0) return "";
1269
+ const cleanData = {
1270
+ boxes: layout.boxes.map((box) => {
1271
+ const b = {
1272
+ id: box.id,
1273
+ target: box.target || `h1`,
1274
+ pos: [
1275
+ Math.round(box.pos[0]),
1276
+ Math.round(box.pos[1]),
1277
+ Math.round(box.pos[2]),
1278
+ Math.round(box.pos[3])
1279
+ ]
1280
+ };
1281
+ if (box.fontSize) b.fontSize = box.fontSize;
1282
+ if (box.color) b.color = box.color;
1283
+ if (box.textAlign) b.textAlign = box.textAlign;
1284
+ if (box.style) b.style = box.style;
1285
+ return b;
1286
+ })
1287
+ };
1288
+ const yamlStr = yaml__default.default.dump(cleanData, {
1289
+ indent: 2,
1290
+ lineWidth: -1,
1291
+ noRefs: true
1292
+ }).trim();
1293
+ return `<!-- layout:
1294
+ ${yamlStr.split("\n").join("\n ")}
1295
+ -->`;
1296
+ }
1297
+ function splitMarkdownSlides(markdown) {
1298
+ const lines = markdown.split("\n");
1299
+ let frontmatter = null;
1300
+ const slideBuffers = [];
1301
+ let currentBuffer = [];
1302
+ let inCodeFence = false;
1303
+ let lineIdx = 0;
1304
+ if (lines.length > 0 && lines[0].trim() === "---") {
1305
+ const fmBuffer = [lines[0]];
1306
+ lineIdx = 1;
1307
+ while (lineIdx < lines.length) {
1308
+ const line = lines[lineIdx];
1309
+ fmBuffer.push(line);
1310
+ if (line.trim() === "---") {
1311
+ frontmatter = fmBuffer.join("\n");
1312
+ lineIdx++;
1313
+ break;
1314
+ }
1315
+ lineIdx++;
1316
+ }
1317
+ }
1318
+ for (let i = lineIdx; i < lines.length; i++) {
1319
+ const line = lines[i];
1320
+ if (/^```/.test(line.trim())) {
1321
+ inCodeFence = !inCodeFence;
1322
+ currentBuffer.push(line);
1323
+ continue;
1324
+ }
1325
+ if (!inCodeFence && line.trim() === "---") {
1326
+ slideBuffers.push(currentBuffer);
1327
+ currentBuffer = [];
1328
+ continue;
1329
+ }
1330
+ currentBuffer.push(line);
1331
+ }
1332
+ slideBuffers.push(currentBuffer);
1333
+ const slides = slideBuffers.map((b) => b.join("\n"));
1334
+ return { frontmatter, slides };
1335
+ }
1336
+ function updateSlideLayoutInMarkdown(markdown, slideIndex, layout) {
1337
+ const { frontmatter, slides } = splitMarkdownSlides(markdown);
1338
+ if (slideIndex < 0 || slideIndex >= slides.length) {
1339
+ return markdown;
1340
+ }
1341
+ let slideContent = slides[slideIndex];
1342
+ const layoutCommentRegex = /<!--\s*layout:\s*[\s\S]*?-->/i;
1343
+ const newComment = layout && layout.boxes && layout.boxes.length > 0 ? serializeLayoutToComment(layout) : "";
1344
+ if (layoutCommentRegex.test(slideContent)) {
1345
+ if (newComment) {
1346
+ slideContent = slideContent.replace(layoutCommentRegex, newComment);
1347
+ } else {
1348
+ slideContent = slideContent.replace(layoutCommentRegex, "").trim();
1349
+ }
1350
+ } else if (newComment) {
1351
+ const trimmed = slideContent.trimStart();
1352
+ slideContent = `${newComment}
1353
+
1354
+ ${trimmed}`;
1355
+ }
1356
+ slides[slideIndex] = slideContent;
1357
+ const joinedSlides = slides.join("\n---\n");
1358
+ if (frontmatter) {
1359
+ return `${frontmatter}
1360
+
1361
+ ${joinedSlides}`;
1362
+ }
1363
+ return joinedSlides;
1364
+ }
1365
+
1366
+ // src/core/layout/css-generator.ts
1367
+ function generateLayoutCss(layouts, containerId = "marp-container") {
1368
+ const cssRules = [];
1369
+ layouts.forEach((layout, index) => {
1370
+ if (!layout || !layout.boxes || layout.boxes.length === 0) return;
1371
+ const slideNum = index + 1;
1372
+ const slideSectionSelector = `#${containerId} svg[data-marpit-svg]:nth-of-type(${slideNum}) section, #${containerId} .marpit > svg:nth-of-type(${slideNum}) section`;
1373
+ cssRules.push(`
1374
+ /* Slide ${slideNum} Layout Container */
1375
+ ${slideSectionSelector} {
1376
+ position: relative !important;
1377
+ display: block !important;
1378
+ }`);
1379
+ for (const box of layout.boxes) {
1380
+ if (!box || !Array.isArray(box.pos) || box.pos.length < 4) continue;
1381
+ const [x, y, w, h] = box.pos;
1382
+ const targetSelector = box.target || `[data-box-id="${box.id}"]`;
1383
+ const ruleSelector = `${slideSectionSelector} ${targetSelector}`;
1384
+ const styles = [
1385
+ `position: absolute !important`,
1386
+ `left: ${Math.round(x)}px !important`,
1387
+ `top: ${Math.round(y)}px !important`,
1388
+ `width: ${Math.round(w)}px !important`,
1389
+ `min-height: ${Math.round(h)}px !important`,
1390
+ `box-sizing: border-box !important`,
1391
+ `margin: 0 !important`
1392
+ ];
1393
+ if (box.fontSize) {
1394
+ styles.push(`font-size: ${box.fontSize} !important`);
1395
+ }
1396
+ if (box.color) {
1397
+ styles.push(`color: ${box.color} !important`);
1398
+ }
1399
+ if (box.textAlign) {
1400
+ styles.push(`text-align: ${box.textAlign} !important`);
1401
+ }
1402
+ if (box.style) {
1403
+ styles.push(box.style);
1404
+ }
1405
+ cssRules.push(`
1406
+ ${ruleSelector} {
1407
+ ${styles.join(";\n ")};
1408
+ }`);
1409
+ }
1410
+ });
1411
+ return cssRules.join("\n");
1412
+ }
1166
1413
  function renderMarp(markdown, containerId = "marp-container", enableClicks = false) {
1167
1414
  const cleanSource = extractMarpSource(markdown);
1168
1415
  const { markdown: clickProcessed, totalClicks } = enableClicks ? preprocessClicks(cleanSource) : { markdown: cleanSource, totalClicks: 0 };
@@ -1172,12 +1419,12 @@ function renderMarp(markdown, containerId = "marp-container", enableClicks = fal
1172
1419
  html: true,
1173
1420
  emoji: { unicode: true }
1174
1421
  });
1175
- const { html, css } = marp.render(arrowsConverted);
1422
+ const { html, css, comments } = marp.render(arrowsConverted);
1176
1423
  if (enableClicks && totalClicks > 0) {
1177
1424
  const { html: processedHtml, totalClicks: finalClicks } = postprocessClicks(html);
1178
- return { html: processedHtml, css, maxClicks: finalClicks };
1425
+ return { html: processedHtml, css, comments: comments ?? [], maxClicks: finalClicks };
1179
1426
  }
1180
- return { html, css, maxClicks: 0 };
1427
+ return { html, css, comments: comments ?? [], maxClicks: 0 };
1181
1428
  }
1182
1429
  function countSlides(html) {
1183
1430
  const matches = html.match(/<svg[^>]*data-marpit-svg/g);
@@ -1187,44 +1434,51 @@ function renderSlide(markdown, options) {
1187
1434
  const containerId = options?.containerId ?? "marp-container";
1188
1435
  const theme = resolveTheme(options?.theme ?? "dark");
1189
1436
  const enableClicks = options?.enableClicks ?? false;
1190
- const { html, css, maxClicks } = renderMarp(markdown, containerId, enableClicks);
1437
+ const { html, css, comments, maxClicks } = renderMarp(markdown, containerId, enableClicks);
1191
1438
  const themeCss = generateScopedCss2(theme, containerId);
1192
1439
  const slideCount = countSlides(html);
1193
1440
  const mermaidBlocks = options?.enableMermaid !== false ? detectMermaidBlocks(html) : [];
1194
1441
  const clickCss = enableClicks ? generateClickCss({ containerId }) : "";
1442
+ const { layouts, notes } = extractLayoutsAndNotes(comments);
1443
+ const layoutCss = generateLayoutCss(layouts, containerId);
1195
1444
  return {
1196
1445
  html,
1197
1446
  css,
1198
1447
  themeCss,
1448
+ layoutCss,
1199
1449
  slideCount,
1200
1450
  mermaidBlocks,
1201
1451
  clickCss,
1202
- maxClicks
1452
+ maxClicks,
1453
+ notes,
1454
+ layouts
1203
1455
  };
1204
1456
  }
1205
1457
  async function renderSlideAsync(markdown, options) {
1206
1458
  const containerId = options?.containerId ?? "marp-container";
1207
1459
  const theme = resolveTheme(options?.theme ?? "dark");
1208
1460
  const enableClicks = options?.enableClicks ?? false;
1209
- const { html, css, maxClicks } = renderMarp(markdown, containerId, enableClicks);
1461
+ const { html, css, comments, maxClicks } = renderMarp(markdown, containerId, enableClicks);
1210
1462
  const themeCss = generateScopedCss2(theme, containerId);
1211
1463
  const slideCount = countSlides(html);
1212
1464
  const mermaidBlocks = options?.enableMermaid !== false ? detectMermaidBlocks(html) : [];
1213
1465
  const clickCss = enableClicks ? generateClickCss({ containerId }) : "";
1214
- let processedHtml = html;
1215
- if (options?.enableShiki !== false) {
1216
- const shikiThemeName = theme.name === "light" ? "light" : "dark";
1217
- processedHtml = await highlightCodeBlocks(html, shikiThemeName);
1218
- }
1466
+ const { layouts, notes } = extractLayoutsAndNotes(comments);
1467
+ const layoutCss = generateLayoutCss(layouts, containerId);
1468
+ const enableShiki = options?.enableShiki ?? true;
1469
+ const processedHtml = enableShiki ? await highlightCodeBlocks(html, theme.name) : html;
1219
1470
  return {
1220
1471
  html,
1221
1472
  css,
1222
1473
  themeCss,
1474
+ layoutCss,
1475
+ processedHtml,
1223
1476
  slideCount,
1224
1477
  mermaidBlocks,
1225
1478
  clickCss,
1226
1479
  maxClicks,
1227
- processedHtml
1480
+ notes,
1481
+ layouts
1228
1482
  };
1229
1483
  }
1230
1484
 
@@ -1233,16 +1487,21 @@ exports.countSlides = countSlides;
1233
1487
  exports.darkThemeTokens = darkThemeTokens;
1234
1488
  exports.defineTheme = defineTheme;
1235
1489
  exports.detectMermaidBlocks = detectMermaidBlocks;
1490
+ exports.extractLayoutsAndNotes = extractLayoutsAndNotes;
1236
1491
  exports.extractMarpSource = extractMarpSource;
1237
1492
  exports.extractMaxClicks = extractMaxClicks;
1493
+ exports.filterPresenterNotes = filterPresenterNotes;
1238
1494
  exports.generateClickCss = generateClickCss;
1495
+ exports.generateLayoutCss = generateLayoutCss;
1239
1496
  exports.generateScopedCss = generateScopedCss;
1240
1497
  exports.generateScopedCss2 = generateScopedCss2;
1241
1498
  exports.getHighlighter = getHighlighter;
1242
1499
  exports.getThemeTokens = getThemeTokens;
1243
1500
  exports.highlightCodeBlocks = highlightCodeBlocks;
1501
+ exports.isLayoutComment = isLayoutComment;
1244
1502
  exports.lightThemeTokens = lightThemeTokens;
1245
1503
  exports.navyThemeTokens = navyThemeTokens;
1504
+ exports.parseLayoutFromComment = parseLayoutFromComment;
1246
1505
  exports.postprocessClicks = postprocessClicks;
1247
1506
  exports.preprocessClicks = preprocessClicks;
1248
1507
  exports.renderMarp = renderMarp;
@@ -1251,5 +1510,8 @@ exports.renderSlide = renderSlide;
1251
1510
  exports.renderSlideAsync = renderSlideAsync;
1252
1511
  exports.resolveTheme = resolveTheme;
1253
1512
  exports.sanitizeMermaidCode = sanitizeMermaidCode;
1254
- //# sourceMappingURL=chunk-N4Q6GUAQ.cjs.map
1255
- //# sourceMappingURL=chunk-N4Q6GUAQ.cjs.map
1513
+ exports.serializeLayoutToComment = serializeLayoutToComment;
1514
+ exports.splitMarkdownSlides = splitMarkdownSlides;
1515
+ exports.updateSlideLayoutInMarkdown = updateSlideLayoutInMarkdown;
1516
+ //# sourceMappingURL=chunk-O4Y3VEOA.cjs.map
1517
+ //# sourceMappingURL=chunk-O4Y3VEOA.cjs.map