@abreen/tada 1.16.5 → 1.16.7
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 +8 -0
- package/bin/tada.ts +2 -2
- package/bin/validators.ts +2 -2
- package/build/site-variables.ts +1 -1
- package/build/types.d.ts +2 -0
- package/build/utils/render.ts +14 -0
- package/package.json +1 -1
- package/schema/site.schema.json +10 -3
- package/src/_alerts.scss +7 -0
- package/src/navigate/style.scss +17 -0
- package/src/search/index.ts +1 -0
- package/templates/_appearance-picker.html +2 -0
- package/templates/_top.html +5 -1
package/README.md
CHANGED
|
@@ -216,6 +216,11 @@ Example site configuration YAML file:
|
|
|
216
216
|
```yaml
|
|
217
217
|
title: Intro to Computer Science
|
|
218
218
|
titlePostfix: " - CS 0"
|
|
219
|
+
banner: |
|
|
220
|
+
The semester is now closed. Final grades will become available on
|
|
221
|
+
[Gradescope](https://example.org/course/12345) on December 30.
|
|
222
|
+
|
|
223
|
+
This site is an archive. This is how the site appeared on December 27, 2020.
|
|
219
224
|
symbol: CS 0
|
|
220
225
|
themeColor: hsl(351 70% 40%)
|
|
221
226
|
tintAmount: 0
|
|
@@ -238,6 +243,7 @@ fontOverrides:
|
|
|
238
243
|
features:
|
|
239
244
|
search: true
|
|
240
245
|
favicon: true
|
|
246
|
+
pickers: true
|
|
241
247
|
base: https://example.edu
|
|
242
248
|
basePath: /cs0
|
|
243
249
|
internalDomains:
|
|
@@ -257,6 +263,7 @@ vars:
|
|
|
257
263
|
|-------|-------------|
|
|
258
264
|
| `title` | Title for the whole site (also used to derive `titlePostfix`) |
|
|
259
265
|
| `titlePostfix` | *Optional*, the string to append to each page's `title` |
|
|
266
|
+
| `banner` | *Optional*, Markdown rendered in a bordered box above every page |
|
|
260
267
|
| `symbol` | Text (1-5 chars) displayed in header (also used as the favicon symbol) |
|
|
261
268
|
| `themeColor` | Theme color for the site (e.g., `"tomato"`, `"#c04040"`, `"hsl(195 70% 40%)"`) |
|
|
262
269
|
| `tintHue` | *Optional*, hue (0-360) for background and foreground tinting (default `20`) |
|
|
@@ -268,6 +275,7 @@ vars:
|
|
|
268
275
|
| `features.search` | Enable search UI and Pagefind index generation |
|
|
269
276
|
| `features.favicon` | Enable automatically generated favicons |
|
|
270
277
|
| `features.footer` | Show the Tada footer at the bottom of every page |
|
|
278
|
+
| `features.pickers` | Show the font and contrast pickers at the bottom of every page (default `true`) |
|
|
271
279
|
| `base` | Full base URL of the deployed site, used for metadata and URL generation |
|
|
272
280
|
| `basePath` | URL prefix for deployment under a subpath (e.g., `"/cs101"`), use `"/"` at root |
|
|
273
281
|
| `internalDomains` | Domain names treated as internal by link processing (not marked external) |
|
package/bin/tada.ts
CHANGED
|
@@ -340,7 +340,7 @@ async function initCommand(args: string[]): Promise<void> {
|
|
|
340
340
|
base: 'http://localhost:8080',
|
|
341
341
|
basePath: '/',
|
|
342
342
|
internalDomains: ['localhost'],
|
|
343
|
-
features: { search: true, favicon: false, footer: true },
|
|
343
|
+
features: { search: true, favicon: false, footer: true, pickers: true },
|
|
344
344
|
extensionToShikiLanguage: bare ? {} : { java: 'java', py: 'python' },
|
|
345
345
|
shikiLanguages: bare ? [] : ['java', 'python', 'html'],
|
|
346
346
|
});
|
|
@@ -355,7 +355,7 @@ async function initCommand(args: string[]): Promise<void> {
|
|
|
355
355
|
base: prodBase,
|
|
356
356
|
basePath: prodBasePath,
|
|
357
357
|
internalDomains: [prodDomain],
|
|
358
|
-
features: { search: true, favicon: true, footer: true },
|
|
358
|
+
features: { search: true, favicon: true, footer: true, pickers: true },
|
|
359
359
|
extensionToShikiLanguage: bare ? {} : { java: 'java', py: 'python' },
|
|
360
360
|
shikiLanguages: bare ? [] : ['java', 'python', 'html'],
|
|
361
361
|
});
|
package/bin/validators.ts
CHANGED
|
@@ -49,8 +49,8 @@ export function validateUrl(value: string): string | null {
|
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export function validateBasePath(value: string): string | null {
|
|
52
|
-
if (!/^\/[-a-zA-Z0-9]
|
|
53
|
-
return 'Must start with / and contain
|
|
52
|
+
if (!/^\/(?:[-a-zA-Z0-9]+(?:\/[-a-zA-Z0-9]+)*)?$/.test(value)) {
|
|
53
|
+
return 'Must start with / and contain path segments made of letters, digits, and hyphens';
|
|
54
54
|
}
|
|
55
55
|
return null;
|
|
56
56
|
}
|
package/build/site-variables.ts
CHANGED
|
@@ -14,7 +14,7 @@ const DEFAULT: Partial<SiteVariables> = {
|
|
|
14
14
|
basePath: '/',
|
|
15
15
|
defaultFont: 'sans',
|
|
16
16
|
defaultContrast: 'standard',
|
|
17
|
-
features: { search: true, favicon: true, footer: true },
|
|
17
|
+
features: { search: true, favicon: true, footer: true, pickers: true },
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
const isValid = compileJsonSchema(siteSchema);
|
package/build/types.d.ts
CHANGED
|
@@ -37,6 +37,7 @@ export interface SiteVariables {
|
|
|
37
37
|
basePath: string;
|
|
38
38
|
title: string;
|
|
39
39
|
titlePostfix: string;
|
|
40
|
+
banner?: string;
|
|
40
41
|
symbol?: string;
|
|
41
42
|
faviconSymbol?: string;
|
|
42
43
|
themeColor: string;
|
|
@@ -62,6 +63,7 @@ export type FeatureConfig = {
|
|
|
62
63
|
search: boolean;
|
|
63
64
|
favicon: boolean;
|
|
64
65
|
footer: boolean;
|
|
66
|
+
pickers: boolean;
|
|
65
67
|
};
|
|
66
68
|
|
|
67
69
|
/** A rendered content asset ready to write to dist/ */
|
package/build/utils/render.ts
CHANGED
|
@@ -90,6 +90,7 @@ interface TemplateParametersInput {
|
|
|
90
90
|
content: string | null;
|
|
91
91
|
subPath: string;
|
|
92
92
|
isWatchMode: boolean;
|
|
93
|
+
bannerHtml?: string;
|
|
93
94
|
}
|
|
94
95
|
|
|
95
96
|
function resolveAuthor(
|
|
@@ -141,6 +142,7 @@ function createTemplateParameters({
|
|
|
141
142
|
content,
|
|
142
143
|
subPath,
|
|
143
144
|
isWatchMode,
|
|
145
|
+
bannerHtml,
|
|
144
146
|
}: TemplateParametersInput): Record<string, unknown> {
|
|
145
147
|
const applyBasePath = createApplyBasePath(siteVariables);
|
|
146
148
|
return {
|
|
@@ -149,12 +151,21 @@ function createTemplateParameters({
|
|
|
149
151
|
site: siteVariables,
|
|
150
152
|
page: pageVariables,
|
|
151
153
|
content,
|
|
154
|
+
bannerHtml,
|
|
152
155
|
isWatchMode,
|
|
153
156
|
speculationRulesHrefMatches: `${applyBasePath('/')}*`,
|
|
154
157
|
tadaVersion,
|
|
155
158
|
};
|
|
156
159
|
}
|
|
157
160
|
|
|
161
|
+
function renderSiteBanner(siteVariables: SiteVariables): string {
|
|
162
|
+
if (!siteVariables.banner) {
|
|
163
|
+
return '';
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
return createMarkdown(siteVariables).render(siteVariables.banner);
|
|
167
|
+
}
|
|
168
|
+
|
|
158
169
|
export function injectAssetTags(
|
|
159
170
|
html: string,
|
|
160
171
|
assetFiles: string[],
|
|
@@ -290,6 +301,7 @@ export function renderPlainTextPageAsset({
|
|
|
290
301
|
content,
|
|
291
302
|
subPath,
|
|
292
303
|
isWatchMode: watchMode,
|
|
304
|
+
bannerHtml: renderSiteBanner(siteVariables),
|
|
293
305
|
});
|
|
294
306
|
|
|
295
307
|
const templateHtml = render(
|
|
@@ -371,6 +383,7 @@ export function renderCodePageAsset({
|
|
|
371
383
|
content,
|
|
372
384
|
subPath,
|
|
373
385
|
isWatchMode: isWatchMode(assetFiles),
|
|
386
|
+
bannerHtml: renderSiteBanner(siteVariables),
|
|
374
387
|
});
|
|
375
388
|
|
|
376
389
|
const templateHtml = render('code.html', templateParameters) as string;
|
|
@@ -714,6 +727,7 @@ export function renderLiterateJavaPageAsset({
|
|
|
714
727
|
content: contentHtml,
|
|
715
728
|
subPath,
|
|
716
729
|
isWatchMode: isWatchMode(assetFiles),
|
|
730
|
+
bannerHtml: renderSiteBanner(siteVariables),
|
|
717
731
|
});
|
|
718
732
|
|
|
719
733
|
const templateHtml = render('literate.html', templateParameters) as string;
|
package/package.json
CHANGED
package/schema/site.schema.json
CHANGED
|
@@ -4,11 +4,17 @@
|
|
|
4
4
|
"properties": {
|
|
5
5
|
"features": {
|
|
6
6
|
"type": "object",
|
|
7
|
-
"default": {
|
|
7
|
+
"default": {
|
|
8
|
+
"search": true,
|
|
9
|
+
"favicon": true,
|
|
10
|
+
"footer": true,
|
|
11
|
+
"pickers": true
|
|
12
|
+
},
|
|
8
13
|
"properties": {
|
|
9
14
|
"search": { "type": "boolean", "default": true },
|
|
10
15
|
"favicon": { "type": "boolean", "default": true },
|
|
11
|
-
"footer": { "type": "boolean", "default": true }
|
|
16
|
+
"footer": { "type": "boolean", "default": true },
|
|
17
|
+
"pickers": { "type": "boolean", "default": true }
|
|
12
18
|
},
|
|
13
19
|
"additionalProperties": false
|
|
14
20
|
},
|
|
@@ -16,7 +22,7 @@
|
|
|
16
22
|
"basePath": {
|
|
17
23
|
"type": "string",
|
|
18
24
|
"default": "/",
|
|
19
|
-
"pattern": "^\\/[-a-zA-Z0-9]
|
|
25
|
+
"pattern": "^\\/(?:[-a-zA-Z0-9]+(?:\\/[-a-zA-Z0-9]+)*)?$"
|
|
20
26
|
},
|
|
21
27
|
"internalDomains": {
|
|
22
28
|
"type": "array",
|
|
@@ -24,6 +30,7 @@
|
|
|
24
30
|
"items": { "type": "string", "pattern": "^[-.:a-zA-Z0-9]+$" }
|
|
25
31
|
},
|
|
26
32
|
"title": { "type": "string" },
|
|
33
|
+
"banner": { "type": "string" },
|
|
27
34
|
"symbol": { "type": "string", "pattern": "^[A-Z0-9\\- ]{1,5}$" },
|
|
28
35
|
"titlePostfix": { "type": "string" },
|
|
29
36
|
"themeColor": { "type": "string" },
|
package/src/_alerts.scss
CHANGED
package/src/navigate/style.scss
CHANGED
|
@@ -42,6 +42,23 @@ $duration: 150ms;
|
|
|
42
42
|
animation-duration: $duration;
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
+
// The site-wide banner does not change between pages. Keep it out of the root
|
|
46
|
+
// slide and pin its named transition layer in place without a crossfade.
|
|
47
|
+
.site-banner {
|
|
48
|
+
view-transition-name: site-banner;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
::view-transition-group(site-banner),
|
|
52
|
+
::view-transition-old(site-banner),
|
|
53
|
+
::view-transition-new(site-banner) {
|
|
54
|
+
animation: none;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
::view-transition-old(site-banner),
|
|
58
|
+
::view-transition-new(site-banner) {
|
|
59
|
+
mix-blend-mode: normal;
|
|
60
|
+
}
|
|
61
|
+
|
|
45
62
|
// Forward navigation: old content slides left, new content slides in from right
|
|
46
63
|
.nav-forward::view-transition-old(root) {
|
|
47
64
|
animation: slide-out-left $duration ease-in;
|
package/src/search/index.ts
CHANGED
|
@@ -598,6 +598,7 @@ export default (window: Window) => {
|
|
|
598
598
|
window.addEventListener('pointermove', handleWindowPointerMove);
|
|
599
599
|
window.addEventListener('keydown', handleWindowKeyDown);
|
|
600
600
|
window.addEventListener(PAGE_UPDATE_REFRESH_EVENT, handlePageUpdateRefresh);
|
|
601
|
+
input.disabled = false;
|
|
601
602
|
|
|
602
603
|
return () => {
|
|
603
604
|
window.removeEventListener(
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
<% if (site.features.pickers) { %>
|
|
1
2
|
<div class="appearance-pickers" data-pagefind-ignore>
|
|
2
3
|
<div class="preference-picker font-picker" role="group" aria-label="Font style">
|
|
3
4
|
<button type="button" class="preference-picker-option font-picker-option-sans" data-font-preference-value="sans" aria-label="Use sans-serif fonts" aria-pressed="<%= site.defaultFont === 'sans' %>" disabled>
|
|
@@ -16,3 +17,4 @@
|
|
|
16
17
|
</button>
|
|
17
18
|
</div>
|
|
18
19
|
</div>
|
|
20
|
+
<% } %>
|
package/templates/_top.html
CHANGED
|
@@ -117,7 +117,6 @@
|
|
|
117
117
|
aria-expanded="false"
|
|
118
118
|
aria-controls="quick-search-results"
|
|
119
119
|
disabled />
|
|
120
|
-
<script>document.currentScript.previousElementSibling.disabled=false;</script>
|
|
121
120
|
</div>
|
|
122
121
|
<% } %>
|
|
123
122
|
</div>
|
|
@@ -137,3 +136,8 @@
|
|
|
137
136
|
</details>
|
|
138
137
|
</header>
|
|
139
138
|
<div class="container">
|
|
139
|
+
<% if (site.banner) { %>
|
|
140
|
+
<aside class="site-banner alert" data-pagefind-ignore>
|
|
141
|
+
<div class="content"><%= bannerHtml %></div>
|
|
142
|
+
</aside>
|
|
143
|
+
<% } %>
|