@abreen/tada 1.0.2 → 1.2.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 (146) hide show
  1. package/README.md +96 -48
  2. package/bin/tada.ts +621 -0
  3. package/bin/validators.test.ts +205 -0
  4. package/bin/validators.ts +85 -0
  5. package/{webpack/apply-base-path-plugin.js → build/apply-base-path-plugin.ts} +37 -17
  6. package/build/build-manifest.test.ts +349 -0
  7. package/build/build-manifest.ts +165 -0
  8. package/build/bundle.ts +116 -0
  9. package/{webpack/code.test.js → build/code.test.ts} +10 -7
  10. package/build/colors.ts +25 -0
  11. package/build/content-watch.ts +107 -0
  12. package/build/copy.ts +118 -0
  13. package/{webpack/deflist-id-plugin.js → build/deflist-id-plugin.ts} +7 -6
  14. package/{webpack/external-links-plugin.js → build/external-links-plugin.ts} +14 -5
  15. package/build/features.ts +11 -0
  16. package/build/generate-content-assets.ts +320 -0
  17. package/build/generate-favicon.ts +172 -0
  18. package/build/generate-fonts.ts +31 -0
  19. package/build/generate-katex-assets.ts +35 -0
  20. package/{webpack/generate-manifest-plugin.js → build/generate-manifest.ts} +29 -36
  21. package/build/globals.test.ts +99 -0
  22. package/build/globals.ts +88 -0
  23. package/{webpack/heading-subtitle-plugin.js → build/heading-subtitle-plugin.ts} +4 -2
  24. package/build/json-schema.test.ts +57 -0
  25. package/build/json-schema.ts +33 -0
  26. package/build/log.test.ts +111 -0
  27. package/build/log.ts +167 -0
  28. package/build/markdown-plugins.test.ts +396 -0
  29. package/{webpack/pagefind-plugin.test.js → build/pagefind.test.ts} +74 -13
  30. package/build/pagefind.ts +339 -0
  31. package/build/pdf-text.test.ts +52 -0
  32. package/{webpack/pdf-text.js → build/pdf-text.ts} +47 -27
  33. package/build/pipeline.ts +120 -0
  34. package/{webpack/reachability.test.js → build/reachability.test.ts} +3 -3
  35. package/{webpack/reachability.js → build/reachability.ts} +77 -34
  36. package/build/serve.ts +112 -0
  37. package/build/site-variables.ts +68 -0
  38. package/{webpack/templates.js → build/templates.ts} +38 -35
  39. package/{webpack/text-to-id.js → build/text-to-id.ts} +2 -2
  40. package/build/toc-plugin.test.ts +105 -0
  41. package/{webpack/toc-plugin.js → build/toc-plugin.ts} +32 -13
  42. package/build/types.ts +181 -0
  43. package/build/util.ts +26 -0
  44. package/{webpack/utils/code.js → build/utils/code.ts} +119 -60
  45. package/{webpack/utils/content-files.js → build/utils/content-files.ts} +40 -35
  46. package/build/utils/derive-theme.test.ts +111 -0
  47. package/build/utils/derive-theme.ts +85 -0
  48. package/build/utils/file-types.test.ts +61 -0
  49. package/build/utils/file-types.ts +13 -0
  50. package/build/utils/front-matter.test.ts +77 -0
  51. package/{webpack/utils/front-matter.js → build/utils/front-matter.ts} +22 -9
  52. package/{webpack → build}/utils/jdi-runner/LiterateRunner.java +1 -1
  53. package/{webpack/utils/literate-java.js → build/utils/literate-java.ts} +68 -38
  54. package/{webpack/utils/markdown.js → build/utils/markdown.ts} +126 -49
  55. package/build/utils/paths.test.ts +91 -0
  56. package/{webpack/utils/paths.js → build/utils/paths.ts} +18 -22
  57. package/{webpack/utils/render.js → build/utils/render.ts} +208 -130
  58. package/build/utils/shiki-highlighter.ts +29 -0
  59. package/build/validate-internal-links-plugin.test.ts +106 -0
  60. package/{webpack/validate-internal-links-plugin.js → build/validate-internal-links-plugin.ts} +47 -20
  61. package/{webpack/watch-reachability-state.test.js → build/watch-reachability-state.test.ts} +8 -8
  62. package/{webpack/watch-reachability-state.js → build/watch-reachability-state.ts} +63 -24
  63. package/{webpack/watch-reload-client.js → build/watch-reload-client.ts} +3 -1
  64. package/build/watch.ts +549 -0
  65. package/fonts/google-sans-code/woff2/GoogleSansCodeVariable-Italic.woff2 +0 -0
  66. package/fonts/google-sans-code/woff2/GoogleSansCodeVariable.woff2 +0 -0
  67. package/fonts/inter/woff2/InterVariable-Italic.woff2 +0 -0
  68. package/fonts/inter/woff2/InterVariable.woff2 +0 -0
  69. package/{content → init/content}/index.md +9 -3
  70. package/{content → init/content}/lectures/index.md +1 -1
  71. package/{content → init/content}/markdown.md +28 -8
  72. package/init/content/problem_sets/index.html +14 -0
  73. package/package.json +33 -22
  74. package/{templates → schema}/nav.schema.json +1 -2
  75. package/{webpack → schema}/site.schema.json +4 -12
  76. package/src/_alerts.scss +96 -0
  77. package/src/_base.scss +145 -0
  78. package/src/{layout.scss → _layout.scss} +36 -1
  79. package/src/anchor/index.ts +0 -1
  80. package/src/anchor/style.scss +1 -9
  81. package/src/code/index.ts +3 -3
  82. package/src/code.scss +1 -1
  83. package/src/critical.scss +5 -0
  84. package/src/header/_base.scss +129 -0
  85. package/src/header/style.scss +3 -131
  86. package/src/index.ts +4 -5
  87. package/src/question/style.scss +1 -1
  88. package/src/search/index.test.ts +203 -0
  89. package/src/search/index.ts +38 -93
  90. package/src/search/pdf-utils.ts +79 -0
  91. package/src/search/style.scss +8 -28
  92. package/src/style.scss +15 -326
  93. package/src/timezone/index.ts +5 -6
  94. package/src/toc/style.scss +5 -39
  95. package/src/util.ts +9 -6
  96. package/templates/_theme.scss +38 -14
  97. package/templates/_top.html +1 -1
  98. package/tsconfig.json +10 -6
  99. package/types/dev.d.ts +1 -0
  100. package/types/file-system-access.d.ts +5 -0
  101. package/types/markdown-it-plugins.d.ts +11 -0
  102. package/types/site-variables.d.ts +6 -10
  103. package/types/untyped-modules.d.ts +47 -0
  104. package/bin/tada.js +0 -361
  105. package/config/authors.json +0 -1
  106. package/config/nav.json +0 -28
  107. package/content/problem_sets/index.md +0 -6
  108. package/types/dev.ts +0 -3
  109. package/webpack/build-state.js +0 -97
  110. package/webpack/colors.js +0 -15
  111. package/webpack/config.base.js +0 -151
  112. package/webpack/config.dev.js +0 -23
  113. package/webpack/config.prod.js +0 -32
  114. package/webpack/content-watch-plugin.js +0 -153
  115. package/webpack/features.js +0 -5
  116. package/webpack/generate-content-assets-plugin.js +0 -308
  117. package/webpack/generate-favicon-plugin.js +0 -198
  118. package/webpack/generate-fonts-plugin.js +0 -69
  119. package/webpack/globals.js +0 -74
  120. package/webpack/json-schema.js +0 -19
  121. package/webpack/log.js +0 -143
  122. package/webpack/markdown-plugins.test.js +0 -203
  123. package/webpack/pagefind-plugin.js +0 -379
  124. package/webpack/print-flair-plugin.js +0 -22
  125. package/webpack/serve.js +0 -104
  126. package/webpack/site-variables.js +0 -53
  127. package/webpack/util.js +0 -49
  128. package/webpack/utils/define-plugin.js +0 -20
  129. package/webpack/utils/file-types.js +0 -26
  130. package/webpack/utils/parse-hsl.js +0 -8
  131. package/webpack/utils/shiki-highlighter.js +0 -26
  132. package/webpack/watch.js +0 -166
  133. /package/{webpack → build}/flair.json +0 -0
  134. /package/{webpack → build}/utils/jdi-runner/LiterateRunner.class +0 -0
  135. /package/fonts/google-sans-code/{GoogleSansCodeVariable-Italic.ttf → ttf/GoogleSansCodeVariable-Italic.ttf} +0 -0
  136. /package/fonts/google-sans-code/{GoogleSansCodeVariable.ttf → ttf/GoogleSansCodeVariable.ttf} +0 -0
  137. /package/fonts/inter/{InterVariable-Italic.ttf → ttf/InterVariable-Italic.ttf} +0 -0
  138. /package/fonts/inter/{InterVariable.ttf → ttf/InterVariable.ttf} +0 -0
  139. /package/{content → init/content}/lectures/01/Pair.java.md +0 -0
  140. /package/{content → init/content}/lectures/01/Rectangle.java +0 -0
  141. /package/{content → init/content}/lectures/01/demo.py +0 -0
  142. /package/{content → init/content}/lectures/01/index.md +0 -0
  143. /package/{content → init/content}/lectures/01/lecture1.pdf +0 -0
  144. /package/{public → init/public}/avatars/alex.jpg +0 -0
  145. /package/{public → init/public}/test.txt +0 -0
  146. /package/{templates → schema}/authors.schema.json +0 -0
@@ -1,4 +1,4 @@
1
- @import '../_mixins.scss';
1
+ @use '../mixins' as *;
2
2
 
3
3
  header {
4
4
  .search-controls {
@@ -8,27 +8,7 @@ header {
8
8
  gap: 0.5rem;
9
9
 
10
10
  input.search {
11
- background-color: var(--bg-color);
12
- background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24'><circle cx='11' cy='11' r='7' stroke='hsl(20deg 8% 8%)' stroke-width='2' fill='none'/><line x1='16.5' y1='16.5' x2='22' y2='22' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/></svg>");
13
- background-repeat: no-repeat;
14
- background-position: left 6px center;
15
- background-size: 16px 16px;
16
- padding-left: 2rem;
17
-
18
- border-radius: 18px;
19
11
  flex: 1;
20
- min-width: 0;
21
-
22
- &:disabled {
23
- opacity: 0.4;
24
- cursor: not-allowed;
25
- }
26
- }
27
-
28
- @media (prefers-color-scheme: dark) {
29
- input.search {
30
- background-image: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24'><circle cx='11' cy='11' r='7' stroke='hsl(20deg 20% 90%)' stroke-width='2' fill='none'/><line x1='16.5' y1='16.5' x2='22' y2='22' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/></svg>");
31
- }
32
12
  }
33
13
  }
34
14
 
@@ -48,13 +28,6 @@ header {
48
28
  .results {
49
29
  opacity: 0;
50
30
  pointer-events: none;
51
-
52
- @media (prefers-reduced-motion: no-preference) {
53
- transform: translateY(-8px);
54
- transition:
55
- opacity 0.25s ease,
56
- transform 0.25s ease;
57
- }
58
31
  margin: 0 auto;
59
32
  background: var(--bg-color);
60
33
  color: var(--fg-color);
@@ -68,6 +41,13 @@ header {
68
41
  min-height: 80px;
69
42
  @include user-select(none);
70
43
 
44
+ @media (prefers-reduced-motion: no-preference) {
45
+ transform: translateY(-8px);
46
+ transition:
47
+ opacity 0.25s ease,
48
+ transform 0.25s ease;
49
+ }
50
+
71
51
  .results-info {
72
52
  display: flex;
73
53
  align-items: center;
package/src/style.scss CHANGED
@@ -1,5 +1,8 @@
1
- @import './_mixins.scss';
2
- @import 'config/theme';
1
+ @use 'mixins' as *;
2
+ @use 'config/theme';
3
+ @use 'base';
4
+ @use 'layout';
5
+ @use 'alerts';
3
6
 
4
7
  @font-face {
5
8
  font-family: 'Inter';
@@ -34,38 +37,6 @@
34
37
  format('woff2');
35
38
  }
36
39
 
37
- :root {
38
- --box-border-width: 5px;
39
-
40
- --gap: 12px;
41
- --border-radius: 12px;
42
- --control-border-width: 2px;
43
- --label-border-width: 2px;
44
- --focus-border-width: 3px;
45
- --table-padding: 12px;
46
- --details-padding: 12px;
47
- --section-padding: 64px;
48
-
49
- --main-width: 900px;
50
-
51
- --icon-external-link: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><rect x='3' y='3' width='18' height='18' stroke='hsl(20deg 8% 8%)' stroke-width='2' fill='none' rx='2'/><path d='M9 15 L15 9' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round' fill='none'/><path d='M9 9 H15 V15' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
52
- --icon-external-link-dark: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><rect x='3' y='3' width='18' height='18' stroke='hsl(20deg 20% 90%)' stroke-width='2' fill='none' rx='2'/><path d='M9 15 L15 9' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round' fill='none'/><path d='M9 9 H15 V15' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
53
- --icon-external-link-hover: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><rect x='3' y='3' width='18' height='18' stroke='hsl(20deg 6% 60%)' stroke-width='2' fill='none' rx='2'/><path d='M9 15 L15 9' stroke='hsl(20deg 6% 60%)' stroke-width='2' stroke-linecap='round' fill='none'/><path d='M9 9 H15 V15' stroke='hsl(20deg 6% 60%)' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
54
- --icon-external-link-dark-hover: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><rect x='3' y='3' width='18' height='18' stroke='hsl(20deg 6% 55%)' stroke-width='2' fill='none' rx='2'/><path d='M9 15 L15 9' stroke='hsl(20deg 6% 55%)' stroke-width='2' stroke-linecap='round' fill='none'/><path d='M9 9 H15 V15' stroke='hsl(20deg 6% 55%)' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
55
- --icon-external-link-active: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><rect x='3' y='3' width='18' height='18' stroke='black' stroke-width='2' fill='none' rx='2'/><path d='M9 15 L15 9' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/><path d='M9 9 H15 V15' stroke='black' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
56
- --icon-external-link-dark-active: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><rect x='3' y='3' width='18' height='18' stroke='white' stroke-width='2' fill='none' rx='2'/><path d='M9 15 L15 9' stroke='white' stroke-width='2' stroke-linecap='round' fill='none'/><path d='M9 9 H15 V15' stroke='white' stroke-width='2' stroke-linecap='round' fill='none'/></svg>");
57
-
58
- --icon-external-translucent: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><g opacity='0.3' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round' fill='none'><rect x='3' y='3' width='18' height='18' rx='2'/><path d='M9 15 L15 9' stroke-linecap='round'/><path d='M9 9 H15 V15' stroke-linecap='round'/></g></svg>");
59
- --icon-external-translucent-dark: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='12' height='12' viewBox='0 0 24 24'><g opacity='0.3' stroke='hsl(20deg 85% 90%)' stroke-width='2' stroke-linecap='round' fill='none'><rect x='3' y='3' width='18' height='18' rx='2'/><path d='M9 15 L15 9' stroke-linecap='round'/><path d='M9 9 H15 V15' stroke-linecap='round'/></g></svg>");
60
-
61
- --icon-warning: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24'><polygon points='12,2 22,20 2,20' fill='none' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linejoin='round'/><line x1='12' y1='9' x2='12' y2='13' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='16' x2='12' y2='16' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/></svg>");
62
- --icon-warning-dark: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24'><polygon points='12,2 22,20 2,20' fill='none' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linejoin='round'/><line x1='12' y1='9' x2='12' y2='13' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='16' x2='12' y2='16' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/></svg>");
63
- }
64
-
65
- p {
66
- margin: 0 0 1rem 0;
67
- }
68
-
69
40
  ::selection {
70
41
  color: var(--bg-color);
71
42
  background: var(--fg-color);
@@ -76,116 +47,18 @@ p {
76
47
  outline-offset: 1px;
77
48
  }
78
49
 
79
- h1,
80
- h2,
81
- h3,
82
- h4,
83
- h5,
84
- h6 {
85
- font-family: var(--heading-font);
86
- -webkit-break-after: avoid;
87
- break-after: avoid;
88
- line-height: 1.3;
89
-
90
- // Enable Inter's ligatures (for style)
91
- font-feature-settings: 'dlig';
92
- }
93
-
94
- h1 {
95
- font-size: 250%;
96
- font-weight: 700;
97
- }
98
-
99
- .info {
100
- @include user-select(none);
101
- display: grid;
102
- grid-template-columns: 1fr auto;
103
- align-items: baseline;
104
- color: var(--fg2-color);
105
- font-size: var(--font-size-smaller);
106
-
107
- @media (width < 450px) {
108
- grid-template-columns: 1fr;
109
- }
110
-
111
- aside.author {
112
- a {
113
- text-decoration: none;
114
-
115
- .text {
116
- color: var(--fg2-color);
117
- text-decoration: underline;
118
- text-decoration-color: var(--fg2-color);
119
- text-decoration-thickness: 1px;
120
- text-underline-offset: 3px;
121
- }
122
- }
123
-
124
- .avatar {
125
- width: 24px;
126
- height: 24px;
127
- vertical-align: middle;
128
- margin-left: 4px;
129
- }
130
- }
131
- }
132
-
133
- body {
134
- color: var(--fg-color);
135
- background-color: var(--bg-color);
136
-
137
- font-family: var(--font);
138
- font-size: var(--font-size);
139
- font-weight: var(--font-weight);
140
- line-height: var(--line-height);
141
-
142
- /*
143
- * Enable Inter's features for legibility:
144
- * ss03 - round quotes & commas
145
- * ss04 - disambiguation (make uppercase i and lowercase L distinct)
146
- */
147
- font-feature-settings: 'ss03', 'ss04';
148
-
149
- @media (prefers-color-scheme: dark) {
150
- & {
151
- text-rendering: optimizeLegibility;
152
- -webkit-font-smoothing: antialiased;
153
- }
154
- }
155
- }
156
-
157
- html {
158
- overscroll-behavior: none;
159
- background: var(--bg-color);
160
- }
161
-
162
- a {
163
- color: var(--fg-color);
164
- text-decoration-color: var(--fg2-color);
165
- text-decoration-thickness: 1px;
166
- text-underline-offset: 3px;
167
- }
168
-
169
50
  a.disabled {
170
51
  color: var(--fg-color-translucent);
171
52
  text-decoration-color: var(--fg-color-translucent);
172
53
  cursor: not-allowed;
173
- }
174
54
 
175
- @media (hover: hover) {
176
- a:hover {
177
- color: var(--fg2-color);
178
- }
179
-
180
- a.disabled:hover {
181
- color: var(--fg-color-translucent);
55
+ @media (hover: hover) {
56
+ &:hover {
57
+ color: var(--fg-color-translucent);
58
+ }
182
59
  }
183
60
  }
184
61
 
185
- a:active {
186
- color: var(--link-active-color);
187
- }
188
-
189
62
  a.external::after {
190
63
  content: '';
191
64
  background: var(--icon-external-link);
@@ -196,15 +69,6 @@ a.external::after {
196
69
  padding-right: 18px;
197
70
  }
198
71
 
199
- @media (prefers-color-scheme: dark) {
200
- a.external::after {
201
- background: var(--icon-external-link-dark);
202
- background-size: contain;
203
- background-repeat: no-repeat;
204
- background-position: center center;
205
- }
206
- }
207
-
208
72
  @media (hover: hover) {
209
73
  a.external:hover::after {
210
74
  background: var(--icon-external-link-hover);
@@ -214,15 +78,6 @@ a.external::after {
214
78
  }
215
79
  }
216
80
 
217
- @media (hover: hover) and (prefers-color-scheme: dark) {
218
- a.external:hover::after {
219
- background: var(--icon-external-link-dark-hover);
220
- background-size: contain;
221
- background-repeat: no-repeat;
222
- background-position: center center;
223
- }
224
- }
225
-
226
81
  a.external:active::after {
227
82
  background: var(--icon-external-link-active) !important;
228
83
  background-size: contain !important;
@@ -230,15 +85,6 @@ a.external:active::after {
230
85
  background-position: center center !important;
231
86
  }
232
87
 
233
- @media (prefers-color-scheme: dark) {
234
- a.external:active::after {
235
- background: var(--icon-external-link-dark-active) !important;
236
- background-size: contain !important;
237
- background-repeat: no-repeat !important;
238
- background-position: center center !important;
239
- }
240
- }
241
-
242
88
  a.external.disabled::after,
243
89
  a.external.disabled:active::after {
244
90
  background: var(--icon-external-translucent) !important;
@@ -247,16 +93,6 @@ a.external.disabled:active::after {
247
93
  background-position: center center !important;
248
94
  }
249
95
 
250
- @media (prefers-color-scheme: dark) {
251
- a.external.disabled::after,
252
- a.external.disabled:active::after {
253
- background: var(--icon-external-translucent-dark) !important;
254
- background-size: contain !important;
255
- background-repeat: no-repeat !important;
256
- background-position: center center !important;
257
- }
258
- }
259
-
260
96
  .footnotes {
261
97
  margin-top: calc(var(--thematic-break-margin) / 2);
262
98
  padding-top: 32px;
@@ -355,16 +191,6 @@ main details {
355
191
  border: 2px solid var(--fg-color);
356
192
  }
357
193
 
358
- input[type='text'],
359
- input[type='search'] {
360
- background: var(--bg-color);
361
- color: var(--fg-color);
362
- border: var(--control-border-width) solid var(--fg2-color);
363
- border-radius: var(--border-radius);
364
- font-size: 12pt;
365
- padding: 4px 4px;
366
- }
367
-
368
194
  button,
369
195
  a.button,
370
196
  input[type='submit'] {
@@ -401,7 +227,7 @@ input[type='submit']:focus-visible,
401
227
  input[type='text']:focus-visible,
402
228
  input[type='search']:focus-visible {
403
229
  border-color: var(--fg-color);
404
- background: var(--bg2-color);
230
+ background-color: var(--bg2-color);
405
231
  }
406
232
 
407
233
  button.icon-button {
@@ -508,114 +334,6 @@ tbody tr:last-child td {
508
334
  border-bottom: none;
509
335
  }
510
336
 
511
- .alert {
512
- border: 3px solid var(--bg2-color);
513
- position: relative;
514
- margin: 1rem 0;
515
- }
516
-
517
- .alert.warning {
518
- background: var(--warning-bg-color);
519
- border-color: var(--warning-bg-color);
520
- }
521
-
522
- .alert.note {
523
- background: var(--note-bg-color);
524
- border-color: var(--note-bg-color);
525
- }
526
-
527
- .alert .title {
528
- padding: 10px 6px;
529
- }
530
-
531
- .alert .content {
532
- padding: 12px;
533
-
534
- .styled-list {
535
- color: var(--fg-color);
536
- }
537
-
538
- tt,
539
- code {
540
- background: inherit;
541
- padding: inherit;
542
- }
543
-
544
- time[datetime].is-modified {
545
- // Reset the underline color
546
- text-decoration: underline dotted;
547
- }
548
-
549
- a {
550
- text-decoration-color: var(--fg-color);
551
- }
552
-
553
- dfn {
554
- color: inherit;
555
- }
556
- }
557
-
558
- .alert .content > *:first-child {
559
- margin-top: 0;
560
- }
561
-
562
- .alert .content > *:last-child {
563
- margin-bottom: 0;
564
- }
565
-
566
- .alert .title::before {
567
- left: 8px;
568
- top: 8px;
569
- position: absolute;
570
- width: 32px;
571
- height: 32px;
572
- }
573
-
574
- .alert.warning .title::before {
575
- content: var(--icon-warning);
576
- }
577
-
578
- i.warning {
579
- background: var(--icon-warning);
580
- background-size: contain;
581
- display: inline-block;
582
- height: 1em;
583
- width: 1em;
584
- vertical-align: sub;
585
- }
586
-
587
- @media (prefers-color-scheme: dark) {
588
- .alert.warning .title::before {
589
- content: var(--icon-warning-dark);
590
- }
591
-
592
- i.warning {
593
- background: var(--icon-warning-dark);
594
- background-size: contain;
595
- }
596
- }
597
-
598
- .alert.note .title::before {
599
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='hsl(20deg 8% 8%)' stroke-width='2'/><line x1='12' y1='10' x2='12' y2='16' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='7' x2='12' y2='7' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/></svg>");
600
- }
601
-
602
- @media (prefers-color-scheme: dark) {
603
- .alert.note .title::before {
604
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='32' height='32' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='hsl(20deg 20% 90%)' stroke-width='2'/><line x1='12' y1='10' x2='12' y2='16' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='7' x2='12' y2='7' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/></svg>");
605
- }
606
- }
607
-
608
- .alert .title {
609
- font-weight: 700;
610
- @include user-select(none);
611
- padding-left: 48px;
612
- margin: 0;
613
- }
614
-
615
- .alert > p:last-child {
616
- margin-bottom: 0;
617
- }
618
-
619
337
  section {
620
338
  background: linear-gradient(
621
339
  0deg,
@@ -700,6 +418,10 @@ dl {
700
418
  text-decoration-color: var(--fg2-color);
701
419
  }
702
420
  }
421
+
422
+ &:active {
423
+ text-decoration-color: var(--link-active-color);
424
+ }
703
425
  }
704
426
  }
705
427
 
@@ -718,15 +440,9 @@ dfn {
718
440
  @include user-select(none);
719
441
 
720
442
  &::after {
721
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24'><path d='M3 7 H17 V22' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'/><polyline points='11 16 17 22 23 16' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'/></svg>");
443
+ content: var(--icon-breadcrumb);
722
444
  vertical-align: middle;
723
445
  }
724
-
725
- @media (prefers-color-scheme: dark) {
726
- &::after {
727
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='16' height='16' viewBox='0 0 24 24'><path d='M3 7 H17 V22' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'/><polyline points='11 16 17 22 23 16' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round' stroke-linejoin='round' fill='none'/></svg>");
728
- }
729
- }
730
446
  }
731
447
 
732
448
  img {
@@ -775,33 +491,6 @@ select {
775
491
  font-size: inherit;
776
492
  }
777
493
 
778
- pre,
779
- tt,
780
- code {
781
- font-family: var(--mono-font);
782
- }
783
-
784
- tt,
785
- code {
786
- font-size: var(--mono-font-size);
787
- background: var(--bg2-color);
788
- border-radius: var(--mono-border-radius);
789
- padding: 0.12em 0.25em;
790
- overflow-wrap: anywhere;
791
- }
792
-
793
- pre {
794
- background: var(--bg2-color);
795
- border-radius: var(--mono-border-radius);
796
- line-height: var(--mono-line-height);
797
- overflow: auto;
798
- padding: var(--gap);
799
-
800
- code {
801
- padding: 0;
802
- }
803
- }
804
-
805
494
  // Shiki dual-theme support (defaultColor: false — CSS custom properties only,
806
495
  // no inline color/background-color, so no !important needed)
807
496
  .shiki span {
@@ -84,14 +84,13 @@ function getOffsetMinutes(tz: string, date: Date): number {
84
84
  return (utcTs - date.getTime()) / 60000;
85
85
  }
86
86
 
87
- // window.siteVariables.timezones is replaced by DefinePlugin at build time.
88
- // The typeof guard prevents a ReferenceError in test environments where
89
- // window is not defined.
90
- const TIMEZONES: TimezoneDef[] =
91
- typeof window !== 'undefined' ? window.siteVariables.timezones : [];
87
+ // typeof guard prevents ReferenceError when tests import this module
88
+ // without going through the bundler (which substitutes __SITE_TIMEZONES__).
89
+ const TIMEZONES: TimeZone[] =
90
+ typeof __SITE_TIMEZONES__ !== 'undefined' ? __SITE_TIMEZONES__ : [];
92
91
 
93
92
  function getDefaultTimezone() {
94
- const value = window.siteVariables.defaultTimeZone;
93
+ const value = __SITE_DEFAULT_TIMEZONE__;
95
94
  return TIMEZONES.find(tz => tz.value === value)!;
96
95
  }
97
96
 
@@ -1,4 +1,4 @@
1
- @import '../_mixins.scss';
1
+ @use '../mixins' as *;
2
2
 
3
3
  :root {
4
4
  --highlight-hue: 59deg;
@@ -136,58 +136,24 @@ body.code .toc ol a {
136
136
  }
137
137
 
138
138
  .toc ol li.alert-item.warning a::before {
139
- // fg-color
140
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><polygon points='12,2 22,20 2,20' fill='none' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linejoin='round'/><line x1='12' y1='9' x2='12' y2='13' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='16' x2='12' y2='16' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/></svg>");
141
- }
142
-
143
- @media (prefers-color-scheme: dark) {
144
- .toc ol li.alert-item.warning a::before {
145
- // fg2-color
146
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><polygon points='12,2 22,20 2,20' fill='none' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linejoin='round'/><line x1='12' y1='9' x2='12' y2='13' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='16' x2='12' y2='16' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/></svg>");
147
- }
139
+ content: var(--icon-warning-sm);
148
140
  }
149
141
 
150
142
  @media (hover: hover) {
151
143
  .toc ol li.alert-item.warning:hover a::before,
152
144
  .toc ol li.alert-item.warning a:hover::before {
153
- // fg2-color
154
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><polygon points='12,2 22,20 2,20' fill='none' stroke='hsl(20deg 6% 60%)' stroke-width='2' stroke-linejoin='round'/><line x1='12' y1='9' x2='12' y2='13' stroke='hsl(20deg 6% 60%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='16' x2='12' y2='16' stroke='hsl(20deg 6% 60%)' stroke-width='2' stroke-linecap='round'/></svg>");
155
- }
156
- }
157
-
158
- @media (hover: hover) and (prefers-color-scheme: dark) {
159
- .toc ol li.alert-item.warning:hover a::before,
160
- .toc ol li.alert-item.warning a:hover::before {
161
- // fg2-color
162
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><polygon points='12,2 22,20 2,20' fill='none' stroke='hsl(20deg 6% 55%)' stroke-width='2' stroke-linejoin='round'/><line x1='12' y1='9' x2='12' y2='13' stroke='hsl(20deg 6% 55%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='16' x2='12' y2='16' stroke='hsl(20deg 6% 55%)' stroke-width='2' stroke-linecap='round'/></svg>");
145
+ content: var(--icon-warning-sm-hover);
163
146
  }
164
147
  }
165
148
 
166
149
  .toc ol li.alert-item.note a::before {
167
- // fg-color
168
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='hsl(20deg 8% 8%)' stroke-width='2'/><line x1='12' y1='10' x2='12' y2='16' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='7' x2='12' y2='7' stroke='hsl(20deg 8% 8%)' stroke-width='2' stroke-linecap='round'/></svg>");
169
- }
170
-
171
- @media (prefers-color-scheme: dark) {
172
- .toc ol li.alert-item.note a::before {
173
- // fg-color
174
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='hsl(20deg 20% 90%)' stroke-width='2'/><line x1='12' y1='10' x2='12' y2='16' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='7' x2='12' y2='7' stroke='hsl(20deg 20% 90%)' stroke-width='2' stroke-linecap='round'/></svg>");
175
- }
150
+ content: var(--icon-note-sm);
176
151
  }
177
152
 
178
153
  @media (hover: hover) {
179
154
  .toc ol li.alert-item.note:hover a::before,
180
155
  .toc ol li.alert-item.note a:hover::before {
181
- // fg2-color
182
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='hsl(20deg 6% 60%)' stroke-width='2'/><line x1='12' y1='10' x2='12' y2='16' stroke='hsl(20deg 6% 60%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='7' x2='12' y2='7' stroke='hsl(20deg 6% 60%)' stroke-width='2' stroke-linecap='round'/></svg>");
183
- }
184
- }
185
-
186
- @media (hover: hover) and (prefers-color-scheme: dark) {
187
- .toc ol li.alert-item.note:hover a::before,
188
- .toc ol li.alert-item.note a:hover::before {
189
- // fg2-color
190
- content: url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='20' height='20' viewBox='0 0 24 24'><circle cx='12' cy='12' r='10' fill='none' stroke='hsl(20deg 6% 55%)' stroke-width='2'/><line x1='12' y1='10' x2='12' y2='16' stroke='hsl(20deg 6% 55%)' stroke-width='2' stroke-linecap='round'/><line x1='12' y1='7' x2='12' y2='7' stroke='hsl(20deg 6% 55%)' stroke-width='2' stroke-linecap='round'/></svg>");
156
+ content: var(--icon-note-sm-hover);
191
157
  }
192
158
  }
193
159
 
package/src/util.ts CHANGED
@@ -1,9 +1,12 @@
1
- export function debounce(fn: Function, time: number) {
1
+ export function debounce<T extends (...args: unknown[]) => void>(
2
+ fn: T,
3
+ time: number,
4
+ ) {
2
5
  let timer: number;
3
- return (...args: any[]) => {
6
+ return (...args: Parameters<T>) => {
4
7
  window.clearTimeout(timer);
5
8
  timer = window.setTimeout(() => {
6
- fn.apply(null, args);
9
+ fn(...args);
7
10
  }, time);
8
11
  };
9
12
  }
@@ -31,7 +34,7 @@ export function applyBasePath(subPath: string): string {
31
34
  throw new Error('invalid internal path, must start with "/": ' + subPath);
32
35
  }
33
36
 
34
- let path = window.siteVariables.basePath || '/';
37
+ let path = __SITE_BASE_PATH__;
35
38
  if (path.endsWith('/')) {
36
39
  path = path.slice(0, -1);
37
40
  }
@@ -106,8 +109,8 @@ export function formatDuration(ms: number): string {
106
109
 
107
110
  if (absMs < 1000) {
108
111
  // 0.0000ms - 999.99ms
109
- let decimals = absMs < 10 ? 4 : absMs < 100 ? 3 : 2;
110
- let val = roundTo(absMs, decimals);
112
+ const decimals = absMs < 10 ? 4 : absMs < 100 ? 3 : 2;
113
+ const val = roundTo(absMs, decimals);
111
114
  if (val >= 1000) {
112
115
  return sign + formatSecondsFromMs(absMs);
113
116
  }