@abreen/tada 1.1.0 → 1.3.1

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 (94) hide show
  1. package/README.md +69 -17
  2. package/bin/tada.ts +317 -25
  3. package/bin/validators.test.ts +4 -3
  4. package/bin/validators.ts +4 -2
  5. package/build/apply-base-path-plugin.ts +24 -13
  6. package/build/build-manifest.test.ts +349 -0
  7. package/build/build-manifest.ts +165 -0
  8. package/build/bundle.ts +19 -20
  9. package/build/code.test.ts +7 -3
  10. package/build/content-watch.ts +6 -6
  11. package/build/copy.ts +2 -2
  12. package/build/deflist-id-plugin.ts +1 -1
  13. package/build/external-links-plugin.ts +2 -2
  14. package/build/features.ts +1 -1
  15. package/build/generate-content-assets.ts +12 -7
  16. package/build/generate-favicon.ts +13 -6
  17. package/build/generate-fonts.ts +2 -2
  18. package/build/generate-katex-assets.ts +35 -0
  19. package/build/generate-manifest.ts +2 -2
  20. package/build/globals.test.ts +10 -11
  21. package/build/globals.ts +14 -7
  22. package/build/json-schema.test.ts +1 -1
  23. package/build/log.test.ts +1 -1
  24. package/build/log.ts +2 -2
  25. package/build/markdown-plugins.test.ts +116 -10
  26. package/build/pagefind.test.ts +2 -2
  27. package/build/pagefind.ts +5 -5
  28. package/build/pdf-text.test.ts +52 -0
  29. package/build/pipeline.ts +42 -15
  30. package/build/reachability.test.ts +1 -1
  31. package/build/serve.ts +20 -8
  32. package/build/site-variables.ts +13 -5
  33. package/build/templates.ts +16 -7
  34. package/build/toc-plugin.test.ts +2 -2
  35. package/build/toc-plugin.ts +1 -1
  36. package/build/types.ts +15 -6
  37. package/build/util.ts +6 -6
  38. package/build/utils/code.ts +5 -5
  39. package/build/utils/content-files.ts +3 -3
  40. package/build/utils/derive-theme.test.ts +1 -1
  41. package/build/utils/derive-theme.ts +1 -1
  42. package/build/utils/file-types.test.ts +1 -1
  43. package/build/utils/front-matter.test.ts +1 -4
  44. package/build/utils/front-matter.ts +2 -2
  45. package/build/utils/jdi-runner/LiterateRunner.java +13 -0
  46. package/build/utils/literate-java.ts +24 -12
  47. package/build/utils/markdown.ts +41 -9
  48. package/build/utils/paths.test.ts +2 -2
  49. package/build/utils/paths.ts +5 -1
  50. package/build/utils/render.ts +57 -36
  51. package/build/utils/shiki-highlighter.ts +1 -1
  52. package/build/validate-internal-links-plugin.test.ts +1 -1
  53. package/build/validate-internal-links-plugin.ts +1 -1
  54. package/build/watch-reachability-state.test.ts +2 -2
  55. package/build/watch-reachability-state.ts +1 -1
  56. package/build/watch.ts +91 -110
  57. package/init/content/labs/00/VowelCounter.java.md +129 -0
  58. package/init/content/labs/00/index.md +29 -0
  59. package/init/content/labs/index.md +9 -0
  60. package/{content → init/content}/lectures/01/Pair.java.md +1 -0
  61. package/{content → init/content}/lectures/index.md +1 -1
  62. package/{content → init/content}/markdown.md +26 -7
  63. package/package.json +19 -7
  64. package/{templates → schema}/nav.schema.json +1 -2
  65. package/{build → schema}/site.schema.json +3 -5
  66. package/src/_alerts.scss +4 -0
  67. package/src/_base.scss +90 -6
  68. package/src/_layout.scss +39 -2
  69. package/src/anchor/index.ts +0 -1
  70. package/src/index.ts +3 -3
  71. package/src/question/style.scss +8 -3
  72. package/src/search/index.test.ts +203 -0
  73. package/src/search/index.ts +3 -79
  74. package/src/search/pdf-utils.ts +79 -0
  75. package/src/search/style.scss +2 -20
  76. package/src/style.scss +20 -101
  77. package/src/timezone/index.ts +9 -25
  78. package/src/util.ts +1 -1
  79. package/templates/_top.html +2 -1
  80. package/types/dev.d.ts +1 -3
  81. package/types/site-variables.d.ts +6 -10
  82. package/types/untyped-modules.d.ts +7 -0
  83. package/build/utils/jdi-runner/LiterateRunner.class +0 -0
  84. package/config/authors.json +0 -1
  85. package/config/nav.json +0 -28
  86. /package/{content → init/content}/index.md +0 -0
  87. /package/{content → init/content}/lectures/01/Rectangle.java +0 -0
  88. /package/{content → init/content}/lectures/01/demo.py +0 -0
  89. /package/{content → init/content}/lectures/01/index.md +0 -0
  90. /package/{content → init/content}/lectures/01/lecture1.pdf +0 -0
  91. /package/{content → init/content}/problem_sets/index.html +0 -0
  92. /package/{public → init/public}/avatars/alex.jpg +0 -0
  93. /package/{public → init/public}/test.txt +0 -0
  94. /package/{templates → schema}/authors.schema.json +0 -0
@@ -0,0 +1,129 @@
1
+ parent: /labs/00/index.html
2
+ parentLabel: Lab 0
3
+ title: Counting vowels
4
+ author: alex
5
+ description: An example of a literate Java program that takes predefined input.
6
+ stdin: "hello, world!\n"
7
+
8
+ A Java program can process input in different ways: it could open a file and
9
+ read it; it could open a network connection and wait for data from another
10
+ computer on the Internet, or it can read from the standard in.
11
+
12
+ The <dfn>standard in</dfn> (or `stdin`) is one of three streams available to a
13
+ running program. The other two streams are the standard out and standard error.
14
+
15
+ <figure>
16
+ <svg viewBox="0 50 410 90" xmlns="http://www.w3.org/2000/svg" font-size="14" fill="none" style="margin:1rem auto;display:block;max-width:410px">
17
+ <defs>
18
+ <marker id="arrow" markerWidth="8" markerHeight="8" refX="8" refY="4" orient="auto">
19
+ <path d="M0,0 L8,4 L0,8 Z" stroke="currentColor" fill="currentColor"></path>
20
+ </marker>
21
+ </defs>
22
+ <!-- Java program box -->
23
+ <rect x="155" y="60" width="100" height="60" stroke-width="2" stroke="currentColor"></rect>
24
+ <text x="205" y="95" text-anchor="middle" fill="currentColor">Program</text>
25
+ <!-- stdin arrow (incoming from left) -->
26
+ <path d="M20 90H143" marker-end="url(#arrow)" stroke="currentColor"></path>
27
+ <text x="80" y="82" text-anchor="middle" fill="currentColor" font-family="var(--mono-font)">stdin</text>
28
+ <!-- stdout arrow (outgoing, upper right) -->
29
+ <path d="M267 75H390" marker-end="url(#arrow)" stroke="currentColor"></path>
30
+ <text x="328" y="67" text-anchor="middle" fill="currentColor" font-family="var(--mono-font)">stdout</text>
31
+ <!-- stderr arrow (outgoing, lower right) -->
32
+ <path d="M267 105H390" marker-end="url(#arrow)" stroke="currentColor"></path>
33
+ <text x="328" y="125" text-anchor="middle" fill="currentColor" font-family="var(--mono-font)">stderr</text>
34
+ </svg>
35
+ <figcaption>
36
+ A running Java program (depicted as a box) with the standard in stream as an
37
+ incoming arrow and the standard out & error streams as outgoing arrows.
38
+ </figcaption>
39
+ </figure>
40
+
41
+ When a Java program calls `System.out.print()` (or `IO.print()`), the program
42
+ sends data to the standard out. When a program uses `System.err.print()`, it
43
+ sends data to the standard error, an output stream similar to `System.out`
44
+ but reserved for error messages.
45
+
46
+ `System.in` is an `InputStream` object that allows a program to read characters
47
+ from the standard input, one character at a time. Its `read()` method returns an
48
+ integer value.
49
+
50
+ - If the integer is positive, it represents a Unicode character coming through
51
+ the stream.
52
+ - If the integer is -1, there is no more input in the stream.
53
+
54
+ The -1 is known as a <dfn>sentinel</dfn>, or a reserved value known ahead of
55
+ time to represent a specific condition. Because all Unicode characters are
56
+ positive numbers, -1 cannot be converted to a character, and is instead used
57
+ to represent the specific condition of "*no more input in the stream*."
58
+
59
+ Let's implement a program that uses `System.in.read()` to get all the characters
60
+ from the standard in, counting how many characters are vowels. When there are
61
+ no more characters in the stream, the program prints the total number of vowels.
62
+
63
+ <!---
64
+ Hiding the method signature for main() keeps us focused on the program's logic,
65
+ and avoids discussion of IOException.
66
+ ```
67
+ void main() throws Exception {
68
+ ```
69
+ -->
70
+
71
+ We'll start the program with a `numVowels` counter initialized to zero,
72
+ the additive identity, and a second integer variable `ch` used to store the
73
+ return value of the `read()` method:
74
+
75
+ ```
76
+ int numVowels = 0;
77
+ int ch;
78
+ ```
79
+
80
+ Using an indefinite loop (since we don't know in advance how many characters
81
+ we'll get), we call the `read()` method and check if it returned the sentinel:
82
+
83
+ ```
84
+ while (true) {
85
+ ch = System.in.read();
86
+ if (ch == -1) {
87
+ break;
88
+ }
89
+ ```
90
+
91
+ If `read()` returns the sentinel, we stop the loop with `break`. Otherwise,
92
+ we test whether `ch` is a vowel:
93
+
94
+ ```
95
+ if ("aeiouAEIOU".indexOf(ch) >= 0) {
96
+ numVowels++;
97
+ }
98
+ ```
99
+
100
+ <!---
101
+ Hide the closing brace of the `while` loop to avoid indenting the conditional.
102
+ ```
103
+ }
104
+ ```
105
+ -->
106
+
107
+ Putting lower case and upper case vowels into a `String` allows us to use the
108
+ `indexOf()` method to check if `ch` is one of those characters. If `ch` is
109
+ nowhere in the string, `indexOf()` returns -1.
110
+
111
+ When reading input from a terminal, the loop ends when the user presses
112
+ <kbd>Ctrl</kbd>+<kbd>D</kbd> on the keyboard. If we type the input
113
+
114
+ ```text
115
+ hello, world!
116
+ ```
117
+
118
+ Then the last line of the program, which prints the total count, will output 3:
119
+
120
+ ```
121
+ IO.println("vowels: " + numVowels);
122
+ ```
123
+
124
+ <!---
125
+ Hiding the closing brace for main().
126
+ ```
127
+ }
128
+ ```
129
+ -->
@@ -0,0 +1,29 @@
1
+ parent: /labs/index.html
2
+ parentLabel: Labs
3
+ title: Lab 0
4
+ author: alex
5
+ description: An example lab page for <%= site.title %>.
6
+
7
+ In this lab, we'll explore the [`VowelCounter` program](./VowelCounter.html).
8
+
9
+ ## Review questions
10
+
11
+ ??? question What is an input stream?
12
+
13
+ An input stream is an abstraction that represents arbitrary data going into a
14
+ program. The data in a stream doesn't have a predefined size or length.
15
+ When you write a program that uses an input stream, the program may wait for
16
+ more data.
17
+
18
+ ???
19
+
20
+ ??? question What is a sentinel? Provide an example.
21
+
22
+ A sentinel is a special value a program uses to change its behavior.
23
+ For example, `System.in.read()` returns -1 when the standard in stream doesn't
24
+ have any more characters.
25
+
26
+ Another example: the character `'q'` might be reserved to indicate a command
27
+ like "quit." When a user presses <kbd>Q</kbd>, the program exits.
28
+
29
+ ???
@@ -0,0 +1,9 @@
1
+ title: Labs
2
+ author: alex
3
+ description: An example page for <%= site.title %>.
4
+
5
+ In each one-hour lab, we'll dive deeper and write code together, exploring how
6
+ to apply the concepts we learned in lecture to solve real-world problems and
7
+ write full-length programs.
8
+
9
+ 0. [`VowelCounter` and user input](/labs/00/index.html)
@@ -1,5 +1,6 @@
1
1
  title: A generic `Pair` class
2
2
  author: alex
3
+ description: An example of a literate Java program.
3
4
 
4
5
  <!---
5
6
  You may hide code from the generated HTML page but still include it in the
@@ -2,7 +2,7 @@ title: Lectures
2
2
  author: alex
3
3
  description: An example page for <%= site.title %>.
4
4
 
5
- <%= timezoneChooser %>
5
+ <%= renderTimeZoneChooser() %>
6
6
 
7
7
  One-hour lectures are held weekly at <time datetime="17:40">5:40 PM</time>.
8
8
  Each lecture is recorded and made available by password-protected link.
@@ -128,6 +128,20 @@ See `config/site.dev.json` and `config/site.prod.json` to change `site.basePath`
128
128
  and `site.internalDomains`.
129
129
 
130
130
 
131
+ ## LaTeX
132
+
133
+ $\LaTeX$ support is implemented via [KaTeX](https://katex.org/). The standard
134
+ dollar sign-based syntax is supported. Wrap inline math in single `$`,
135
+ or use `$$` for a math block.
136
+
137
+ Here's an example: selection sort performs $O(n^2)$ comparisons. And to
138
+ demonstrate a block, here's the exact number of comparisons:
139
+
140
+ $$
141
+ (n-1) + (n-2) + \dots + 1 = \sum_{i=1}^{n-1}i
142
+ $$
143
+
144
+
131
145
  ## Additional syntax
132
146
 
133
147
  !!! note Headings are links
@@ -228,7 +242,7 @@ Beware of this rule.
228
242
  A time zone chooser for testing styles (see the "time zone chooser" section
229
243
  below):
230
244
 
231
- <%= timezoneChooser %>
245
+ <%= renderTimeZoneChooser() %>
232
246
 
233
247
  A `<time>` element for testing styles: <time datetime="15:00">3 pm</time>
234
248
 
@@ -326,14 +340,19 @@ These features aren't Markdown-specific, but are included here for reference.
326
340
 
327
341
  Allows the user to see times in their local time zone.
328
342
 
329
- !!! note
330
- Look at the source code for this file to see how to insert it.
331
- !!!
343
+ Insert the time zone chooser using Lodash templates, calling the
344
+ `renderTimeZoneChooser()` function (made available on any page as a global):
345
+
346
+ ```
347
+ <%= '\x3C%= renderTimeZoneChooser() %\x3E' %>
348
+ ```
349
+
350
+ To produce:
332
351
 
333
- <%= timezoneChooser %>
352
+ <%= renderTimeZoneChooser() %>
334
353
 
335
- Wrap your times in `<time datetime="...">` elements and they will be updated
336
- when the user makes a time zone selection.
354
+ Then, wrap your times in `<time datetime="...">` elements and they will be
355
+ updated when the user makes a time zone selection.
337
356
 
338
357
  Use
339
358
 
package/package.json CHANGED
@@ -1,9 +1,14 @@
1
1
  {
2
2
  "name": "@abreen/tada",
3
- "version": "1.1.0",
3
+ "version": "1.3.1",
4
4
  "type": "module",
5
5
  "description": "A static site generator",
6
6
  "license": "MIT",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "git+https://github.com/abreen/Tada.git"
10
+ },
11
+ "author": "Alex Breen <npm@abreen.email>",
7
12
  "bin": {
8
13
  "tada": "bin/tada.ts"
9
14
  },
@@ -13,24 +18,30 @@
13
18
  "src/",
14
19
  "templates/",
15
20
  "fonts/",
16
- "config/",
17
- "content/",
18
- "public/",
21
+ "init/",
22
+ "schema/",
19
23
  "types/",
20
24
  "tsconfig.json"
21
25
  ],
22
26
  "scripts": {
23
- "prepare": "husky",
24
- "init-example": "bun run bin/tada.ts init example --default",
27
+ "prepare": "husky && bun run scripts/check-deps.ts",
28
+ "prepack": "bun run scripts/prepack.ts",
29
+ "init-example": "bun run bin/tada.ts init example --no-interactive",
25
30
  "lint": "eslint src/ build/ bin/",
26
31
  "typecheck": "tsc --noEmit",
27
- "test:functional": "python3 -m pip install -q -r functional_tests/requirements.txt && python3 -m pytest functional_tests/ -v -n auto"
32
+ "test:functional": "python3 -m pip install -q -r functional_tests/requirements.txt && python3 -m pytest functional_tests/ -v -n auto --durations=10",
33
+ "test:all": "bun test && bun run test:functional"
28
34
  },
29
35
  "engines": {
30
36
  "bun": ">=1.0.0"
31
37
  },
38
+ "os": [
39
+ "darwin",
40
+ "linux"
41
+ ],
32
42
  "dependencies": {
33
43
  "@tsconfig/node23": "^23.0.2",
44
+ "@vscode/markdown-it-katex": "^1.1.2",
34
45
  "ajv": "^8.17.1",
35
46
  "chokidar": "^4.0.0",
36
47
  "culori": "^4.0.2",
@@ -38,6 +49,7 @@
38
49
  "front-matter": "^4.0.2",
39
50
  "java-parser": "^3.0.1",
40
51
  "jsdom": "^26.1.0",
52
+ "katex": "^0.16.40",
41
53
  "lodash": "^4.17.21",
42
54
  "markdown-it": "^14.1.0",
43
55
  "markdown-it-anchor": "^9.2.0",
@@ -14,8 +14,7 @@
14
14
  "text": { "type": "string" },
15
15
  "internal": { "type": "string", "pattern": "^\\/.*$" },
16
16
  "external": { "type": "string", "pattern": "^https?:\\/\\/.*$" },
17
- "disabled": { "type": "boolean" },
18
- "keywords": { "type": "array", "items": { "type": "string" } }
17
+ "disabled": { "type": "boolean" }
19
18
  },
20
19
  "oneOf": [{ "required": ["internal"] }, { "required": ["external"] }],
21
20
  "additionalProperties": false
@@ -1,16 +1,15 @@
1
1
  {
2
2
  "type": "object",
3
- "required": ["defaultTimeZone"],
3
+ "required": ["base", "title", "defaultTimeZone", "themeColor"],
4
4
  "properties": {
5
5
  "features": {
6
6
  "type": "object",
7
- "default": { "search": true, "code": true },
7
+ "default": { "search": true, "code": true, "favicon": true },
8
8
  "properties": {
9
9
  "search": { "type": "boolean", "default": true },
10
10
  "code": { "type": "boolean", "default": true },
11
- "favicon": { "type": "boolean", "default": false }
11
+ "favicon": { "type": "boolean", "default": true }
12
12
  },
13
- "required": ["search", "code", "favicon"],
14
13
  "additionalProperties": false
15
14
  },
16
15
  "base": { "type": "string", "pattern": "^https?:\\/\\/[-.:a-zA-Z0-9]+$" },
@@ -27,7 +26,6 @@
27
26
  "title": { "type": "string" },
28
27
  "symbol": { "type": "string", "pattern": "^[A-Z0-9\\- ]{1,5}$" },
29
28
  "titlePostfix": { "type": "string" },
30
- "courseId": { "type": "string" },
31
29
  "themeColor": { "type": "string" },
32
30
  "tintHue": {
33
31
  "type": "integer",
package/src/_alerts.scss CHANGED
@@ -40,6 +40,10 @@
40
40
 
41
41
  a {
42
42
  text-decoration-color: var(--fg-color);
43
+
44
+ &:hover {
45
+ text-decoration-color: inherit;
46
+ }
43
47
  }
44
48
 
45
49
  dfn {
package/src/_base.scss CHANGED
@@ -1,3 +1,5 @@
1
+ @use 'mixins' as *;
2
+
1
3
  :root {
2
4
  --box-border-width: 5px;
3
5
 
@@ -13,10 +15,6 @@
13
15
  --main-width: 900px;
14
16
  }
15
17
 
16
- p {
17
- margin: 0 0 1rem 0;
18
- }
19
-
20
18
  h1,
21
19
  h2,
22
20
  h3,
@@ -74,8 +72,21 @@ html {
74
72
  a {
75
73
  color: var(--fg-color);
76
74
  text-decoration-color: var(--fg2-color);
77
- text-decoration-thickness: 1px;
78
- text-underline-offset: 3px;
75
+ text-decoration-thickness: 1.5px;
76
+
77
+ @media (hover: hover) {
78
+ &:hover {
79
+ color: var(--fg2-color);
80
+ }
81
+ }
82
+ }
83
+
84
+ a:active {
85
+ color: var(--link-active-color);
86
+
87
+ @media (hover: hover) {
88
+ text-decoration-color: var(--link-active-color);
89
+ }
79
90
  }
80
91
 
81
92
  pre,
@@ -104,3 +115,76 @@ pre {
104
115
  padding: 0;
105
116
  }
106
117
  }
118
+
119
+ details .content > *:first-child {
120
+ margin-top: 0;
121
+ }
122
+
123
+ details .content > *:last-child {
124
+ margin-bottom: 0;
125
+ }
126
+
127
+ details summary {
128
+ cursor: pointer;
129
+ @include user-select(none);
130
+ padding: var(--details-padding);
131
+ }
132
+
133
+ details .content {
134
+ padding: 0 var(--details-padding) var(--details-padding)
135
+ var(--details-padding);
136
+ }
137
+
138
+ @media (hover: hover) {
139
+ details summary {
140
+ &:hover {
141
+ color: var(--fg2-color);
142
+ }
143
+
144
+ &:active {
145
+ color: var(--link-active-color);
146
+ }
147
+ }
148
+ }
149
+
150
+ main details {
151
+ margin-bottom: 1rem;
152
+ border-radius: var(--border-radius);
153
+ border: 2px solid var(--fg-color);
154
+ }
155
+
156
+ input[type='text'],
157
+ input[type='search'] {
158
+ background: var(--bg-color);
159
+ color: var(--fg-color);
160
+ border: var(--control-border-width) solid var(--fg2-color);
161
+ border-radius: var(--border-radius);
162
+ font-size: 12pt;
163
+ padding: 4px 4px;
164
+ }
165
+
166
+ input[type='search'] {
167
+ background-color: var(--bg-color);
168
+ background-image: var(--icon-search);
169
+ background-repeat: no-repeat;
170
+ background-position: left 6px center;
171
+ background-size: 16px 16px;
172
+ padding-left: 2rem;
173
+ border-radius: 18px;
174
+ min-width: 0;
175
+
176
+ &:disabled {
177
+ opacity: 0.4;
178
+ cursor: not-allowed;
179
+ }
180
+ }
181
+
182
+ figure {
183
+ margin: 1rem 0;
184
+
185
+ figcaption {
186
+ margin: 0 3rem;
187
+ font-size: var(--font-size-smaller);
188
+ color: var(--fg2-color);
189
+ }
190
+ }
package/src/_layout.scss CHANGED
@@ -1,3 +1,5 @@
1
+ @use 'mixins' as *;
2
+
1
3
  :root {
2
4
  --toc-width: 260px;
3
5
  }
@@ -8,6 +10,7 @@ html {
8
10
  overflow-y: auto;
9
11
  scroll-padding-top: calc(var(--header-collapsed-height) + var(--gap));
10
12
  }
13
+
11
14
  body {
12
15
  margin: 0;
13
16
  padding: 0;
@@ -49,7 +52,7 @@ body.literate main table {
49
52
  width: 100%;
50
53
  }
51
54
 
52
- @media (max-width: 899px) {
55
+ @media (width < 900px) {
53
56
  .toc-is-active .main-content {
54
57
  display: flex;
55
58
  flex-direction: column;
@@ -78,7 +81,7 @@ body.literate main table {
78
81
  }
79
82
  }
80
83
 
81
- @media (min-width: 900px) {
84
+ @media (width >= 900px) {
82
85
  body.default main table,
83
86
  body.literate main table {
84
87
  width: auto;
@@ -132,6 +135,40 @@ body.literate main table {
132
135
  }
133
136
  }
134
137
 
138
+ .info {
139
+ @include user-select(none);
140
+ display: grid;
141
+ grid-template-columns: 1fr auto;
142
+ align-items: baseline;
143
+ color: var(--fg2-color);
144
+ font-size: var(--font-size-smaller);
145
+
146
+ @media (width < 450px) {
147
+ grid-template-columns: 1fr;
148
+ }
149
+
150
+ aside.author {
151
+ a {
152
+ text-decoration: none;
153
+
154
+ .text {
155
+ color: var(--fg2-color);
156
+ text-decoration: underline;
157
+ text-decoration-color: var(--fg2-color);
158
+ text-decoration-thickness: 1px;
159
+ text-underline-offset: 3px;
160
+ }
161
+ }
162
+
163
+ .avatar {
164
+ width: 24px;
165
+ height: 24px;
166
+ vertical-align: middle;
167
+ margin-left: 4px;
168
+ }
169
+ }
170
+ }
171
+
135
172
  .columns {
136
173
  display: grid;
137
174
  grid-template-columns: max-content auto;
@@ -17,7 +17,6 @@ export default (window: Window) => {
17
17
  link.className = 'heading-anchor';
18
18
  link.href = `#${el.id}`;
19
19
  link.title = 'Link to this heading';
20
- link.setAttribute('aria-label', 'Link to this heading');
21
20
 
22
21
  // Move all existing child nodes into the link
23
22
  while (el.firstChild) {
package/src/index.ts CHANGED
@@ -18,7 +18,7 @@ import mountPrint from './print';
18
18
  import mountTop from './top';
19
19
  import mountAnchor from './anchor';
20
20
  import mountQuestion from './question';
21
- import mountTimezone from './timezone';
21
+ import mountTimeZone from './timezone';
22
22
  import mountCode from './code';
23
23
 
24
24
  import { scheduleTask, formatDuration } from './util';
@@ -31,7 +31,7 @@ const COMPONENTS = {
31
31
  top: mountTop,
32
32
  anchor: mountAnchor,
33
33
  question: mountQuestion,
34
- timezone: mountTimezone,
34
+ timeZone: mountTimeZone,
35
35
  code: mountCode,
36
36
  };
37
37
 
@@ -65,7 +65,7 @@ document.addEventListener('DOMContentLoaded', async () => {
65
65
  console.error(`Failed to mount ${name} component:`, reason);
66
66
  }
67
67
 
68
- if (window.IS_DEV) {
68
+ if (__IS_DEV__) {
69
69
  const diff = window.performance.now() - startTime;
70
70
  console.info(`Components mounted in ${formatDuration(diff)}`);
71
71
  }
@@ -35,8 +35,7 @@
35
35
  @include user-select(none);
36
36
  }
37
37
 
38
- .question-a-body > ol:first-child,
39
- .question-a-body > ul:first-child {
38
+ .question-a-body > *:first-child {
40
39
  margin-top: 0;
41
40
  }
42
41
 
@@ -49,19 +48,25 @@
49
48
  @media (prefers-reduced-motion: no-preference) {
50
49
  transition:
51
50
  color 0.25s,
52
- background-color 0.25s;
51
+ background-color 0.25s,
52
+ border-color 0.25s,
53
+ box-shadow 0.25s;
53
54
  }
54
55
  }
55
56
 
56
57
  .question-a-body:not([data-revealed]) > * {
57
58
  color: transparent;
58
59
  background-color: var(--bg2-color);
60
+ border-color: transparent;
61
+ box-shadow: none;
59
62
  pointer-events: none;
60
63
  }
61
64
 
62
65
  .question-a-body:not([data-revealed]) > * * {
63
66
  color: transparent;
64
67
  background-color: var(--bg2-color);
68
+ border-color: transparent;
69
+ box-shadow: none;
65
70
  }
66
71
 
67
72
  .question-a-body::after {