pandorga 1.6.6 → 1.6.8
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +50 -0
- data/README.md +3 -2
- data/_includes/home/band-listing.html +1 -1
- data/_includes/page/content-runtime.html +3 -0
- data/_includes/page/network-graph.html +5 -2
- data/_includes/page/timeline-section.html +13 -1
- data/_includes/theme/favicons.html +3 -1
- data/_includes/theme/font-loader.html +5 -9
- data/_layouts/articles.html +5 -2
- data/_layouts/bibliography.html +5 -2
- data/_layouts/blog.html +5 -2
- data/_layouts/cv.html +5 -2
- data/_layouts/home.html +10 -3
- data/_layouts/projects.html +5 -2
- data/_layouts/resources.html +5 -2
- data/_layouts/shell.html +85 -13
- data/assets/css/ledger/home.css +20 -0
- data/assets/css/ledger/rascunhos.css +40 -2
- data/assets/icons/apple-touch-icon.png +0 -0
- data/assets/icons/favicon-32.png +0 -0
- data/assets/icons/favicon.ico +0 -0
- data/assets/icons/favicon.svg +23 -0
- data/assets/icons/icon-192.png +0 -0
- data/assets/icons/icon-32.png +0 -0
- data/assets/icons/icon-512.png +0 -0
- data/assets/icons/icon-maskable-192.png +0 -0
- data/assets/icons/icon-maskable-512.png +0 -0
- data/assets/icons/studio-apple-touch-icon.png +0 -0
- data/assets/icons/studio-icon-192.png +0 -0
- data/assets/icons/studio-icon-512.png +0 -0
- data/assets/icons/studio-logo-32.png +0 -0
- data/assets/icons/studio-logo.ico +0 -0
- data/assets/icons/studio-logo.svg +25 -5
- data/assets/icons/studio-maskable-192.png +0 -0
- data/assets/icons/studio-maskable-512.png +0 -0
- data/examples/full/content/pages/cv/summary.md +1 -1
- data/lib/pandorga/jekyll/plugins/web_manifest.rb +81 -0
- data/lib/pandorga/version.rb +1 -1
- data/scripts/check_home_lists.mjs +209 -0
- data/scripts/lighthouse-home.sh +9 -1
- data/scripts/render-pwa-icons.py +141 -0
- data/scripts/test/test-home-articles.rb +30 -0
- data/scripts/test/test-home-lists.rb +74 -0
- data/scripts/test/test-lighthouse-policy.rb +13 -6
- data/scripts/test/test-pwa-icons.rb +280 -0
- data/scripts/test/test-rascunhos-licence.rb +43 -0
- data/scripts/validate.sh +4 -0
- data/studio/index.html +4 -1
- data/studio-app/index.html +4 -1
- metadata +24 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 355770a826a6483d7fbc1e014c76fc0ef865d23bba44674cc2153d25ed840a9c
|
|
4
|
+
data.tar.gz: 6fd8451064d1a3bc58a8ff4ed53b90606183644756c28984018ff20ae485a543
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 331cf7a4687f241ee1b653e2435986bd511536ac3d1bfd21b65c91deef8969994999d8d65696e54a5725e7be41169d10ff9abac70475844a018480869cb19c1c
|
|
7
|
+
data.tar.gz: 88fc4c23d1cb5680b054c2e7028e374caab861977114ae235de52547b482de74b0c282957fc5bdf31764c9c3f11e39a65bbd4372ee7ee8fbf397b238b41f1c66
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,55 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [1.6.8] — 2026-10-10
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- Home bands and the other listing pages fill again. Their scripts sit in
|
|
8
|
+
the page and used to run before the runtime existed, then return. The
|
|
9
|
+
titles stayed in the HTML and the lists stayed empty, on the phone and
|
|
10
|
+
on the desktop. Lighthouse scored that empty document. Those scripts
|
|
11
|
+
now start when the runtime is assigned. The runtime stays after the
|
|
12
|
+
page. The static hero summary, the deferred text faces, the deferred
|
|
13
|
+
markdown library, and the named icon subset stay as they are.
|
|
14
|
+
- CI loads the built example home and fails when the projects, articles,
|
|
15
|
+
or posts band has no items after load, on a phone viewport and on a
|
|
16
|
+
desktop viewport.
|
|
17
|
+
- On a phone, the featured card in the home Articles band has more space
|
|
18
|
+
above its text. The other article cards keep their padding. Article
|
|
19
|
+
titles in that band are 2pt larger.
|
|
20
|
+
- On the Rascunhos page, the licence sits under the entries again below
|
|
21
|
+
1024px. The per-page stylesheet split had stopped loading the sheet
|
|
22
|
+
that ordered it, and the page's own `display: block` put it back on
|
|
23
|
+
top. The order now lives on the sheet the blog layout always loads.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- The site and Studio launcher icons are the same stamp, on the same
|
|
28
|
+
plate, in the same pastel triad. The stamp is the same size on both,
|
|
29
|
+
with the same padding, at 512, 192, 180, and 32. Studio adds a small
|
|
30
|
+
badge inside that stamp. The build writes `/site.webmanifest` and
|
|
31
|
+
`/studio.webmanifest` with maskable icons, so Android masks both to
|
|
32
|
+
one shape and one visual size. The shell links the site manifest.
|
|
33
|
+
Studio links the studio manifest.
|
|
34
|
+
|
|
35
|
+
No `pandorga:` config keys were added or renamed.
|
|
36
|
+
|
|
37
|
+
## [1.6.7] — 2026-10-10
|
|
38
|
+
|
|
39
|
+
### Fixed
|
|
40
|
+
|
|
41
|
+
- Text faces are requested after the first paint and before the load
|
|
42
|
+
event. A blocking sheet held first paint on the font host. The load
|
|
43
|
+
event held the hero summary until images finished, so the live home
|
|
44
|
+
scored about 50 while the example, which has no summary, scored 98.
|
|
45
|
+
- The icon face names the icons it needs. The full variable file is about
|
|
46
|
+
a megabyte, and decoding it blocked the main thread on the live home.
|
|
47
|
+
- The project inventory region has a role to match its accessible name.
|
|
48
|
+
- Lighthouse measures `examples/full`, whose home includes a static hero
|
|
49
|
+
summary, the element a real site paints largest.
|
|
50
|
+
|
|
51
|
+
No `pandorga:` config keys were added or renamed.
|
|
52
|
+
|
|
3
53
|
## [1.6.6] — 2026-10-10
|
|
4
54
|
|
|
5
55
|
### Fixed
|
data/README.md
CHANGED
|
@@ -85,8 +85,9 @@ and an urgent performance campaign must then bring it back to 90 or above.
|
|
|
85
85
|
Below 75 is never acceptable for a release. A pull request or a merge may
|
|
86
86
|
score lower when that is unavoidable to keep the work modular. The release
|
|
87
87
|
build publishes at 90 or above. Notes that include `LIGHTHOUSE_BUGFIX=1`
|
|
88
|
-
may publish a bug fix from 75 to 89. Pull requests and merges only warn
|
|
89
|
-
The
|
|
88
|
+
may publish a bug fix from 75 to 89. Pull requests and merges only warn
|
|
89
|
+
on the score. The same run fails when the loaded example home has no
|
|
90
|
+
project or article items. The checklist is in [CONTRIBUTING.md](CONTRIBUTING.md).
|
|
90
91
|
|
|
91
92
|
## License
|
|
92
93
|
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
data-tag-base="{{ _path }}"
|
|
55
55
|
>
|
|
56
56
|
<div class="home-project-specimen-slot" data-home-specimen></div>
|
|
57
|
-
<div class="home-project-inventory" data-home-inventory aria-label="Project inventory"></div>
|
|
57
|
+
<div class="home-project-inventory" data-home-inventory role="region" aria-label="Project inventory"></div>
|
|
58
58
|
</div>
|
|
59
59
|
{%- else -%}
|
|
60
60
|
<div
|
|
@@ -17,4 +17,7 @@
|
|
|
17
17
|
{% include content-runtime/43-blocks.html %}
|
|
18
18
|
{% include content-runtime/90-bootstrap.html %}
|
|
19
19
|
})();
|
|
20
|
+
/* Band and listing scripts sit in the page, so they run before this
|
|
21
|
+
assignment. They listen for the event and start once the runtime exists. */
|
|
22
|
+
document.dispatchEvent(new CustomEvent('pandorga:runtime'));
|
|
20
23
|
</script>
|
|
@@ -454,11 +454,14 @@
|
|
|
454
454
|
|
|
455
455
|
<script src="https://cdn.jsdelivr.net/npm/d3@7.9.0/dist/d3.min.js"></script>
|
|
456
456
|
<script>
|
|
457
|
-
(function () {
|
|
457
|
+
(function bootNetwork() {
|
|
458
458
|
'use strict';
|
|
459
459
|
|
|
460
460
|
var runtime = window.ContentRuntime;
|
|
461
|
-
if (!runtime ||
|
|
461
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
462
|
+
document.addEventListener('pandorga:runtime', bootNetwork, { once: true });
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
462
465
|
|
|
463
466
|
var params = new URLSearchParams(window.location.search);
|
|
464
467
|
var filterRoot = document.querySelector('[data-listing-filter-root]');
|
|
@@ -852,14 +852,26 @@
|
|
|
852
852
|
var runtime = window.ContentRuntime;
|
|
853
853
|
/* The content base is empty when the JSON is served from the site root
|
|
854
854
|
(local preview), which is a valid source, not a missing one — gate on
|
|
855
|
-
the loader instead, and let the catch fall back to the inline stub.
|
|
855
|
+
the loader instead, and let the catch fall back to the inline stub.
|
|
856
|
+
The runtime script follows the page, so the first call waits for it. */
|
|
856
857
|
if (runtime && typeof runtime.loadJson === 'function') {
|
|
858
|
+
loadTimeline.started = true;
|
|
857
859
|
runtime.loadJson('data/timeline.json').then(bootTimeline).catch(function (error) {
|
|
858
860
|
console.error(error);
|
|
859
861
|
if (el) bootTimeline(JSON.parse(el.textContent));
|
|
860
862
|
});
|
|
861
863
|
return;
|
|
862
864
|
}
|
|
865
|
+
if (!loadTimeline.armed) {
|
|
866
|
+
loadTimeline.armed = true;
|
|
867
|
+
document.addEventListener('pandorga:runtime', loadTimeline, { once: true });
|
|
868
|
+
window.setTimeout(function () {
|
|
869
|
+
if (loadTimeline.started || !el) return;
|
|
870
|
+
loadTimeline.started = true;
|
|
871
|
+
bootTimeline(JSON.parse(el.textContent));
|
|
872
|
+
}, 0);
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
863
875
|
if (el) bootTimeline(JSON.parse(el.textContent));
|
|
864
876
|
}
|
|
865
877
|
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
<link rel="icon" href="/assets/icons/favicon.svg" type="image/svg+xml" sizes="any" />
|
|
2
2
|
<link rel="icon" href="/assets/icons/favicon-32.png" type="image/png" sizes="32x32" />
|
|
3
|
-
<link rel="apple-touch-icon" href="/assets/icons/apple-touch-icon.png" />
|
|
3
|
+
<link rel="apple-touch-icon" href="/assets/icons/apple-touch-icon.png" sizes="180x180" />
|
|
4
4
|
<link rel="icon" href="/favicon.ico" sizes="16x16 32x32" />
|
|
5
|
+
<link rel="manifest" href="/site.webmanifest" />
|
|
6
|
+
<meta name="theme-color" content="#5e5d59" />
|
|
@@ -52,16 +52,12 @@
|
|
|
52
52
|
{% endif %}
|
|
53
53
|
{% assign fonts_href = fonts_href | append: "&display=swap" %}
|
|
54
54
|
{% comment %}
|
|
55
|
-
Not a head link
|
|
56
|
-
|
|
57
|
-
|
|
55
|
+
Not a render-blocking head link, and not the load event. A blocking
|
|
56
|
+
sheet holds first paint on the font host. The load event holds the hero
|
|
57
|
+
summary until images finish. The shell inserts this sheet after the
|
|
58
|
+
first paint. display=swap stays.
|
|
58
59
|
{% endcomment %}
|
|
59
60
|
<script>
|
|
60
|
-
window.
|
|
61
|
-
var link = document.createElement('link');
|
|
62
|
-
link.rel = 'stylesheet';
|
|
63
|
-
link.href = {{ fonts_href | jsonify }};
|
|
64
|
-
document.head.appendChild(link);
|
|
65
|
-
});
|
|
61
|
+
window.__pandorgaFontsHref = {{ fonts_href | jsonify }};
|
|
66
62
|
</script>
|
|
67
63
|
<noscript><link rel="stylesheet" href="{{ fonts_href }}" /></noscript>
|
data/_layouts/articles.html
CHANGED
|
@@ -129,11 +129,14 @@ layout: shell
|
|
|
129
129
|
{% include mathjax.html %}
|
|
130
130
|
|
|
131
131
|
<script>
|
|
132
|
-
(function () {
|
|
132
|
+
(function bootArticles() {
|
|
133
133
|
'use strict';
|
|
134
134
|
|
|
135
135
|
var runtime = window.ContentRuntime;
|
|
136
|
-
if (!runtime ||
|
|
136
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
137
|
+
document.addEventListener('pandorga:runtime', bootArticles, { once: true });
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
137
140
|
|
|
138
141
|
var configRoot = document.querySelector('[data-listing-collection]');
|
|
139
142
|
var collection = (configRoot && configRoot.getAttribute('data-listing-collection')) || 'articles';
|
data/_layouts/bibliography.html
CHANGED
|
@@ -24,11 +24,14 @@ layout: shell
|
|
|
24
24
|
</main>
|
|
25
25
|
|
|
26
26
|
<script>
|
|
27
|
-
(function () {
|
|
27
|
+
(function bootBibliography() {
|
|
28
28
|
'use strict';
|
|
29
29
|
|
|
30
30
|
var runtime = window.ContentRuntime;
|
|
31
|
-
if (!runtime ||
|
|
31
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
32
|
+
document.addEventListener('pandorga:runtime', bootBibliography, { once: true });
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
32
35
|
|
|
33
36
|
var listing = runtime.Listing;
|
|
34
37
|
var params = new URLSearchParams(window.location.search);
|
data/_layouts/blog.html
CHANGED
|
@@ -93,11 +93,14 @@ layout: shell
|
|
|
93
93
|
{% include mathjax.html %}
|
|
94
94
|
|
|
95
95
|
<script>
|
|
96
|
-
(function () {
|
|
96
|
+
(function bootBlog() {
|
|
97
97
|
'use strict';
|
|
98
98
|
|
|
99
99
|
var runtime = window.ContentRuntime;
|
|
100
|
-
if (!runtime ||
|
|
100
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
101
|
+
document.addEventListener('pandorga:runtime', bootBlog, { once: true });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
101
104
|
|
|
102
105
|
var configRoot = document.querySelector('[data-listing-collection]');
|
|
103
106
|
var collection = (configRoot && configRoot.getAttribute('data-listing-collection')) || 'posts';
|
data/_layouts/cv.html
CHANGED
|
@@ -80,11 +80,14 @@ layout: shell
|
|
|
80
80
|
</main>
|
|
81
81
|
|
|
82
82
|
<script>
|
|
83
|
-
(function () {
|
|
83
|
+
(function bootCv() {
|
|
84
84
|
'use strict';
|
|
85
85
|
|
|
86
86
|
var runtime = window.ContentRuntime;
|
|
87
|
-
if (!runtime)
|
|
87
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
88
|
+
document.addEventListener('pandorga:runtime', bootCv, { once: true });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
88
91
|
|
|
89
92
|
var experienceList = document.getElementById('cv-experience-list');
|
|
90
93
|
var educationList = document.getElementById('cv-education-list');
|
data/_layouts/home.html
CHANGED
|
@@ -63,8 +63,12 @@ layout: shell
|
|
|
63
63
|
</div>
|
|
64
64
|
</section>
|
|
65
65
|
<script>
|
|
66
|
-
(function () {
|
|
66
|
+
(function bootHomePaint() {
|
|
67
67
|
var runtime = window.ContentRuntime;
|
|
68
|
+
if (!runtime || typeof runtime.renderMarkdown !== 'function') {
|
|
69
|
+
document.addEventListener('pandorga:runtime', bootHomePaint, { once: true });
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
68
72
|
var pre = window.__pandorgaPreload || {};
|
|
69
73
|
function paint(id, path) {
|
|
70
74
|
var el = document.getElementById(id);
|
|
@@ -95,11 +99,14 @@ layout: shell
|
|
|
95
99
|
|
|
96
100
|
<script>
|
|
97
101
|
{% raw %}
|
|
98
|
-
(function () {
|
|
102
|
+
(function bootHomeBands() {
|
|
99
103
|
'use strict';
|
|
100
104
|
|
|
101
105
|
var runtime = window.ContentRuntime;
|
|
102
|
-
if (!runtime)
|
|
106
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
107
|
+
document.addEventListener('pandorga:runtime', bootHomeBands, { once: true });
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
103
110
|
|
|
104
111
|
function asItem(entry) {
|
|
105
112
|
return {
|
data/_layouts/projects.html
CHANGED
|
@@ -59,11 +59,14 @@ layout: shell
|
|
|
59
59
|
</main>
|
|
60
60
|
|
|
61
61
|
<script>
|
|
62
|
-
(function () {
|
|
62
|
+
(function bootProjects() {
|
|
63
63
|
'use strict';
|
|
64
64
|
|
|
65
65
|
var runtime = window.ContentRuntime;
|
|
66
|
-
if (!runtime)
|
|
66
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
67
|
+
document.addEventListener('pandorga:runtime', bootProjects, { once: true });
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
67
70
|
|
|
68
71
|
var esc = runtime.escapeHtml;
|
|
69
72
|
var escAttr = runtime.escapeAttr;
|
data/_layouts/resources.html
CHANGED
|
@@ -34,11 +34,14 @@ layout: shell
|
|
|
34
34
|
</main>
|
|
35
35
|
|
|
36
36
|
<script>
|
|
37
|
-
(function () {
|
|
37
|
+
(function bootResources() {
|
|
38
38
|
'use strict';
|
|
39
39
|
|
|
40
40
|
var runtime = window.ContentRuntime;
|
|
41
|
-
if (!runtime ||
|
|
41
|
+
if (!runtime || typeof runtime.loadJson !== 'function') {
|
|
42
|
+
document.addEventListener('pandorga:runtime', bootResources, { once: true });
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
42
45
|
|
|
43
46
|
var configRoot = document.querySelector('[data-listing-collection]');
|
|
44
47
|
var collection = (configRoot && configRoot.getAttribute('data-listing-collection')) || 'resources';
|
data/_layouts/shell.html
CHANGED
|
@@ -62,7 +62,7 @@
|
|
|
62
62
|
Preconnect only. The preload script below is parser-blocking. A
|
|
63
63
|
stylesheet before that script holds the parser until the font host
|
|
64
64
|
answers, so the ledger sheets and the hero cannot paint. The text-face
|
|
65
|
-
loader sits with the local sheets
|
|
65
|
+
loader sits with the local sheets.
|
|
66
66
|
{%- endcomment -%}
|
|
67
67
|
<link href="https://fonts.googleapis.com" rel="preconnect" />
|
|
68
68
|
<link crossorigin="" href="https://fonts.gstatic.com" rel="preconnect" />
|
|
@@ -85,7 +85,12 @@
|
|
|
85
85
|
{%- assign _ledger = "writing|detail" | split: "|" -%}
|
|
86
86
|
{%- assign _article_css = true -%}
|
|
87
87
|
{%- when "blog" -%}
|
|
88
|
-
{%-
|
|
88
|
+
{%- comment -%}
|
|
89
|
+
writing.css holds the rail, and it has to follow rascunhos.css. The
|
|
90
|
+
body rule in rascunhos.css is `display: block`, which would put the
|
|
91
|
+
licence back above the entries if it won the cascade.
|
|
92
|
+
{%- endcomment -%}
|
|
93
|
+
{%- assign _ledger = "rascunhos|writing|detail" | split: "|" -%}
|
|
89
94
|
{%- assign _article_css = true -%}
|
|
90
95
|
{%- when "cv" -%}
|
|
91
96
|
{%- assign _ledger = "cv|detail" | split: "|" -%}
|
|
@@ -117,20 +122,65 @@
|
|
|
117
122
|
{%- endfor -%}
|
|
118
123
|
{% include theme/font-loader.html %}
|
|
119
124
|
{%- comment -%}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
125
|
+
Named icons only. The full variable face is about a megabyte, and a
|
|
126
|
+
late request for it becomes the largest paint on a real hero. Nav icons
|
|
127
|
+
from the registry join the shell set.
|
|
123
128
|
{%- endcomment -%}
|
|
124
|
-
{%- assign
|
|
129
|
+
{%- assign _icon_names = "arrow_left_alt,arrow_right_alt,architecture,article,chat,chevron_left,chevron_right,close,code,dark_mode,expand_more,filter_list,format_quote,format_size,info,light_mode,menu,picture_as_pdf,public,routine,search,share,shuffle,sync" -%}
|
|
130
|
+
{%- for _group in site.data.nav -%}
|
|
131
|
+
{%- for _item in _group.pages -%}
|
|
132
|
+
{%- if _item.icon -%}
|
|
133
|
+
{%- assign _icon_hay = "," | append: _icon_names | append: "," -%}
|
|
134
|
+
{%- assign _icon_needle = "," | append: _item.icon | append: "," -%}
|
|
135
|
+
{%- unless _icon_hay contains _icon_needle -%}
|
|
136
|
+
{%- assign _icon_names = _icon_names | append: "," | append: _item.icon -%}
|
|
137
|
+
{%- endunless -%}
|
|
138
|
+
{%- endif -%}
|
|
139
|
+
{%- endfor -%}
|
|
140
|
+
{%- endfor -%}
|
|
141
|
+
{%- assign _symbols_href = "https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&icon_names=" | append: _icon_names | append: "&display=swap" -%}
|
|
125
142
|
<script>
|
|
126
|
-
window.
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
143
|
+
window.__pandorgaIconsHref = {{ _symbols_href | jsonify }};
|
|
144
|
+
</script>
|
|
145
|
+
<noscript><link id="pandorga-icons" rel="stylesheet" href="{{ _symbols_href }}" /></noscript>
|
|
146
|
+
<script>
|
|
147
|
+
(function () {
|
|
148
|
+
var known = {{ _icon_names | split: "," | jsonify }};
|
|
149
|
+
var seen = {};
|
|
150
|
+
known.forEach(function (name) { seen[name] = true; });
|
|
151
|
+
var dirty = false;
|
|
152
|
+
var timer = 0;
|
|
153
|
+
window.__pandorgaFlushIcons = function () {
|
|
154
|
+
var link = document.getElementById('pandorga-icons');
|
|
155
|
+
if (!link || !dirty) return;
|
|
156
|
+
dirty = false;
|
|
157
|
+
link.href = 'https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&icon_names=' + known.join(',') + '&display=swap';
|
|
158
|
+
};
|
|
159
|
+
function consider(root) {
|
|
160
|
+
if (!root || !root.querySelectorAll) return;
|
|
161
|
+
var nodes = root.querySelectorAll('.material-symbols-outlined');
|
|
162
|
+
var extra = false;
|
|
163
|
+
for (var i = 0; i < nodes.length; i++) {
|
|
164
|
+
var name = (nodes[i].textContent || '').trim();
|
|
165
|
+
if (!name || seen[name] || !/^[a-z0-9_]+$/.test(name)) continue;
|
|
166
|
+
seen[name] = true;
|
|
167
|
+
known.push(name);
|
|
168
|
+
extra = true;
|
|
169
|
+
}
|
|
170
|
+
if (!extra) return;
|
|
171
|
+
dirty = true;
|
|
172
|
+
clearTimeout(timer);
|
|
173
|
+
timer = setTimeout(window.__pandorgaFlushIcons, 50);
|
|
174
|
+
}
|
|
175
|
+
function start() {
|
|
176
|
+
consider(document);
|
|
177
|
+
var obs = new MutationObserver(function () { consider(document); });
|
|
178
|
+
obs.observe(document.body, { childList: true, subtree: true, characterData: true });
|
|
179
|
+
}
|
|
180
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start);
|
|
181
|
+
else start();
|
|
182
|
+
})();
|
|
132
183
|
</script>
|
|
133
|
-
<noscript><link rel="stylesheet" href="{{ _symbols_href }}" /></noscript>
|
|
134
184
|
{%- assign _flags_href = "https://cdn.jsdelivr.net/gh/lipis/flag-icons@7.2.3/css/flag-icons.min.css" -%}
|
|
135
185
|
<script>
|
|
136
186
|
window.addEventListener('load', function () {
|
|
@@ -265,6 +315,28 @@
|
|
|
265
315
|
{% include page/site-footer.html nav_active=nav_active %}
|
|
266
316
|
|
|
267
317
|
{% include page/content-runtime.html %}
|
|
318
|
+
<script>
|
|
319
|
+
(function () {
|
|
320
|
+
var fonts = window.__pandorgaFontsHref;
|
|
321
|
+
var icons = window.__pandorgaIconsHref;
|
|
322
|
+
if (!fonts && !icons) return;
|
|
323
|
+
requestAnimationFrame(function () {
|
|
324
|
+
requestAnimationFrame(function () {
|
|
325
|
+
function sheet(href, id) {
|
|
326
|
+
if (!href) return;
|
|
327
|
+
var link = document.createElement('link');
|
|
328
|
+
link.rel = 'stylesheet';
|
|
329
|
+
link.href = href;
|
|
330
|
+
if (id) link.id = id;
|
|
331
|
+
document.head.appendChild(link);
|
|
332
|
+
}
|
|
333
|
+
sheet(fonts);
|
|
334
|
+
sheet(icons, 'pandorga-icons');
|
|
335
|
+
if (window.__pandorgaFlushIcons) window.__pandorgaFlushIcons();
|
|
336
|
+
});
|
|
337
|
+
});
|
|
338
|
+
})();
|
|
339
|
+
</script>
|
|
268
340
|
|
|
269
341
|
</body>
|
|
270
342
|
|
data/assets/css/ledger/home.css
CHANGED
|
@@ -740,6 +740,26 @@ html[data-theme="light"] .home-hero-plate {
|
|
|
740
740
|
line-height: var(--home-featured-title-line);
|
|
741
741
|
}
|
|
742
742
|
|
|
743
|
+
/* Articles band only. Two points over the size the title already uses,
|
|
744
|
+
the same point step as the phone hero name. The section heading is
|
|
745
|
+
untouched. Listed cards in other bands are untouched. */
|
|
746
|
+
[data-home-kind="articles"] .home-featured-title {
|
|
747
|
+
font-size: calc(var(--home-featured-title-size) + 2pt);
|
|
748
|
+
}
|
|
749
|
+
|
|
750
|
+
[data-home-kind="articles"] .home-card-grid .card-title,
|
|
751
|
+
[data-home-kind="articles"] .home-card-grid .ledger-card-title {
|
|
752
|
+
font-size: calc(var(--type-card) + 2pt);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
/* Phone only: the featured card's text sat against the top rule. One
|
|
756
|
+
step more than the shared top padding, and only on this card. */
|
|
757
|
+
@media (max-width: 767px) {
|
|
758
|
+
[data-home-kind="articles"] .home-featured {
|
|
759
|
+
padding-top: calc(var(--space-md) + 0.75rem);
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
|
|
743
763
|
/* Home article / rascunho / project cards — content-title voice, not display. */
|
|
744
764
|
.home-card-grid .ledger-card-title,
|
|
745
765
|
.home-card-grid .card-title,
|
|
@@ -66,8 +66,46 @@
|
|
|
66
66
|
display: block;
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
/*
|
|
70
|
-
.
|
|
69
|
+
/* Below 1024px the rail is a disclosure above the ledger, and the licence
|
|
70
|
+
is a child of that rail, so source order paints it above the texts.
|
|
71
|
+
`writing.css` already sets this column, but the per-page split dropped
|
|
72
|
+
that sheet from the blog layout, and this `display: block` beats the
|
|
73
|
+
flex rule whenever rascunhos.css is the later file. The selector here is
|
|
74
|
+
more specific than that block display, so the licence stays under the
|
|
75
|
+
entries even if the sheet list changes again. */
|
|
76
|
+
@media (max-width: 1023px) {
|
|
77
|
+
.rascunhos-main .rascunhos-body {
|
|
78
|
+
display: flex;
|
|
79
|
+
flex-direction: column;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
.rascunhos-main .rascunhos-body>.writing-rail:not([hidden]) {
|
|
83
|
+
display: contents;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.rascunhos-main .rascunhos-body>.rascunhos-ledger {
|
|
87
|
+
order: 1;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
.rascunhos-main .writing-rail-licence {
|
|
91
|
+
order: 2;
|
|
92
|
+
margin-top: var(--space-xl);
|
|
93
|
+
padding-top: var(--space-lg);
|
|
94
|
+
border-top: 1px solid var(--border-gentle-subtle);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
.rascunhos-main .writing-rail-panel {
|
|
98
|
+
margin-bottom: var(--space-xl);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
.rascunhos-main .writing-rail:has(> .writing-rail-panel[hidden]) .writing-rail-trigger {
|
|
102
|
+
margin-bottom: var(--space-xl);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/* `.hidden` swaps the listing for the detail view; it has to beat the
|
|
107
|
+
mobile flex column above, which is why the page class is on the selector. */
|
|
108
|
+
.rascunhos-main .rascunhos-body.hidden {
|
|
71
109
|
display: none;
|
|
72
110
|
}
|
|
73
111
|
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="Site">
|
|
2
|
+
<title>Site</title>
|
|
3
|
+
<style>
|
|
4
|
+
/* Light plate: pastel triad on the dark frame. Dark plate: production triad
|
|
5
|
+
on the light frame. The mark stays inside the maskable safe zone. */
|
|
6
|
+
.primary { fill: #a4c8da; }
|
|
7
|
+
.secondary { fill: #95c8a6; }
|
|
8
|
+
.tertiary { fill: #ddd8a8; }
|
|
9
|
+
.plate { fill: #5e5d59; }
|
|
10
|
+
@media (prefers-color-scheme: dark) {
|
|
11
|
+
.primary { fill: #1c5a7a; }
|
|
12
|
+
.secondary { fill: #287445; }
|
|
13
|
+
.tertiary { fill: #746f30; }
|
|
14
|
+
.plate { fill: #b8b7ae; }
|
|
15
|
+
}
|
|
16
|
+
</style>
|
|
17
|
+
<rect class="plate" width="32" height="32"/>
|
|
18
|
+
<g transform="translate(7.68 7.68) scale(0.52)">
|
|
19
|
+
<polygon class="primary" points="0,0 23,0 15,17 0,20"/>
|
|
20
|
+
<polygon class="secondary" points="23,0 32,0 32,32 17,21 15,17"/>
|
|
21
|
+
<polygon class="tertiary" points="0,20 15,17 17,21 32,32 0,32"/>
|
|
22
|
+
</g>
|
|
23
|
+
</svg>
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-
|
|
2
|
-
<
|
|
3
|
-
<
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 32 32" role="img" aria-label="Studio">
|
|
2
|
+
<title>Studio</title>
|
|
3
|
+
<style>
|
|
4
|
+
/* Same stamp and plate as the site icon. The small badge is the only
|
|
5
|
+
difference. It stays inside the maskable safe zone. */
|
|
6
|
+
.primary { fill: #a4c8da; }
|
|
7
|
+
.secondary { fill: #95c8a6; }
|
|
8
|
+
.tertiary { fill: #ddd8a8; }
|
|
9
|
+
.plate { fill: #5e5d59; }
|
|
10
|
+
.badge { fill: #b8b7ae; }
|
|
11
|
+
@media (prefers-color-scheme: dark) {
|
|
12
|
+
.primary { fill: #1c5a7a; }
|
|
13
|
+
.secondary { fill: #287445; }
|
|
14
|
+
.tertiary { fill: #746f30; }
|
|
15
|
+
.plate { fill: #b8b7ae; }
|
|
16
|
+
.badge { fill: #5e5d59; }
|
|
17
|
+
}
|
|
18
|
+
</style>
|
|
19
|
+
<rect class="plate" width="32" height="32"/>
|
|
20
|
+
<g transform="translate(7.68 7.68) scale(0.52)">
|
|
21
|
+
<polygon class="primary" points="0,0 23,0 15,17 0,20"/>
|
|
22
|
+
<polygon class="secondary" points="23,0 32,0 32,32 17,21 15,17"/>
|
|
23
|
+
<polygon class="tertiary" points="0,20 15,17 17,21 32,32 0,32"/>
|
|
24
|
+
</g>
|
|
25
|
+
<rect class="badge" x="20.32" y="20.32" width="2.88" height="2.88"/>
|
|
6
26
|
</svg>
|
|
Binary file
|
|
Binary file
|
|
@@ -1 +1 @@
|
|
|
1
|
-
Ada Example designs publishing frames. This summary is fictional.
|
|
1
|
+
Ada Example designs publishing frames. This summary is fictional. The home hero includes it as HTML, so the largest paint is this paragraph, the same element a real site measures.
|