@rathnasgala/theme 0.0.18 → 0.0.20
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/package.json +1 -1
- package/payload/.gala/managed-files.json +11 -7
- package/payload/lib/site-config.js +10 -7
- package/payload/src/_data/site.js +12 -1
- package/payload/src/_includes/layouts/base.njk +3 -7
- package/payload/src/assets/favicon.svg +1 -0
- package/payload/src/assets/interactions.js +10 -0
- package/payload/src/assets/theme.css +214 -62
- package/payload/src/settings.njk +0 -19
package/package.json
CHANGED
|
@@ -2,12 +2,16 @@
|
|
|
2
2
|
"schemaVersion": 1,
|
|
3
3
|
"themePackage": {
|
|
4
4
|
"name": "@rathnasgala/theme",
|
|
5
|
-
"version": "0.0.
|
|
5
|
+
"version": "0.0.20",
|
|
6
6
|
"availableDesignThemes": [
|
|
7
7
|
"editorial"
|
|
8
8
|
],
|
|
9
9
|
"securityAdvisories": []
|
|
10
10
|
},
|
|
11
|
+
"requiredBudgets": {
|
|
12
|
+
"managedJavaScriptBytes": 65536,
|
|
13
|
+
"managedCssBytes": 32768
|
|
14
|
+
},
|
|
11
15
|
"files": {
|
|
12
16
|
".gala/publish.yml.template": "73080241d89bd09964b797a8bcc8e18471412e11bc873efad76305b60f497d08",
|
|
13
17
|
".gitignore": "b5fa24e10155097a0d372926fd2e59e6072e7cc2cb6399bbfb4beb8b33ea315b",
|
|
@@ -21,7 +25,7 @@
|
|
|
21
25
|
"lib/render-markdown.js": "40e6d6743b76de6c16d138475f188a4263967530c370d8b26a363f4df58c2caf",
|
|
22
26
|
"lib/seo.js": "107de8804931945b8e73894877fc394d6b535a9d0d969a4ba5b68f2e136e0a17",
|
|
23
27
|
"lib/share-targets.js": "458aff86fab2b62a364442cd8c612565c6e0b53eef2f20cb6237cc562b1e0731",
|
|
24
|
-
"lib/site-config.js": "
|
|
28
|
+
"lib/site-config.js": "3ed45daef0b7f79d94bf0c648c4fe7d8bf517534e4645a4b43d952dfc434ddc4",
|
|
25
29
|
"package-lock.json": "c97a6a2f794aef083a39a8d2628eccc4a3c484e1c6225899b77ec1fb7c466d9e",
|
|
26
30
|
"package.json": "4c60bea06f39aec755ac68caf8d8841c1d59d0f6121fad7f4396231ce14712dc",
|
|
27
31
|
"src/404.njk": "be0d44370ac5402156aaf3d32ea581057bc61ec94c1a5f92bb809733af7a8a20",
|
|
@@ -29,9 +33,9 @@
|
|
|
29
33
|
"src/_data/engagementSnapshot.js": "9217dacebfaf008f7a0ad67ff4e8d1fa8fba609a9dc7e3430c78c5b32024da0e",
|
|
30
34
|
"src/_data/feedLinks.js": "06c93352ebd888acb431a1c9a8be6ecff757895468e9f2d336761038751c2d5e",
|
|
31
35
|
"src/_data/languages.js": "1358748f7fa2f74406d3295a030827d6229a53e94da72cf712e719d7a356aeac",
|
|
32
|
-
"src/_data/site.js": "
|
|
36
|
+
"src/_data/site.js": "6f9b754876ab7cfa93f02a38be2962edce8245423c354426a1465513caec7911",
|
|
33
37
|
"src/_includes/components/ui.njk": "23eb647d8658868449ec6bb809e965a85302124a97639f94d5d28af72df56e4c",
|
|
34
|
-
"src/_includes/layouts/base.njk": "
|
|
38
|
+
"src/_includes/layouts/base.njk": "638457f6c10f3ba866e8c70715678298096a668568e99456bef4167ebf1111e7",
|
|
35
39
|
"src/_includes/layouts/post.njk": "1accd2832064ad19ee7bf18daf5fa1e60569f32c9b7a547934a6361f747d7eb7",
|
|
36
40
|
"src/assets/embed-codepen.svg": "e9def697f38c466fb2b6652535c4c814e8cbbbefc6e052a69f335aeb27e8356b",
|
|
37
41
|
"src/assets/embed-gist.svg": "fcd9bc2bf29a5c118492b853c0a01390b7539c38ddb985da3c2a6e2f246a39f7",
|
|
@@ -39,11 +43,12 @@
|
|
|
39
43
|
"src/assets/embed-youtube.svg": "10d192f2b14b67664fea88c8cf246321d20190def51d59fad5762e552219b067",
|
|
40
44
|
"src/assets/engagement-comments.js": "b20d9268c9d908b4453a42188eaca25349f25534fb04a9293c9e688a982cd8f8",
|
|
41
45
|
"src/assets/engagement-transport.js": "4f9ca0cd669bf8abc25f2909104e3e4b231657ef97d36a17d06e53454d711786",
|
|
42
|
-
"src/assets/
|
|
46
|
+
"src/assets/favicon.svg": "8615e3d96fe37ae9ed14afb1886e7c0e690eef5b10be66ca91cccfd085a74bb6",
|
|
47
|
+
"src/assets/interactions.js": "4b65dcfcc23682616b15071d746da053bcc3a6bc5df36e11dc5698dd3348f314",
|
|
43
48
|
"src/assets/preferences.js": "789127bee013ed6a1bbf8cefd7b9109291c16220e7a6e09314e3c93c54731d1d",
|
|
44
49
|
"src/assets/search.js": "df425f0239277792ad39f2138bc89cb66cc4ecda5ed59042d46abc2f05372088",
|
|
45
50
|
"src/assets/theme-mode.js": "944b29db11a577961a60ddcfa52f07ef2411f3f3631bea85bd79be16428c08be",
|
|
46
|
-
"src/assets/theme.css": "
|
|
51
|
+
"src/assets/theme.css": "300f6c2ffd7e63a948cfdb46b2d0f4abdbce5f5c4da7ee2cca5633d9795277c4",
|
|
47
52
|
"src/assets/vendor/hooks.js": "ae6ec58592683ca64fa4d65b20d40b103df62a673bcc4712515cf165950b07f3",
|
|
48
53
|
"src/assets/vendor/htm.js": "e4dac9bc40a6f2ec590413d787ae30bbcfdfcde4f28971ee65d9578271b7aad4",
|
|
49
54
|
"src/assets/vendor/preact.js": "712517dd2a42c3c22b5ab0264ad7e9a2b1e8be6cf97fa00dbedd98203617e616",
|
|
@@ -58,7 +63,6 @@
|
|
|
58
63
|
"src/redirects.11ty.js": "3c163246a59f5364861db6a6f05ae88afc938a5379d86cf42776d8d49b0031f3",
|
|
59
64
|
"src/search-index.11ty.js": "700dc2a2be0ef20de3a828a4612fcf7a082691eade29c6e1d75f09c24b6c6024",
|
|
60
65
|
"src/search.njk": "63f2e8aeebb63c90da2e375eece639ce096cad1eff7f28628cafc46faf7ceee6",
|
|
61
|
-
"src/settings.njk": "9e6babf4d2774687558618c4fbd109ddfc0f479f52ec2e5d00c373c44ad16676",
|
|
62
66
|
"src/sitemap.11ty.js": "4f233e94fb4a913ad5659116518432ed264984a7b622eba3558c77b4ec6435dc",
|
|
63
67
|
"static/robots.txt": "16ceb5ee3e0dc13aa9adf31a3ebbe45a1d965b8c2b9f72eaf84e5911e140ed95"
|
|
64
68
|
},
|
|
@@ -13,13 +13,9 @@ const BUDGET_KEYS = Object.freeze([
|
|
|
13
13
|
*/
|
|
14
14
|
const DESIGN_VALUES = Object.freeze({
|
|
15
15
|
layout: Object.freeze(['article-first', 'portfolio']),
|
|
16
|
-
palette: Object.freeze(['default', 'ocean']),
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
spacing: Object.freeze(['compact', 'comfortable', 'spacious']),
|
|
20
|
-
radius: Object.freeze(['sharp', 'soft', 'round']),
|
|
21
|
-
motion: Object.freeze(['none', 'subtle', 'expressive']),
|
|
22
|
-
componentStyle: Object.freeze(['quiet', 'outlined', 'raised'])
|
|
16
|
+
palette: Object.freeze(['default', 'ocean', 'forest', 'plum']),
|
|
17
|
+
theme: Object.freeze(['editorial', 'modern', 'technical']),
|
|
18
|
+
colorMode: Object.freeze(['system', 'light', 'dark'])
|
|
23
19
|
});
|
|
24
20
|
const CONTACT_KEYS = Object.freeze([
|
|
25
21
|
'enabled', 'websiteEnabled', 'phoneEnabled'
|
|
@@ -33,7 +29,14 @@ const CONTACT_KEYS = Object.freeze([
|
|
|
33
29
|
*/
|
|
34
30
|
const REQUIRED_DESIGN = Object.freeze(['layout', 'palette']);
|
|
35
31
|
|
|
32
|
+
/** A free colour, not a menu — but still a colour. */
|
|
33
|
+
const ACCENT = /^#(?:[0-9a-f]{3}|[0-9a-f]{6})$/i;
|
|
34
|
+
|
|
36
35
|
function validateImplementedDesign(config) {
|
|
36
|
+
const accent = config?.design?.accent;
|
|
37
|
+
if (accent !== undefined && !(typeof accent === 'string' && ACCENT.test(accent.trim()))) {
|
|
38
|
+
throw new TypeError(`Unsupported design.accent: ${accent}`);
|
|
39
|
+
}
|
|
37
40
|
if (config?.design == null) return;
|
|
38
41
|
for (const [field, allowed] of Object.entries(DESIGN_VALUES)) {
|
|
39
42
|
const value = config.design[field];
|
|
@@ -1,5 +1,16 @@
|
|
|
1
|
+
import { accentPair } from '../../lib/accent.js';
|
|
1
2
|
import { loadSiteConfiguration } from '../../lib/site-config.js';
|
|
2
3
|
|
|
3
4
|
export default async function siteConfiguration() {
|
|
4
|
-
|
|
5
|
+
const configuration = await loadSiteConfiguration();
|
|
6
|
+
/*
|
|
7
|
+
* The writer picks one colour; the page needs two, because the same colour cannot be readable on
|
|
8
|
+
* both a light and a dark ground. Derived here rather than in CSS so the contrast is exact — a
|
|
9
|
+
* `color-mix()` approximation can land under 4.5:1 and nobody would know until a reader could
|
|
10
|
+
* not read a link.
|
|
11
|
+
*
|
|
12
|
+
* An absent or unparseable value leaves this undefined, and the look's own accent stands.
|
|
13
|
+
*/
|
|
14
|
+
const accent = accentPair(configuration?.design?.accent);
|
|
15
|
+
return accent ? { ...configuration, accent } : configuration;
|
|
5
16
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<!doctype html>
|
|
2
|
-
<html lang="{{ post.language or site.site.defaultLanguage }}" data-theme="{{ site.design.theme }}" data-layout="{{ site.design.layout }}" data-palette="{{ site.design.palette
|
|
2
|
+
<html lang="{{ post.language or site.site.defaultLanguage }}" data-theme="{{ site.design.theme | default('modern') }}" data-layout="{{ site.design.layout }}" data-palette="{{ site.design.palette | default('default') }}" data-mode="{{ site.design.colorMode | default('system') }}"{% if site.accent %} style="--gala-accent-light: {{ site.accent.light }}; --gala-accent-dark: {{ site.accent.dark }}"{% endif %}>
|
|
3
3
|
<head>
|
|
4
4
|
<meta charset="utf-8">
|
|
5
5
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
<link rel="stylesheet" href="{{ '/custom.css' | url }}">
|
|
27
27
|
<script src="{{ '/assets/theme-mode.js' | url }}" defer></script>
|
|
28
28
|
<script src="{{ '/assets/preferences.js' | url }}" defer></script>
|
|
29
|
+
<link rel="icon" href="{{ '/assets/favicon.svg' | url }}" type="image/svg+xml">
|
|
29
30
|
<script src="{{ '/assets/interactions.js' | url }}" defer></script>
|
|
30
31
|
<script type="module" src="{{ '/assets/engagement-comments.js' | url }}"></script>
|
|
31
32
|
<script src="{{ '/assets/search.js' | url }}" defer></script>
|
|
@@ -69,17 +70,12 @@
|
|
|
69
70
|
<dialog id="gala-settings-dialog" class="gala-dialog" aria-labelledby="gala-settings-title">
|
|
70
71
|
<form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close settings">Close</button></form>
|
|
71
72
|
<h2 id="gala-settings-title">Reader settings</h2>
|
|
72
|
-
<section aria-labelledby="gala-dialog-theme-setting">
|
|
73
|
-
<h3 id="gala-dialog-theme-setting">Appearance</h3>
|
|
74
|
-
<button type="button" data-theme-mode-toggle aria-label="Color mode: system. Activate for light."><span data-theme-mode-label>Theme: system</span></button>
|
|
75
|
-
</section>
|
|
76
73
|
<section aria-labelledby="gala-dialog-language-setting">
|
|
77
74
|
<h3 id="gala-dialog-language-setting">Language preference</h3>
|
|
78
75
|
<label>Preferred language
|
|
79
76
|
<select data-language-preference>{% for language in languages %}<option value="{{ language | escape }}">{{ language }}</option>{% endfor %}</select>
|
|
80
77
|
</label>
|
|
81
78
|
</section>
|
|
82
|
-
<p><a href="{{ '/settings/' | url }}">Open settings page</a></p>
|
|
83
79
|
</dialog>
|
|
84
80
|
<dialog id="gala-search-dialog" class="gala-dialog" aria-labelledby="gala-search-title">
|
|
85
81
|
<form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close search">Close</button></form>
|
|
@@ -98,7 +94,7 @@
|
|
|
98
94
|
{% if site.site.id and site.site.id != "unavailable" %}
|
|
99
95
|
<dialog id="gala-account-dialog" class="gala-dialog gala-account-dialog" aria-labelledby="gala-account-title">
|
|
100
96
|
<form method="dialog" class="gala-dialog__close"><button type="submit" aria-label="Close account">Close</button></form>
|
|
101
|
-
<h2 id="gala-account-title">Gala account</h2>
|
|
97
|
+
<h2 id="gala-account-title" class="gala-visually-hidden">Gala account</h2>
|
|
102
98
|
<iframe data-gala-session-frame title="Gala account and sign in" allow="identity-credentials-get" src="{{ site.platform.apiBaseUrl or 'https://api.gala67.com' }}/v1/widget/session?siteId={{ site.site.id | escape }}"></iframe>
|
|
103
99
|
</dialog>
|
|
104
100
|
{% endif %}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32"><rect width="32" height="32" rx="7" fill="#8a4b2a"/><path d="M22 11.5c-1.1-1.3-2.8-2-4.6-2-3.6 0-6.4 2.9-6.4 6.5s2.8 6.5 6.4 6.5c3.2 0 5.6-2 6-5h-5.6" fill="none" stroke="#fdfcfb" stroke-width="2.4" stroke-linecap="round" stroke-linejoin="round"/></svg>
|
|
@@ -392,6 +392,16 @@ if (sessionFrame) {
|
|
|
392
392
|
else pending.reject(new Error(event.data.error?.code || 'ENGAGEMENT_WRITE_FAILED'));
|
|
393
393
|
return;
|
|
394
394
|
}
|
|
395
|
+
/* The frame is cross-origin, so its content height is not readable from here — it reports
|
|
396
|
+
its own, and the box is sized to it. Without this the account panel scrolled inside a fixed
|
|
397
|
+
box, clipping the first line of its own text. */
|
|
398
|
+
if (event.data?.type === 'gala-session-height') {
|
|
399
|
+
const height = Number(event.data.height);
|
|
400
|
+
if (Number.isFinite(height) && height > 0 && height < 2000) {
|
|
401
|
+
sessionFrame.style.height = `${Math.ceil(height)}px`;
|
|
402
|
+
}
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
395
405
|
if (event.data?.type !== 'gala-session') return;
|
|
396
406
|
sessionUser = event.data.user && typeof event.data.user.id === 'string' ? event.data.user : null;
|
|
397
407
|
const control = document.querySelector('[data-user-control]');
|
|
@@ -18,7 +18,9 @@
|
|
|
18
18
|
--gala-color-border: light-dark(#968e86, #6b645e);
|
|
19
19
|
--gala-color-hairline: light-dark(#e8e3dd, #2a2724);
|
|
20
20
|
--gala-color-border-strong: light-dark(#c9c2ba, #46413d);
|
|
21
|
-
--gala-color-accent: light-dark(
|
|
21
|
+
--gala-color-accent: light-dark(
|
|
22
|
+
var(--gala-accent-light, #8a4b2a),
|
|
23
|
+
var(--gala-accent-dark, #e8a87c));
|
|
22
24
|
|
|
23
25
|
/* Type. One scale, used everywhere, fluid between a phone and a desk. */
|
|
24
26
|
--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
|
@@ -48,7 +50,6 @@
|
|
|
48
50
|
--gala-space-page: clamp(1.25rem, 5vw, 4.5rem);
|
|
49
51
|
--gala-radius-control: 0.625rem;
|
|
50
52
|
--gala-radius-surface: 1rem;
|
|
51
|
-
--gala-shadow-low: 0 1px 2px light-dark(rgb(26 24 23 / 6%), rgb(0 0 0 / 40%));
|
|
52
53
|
--gala-shadow-high:
|
|
53
54
|
0 1px 2px light-dark(rgb(26 24 23 / 5%), rgb(0 0 0 / 35%)),
|
|
54
55
|
0 12px 28px -12px light-dark(rgb(26 24 23 / 18%), rgb(0 0 0 / 60%));
|
|
@@ -73,7 +74,7 @@
|
|
|
73
74
|
--gala-color-border: #968e86;
|
|
74
75
|
--gala-color-hairline: #e8e3dd;
|
|
75
76
|
--gala-color-border-strong: #c9c2ba;
|
|
76
|
-
--gala-color-accent: #8a4b2a;
|
|
77
|
+
--gala-color-accent: var(--gala-accent-light, #8a4b2a);
|
|
77
78
|
}
|
|
78
79
|
:root[data-mode='dark'] {
|
|
79
80
|
color-scheme: dark;
|
|
@@ -85,7 +86,7 @@
|
|
|
85
86
|
--gala-color-border: #6b645e;
|
|
86
87
|
--gala-color-hairline: #2a2724;
|
|
87
88
|
--gala-color-border-strong: #46413d;
|
|
88
|
-
--gala-color-accent: #e8a87c;
|
|
89
|
+
--gala-color-accent: var(--gala-accent-dark, #e8a87c);
|
|
89
90
|
}
|
|
90
91
|
|
|
91
92
|
/* ---------------------------------------------------------------- palettes */
|
|
@@ -110,7 +111,7 @@
|
|
|
110
111
|
--gala-color-border: #7d8d99;
|
|
111
112
|
--gala-color-hairline: #dde7ee;
|
|
112
113
|
--gala-color-border-strong: #bdccd7;
|
|
113
|
-
--gala-color-accent: #0f5f7a;
|
|
114
|
+
--gala-color-accent: var(--gala-accent-light, #0f5f7a);
|
|
114
115
|
}
|
|
115
116
|
:root[data-palette='ocean'][data-mode='dark'] {
|
|
116
117
|
color-scheme: dark;
|
|
@@ -122,62 +123,150 @@
|
|
|
122
123
|
--gala-color-border: #5f7d8c;
|
|
123
124
|
--gala-color-hairline: #1d3644;
|
|
124
125
|
--gala-color-border-strong: #33505f;
|
|
125
|
-
--gala-color-accent: #7fd0e8;
|
|
126
|
+
--gala-color-accent: var(--gala-accent-dark, #7fd0e8);
|
|
126
127
|
}
|
|
127
128
|
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
to
|
|
131
|
-
|
|
132
|
-
:root[data-
|
|
129
|
+
|
|
130
|
+
/* Two more, because colour is the choice a writer actually wants to make — and the one that is
|
|
131
|
+
safe to offer, since a palette only swaps values every rule already reads and each is checked
|
|
132
|
+
for contrast in both modes. */
|
|
133
|
+
:root[data-palette='forest'] {
|
|
134
|
+
--gala-color-background: light-dark(#fbfcfa, #101410);
|
|
135
|
+
--gala-color-surface: light-dark(#f0f4ee, #182018);
|
|
136
|
+
--gala-color-raised: light-dark(#ffffff, #1f271f);
|
|
137
|
+
--gala-color-text: light-dark(#18201a, #eef3ec);
|
|
138
|
+
--gala-color-muted: light-dark(#5b665d, #9aa89b);
|
|
139
|
+
--gala-color-border: light-dark(#849084, #5e685f);
|
|
140
|
+
--gala-color-hairline: light-dark(#e2e9df, #232b23);
|
|
141
|
+
--gala-color-border-strong: light-dark(#5b665d, #7d897e);
|
|
142
|
+
--gala-color-accent: light-dark(#2f6b3f, #8fd3a1);
|
|
143
|
+
}
|
|
144
|
+
:root[data-palette='forest'][data-mode='light'] {
|
|
145
|
+
color-scheme: light;
|
|
146
|
+
--gala-color-background: #fbfcfa;
|
|
147
|
+
--gala-color-surface: #f0f4ee;
|
|
148
|
+
--gala-color-raised: #ffffff;
|
|
149
|
+
--gala-color-text: #18201a;
|
|
150
|
+
--gala-color-muted: #5b665d;
|
|
151
|
+
--gala-color-border: #849084;
|
|
152
|
+
--gala-color-hairline: #e2e9df;
|
|
153
|
+
--gala-color-border-strong: #5b665d;
|
|
154
|
+
--gala-color-accent: var(--gala-accent-light, #2f6b3f);
|
|
155
|
+
}
|
|
156
|
+
:root[data-palette='forest'][data-mode='dark'] {
|
|
157
|
+
color-scheme: dark;
|
|
158
|
+
--gala-color-background: #101410;
|
|
159
|
+
--gala-color-surface: #182018;
|
|
160
|
+
--gala-color-raised: #1f271f;
|
|
161
|
+
--gala-color-text: #eef3ec;
|
|
162
|
+
--gala-color-muted: #9aa89b;
|
|
163
|
+
--gala-color-border: #5e685f;
|
|
164
|
+
--gala-color-hairline: #232b23;
|
|
165
|
+
--gala-color-border-strong: #7d897e;
|
|
166
|
+
--gala-color-accent: var(--gala-accent-dark, #8fd3a1);
|
|
167
|
+
}
|
|
168
|
+
:root[data-palette='plum'] {
|
|
169
|
+
--gala-color-background: light-dark(#fdfbfd, #141016);
|
|
170
|
+
--gala-color-surface: light-dark(#f5eff5, #1d1720);
|
|
171
|
+
--gala-color-raised: light-dark(#ffffff, #241d28);
|
|
172
|
+
--gala-color-text: light-dark(#1f1820, #f2ecf3);
|
|
173
|
+
--gala-color-muted: light-dark(#665c69, #a99dac);
|
|
174
|
+
--gala-color-border: light-dark(#948a95, #6b606d);
|
|
175
|
+
--gala-color-hairline: light-dark(#ebe2ec, #281f2b);
|
|
176
|
+
--gala-color-border-strong: light-dark(#665c69, #8b7f8d);
|
|
177
|
+
--gala-color-accent: light-dark(#7a3d76, #dda6d8);
|
|
178
|
+
}
|
|
179
|
+
:root[data-palette='plum'][data-mode='light'] {
|
|
180
|
+
color-scheme: light;
|
|
181
|
+
--gala-color-background: #fdfbfd;
|
|
182
|
+
--gala-color-surface: #f5eff5;
|
|
183
|
+
--gala-color-raised: #ffffff;
|
|
184
|
+
--gala-color-text: #1f1820;
|
|
185
|
+
--gala-color-muted: #665c69;
|
|
186
|
+
--gala-color-border: #948a95;
|
|
187
|
+
--gala-color-hairline: #ebe2ec;
|
|
188
|
+
--gala-color-border-strong: #665c69;
|
|
189
|
+
--gala-color-accent: var(--gala-accent-light, #7a3d76);
|
|
190
|
+
}
|
|
191
|
+
:root[data-palette='plum'][data-mode='dark'] {
|
|
192
|
+
color-scheme: dark;
|
|
193
|
+
--gala-color-background: #141016;
|
|
194
|
+
--gala-color-surface: #1d1720;
|
|
195
|
+
--gala-color-raised: #241d28;
|
|
196
|
+
--gala-color-text: #f2ecf3;
|
|
197
|
+
--gala-color-muted: #a99dac;
|
|
198
|
+
--gala-color-border: #6b606d;
|
|
199
|
+
--gala-color-hairline: #281f2b;
|
|
200
|
+
--gala-color-border-strong: #8b7f8d;
|
|
201
|
+
--gala-color-accent: var(--gala-accent-dark, #dda6d8);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/* ---------------------------------------------------------------- the looks
|
|
205
|
+
*
|
|
206
|
+
* Three, each designed whole.
|
|
207
|
+
*
|
|
208
|
+
* This replaced nine independent knobs — typeface, spacing, density, radius, motion, surfaces,
|
|
209
|
+
* palette — which a writer set one at a time, blind, and only saw combined after a deploy. Nine
|
|
210
|
+
* knobs is several hundred looks, and nobody had seen most of them: `mono` + `round` + `spacious`
|
|
211
|
+
* + `raised` produced monospace headings inside page-wide pills, and it was reachable in four
|
|
212
|
+
* clicks. A look is a set of decisions that agree with each other, so it is chosen as a set.
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
/* Calm, serif, generous. For essays and long reading. */
|
|
216
|
+
:root[data-theme='editorial'] {
|
|
133
217
|
--gala-font-body: ui-serif, "Iowan Old Style", Charter, "Source Serif 4", Georgia, serif;
|
|
134
218
|
--gala-font-display: var(--gala-font-body);
|
|
135
219
|
--gala-weight-display: 600;
|
|
136
|
-
|
|
137
|
-
:
|
|
138
|
-
--gala-
|
|
139
|
-
--gala-
|
|
140
|
-
|
|
141
|
-
:
|
|
142
|
-
--gala-
|
|
143
|
-
--gala-weight-display: 560;
|
|
144
|
-
--gala-tracking-tight: -0.005em;
|
|
220
|
+
--gala-step: 1.1rem;
|
|
221
|
+
--gala-leading-body: 1.7;
|
|
222
|
+
--gala-radius-control: 0.5rem;
|
|
223
|
+
--gala-radius-surface: 0.75rem;
|
|
224
|
+
--gala-measure: 66ch;
|
|
225
|
+
--gala-surface-border: var(--gala-color-hairline);
|
|
226
|
+
--gala-surface-shadow: none;
|
|
145
227
|
}
|
|
146
228
|
|
|
147
|
-
/*
|
|
148
|
-
:root[data-
|
|
149
|
-
--gala-
|
|
150
|
-
--gala-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
--gala-
|
|
154
|
-
--gala-
|
|
229
|
+
/* Crisp, sans, a little tighter. The default, and the safe one. */
|
|
230
|
+
:root[data-theme='modern'] {
|
|
231
|
+
--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", sans-serif;
|
|
232
|
+
--gala-font-display: var(--gala-font-body);
|
|
233
|
+
--gala-weight-display: 640;
|
|
234
|
+
--gala-step: 1rem;
|
|
235
|
+
--gala-leading-body: 1.65;
|
|
236
|
+
--gala-radius-control: 0.625rem;
|
|
237
|
+
--gala-radius-surface: 1rem;
|
|
238
|
+
--gala-measure: 70ch;
|
|
239
|
+
--gala-surface-border: transparent;
|
|
240
|
+
--gala-surface-shadow: var(--gala-shadow-high);
|
|
155
241
|
}
|
|
156
242
|
|
|
157
|
-
/*
|
|
158
|
-
:root[data-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
243
|
+
/* For writing about code: mono for the furniture, never for the prose or the headings. */
|
|
244
|
+
:root[data-theme='technical'] {
|
|
245
|
+
--gala-font-body: ui-sans-serif, -apple-system, "Segoe UI", Roboto, sans-serif;
|
|
246
|
+
--gala-font-display: var(--gala-font-body);
|
|
247
|
+
--gala-weight-display: 660;
|
|
248
|
+
--gala-tracking-tight: -0.022em;
|
|
249
|
+
--gala-step: 0.9rem;
|
|
250
|
+
--gala-leading-body: 1.6;
|
|
251
|
+
--gala-radius-control: 0.375rem;
|
|
252
|
+
--gala-radius-surface: 0.5rem;
|
|
253
|
+
--gala-measure: 74ch;
|
|
254
|
+
--gala-surface-border: var(--gala-color-border-strong);
|
|
255
|
+
--gala-surface-shadow: none;
|
|
256
|
+
}
|
|
257
|
+
/* Mono is an accent here — labels, counts, metadata — not a face to set a page in. */
|
|
258
|
+
:root[data-theme='technical'] .gala-eyebrow,
|
|
259
|
+
:root[data-theme='technical'] .gala-engagement dt,
|
|
260
|
+
:root[data-theme='technical'] .gala-comment__meta time {
|
|
261
|
+
font-family: var(--gala-font-mono);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/* Motion is not a choice a writer has to make; it is a property of a considered page. */
|
|
166
265
|
@media (prefers-reduced-motion: reduce) {
|
|
167
266
|
:root { --gala-motion-fast: 0ms; --gala-motion-base: 0ms; }
|
|
168
267
|
*, *::before, *::after { animation-duration: 1ms !important; transition-duration: 1ms !important; }
|
|
169
268
|
}
|
|
170
269
|
|
|
171
|
-
/* ---------------------------------------------------------------- surfaces
|
|
172
|
-
`quiet` sits on the page, `outlined` draws its edge, `raised` lifts. One variable decides,
|
|
173
|
-
so every card, dialog and chip agrees. */
|
|
174
|
-
:root { --gala-surface-border: var(--gala-color-hairline); --gala-surface-shadow: var(--gala-shadow-low); }
|
|
175
|
-
:root[data-component-style='outlined'] { --gala-surface-border: var(--gala-color-border-strong); }
|
|
176
|
-
:root[data-component-style='raised'] {
|
|
177
|
-
--gala-surface-border: transparent;
|
|
178
|
-
--gala-surface-shadow: var(--gala-shadow-high);
|
|
179
|
-
}
|
|
180
|
-
|
|
181
270
|
:root[data-layout='portfolio'] { --gala-content-width: 82rem; }
|
|
182
271
|
|
|
183
272
|
body {
|
|
@@ -235,13 +324,29 @@ blockquote {
|
|
|
235
324
|
color: var(--gala-color-muted);
|
|
236
325
|
}
|
|
237
326
|
|
|
327
|
+
/*
|
|
328
|
+
* Stays with the reader. It used to scroll away, so on a long post the only way back to the site
|
|
329
|
+
* — or to sign in — was to scroll to the top. The negative inline margin lets the bar's background
|
|
330
|
+
* reach the edge of the viewport while its contents stay on the page's own measure.
|
|
331
|
+
*/
|
|
238
332
|
.gala-site-header {
|
|
333
|
+
position: sticky;
|
|
334
|
+
inset-block-start: 0;
|
|
335
|
+
z-index: 10;
|
|
239
336
|
display: flex;
|
|
240
337
|
align-items: center;
|
|
241
338
|
justify-content: space-between;
|
|
339
|
+
gap: var(--gala-space-md);
|
|
242
340
|
max-inline-size: var(--gala-content-width);
|
|
243
341
|
margin-inline: auto;
|
|
244
|
-
margin-block-end:
|
|
342
|
+
margin-block-end: var(--gala-space-xl);
|
|
343
|
+
padding-block: var(--gala-space-xs);
|
|
344
|
+
background: color-mix(in srgb, var(--gala-color-background) 88%, transparent);
|
|
345
|
+
backdrop-filter: blur(8px);
|
|
346
|
+
border-block-end: 1px solid var(--gala-color-hairline);
|
|
347
|
+
}
|
|
348
|
+
@supports not (backdrop-filter: blur(8px)) {
|
|
349
|
+
.gala-site-header { background: var(--gala-color-background); }
|
|
245
350
|
}
|
|
246
351
|
|
|
247
352
|
.gala-site-header__actions { display: flex; gap: 0.5rem; }
|
|
@@ -279,8 +384,21 @@ blockquote {
|
|
|
279
384
|
box-shadow: var(--gala-shadow-high);
|
|
280
385
|
}
|
|
281
386
|
.gala-dialog::backdrop { background: rgb(0 0 0 / 65%); }
|
|
282
|
-
.
|
|
283
|
-
.gala-account-dialog
|
|
387
|
+
/* Sized to what it holds. 22rem was a box for a name and one button, and it showed. */
|
|
388
|
+
.gala-account-dialog { inline-size: min(26rem, calc(100% - 2rem)); }
|
|
389
|
+
.gala-account-dialog iframe {
|
|
390
|
+
display: block;
|
|
391
|
+
inline-size: 100%;
|
|
392
|
+
/* Height is set from the frame's own report; this is only what it shows before that arrives. */
|
|
393
|
+
block-size: 7rem;
|
|
394
|
+
border: 0;
|
|
395
|
+
/* The frame owns its layout and reports its size, so it never needs to scroll inside the box. */
|
|
396
|
+
overflow: hidden;
|
|
397
|
+
}
|
|
398
|
+
/* The close control belongs on the same line as the title, not floated above it. */
|
|
399
|
+
.gala-dialog { display: grid; gap: var(--gala-space-sm); }
|
|
400
|
+
.gala-dialog__close { justify-self: end; margin: 0; }
|
|
401
|
+
.gala-dialog > h2 { margin-block: 0; }
|
|
284
402
|
|
|
285
403
|
main,
|
|
286
404
|
.gala-page-footer {
|
|
@@ -350,14 +468,11 @@ button:focus-visible {
|
|
|
350
468
|
border-radius: var(--gala-radius-surface);
|
|
351
469
|
box-shadow: var(--gala-surface-shadow);
|
|
352
470
|
}
|
|
353
|
-
[data-component-style='raised'] .gala-card { background: var(--gala-color-raised); }
|
|
354
471
|
/* The one place the page moves of its own accord, and so the one place `motion` is legible:
|
|
355
472
|
`subtle` is a short settle, `expressive` a longer one, `none` no movement at all. */
|
|
356
473
|
.gala-card { transition: transform var(--gala-motion-base) var(--gala-ease),
|
|
357
474
|
box-shadow var(--gala-motion-base) var(--gala-ease); }
|
|
358
475
|
.gala-card-index li:hover .gala-card { transform: translateY(-2px); box-shadow: var(--gala-shadow-high); }
|
|
359
|
-
[data-motion='none'] .gala-card { transition: none; }
|
|
360
|
-
[data-motion='none'] .gala-card-index li:hover .gala-card { transform: none; }
|
|
361
476
|
.gala-stats-graph { min-block-size: var(--gala-widget-min-block-size); margin-inline: 0; }
|
|
362
477
|
.gala-stats-graph svg { inline-size: 100%; block-size: 8rem; }
|
|
363
478
|
.gala-stats-graph polyline { fill: none; stroke: var(--gala-color-accent); stroke-width: 2; }
|
|
@@ -372,23 +487,14 @@ button:focus-visible {
|
|
|
372
487
|
.gala-search-results h2 { margin-block-start: 0; }
|
|
373
488
|
.gala-toc { padding: 1rem; background: var(--gala-color-surface); }
|
|
374
489
|
.gala-share__fallback { inline-size: min(100%, 36rem); }
|
|
375
|
-
.gala-engagement { min-block-size: var(--gala-widget-min-block-size); }
|
|
376
|
-
.gala-engagement dl { display: flex; flex-wrap: wrap; gap: 1rem 2rem; }
|
|
377
|
-
.gala-engagement dl > div { display: grid; gap: 0.25rem; }
|
|
378
|
-
.gala-engagement dd { margin: 0; font-size: 1.25rem; font-weight: 700; }
|
|
379
490
|
.gala-engagement__placeholder { display: grid; min-block-size: var(--gala-widget-min-block-size); align-content: center; margin: 0; }
|
|
380
|
-
.gala-engagement-profile { margin-block: 1.5rem; padding: 1rem; background: var(--gala-color-surface); border-radius: var(--gala-radius-control); }
|
|
381
491
|
.gala-engagement-profile > * { margin-block: 0 0.5rem; }
|
|
382
|
-
.gala-comments { display: grid; gap: 1rem; padding-inline-start: 1.5rem; }
|
|
383
|
-
.gala-comments li { padding: 1rem; background: var(--gala-color-surface); border-radius: var(--gala-radius-control); }
|
|
384
492
|
.gala-engagement-actions { display: grid; gap: 1rem; margin-block-start: 1.5rem; }
|
|
385
493
|
.gala-engagement-actions[hidden] { display: none; }
|
|
386
494
|
/* Shown only when signing in interrupted something the reader had already decided to do, so it
|
|
387
495
|
reassures rather than sells. Hidden for anyone who opened the account dialog deliberately. */
|
|
388
496
|
.gala-account-dialog__invite { margin-block: 0 1rem; max-inline-size: 34rem; }
|
|
389
497
|
.gala-account-dialog__invite[hidden] { display: none; }
|
|
390
|
-
.gala-reaction-actions,
|
|
391
|
-
.gala-comment-actions { display: flex; flex-wrap: wrap; gap: 0.5rem; }
|
|
392
498
|
.gala-engagement-actions form,
|
|
393
499
|
[data-comment-editor] { display: grid; gap: 0.5rem; max-inline-size: 42rem; }
|
|
394
500
|
.gala-engagement-actions label { display: grid; gap: 0.5rem; }
|
|
@@ -522,3 +628,49 @@ button:focus-visible {
|
|
|
522
628
|
font-size: var(--gala-text-sm);
|
|
523
629
|
}
|
|
524
630
|
.gala-comments__more { margin-block-start: var(--gala-space-md); }
|
|
631
|
+
|
|
632
|
+
/* ---------------------------------------------------------------- where the article ends
|
|
633
|
+
The writing and the conversation about it are different things, and the page has to say so.
|
|
634
|
+
A footnote used to run straight into the author card with nothing between them. */
|
|
635
|
+
.gala-engagement {
|
|
636
|
+
/* Space is reserved before the counts arrive, so the page does not jump under the reader. */
|
|
637
|
+
min-block-size: var(--gala-widget-min-block-size);
|
|
638
|
+
max-inline-size: var(--gala-content-width);
|
|
639
|
+
margin-block-start: var(--gala-space-xl);
|
|
640
|
+
padding-block-start: var(--gala-space-lg);
|
|
641
|
+
border-block-start: 1px solid var(--gala-color-border);
|
|
642
|
+
}
|
|
643
|
+
.gala-engagement-profile {
|
|
644
|
+
display: flex;
|
|
645
|
+
align-items: baseline;
|
|
646
|
+
gap: var(--gala-space-sm);
|
|
647
|
+
padding: 0;
|
|
648
|
+
background: none;
|
|
649
|
+
}
|
|
650
|
+
.gala-engagement-profile h2 { font-size: var(--gala-text-lg); margin: 0; }
|
|
651
|
+
.gala-engagement-profile p { margin: 0; color: var(--gala-color-muted); font-size: var(--gala-text-sm); }
|
|
652
|
+
|
|
653
|
+
/* Counts read as data, not as three stacked paragraphs. */
|
|
654
|
+
.gala-engagement dl {
|
|
655
|
+
display: flex;
|
|
656
|
+
flex-wrap: wrap;
|
|
657
|
+
gap: var(--gala-space-lg);
|
|
658
|
+
margin-block: var(--gala-space-md);
|
|
659
|
+
}
|
|
660
|
+
.gala-engagement dl > div { display: flex; flex-direction: column-reverse; gap: 0.1rem; }
|
|
661
|
+
.gala-engagement dt {
|
|
662
|
+
font-size: var(--gala-text-xs);
|
|
663
|
+
letter-spacing: var(--gala-tracking-wide);
|
|
664
|
+
text-transform: uppercase;
|
|
665
|
+
color: var(--gala-color-muted);
|
|
666
|
+
}
|
|
667
|
+
.gala-engagement dd {
|
|
668
|
+
margin: 0;
|
|
669
|
+
font-size: var(--gala-text-lg);
|
|
670
|
+
font-variant-numeric: tabular-nums;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
.gala-reaction-actions { display: flex; flex-wrap: wrap; gap: var(--gala-space-2xs); }
|
|
674
|
+
.gala-engagement-actions { display: grid; gap: var(--gala-space-sm); justify-items: start; }
|
|
675
|
+
.gala-engagement-actions > [data-follow-article] { inline-size: auto; }
|
|
676
|
+
.gala-share { margin-block-start: var(--gala-space-lg); }
|
package/payload/src/settings.njk
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
layout: layouts/base.njk
|
|
3
|
-
title: Settings
|
|
4
|
-
permalink: /settings/index.html
|
|
5
|
-
---
|
|
6
|
-
<h1>Reader settings</h1>
|
|
7
|
-
<section aria-labelledby="theme-setting">
|
|
8
|
-
<h2 id="theme-setting">Theme</h2>
|
|
9
|
-
<button type="button" data-theme-mode-toggle aria-label="Color mode: system. Activate for light.">Theme: system</button>
|
|
10
|
-
</section>
|
|
11
|
-
<section aria-labelledby="language-setting">
|
|
12
|
-
<h2 id="language-setting">Language preference</h2>
|
|
13
|
-
<p>Your preference highlights matching choices. The language in the page URL always controls the content.</p>
|
|
14
|
-
<label>Preferred language
|
|
15
|
-
<select data-language-preference>
|
|
16
|
-
{% for language in languages %}<option value="{{ language | escape }}">{{ language }}</option>{% endfor %}
|
|
17
|
-
</select>
|
|
18
|
-
</label>
|
|
19
|
-
</section>
|