@abreen/tada 1.18.4 → 1.19.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.
- package/README.md +75 -31
- package/bin/tada.ts +16 -7
- package/bin/validators.ts +6 -5
- package/build/bundle.ts +2 -5
- package/build/config-loader.ts +8 -0
- package/build/site-variables.ts +24 -4
- package/build/template-globals.ts +3 -0
- package/build/utils/symbol.ts +21 -0
- package/build/utils/trace-core.ts +5 -5
- package/package.json +1 -2
- package/schema/site.schema.json +5 -2
- package/src/_base.scss +2 -2
- package/src/_content.scss +2 -2
- package/src/_icons.scss +115 -0
- package/src/_layout.scss +5 -12
- package/src/_mixins.scss +8 -0
- package/src/anchor/index.ts +1 -1
- package/src/header/_index.scss +11 -0
- package/src/question/_index.scss +4 -4
- package/src/slides/_index.scss +4 -4
- package/src/style.scss +1 -1
- package/src/timezone/index.ts +2 -2
- package/templates/_appearance-picker.html +2 -2
- package/templates/_heading.html +2 -2
- package/templates/_theme.scss +0 -5
- package/templates/_top.html +2 -2
- package/assets/material-symbols/celebration_24px.svg +0 -1
- package/assets/material-symbols/chevron_right_24px.svg +0 -1
- package/assets/material-symbols/contrast_20px.svg +0 -1
- package/assets/material-symbols/contrast_rtl_off_20px.svg +0 -1
- package/assets/material-symbols/info_20px.svg +0 -1
- package/assets/material-symbols/info_40px.svg +0 -1
- package/assets/material-symbols/open_in_new_20px.svg +0 -1
- package/assets/material-symbols/search_20px.svg +0 -1
- package/assets/material-symbols/smart_display_24px.svg +0 -1
- package/assets/material-symbols/warning_20px.svg +0 -1
- package/assets/material-symbols/warning_40px.svg +0 -1
- package/build/material-symbols.ts +0 -138
- package/src/_material-symbols.scss +0 -31
package/README.md
CHANGED
|
@@ -5,37 +5,62 @@
|
|
|
5
5
|
|
|
6
6
|
A static site generator. The successor to Presto.
|
|
7
7
|
|
|
8
|
+
<figure>
|
|
9
|
+
<a href="https://abreen.io/Tada/markdown.html" target="_blank">
|
|
10
|
+
<img src=".github/screenshot.png" alt="Four screenshots of the Tada example site">
|
|
11
|
+
</a>
|
|
12
|
+
<figcaption>
|
|
13
|
+
A screenshot of the Tada example site in:
|
|
14
|
+
<ul>
|
|
15
|
+
<li>light mode</li>
|
|
16
|
+
<li>dark mode, high contrast</li>
|
|
17
|
+
<li>light mode, high contrast, & serif fonts</li>
|
|
18
|
+
<li>dark mode, standard contrast</li>
|
|
19
|
+
</ul>
|
|
20
|
+
</figcaption>
|
|
21
|
+
</figure>
|
|
22
|
+
|
|
23
|
+
[Visit the example site ↗](https://abreen.io/Tada/index.html)
|
|
24
|
+
|
|
25
|
+
|
|
8
26
|
## Features
|
|
9
27
|
|
|
10
|
-
- Modern design
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
*
|
|
28
|
+
- Modern design
|
|
29
|
+
* Light & dark mode following system, customizable tint
|
|
30
|
+
* Standard & high contrast picker
|
|
31
|
+
* Sans-serif & serif font picker
|
|
32
|
+
* Plus, provide your own web fonts (with many tuning options)
|
|
33
|
+
|
|
34
|
+
- LaTeX math support
|
|
35
|
+
* Provided by [KaTeX][katex]
|
|
36
|
+
* Rendered completely at build time (zero load time on the client)
|
|
37
|
+
|
|
38
|
+
- Automatically generated favicon
|
|
39
|
+
* Text, color, font and font weight taken from config file
|
|
40
|
+
* Or, provide your own favicon file
|
|
41
|
+
|
|
42
|
+
- High quality output and ergonomic authoring
|
|
43
|
+
* Exhaustive internal link validation (broken links fail the build)
|
|
44
|
+
* External link handling (special visual treatment for external links,
|
|
45
|
+
no need to type `target="_blank"`)
|
|
46
|
+
* Internal links automatically prefixed with base path, if specified (no
|
|
47
|
+
need to keep writing the same URL prefix everywhere)
|
|
48
|
+
|
|
18
49
|
- Built-in search powered by [Pagefind][pagefind]
|
|
19
50
|
* Only pages in `content/` reachable from `/index.html` are indexed
|
|
51
|
+
* If `mutool` is installed, text inside PDFs in `content/` is indexed
|
|
52
|
+
|
|
20
53
|
- Generated HTML pages for source code
|
|
21
54
|
* Automatic code highlighting, clickable line numbers
|
|
22
55
|
* Dynamic table of contents for each method/function
|
|
23
56
|
* Converts new Markdown comment syntax ([added in Java 23][jep467]) to HTML
|
|
24
57
|
* Indexed by Pagefind (classes, interfaces, methods, and fields)
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
*
|
|
28
|
-
|
|
29
|
-
*
|
|
30
|
-
|
|
31
|
-
* Hold Shift while annotating to erase
|
|
32
|
-
- PDF files are copied into `dist/`
|
|
33
|
-
* Text of each PDF page is extracted using `mutool` (if present) and indexed
|
|
34
|
-
- External link handling (special visual treatment for external links)
|
|
35
|
-
- Internal link validation at build time (broken links fail the build)
|
|
36
|
-
- Internal links automatically prefixed with base path, if specified
|
|
37
|
-
- Time zone chooser (automatically adjusts `<datetime>` elements)
|
|
38
|
-
- LaTeX math rendered at build time via [KaTeX][katex]
|
|
58
|
+
|
|
59
|
+
- Dynamic table of contents
|
|
60
|
+
* Floats on the side of the screen when window is large enough
|
|
61
|
+
* Renders headings, alert boxes, and `<hr>` elements
|
|
62
|
+
* Highlights the heading currently being viewed
|
|
63
|
+
|
|
39
64
|
- Extended Markdown syntax
|
|
40
65
|
* `<<< details ... <<<` renders a collapsible box
|
|
41
66
|
* `::: section ... :::` renders a special section with a fancy background
|
|
@@ -45,9 +70,26 @@ A static site generator. The successor to Presto.
|
|
|
45
70
|
* `+++ ... +++ ... +++` renders a two-column layout
|
|
46
71
|
* Special heading subtitles with `## Heading # A subtitle here`
|
|
47
72
|
* `{{{ _partial.md }}}` syntax for including partials
|
|
48
|
-
|
|
49
|
-
-
|
|
50
|
-
*
|
|
73
|
+
|
|
74
|
+
- Extremely fast client-side navigation
|
|
75
|
+
* A miniature SPA without the bloat of a framework
|
|
76
|
+
* Highly efficient, thoroughly covered by cross-platform browser tests
|
|
77
|
+
* Also detects a new version of the current page and supplies a reload button
|
|
78
|
+
|
|
79
|
+
### Experimental features
|
|
80
|
+
|
|
81
|
+
- Interactive execution traces via `renderTrace()`
|
|
82
|
+
* Supports Java and Python source files
|
|
83
|
+
* Renders step-by-step source highlighting, output, and memory diagrams
|
|
84
|
+
|
|
85
|
+
- Slides mode: separate content by `---` and present sections as full-screen slides
|
|
86
|
+
* Click icon near slide titles to start presenting at that slide
|
|
87
|
+
* Right-click in presentation mode to annotate
|
|
88
|
+
* Hold Shift while annotating to erase
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
- Time zone chooser (automatically adjusts `<datetime>` elements)
|
|
51
93
|
|
|
52
94
|
## Prerequisites
|
|
53
95
|
|
|
@@ -107,9 +149,11 @@ Visit [http://localhost:8080/index.html](http://localhost:8080/index.html).
|
|
|
107
149
|
|
|
108
150
|
Create a new Tada site in a new directory. Prompts for:
|
|
109
151
|
- **Site title**: displayed in the header and `<title>` tag
|
|
110
|
-
- **Symbol**: short text (1-5 uppercase characters) shown in the logo and favicon
|
|
111
|
-
|
|
112
|
-
|
|
152
|
+
- **Symbol**: short text (1-5 uppercase characters) shown in the logo and favicon,
|
|
153
|
+
or a single emoji shown in the logo (defaults to 🎉; emoji symbols turn off
|
|
154
|
+
generated favicons)
|
|
155
|
+
- **Theme color**: CSS color, e.g. `hsl(195 70% 40%)` (defaults to `darkturquoise`)
|
|
156
|
+
- **Background tint hue**: hue (0-360) for background/foreground tinting (defaults to `190`)
|
|
113
157
|
- **Background tint amount**: percentage (0-100) of tint to apply (defaults to `100`)
|
|
114
158
|
- **Default time zone**: for `<time>` elements (defaults to your system zone)
|
|
115
159
|
- **Production base URL**: e.g. `https://example.edu`
|
|
@@ -268,16 +312,16 @@ vars:
|
|
|
268
312
|
| `title` | Title for the whole site (also used to derive `titlePostfix`) |
|
|
269
313
|
| `titlePostfix` | *Optional*, the string to append to each page's `title` |
|
|
270
314
|
| `banner` | *Optional*, Markdown rendered in a bordered box above every page |
|
|
271
|
-
| `symbol` | Text (1-5 chars) displayed in header when `logo` is absent; also used for generated favicons |
|
|
315
|
+
| `symbol` | Text (1-5 chars) or a single emoji displayed in header when `logo` is absent; also used for generated favicons |
|
|
272
316
|
| `logo` | *Optional*, image path relative to `public/`, replacing the header symbol |
|
|
273
317
|
| `favicon` | *Optional*, `.ico` path relative to `public/`, replacing generated favicons and the web app manifest |
|
|
274
318
|
| `themeColor` | Theme color for the site (e.g., `"tomato"`, `"#c04040"`, `"hsl(195 70% 40%)"`) |
|
|
275
|
-
| `tintHue` | *Optional*, hue (0-360) for background and foreground tinting (default `
|
|
319
|
+
| `tintHue` | *Optional*, hue (0-360) for background and foreground tinting (default `190`) |
|
|
276
320
|
| `tintAmount` | *Optional*, percentage (0-100) of tint to apply to the neutral palette (default `100`); link saturation stays fixed |
|
|
277
321
|
| `defaultFont` | *Optional*, initial font pairing: `sans` or `serif` (default `sans`) |
|
|
278
322
|
| `defaultContrast` | *Optional*, initial neutral-palette contrast: `standard` or `high` (default `standard`) |
|
|
279
323
|
| `fontOverrides` | *Optional*, custom serif and serif-monospace WOFF2 faces from `public/`; each configured family requires `regular` and may include styled faces, OpenType `features`, and font-specific `tuning` |
|
|
280
|
-
| `faviconSymbol` | *Optional*, the text to use instead of `symbol` in generated favicons |
|
|
324
|
+
| `faviconSymbol` | *Optional*, the text to use instead of `symbol` in generated favicons; required when `symbol` is an emoji and favicons are generated |
|
|
281
325
|
| `features.search` | Enable search UI and Pagefind index generation |
|
|
282
326
|
| `features.favicon` | Enable favicon links and generation (default `true`); `false` also omits custom favicon links |
|
|
283
327
|
| `features.footer` | Show the Tada footer at the bottom of every page |
|
package/bin/tada.ts
CHANGED
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
resolveSiteConfigFile,
|
|
28
28
|
type SiteEnv,
|
|
29
29
|
} from '../build/config-files';
|
|
30
|
+
import { isEmojiSymbol } from '../build/utils/symbol';
|
|
30
31
|
|
|
31
32
|
const { version } = packageJson;
|
|
32
33
|
|
|
@@ -75,22 +76,22 @@ interface InitQuestion {
|
|
|
75
76
|
const INIT_QUESTIONS: Record<string, InitQuestion> = {
|
|
76
77
|
title: {
|
|
77
78
|
prompt: 'Site title',
|
|
78
|
-
defaultValue: '
|
|
79
|
+
defaultValue: 'Tada',
|
|
79
80
|
validate: (v: string) => (v ? null : 'Title is required'),
|
|
80
81
|
},
|
|
81
82
|
symbol: {
|
|
82
|
-
prompt: 'Logo symbol (1-5 uppercase chars)',
|
|
83
|
-
defaultValue: '
|
|
83
|
+
prompt: 'Logo symbol (1-5 uppercase chars or one emoji)',
|
|
84
|
+
defaultValue: '🎉',
|
|
84
85
|
validate: validateSymbol,
|
|
85
86
|
},
|
|
86
87
|
themeColor: {
|
|
87
88
|
prompt: 'Theme color',
|
|
88
|
-
defaultValue: '
|
|
89
|
+
defaultValue: 'darkturquoise',
|
|
89
90
|
validate: validateColor,
|
|
90
91
|
},
|
|
91
92
|
tintHue: {
|
|
92
93
|
prompt: 'Background tint hue (0-360)',
|
|
93
|
-
defaultValue: '
|
|
94
|
+
defaultValue: '190',
|
|
94
95
|
validate: validateHue,
|
|
95
96
|
},
|
|
96
97
|
tintAmount: {
|
|
@@ -338,6 +339,14 @@ async function initCommand(args: string[]): Promise<void> {
|
|
|
338
339
|
// Create project directory
|
|
339
340
|
fs.mkdirSync(projectDir);
|
|
340
341
|
|
|
342
|
+
// Generated favicons are text-only, so an emoji symbol starts without them
|
|
343
|
+
const features = {
|
|
344
|
+
search: true,
|
|
345
|
+
favicon: !isEmojiSymbol(symbol),
|
|
346
|
+
footer: true,
|
|
347
|
+
pickers: true,
|
|
348
|
+
};
|
|
349
|
+
|
|
341
350
|
// Generate site configs
|
|
342
351
|
const devConfig = createSiteConfig({
|
|
343
352
|
title,
|
|
@@ -349,7 +358,7 @@ async function initCommand(args: string[]): Promise<void> {
|
|
|
349
358
|
base: 'http://localhost:8080',
|
|
350
359
|
basePath: '/',
|
|
351
360
|
internalDomains: ['localhost'],
|
|
352
|
-
features
|
|
361
|
+
features,
|
|
353
362
|
extensionToShikiLanguage: bare ? {} : { java: 'java', py: 'python' },
|
|
354
363
|
shikiLanguages: bare ? [] : ['java', 'python', 'html'],
|
|
355
364
|
});
|
|
@@ -364,7 +373,7 @@ async function initCommand(args: string[]): Promise<void> {
|
|
|
364
373
|
base: prodBase,
|
|
365
374
|
basePath: prodBasePath,
|
|
366
375
|
internalDomains: [prodDomain],
|
|
367
|
-
features
|
|
376
|
+
features,
|
|
368
377
|
extensionToShikiLanguage: bare ? {} : { java: 'java', py: 'python' },
|
|
369
378
|
shikiLanguages: bare ? [] : ['java', 'python', 'html'],
|
|
370
379
|
});
|
package/bin/validators.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import timezones from '../src/timezone/timezones.json' with { type: 'json' };
|
|
2
2
|
import type { SiteConfigInput, SiteVariables } from '../build/types';
|
|
3
|
+
import { isValidSymbol } from '../build/utils/symbol';
|
|
3
4
|
|
|
4
5
|
const SUPPORTED_TIME_ZONES: readonly string[] = timezones.map(tz => tz.value);
|
|
5
6
|
const FALLBACK_TIME_ZONE = 'UTC';
|
|
@@ -8,13 +9,13 @@ export function validateSymbol(value: string): string | null {
|
|
|
8
9
|
if (!value) {
|
|
9
10
|
return 'Symbol is required';
|
|
10
11
|
}
|
|
11
|
-
if (value
|
|
12
|
-
return
|
|
12
|
+
if (isValidSymbol(value)) {
|
|
13
|
+
return null;
|
|
13
14
|
}
|
|
14
|
-
if (
|
|
15
|
-
return 'Symbol must
|
|
15
|
+
if (value.length > 5) {
|
|
16
|
+
return 'Symbol must be 5 characters or fewer, or a single emoji';
|
|
16
17
|
}
|
|
17
|
-
return
|
|
18
|
+
return 'Symbol must contain only uppercase letters, digits, hyphens, and spaces, or be a single emoji';
|
|
18
19
|
}
|
|
19
20
|
|
|
20
21
|
export function validateColor(value: string): string | null {
|
package/build/bundle.ts
CHANGED
|
@@ -12,7 +12,6 @@ import type { PluginBuilder } from 'bun';
|
|
|
12
12
|
import type { SiteVariables } from './types';
|
|
13
13
|
import timezones from '../src/timezone/timezones.json' with { type: 'json' };
|
|
14
14
|
import pkg from '../package.json' with { type: 'json' };
|
|
15
|
-
import { renderMaterialSymbolVariables } from './material-symbols';
|
|
16
15
|
import {
|
|
17
16
|
getSerifFontStack,
|
|
18
17
|
getSerifMonoFontStack,
|
|
@@ -52,7 +51,7 @@ function renderThemeScss(siteVariables: SiteVariables): string {
|
|
|
52
51
|
const templatePath = path.join(getPackageDir(), 'templates/_theme.scss');
|
|
53
52
|
const template = fs.readFileSync(templatePath, 'utf-8');
|
|
54
53
|
const theme = deriveTheme(siteVariables.themeColor);
|
|
55
|
-
const tintHue = siteVariables.tintHue ??
|
|
54
|
+
const tintHue = siteVariables.tintHue ?? 190;
|
|
56
55
|
const tintAmount = siteVariables.tintAmount ?? 100;
|
|
57
56
|
|
|
58
57
|
const linkHue = formatCssNumber(deriveLinkHue(tintHue));
|
|
@@ -63,7 +62,6 @@ function renderThemeScss(siteVariables: SiteVariables): string {
|
|
|
63
62
|
const traceLineActiveHue = formatCssNumber(deriveTraceLineActiveHue(tintHue));
|
|
64
63
|
const bgTraceLineActive = `hsl(${traceLineActiveHue}deg 100% 86%)`;
|
|
65
64
|
const bgTraceLineActiveDark = `hsl(${traceLineActiveHue}deg 90% 18%)`;
|
|
66
|
-
const materialSymbolVariables = renderMaterialSymbolVariables();
|
|
67
65
|
const customFontFaces = renderCustomFontFaceScss(siteVariables.fontOverrides);
|
|
68
66
|
const customFontTuning = renderCustomFontTuningScss(
|
|
69
67
|
siteVariables.fontOverrides,
|
|
@@ -90,8 +88,7 @@ function renderThemeScss(siteVariables: SiteVariables): string {
|
|
|
90
88
|
});
|
|
91
89
|
const rendered = renderedTemplate
|
|
92
90
|
.replace('/* TADA_CUSTOM_FONT_FACES */', customFontFaces)
|
|
93
|
-
.replace('/* TADA_CUSTOM_FONT_TUNING */', customFontTuning)
|
|
94
|
-
.replace('/* TADA_MATERIAL_SYMBOL_VARIABLES */', materialSymbolVariables);
|
|
91
|
+
.replace('/* TADA_CUSTOM_FONT_TUNING */', customFontTuning);
|
|
95
92
|
|
|
96
93
|
return rendered;
|
|
97
94
|
}
|
package/build/config-loader.ts
CHANGED
|
@@ -29,6 +29,14 @@ export function parseConfigText(text: string, fileName: string): unknown {
|
|
|
29
29
|
try {
|
|
30
30
|
return Bun.YAML.parse(text);
|
|
31
31
|
} catch (error) {
|
|
32
|
+
// YAML rejects JSON surrogate pair escapes such as emoji in `\ud83c\udf89` form
|
|
33
|
+
if (fileName.endsWith('.json')) {
|
|
34
|
+
try {
|
|
35
|
+
return JSON.parse(text);
|
|
36
|
+
} catch {
|
|
37
|
+
// Report the YAML error, as for any other config
|
|
38
|
+
}
|
|
39
|
+
}
|
|
32
40
|
const message = error instanceof Error ? error.message : String(error);
|
|
33
41
|
throw new Error(`${fileName}: ${message}`, { cause: error });
|
|
34
42
|
}
|
package/build/site-variables.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { SiteEnv } from './config-files';
|
|
|
4
4
|
import { loadSiteConfig } from './config-loader';
|
|
5
5
|
import { compile as compileJsonSchema, doValidation } from './json-schema';
|
|
6
6
|
import { getProjectDir } from './utils/paths';
|
|
7
|
+
import { isEmojiSymbol } from './utils/symbol';
|
|
7
8
|
import type { PlainTextLanguage, SiteVariables } from './types';
|
|
8
9
|
import siteSchema from '../schema/site.schema.json' with { type: 'json' };
|
|
9
10
|
import timezones from '../src/timezone/timezones.json' with { type: 'json' };
|
|
@@ -131,10 +132,7 @@ function getSiteVariables(env: SiteEnv): SiteVariables {
|
|
|
131
132
|
},
|
|
132
133
|
} as SiteVariables;
|
|
133
134
|
|
|
134
|
-
|
|
135
|
-
if (variables.symbol && !variables.faviconSymbol) {
|
|
136
|
-
variables.faviconSymbol = variables.symbol;
|
|
137
|
-
}
|
|
135
|
+
resolveFaviconSymbol(variables, fileName);
|
|
138
136
|
|
|
139
137
|
// Derive faviconColor from themeColor if not explicitly set
|
|
140
138
|
if (!variables.faviconColor) {
|
|
@@ -157,6 +155,28 @@ function getSiteVariables(env: SiteEnv): SiteVariables {
|
|
|
157
155
|
return variables;
|
|
158
156
|
}
|
|
159
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Derive faviconSymbol from a text symbol. Generated favicons are drawn with a
|
|
160
|
+
* text font that has no emoji, so an emoji symbol needs a text faviconSymbol.
|
|
161
|
+
*/
|
|
162
|
+
export function resolveFaviconSymbol(
|
|
163
|
+
variables: SiteVariables,
|
|
164
|
+
fileName: string,
|
|
165
|
+
): void {
|
|
166
|
+
if (!variables.symbol || variables.faviconSymbol) {
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
if (!isEmojiSymbol(variables.symbol)) {
|
|
170
|
+
variables.faviconSymbol = variables.symbol;
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
if (variables.features.favicon !== false && !variables.favicon) {
|
|
174
|
+
throw new Error(
|
|
175
|
+
`${fileName}: faviconSymbol is required when symbol is an emoji and favicons are generated; set faviconSymbol to 1 to 5 uppercase characters, digits, hyphens, or spaces`,
|
|
176
|
+
);
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
160
180
|
export function getDevSiteVariables(): SiteVariables {
|
|
161
181
|
return getSiteVariables('dev');
|
|
162
182
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { encodePublicAssetPath } from './custom-fonts';
|
|
2
|
+
import { isEmojiSymbol } from './utils/symbol';
|
|
2
3
|
import timezones from '../src/timezone/timezones.json' with { type: 'json' };
|
|
3
4
|
import type { SiteVariables } from './types';
|
|
4
5
|
|
|
@@ -26,6 +27,7 @@ interface TemplateGlobals {
|
|
|
26
27
|
cx: (obj: Record<string, unknown>) => string;
|
|
27
28
|
encodeAuthoredUrl: (value: string) => string;
|
|
28
29
|
encodePublicAssetPath: (value: string) => string;
|
|
30
|
+
isEmojiSymbol: (value: string | null | undefined) => boolean;
|
|
29
31
|
renderTimeZoneChooser: () => string;
|
|
30
32
|
}
|
|
31
33
|
|
|
@@ -56,6 +58,7 @@ export default function createTemplateGlobals(
|
|
|
56
58
|
cx: classNames,
|
|
57
59
|
encodeAuthoredUrl,
|
|
58
60
|
encodePublicAssetPath,
|
|
61
|
+
isEmojiSymbol,
|
|
59
62
|
renderTimeZoneChooser,
|
|
60
63
|
};
|
|
61
64
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// One emoji: a flag, keycap, subdivision flag, or pictograph with optional
|
|
2
|
+
// skin tone and ZWJ joins. Written for the `u` flag so the site schema (Ajv)
|
|
3
|
+
// can share it; `\p{RGI_Emoji}` needs the `v` flag.
|
|
4
|
+
const EMOJI = String.raw`\p{RI}\p{RI}|[#*0-9]\uFE0F\u20E3|\u{1F3F4}[\u{E0061}-\u{E007A}]+\u{E007F}|(?!\p{RI})(?:\p{Emoji_Presentation}|\p{Extended_Pictographic}\uFE0F)\p{Emoji_Modifier}?(?:\u200D(?:\p{Emoji_Presentation}|\p{Extended_Pictographic}\uFE0F?)\p{Emoji_Modifier}?)*`;
|
|
5
|
+
|
|
6
|
+
/** Must match `faviconSymbol` in `schema/site.schema.json` */
|
|
7
|
+
export const TEXT_SYMBOL_PATTERN = '^[A-Z0-9\\- ]{1,5}$';
|
|
8
|
+
|
|
9
|
+
/** Must match `symbol` in `schema/site.schema.json` */
|
|
10
|
+
export const SYMBOL_PATTERN = `^(?:[A-Z0-9\\- ]{1,5}|${EMOJI})$`;
|
|
11
|
+
|
|
12
|
+
const SYMBOL_RE = new RegExp(SYMBOL_PATTERN, 'u');
|
|
13
|
+
const EMOJI_RE = new RegExp(`^(?:${EMOJI})$`, 'u');
|
|
14
|
+
|
|
15
|
+
export function isValidSymbol(value: string): boolean {
|
|
16
|
+
return SYMBOL_RE.test(value);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function isEmojiSymbol(value: string | null | undefined): boolean {
|
|
20
|
+
return value != null && EMOJI_RE.test(value);
|
|
21
|
+
}
|
|
@@ -277,11 +277,11 @@ export function renderTraceWidgetHtml({
|
|
|
277
277
|
manifestUrl?: string;
|
|
278
278
|
totalSteps?: number;
|
|
279
279
|
}): string {
|
|
280
|
-
const svgAttrs = `aria-hidden='true' width='16' height='16' viewBox='0 0
|
|
281
|
-
const iconFirst = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><
|
|
282
|
-
const iconPrev = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><
|
|
283
|
-
const iconNext = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><
|
|
284
|
-
const iconLast = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><
|
|
280
|
+
const svgAttrs = `aria-hidden='true' width='16' height='16' viewBox='0 0 16 16' fill='none' stroke='currentColor' stroke-width='1.65' stroke-linecap='round' stroke-linejoin='round'`;
|
|
281
|
+
const iconFirst = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><path d='M1.25 4v8M8.25 4l-4 4 4 4M4.25 8h10.5'/></svg>`;
|
|
282
|
+
const iconPrev = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><path d='M6.25 4l-4 4 4 4M2.25 8h11.5'/></svg>`;
|
|
283
|
+
const iconNext = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><path d='M2.25 8h11.5M9.75 4l4 4-4 4'/></svg>`;
|
|
284
|
+
const iconLast = `<svg xmlns='http://www.w3.org/2000/svg' ${svgAttrs}><path d='M1.25 8h10.5M7.75 4l4 4-4 4M14.75 4v8'/></svg>`;
|
|
285
285
|
const disabled = totalSteps === undefined;
|
|
286
286
|
const counterContent = disabled ? '--' : `1/${totalSteps}`;
|
|
287
287
|
const counterStyle = disabled
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@abreen/tada",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.19.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "A static site generator",
|
|
6
6
|
"license": "MIT",
|
|
@@ -17,7 +17,6 @@
|
|
|
17
17
|
"build/",
|
|
18
18
|
"src/",
|
|
19
19
|
"templates/",
|
|
20
|
-
"assets/",
|
|
21
20
|
"fonts/",
|
|
22
21
|
"init/",
|
|
23
22
|
"schema/",
|
package/schema/site.schema.json
CHANGED
|
@@ -31,14 +31,17 @@
|
|
|
31
31
|
},
|
|
32
32
|
"title": { "type": "string" },
|
|
33
33
|
"banner": { "type": "string" },
|
|
34
|
-
"symbol": {
|
|
34
|
+
"symbol": {
|
|
35
|
+
"type": "string",
|
|
36
|
+
"pattern": "^(?:[A-Z0-9\\- ]{1,5}|\\p{RI}\\p{RI}|[#*0-9]\\uFE0F\\u20E3|\\u{1F3F4}[\\u{E0061}-\\u{E007A}]+\\u{E007F}|(?!\\p{RI})(?:\\p{Emoji_Presentation}|\\p{Extended_Pictographic}\\uFE0F)\\p{Emoji_Modifier}?(?:\\u200D(?:\\p{Emoji_Presentation}|\\p{Extended_Pictographic}\\uFE0F?)\\p{Emoji_Modifier}?)*)$"
|
|
37
|
+
},
|
|
35
38
|
"titlePostfix": { "type": "string" },
|
|
36
39
|
"themeColor": { "type": "string" },
|
|
37
40
|
"tintHue": {
|
|
38
41
|
"type": "integer",
|
|
39
42
|
"minimum": 0,
|
|
40
43
|
"maximum": 360,
|
|
41
|
-
"default":
|
|
44
|
+
"default": 190
|
|
42
45
|
},
|
|
43
46
|
"tintAmount": {
|
|
44
47
|
"type": "integer",
|
package/src/_base.scss
CHANGED
package/src/_content.scss
CHANGED
|
@@ -184,7 +184,7 @@ button.icon-button:focus {
|
|
|
184
184
|
|
|
185
185
|
ol.styled-list,
|
|
186
186
|
ul.styled-list {
|
|
187
|
-
font-weight:
|
|
187
|
+
font-weight: 600;
|
|
188
188
|
color: var(--theme-color-text);
|
|
189
189
|
}
|
|
190
190
|
|
|
@@ -392,7 +392,7 @@ dfn {
|
|
|
392
392
|
font-weight: 700;
|
|
393
393
|
}
|
|
394
394
|
|
|
395
|
-
.
|
|
395
|
+
.mask-icon {
|
|
396
396
|
flex-shrink: 0;
|
|
397
397
|
}
|
|
398
398
|
}
|
package/src/_icons.scss
ADDED
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
@use 'mixins' as *;
|
|
2
|
+
|
|
3
|
+
@mixin define-icon($name, $size, $body) {
|
|
4
|
+
--icon-#{$name}: #{icon-svg($size, $body)};
|
|
5
|
+
--icon-#{$name}-size: #{$size}px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
// Mask icons (color-agnostic, painted via background-color: currentColor)
|
|
9
|
+
:root {
|
|
10
|
+
@include define-icon(
|
|
11
|
+
'external-link',
|
|
12
|
+
20,
|
|
13
|
+
"<path d='M9 4H6a2 2 0 0 0-2 2v8a2 2 0 0 0 2 2h8a2 2 0 0 0 2-2v-3M10 10l6-6M12 4h4v4'/>"
|
|
14
|
+
);
|
|
15
|
+
@include define-icon(
|
|
16
|
+
'search',
|
|
17
|
+
20,
|
|
18
|
+
"<circle cx='8.5' cy='8.5' r='5'/><path d='m12 12 4.5 4.5'/>"
|
|
19
|
+
);
|
|
20
|
+
|
|
21
|
+
// Thinner stripes keep the striped half lighter than the solid one. Stripe
|
|
22
|
+
// ends sit on the outline so their caps blend into it.
|
|
23
|
+
@include define-icon(
|
|
24
|
+
'contrast-standard',
|
|
25
|
+
20,
|
|
26
|
+
"<circle cx='10' cy='10' r='7'/><path d='M5.333 4.783v10.435M7.167 3.599v12.802M9 3.072v13.856' stroke-width='1.25'/>"
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// One filled path: the outline's outer edge minus the right of its
|
|
30
|
+
// inner edge, so the solid half and the outline share no seam.
|
|
31
|
+
@include define-icon(
|
|
32
|
+
'contrast-high',
|
|
33
|
+
20,
|
|
34
|
+
"<path d='M10 2.175a7.825 7.825 0 1 1 0 15.65 7.825 7.825 0 1 1 0-15.65zM9.825 3.827A6.175 6.175 0 1 1 9.825 16.173z' fill='black' fill-rule='evenodd' stroke='none'/>"
|
|
35
|
+
);
|
|
36
|
+
|
|
37
|
+
// Outlines of a serif "i" and an exclamation point, with no enclosing shape.
|
|
38
|
+
// The compact versions fill smaller glyphs inside a thin circle or triangle,
|
|
39
|
+
// since outlined glyphs that small would leave almost no space inside.
|
|
40
|
+
@include define-icon(
|
|
41
|
+
'info',
|
|
42
|
+
40,
|
|
43
|
+
"<circle cx='20' cy='10' r='3'/><path d='M14.5 17 22.5 16v14h3v3.5h-11V30h3V19.5h-3z'/>"
|
|
44
|
+
);
|
|
45
|
+
@include define-icon(
|
|
46
|
+
'info-compact',
|
|
47
|
+
20,
|
|
48
|
+
"<circle cx='10' cy='10' r='7.75' stroke-width='1'/><g fill='black' stroke='none'><circle cx='10' cy='6.5' r='1.1'/><path d='M8 9 11 8.5v5h1v1H8v-1h1V10H8z'/></g>"
|
|
49
|
+
);
|
|
50
|
+
@include define-icon(
|
|
51
|
+
'warning',
|
|
52
|
+
40,
|
|
53
|
+
"<path d='M17 9a3 3 0 0 1 6 0l-1.25 14.5a1.75 1.75 0 0 1-3.5 0z'/><circle cx='20' cy='31' r='2.5'/>"
|
|
54
|
+
);
|
|
55
|
+
@include define-icon(
|
|
56
|
+
'warning-compact',
|
|
57
|
+
20,
|
|
58
|
+
"<path d='M10 2.5 2 16.75h16z' stroke-width='1'/><g fill='black' stroke='none'><path d='M8.9 8.1a1.1 1.1 0 0 1 2.2 0l-.4 3.5a.7.7 0 0 1-1.4 0z'/><circle cx='10' cy='14.1' r='1.05'/></g>"
|
|
59
|
+
);
|
|
60
|
+
@include define-icon(
|
|
61
|
+
'breadcrumb-separator',
|
|
62
|
+
24,
|
|
63
|
+
"<path d='m9.25 6.5 5.5 5.5-5.5 5.5'/>"
|
|
64
|
+
);
|
|
65
|
+
@include define-icon(
|
|
66
|
+
'heading-present',
|
|
67
|
+
24,
|
|
68
|
+
"<rect x='4' y='5' width='16' height='11' rx='1'/><path d='M12 16v4M9 20h6'/>"
|
|
69
|
+
);
|
|
70
|
+
@include define-icon(
|
|
71
|
+
'check',
|
|
72
|
+
18,
|
|
73
|
+
"<path d='M3.75 9.375 7.5 12.75l6.75-7.5'/>"
|
|
74
|
+
);
|
|
75
|
+
@include define-icon(
|
|
76
|
+
'question-correct',
|
|
77
|
+
22,
|
|
78
|
+
"<circle cx='11' cy='11' r='9'/><path d='m6.5 11.5 3.25 3 5.75-6.5'/>"
|
|
79
|
+
);
|
|
80
|
+
@include define-icon(
|
|
81
|
+
'question-incorrect',
|
|
82
|
+
22,
|
|
83
|
+
"<path d='m6.5 6.5 9 9m0-9-9 9'/>"
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.mask-icon {
|
|
88
|
+
display: block;
|
|
89
|
+
width: var(--mask-icon-size);
|
|
90
|
+
height: var(--mask-icon-size);
|
|
91
|
+
|
|
92
|
+
@include contained-mask(var(--mask-icon));
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.mask-icon-heading-present {
|
|
96
|
+
--mask-icon: var(--icon-heading-present);
|
|
97
|
+
--mask-icon-size: var(--icon-heading-present-size);
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
.mask-icon-contrast-standard {
|
|
101
|
+
--mask-icon: var(--icon-contrast-standard);
|
|
102
|
+
--mask-icon-size: var(--icon-contrast-standard-size);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
.mask-icon-contrast-high {
|
|
106
|
+
--mask-icon: var(--icon-contrast-high);
|
|
107
|
+
--mask-icon-size: var(--icon-contrast-high-size);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.mask-icon-breadcrumb-separator {
|
|
111
|
+
--mask-icon: var(--icon-breadcrumb-separator);
|
|
112
|
+
--mask-icon-size: var(--icon-breadcrumb-separator-size);
|
|
113
|
+
|
|
114
|
+
color: var(--fg2-color);
|
|
115
|
+
}
|
package/src/_layout.scss
CHANGED
|
@@ -112,7 +112,10 @@ body.literate main table {
|
|
|
112
112
|
min-width: 400px;
|
|
113
113
|
margin: 1rem auto;
|
|
114
114
|
}
|
|
115
|
+
}
|
|
115
116
|
|
|
117
|
+
// Screen only: in print the TOC is hidden, so the content takes the full width
|
|
118
|
+
@media screen and (width >= 900px) {
|
|
116
119
|
:not(.toc-is-active) > .container > .main-content {
|
|
117
120
|
max-width: var(--main-width);
|
|
118
121
|
margin: 0 auto;
|
|
@@ -142,7 +145,7 @@ body.literate main table {
|
|
|
142
145
|
}
|
|
143
146
|
}
|
|
144
147
|
|
|
145
|
-
@media (width >= 1300px) {
|
|
148
|
+
@media screen and (width >= 1300px) {
|
|
146
149
|
.toc-is-active .main-content {
|
|
147
150
|
max-width: calc(var(--toc-width) + var(--gap) + 960px);
|
|
148
151
|
margin: 0 auto;
|
|
@@ -217,6 +220,7 @@ body.literate main table {
|
|
|
217
220
|
footer {
|
|
218
221
|
@include user-select(none);
|
|
219
222
|
|
|
223
|
+
font-size: var(--font-size-smaller);
|
|
220
224
|
color: var(--fg2-color);
|
|
221
225
|
text-align: center;
|
|
222
226
|
|
|
@@ -237,16 +241,5 @@ footer {
|
|
|
237
241
|
&:active {
|
|
238
242
|
color: var(--link-active-color);
|
|
239
243
|
}
|
|
240
|
-
|
|
241
|
-
&::after {
|
|
242
|
-
display: inline-block;
|
|
243
|
-
width: var(--icon-tada-size);
|
|
244
|
-
height: var(--icon-tada-size);
|
|
245
|
-
margin-left: 0.2em;
|
|
246
|
-
vertical-align: middle;
|
|
247
|
-
content: '';
|
|
248
|
-
|
|
249
|
-
@include contained-mask(var(--icon-tada));
|
|
250
|
-
}
|
|
251
244
|
}
|
|
252
245
|
}
|
package/src/_mixins.scss
CHANGED
|
@@ -48,3 +48,11 @@
|
|
|
48
48
|
-webkit-mask-size: contain;
|
|
49
49
|
mask-size: contain;
|
|
50
50
|
}
|
|
51
|
+
|
|
52
|
+
// Every icon is drawn in a viewBox matching its rendered pixel size, so this
|
|
53
|
+
// one stroke width renders identically on every icon.
|
|
54
|
+
$icon-stroke-width: 1.65;
|
|
55
|
+
|
|
56
|
+
@function icon-svg($size, $body) {
|
|
57
|
+
@return url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='#{$size}' height='#{$size}' viewBox='0 0 #{$size} #{$size}' fill='none' stroke='black' stroke-width='#{$icon-stroke-width}' stroke-linecap='round' stroke-linejoin='round'>#{$body}</svg>");
|
|
58
|
+
}
|
package/src/anchor/index.ts
CHANGED
|
@@ -4,7 +4,7 @@ function getElements(parent: HTMLElement): HTMLHeadingElement[] {
|
|
|
4
4
|
|
|
5
5
|
function createPresentIcon(window: Window): HTMLSpanElement {
|
|
6
6
|
const icon = window.document.createElement('span');
|
|
7
|
-
icon.className = '
|
|
7
|
+
icon.className = 'mask-icon mask-icon-heading-present';
|
|
8
8
|
icon.setAttribute('aria-hidden', 'true');
|
|
9
9
|
return icon;
|
|
10
10
|
}
|
package/src/header/_index.scss
CHANGED
|
@@ -184,6 +184,17 @@ header summary .logo {
|
|
|
184
184
|
background: var(--theme-color);
|
|
185
185
|
}
|
|
186
186
|
|
|
187
|
+
// A single emoji is the logo itself: no badge, sized like an image logo
|
|
188
|
+
header summary .logo-emoji {
|
|
189
|
+
padding: 0;
|
|
190
|
+
font-family:
|
|
191
|
+
'Apple Color Emoji', 'Segoe UI Emoji', 'Noto Color Emoji', sans-serif;
|
|
192
|
+
font-size: 22px;
|
|
193
|
+
font-weight: normal;
|
|
194
|
+
line-height: 24px;
|
|
195
|
+
background: none;
|
|
196
|
+
}
|
|
197
|
+
|
|
187
198
|
header summary .logo-image {
|
|
188
199
|
flex: 0 0 auto;
|
|
189
200
|
width: auto;
|
package/src/question/_index.scss
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
.question-a-label {
|
|
22
22
|
flex: 0 0 var(--question-label-width);
|
|
23
23
|
margin: 0;
|
|
24
|
-
font-weight:
|
|
24
|
+
font-weight: 600;
|
|
25
25
|
color: var(--theme-color-text);
|
|
26
26
|
|
|
27
27
|
@include user-select(none);
|
|
@@ -129,10 +129,10 @@
|
|
|
129
129
|
|
|
130
130
|
.question-multiple-choice {
|
|
131
131
|
--question-correct-color: hsl(142deg 58% 36%);
|
|
132
|
-
--question-correct-icon:
|
|
132
|
+
--question-correct-icon: var(--icon-question-correct);
|
|
133
133
|
--question-incorrect-color: hsl(0deg 72% 48%);
|
|
134
|
-
--question-incorrect-icon:
|
|
135
|
-
--question-result-icon-size:
|
|
134
|
+
--question-incorrect-icon: var(--icon-question-incorrect);
|
|
135
|
+
--question-result-icon-size: var(--icon-question-correct-size);
|
|
136
136
|
}
|
|
137
137
|
|
|
138
138
|
@media (prefers-color-scheme: dark) {
|
package/src/slides/_index.scss
CHANGED
|
@@ -7,20 +7,20 @@
|
|
|
7
7
|
|
|
8
8
|
body.is-presenting {
|
|
9
9
|
--slides-annotation-cursor-light:
|
|
10
|
-
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(45 12 12)'%3E%3Crect x='10' y='4.8' width='4' height='13.2' rx='2' fill='white' stroke='black' stroke-width='
|
|
10
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(45 12 12)'%3E%3Crect x='10' y='4.8' width='4' height='13.2' rx='2' fill='white' stroke='black' stroke-width='#{$icon-stroke-width}'/%3E%3Cline x1='12' y1='18' x2='12' y2='20.8' stroke='black' stroke-width='#{$icon-stroke-width}' stroke-linecap='round'/%3E%3C/g%3E%3C/svg%3E")
|
|
11
11
|
6 18,
|
|
12
12
|
crosshair;
|
|
13
13
|
--slides-annotation-cursor-dark:
|
|
14
|
-
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(45 12 12)'%3E%3Crect x='10' y='4.8' width='4' height='13.2' rx='2' fill='black' stroke='white' stroke-width='
|
|
14
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(45 12 12)'%3E%3Crect x='10' y='4.8' width='4' height='13.2' rx='2' fill='black' stroke='white' stroke-width='#{$icon-stroke-width}'/%3E%3Cline x1='12' y1='18' x2='12' y2='20.8' stroke='white' stroke-width='#{$icon-stroke-width}' stroke-linecap='round'/%3E%3C/g%3E%3C/svg%3E")
|
|
15
15
|
6 18,
|
|
16
16
|
crosshair;
|
|
17
17
|
--slides-annotation-cursor: var(--slides-annotation-cursor-light);
|
|
18
18
|
--slides-eraser-cursor-light:
|
|
19
|
-
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Cpath d='M6 10 Q6 8.5 7.5 8.5 H16.5 Q18 8.5 18 10 V14 Q18 15.5 16.5 15.5 H7.5 Q6 15.5 6 14 Z' fill='white' stroke='black' stroke-width='
|
|
19
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Cpath d='M6 10 Q6 8.5 7.5 8.5 H16.5 Q18 8.5 18 10 V14 Q18 15.5 16.5 15.5 H7.5 Q6 15.5 6 14 Z' fill='white' stroke='black' stroke-width='#{$icon-stroke-width}' stroke-linejoin='round'/%3E%3Cline x1='10' y1='8.5' x2='10' y2='15.5' stroke='black' stroke-width='#{$icon-stroke-width}' stroke-linecap='round'/%3E%3C/g%3E%3C/svg%3E")
|
|
20
20
|
12 12,
|
|
21
21
|
cell;
|
|
22
22
|
--slides-eraser-cursor-dark:
|
|
23
|
-
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Cpath d='M6 10 Q6 8.5 7.5 8.5 H16.5 Q18 8.5 18 10 V14 Q18 15.5 16.5 15.5 H7.5 Q6 15.5 6 14 Z' fill='black' stroke='white' stroke-width='
|
|
23
|
+
url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24'%3E%3Cg transform='rotate(-45 12 12)'%3E%3Cpath d='M6 10 Q6 8.5 7.5 8.5 H16.5 Q18 8.5 18 10 V14 Q18 15.5 16.5 15.5 H7.5 Q6 15.5 6 14 Z' fill='black' stroke='white' stroke-width='#{$icon-stroke-width}' stroke-linejoin='round'/%3E%3Cline x1='10' y1='8.5' x2='10' y2='15.5' stroke='white' stroke-width='#{$icon-stroke-width}' stroke-linecap='round'/%3E%3C/g%3E%3C/svg%3E")
|
|
24
24
|
12 12,
|
|
25
25
|
cell;
|
|
26
26
|
--slides-eraser-cursor: var(--slides-eraser-cursor-light);
|
package/src/style.scss
CHANGED
package/src/timezone/index.ts
CHANGED
|
@@ -271,8 +271,8 @@ export default (window: Window) => {
|
|
|
271
271
|
resetBtn.type = 'button';
|
|
272
272
|
resetBtn.innerHTML =
|
|
273
273
|
'<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" aria-hidden="true" focusable="false">' +
|
|
274
|
-
'<line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" stroke-width="
|
|
275
|
-
'<line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" stroke-width="
|
|
274
|
+
'<line x1="18" y1="6" x2="6" y2="18" stroke="currentColor" stroke-width="1.65" stroke-linecap="round"/>' +
|
|
275
|
+
'<line x1="6" y1="6" x2="18" y2="18" stroke="currentColor" stroke-width="1.65" stroke-linecap="round"/>' +
|
|
276
276
|
'</svg>';
|
|
277
277
|
resetBtn.className = 'icon-button';
|
|
278
278
|
|
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
</button>
|
|
7
7
|
<button type="button" class="preference-picker contrast-picker" role="switch" data-contrast-preference-switch aria-label="Use high contrast" aria-checked="<%= site.defaultContrast === 'high' %>" title="<%= site.defaultContrast === 'high' ? 'Use standard contrast' : 'Use high contrast' %>" disabled>
|
|
8
8
|
<span class="preference-picker-option contrast-picker-option-standard" data-contrast-preference-value="standard" aria-hidden="true">
|
|
9
|
-
<span class="
|
|
9
|
+
<span class="mask-icon mask-icon-contrast-standard"></span>
|
|
10
10
|
</span>
|
|
11
11
|
<span class="preference-picker-option contrast-picker-option-high" data-contrast-preference-value="high" aria-hidden="true">
|
|
12
|
-
<span class="
|
|
12
|
+
<span class="mask-icon mask-icon-contrast-high"></span>
|
|
13
13
|
</span>
|
|
14
14
|
</button>
|
|
15
15
|
</div>
|
package/templates/_heading.html
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
<ol>
|
|
5
5
|
<% page.breadcrumbs.forEach((entry, index) => { %>
|
|
6
6
|
<li>
|
|
7
|
-
<% if (index > 0) { %><span class="
|
|
7
|
+
<% if (index > 0) { %><span class="mask-icon mask-icon-breadcrumb-separator" aria-hidden="true"></span><% } %>
|
|
8
8
|
<a href="<%- encodeAuthoredUrl(entry.url) %>"><%- entry.label %></a>
|
|
9
9
|
</li>
|
|
10
10
|
<% }); %>
|
|
11
11
|
<li>
|
|
12
|
-
<span class="
|
|
12
|
+
<span class="mask-icon mask-icon-breadcrumb-separator" aria-hidden="true"></span>
|
|
13
13
|
<span aria-current="page"><%- page.title %></span>
|
|
14
14
|
</li>
|
|
15
15
|
</ol>
|
package/templates/_theme.scss
CHANGED
|
@@ -79,11 +79,6 @@
|
|
|
79
79
|
--mono-border-radius: 0.375em;
|
|
80
80
|
--mono-padding: 0.12em 0.25em;
|
|
81
81
|
|
|
82
|
-
// SVG icons
|
|
83
|
-
// Mask icons (color-agnostic, painted via background-color: currentColor)
|
|
84
|
-
--icon-check: 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='M5 12.5 10 17 19 7' stroke='black' stroke-width='2.5' stroke-linecap='round' stroke-linejoin='round' fill='none'/></svg>");
|
|
85
|
-
/* TADA_MATERIAL_SYMBOL_VARIABLES */
|
|
86
|
-
|
|
87
82
|
color-scheme: light dark;
|
|
88
83
|
}
|
|
89
84
|
|
package/templates/_top.html
CHANGED
|
@@ -23,7 +23,7 @@
|
|
|
23
23
|
<link rel="apple-touch-icon" sizes="512x512" href="/favicon-512.png" />
|
|
24
24
|
<link rel="apple-touch-icon" sizes="256x256" href="/favicon-256.png" />
|
|
25
25
|
<link rel="manifest" href="/manifest.json" />
|
|
26
|
-
<meta name="apple-mobile-web-app-title" content="<%- site.
|
|
26
|
+
<meta name="apple-mobile-web-app-title" content="<%- site.title %>">
|
|
27
27
|
<meta name="mobile-web-app-capable" content="yes">
|
|
28
28
|
<% } %>
|
|
29
29
|
<% } %>
|
|
@@ -219,7 +219,7 @@
|
|
|
219
219
|
<path class="menu-icon-line menu-icon-line-middle" d="M3 12h18" />
|
|
220
220
|
<path class="menu-icon-line menu-icon-line-bottom" d="M3 18h18" />
|
|
221
221
|
</svg>
|
|
222
|
-
<% if (site.logo) { %><img class="logo-image" src="/<%- encodePublicAssetPath(site.logo) %>" alt="" aria-hidden="true" /><% } else if (site.symbol) { %><span class="logo" aria-hidden="true"><%- site.symbol %></span><% } %>
|
|
222
|
+
<% if (site.logo) { %><img class="logo-image" src="/<%- encodePublicAssetPath(site.logo) %>" alt="" aria-hidden="true" /><% } else if (site.symbol) { %><span class="<%- isEmojiSymbol(site.symbol) ? 'logo logo-emoji' : 'logo' %>" aria-hidden="true"><%- site.symbol %></span><% } %>
|
|
223
223
|
<span class="header-title" aria-hidden="true">
|
|
224
224
|
<span class="header-title-reel">
|
|
225
225
|
<span class="site-title"><%- site.title %></span>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m96.85-94.15 184.77-517.54 332.77 332.77L96.85-94.15ZM206.69-204l288-102-186-184-102 286Zm358.93-245.69-37.08-35.08 226.77-226.77q31.15-31.15 74.54-31.15 43.38 0 74.53 31.15l20.77 22.77-35.53 35.08-20.77-20.77q-17.62-17.62-39.23-17.62-21.62 0-39.24 17.62L565.62-449.69ZM413.31-602l-37.08-37.08 26-24q17.69-17.69 17.69-41.46T402.23-746l-26.46-26.46 37.08-35.08 24.46 24.46q32 32 32 78.54 0 46.54-32 78.54l-24 24Zm76.15 76.15-37.08-35.07 144.77-144.77q17.62-17.62 17.62-39.23 0-21.62-17.62-39.23l-62.77-60.77L571.46-882l60.77 62.77q31.92 31.92 31.92 75.31 0 43.38-31.92 75.3L489.46-525.85Zm152.31 152.31-37.08-35.08 53.7-53.69q32.76-32.77 79.3-32.77T817-462.31l53.69 53.69-37.07 35.08-51.7-51.69q-18.46-18.46-43.23-18.46-24.77 0-43.23 18.46l-53.69 51.69ZM206.69-204Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M504-480 320-664l56-56 240 240-240 240-56-56 184-184Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M334.22-133.34q-68.23-29.34-119.86-80.92-51.63-51.58-80.99-119.76Q104-402.19 104-480.37q0-78.17 29.34-145.91 29.34-67.73 80.92-119.36 51.58-51.63 119.76-80.99Q402.19-856 480.37-856q78.17 0 145.91 29.34 67.73 29.34 119.36 80.92 51.63 51.58 80.99 119.26Q856-558.81 856-480.63q0 78.17-29.34 146.41-29.34 68.23-80.92 119.86-51.58 51.63-119.26 80.99Q558.81-104 480.63-104q-78.17 0-146.41-29.34ZM490-160.69q127.62-8.08 217.81-98.35T798-480q0-130.69-89.42-220.19-89.43-89.5-218.58-99.12v638.62Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="m798.38-95.77-88.3-88.31q-50.46 37.39-108.68 58.73Q543.17-104 480-104q-77.34 0-145.88-29.37-68.54-29.37-119.96-80.79-51.42-51.42-80.79-119.96Q104-402.66 104-480q0-63.17 21.35-121.4 21.34-58.22 58.73-108.68l-68.62-68.61L156-819.23l682.92 682.92-40.54 40.54ZM480-162q51.77 0 99.62-17.15 47.84-17.16 89.46-46.93L480-415.15V-162Zm317-116.69-41.77-40.77Q776-358.23 787-398.48q11-40.25 11-81.52 0-133-92.5-225.5T480-798v202.31L278.69-797q44.8-28.66 96.09-43.83Q426.07-856 480-856q78.59 0 146.84 28.85Q695.1-798.3 746.7-746.7q51.6 51.6 80.45 119.86Q856-558.59 856-480q0 53.93-15.17 105.22T797-278.69Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M452-292h58v-236h-58v236Zm49.35-309.61q9.27-8.7 9.27-21.54 0-12.85-8.7-21.93-8.69-9.07-21.53-9.07-12.85 0-21.93 8.69t-9.08 21.54q0 12.84 8.89 21.92 8.88 9.08 21.34 9.08 12.47 0 21.74-8.69ZM480.41-104q-77.59 0-146.17-29.36-68.57-29.36-120.02-80.76-51.45-51.4-80.83-119.88Q104-402.47 104-480.32q0-78.11 29.42-146.42 29.42-68.3 80.92-119.91 51.5-51.62 119.87-80.48Q402.59-856 480.32-856q78.1 0 146.4 28.84 68.29 28.84 119.92 80.42 51.63 51.58 80.49 120.07Q856-558.19 856-480.33q0 77.87-28.84 146.11-28.84 68.23-80.41 119.78-51.57 51.55-120.03 81Q558.25-104 480.41-104Zm-.41-58q132.51 0 225.26-92.74Q798-347.49 798-480t-92.74-225.26Q612.51-798 480-798t-225.26 92.74Q162-612.51 162-480t92.74 225.26Q347.49-162 480-162Zm0-318Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="40" viewBox="0 -960 960 960" width="40"><path d="M456.05-289.33h51.18V-520h-51.18v230.67Zm44.42-304.49q8.71-8.18 8.71-20.67 0-13.3-8.37-21.4-8.37-8.11-20.62-8.11-13.52 0-21.45 7.93-7.92 7.93-7.92 20.89 0 12.91 8.58 21.23 8.57 8.31 20.47 8.31 11.9 0 20.6-8.18ZM480.01-98.67q-79.35 0-148.51-30.19-69.17-30.19-120.78-81.76-51.61-51.57-81.83-120.81-30.22-69.24-30.22-148.77 0-79.03 30.25-148.6t82.04-121.42q51.8-51.85 120.76-81.48 68.97-29.63 148.18-29.63 79.07 0 148.84 29.6 69.77 29.6 121.48 81.42 51.71 51.82 81.41 121.55 29.7 69.73 29.7 148.84 0 79.62-29.6 148.33-29.6 68.72-81.41 120.42-51.8 51.7-121.52 82.1-69.71 30.4-148.79 30.4Zm.32-51.18q137.11 0 233.46-96.43 96.36-96.44 96.36-234.05 0-137.11-96.23-233.46-96.23-96.36-233.92-96.36-137.28 0-233.72 96.23-96.43 96.23-96.43 233.92 0 137.28 96.43 233.72 96.44 96.43 234.05 96.43ZM480-480Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M234.62-152q-35.05 0-58.83-23.79Q152-199.57 152-234.62v-490.76q0-35.05 23.79-58.83Q199.57-808 234.62-808h233.61v58H234.62q-9.24 0-16.93 7.69-7.69 7.69-7.69 16.93v490.76q0 9.24 7.69 16.93 7.69 7.69 16.93 7.69h490.76q9.24 0 16.93-7.69 7.69-7.69 7.69-16.93v-233.61h58v233.61q0 35.05-23.79 58.83Q760.43-152 725.38-152H234.62Zm150.92-192.23-41.31-41.31L708.69-750H595v-58h213v213h-58v-113.69L385.54-344.23Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M769.38-151.85 529.92-391.31q-30 22.54-70.29 34.54-40.29 12-77.06 12-96.95 0-165.11-68.15-68.15-68.16-68.15-165.08 0-96.92 68.15-165.08 68.16-68.15 165.08-68.15 96.92 0 165.08 68.15 68.15 68.16 68.15 165.11 0 39.08-11.77 76.87-11.77 37.79-33.77 67.48l240.46 240.47-41.31 41.3ZM382.54-402.77q74.61 0 124.92-50.31 50.31-50.3 50.31-124.92t-50.31-124.92q-50.31-50.31-124.92-50.31-74.62 0-124.92 50.31-50.31 50.3-50.31 124.92t50.31 124.92q50.3 50.31 124.92 50.31Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="M386-310.92 649.08-480 386-649.08v338.16ZM184.62-176q-38.35 0-64.48-26.14Q94-228.27 94-266.62v-426.76q0-38.35 26.14-64.48Q146.27-784 184.62-784h590.76q38.35 0 64.48 26.14Q866-731.73 866-693.38v426.76q0 38.35-26.14 64.48Q813.73-176 775.38-176H184.62Zm0-66h590.76q9.24 0 16.93-7.69 7.69-7.69 7.69-16.93v-426.76q0-9.24-7.69-16.93-7.69-7.69-16.93-7.69H184.62q-9.24 0-16.93 7.69-7.69 7.69-7.69 16.93v426.76q0 9.24 7.69 16.93 7.69 7.69 16.93 7.69ZM160-242v-476 476Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="20" viewBox="0 -960 960 960" width="20"><path d="M65.23-142 480-830l414.77 688H65.23ZM169-200h622L480-718 169-200Zm335.35-62.44q10.27-10.06 10.27-23.35 0-13.29-10.06-23.56t-23.35-10.27q-13.29 0-23.56 10.06t-10.27 23.35q0 13.29 10.06 23.56t23.35 10.27q13.29 0 23.56-10.06ZM452-364.62h58v-196h-58v196ZM480-459Z"/></svg>
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" height="40" viewBox="0 -960 960 960" width="40"><path d="M74.56-132 480-830.67 885.44-132H74.56Zm89.08-51.18h632.72L480-728.31 163.64-183.18Zm339.4-62.64q8.96-9.08 8.96-20.91t-9.21-21.13q-9.21-9.29-21.24-9.29-12.04 0-21 9.42t-8.96 21.25q0 11.84 9.21 20.79t21.24 8.95q12.04 0 21-9.08Zm-46.83-92.23h51.17v-210.46h-51.17v210.46ZM480-456.08Z"/></svg>
|
|
@@ -1,138 +0,0 @@
|
|
|
1
|
-
import fs from 'fs';
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { getPackageDir } from './utils/paths';
|
|
4
|
-
|
|
5
|
-
export const MATERIAL_SYMBOL_CONFIG = Object.freeze({
|
|
6
|
-
family: 'Material Symbols Outlined',
|
|
7
|
-
fill: 0,
|
|
8
|
-
weight: 200,
|
|
9
|
-
grade: 200,
|
|
10
|
-
opticalSizes: Object.freeze([20, 24, 40] as const),
|
|
11
|
-
viewBox: '0 -960 960 960',
|
|
12
|
-
source: 'https://fonts.google.com/icons',
|
|
13
|
-
} as const);
|
|
14
|
-
|
|
15
|
-
export const MATERIAL_SYMBOLS = Object.freeze({
|
|
16
|
-
tada: Object.freeze({
|
|
17
|
-
cssVariable: '--icon-tada',
|
|
18
|
-
symbol: 'celebration',
|
|
19
|
-
opticalSize: 24,
|
|
20
|
-
}),
|
|
21
|
-
contrastStandard: Object.freeze({
|
|
22
|
-
cssVariable: '--icon-contrast-standard',
|
|
23
|
-
symbol: 'contrast_rtl_off',
|
|
24
|
-
opticalSize: 20,
|
|
25
|
-
}),
|
|
26
|
-
contrastHigh: Object.freeze({
|
|
27
|
-
cssVariable: '--icon-contrast-high',
|
|
28
|
-
symbol: 'contrast',
|
|
29
|
-
opticalSize: 20,
|
|
30
|
-
}),
|
|
31
|
-
info: Object.freeze({
|
|
32
|
-
cssVariable: '--icon-info',
|
|
33
|
-
symbol: 'info',
|
|
34
|
-
opticalSize: 40,
|
|
35
|
-
}),
|
|
36
|
-
infoCompact: Object.freeze({
|
|
37
|
-
cssVariable: '--icon-info-compact',
|
|
38
|
-
symbol: 'info',
|
|
39
|
-
opticalSize: 20,
|
|
40
|
-
}),
|
|
41
|
-
warning: Object.freeze({
|
|
42
|
-
cssVariable: '--icon-warning',
|
|
43
|
-
symbol: 'warning',
|
|
44
|
-
opticalSize: 40,
|
|
45
|
-
}),
|
|
46
|
-
warningCompact: Object.freeze({
|
|
47
|
-
cssVariable: '--icon-warning-compact',
|
|
48
|
-
symbol: 'warning',
|
|
49
|
-
opticalSize: 20,
|
|
50
|
-
}),
|
|
51
|
-
breadcrumbSeparator: Object.freeze({
|
|
52
|
-
cssVariable: '--icon-breadcrumb-separator',
|
|
53
|
-
symbol: 'chevron_right',
|
|
54
|
-
opticalSize: 24,
|
|
55
|
-
// The authored selection differs from the shared weight/grade defaults.
|
|
56
|
-
weight: 400,
|
|
57
|
-
grade: 0,
|
|
58
|
-
}),
|
|
59
|
-
search: Object.freeze({
|
|
60
|
-
cssVariable: '--icon-search',
|
|
61
|
-
symbol: 'search',
|
|
62
|
-
opticalSize: 20,
|
|
63
|
-
}),
|
|
64
|
-
externalLink: Object.freeze({
|
|
65
|
-
cssVariable: '--icon-external-link',
|
|
66
|
-
symbol: 'open_in_new',
|
|
67
|
-
opticalSize: 20,
|
|
68
|
-
}),
|
|
69
|
-
headingPresent: Object.freeze({
|
|
70
|
-
cssVariable: '--icon-heading-present',
|
|
71
|
-
symbol: 'smart_display',
|
|
72
|
-
opticalSize: 24,
|
|
73
|
-
}),
|
|
74
|
-
} as const);
|
|
75
|
-
|
|
76
|
-
type MaterialSymbol = (typeof MATERIAL_SYMBOLS)[keyof typeof MATERIAL_SYMBOLS];
|
|
77
|
-
|
|
78
|
-
interface RenderMaterialSymbolOptions {
|
|
79
|
-
packageDir?: string;
|
|
80
|
-
readFile?: (filePath: string) => string;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function getAssetPath(packageDir: string, symbol: MaterialSymbol): string {
|
|
84
|
-
return path.join(
|
|
85
|
-
packageDir,
|
|
86
|
-
'assets/material-symbols',
|
|
87
|
-
`${symbol.symbol}_${symbol.opticalSize}px.svg`,
|
|
88
|
-
);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function isConfiguredSvg(
|
|
92
|
-
svg: string,
|
|
93
|
-
opticalSize: MaterialSymbol['opticalSize'],
|
|
94
|
-
): boolean {
|
|
95
|
-
const svgTag = svg.match(/<svg\b[^>]*>/)?.[0];
|
|
96
|
-
if (!svgTag) {
|
|
97
|
-
return false;
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
const hasAttribute = (name: string, value: string) =>
|
|
101
|
-
new RegExp(`\\b${name}=["']${value}["']`).test(svgTag);
|
|
102
|
-
|
|
103
|
-
return (
|
|
104
|
-
hasAttribute('width', String(opticalSize)) &&
|
|
105
|
-
hasAttribute('height', String(opticalSize)) &&
|
|
106
|
-
hasAttribute('viewBox', MATERIAL_SYMBOL_CONFIG.viewBox)
|
|
107
|
-
);
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
export function renderMaterialSymbolVariables({
|
|
111
|
-
packageDir = getPackageDir(),
|
|
112
|
-
readFile = filePath => fs.readFileSync(filePath, 'utf8'),
|
|
113
|
-
}: RenderMaterialSymbolOptions = {}): string {
|
|
114
|
-
return Object.values(MATERIAL_SYMBOLS)
|
|
115
|
-
.map(symbol => {
|
|
116
|
-
const assetPath = getAssetPath(packageDir, symbol);
|
|
117
|
-
let svg: string;
|
|
118
|
-
|
|
119
|
-
try {
|
|
120
|
-
svg = readFile(assetPath);
|
|
121
|
-
} catch (error) {
|
|
122
|
-
throw new Error(
|
|
123
|
-
`Material Symbol "${symbol.symbol}" could not be read from ${assetPath}`,
|
|
124
|
-
{ cause: error },
|
|
125
|
-
);
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
if (!isConfiguredSvg(svg, symbol.opticalSize)) {
|
|
129
|
-
throw new Error(
|
|
130
|
-
`Material Symbol "${symbol.symbol}" does not match the configured ${symbol.opticalSize}px SVG format: ${assetPath}`,
|
|
131
|
-
);
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
const dataUri = `data:image/svg+xml,${encodeURIComponent(svg.trim())}`;
|
|
135
|
-
return ` ${symbol.cssVariable}: url("${dataUri}");\n ${symbol.cssVariable}-size: ${symbol.opticalSize}px;`;
|
|
136
|
-
})
|
|
137
|
-
.join('\n');
|
|
138
|
-
}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
@use 'mixins' as *;
|
|
2
|
-
|
|
3
|
-
.material-symbol-icon {
|
|
4
|
-
display: block;
|
|
5
|
-
width: var(--material-symbol-icon-size);
|
|
6
|
-
height: var(--material-symbol-icon-size);
|
|
7
|
-
|
|
8
|
-
@include contained-mask(var(--material-symbol-icon));
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
.material-symbol-icon-heading-present {
|
|
12
|
-
--material-symbol-icon: var(--icon-heading-present);
|
|
13
|
-
--material-symbol-icon-size: var(--icon-heading-present-size);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
.material-symbol-icon-contrast-standard {
|
|
17
|
-
--material-symbol-icon: var(--icon-contrast-standard);
|
|
18
|
-
--material-symbol-icon-size: var(--icon-contrast-standard-size);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
.material-symbol-icon-contrast-high {
|
|
22
|
-
--material-symbol-icon: var(--icon-contrast-high);
|
|
23
|
-
--material-symbol-icon-size: var(--icon-contrast-high-size);
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
.material-symbol-icon-breadcrumb-separator {
|
|
27
|
-
--material-symbol-icon: var(--icon-breadcrumb-separator);
|
|
28
|
-
--material-symbol-icon-size: var(--icon-breadcrumb-separator-size);
|
|
29
|
-
|
|
30
|
-
color: var(--fg2-color);
|
|
31
|
-
}
|