@abreen/tada 1.6.2 → 1.6.4

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.
@@ -36,6 +36,22 @@ function capitalize(str: string): string {
36
36
  return str[0].toUpperCase() + str.slice(1);
37
37
  }
38
38
 
39
+ const MAX_FOOTNOTES = 35;
40
+
41
+ export function footnoteLabel(oneBasedIndex: number): string {
42
+ if (oneBasedIndex < 1 || oneBasedIndex > MAX_FOOTNOTES) {
43
+ throw new Error(
44
+ `Tada supports at most ${MAX_FOOTNOTES} footnotes per page ` +
45
+ `(9 digits + 26 capital letters), but footnote ${oneBasedIndex} ` +
46
+ `was requested. Reduce the number of footnotes on this page.`,
47
+ );
48
+ }
49
+ if (oneBasedIndex <= 9) {
50
+ return String(oneBasedIndex);
51
+ }
52
+ return String.fromCharCode('A'.charCodeAt(0) + (oneBasedIndex - 10));
53
+ }
54
+
39
55
  export function createMarkdown(
40
56
  siteVariables: SiteVariables,
41
57
  options: CreateMarkdownOptions = {},
@@ -196,24 +212,22 @@ export function createMarkdown(
196
212
  });
197
213
 
198
214
  /*
199
- * Customize markdown-it-footnote renderer
215
+ * Customize markdown-it-footnote renderer.
216
+ *
217
+ * Footnotes are labeled with single characters from Inter's ss06
218
+ * stylistic set: 1-9 for the first nine footnotes, then A-Z. The
219
+ * default <ol> numbering is suppressed via CSS and we inject a
220
+ * marker span per item so the label sequence can mix digits and
221
+ * letters.
200
222
  */
201
223
  markdown.renderer.rules.footnote_block_open = () =>
202
224
  '<div class="footnotes"><p class="title">Footnotes</p><ol>';
203
225
 
204
226
  markdown.renderer.rules.footnote_block_close = () => '</ol></div>';
205
227
 
206
- // Change appearance of reference
207
- const caption = markdown.renderer.rules.footnote_caption!;
208
- markdown.renderer.rules.footnote_caption = (
209
- tokens: Token[],
210
- idx: number,
211
- options: Options,
212
- env: unknown,
213
- self: Renderer,
214
- ) => {
215
- const str = caption(tokens, idx, options, env, self);
216
- return str.slice(1, str.length - 1);
228
+ markdown.renderer.rules.footnote_caption = (tokens: Token[], idx: number) => {
229
+ const id = tokens[idx].meta!.id as number;
230
+ return footnoteLabel(id + 1);
217
231
  };
218
232
 
219
233
  const footnoteRef = markdown.renderer.rules.footnote_ref!;
@@ -224,11 +238,26 @@ export function createMarkdown(
224
238
  env: unknown,
225
239
  self: Renderer,
226
240
  ) =>
241
+ // Prepend a non-breaking space so the reference link cannot wrap
242
+ // away from the word it follows.
243
+ '\u00a0' +
227
244
  footnoteRef(tokens, idx, options, env, self)
228
245
  .replace('<sup class="footnote-ref">', '')
229
246
  .replace('</sup>', '')
230
247
  .replace('<a href="', '<a class="footnote-ref" href="');
231
248
 
249
+ markdown.renderer.rules.footnote_open = (tokens: Token[], idx: number) => {
250
+ const id = tokens[idx].meta!.id as number;
251
+ const label = footnoteLabel(id + 1);
252
+ const refid = id + 1;
253
+ return (
254
+ `<li id="fn${refid}" class="footnote-item">` +
255
+ `<span class="footnote-marker" aria-hidden="true">${label}</span> `
256
+ );
257
+ };
258
+
259
+ markdown.renderer.rules.footnote_close = () => '</li>\n';
260
+
232
261
  const footnoteAnchor = markdown.renderer.rules.footnote_anchor!;
233
262
  markdown.renderer.rules.footnote_anchor = (
234
263
  tokens: Token[],
@@ -182,10 +182,10 @@ footnote.[^example-footnote]
182
182
  Definition lists are supported using the same syntax as Presto:
183
183
 
184
184
  Stack
185
- : Last-in first-out collection.
185
+ : Last-in first-out collection.[^footnote-2]
186
186
 
187
187
  Queue
188
- : First-in first-out collection.
188
+ : First-in first-out collection.[^footnote-3]
189
189
 
190
190
  Binary tree
191
191
  : Hierarchical structure where each node has up to two children.
@@ -417,7 +417,15 @@ Here's a time range:
417
417
 
418
418
 
419
419
  [^example-footnote]: Footnotes render inside a numbered list at the bottom of
420
- the page.
420
+ the page.
421
+
422
+ Here's a second paragraph.
423
+
424
+ Here's a third paragraph.
425
+
426
+ [^footnote-2]: Also known as "LIFO".
427
+
428
+ [^footnote-3]: Also known as "FIFO".
421
429
 
422
430
  [front-matter]: https://www.npmjs.com/package/front-matter
423
431
  [markdown-it]: https://markdown-it.github.io/
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abreen/tada",
3
- "version": "1.6.2",
3
+ "version": "1.6.4",
4
4
  "type": "module",
5
5
  "description": "A static site generator",
6
6
  "license": "MIT",
@@ -35,9 +35,21 @@ export default (window: Window) => {
35
35
  }
36
36
  window.addEventListener('keydown', handleWindowKeyDown);
37
37
 
38
+ function handleDetailsFocusOut(e: FocusEvent) {
39
+ if (!details.open) {
40
+ return;
41
+ }
42
+ const next = e.relatedTarget as Node | null;
43
+ if (!next || !details.contains(next)) {
44
+ close();
45
+ }
46
+ }
47
+ details.addEventListener('focusout', handleDetailsFocusOut);
48
+
38
49
  return () => {
39
50
  window.removeEventListener('keydown', handleWindowKeyDown);
40
51
  window.removeEventListener('click', handleWindowClick);
41
52
  details.removeEventListener('click', handleDetailsClick);
53
+ details.removeEventListener('focusout', handleDetailsFocusOut);
42
54
  };
43
55
  };
package/src/style.scss CHANGED
@@ -91,14 +91,34 @@ a.external:not(:has(.external-link-tail))::after {
91
91
  margin: 0;
92
92
  }
93
93
 
94
+ .footnotes ol {
95
+ list-style: none;
96
+ padding-left: 0;
97
+ }
98
+
94
99
  .footnotes li {
100
+ position: relative;
101
+ padding-left: 1.8em;
95
102
  margin-bottom: 8px;
96
103
  }
97
104
 
98
105
  a.footnote-ref {
99
- vertical-align: super;
100
- border-bottom: none;
106
+ vertical-align: text-bottom;
101
107
  font-size: 0.8em;
108
+ font-weight: 600;
109
+ }
110
+
111
+ .footnote-marker {
112
+ @include user-select(none);
113
+ position: absolute;
114
+ left: 0;
115
+ top: 0;
116
+ font-weight: 500;
117
+ }
118
+
119
+ a.footnote-ref,
120
+ .footnote-marker {
121
+ font-feature-settings: 'ss06';
102
122
  }
103
123
 
104
124
  .footnote-item {
@@ -108,7 +128,10 @@ a.footnote-ref {
108
128
  }
109
129
  }
110
130
 
111
- a.footnote-ref,
131
+ a.footnote-ref {
132
+ @include user-select(none);
133
+ }
134
+
112
135
  .footnotes .footnote-backref {
113
136
  display: inline-block;
114
137
  @include user-select(none);