markserv 1.17.4 → 1.20.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 +1,243 @@
1
- .hljs{display:block;background:white;padding:0.5em;color:#333333;overflow-x:auto}.hljs-comment,.hljs-meta{color:#969896}.hljs-string,.hljs-variable,.hljs-template-variable,.hljs-strong,.hljs-emphasis,.hljs-quote{color:#df5000}.hljs-keyword,.hljs-selector-tag,.hljs-type{color:#a71d5d}.hljs-literal,.hljs-symbol,.hljs-bullet,.hljs-attribute{color:#0086b3}.hljs-section,.hljs-name{color:#63a35c}.hljs-tag{color:#333333}.hljs-title,.hljs-attr,.hljs-selector-id,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo{color:#795da3}.hljs-addition{color:#55a532;background-color:#eaffea}.hljs-deletion{color:#bd2c00;background-color:#ffecec}.hljs-link{text-decoration:underline}
1
+ /* highlight.js — theme-aware syntax highlighting */
2
+
3
+ .hljs {
4
+ display: block;
5
+ padding: 0.5em;
6
+ overflow-x: auto;
7
+ }
8
+
9
+ /* Light theme (original github-gist) */
10
+ [data-theme="light"] .hljs {
11
+ background: white;
12
+ color: #333333;
13
+ }
14
+ [data-theme="light"] .hljs-comment,
15
+ [data-theme="light"] .hljs-meta {
16
+ color: #969896;
17
+ }
18
+ [data-theme="light"] .hljs-string,
19
+ [data-theme="light"] .hljs-variable,
20
+ [data-theme="light"] .hljs-template-variable,
21
+ [data-theme="light"] .hljs-strong,
22
+ [data-theme="light"] .hljs-emphasis,
23
+ [data-theme="light"] .hljs-quote {
24
+ color: #df5000;
25
+ }
26
+ [data-theme="light"] .hljs-keyword,
27
+ [data-theme="light"] .hljs-selector-tag,
28
+ [data-theme="light"] .hljs-type {
29
+ color: #a71d5d;
30
+ }
31
+ [data-theme="light"] .hljs-literal,
32
+ [data-theme="light"] .hljs-symbol,
33
+ [data-theme="light"] .hljs-bullet,
34
+ [data-theme="light"] .hljs-attribute {
35
+ color: #0086b3;
36
+ }
37
+ [data-theme="light"] .hljs-section,
38
+ [data-theme="light"] .hljs-name {
39
+ color: #63a35c;
40
+ }
41
+ [data-theme="light"] .hljs-tag {
42
+ color: #333333;
43
+ }
44
+ [data-theme="light"] .hljs-title,
45
+ [data-theme="light"] .hljs-attr,
46
+ [data-theme="light"] .hljs-selector-id,
47
+ [data-theme="light"] .hljs-selector-class,
48
+ [data-theme="light"] .hljs-selector-attr,
49
+ [data-theme="light"] .hljs-selector-pseudo {
50
+ color: #795da3;
51
+ }
52
+ [data-theme="light"] .hljs-addition {
53
+ color: #55a532;
54
+ background-color: #eaffea;
55
+ }
56
+ [data-theme="light"] .hljs-deletion {
57
+ color: #bd2c00;
58
+ background-color: #ffecec;
59
+ }
60
+ [data-theme="light"] .hljs-link {
61
+ text-decoration: underline;
62
+ }
63
+
64
+ /* Dark theme (GitHub dark) */
65
+ [data-theme="dark"] .hljs {
66
+ background: #161b22;
67
+ color: #e6edf3;
68
+ }
69
+ [data-theme="dark"] .hljs-comment,
70
+ [data-theme="dark"] .hljs-meta {
71
+ color: #8b949e;
72
+ }
73
+ [data-theme="dark"] .hljs-string,
74
+ [data-theme="dark"] .hljs-variable,
75
+ [data-theme="dark"] .hljs-template-variable,
76
+ [data-theme="dark"] .hljs-strong,
77
+ [data-theme="dark"] .hljs-emphasis,
78
+ [data-theme="dark"] .hljs-quote {
79
+ color: #a5d6ff;
80
+ }
81
+ [data-theme="dark"] .hljs-keyword,
82
+ [data-theme="dark"] .hljs-selector-tag,
83
+ [data-theme="dark"] .hljs-type {
84
+ color: #ff7b72;
85
+ }
86
+ [data-theme="dark"] .hljs-literal,
87
+ [data-theme="dark"] .hljs-symbol,
88
+ [data-theme="dark"] .hljs-bullet,
89
+ [data-theme="dark"] .hljs-attribute {
90
+ color: #79c0ff;
91
+ }
92
+ [data-theme="dark"] .hljs-section,
93
+ [data-theme="dark"] .hljs-name {
94
+ color: #7ee787;
95
+ }
96
+ [data-theme="dark"] .hljs-tag {
97
+ color: #e6edf3;
98
+ }
99
+ [data-theme="dark"] .hljs-title,
100
+ [data-theme="dark"] .hljs-attr,
101
+ [data-theme="dark"] .hljs-selector-id,
102
+ [data-theme="dark"] .hljs-selector-class,
103
+ [data-theme="dark"] .hljs-selector-attr,
104
+ [data-theme="dark"] .hljs-selector-pseudo {
105
+ color: #d2a8ff;
106
+ }
107
+ [data-theme="dark"] .hljs-addition {
108
+ color: #aff5b4;
109
+ background-color: #033a16;
110
+ }
111
+ [data-theme="dark"] .hljs-deletion {
112
+ color: #ffdcd7;
113
+ background-color: #67060c;
114
+ }
115
+ [data-theme="dark"] .hljs-link {
116
+ text-decoration: underline;
117
+ }
118
+
119
+ /* Synthwave theme */
120
+ [data-theme="synthwave"] .hljs {
121
+ background: #1a1228;
122
+ color: #e0d0ff;
123
+ }
124
+ [data-theme="synthwave"] .hljs-comment,
125
+ [data-theme="synthwave"] .hljs-meta {
126
+ color: #6c5987;
127
+ font-style: italic;
128
+ }
129
+ [data-theme="synthwave"] .hljs-string,
130
+ [data-theme="synthwave"] .hljs-variable,
131
+ [data-theme="synthwave"] .hljs-template-variable,
132
+ [data-theme="synthwave"] .hljs-strong,
133
+ [data-theme="synthwave"] .hljs-emphasis,
134
+ [data-theme="synthwave"] .hljs-quote {
135
+ color: #ff8b39;
136
+ }
137
+ [data-theme="synthwave"] .hljs-keyword,
138
+ [data-theme="synthwave"] .hljs-selector-tag,
139
+ [data-theme="synthwave"] .hljs-type {
140
+ color: #ff7edb;
141
+ }
142
+ [data-theme="synthwave"] .hljs-literal,
143
+ [data-theme="synthwave"] .hljs-symbol,
144
+ [data-theme="synthwave"] .hljs-bullet,
145
+ [data-theme="synthwave"] .hljs-attribute {
146
+ color: #36f9f6;
147
+ }
148
+ [data-theme="synthwave"] .hljs-section,
149
+ [data-theme="synthwave"] .hljs-name {
150
+ color: #72f1b8;
151
+ }
152
+ [data-theme="synthwave"] .hljs-tag {
153
+ color: #e0d0ff;
154
+ }
155
+ [data-theme="synthwave"] .hljs-title,
156
+ [data-theme="synthwave"] .hljs-attr,
157
+ [data-theme="synthwave"] .hljs-selector-id,
158
+ [data-theme="synthwave"] .hljs-selector-class,
159
+ [data-theme="synthwave"] .hljs-selector-attr,
160
+ [data-theme="synthwave"] .hljs-selector-pseudo {
161
+ color: #fede5d;
162
+ }
163
+ [data-theme="synthwave"] .hljs-addition {
164
+ color: #72f1b8;
165
+ background-color: #1a3a2a;
166
+ }
167
+ [data-theme="synthwave"] .hljs-deletion {
168
+ color: #ff7edb;
169
+ background-color: #3a1a2a;
170
+ }
171
+ [data-theme="synthwave"] .hljs-link {
172
+ text-decoration: underline;
173
+ color: #36f9f6;
174
+ }
175
+
176
+ /* Solarized theme — Hopscotch syntax highlighting (github.com/idleberg/Hopscotch) */
177
+ [data-theme="solarized"] .hljs {
178
+ background: #322931;
179
+ color: #b9b5b8;
180
+ }
181
+ [data-theme="solarized"] .hljs-comment,
182
+ [data-theme="solarized"] .hljs-meta {
183
+ color: #797379;
184
+ font-style: italic;
185
+ }
186
+ [data-theme="solarized"] .hljs-string,
187
+ [data-theme="solarized"] .hljs-variable,
188
+ [data-theme="solarized"] .hljs-template-variable,
189
+ [data-theme="solarized"] .hljs-strong,
190
+ [data-theme="solarized"] .hljs-emphasis,
191
+ [data-theme="solarized"] .hljs-quote {
192
+ color: #8fc13e;
193
+ }
194
+ [data-theme="solarized"] .hljs-keyword,
195
+ [data-theme="solarized"] .hljs-selector-tag,
196
+ [data-theme="solarized"] .hljs-type {
197
+ color: #c85e7c;
198
+ }
199
+ [data-theme="solarized"] .hljs-literal,
200
+ [data-theme="solarized"] .hljs-symbol,
201
+ [data-theme="solarized"] .hljs-bullet,
202
+ [data-theme="solarized"] .hljs-attribute {
203
+ color: #fd8b19;
204
+ }
205
+ [data-theme="solarized"] .hljs-section,
206
+ [data-theme="solarized"] .hljs-name {
207
+ color: #dd464c;
208
+ }
209
+ [data-theme="solarized"] .hljs-tag {
210
+ color: #b9b5b8;
211
+ }
212
+ [data-theme="solarized"] .hljs-title,
213
+ [data-theme="solarized"] .hljs-attr,
214
+ [data-theme="solarized"] .hljs-selector-id,
215
+ [data-theme="solarized"] .hljs-selector-class,
216
+ [data-theme="solarized"] .hljs-selector-attr,
217
+ [data-theme="solarized"] .hljs-selector-pseudo {
218
+ color: #1290bf;
219
+ }
220
+ [data-theme="solarized"] .hljs-addition {
221
+ color: #8fc13e;
222
+ background-color: rgba(143, 193, 62, 0.1);
223
+ }
224
+ [data-theme="solarized"] .hljs-deletion {
225
+ color: #dd464c;
226
+ background-color: rgba(221, 70, 76, 0.1);
227
+ }
228
+ [data-theme="solarized"] .hljs-link {
229
+ text-decoration: underline;
230
+ color: #1290bf;
231
+ }
232
+ [data-theme="solarized"] .hljs-number {
233
+ color: #fd8b19;
234
+ }
235
+ [data-theme="solarized"] .hljs-built_in {
236
+ color: #fd8b19;
237
+ }
238
+ [data-theme="solarized"] .hljs-params {
239
+ color: #b9b5b8;
240
+ }
241
+ [data-theme="solarized"] .hljs-regexp {
242
+ color: #dd464c;
243
+ }
@@ -1,11 +1,15 @@
1
1
  <!DOCTYPE html>
2
- <html>
2
+ <html data-theme="{{theme}}">
3
3
  <head>
4
4
  <meta charset="UTF-8">
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
6
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
7
7
  <title>{{title}}</title>
8
8
  <meta charset="utf-8">
9
+ <link rel="stylesheet" id="theme-dark" href="{markserv}templates/github-markdown-dark.css"{{#unless themeDark}} disabled{{/unless}}>
10
+ <link rel="stylesheet" id="theme-light" href="{markserv}templates/github-markdown-light.css"{{#unless themeLight}} disabled{{/unless}}>
11
+ <link rel="stylesheet" id="theme-synthwave" href="{markserv}templates/github-markdown-synthwave.css"{{#unless themeSynthwave}} disabled{{/unless}}>
12
+ <link rel="stylesheet" id="theme-solarized" href="{markserv}templates/github-markdown-solarized.css"{{#unless themeSolarized}} disabled{{/unless}}>
9
13
  <link rel="stylesheet" href="{markserv}templates/markserv.css">
10
14
  <link rel="stylesheet" href="{markserv}templates/highlight-js-github-gist.css">
11
15
  <script type="text/javascript" id="MathJax-script" async
@@ -17,5 +21,240 @@
17
21
  {{{content}}}
18
22
  <footer><sup><hr> Served by <a href="https://www.npmjs.com/package/markserv">MarkServ</a> | PID: {{pid}}</sup></footer>
19
23
  </article>
24
+ <div class="width-control" id="width-control">
25
+ <span id="width-tooltip"></span>
26
+ <input type="range" id="width-slider" min="0" max="1920" value="978" step="1">
27
+ </div>
28
+ <button class="theme-toggle" id="theme-toggle" title="Toggle theme"></button>
29
+ <script>
30
+ (function() {
31
+ var themes = ['dark', 'light', 'synthwave', 'solarized'];
32
+ var icons = {dark: '\u{1F319}', light: '\u{2600}\u{FE0F}', synthwave: '\u{1F9D1}\u{200D}\u{1F3A4}', solarized: '\u{262F}\u{FE0F}'};
33
+ var serverTheme = '{{theme}}' || 'dark';
34
+ var current = localStorage.getItem('markserv-theme') || serverTheme;
35
+
36
+ function applyTheme(t) {
37
+ document.documentElement.setAttribute('data-theme', t);
38
+ themes.forEach(function(name) {
39
+ var el = document.getElementById('theme-' + name);
40
+ if (el) el.disabled = (name !== t);
41
+ });
42
+ var btn = document.getElementById('theme-toggle');
43
+ if (btn) btn.textContent = icons[t] || icons.dark;
44
+ current = t;
45
+
46
+ // Re-render mermaid diagrams so they follow the new theme
47
+ // (mermaid bakes theme CSS into the SVG at render time)
48
+ if (window.markservRenderMermaid) {
49
+ window.markservRenderMermaid();
50
+ }
51
+ }
52
+
53
+ applyTheme(current);
54
+
55
+ document.getElementById('theme-toggle').addEventListener('click', function() {
56
+ var idx = themes.indexOf(current);
57
+ var next = themes[(idx + 1) % themes.length];
58
+ localStorage.setItem('markserv-theme', next);
59
+ applyTheme(next);
60
+ });
61
+ })();
62
+ </script>
63
+ <script>
64
+ (function() {
65
+ var slider = document.getElementById('width-slider');
66
+ var tooltip = document.getElementById('width-tooltip');
67
+ if (!slider) return;
68
+
69
+ var CSS_DEFAULT = 978; // must match body { width } in markserv.css
70
+ var storageKey = 'markserv-width:' + '{{rootDir}}';
71
+ var stored = localStorage.getItem(storageKey);
72
+
73
+ function updateSliderMax() {
74
+ // Slider max = current viewport width so user can slide up to full-bleed
75
+ slider.max = window.innerWidth;
76
+ }
77
+
78
+ function applyWidth(px) {
79
+ if (px === CSS_DEFAULT) {
80
+ // Matches stylesheet default — remove inline style so CSS rules apply normally
81
+ document.body.style.width = '';
82
+ } else {
83
+ document.body.style.width = px + 'px';
84
+ }
85
+ slider.value = Math.min(px, parseInt(slider.max, 10));
86
+ }
87
+
88
+ // Initialize
89
+ updateSliderMax();
90
+ if (stored) {
91
+ applyWidth(parseInt(stored, 10));
92
+ } else {
93
+ // No stored value — keep the 978px stylesheet default; slider reflects it
94
+ slider.value = Math.min(CSS_DEFAULT, parseInt(slider.max, 10));
95
+ }
96
+
97
+ function positionTooltip() {
98
+ if (!tooltip) return;
99
+ var val = parseInt(slider.value, 10);
100
+ var min = parseInt(slider.min, 10);
101
+ var max = parseInt(slider.max, 10);
102
+ var pct = (val - min) / (max - min);
103
+ var sliderW = slider.offsetWidth;
104
+ var thumbW = 14;
105
+ var offset = thumbW / 2 + pct * (sliderW - thumbW);
106
+ tooltip.textContent = val + 'px';
107
+ tooltip.style.left = offset + 'px';
108
+ tooltip.style.transform = 'translateX(-50%)';
109
+ }
110
+
111
+ // Slider input → live update
112
+ slider.addEventListener('input', function() {
113
+ var val = parseInt(slider.value, 10);
114
+ applyWidth(val);
115
+ localStorage.setItem(storageKey, String(val));
116
+ if (tooltip) tooltip.classList.add('visible');
117
+ positionTooltip();
118
+ });
119
+
120
+ slider.addEventListener('mousedown', function() {
121
+ if (tooltip) tooltip.classList.add('visible');
122
+ positionTooltip();
123
+ });
124
+
125
+ window.addEventListener('mouseup', function() {
126
+ if (tooltip) tooltip.classList.remove('visible');
127
+ });
128
+
129
+ slider.addEventListener('focus', function() {
130
+ if (tooltip) tooltip.classList.add('visible');
131
+ positionTooltip();
132
+ });
133
+
134
+ slider.addEventListener('blur', function() {
135
+ if (tooltip) tooltip.classList.remove('visible');
136
+ });
137
+
138
+ // Double-click to reset to default width
139
+ slider.addEventListener('dblclick', function() {
140
+ applyWidth(CSS_DEFAULT);
141
+ localStorage.removeItem(storageKey);
142
+ });
143
+
144
+ // On window resize, update slider max to reflect new viewport
145
+ window.addEventListener('resize', function() {
146
+ updateSliderMax();
147
+ });
148
+ })();
149
+ </script>
150
+ {{#if hotreload}}
151
+ <script>
152
+ (function() {
153
+ var ws;
154
+ var delay = 1000;
155
+ var maxDelay = 30000;
156
+ var maxRetries = 20;
157
+ var retries = 0;
158
+
159
+ function connect() {
160
+ ws = new WebSocket('ws://localhost:{{wsPort}}');
161
+ ws.onopen = function() {
162
+ delay = 1000;
163
+ retries = 0;
164
+ ws.send(JSON.stringify({path: location.pathname}));
165
+ };
166
+ ws.onmessage = function(e) {
167
+ var el = document.querySelector('.markdown-body');
168
+ if (el) {
169
+ el.innerHTML = e.data;
170
+ if (el.querySelector('pre.mermaid')) {
171
+ window.markservLoadMermaid();
172
+ }
173
+ }
174
+ };
175
+ ws.onclose = function() {
176
+ if (retries < maxRetries) {
177
+ retries++;
178
+ setTimeout(connect, delay);
179
+ delay = Math.min(delay * 2, maxDelay);
180
+ }
181
+ };
182
+ }
183
+ connect();
184
+ })();
185
+ </script>
186
+ {{/if}}
187
+ <script>
188
+ (function() {
189
+ // Lazy mermaid loader: costs nothing (no network) on pages without a
190
+ // mermaid fence, and degrades to the plain source text when the CDN is
191
+ // unreachable. The script is appended asynchronously and rendered via
192
+ // contentLoaded(), because startOnLoad hooks the window load event,
193
+ // which may already have fired by the time the CDN answers.
194
+ var loading = false;
195
+ var sourceCache = new WeakMap();
196
+
197
+ function mermaidThemeFor(theme) {
198
+ return theme === 'light' ? 'default' : (theme === 'solarized' ? 'neutral' : 'dark')
199
+ }
200
+
201
+ // Render/re-render all mermaid fences with the page's current theme.
202
+ // Mermaid replaces a fence's content with the SVG, so previously
203
+ // rendered fences get their source restored from the cache first.
204
+ window.markservRenderMermaid = function() {
205
+ // window.mermaid can be a named element (e.g. <h1 id="mermaid">);
206
+ // only treat it as the library if it actually exposes the API
207
+ var mermaidLib = window.mermaid;
208
+ if (!mermaidLib || typeof mermaidLib.contentLoaded !== 'function') {
209
+ return
210
+ }
211
+
212
+ var els = document.querySelectorAll('pre.mermaid');
213
+ els.forEach(function(el) {
214
+ if (!sourceCache.has(el)) {
215
+ sourceCache.set(el, el.innerHTML);
216
+ }
217
+ });
218
+ els.forEach(function(el) {
219
+ if (el.getAttribute('data-processed')) {
220
+ el.innerHTML = sourceCache.get(el);
221
+ el.removeAttribute('data-processed');
222
+ }
223
+ });
224
+
225
+ var theme = document.documentElement.getAttribute('data-theme') || 'dark';
226
+ mermaidLib.initialize({ theme: mermaidThemeFor(theme) });
227
+ mermaidLib.contentLoaded();
228
+ };
229
+
230
+ window.markservLoadMermaid = function() {
231
+ var mermaidLib = window.mermaid;
232
+ if (mermaidLib && typeof mermaidLib.contentLoaded === 'function') {
233
+ window.markservRenderMermaid();
234
+ return
235
+ }
236
+
237
+ if (loading) {
238
+ return
239
+ }
240
+
241
+ loading = true;
242
+ var script = document.createElement('script');
243
+ script.src = 'https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js';
244
+ script.onload = function() {
245
+ window.markservRenderMermaid();
246
+ };
247
+ script.onerror = function() {
248
+ // Offline or CDN unreachable: keep the diagram source as plain text
249
+ loading = false;
250
+ };
251
+ document.head.appendChild(script);
252
+ };
253
+
254
+ if (document.querySelector('pre.mermaid')) {
255
+ window.markservLoadMermaid();
256
+ }
257
+ })();
258
+ </script>
20
259
  </body>
21
260
  </html>