@farberg/reveal-template 1.1.30 → 1.1.32
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.
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
|
|
8
8
|
<ul class="menu"><ul>
|
|
9
9
|
|
|
10
|
+
---
|
|
11
|
+
## Code Example
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Create a Kafka cluster using the operator
|
|
15
|
+
kubectl apply -f https://raw.githubusercontent.com/strimzi/strimzi-kafka-operator/refs/heads/main/examples/kafka/kafka-ephemeral.yaml
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
docker buildx build --platform linux/amd64,linux/arm64,linux/arm/v7 -t yourusername/yourcontainername:1.2.3 -t yourusername/yourcontainername:latest --push .
|
|
20
|
+
```
|
|
21
|
+
|
|
10
22
|
---
|
|
11
23
|
## Mermaid Example
|
|
12
24
|
|
package/package.json
CHANGED
|
@@ -10,9 +10,9 @@ Parameters:
|
|
|
10
10
|
|
|
11
11
|
Example
|
|
12
12
|
|
|
13
|
-
<a data-code='bash'
|
|
14
|
-
data-begin="# Begin indicator in the file"
|
|
15
|
-
data-end="# End indicator in the file"
|
|
13
|
+
<a data-code='bash'
|
|
14
|
+
data-begin="# Begin indicator in the file"
|
|
15
|
+
data-end="# End indicator in the file"
|
|
16
16
|
data-link
|
|
17
17
|
href="link/to/the/file.sh">Source code</a>
|
|
18
18
|
*/
|
|
@@ -26,6 +26,9 @@ function showError(el, err) {
|
|
|
26
26
|
function showCode(el, language, code, link, outdent) {
|
|
27
27
|
var newEl = document.createElement('pre');
|
|
28
28
|
newEl.setAttribute('class', `language-${language}`);
|
|
29
|
+
// Keep the exact, un-escaped source so the copy button can reproduce it
|
|
30
|
+
// verbatim regardless of how we later restructure the DOM for display.
|
|
31
|
+
newEl.__rawCode = code
|
|
29
32
|
//Replace special chars
|
|
30
33
|
code = code.replace(/&/g, "&").replace(/>/g, ">").replace(/</g, "<").replace(/"/g, """)
|
|
31
34
|
|
|
@@ -82,6 +85,49 @@ function injectStyles() {
|
|
|
82
85
|
pre.with-copy-btn {
|
|
83
86
|
position: relative;
|
|
84
87
|
}
|
|
88
|
+
/* Soft-wrap long lines like VS Code's word wrap. white-space:pre-wrap is
|
|
89
|
+
a purely visual wrap: it does NOT insert real newlines into the text.
|
|
90
|
+
overflow-wrap:break-word prefers breaking at whitespace and only splits a
|
|
91
|
+
word when that single token is itself too long to fit (long URLs / base64
|
|
92
|
+
/ paths). Unlike "anywhere", it does not snap mid-word when a whitespace
|
|
93
|
+
break is available. Copy fidelity is handled separately (see
|
|
94
|
+
addCopyButton / wrapCodeLines), so wrapping never leaks into copied text. */
|
|
95
|
+
.reveal pre.with-copy-btn,
|
|
96
|
+
.reveal pre.with-copy-btn code {
|
|
97
|
+
white-space: pre-wrap;
|
|
98
|
+
overflow-wrap: break-word;
|
|
99
|
+
word-break: normal;
|
|
100
|
+
}
|
|
101
|
+
/* Each logical source line becomes its own block so wrapped continuation
|
|
102
|
+
rows can be hang-indented (text-indent pulls the first row back to the
|
|
103
|
+
margin; padding-left indents everything else). padding-right reserves
|
|
104
|
+
room for the end-of-row wrap marker (see decorateWrappedLines): text
|
|
105
|
+
wraps before that zone, so the absolutely-positioned marker lands inside
|
|
106
|
+
the box instead of overflowing and triggering a horizontal scrollbar. */
|
|
107
|
+
.reveal pre.with-copy-btn code .cl {
|
|
108
|
+
display: block;
|
|
109
|
+
position: relative;
|
|
110
|
+
padding-left: 2.5ch;
|
|
111
|
+
padding-right: 1.5ch;
|
|
112
|
+
text-indent: -2.5ch;
|
|
113
|
+
}
|
|
114
|
+
/* Preserve the height of blank lines. Generated content is excluded from
|
|
115
|
+
selection/copy, so the zero-width space never reaches the clipboard. */
|
|
116
|
+
.reveal pre.with-copy-btn code .cl:empty::before {
|
|
117
|
+
content: "\\200b";
|
|
118
|
+
}
|
|
119
|
+
/* Continuation marker placed at the end of each row that soft-wraps (see
|
|
120
|
+
decorateWrappedLines). The horizontal/vertical offset is set inline per
|
|
121
|
+
row; user-select:none keeps it out of native select+copy. */
|
|
122
|
+
.reveal pre.with-copy-btn code .wrap-marker {
|
|
123
|
+
position: absolute;
|
|
124
|
+
text-indent: 0;
|
|
125
|
+
font-style: normal;
|
|
126
|
+
opacity: 0.4;
|
|
127
|
+
pointer-events: none;
|
|
128
|
+
user-select: none;
|
|
129
|
+
-webkit-user-select: none;
|
|
130
|
+
}
|
|
85
131
|
.copy-code-btn {
|
|
86
132
|
position: absolute;
|
|
87
133
|
top: 0.4em;
|
|
@@ -114,6 +160,89 @@ function injectStyles() {
|
|
|
114
160
|
document.head.appendChild(style);
|
|
115
161
|
}
|
|
116
162
|
|
|
163
|
+
// Wrap each logical line of a (already highlighted) <code> element in its own
|
|
164
|
+
// <span class="cl"> block. hljs emits a single run of HTML with "\n"
|
|
165
|
+
// separators and token <span>s that may straddle newlines, so we tokenize the
|
|
166
|
+
// markup and re-open any spans still active when a line ends.
|
|
167
|
+
function wrapCodeLines(codeEl) {
|
|
168
|
+
const html = codeEl.innerHTML
|
|
169
|
+
const tokenRe = /(<\/?[^>]+>)|([^<]+)/g
|
|
170
|
+
let m
|
|
171
|
+
let open = [] // stack of currently-open tag strings (hljs uses <span>)
|
|
172
|
+
let buf = ''
|
|
173
|
+
let lines = []
|
|
174
|
+
const closers = () => open.map(() => '</span>').join('')
|
|
175
|
+
const reopen = () => open.join('')
|
|
176
|
+
|
|
177
|
+
while ((m = tokenRe.exec(html)) !== null) {
|
|
178
|
+
if (m[1]) {
|
|
179
|
+
const tag = m[1]
|
|
180
|
+
if (tag[1] === '/') { open.pop(); buf += tag }
|
|
181
|
+
else if (tag.endsWith('/>')) { buf += tag } // self-closing (rare)
|
|
182
|
+
else { open.push(tag); buf += tag }
|
|
183
|
+
} else {
|
|
184
|
+
const parts = m[2].split('\n')
|
|
185
|
+
for (let i = 0; i < parts.length; i++) {
|
|
186
|
+
if (i > 0) {
|
|
187
|
+
buf += closers() // close spans before the line break
|
|
188
|
+
lines.push(buf)
|
|
189
|
+
buf = reopen() // re-open them on the next line
|
|
190
|
+
}
|
|
191
|
+
buf += parts[i]
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
buf += closers()
|
|
196
|
+
lines.push(buf)
|
|
197
|
+
|
|
198
|
+
codeEl.innerHTML = lines.map(l => `<span class="cl">${l}</span>`).join('')
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// Place a "↴" marker at the end of every row that soft-wraps (i.e. every visual
|
|
202
|
+
// row except the last). CSS has no selector for soft-wrap rows, so we measure
|
|
203
|
+
// them with a Range. The deck is rendered at a fixed layout width and merely
|
|
204
|
+
// CSS-scaled, so wrap positions are stable; we divide measured offsets by the
|
|
205
|
+
// current scale to get layout pixels.
|
|
206
|
+
function decorateWrappedLines(root, scale) {
|
|
207
|
+
if (!root) return
|
|
208
|
+
const s = scale || 1
|
|
209
|
+
for (const line of root.querySelectorAll('pre.with-copy-btn code .cl')) {
|
|
210
|
+
// Idempotent: clear any decoration from a previous pass before measuring.
|
|
211
|
+
for (const old of line.querySelectorAll('.wrap-marker')) old.remove()
|
|
212
|
+
|
|
213
|
+
const range = document.createRange()
|
|
214
|
+
range.selectNodeContents(line)
|
|
215
|
+
const rects = range.getClientRects()
|
|
216
|
+
if (!rects.length) continue
|
|
217
|
+
|
|
218
|
+
const base = line.getBoundingClientRect()
|
|
219
|
+
// Group the rects (one per inline fragment) into visual rows keyed by
|
|
220
|
+
// their top offset, tracking the rightmost text edge of each row — that
|
|
221
|
+
// edge is where the row visually ends, i.e. the wrap point.
|
|
222
|
+
const rows = []
|
|
223
|
+
for (const r of rects) {
|
|
224
|
+
if (r.width === 0 && r.height === 0) continue
|
|
225
|
+
const top = Math.round(r.top - base.top)
|
|
226
|
+
const right = r.right - base.left
|
|
227
|
+
const row = rows.find(x => Math.abs(x.top - top) <= 2)
|
|
228
|
+
if (row) row.right = Math.max(row.right, right)
|
|
229
|
+
else rows.push({ top, right })
|
|
230
|
+
}
|
|
231
|
+
if (rows.length <= 1) continue // line did not wrap
|
|
232
|
+
|
|
233
|
+
// Mark the end of every row except the last — those are the wrap points.
|
|
234
|
+
for (let i = 0; i < rows.length - 1; i++) {
|
|
235
|
+
const marker = document.createElement('span')
|
|
236
|
+
marker.className = 'wrap-marker'
|
|
237
|
+
marker.textContent = '↴'
|
|
238
|
+
marker.setAttribute('aria-hidden', 'true')
|
|
239
|
+
marker.style.top = (rows[i].top / s) + 'px'
|
|
240
|
+
marker.style.left = (rows[i].right / s) + 'px'
|
|
241
|
+
line.appendChild(marker)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
117
246
|
function writeToClipboard(text) {
|
|
118
247
|
if (navigator.clipboard && navigator.clipboard.writeText)
|
|
119
248
|
return navigator.clipboard.writeText(text);
|
|
@@ -140,7 +269,13 @@ function addCopyButton(preEl) {
|
|
|
140
269
|
btn.textContent = 'copy';
|
|
141
270
|
btn.addEventListener('click', () => {
|
|
142
271
|
const code = preEl.querySelector('code');
|
|
143
|
-
|
|
272
|
+
// Prefer the stashed raw source: it is immune to the per-line <span>
|
|
273
|
+
// wrapping and wrap markers used for display. textContent is the
|
|
274
|
+
// fallback (block-per-line collapses to no newlines under textContent,
|
|
275
|
+
// so raw is what we really want here).
|
|
276
|
+
const text = preEl.__rawCode != null
|
|
277
|
+
? preEl.__rawCode
|
|
278
|
+
: (code ? code.textContent : preEl.textContent);
|
|
144
279
|
writeToClipboard(text).then(() => {
|
|
145
280
|
btn.textContent = '✓ copied';
|
|
146
281
|
btn.classList.add('copied');
|
|
@@ -162,6 +297,17 @@ export default () => {
|
|
|
162
297
|
init: (deck) => {
|
|
163
298
|
injectStyles();
|
|
164
299
|
|
|
300
|
+
// Re-measure wrap points after fonts settle and on every layout change.
|
|
301
|
+
// Only the visible slide can be measured (hidden slides have no layout),
|
|
302
|
+
// so slidechanged re-runs decoration as each slide is shown.
|
|
303
|
+
const decorate = (root) => {
|
|
304
|
+
const run = () => decorateWrappedLines(root, deck.getScale());
|
|
305
|
+
if (document.fonts && document.fonts.ready)
|
|
306
|
+
document.fonts.ready.then(() => requestAnimationFrame(run));
|
|
307
|
+
else
|
|
308
|
+
requestAnimationFrame(run);
|
|
309
|
+
};
|
|
310
|
+
|
|
165
311
|
deck.on('ready', async () => {
|
|
166
312
|
const highlightPlugin = deck.getPlugin("highlight")
|
|
167
313
|
|
|
@@ -178,8 +324,12 @@ export default () => {
|
|
|
178
324
|
// code text and overwrites the rendered diagram.
|
|
179
325
|
for (let el of deck.getRevealElement().querySelectorAll("pre code[class]")) {
|
|
180
326
|
if (!el.classList.contains("mermaid")) {
|
|
327
|
+
const pre = el.closest('pre')
|
|
328
|
+
// Capture raw source before highlighting/line-wrapping touches the DOM.
|
|
329
|
+
if (pre) pre.__rawCode = el.textContent
|
|
181
330
|
highlightPlugin.hljs.highlightElement(el);
|
|
182
|
-
|
|
331
|
+
wrapCodeLines(el);
|
|
332
|
+
addCopyButton(pre);
|
|
183
333
|
}
|
|
184
334
|
}
|
|
185
335
|
|
|
@@ -225,7 +375,9 @@ export default () => {
|
|
|
225
375
|
|
|
226
376
|
const newEl = showCode(el, language, code, showLink ? url : null, outdent)
|
|
227
377
|
if (language !== 'mermaid') {
|
|
228
|
-
|
|
378
|
+
const codeEl = newEl.querySelector('code') ?? newEl
|
|
379
|
+
highlightPlugin.hljs.highlightElement(codeEl)
|
|
380
|
+
wrapCodeLines(codeEl)
|
|
229
381
|
addCopyButton(newEl)
|
|
230
382
|
}
|
|
231
383
|
} catch (err) {
|
|
@@ -234,10 +386,15 @@ export default () => {
|
|
|
234
386
|
}
|
|
235
387
|
}
|
|
236
388
|
|
|
237
|
-
|
|
389
|
+
// First pass for the slide that is visible at startup.
|
|
390
|
+
decorate(deck.getRevealElement())
|
|
238
391
|
})
|
|
239
392
|
|
|
240
|
-
|
|
393
|
+
// Slides other than the current one have no layout while hidden, so we
|
|
394
|
+
// (re)place wrap markers each time a slide becomes visible, and after
|
|
395
|
+
// any resize that changes the scale.
|
|
396
|
+
deck.on('slidechanged', (e) => decorate(e.currentSlide))
|
|
397
|
+
deck.on('resize', () => decorate(deck.getRevealElement()))
|
|
241
398
|
}
|
|
242
399
|
}
|
|
243
|
-
}
|
|
400
|
+
}
|