@abreen/tada 1.8.1 → 1.10.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 (79) hide show
  1. package/README.md +24 -34
  2. package/bin/tada.ts +1 -1
  3. package/bin/validators.ts +1 -1
  4. package/build/apply-base-path-plugin.ts +79 -17
  5. package/build/bundle.ts +9 -1
  6. package/build/content-watch.ts +3 -3
  7. package/build/copy.ts +30 -0
  8. package/build/generate-content-assets.ts +45 -59
  9. package/build/pagefind.ts +0 -7
  10. package/build/serve.ts +4 -0
  11. package/build/templates.ts +0 -2
  12. package/build/types.d.ts +19 -1
  13. package/build/util.ts +3 -0
  14. package/build/utils/content-files.ts +98 -0
  15. package/build/utils/include.ts +4 -0
  16. package/build/utils/python-runner/trace_runner.py +272 -0
  17. package/build/utils/render.ts +47 -15
  18. package/build/utils/source-template.ts +27 -0
  19. package/build/utils/trace-core.ts +203 -0
  20. package/build/utils/trace-java.ts +132 -0
  21. package/build/utils/trace-layout.ts +31 -3
  22. package/build/utils/trace-python.ts +26 -0
  23. package/build/utils/trace.ts +174 -294
  24. package/build/validate-internal-links-plugin.ts +16 -4
  25. package/build/watch/assets.ts +111 -0
  26. package/build/watch/build-full.ts +124 -0
  27. package/build/watch/build-incremental.ts +139 -0
  28. package/build/watch/compiler-types.d.ts +19 -0
  29. package/build/watch/compiler.ts +112 -0
  30. package/build/watch/index.ts +22 -0
  31. package/build/watch/mutations.ts +75 -0
  32. package/build/watch/planner.ts +230 -0
  33. package/build/watch/records.ts +190 -0
  34. package/build/watch/runtime.ts +143 -0
  35. package/build/watch/snapshot.ts +602 -0
  36. package/build/watch/validation.ts +36 -0
  37. package/build/watch-reload-client.ts +10 -5
  38. package/init/content/labs/01/index.md +6 -0
  39. package/init/content/labs/01/trace_demo.py +16 -0
  40. package/init/content/lectures/01/Rectangle.java +2 -0
  41. package/init/content/lectures/01/index.md +6 -0
  42. package/init/content/lectures/01/rectangle.py +5 -0
  43. package/package.json +42 -23
  44. package/python/command.ts +95 -0
  45. package/python/module.ts +18 -0
  46. package/src/_alerts.scss +11 -8
  47. package/src/_base.scss +25 -29
  48. package/src/_layout.scss +17 -14
  49. package/src/_mixins.scss +10 -9
  50. package/src/anchor/style.scss +4 -2
  51. package/src/code/index.ts +9 -2
  52. package/src/code/style.scss +14 -13
  53. package/src/code.scss +14 -13
  54. package/src/header/_base.scss +21 -24
  55. package/src/header/style.scss +16 -12
  56. package/src/index.ts +3 -0
  57. package/src/literate/style.scss +4 -4
  58. package/src/navigate/index.ts +43 -279
  59. package/src/navigate/lifecycle.ts +1 -1
  60. package/src/navigate/runtime.ts +341 -0
  61. package/src/page-update/README.md +4 -0
  62. package/src/page-update/index.ts +280 -0
  63. package/src/page-update/style.scss +53 -0
  64. package/src/print/style.scss +4 -4
  65. package/src/question/style.scss +10 -6
  66. package/src/search/index.ts +9 -12
  67. package/src/search/style.scss +44 -42
  68. package/src/style.scss +63 -58
  69. package/src/timezone/style.scss +5 -5
  70. package/src/toc/style.scss +17 -16
  71. package/src/trace/style.scss +27 -27
  72. package/src/validators.ts +45 -0
  73. package/templates/_footer.html +1 -1
  74. package/templates/_theme.scss +8 -19
  75. package/watch/engine.ts +296 -0
  76. package/watch/events.ts +10 -0
  77. package/watch/fs-commit.ts +102 -0
  78. package/watch/types.d.ts +103 -0
  79. package/build/watch.ts +0 -493
@@ -8,6 +8,12 @@ author: alex
8
8
 
9
9
  Here is a sample description of the topics covered at the first lecture.
10
10
 
11
+ The value of `vars.foobar` is <%= vars.foobar %>.
12
+
13
+ You can add any variables you want to the `site.dev.json` and `site.prod.json`
14
+ files under the `"vars"` property and access them using Lodash template syntax
15
+ from Markdown files, HTML files, and source code. (Lodash template subtitution
16
+ only works in source code files when `features.code` is `true`.)
11
17
 
12
18
  ## Slides
13
19
 
@@ -1,3 +1,8 @@
1
+ #
2
+ # rectangle.py
3
+ #
4
+ # Here's vars.foobar: <%= vars.foobar %>
5
+ #
1
6
  class Rectangle:
2
7
  """A rectangle with integer side lengths.
3
8
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abreen/tada",
3
- "version": "1.8.1",
3
+ "version": "1.10.1",
4
4
  "type": "module",
5
5
  "description": "A static site generator",
6
6
  "license": "MIT",
@@ -15,26 +15,37 @@
15
15
  "files": [
16
16
  "bin/",
17
17
  "build/",
18
+ "watch/",
18
19
  "src/",
19
20
  "templates/",
20
21
  "fonts/",
21
22
  "init/",
22
23
  "schema/",
23
24
  "types/",
25
+ "python/",
24
26
  "tsconfig.json",
25
- "!**/*.test.ts"
27
+ "!**/*.test.ts",
28
+ "!**/__pycache__",
29
+ "!**/__pycache__/**",
30
+ "!**/*.pyc"
26
31
  ],
27
32
  "scripts": {
28
- "prepare": "bunx husky && bun run scripts/check-deps.ts",
29
- "prepack": "bun run scripts/prepack.ts",
33
+ "prepare": "bunx husky",
34
+ "check-deps": "bun run scripts/check-deps.ts",
35
+ "init-example": "bun run bin/tada.ts init example --no-interactive",
36
+ "iew": "bun run scripts/init-example-watch.ts",
30
37
  "lint": "eslint src/ build/ bin/",
38
+ "lint:sass": "bun run scripts/lint-sass.ts",
31
39
  "typecheck": "tsc --noEmit",
40
+ "format": "prettier --write \"**/*.{ts,js,scss,json}\"",
41
+ "test:playwright": "bun run scripts/test.ts playwright",
32
42
  "test:functional": "bun run scripts/test.ts functional",
33
43
  "test:all": "bun run scripts/test.ts all",
34
44
  "test:coverage": "bun run scripts/test.ts coverage",
35
- "test:playwright": "bun run scripts/test.ts playwright",
36
- "init-example": "bun run bin/tada.ts init example --no-interactive",
37
- "iew": "if [ -d example ]; then cd example; else bun run init-example && cd example; fi && ../bin/tada.ts watch"
45
+ "setup:python": "bun run scripts/setup-python.ts",
46
+ "lint:python": "bun run scripts/python-module.ts ruff check functional_tests/",
47
+ "fix:python": "bun run scripts/python-module.ts ruff check --fix functional_tests/",
48
+ "format:python": "bun run fix:python && bun run scripts/python-module.ts ruff format functional_tests/"
38
49
  },
39
50
  "engines": {
40
51
  "bun": ">=1.0.0"
@@ -46,8 +57,8 @@
46
57
  ],
47
58
  "dependencies": {
48
59
  "@vscode/markdown-it-katex": "^1.1.2",
49
- "ajv": "^8.17.1",
50
- "chokidar": "^4.0.0",
60
+ "ajv": "^8.18.0",
61
+ "chokidar": "^4.0.3",
51
62
  "culori": "^4.0.2",
52
63
  "d3-flextree": "^2.1.2",
53
64
  "d3-hierarchy": "^3.1.2",
@@ -55,36 +66,40 @@
55
66
  "front-matter": "^4.0.2",
56
67
  "java-parser": "^3.0.1",
57
68
  "jsdom": "^26.1.0",
58
- "katex": "^0.16.40",
59
- "lodash": "^4.17.21",
60
- "markdown-it": "^14.1.0",
69
+ "katex": "^0.16.45",
70
+ "lodash": "^4.18.1",
71
+ "markdown-it": "^14.1.1",
61
72
  "markdown-it-anchor": "^9.2.0",
62
73
  "markdown-it-container": "^4.0.0",
63
74
  "markdown-it-deflist": "^3.0.0",
64
75
  "markdown-it-footnote": "^4.0.0",
65
- "pagefind": "^1.4.0",
76
+ "pagefind": "^1.5.2",
66
77
  "png-to-ico": "^3.0.1",
67
78
  "quote-quote": "^1.2.0",
68
- "sass": "^1.91.0",
79
+ "sass": "^1.99.0",
69
80
  "sharp": "^0.34.5",
70
- "shiki": "^4.0.1",
81
+ "shiki": "^4.0.2",
71
82
  "string-strip-html": "^8.5.0",
72
- "ws": "^8.18.0"
83
+ "ws": "^8.20.0"
73
84
  },
74
85
  "lint-staged": {
75
86
  "*.{ts,js}": "prettier --write",
76
87
  "*.scss": "prettier --write",
77
- "*.json": "prettier --write"
88
+ "*.json": "prettier --write",
89
+ "functional_tests/**/*.py": [
90
+ "bun run scripts/python-module.ts ruff check --fix",
91
+ "bun run scripts/python-module.ts ruff format"
92
+ ]
78
93
  },
79
94
  "devDependencies": {
80
95
  "@eslint/js": "^10.0.1",
81
96
  "@playwright/test": "^1.59.1",
82
97
  "@saintedlama/lcov-parse": "^1.0.1",
83
- "@types/bun": "^1.3.10",
98
+ "@types/bun": "^1.3.12",
84
99
  "@types/culori": "^4.0.1",
85
100
  "@types/d3-flextree": "^2.1.4",
86
101
  "@types/d3-hierarchy": "^3.1.7",
87
- "@types/fontkit": "^2.0.8",
102
+ "@types/fontkit": "^2.0.9",
88
103
  "@types/istanbul-lib-coverage": "^2.0.6",
89
104
  "@types/istanbul-lib-instrument": "^1.7.8",
90
105
  "@types/istanbul-lib-report": "^3.0.3",
@@ -92,16 +107,20 @@
92
107
  "@types/lodash": "^4.17.24",
93
108
  "@types/markdown-it-container": "^4.0.0",
94
109
  "@types/ws": "^8.18.1",
95
- "eslint": "^10.0.3",
110
+ "eslint": "^10.2.1",
96
111
  "husky": "^9.1.7",
97
112
  "istanbul-lib-coverage": "^3.2.2",
98
113
  "istanbul-lib-instrument": "^6.0.3",
99
114
  "istanbul-lib-report": "^3.0.1",
100
115
  "istanbul-reports": "^3.2.0",
101
116
  "lint-staged": "^16.4.0",
102
- "prettier": "^3.6.2",
117
+ "postcss-scss": "^4.0.9",
118
+ "prettier": "^3.8.3",
103
119
  "prettier-plugin-curly": "^0.4.1",
104
- "typescript": "^5.4.5",
105
- "typescript-eslint": "^8.57.1"
120
+ "stylelint": "^17.8.0",
121
+ "stylelint-config-recess-order": "^7.7.0",
122
+ "stylelint-config-standard-scss": "^17.0.0",
123
+ "typescript": "^5.9.3",
124
+ "typescript-eslint": "^8.58.2"
106
125
  }
107
126
  }
@@ -0,0 +1,95 @@
1
+ import {
2
+ execFileSync,
3
+ spawnSync,
4
+ type ExecFileSyncOptionsWithStringEncoding,
5
+ type SpawnSyncOptions,
6
+ } from 'child_process';
7
+
8
+ export interface PythonCommand {
9
+ shell: 'direct' | 'powershell';
10
+ command: 'python' | 'python3';
11
+ }
12
+
13
+ const WINDOWS_PYTHON_CANDIDATES = ['python', 'python3'] as const;
14
+
15
+ function psQuote(arg: string): string {
16
+ return `'${arg.replaceAll("'", "''")}'`;
17
+ }
18
+
19
+ function buildPowerShellArgs(
20
+ command: PythonCommand['command'],
21
+ args: string[],
22
+ ): string[] {
23
+ return [
24
+ '-NoProfile',
25
+ '-NonInteractive',
26
+ '-Command',
27
+ [command, ...args.map(psQuote)].join(' '),
28
+ ];
29
+ }
30
+
31
+ function commandExists(
32
+ command: string,
33
+ args: string[] = ['--version'],
34
+ ): boolean {
35
+ return spawnSync(command, args, { stdio: 'ignore' }).status === 0;
36
+ }
37
+
38
+ export function resolvePythonCommand(): PythonCommand | null {
39
+ if (process.platform === 'win32') {
40
+ for (const command of WINDOWS_PYTHON_CANDIDATES) {
41
+ if (commandExists(command)) {
42
+ return { shell: 'direct', command };
43
+ }
44
+ }
45
+
46
+ for (const command of WINDOWS_PYTHON_CANDIDATES) {
47
+ if (
48
+ commandExists(
49
+ 'powershell.exe',
50
+ buildPowerShellArgs(command, ['--version']),
51
+ )
52
+ ) {
53
+ return { shell: 'powershell', command };
54
+ }
55
+ }
56
+
57
+ return null;
58
+ }
59
+
60
+ return commandExists('python3')
61
+ ? { shell: 'direct', command: 'python3' }
62
+ : null;
63
+ }
64
+
65
+ export function execFileSyncPython(
66
+ args: string[],
67
+ options: ExecFileSyncOptionsWithStringEncoding,
68
+ python: PythonCommand,
69
+ ): string {
70
+ if (python.shell === 'direct') {
71
+ return execFileSync(python.command, args, options);
72
+ }
73
+
74
+ return execFileSync(
75
+ 'powershell.exe',
76
+ buildPowerShellArgs(python.command, args),
77
+ options,
78
+ );
79
+ }
80
+
81
+ export function spawnSyncPython(
82
+ args: string[],
83
+ options: SpawnSyncOptions,
84
+ python: PythonCommand,
85
+ ) {
86
+ if (python.shell === 'direct') {
87
+ return spawnSync(python.command, args, options);
88
+ }
89
+
90
+ return spawnSync(
91
+ 'powershell.exe',
92
+ buildPowerShellArgs(python.command, args),
93
+ options,
94
+ );
95
+ }
@@ -0,0 +1,18 @@
1
+ import { resolvePythonCommand, spawnSyncPython } from './command';
2
+
3
+ export function runPythonModuleSync(
4
+ moduleName: string,
5
+ args: string[],
6
+ options: { env?: NodeJS.ProcessEnv; stdio?: 'inherit' | 'ignore' } = {},
7
+ ): number {
8
+ const pythonCommand = resolvePythonCommand();
9
+ if (!pythonCommand) {
10
+ console.error(`Error: Python is required to run the ${moduleName} module.`);
11
+ return 1;
12
+ }
13
+
14
+ return (
15
+ spawnSyncPython(['-m', moduleName, ...args], options, pythonCommand)
16
+ .status ?? 1
17
+ );
18
+ }
package/src/_alerts.scss CHANGED
@@ -1,9 +1,9 @@
1
1
  @use 'mixins' as *;
2
2
 
3
3
  .alert {
4
- border: 2px solid var(--bg2-color);
5
4
  position: relative;
6
5
  margin: 1rem 0;
6
+ border: 2px solid var(--bg2-color);
7
7
  }
8
8
 
9
9
  .alert.warning {
@@ -29,8 +29,8 @@
29
29
 
30
30
  tt,
31
31
  code {
32
- background: inherit;
33
32
  padding: inherit;
33
+ background: inherit;
34
34
  }
35
35
 
36
36
  time[datetime].is-modified {
@@ -40,6 +40,7 @@
40
40
 
41
41
  a {
42
42
  @include link-underline;
43
+
43
44
  color: var(--fg-color);
44
45
 
45
46
  &:hover {
@@ -65,12 +66,12 @@
65
66
  }
66
67
 
67
68
  .alert .title::before {
68
- content: '';
69
- left: 8px;
70
- top: 8px;
71
69
  position: absolute;
70
+ top: 8px;
71
+ left: 8px;
72
72
  width: 32px;
73
73
  height: 32px;
74
+ content: '';
74
75
  }
75
76
 
76
77
  .alert.warning .title::before {
@@ -79,9 +80,10 @@
79
80
 
80
81
  i.warning {
81
82
  @include contained-mask(var(--icon-warning));
83
+
82
84
  display: inline-block;
83
- height: 1em;
84
85
  width: 1em;
86
+ height: 1em;
85
87
  vertical-align: sub;
86
88
  }
87
89
 
@@ -90,10 +92,11 @@ i.warning {
90
92
  }
91
93
 
92
94
  .alert .title {
93
- font-weight: 700;
94
- @include user-select(none);
95
95
  padding-left: 48px;
96
96
  margin: 0;
97
+ font-weight: 700;
98
+
99
+ @include user-select(none);
97
100
  }
98
101
 
99
102
  .alert > p:last-child {
package/src/_base.scss CHANGED
@@ -2,16 +2,13 @@
2
2
 
3
3
  :root {
4
4
  --box-border-width: 5px;
5
-
6
5
  --gap: 12px;
7
6
  --border-radius: 12px;
8
7
  --control-border-width: 2px;
9
8
  --label-border-width: 2px;
10
-
11
9
  --table-padding: 12px;
12
10
  --details-padding: 12px;
13
11
  --section-padding: 64px;
14
-
15
12
  --main-width: 900px;
16
13
  }
17
14
 
@@ -22,9 +19,9 @@ h4,
22
19
  h5,
23
20
  h6 {
24
21
  font-family: var(--heading-font);
22
+ line-height: 1.3;
25
23
  -webkit-break-after: avoid;
26
24
  break-after: avoid;
27
- line-height: 1.3;
28
25
  }
29
26
 
30
27
  h1 {
@@ -33,13 +30,9 @@ h1 {
33
30
  }
34
31
 
35
32
  body {
36
- color: var(--fg-color);
37
- background-color: var(--bg-color);
38
-
39
33
  font-family: var(--font);
40
34
  font-size: var(--font-size);
41
35
  font-weight: var(--font-weight);
42
- line-height: var(--line-height);
43
36
 
44
37
  /*
45
38
  * Enable Inter's features:
@@ -51,12 +44,13 @@ body {
51
44
  * cv10 - capital G with spur (style)
52
45
  */
53
46
  font-feature-settings: 'liga', 'calt', 'ss03', 'cv01', 'cv05', 'cv10';
47
+ line-height: var(--line-height);
48
+ color: var(--fg-color);
49
+ background-color: var(--bg-color);
54
50
 
55
51
  @media (prefers-color-scheme: dark) {
56
- & {
57
- text-rendering: optimizeLegibility;
58
- -webkit-font-smoothing: antialiased;
59
- }
52
+ text-rendering: optimizelegibility;
53
+ -webkit-font-smoothing: antialiased;
60
54
  }
61
55
  }
62
56
 
@@ -72,6 +66,7 @@ a {
72
66
  @media (hover: hover) {
73
67
  &:hover {
74
68
  color: var(--link-color-hover);
69
+
75
70
  @include link-underline;
76
71
  }
77
72
  }
@@ -89,26 +84,25 @@ code {
89
84
 
90
85
  tt,
91
86
  code {
87
+ padding: var(--mono-padding);
92
88
  font-size: var(--mono-font-size);
89
+ overflow-wrap: anywhere;
93
90
  background: var(--bg2-color);
94
91
  border-radius: var(--mono-border-radius);
95
- padding: var(--mono-padding);
96
- overflow-wrap: anywhere;
97
92
  }
98
93
 
99
94
  pre {
100
- background: var(--bg2-color);
101
- border-radius: var(--mono-border-radius);
95
+ padding: var(--gap);
96
+ overflow: auto hidden;
97
+ overscroll-behavior-x: none;
102
98
  font-size: var(--mono-font-size);
103
99
  line-height: var(--mono-line-height);
104
- overflow-x: auto;
105
- overflow-y: hidden;
106
- overscroll-behavior-x: none;
107
- padding: var(--gap);
100
+ background: var(--bg2-color);
101
+ border-radius: var(--mono-border-radius);
108
102
 
109
103
  code {
110
- font-size: inherit;
111
104
  padding: 0;
105
+ font-size: inherit;
112
106
  }
113
107
  }
114
108
 
@@ -121,9 +115,10 @@ details .content > *:last-child {
121
115
  }
122
116
 
123
117
  details summary {
118
+ padding: var(--details-padding);
124
119
  cursor: pointer;
120
+
125
121
  @include user-select(none);
126
- padding: var(--details-padding);
127
122
  }
128
123
 
129
124
  main details summary:focus {
@@ -143,6 +138,7 @@ details .content {
143
138
  @media (hover: hover) {
144
139
  details summary:hover {
145
140
  color: var(--fg2-color);
141
+
146
142
  @include link-underline;
147
143
  }
148
144
  }
@@ -153,34 +149,34 @@ details summary:active {
153
149
 
154
150
  main details {
155
151
  margin-bottom: 1rem;
156
- border-radius: var(--border-radius);
157
152
  border: 2px solid var(--fg-color);
153
+ border-radius: var(--border-radius);
158
154
  }
159
155
 
160
156
  input[type='text'],
161
157
  input[type='search'] {
158
+ padding: 4px;
162
159
  font-family: var(--font);
163
- background: var(--bg-color);
160
+ font-size: 12pt;
164
161
  color: var(--fg-color);
162
+ background: var(--bg-color);
165
163
  border: var(--control-border-width) solid var(--fg2-color);
166
164
  border-radius: var(--border-radius);
167
- font-size: 12pt;
168
- padding: 4px 4px;
169
165
  }
170
166
 
171
167
  input[type='search'] {
168
+ min-width: 0;
169
+ padding-left: 2rem;
172
170
  background-color: var(--bg-color);
173
171
  background-image: var(--icon-search);
174
172
  background-repeat: no-repeat;
175
173
  background-position: left 6px center;
176
174
  background-size: 16px 16px;
177
- padding-left: 2rem;
178
175
  border-radius: 18px;
179
- min-width: 0;
180
176
 
181
177
  &:disabled {
182
- opacity: 0.4;
183
178
  cursor: not-allowed;
179
+ opacity: 0.4;
184
180
  }
185
181
  }
186
182
 
package/src/_layout.scss CHANGED
@@ -5,15 +5,15 @@
5
5
  }
6
6
 
7
7
  html {
8
- margin: 0;
9
8
  padding: 0;
9
+ margin: 0;
10
10
  overflow-y: auto;
11
11
  scroll-padding-top: calc(var(--header-collapsed-height) + var(--gap));
12
12
  }
13
13
 
14
14
  body {
15
- margin: 0;
16
15
  padding: 0;
16
+ margin: 0;
17
17
  }
18
18
 
19
19
  body > .container {
@@ -74,8 +74,8 @@ body.literate main table {
74
74
 
75
75
  body.default.toc-is-active nav.toc,
76
76
  body.literate.toc-is-active nav.toc {
77
- background: var(--bg2-color);
78
77
  padding: var(--gap);
78
+ background: var(--bg2-color);
79
79
  }
80
80
 
81
81
  body.code.toc-is-active nav.toc {
@@ -107,21 +107,21 @@ body.literate main table {
107
107
  }
108
108
 
109
109
  .toc-is-active .main-content > .body {
110
- order: 1;
111
110
  flex: 1;
111
+ order: 1;
112
112
  min-width: 0;
113
113
  }
114
114
 
115
115
  body.toc-is-active nav.toc {
116
+ position: sticky;
117
+ top: var(--header-collapsed-height);
116
118
  box-sizing: border-box;
117
- width: var(--toc-width);
118
119
  flex-shrink: 0;
119
120
  align-self: flex-start;
120
- position: sticky;
121
- top: var(--header-collapsed-height);
121
+ width: var(--toc-width);
122
122
  height: calc(100vh - var(--header-collapsed-height));
123
- overflow-y: auto;
124
123
  margin-bottom: 0;
124
+ overflow-y: auto;
125
125
  }
126
126
 
127
127
  body.code.toc-is-active nav.toc {
@@ -130,7 +130,7 @@ body.literate main table {
130
130
  }
131
131
  }
132
132
 
133
- @media (min-width: 1300px) {
133
+ @media (width >= 1300px) {
134
134
  .toc-is-active .main-content {
135
135
  max-width: calc(var(--toc-width) + var(--gap) + 960px);
136
136
  margin: 0 auto;
@@ -139,11 +139,12 @@ body.literate main table {
139
139
 
140
140
  .info {
141
141
  @include user-select(none);
142
+
142
143
  display: grid;
143
144
  grid-template-columns: 1fr auto;
144
145
  align-items: baseline;
145
- color: var(--fg2-color);
146
146
  font-size: var(--font-size-smaller);
147
+ color: var(--fg2-color);
147
148
 
148
149
  @media (width < 450px) {
149
150
  grid-template-columns: 1fr;
@@ -186,8 +187,8 @@ body.literate main table {
186
187
  .avatar {
187
188
  width: 24px;
188
189
  height: 24px;
189
- vertical-align: middle;
190
190
  margin-left: 4px;
191
+ vertical-align: middle;
191
192
  border: 1px solid transparent;
192
193
  }
193
194
  }
@@ -201,9 +202,10 @@ body.literate main table {
201
202
 
202
203
  footer {
203
204
  @include user-select(none);
204
- text-align: center;
205
+
205
206
  padding: 2rem 0 1rem;
206
207
  color: var(--fg2-color);
208
+ text-align: center;
207
209
 
208
210
  a {
209
211
  color: var(--fg2-color);
@@ -220,12 +222,13 @@ footer {
220
222
  }
221
223
 
222
224
  &::after {
223
- content: '';
224
225
  display: inline-block;
225
226
  width: 1.5em;
226
227
  height: 1.5em;
227
- vertical-align: middle;
228
228
  margin-left: 0.2em;
229
+ vertical-align: middle;
230
+ content: '';
231
+
229
232
  @include contained-mask(var(--icon-tada));
230
233
  }
231
234
  }
package/src/_mixins.scss CHANGED
@@ -5,8 +5,8 @@
5
5
 
6
6
  @mixin link-underline {
7
7
  text-decoration-line: underline;
8
- text-decoration-color: currentColor;
9
8
  text-decoration-thickness: 1px;
9
+ text-decoration-color: currentcolor;
10
10
  text-underline-offset: 0.11rem;
11
11
  }
12
12
 
@@ -17,6 +17,7 @@
17
17
  @media (hover: hover) {
18
18
  &:hover {
19
19
  color: var(--fg2-color);
20
+
20
21
  @include link-underline;
21
22
  }
22
23
  }
@@ -27,23 +28,23 @@
27
28
  }
28
29
 
29
30
  @mixin contained-icon {
30
- background-size: contain;
31
31
  background-repeat: no-repeat;
32
32
  background-position: center center;
33
+ background-size: contain;
33
34
  }
34
35
 
35
36
  @mixin contained-mask($url) {
37
+ // The icon's visible fill is the background color, which browsers strip
38
+ // when printing by default. Preserve it so masked icons remain visible.
39
+ -webkit-print-color-adjust: exact;
40
+ print-color-adjust: exact;
41
+ background-color: currentcolor;
36
42
  -webkit-mask-image: $url;
37
43
  mask-image: $url;
38
- -webkit-mask-size: contain;
39
- mask-size: contain;
40
44
  -webkit-mask-repeat: no-repeat;
41
45
  mask-repeat: no-repeat;
42
46
  -webkit-mask-position: center center;
43
47
  mask-position: center center;
44
- background-color: currentColor;
45
- // The icon's visible fill is the background color, which browsers strip
46
- // when printing by default. Preserve it so masked icons remain visible.
47
- -webkit-print-color-adjust: exact;
48
- print-color-adjust: exact;
48
+ -webkit-mask-size: contain;
49
+ mask-size: contain;
49
50
  }
@@ -3,17 +3,19 @@
3
3
  a.heading-anchor {
4
4
  position: relative;
5
5
  display: inline-block;
6
+
6
7
  @include subdued-link;
7
8
  }
8
9
 
9
10
  a.heading-anchor::after {
10
- content: '';
11
11
  display: inline-block;
12
- height: 1em;
13
12
  width: 1em;
13
+ height: 1em;
14
14
  margin-left: 4px;
15
15
  vertical-align: middle;
16
+ content: '';
16
17
  opacity: 0;
18
+
17
19
  @include contained-mask(var(--icon-anchor));
18
20
  }
19
21