@farberg/reveal-template 1.1.13 → 1.1.15

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.
@@ -22,6 +22,21 @@
22
22
 
23
23
  <body>
24
24
  <div class="reveal">
25
- <div class="slides"></div>
25
+ <div class="slides">
26
+ <section data-markdown>
27
+ <textarea data-template>
28
+ ## Gateway API
29
+
30
+ ```mermaid
31
+ graph LR
32
+ GWC[GatewayClass] -->|implemented by| Ctrl[Controller]
33
+ GW[Gateway] -->|references| GWC
34
+ Route[HTTPRoute] -->|attaches to| GW
35
+ Route -->|routes to| SvcA[Service A]
36
+ Route -->|routes to| SvcB[Service B]
37
+ ```
38
+ </textarea>
39
+ </section>
40
+ </div>
26
41
  </div>
27
42
  </body>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@farberg/reveal-template",
3
- "version": "1.1.13",
3
+ "version": "1.1.15",
4
4
  "homepage": "https://github.com/pfisterer/reveal-template",
5
5
  "description": "Reveal.js template for Dennis' lectures",
6
6
  "main": "index.js",
@@ -14,6 +14,7 @@ export default {
14
14
  mermaid.initialize({
15
15
  'startOnLoad': false,
16
16
  'theme': 'base',
17
+ 'fontSize': 13,
17
18
  'themeVariables': {
18
19
  'textColor': '#000',
19
20
  'primaryColor': '#e2001a',
@@ -31,38 +32,75 @@ export default {
31
32
  },
32
33
  'flowchart': {
33
34
  'useMaxWidth': true,
34
- 'htmlLabels': true
35
+ 'padding': 6
35
36
  }
36
37
  });
37
38
 
38
39
  function fixSvgScaling(el) {
39
- el.querySelectorAll('pre.mermaid svg').forEach(svg => {
40
- // mermaid v10+ sets style="max-width: Xpx" which constrains width —
41
- // remove it and let the container CSS drive the size instead
40
+ el.querySelectorAll('.mermaid svg').forEach(svg => {
41
+ // Ensure viewBox so width:100% scales content proportionally
42
+ if (!svg.getAttribute('viewBox')) {
43
+ const w = parseFloat(svg.getAttribute('width'));
44
+ const h = parseFloat(svg.getAttribute('height'));
45
+ if (w && h) svg.setAttribute('viewBox', `0 0 ${w} ${h}`);
46
+ }
47
+ svg.setAttribute('width', '100%');
48
+ svg.removeAttribute('height');
42
49
  svg.style.maxWidth = '100%';
43
50
  svg.style.width = '100%';
44
51
  svg.style.height = 'auto';
52
+
53
+ // mermaid v11 measures text before the document font is loaded,
54
+ // producing foreignObjects that are too narrow for the actual rendered text.
55
+ // Measure the real content width and expand each foreignObject to fit,
56
+ // then shift the label group by half the difference to keep it centered.
57
+ svg.querySelectorAll('foreignObject').forEach(fo => {
58
+ fo.setAttribute('overflow', 'visible');
59
+ const inner = fo.firstElementChild;
60
+ if (!inner) return;
61
+ const actualWidth = inner.scrollWidth;
62
+ const foWidth = parseFloat(fo.getAttribute('width')) || 0;
63
+ if (actualWidth > foWidth) {
64
+ const extra = actualWidth - foWidth;
65
+ fo.setAttribute('width', actualWidth);
66
+ const labelG = fo.parentElement;
67
+ if (labelG && labelG.hasAttribute('transform')) {
68
+ const m = labelG.getAttribute('transform')
69
+ .match(/translate\((-?[\d.]+),\s*(-?[\d.]+)\)/);
70
+ if (m) {
71
+ labelG.setAttribute('transform',
72
+ `translate(${parseFloat(m[1]) - extra / 2}, ${m[2]})`);
73
+ }
74
+ }
75
+ }
76
+ });
45
77
  });
46
78
  }
47
79
 
48
- function handle(el) {
49
- // Convert ```mermaid code blocks into pre.mermaid elements.
50
- // highlight.js processes them first (adding spans, encoding arrows as &gt;),
51
- // so we read textContent to strip spans and decode HTML entities back to raw source.
80
+ async function handle(el) {
81
+ // Convert ```mermaid code blocks to .mermaid elements.
82
+ // highlight.js runs first: adds <span> tags and encodes --> as &gt;.
83
+ // textContent strips spans and decodes HTML entities back to raw mermaid source.
52
84
  el.querySelectorAll('code.mermaid').forEach(code => {
53
- if (code.closest('pre.mermaid')) return; // already converted
54
- const pre = code.parentElement;
55
- pre.className = 'mermaid';
56
- pre.textContent = code.textContent;
85
+ const oldPre = code.parentElement;
86
+ if (oldPre.classList.contains('mermaid')) return;
87
+ const newPre = document.createElement('pre');
88
+ newPre.className = 'mermaid';
89
+ newPre.textContent = code.textContent;
90
+ oldPre.replaceWith(newPre);
57
91
  });
58
92
 
59
- const mermaids = el.querySelectorAll('pre.mermaid');
60
- const result = mermaid.run({ nodes: mermaids });
61
- if (result && typeof result.then === 'function') {
62
- result.then(() => fixSvgScaling(el));
63
- } else {
64
- setTimeout(() => fixSvgScaling(el), 100);
65
- }
93
+ // Yield so DOM mutations are flushed before mermaid reads them
94
+ await new Promise(resolve => requestAnimationFrame(resolve));
95
+
96
+ // Skip elements already rendered (contain an SVG)
97
+ const unrendered = [...el.querySelectorAll('.mermaid')].filter(
98
+ node => !node.querySelector('svg') && node.textContent.trim().length > 0
99
+ );
100
+ if (unrendered.length === 0) return;
101
+
102
+ await mermaid.run({ nodes: unrendered, suppressErrors: true });
103
+ fixSvgScaling(el);
66
104
  }
67
105
 
68
106
  deck.on('ready', event => {
@@ -77,22 +115,29 @@ export default {
77
115
  text-align: center;
78
116
  overflow: visible;
79
117
  }
80
- pre.mermaid svg {
118
+ .mermaid svg {
81
119
  max-width: 100%;
82
120
  height: auto;
83
121
  }
122
+ .mermaid svg foreignObject {
123
+ overflow: visible;
124
+ }
125
+ .mermaid svg foreignObject * {
126
+ font-size: 13px !important;
127
+ font-family: arial, sans-serif !important;
128
+ line-height: 1.5 !important;
129
+ }
84
130
  `;
85
131
  document.head.appendChild(style);
86
132
 
87
133
  const print = window.location.search.match(/print-pdf/gi);
88
-
89
134
  if (print) {
90
- console.log("print-pdf detected, rendering mermaid diagrams")
135
+ console.log("print-pdf detected, rendering mermaid diagrams");
91
136
  handle(document);
92
137
  } else {
93
138
  deck.addEventListener('slidechanged', e => handle(e.currentSlide));
94
139
  handle(event.currentSlide);
95
140
  }
96
- })
141
+ });
97
142
  }
98
143
  }
@@ -92,24 +92,39 @@ export default () => {
92
92
 
93
93
  //console.log(`language = ${language}, url = ${url}, beginMarker = ${beginMarker}, endMarker = ${endMarker}, showLink = ${showLink} `)
94
94
 
95
- if (url) {
96
- const response = await fetch(url, { "cache": "no-store", "credentials": "include" })
95
+ if (!url) {
96
+ showError(el, "No URL provided in elements innerText")
97
+ continue
98
+ }
99
+
100
+ try {
101
+ const sameOrigin = new URL(url, window.location.href).origin === window.location.origin
102
+ const response = await fetch(url, { "cache": "no-store", "credentials": sameOrigin ? "include" : "omit" })
97
103
  if (response.status === 401) {
98
104
  console.log("Authentication required (show-code-snippets), reloading page");
99
105
  window.location.reload();
100
106
  return;
101
107
  }
108
+ if (!response.ok) {
109
+ showError(el, `HTTP ${response.status} loading ${url}`)
110
+ continue
111
+ }
102
112
  const text = await response.text()
103
113
  let code = extractBeginEndSnippet(text, beginMarker, endMarker)
104
114
 
115
+ if (!code) {
116
+ showError(el, `No content extracted from ${url} (begin=${beginMarker}, end=${endMarker})`)
117
+ continue
118
+ }
119
+
105
120
  if (outdentCode)
106
121
  code = outdent(code)
107
122
 
108
123
  const newEl = showCode(el, language, code, showLink ? url : null, outdent)
109
124
  highlightPlugin.hljs.highlightElement(newEl)
110
-
111
- } else {
112
- showError(el, "No URL provided in elements innerText")
125
+ } catch (err) {
126
+ console.error(`show-code-snippets: failed to load ${url}:`, err)
127
+ showError(el, `Failed to load ${url}: ${err.message}`)
113
128
  }
114
129
  }
115
130