@abreen/tada 1.17.1 → 1.18.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.
- package/README.md +38 -7
- package/assets/material-symbols/chevron_right_24px.svg +1 -0
- package/bin/tada.ts +16 -7
- package/bin/validators.ts +33 -0
- package/build/branding.ts +41 -0
- package/build/build-manifest.ts +9 -4
- package/build/{watch/compiler-types.d.ts → build-types.d.ts} +8 -5
- package/build/build-validation.ts +176 -0
- package/build/bundle.ts +75 -65
- package/build/config-loader.ts +3 -3
- package/build/custom-fonts.ts +8 -5
- package/build/generate-favicon.ts +7 -6
- package/build/generate-fonts.ts +8 -15
- package/build/generate-katex-assets.ts +19 -17
- package/build/generate-web-app-manifest.ts +3 -11
- package/build/lodash-template.ts +14 -0
- package/build/material-symbols.ts +7 -4
- package/build/output-publication.ts +238 -0
- package/build/pagefind.ts +49 -21
- package/build/pdf-text.ts +41 -1
- package/build/pipeline.ts +95 -101
- package/build/site-assets.ts +46 -0
- package/build/site-build.ts +267 -0
- package/build/source-model.ts +223 -244
- package/build/source-records.ts +69 -81
- package/build/template-globals.ts +3 -0
- package/build/templates.ts +5 -2
- package/build/toc-plugin.ts +21 -21
- package/build/types.d.ts +44 -38
- package/build/util.ts +0 -4
- package/build/utils/code.ts +38 -101
- package/build/utils/final-html.ts +171 -47
- package/build/utils/literate-java.ts +11 -7
- package/build/utils/markdown-partials.ts +4 -3
- package/build/utils/markdown.ts +6 -17
- package/build/utils/paths.ts +3 -0
- package/build/utils/plain-text.ts +18 -0
- package/build/utils/render.ts +227 -165
- package/build/utils/shiki-highlighter.ts +11 -0
- package/build/utils/source-template.ts +2 -2
- package/build/utils/trace-core.ts +8 -83
- package/build/utils/trace.ts +38 -95
- package/build/validate-config-links.ts +60 -20
- package/build/watch/build-incremental.ts +46 -103
- package/build/watch/compiler.ts +158 -37
- package/build/watch/engine.ts +207 -176
- package/build/watch/index.ts +9 -2
- package/build/watch/planner.ts +88 -144
- package/build/watch/runtime.ts +21 -34
- package/build/watch/types.d.ts +32 -64
- package/init/content/labs/00/VowelCounter.java.md +5 -2
- package/init/content/labs/00/index.md +3 -2
- package/init/content/labs/01/index.md +3 -2
- package/init/content/labs/02/index.md +3 -2
- package/init/content/lectures/01/index.md +3 -2
- package/init/content/lectures/02/index.md +3 -2
- package/package.json +4 -4
- package/schema/site.schema.json +18 -2
- package/src/_content.scss +463 -0
- package/src/_fonts.scss +90 -0
- package/src/_layout.scss +50 -35
- package/src/{material-symbols.scss → _material-symbols.scss} +7 -0
- package/src/appearance-picker/{style.scss → _index.scss} +1 -1
- package/src/code/{style.scss → _index.scss} +61 -0
- package/src/header/{_base.scss → _index.scss} +98 -6
- package/src/index.ts +1 -17
- package/src/navigate/{style.scss → _index.scss} +29 -3
- package/src/navigate/breadcrumbs.ts +129 -0
- package/src/navigate/eligible.ts +0 -40
- package/src/navigate/index.ts +38 -4
- package/src/navigate/lifecycle.ts +19 -2
- package/src/navigate/runtime.ts +57 -22
- package/src/page-update/index.ts +33 -20
- package/src/print/{style.scss → _index.scss} +3 -1
- package/src/search/index.ts +7 -0
- package/src/slides/{style.scss → _index.scss} +5 -0
- package/src/style.scss +24 -536
- package/src/toc/index.ts +2 -2
- package/templates/_author.html +2 -2
- package/templates/_download.html +1 -1
- package/templates/_footer.html +1 -1
- package/templates/_heading.html +17 -4
- package/templates/_nav.html +2 -2
- package/templates/_page-bottom.html +6 -0
- package/templates/_top.html +18 -14
- package/templates/code.html +22 -21
- package/templates/default.html +12 -11
- package/templates/literate.html +6 -5
- package/assets/material-symbols/south_east_20px.svg +0 -1
- package/build/copy.ts +0 -82
- package/build/generate-content-assets.ts +0 -121
- package/build/utils/content-files.ts +0 -170
- package/build/watch/assets.ts +0 -103
- package/build/watch/build-full.ts +0 -97
- package/build/watch/build-helpers.ts +0 -66
- package/build/watch/build-result.ts +0 -19
- package/build/watch/fs-commit.ts +0 -218
- package/build/watch/mutations.ts +0 -73
- package/build/watch/snapshot.ts +0 -201
- package/build/watch/validation.ts +0 -57
- package/src/code.scss +0 -60
- package/src/critical.scss +0 -5
- package/src/header/style.scss +0 -91
- /package/src/{literate.scss → _literate.scss} +0 -0
- /package/src/anchor/{style.scss → _index.scss} +0 -0
- /package/src/page-update/{style.scss → _index.scss} +0 -0
- /package/src/question/{style.scss → _index.scss} +0 -0
- /package/src/search/{style.scss → _index.scss} +0 -0
- /package/src/timezone/{style.scss → _index.scss} +0 -0
- /package/src/toc/{style.scss → _index.scss} +0 -0
- /package/src/trace/{style.scss → _index.scss} +0 -0
package/src/navigate/runtime.ts
CHANGED
|
@@ -1,11 +1,26 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { getResponseValidators, type ResponseValidators } from '../validators';
|
|
2
|
+
import {
|
|
3
|
+
mountAppearancePickerForPage,
|
|
4
|
+
mountPerPageComponents,
|
|
5
|
+
teardownPerPageComponents,
|
|
6
|
+
} from './lifecycle';
|
|
2
7
|
import { globals } from '../globals';
|
|
8
|
+
import {
|
|
9
|
+
cleanupBreadcrumbTransitionNames,
|
|
10
|
+
getBreadcrumbItems,
|
|
11
|
+
prepareBreadcrumbTransitionStyles,
|
|
12
|
+
setBreadcrumbTransitionNames,
|
|
13
|
+
sharedBreadcrumbCount,
|
|
14
|
+
} from './breadcrumbs';
|
|
3
15
|
|
|
4
16
|
export const NAVIGATION_EVENT = 'tada:navigation';
|
|
5
17
|
|
|
6
18
|
let currentAbortController: AbortController | null = null;
|
|
7
19
|
let historyIndex = 0;
|
|
8
20
|
let currentPath = '';
|
|
21
|
+
// Unlike the browser URL (which already changes on popstate), this tracks the
|
|
22
|
+
// page whose content is currently displayed, for relative breadcrumb identity.
|
|
23
|
+
let renderedPageUrl = '';
|
|
9
24
|
|
|
10
25
|
const scrollByIndex = new Map<number, number>();
|
|
11
26
|
const scrollByLocation = new Map<string, number>();
|
|
@@ -93,12 +108,22 @@ export function closeHeaderDetails(document: Document): void {
|
|
|
93
108
|
}
|
|
94
109
|
}
|
|
95
110
|
|
|
96
|
-
|
|
111
|
+
export interface NavigationEventDetail {
|
|
112
|
+
path: string;
|
|
113
|
+
validators: ResponseValidators;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
function dispatchNavigationEvent(
|
|
117
|
+
window: Window,
|
|
118
|
+
validators: ResponseValidators,
|
|
119
|
+
): void {
|
|
97
120
|
const CustomEventCtor = (
|
|
98
121
|
window as unknown as { CustomEvent: typeof CustomEvent }
|
|
99
122
|
).CustomEvent;
|
|
100
123
|
window.dispatchEvent(
|
|
101
|
-
new CustomEventCtor(NAVIGATION_EVENT, {
|
|
124
|
+
new CustomEventCtor(NAVIGATION_EVENT, {
|
|
125
|
+
detail: { path: currentPath, validators },
|
|
126
|
+
}),
|
|
102
127
|
);
|
|
103
128
|
}
|
|
104
129
|
|
|
@@ -109,9 +134,6 @@ function cleanupViewTransitionNames(document: Document): void {
|
|
|
109
134
|
const newInfo = document.querySelector(
|
|
110
135
|
'.title-and-info .info',
|
|
111
136
|
) as HTMLElement | null;
|
|
112
|
-
const newBreadcrumb = document.querySelector(
|
|
113
|
-
'.title-and-info a.breadcrumb',
|
|
114
|
-
) as HTMLElement | null;
|
|
115
137
|
|
|
116
138
|
if (newH1) {
|
|
117
139
|
newH1.style.viewTransitionName = '';
|
|
@@ -119,9 +141,7 @@ function cleanupViewTransitionNames(document: Document): void {
|
|
|
119
141
|
if (newInfo) {
|
|
120
142
|
newInfo.style.viewTransitionName = '';
|
|
121
143
|
}
|
|
122
|
-
|
|
123
|
-
newBreadcrumb.style.viewTransitionName = '';
|
|
124
|
-
}
|
|
144
|
+
cleanupBreadcrumbTransitionNames(document);
|
|
125
145
|
}
|
|
126
146
|
|
|
127
147
|
function getLocationKey(window: Window): string {
|
|
@@ -157,6 +177,7 @@ export function initNavigation(window: Window): void {
|
|
|
157
177
|
scrollByLocation.clear();
|
|
158
178
|
window.history.scrollRestoration = 'manual';
|
|
159
179
|
currentPath = window.location.pathname + window.location.search;
|
|
180
|
+
renderedPageUrl = window.location.href;
|
|
160
181
|
scrollByIndex.set(historyIndex, window.scrollY);
|
|
161
182
|
scrollByLocation.set(getLocationKey(window), window.scrollY);
|
|
162
183
|
}
|
|
@@ -288,7 +309,9 @@ export async function navigateToUrl(
|
|
|
288
309
|
teardownPerPageComponents();
|
|
289
310
|
swapContent(document, newDoc);
|
|
290
311
|
updateHead(document, newDoc);
|
|
312
|
+
mountAppearancePickerForPage(window);
|
|
291
313
|
currentPath = parsed.pathname + parsed.search;
|
|
314
|
+
renderedPageUrl = parsed.href;
|
|
292
315
|
|
|
293
316
|
if (pushHistory) {
|
|
294
317
|
historyIndex++;
|
|
@@ -320,6 +343,18 @@ export async function navigateToUrl(
|
|
|
320
343
|
!prefersReducedMotion(window) &&
|
|
321
344
|
typeof transitionDoc.startViewTransition === 'function'
|
|
322
345
|
) {
|
|
346
|
+
const oldBreadcrumbItems = getBreadcrumbItems(document, renderedPageUrl);
|
|
347
|
+
const newBreadcrumbItems = getBreadcrumbItems(newDoc, parsed.href);
|
|
348
|
+
const sharedCount = sharedBreadcrumbCount(
|
|
349
|
+
oldBreadcrumbItems,
|
|
350
|
+
newBreadcrumbItems,
|
|
351
|
+
);
|
|
352
|
+
prepareBreadcrumbTransitionStyles(
|
|
353
|
+
document,
|
|
354
|
+
oldBreadcrumbItems.length,
|
|
355
|
+
newBreadcrumbItems.length,
|
|
356
|
+
sharedCount,
|
|
357
|
+
);
|
|
323
358
|
const titleEl = document.querySelector('.title-and-info');
|
|
324
359
|
const headerHeight =
|
|
325
360
|
document.querySelector('header')?.getBoundingClientRect().height ?? 0;
|
|
@@ -329,18 +364,18 @@ export async function navigateToUrl(
|
|
|
329
364
|
if (titleVisible) {
|
|
330
365
|
const h1 = titleEl.querySelector('h1') as HTMLElement | null;
|
|
331
366
|
const info = titleEl.querySelector('.info') as HTMLElement | null;
|
|
332
|
-
const breadcrumb = titleEl.querySelector(
|
|
333
|
-
'a.breadcrumb',
|
|
334
|
-
) as HTMLElement | null;
|
|
335
367
|
if (h1) {
|
|
336
368
|
h1.style.viewTransitionName = 'page-title';
|
|
337
369
|
}
|
|
338
370
|
if (info) {
|
|
339
371
|
info.style.viewTransitionName = 'page-info';
|
|
340
372
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
373
|
+
setBreadcrumbTransitionNames(
|
|
374
|
+
document,
|
|
375
|
+
renderedPageUrl,
|
|
376
|
+
sharedCount,
|
|
377
|
+
'leave',
|
|
378
|
+
);
|
|
344
379
|
}
|
|
345
380
|
|
|
346
381
|
document.documentElement.classList.add(
|
|
@@ -362,18 +397,18 @@ export async function navigateToUrl(
|
|
|
362
397
|
if (newTitleVisible && newTitleEl) {
|
|
363
398
|
const h1 = newTitleEl.querySelector('h1') as HTMLElement | null;
|
|
364
399
|
const info = newTitleEl.querySelector('.info') as HTMLElement | null;
|
|
365
|
-
const breadcrumb = newTitleEl.querySelector(
|
|
366
|
-
'a.breadcrumb',
|
|
367
|
-
) as HTMLElement | null;
|
|
368
400
|
if (h1) {
|
|
369
401
|
h1.style.viewTransitionName = 'page-title';
|
|
370
402
|
}
|
|
371
403
|
if (info) {
|
|
372
404
|
info.style.viewTransitionName = 'page-info';
|
|
373
405
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
406
|
+
setBreadcrumbTransitionNames(
|
|
407
|
+
document,
|
|
408
|
+
renderedPageUrl,
|
|
409
|
+
sharedCount,
|
|
410
|
+
'enter',
|
|
411
|
+
);
|
|
377
412
|
}
|
|
378
413
|
});
|
|
379
414
|
|
|
@@ -396,7 +431,7 @@ export async function navigateToUrl(
|
|
|
396
431
|
}
|
|
397
432
|
|
|
398
433
|
currentAbortController = null;
|
|
399
|
-
dispatchNavigationEvent(window);
|
|
434
|
+
dispatchNavigationEvent(window, getResponseValidators(response));
|
|
400
435
|
}
|
|
401
436
|
|
|
402
437
|
export async function refreshCurrentPage(window: Window): Promise<void> {
|
package/src/page-update/index.ts
CHANGED
|
@@ -72,7 +72,9 @@ export function mountPageUpdate(
|
|
|
72
72
|
const { container, toast, reloadButton, dismissButton } =
|
|
73
73
|
createToast(document);
|
|
74
74
|
|
|
75
|
-
let currentPath = window.location.pathname;
|
|
75
|
+
let currentPath = window.location.pathname + window.location.search;
|
|
76
|
+
let navigationGeneration = 0;
|
|
77
|
+
let disposed = false;
|
|
76
78
|
let baseline = EMPTY_RESPONSE_VALIDATORS;
|
|
77
79
|
let dismissedValidatorKey: string | null = null;
|
|
78
80
|
let nextValidator: ResponseValidators | null = null;
|
|
@@ -98,7 +100,7 @@ export function mountPageUpdate(
|
|
|
98
100
|
|
|
99
101
|
function scheduleNextCheck() {
|
|
100
102
|
clearTimer();
|
|
101
|
-
if (globals.isDocumentHidden(document)) {
|
|
103
|
+
if (disposed || globals.isDocumentHidden(document)) {
|
|
102
104
|
return;
|
|
103
105
|
}
|
|
104
106
|
timer = window.setTimeout(() => {
|
|
@@ -145,11 +147,16 @@ export function mountPageUpdate(
|
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
const requestedPath = currentPath;
|
|
148
|
-
|
|
150
|
+
const requestedGeneration = navigationGeneration;
|
|
149
151
|
checkInFlight = true;
|
|
150
152
|
try {
|
|
151
153
|
const validators = await fetchValidators(requestedPath);
|
|
152
|
-
if (
|
|
154
|
+
if (
|
|
155
|
+
!validators ||
|
|
156
|
+
disposed ||
|
|
157
|
+
requestedGeneration !== navigationGeneration ||
|
|
158
|
+
requestedPath !== currentPath
|
|
159
|
+
) {
|
|
153
160
|
return;
|
|
154
161
|
}
|
|
155
162
|
|
|
@@ -175,30 +182,32 @@ export function mountPageUpdate(
|
|
|
175
182
|
// best-effort
|
|
176
183
|
} finally {
|
|
177
184
|
checkInFlight = false;
|
|
178
|
-
if (
|
|
185
|
+
if (
|
|
186
|
+
rerunAfterCurrentCheck &&
|
|
187
|
+
!disposed &&
|
|
188
|
+
!globals.isDocumentHidden(document)
|
|
189
|
+
) {
|
|
179
190
|
rerunAfterCurrentCheck = false;
|
|
180
|
-
|
|
181
|
-
} else {
|
|
191
|
+
void checkForUpdate();
|
|
192
|
+
} else if (requestedGeneration === navigationGeneration) {
|
|
182
193
|
scheduleNextCheck();
|
|
183
194
|
}
|
|
184
195
|
}
|
|
185
|
-
|
|
186
|
-
if (shouldRerun) {
|
|
187
|
-
void checkForUpdate();
|
|
188
|
-
}
|
|
189
196
|
}
|
|
190
197
|
|
|
191
|
-
function resetState(
|
|
192
|
-
|
|
193
|
-
|
|
198
|
+
function resetState(
|
|
199
|
+
validators: ResponseValidators = EMPTY_RESPONSE_VALIDATORS,
|
|
200
|
+
) {
|
|
201
|
+
navigationGeneration++;
|
|
202
|
+
rerunAfterCurrentCheck = false;
|
|
203
|
+
currentPath = window.location.pathname + window.location.search;
|
|
204
|
+
baseline = validators;
|
|
194
205
|
dismissedValidatorKey = null;
|
|
195
206
|
nextValidator = null;
|
|
196
|
-
hasBaseline =
|
|
207
|
+
hasBaseline = hasUsableResponseValidators(validators);
|
|
197
208
|
hideToast();
|
|
198
209
|
clearTimer();
|
|
199
|
-
|
|
200
|
-
void checkForUpdate();
|
|
201
|
-
}
|
|
210
|
+
scheduleNextCheck();
|
|
202
211
|
}
|
|
203
212
|
|
|
204
213
|
function handleVisibilityChange() {
|
|
@@ -216,13 +225,16 @@ export function mountPageUpdate(
|
|
|
216
225
|
void checkForUpdate();
|
|
217
226
|
}
|
|
218
227
|
|
|
219
|
-
function handleNavigation() {
|
|
228
|
+
function handleNavigation(event: Event) {
|
|
220
229
|
if (__IS_DEV__) {
|
|
221
230
|
console.log(
|
|
222
231
|
`[page-update] navigation path=${window.location.pathname} visibility=${document.visibilityState} focus=${document.hasFocus()}`,
|
|
223
232
|
);
|
|
224
233
|
}
|
|
225
|
-
resetState(
|
|
234
|
+
resetState(
|
|
235
|
+
(event as CustomEvent<{ validators?: ResponseValidators }>).detail
|
|
236
|
+
?.validators,
|
|
237
|
+
);
|
|
226
238
|
}
|
|
227
239
|
|
|
228
240
|
function handleDismiss() {
|
|
@@ -272,6 +284,7 @@ export function mountPageUpdate(
|
|
|
272
284
|
}
|
|
273
285
|
|
|
274
286
|
return () => {
|
|
287
|
+
disposed = true;
|
|
275
288
|
clearTimer();
|
|
276
289
|
document.removeEventListener('visibilitychange', handleVisibilityChange);
|
|
277
290
|
window.removeEventListener('focus', handleWindowFocus);
|
package/src/search/index.ts
CHANGED
|
@@ -141,6 +141,10 @@ function render(
|
|
|
141
141
|
a.id = `result-${i}`;
|
|
142
142
|
a.className = 'result';
|
|
143
143
|
a.href = result.url;
|
|
144
|
+
const isGeneratedPage = Boolean(result.template);
|
|
145
|
+
if (isGeneratedPage) {
|
|
146
|
+
a.setAttribute('data-tada-page', '');
|
|
147
|
+
}
|
|
144
148
|
a.tabIndex = 0;
|
|
145
149
|
|
|
146
150
|
const titleEl = doc.createElement('div');
|
|
@@ -177,6 +181,9 @@ function render(
|
|
|
177
181
|
for (const sub of subsToShow) {
|
|
178
182
|
const subA = doc.createElement('a');
|
|
179
183
|
subA.href = sub.url;
|
|
184
|
+
if (isGeneratedPage) {
|
|
185
|
+
subA.setAttribute('data-tada-page', '');
|
|
186
|
+
}
|
|
180
187
|
subA.className = 'sub-result';
|
|
181
188
|
|
|
182
189
|
const subTitle = doc.createElement('div');
|
|
@@ -93,6 +93,7 @@ body.is-presenting [data-slides-annotation-layer] {
|
|
|
93
93
|
body.is-presenting header,
|
|
94
94
|
body.is-presenting .title-and-info,
|
|
95
95
|
body.is-presenting nav.toc,
|
|
96
|
+
body.is-presenting .page-bottom,
|
|
96
97
|
body.is-presenting footer,
|
|
97
98
|
body.is-presenting .appearance-pickers,
|
|
98
99
|
body.is-presenting .slides-header,
|
|
@@ -177,3 +178,7 @@ body.is-presenting .slide:has(> .trace-widget) > .trace-widget > .trace-body {
|
|
|
177
178
|
height: 100%;
|
|
178
179
|
min-height: 0;
|
|
179
180
|
}
|
|
181
|
+
|
|
182
|
+
body.is-presenting > .container {
|
|
183
|
+
min-height: 0;
|
|
184
|
+
}
|