lazyslides 0.1.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.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +207 -0
  3. package/_includes/slides/_nested-list.njk +26 -0
  4. package/_includes/slides/agenda.njk +17 -0
  5. package/_includes/slides/center.njk +16 -0
  6. package/_includes/slides/code.njk +15 -0
  7. package/_includes/slides/columns.njk +35 -0
  8. package/_includes/slides/comparison.njk +29 -0
  9. package/_includes/slides/content.njk +22 -0
  10. package/_includes/slides/footer.njk +58 -0
  11. package/_includes/slides/funnel.njk +30 -0
  12. package/_includes/slides/hero.njk +27 -0
  13. package/_includes/slides/image-overlay.njk +21 -0
  14. package/_includes/slides/metrics.njk +27 -0
  15. package/_includes/slides/quote.njk +17 -0
  16. package/_includes/slides/section.njk +6 -0
  17. package/_includes/slides/split-wide.njk +30 -0
  18. package/_includes/slides/split.njk +30 -0
  19. package/_includes/slides/table.njk +31 -0
  20. package/_includes/slides/timeline.njk +30 -0
  21. package/_includes/slides/title.njk +17 -0
  22. package/_layouts/default.njk +20 -0
  23. package/_layouts/presentation.njk +240 -0
  24. package/assets/css/themes/default.css +62 -0
  25. package/assets/css/vendor/glightbox.min.css +1 -0
  26. package/assets/js/vendor/glightbox.min.js +1 -0
  27. package/assets/reveal.js/LICENSE +19 -0
  28. package/assets/reveal.js/dist/reset.css +30 -0
  29. package/assets/reveal.js/dist/reveal.css +8 -0
  30. package/assets/reveal.js/dist/reveal.esm.js +9 -0
  31. package/assets/reveal.js/dist/reveal.esm.js.map +1 -0
  32. package/assets/reveal.js/dist/reveal.js +9 -0
  33. package/assets/reveal.js/dist/reveal.js.map +1 -0
  34. package/assets/reveal.js/dist/theme/beige.css +366 -0
  35. package/assets/reveal.js/dist/theme/black-contrast.css +362 -0
  36. package/assets/reveal.js/dist/theme/black.css +359 -0
  37. package/assets/reveal.js/dist/theme/blood.css +392 -0
  38. package/assets/reveal.js/dist/theme/dracula.css +385 -0
  39. package/assets/reveal.js/dist/theme/fonts/league-gothic/LICENSE +2 -0
  40. package/assets/reveal.js/dist/theme/fonts/league-gothic/league-gothic.css +10 -0
  41. package/assets/reveal.js/dist/theme/fonts/league-gothic/league-gothic.eot +0 -0
  42. package/assets/reveal.js/dist/theme/fonts/league-gothic/league-gothic.ttf +0 -0
  43. package/assets/reveal.js/dist/theme/fonts/league-gothic/league-gothic.woff +0 -0
  44. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/LICENSE +45 -0
  45. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-italic.eot +0 -0
  46. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-italic.ttf +0 -0
  47. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-italic.woff +0 -0
  48. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-regular.eot +0 -0
  49. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-regular.ttf +0 -0
  50. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-regular.woff +0 -0
  51. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-semibold.eot +0 -0
  52. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-semibold.ttf +0 -0
  53. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-semibold.woff +0 -0
  54. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-semibolditalic.eot +0 -0
  55. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-semibolditalic.ttf +0 -0
  56. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro-semibolditalic.woff +0 -0
  57. package/assets/reveal.js/dist/theme/fonts/source-sans-pro/source-sans-pro.css +39 -0
  58. package/assets/reveal.js/dist/theme/league.css +368 -0
  59. package/assets/reveal.js/dist/theme/moon.css +362 -0
  60. package/assets/reveal.js/dist/theme/night.css +360 -0
  61. package/assets/reveal.js/dist/theme/serif.css +363 -0
  62. package/assets/reveal.js/dist/theme/simple.css +362 -0
  63. package/assets/reveal.js/dist/theme/sky.css +370 -0
  64. package/assets/reveal.js/dist/theme/solarized.css +363 -0
  65. package/assets/reveal.js/dist/theme/white-contrast.css +362 -0
  66. package/assets/reveal.js/dist/theme/white.css +359 -0
  67. package/assets/reveal.js/dist/theme/white_contrast_compact_verbatim_headers.css +360 -0
  68. package/assets/reveal.js/plugin/highlight/highlight.esm.js +5 -0
  69. package/assets/reveal.js/plugin/highlight/highlight.js +5 -0
  70. package/assets/reveal.js/plugin/highlight/monokai.css +71 -0
  71. package/assets/reveal.js/plugin/highlight/plugin.js +439 -0
  72. package/assets/reveal.js/plugin/highlight/zenburn.css +80 -0
  73. package/assets/reveal.js/plugin/markdown/markdown.esm.js +7 -0
  74. package/assets/reveal.js/plugin/markdown/markdown.js +7 -0
  75. package/assets/reveal.js/plugin/markdown/plugin.js +491 -0
  76. package/assets/reveal.js/plugin/notes/notes.esm.js +1 -0
  77. package/assets/reveal.js/plugin/notes/notes.js +1 -0
  78. package/assets/reveal.js/plugin/notes/plugin.js +267 -0
  79. package/assets/reveal.js/plugin/notes/speaker-view.html +898 -0
  80. package/cli.js +80 -0
  81. package/data/site.json +3 -0
  82. package/index.js +153 -0
  83. package/lib/export-pdf.js +137 -0
  84. package/lib/init.js +154 -0
  85. package/lib/renumber.js +181 -0
  86. package/lib/validate.js +196 -0
  87. package/package.json +76 -0
  88. package/scaffold/CLAUDE.md +283 -0
  89. package/scaffold/README.md +29 -0
  90. package/scaffold/_template/index.md +78 -0
  91. package/scaffold/_template/outline.md +32 -0
  92. package/scaffold/claude-commands/add-slide.md +61 -0
  93. package/scaffold/claude-commands/create-outline.md +75 -0
  94. package/scaffold/claude-commands/new-presentation.md +218 -0
  95. package/scaffold/claude-commands/refine-slides.md +62 -0
  96. package/scaffold/claude-commands/research-topic.md +66 -0
  97. package/scaffold/claude-commands/validate.md +47 -0
  98. package/scaffold/claude-settings.json +7 -0
  99. package/scaffold/eleventy.config.js +11 -0
  100. package/scaffold/gitignore +5 -0
  101. package/scaffold/my-first-deck/index.md +26 -0
  102. package/scaffold/nvmrc +1 -0
  103. package/scaffold/package.json.tmpl +25 -0
  104. package/scaffold/presentations.11tydata.js +11 -0
  105. package/scaffold/styles.css +3 -0
  106. package/src/styles.css +2077 -0
@@ -0,0 +1,71 @@
1
+ /*
2
+ Monokai style - ported by Luigi Maselli - http://grigio.org
3
+ */
4
+
5
+ .hljs {
6
+ display: block;
7
+ overflow-x: auto;
8
+ padding: 0.5em;
9
+ background: #272822;
10
+ color: #ddd;
11
+ }
12
+
13
+ .hljs-tag,
14
+ .hljs-keyword,
15
+ .hljs-selector-tag,
16
+ .hljs-literal,
17
+ .hljs-strong,
18
+ .hljs-name {
19
+ color: #f92672;
20
+ }
21
+
22
+ .hljs-code {
23
+ color: #66d9ef;
24
+ }
25
+
26
+ .hljs-class .hljs-title {
27
+ color: white;
28
+ }
29
+
30
+ .hljs-attribute,
31
+ .hljs-symbol,
32
+ .hljs-regexp,
33
+ .hljs-link {
34
+ color: #bf79db;
35
+ }
36
+
37
+ .hljs-string,
38
+ .hljs-bullet,
39
+ .hljs-subst,
40
+ .hljs-title,
41
+ .hljs-section,
42
+ .hljs-emphasis,
43
+ .hljs-type,
44
+ .hljs-built_in,
45
+ .hljs-builtin-name,
46
+ .hljs-selector-attr,
47
+ .hljs-selector-pseudo,
48
+ .hljs-addition,
49
+ .hljs-variable,
50
+ .hljs-template-tag,
51
+ .hljs-template-variable {
52
+ color: #a6e22e;
53
+ }
54
+
55
+ .hljs-comment,
56
+ .hljs-quote,
57
+ .hljs-deletion,
58
+ .hljs-meta {
59
+ color: #75715e;
60
+ }
61
+
62
+ .hljs-keyword,
63
+ .hljs-selector-tag,
64
+ .hljs-literal,
65
+ .hljs-doctag,
66
+ .hljs-title,
67
+ .hljs-section,
68
+ .hljs-type,
69
+ .hljs-selector-id {
70
+ font-weight: bold;
71
+ }
@@ -0,0 +1,439 @@
1
+ import hljs from 'highlight.js';
2
+
3
+ /* highlightjs-line-numbers.js 2.8.0 | (C) 2018 Yauheni Pakala | MIT License | github.com/wcoder/highlightjs-line-numbers.js */
4
+ !function(r,o){"use strict";var e,i="hljs-ln",l="hljs-ln-line",h="hljs-ln-code",s="hljs-ln-numbers",c="hljs-ln-n",m="data-line-number",a=/\r\n|\r|\n/g;function u(e){for(var n=e.toString(),t=e.anchorNode;"TD"!==t.nodeName;)t=t.parentNode;for(var r=e.focusNode;"TD"!==r.nodeName;)r=r.parentNode;var o=parseInt(t.dataset.lineNumber),a=parseInt(r.dataset.lineNumber);if(o==a)return n;var i,l=t.textContent,s=r.textContent;for(a<o&&(i=o,o=a,a=i,i=l,l=s,s=i);0!==n.indexOf(l);)l=l.slice(1);for(;-1===n.lastIndexOf(s);)s=s.slice(0,-1);for(var c=l,u=function(e){for(var n=e;"TABLE"!==n.nodeName;)n=n.parentNode;return n}(t),d=o+1;d<a;++d){var f=p('.{0}[{1}="{2}"]',[h,m,d]);c+="\n"+u.querySelector(f).textContent}return c+="\n"+s}function n(e){try{var n=o.querySelectorAll("code.hljs,code.nohighlight");for(var t in n)n.hasOwnProperty(t)&&(n[t].classList.contains("nohljsln")||d(n[t],e))}catch(e){r.console.error("LineNumbers error: ",e)}}function d(e,n){if("object"==typeof e)e.innerHTML=f(e,n)}function f(e,n){var t,r,o=(t=e,{singleLine:function(e){return!!e.singleLine&&e.singleLine}(r=(r=n)||{}),startFrom:function(e,n){var t=1;isFinite(n.startFrom)&&(t=n.startFrom);var r=function(e,n){return e.hasAttribute(n)?e.getAttribute(n):null}(e,"data-ln-start-from");return null!==r&&(t=function(e,n){if(!e)return n;var t=Number(e);return isFinite(t)?t:n}(r,1)),t}(t,r)});return function e(n){var t=n.childNodes;for(var r in t){var o;t.hasOwnProperty(r)&&(o=t[r],0<(o.textContent.trim().match(a)||[]).length&&(0<o.childNodes.length?e(o):v(o.parentNode)))}}(e),function(e,n){var t=g(e);""===t[t.length-1].trim()&&t.pop();if(1<t.length||n.singleLine){for(var r="",o=0,a=t.length;o<a;o++)r+=p('<tr><td class="{0} {1}" {3}="{5}"><div class="{2}" {3}="{5}"></div></td><td class="{0} {4}" {3}="{5}">{6}</td></tr>',[l,s,c,m,h,o+n.startFrom,0<t[o].length?t[o]:" "]);return p('<table class="{0}">{1}</table>',[i,r])}return e}(e.innerHTML,o)}function v(e){var n=e.className;if(/hljs-/.test(n)){for(var t=g(e.innerHTML),r=0,o="";r<t.length;r++){o+=p('<span class="{0}">{1}</span>\n',[n,0<t[r].length?t[r]:" "])}e.innerHTML=o.trim()}}function g(e){return 0===e.length?[]:e.split(a)}function p(e,t){return e.replace(/\{(\d+)\}/g,function(e,n){return void 0!==t[n]?t[n]:e})}hljs?(hljs.initLineNumbersOnLoad=function(e){"interactive"===o.readyState||"complete"===o.readyState?n(e):r.addEventListener("DOMContentLoaded",function(){n(e)})},hljs.lineNumbersBlock=d,hljs.lineNumbersValue=function(e,n){if("string"!=typeof e)return;var t=document.createElement("code");return t.innerHTML=e,f(t,n)},(e=o.createElement("style")).type="text/css",e.innerHTML=p(".{0}{border-collapse:collapse}.{0} td{padding:0}.{1}:before{content:attr({2})}",[i,c,m]),o.getElementsByTagName("head")[0].appendChild(e)):r.console.error("highlight.js not detected!"),document.addEventListener("copy",function(e){var n,t=window.getSelection();!function(e){for(var n=e;n;){if(n.className&&-1!==n.className.indexOf("hljs-ln-code"))return 1;n=n.parentNode}}(t.anchorNode)||(n=-1!==window.navigator.userAgent.indexOf("Edge")?u(t):t.toString(),e.clipboardData.setData("text/plain",n),e.preventDefault())})}(window,document);
5
+
6
+
7
+ /*!
8
+ * reveal.js plugin that adds syntax highlight support.
9
+ */
10
+
11
+ const Plugin = {
12
+
13
+ id: 'highlight',
14
+
15
+ HIGHLIGHT_STEP_DELIMITER: '|',
16
+ HIGHLIGHT_LINE_DELIMITER: ',',
17
+ HIGHLIGHT_LINE_RANGE_DELIMITER: '-',
18
+
19
+ hljs,
20
+
21
+ /**
22
+ * Highlights code blocks within the given deck.
23
+ *
24
+ * Note that this can be called multiple times if
25
+ * there are multiple presentations on one page.
26
+ *
27
+ * @param {Reveal} reveal the reveal.js instance
28
+ */
29
+ init: function( reveal ) {
30
+
31
+ // Read the plugin config options and provide fallbacks
32
+ let config = reveal.getConfig().highlight || {};
33
+
34
+ config.highlightOnLoad = typeof config.highlightOnLoad === 'boolean' ? config.highlightOnLoad : true;
35
+ config.escapeHTML = typeof config.escapeHTML === 'boolean' ? config.escapeHTML : true;
36
+
37
+ Array.from( reveal.getRevealElement().querySelectorAll( 'pre code' ) ).forEach( block => {
38
+
39
+ block.parentNode.classList.add('code-wrapper');
40
+
41
+ // Code can optionally be wrapped in script template to avoid
42
+ // HTML being parsed by the browser (i.e. when you need to
43
+ // include <, > or & in your code).
44
+ let substitute = block.querySelector( 'script[type="text/template"]' );
45
+ if( substitute ) {
46
+ // textContent handles the HTML entity escapes for us
47
+ block.textContent = substitute.innerHTML;
48
+ }
49
+
50
+ // Trim whitespace if the "data-trim" attribute is present
51
+ if( block.hasAttribute( 'data-trim' ) && typeof block.innerHTML.trim === 'function' ) {
52
+ block.innerHTML = betterTrim( block );
53
+ }
54
+
55
+ // Escape HTML tags unless the "data-noescape" attrbute is present
56
+ if( config.escapeHTML && !block.hasAttribute( 'data-noescape' )) {
57
+ block.innerHTML = block.innerHTML.replace( /</g,"&lt;").replace(/>/g, '&gt;' );
58
+ }
59
+
60
+ // Re-highlight when focus is lost (for contenteditable code)
61
+ block.addEventListener( 'focusout', function( event ) {
62
+ hljs.highlightElement( event.currentTarget );
63
+ }, false );
64
+
65
+ } );
66
+
67
+ // Triggers a callback function before we trigger highlighting
68
+ if( typeof config.beforeHighlight === 'function' ) {
69
+ config.beforeHighlight( hljs );
70
+ }
71
+
72
+ // Run initial highlighting for all code
73
+ if( config.highlightOnLoad ) {
74
+ Array.from( reveal.getRevealElement().querySelectorAll( 'pre code' ) ).forEach( block => {
75
+ Plugin.highlightBlock( block );
76
+ } );
77
+ }
78
+
79
+ // If we're printing to PDF, scroll the code highlights of
80
+ // all blocks in the deck into view at once
81
+ reveal.on( 'pdf-ready', function() {
82
+ [].slice.call( reveal.getRevealElement().querySelectorAll( 'pre code[data-line-numbers].current-fragment' ) ).forEach( function( block ) {
83
+ Plugin.scrollHighlightedLineIntoView( block, {}, true );
84
+ } );
85
+ } );
86
+
87
+ },
88
+
89
+ /**
90
+ * Highlights a code block. If the <code> node has the
91
+ * 'data-line-numbers' attribute we also generate slide
92
+ * numbers.
93
+ *
94
+ * If the block contains multiple line highlight steps,
95
+ * we clone the block and create a fragment for each step.
96
+ */
97
+ highlightBlock: function( block ) {
98
+
99
+ hljs.highlightElement( block );
100
+
101
+ // Don't generate line numbers for empty code blocks
102
+ if( block.innerHTML.trim().length === 0 ) return;
103
+
104
+ if( block.hasAttribute( 'data-line-numbers' ) ) {
105
+ hljs.lineNumbersBlock( block, { singleLine: true } );
106
+
107
+ var scrollState = { currentBlock: block };
108
+
109
+ // If there is more than one highlight step, generate
110
+ // fragments
111
+ var highlightSteps = Plugin.deserializeHighlightSteps( block.getAttribute( 'data-line-numbers' ) );
112
+ if( highlightSteps.length > 1 ) {
113
+
114
+ // If the original code block has a fragment-index,
115
+ // each clone should follow in an incremental sequence
116
+ var fragmentIndex = parseInt( block.getAttribute( 'data-fragment-index' ), 10 );
117
+
118
+ if( typeof fragmentIndex !== 'number' || isNaN( fragmentIndex ) ) {
119
+ fragmentIndex = null;
120
+ }
121
+
122
+ // Generate fragments for all steps except the original block
123
+ highlightSteps.slice(1).forEach( function( highlight ) {
124
+
125
+ var fragmentBlock = block.cloneNode( true );
126
+ fragmentBlock.setAttribute( 'data-line-numbers', Plugin.serializeHighlightSteps( [ highlight ] ) );
127
+ fragmentBlock.classList.add( 'fragment' );
128
+ block.parentNode.appendChild( fragmentBlock );
129
+ Plugin.highlightLines( fragmentBlock );
130
+
131
+ if( typeof fragmentIndex === 'number' ) {
132
+ fragmentBlock.setAttribute( 'data-fragment-index', fragmentIndex );
133
+ fragmentIndex += 1;
134
+ }
135
+ else {
136
+ fragmentBlock.removeAttribute( 'data-fragment-index' );
137
+ }
138
+
139
+ // Scroll highlights into view as we step through them
140
+ fragmentBlock.addEventListener( 'visible', Plugin.scrollHighlightedLineIntoView.bind( Plugin, fragmentBlock, scrollState ) );
141
+ fragmentBlock.addEventListener( 'hidden', Plugin.scrollHighlightedLineIntoView.bind( Plugin, fragmentBlock.previousElementSibling, scrollState ) );
142
+
143
+ } );
144
+
145
+ block.removeAttribute( 'data-fragment-index' );
146
+ block.setAttribute( 'data-line-numbers', Plugin.serializeHighlightSteps( [ highlightSteps[0] ] ) );
147
+
148
+ }
149
+
150
+ // Scroll the first highlight into view when the slide
151
+ // becomes visible. Note supported in IE11 since it lacks
152
+ // support for Element.closest.
153
+ var slide = typeof block.closest === 'function' ? block.closest( 'section:not(.stack)' ) : null;
154
+ if( slide ) {
155
+ var scrollFirstHighlightIntoView = function() {
156
+ Plugin.scrollHighlightedLineIntoView( block, scrollState, true );
157
+ slide.removeEventListener( 'visible', scrollFirstHighlightIntoView );
158
+ }
159
+ slide.addEventListener( 'visible', scrollFirstHighlightIntoView );
160
+ }
161
+
162
+ Plugin.highlightLines( block );
163
+
164
+ }
165
+
166
+ },
167
+
168
+ /**
169
+ * Animates scrolling to the first highlighted line
170
+ * in the given code block.
171
+ */
172
+ scrollHighlightedLineIntoView: function( block, scrollState, skipAnimation ) {
173
+
174
+ cancelAnimationFrame( scrollState.animationFrameID );
175
+
176
+ // Match the scroll position of the currently visible
177
+ // code block
178
+ if( scrollState.currentBlock ) {
179
+ block.scrollTop = scrollState.currentBlock.scrollTop;
180
+ }
181
+
182
+ // Remember the current code block so that we can match
183
+ // its scroll position when showing/hiding fragments
184
+ scrollState.currentBlock = block;
185
+
186
+ var highlightBounds = this.getHighlightedLineBounds( block )
187
+ var viewportHeight = block.offsetHeight;
188
+
189
+ // Subtract padding from the viewport height
190
+ var blockStyles = getComputedStyle( block );
191
+ viewportHeight -= parseInt( blockStyles.paddingTop ) + parseInt( blockStyles.paddingBottom );
192
+
193
+ // Scroll position which centers all highlights
194
+ var startTop = block.scrollTop;
195
+ var targetTop = highlightBounds.top + ( Math.min( highlightBounds.bottom - highlightBounds.top, viewportHeight ) - viewportHeight ) / 2;
196
+
197
+ // Account for offsets in position applied to the
198
+ // <table> that holds our lines of code
199
+ var lineTable = block.querySelector( '.hljs-ln' );
200
+ if( lineTable ) targetTop += lineTable.offsetTop - parseInt( blockStyles.paddingTop );
201
+
202
+ // Make sure the scroll target is within bounds
203
+ targetTop = Math.max( Math.min( targetTop, block.scrollHeight - viewportHeight ), 0 );
204
+
205
+ if( skipAnimation === true || startTop === targetTop ) {
206
+ block.scrollTop = targetTop;
207
+ }
208
+ else {
209
+
210
+ // Don't attempt to scroll if there is no overflow
211
+ if( block.scrollHeight <= viewportHeight ) return;
212
+
213
+ var time = 0;
214
+ var animate = function() {
215
+ time = Math.min( time + 0.02, 1 );
216
+
217
+ // Update our eased scroll position
218
+ block.scrollTop = startTop + ( targetTop - startTop ) * Plugin.easeInOutQuart( time );
219
+
220
+ // Keep animating unless we've reached the end
221
+ if( time < 1 ) {
222
+ scrollState.animationFrameID = requestAnimationFrame( animate );
223
+ }
224
+ };
225
+
226
+ animate();
227
+
228
+ }
229
+
230
+ },
231
+
232
+ /**
233
+ * The easing function used when scrolling.
234
+ */
235
+ easeInOutQuart: function( t ) {
236
+
237
+ // easeInOutQuart
238
+ return t<.5 ? 8*t*t*t*t : 1-8*(--t)*t*t*t;
239
+
240
+ },
241
+
242
+ getHighlightedLineBounds: function( block ) {
243
+
244
+ var highlightedLines = block.querySelectorAll( '.highlight-line' );
245
+ if( highlightedLines.length === 0 ) {
246
+ return { top: 0, bottom: 0 };
247
+ }
248
+ else {
249
+ var firstHighlight = highlightedLines[0];
250
+ var lastHighlight = highlightedLines[ highlightedLines.length -1 ];
251
+
252
+ return {
253
+ top: firstHighlight.offsetTop,
254
+ bottom: lastHighlight.offsetTop + lastHighlight.offsetHeight
255
+ }
256
+ }
257
+
258
+ },
259
+
260
+ /**
261
+ * Visually emphasize specific lines within a code block.
262
+ * This only works on blocks with line numbering turned on.
263
+ *
264
+ * @param {HTMLElement} block a <code> block
265
+ * @param {String} [linesToHighlight] The lines that should be
266
+ * highlighted in this format:
267
+ * "1" = highlights line 1
268
+ * "2,5" = highlights lines 2 & 5
269
+ * "2,5-7" = highlights lines 2, 5, 6 & 7
270
+ */
271
+ highlightLines: function( block, linesToHighlight ) {
272
+
273
+ var highlightSteps = Plugin.deserializeHighlightSteps( linesToHighlight || block.getAttribute( 'data-line-numbers' ) );
274
+
275
+ if( highlightSteps.length ) {
276
+
277
+ highlightSteps[0].forEach( function( highlight ) {
278
+
279
+ var elementsToHighlight = [];
280
+
281
+ // Highlight a range
282
+ if( typeof highlight.end === 'number' ) {
283
+ elementsToHighlight = [].slice.call( block.querySelectorAll( 'table tr:nth-child(n+'+highlight.start+'):nth-child(-n+'+highlight.end+')' ) );
284
+ }
285
+ // Highlight a single line
286
+ else if( typeof highlight.start === 'number' ) {
287
+ elementsToHighlight = [].slice.call( block.querySelectorAll( 'table tr:nth-child('+highlight.start+')' ) );
288
+ }
289
+
290
+ if( elementsToHighlight.length ) {
291
+ elementsToHighlight.forEach( function( lineElement ) {
292
+ lineElement.classList.add( 'highlight-line' );
293
+ } );
294
+
295
+ block.classList.add( 'has-highlights' );
296
+ }
297
+
298
+ } );
299
+
300
+ }
301
+
302
+ },
303
+
304
+ /**
305
+ * Parses and formats a user-defined string of line
306
+ * numbers to highlight.
307
+ *
308
+ * @example
309
+ * Plugin.deserializeHighlightSteps( '1,2|3,5-10' )
310
+ * // [
311
+ * // [ { start: 1 }, { start: 2 } ],
312
+ * // [ { start: 3 }, { start: 5, end: 10 } ]
313
+ * // ]
314
+ */
315
+ deserializeHighlightSteps: function( highlightSteps ) {
316
+
317
+ // Remove whitespace
318
+ highlightSteps = highlightSteps.replace( /\s/g, '' );
319
+
320
+ // Divide up our line number groups
321
+ highlightSteps = highlightSteps.split( Plugin.HIGHLIGHT_STEP_DELIMITER );
322
+
323
+ return highlightSteps.map( function( highlights ) {
324
+
325
+ return highlights.split( Plugin.HIGHLIGHT_LINE_DELIMITER ).map( function( highlight ) {
326
+
327
+ // Parse valid line numbers
328
+ if( /^[\d-]+$/.test( highlight ) ) {
329
+
330
+ highlight = highlight.split( Plugin.HIGHLIGHT_LINE_RANGE_DELIMITER );
331
+
332
+ var lineStart = parseInt( highlight[0], 10 ),
333
+ lineEnd = parseInt( highlight[1], 10 );
334
+
335
+ if( isNaN( lineEnd ) ) {
336
+ return {
337
+ start: lineStart
338
+ };
339
+ }
340
+ else {
341
+ return {
342
+ start: lineStart,
343
+ end: lineEnd
344
+ };
345
+ }
346
+
347
+ }
348
+ // If no line numbers are provided, no code will be highlighted
349
+ else {
350
+
351
+ return {};
352
+
353
+ }
354
+
355
+ } );
356
+
357
+ } );
358
+
359
+ },
360
+
361
+ /**
362
+ * Serializes parsed line number data into a string so
363
+ * that we can store it in the DOM.
364
+ */
365
+ serializeHighlightSteps: function( highlightSteps ) {
366
+
367
+ return highlightSteps.map( function( highlights ) {
368
+
369
+ return highlights.map( function( highlight ) {
370
+
371
+ // Line range
372
+ if( typeof highlight.end === 'number' ) {
373
+ return highlight.start + Plugin.HIGHLIGHT_LINE_RANGE_DELIMITER + highlight.end;
374
+ }
375
+ // Single line
376
+ else if( typeof highlight.start === 'number' ) {
377
+ return highlight.start;
378
+ }
379
+ // All lines
380
+ else {
381
+ return '';
382
+ }
383
+
384
+ } ).join( Plugin.HIGHLIGHT_LINE_DELIMITER );
385
+
386
+ } ).join( Plugin.HIGHLIGHT_STEP_DELIMITER );
387
+
388
+ }
389
+
390
+ }
391
+
392
+ // Function to perform a better "data-trim" on code snippets
393
+ // Will slice an indentation amount on each line of the snippet (amount based on the line having the lowest indentation length)
394
+ function betterTrim(snippetEl) {
395
+ // Helper functions
396
+ function trimLeft(val) {
397
+ // Adapted from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim#Polyfill
398
+ return val.replace(/^[\s\uFEFF\xA0]+/g, '');
399
+ }
400
+ function trimLineBreaks(input) {
401
+ var lines = input.split('\n');
402
+
403
+ // Trim line-breaks from the beginning
404
+ for (var i = 0; i < lines.length; i++) {
405
+ if (lines[i].trim() === '') {
406
+ lines.splice(i--, 1);
407
+ } else break;
408
+ }
409
+
410
+ // Trim line-breaks from the end
411
+ for (var i = lines.length-1; i >= 0; i--) {
412
+ if (lines[i].trim() === '') {
413
+ lines.splice(i, 1);
414
+ } else break;
415
+ }
416
+
417
+ return lines.join('\n');
418
+ }
419
+
420
+ // Main function for betterTrim()
421
+ return (function(snippetEl) {
422
+ var content = trimLineBreaks(snippetEl.innerHTML);
423
+ var lines = content.split('\n');
424
+ // Calculate the minimum amount to remove on each line start of the snippet (can be 0)
425
+ var pad = lines.reduce(function(acc, line) {
426
+ if (line.length > 0 && trimLeft(line).length > 0 && acc > line.length - trimLeft(line).length) {
427
+ return line.length - trimLeft(line).length;
428
+ }
429
+ return acc;
430
+ }, Number.POSITIVE_INFINITY);
431
+ // Slice each line with this amount
432
+ return lines.map(function(line, index) {
433
+ return line.slice(pad);
434
+ })
435
+ .join('\n');
436
+ })(snippetEl);
437
+ }
438
+
439
+ export default () => Plugin;
@@ -0,0 +1,80 @@
1
+ /*
2
+
3
+ Zenburn style from voldmar.ru (c) Vladimir Epifanov <voldmar@voldmar.ru>
4
+ based on dark.css by Ivan Sagalaev
5
+
6
+ */
7
+
8
+ .hljs {
9
+ display: block;
10
+ overflow-x: auto;
11
+ padding: 0.5em;
12
+ background: #3f3f3f;
13
+ color: #dcdcdc;
14
+ }
15
+
16
+ .hljs-keyword,
17
+ .hljs-selector-tag,
18
+ .hljs-tag {
19
+ color: #e3ceab;
20
+ }
21
+
22
+ .hljs-template-tag {
23
+ color: #dcdcdc;
24
+ }
25
+
26
+ .hljs-number {
27
+ color: #8cd0d3;
28
+ }
29
+
30
+ .hljs-variable,
31
+ .hljs-template-variable,
32
+ .hljs-attribute {
33
+ color: #efdcbc;
34
+ }
35
+
36
+ .hljs-literal {
37
+ color: #efefaf;
38
+ }
39
+
40
+ .hljs-subst {
41
+ color: #8f8f8f;
42
+ }
43
+
44
+ .hljs-title,
45
+ .hljs-name,
46
+ .hljs-selector-id,
47
+ .hljs-selector-class,
48
+ .hljs-section,
49
+ .hljs-type {
50
+ color: #efef8f;
51
+ }
52
+
53
+ .hljs-symbol,
54
+ .hljs-bullet,
55
+ .hljs-link {
56
+ color: #dca3a3;
57
+ }
58
+
59
+ .hljs-deletion,
60
+ .hljs-string,
61
+ .hljs-built_in,
62
+ .hljs-builtin-name {
63
+ color: #cc9393;
64
+ }
65
+
66
+ .hljs-addition,
67
+ .hljs-comment,
68
+ .hljs-quote,
69
+ .hljs-meta {
70
+ color: #7f9f7f;
71
+ }
72
+
73
+
74
+ .hljs-emphasis {
75
+ font-style: italic;
76
+ }
77
+
78
+ .hljs-strong {
79
+ font-weight: bold;
80
+ }