@gemboss/website-ui 0.3.0 → 0.5.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/AGENTS.md +20 -5
- package/CHANGELOG.md +93 -0
- package/README.md +36 -13
- package/bin/lib/check.mjs +47 -0
- package/css/article.css +237 -0
- package/css/components.css +15 -0
- package/css/prose.css +29 -16
- package/css/tokens.css +5 -0
- package/demo/article.html +359 -0
- package/demo/assets/article-hero.svg +1 -0
- package/demo/assets/avatar-gemboss.svg +1 -0
- package/demo/assets/post-headless.svg +1 -0
- package/demo/assets/post-motion.svg +1 -0
- package/demo/assets/post-output.svg +1 -0
- package/demo/assets/post-speed.svg +1 -0
- package/demo/assets/post-theme.svg +1 -0
- package/demo/assets/post-voice.svg +1 -0
- package/demo/blog.html +314 -0
- package/demo/index.html +1 -0
- package/docs/components.md +218 -4
- package/docs/markup-contract.md +145 -14
- package/js/website.js +289 -175
- package/js/website.mjs +342 -0
- package/package.json +2 -1
- package/skill/SKILL.md +5 -0
- package/system.json +3 -1
- package/templates/sections/article.html +93 -0
- package/templates/sections/post-list.html +65 -0
- package/website.css +288 -17
- package/website.min.css +1 -1
package/js/website.js
CHANGED
|
@@ -1,186 +1,300 @@
|
|
|
1
|
-
/*! @gemboss/website-ui website.js | spec: docs/markup-contract.md | load with defer */
|
|
1
|
+
/*! @gemboss/website-ui 0.5.0 website.js | GENERATED by scripts/build.mjs from js/website.mjs (the source, with its comments): edit that file | spec: docs/markup-contract.md | load with defer */
|
|
2
2
|
(function () {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
3
|
+
'use strict';
|
|
4
|
+
if (window.gwWebsite) return;
|
|
5
|
+
|
|
6
|
+
var version = '0.5.0';
|
|
7
|
+
var api = { version: version, init: init, destroy: destroy };
|
|
8
|
+
var doc, root, mine, fine, sys, wide, live = [], megaOpen = null, megaTimer = 0, queued = false;
|
|
9
|
+
var READY = 'data-gw-ready';
|
|
10
|
+
|
|
11
|
+
function mq(q) { return window.matchMedia ? matchMedia(q) : { matches: false }; }
|
|
12
|
+
function watch(m, fn) { if (m.addEventListener) m.addEventListener('change', fn); }
|
|
13
|
+
function all(sel, ctx) { return [].slice.call((ctx || doc).querySelectorAll(sel)); }
|
|
14
|
+
function within(sel, ctx) { var l = all(sel, ctx); if (ctx.matches && ctx.matches(sel)) l.unshift(ctx); return l; }
|
|
15
|
+
function on(el, type, fn, opt) { el.addEventListener(type, fn, opt || false); }
|
|
16
|
+
function attr(el, name, dflt) { return el.getAttribute(name) || dflt; }
|
|
17
|
+
function esc(e) { return e.key === 'Escape'; }
|
|
18
|
+
function link(e) { return e.target.closest('a[href]'); }
|
|
19
|
+
function emit(el, type, detail) { if (window.CustomEvent) el.dispatchEvent(new CustomEvent(type, { bubbles: true, detail: detail })); }
|
|
20
|
+
|
|
21
|
+
function each(ctx, sel, kind, fn) { wire(within(sel, ctx), kind, fn); }
|
|
22
|
+
function wire(els, kind, fn) {
|
|
23
|
+
els.forEach(function (el) {
|
|
24
|
+
if (live.some(function (r) { return r.el === el && r.kind === kind; })) return;
|
|
25
|
+
var offs = [], r = fn(el, function (t, type, f, opt) {
|
|
26
|
+
on(t, type, f, opt);
|
|
27
|
+
offs.push(function () { t.removeEventListener(type, f, opt || false); });
|
|
28
|
+
});
|
|
29
|
+
if (!r) return offs.forEach(function (f) { f(); });
|
|
30
|
+
r.el = el; r.kind = kind; r.offs = offs;
|
|
31
|
+
mark(el, kind, true);
|
|
32
|
+
live.push(r);
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function mark(el, kind, add) {
|
|
36
|
+
var l = attr(el, READY, '').split(' ').filter(function (k) { return k && k !== kind; });
|
|
37
|
+
if (add) l.push(kind);
|
|
38
|
+
if (l.length) el.setAttribute(READY, l.join(' ')); else el.removeAttribute(READY);
|
|
39
|
+
}
|
|
40
|
+
function drop(r) {
|
|
41
|
+
if (r.stop) r.stop();
|
|
42
|
+
r.offs.forEach(function (f) { f(); });
|
|
43
|
+
mark(r.el, r.kind);
|
|
44
|
+
live.splice(live.indexOf(r), 1);
|
|
45
|
+
}
|
|
46
|
+
function records(kind, fn) { live.slice().forEach(function (r) { if (r.kind === kind) fn(r); }); }
|
|
47
|
+
|
|
48
|
+
function setMega(m, show, mode) {
|
|
49
|
+
m.p.hidden = !show;
|
|
50
|
+
m.t.setAttribute('aria-expanded', String(show));
|
|
51
|
+
m.item.classList.toggle('is-open', show);
|
|
52
|
+
m.mode = mode;
|
|
53
|
+
megaOpen = show ? m : megaOpen === m ? null : megaOpen;
|
|
54
|
+
emit(m.t, 'gw:mega', { id: m.p.id, open: show });
|
|
55
|
+
}
|
|
56
|
+
function showMega(m, mode) {
|
|
57
|
+
clearTimeout(megaTimer);
|
|
58
|
+
if (megaOpen === m) { if (mode === 'click') m.mode = mode; return; }
|
|
59
|
+
if (megaOpen) setMega(megaOpen, false);
|
|
60
|
+
setMega(m, true, mode);
|
|
61
|
+
}
|
|
62
|
+
function hideMega(focus) {
|
|
63
|
+
var m = megaOpen;
|
|
64
|
+
clearTimeout(megaTimer);
|
|
65
|
+
if (!m) return;
|
|
66
|
+
setMega(m, false);
|
|
67
|
+
if (focus === true) m.t.focus();
|
|
68
|
+
}
|
|
69
|
+
function inside(m, el) { return !!el && (m.item.contains(el) || m.p.contains(el)); }
|
|
70
|
+
function mega(ctx) {
|
|
71
|
+
each(ctx, '[data-gw-mega]', 'mega', function (t, on) {
|
|
72
|
+
var p = doc.getElementById(attr(t, 'data-gw-mega', attr(t, 'aria-controls', '')));
|
|
73
|
+
if (!p) return;
|
|
74
|
+
var m = { t: t, p: p, item: t.closest('.gw-nav__item') || t.parentNode };
|
|
75
|
+
on(t, 'click', function () { if (megaOpen === m && m.mode !== 'hover') hideMega(); else showMega(m, 'click'); });
|
|
76
|
+
(m.item.contains(p) ? [m.item] : [m.item, p]).forEach(function (el) {
|
|
77
|
+
on(el, 'mouseenter', function () {
|
|
78
|
+
if (fine.matches) { clearTimeout(megaTimer); if (megaOpen !== m) megaTimer = setTimeout(function () { showMega(m, 'hover'); }, 80); }
|
|
79
|
+
});
|
|
80
|
+
on(el, 'mouseleave', function () {
|
|
81
|
+
if (fine.matches) { clearTimeout(megaTimer); if (megaOpen === m && m.mode === 'hover') megaTimer = setTimeout(hideMega, 160); }
|
|
53
82
|
});
|
|
54
|
-
on(m.item, 'focusout', function (e) { if (open === m && e.relatedTarget && !inside(m, e.relatedTarget)) hide(); });
|
|
55
|
-
on(m.p, 'click', function (e) { if (link(e)) hide(); });
|
|
56
83
|
});
|
|
57
|
-
on(
|
|
58
|
-
on(
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
84
|
+
on(m.item, 'focusout', function (e) { if (megaOpen === m && e.relatedTarget && !inside(m, e.relatedTarget)) hideMega(); });
|
|
85
|
+
on(p, 'click', function (e) { if (link(e)) hideMega(); });
|
|
86
|
+
m.stop = function () { if (megaOpen === m) hideMega(); };
|
|
87
|
+
return m;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function mobile(ctx) {
|
|
92
|
+
each(ctx, '[data-gw-menu-toggle]', 'menu', function (btn, on) {
|
|
93
|
+
var menu = doc.getElementById(attr(btn, 'aria-controls', 'gw-mobile-menu'));
|
|
65
94
|
if (!menu) return;
|
|
66
95
|
var label = [attr(btn, 'data-gw-label-open', attr(btn, 'aria-label', 'Open menu')), attr(btn, 'data-gw-label-close', 'Close menu')];
|
|
67
|
-
var
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
on(
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
96
|
+
var r = {
|
|
97
|
+
open: function () { return !menu.hidden; },
|
|
98
|
+
set: function (o, focus) {
|
|
99
|
+
menu.hidden = !o;
|
|
100
|
+
btn.setAttribute('aria-expanded', String(o));
|
|
101
|
+
btn.setAttribute('aria-label', label[+o]);
|
|
102
|
+
root.classList.toggle('is-menu-open', o);
|
|
103
|
+
if (focus) btn.focus();
|
|
104
|
+
},
|
|
105
|
+
stop: function () { if (r.open()) r.set(false); }
|
|
106
|
+
};
|
|
107
|
+
on(btn, 'click', function () { r.set(!r.open()); });
|
|
108
|
+
on(menu, 'click', function (e) { if (link(e)) r.set(false); });
|
|
109
|
+
return r;
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
function closeMenus(focus) { records('menu', function (r) { if (r.open()) r.set(false, focus); }); }
|
|
113
|
+
|
|
114
|
+
function dark() { var t = root.getAttribute('data-theme'); return t ? t === 'dark' : sys.matches; }
|
|
115
|
+
function relabel() { records('theme', function (r) { r.el.setAttribute('aria-label', r.labels[+dark()]); }); }
|
|
116
|
+
function theme(ctx) {
|
|
117
|
+
each(ctx, '[data-gw-theme-toggle]', 'theme', function (b, on) {
|
|
118
|
+
var r = { labels: [attr(b, 'data-gw-label-dark', attr(b, 'aria-label', 'Switch to dark theme')), attr(b, 'data-gw-label-light', 'Switch to light theme')] };
|
|
119
|
+
on(b, 'click', function () {
|
|
120
|
+
var next = dark() ? 'light' : 'dark';
|
|
121
|
+
root.setAttribute('data-theme', next);
|
|
122
|
+
try { localStorage.setItem('gw-theme', next); } catch (e) { /* blocked */ }
|
|
123
|
+
relabel();
|
|
124
|
+
emit(root, 'gw:theme', { theme: next });
|
|
90
125
|
});
|
|
91
|
-
function
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
126
|
+
r.stop = function () { b.setAttribute('aria-label', r.labels[0]); };
|
|
127
|
+
return r;
|
|
128
|
+
});
|
|
129
|
+
relabel();
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
function reveal(ctx) {
|
|
133
|
+
var els = [], io = null;
|
|
134
|
+
each(ctx, '.gw-reveal', 'reveal', function (el) { els.push(el); return { stop: function () { if (io) io.unobserve(el); } }; });
|
|
135
|
+
function showAll() { els.forEach(function (el) { el.classList.add('is-in'); }); if (io) io.disconnect(); }
|
|
136
|
+
if (!els.length) return;
|
|
137
|
+
if (!window.IntersectionObserver || mq('(prefers-reduced-motion: reduce)').matches) return showAll();
|
|
138
|
+
io = new IntersectionObserver(function (list) {
|
|
139
|
+
list.forEach(function (en) { if (en.isIntersecting) { en.target.classList.add('is-in'); io.unobserve(en.target); } });
|
|
140
|
+
}, { threshold: 0.15 });
|
|
141
|
+
els.forEach(function (el) { io.observe(el); });
|
|
142
|
+
setTimeout(showAll, 2500);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function scrolled() {
|
|
146
|
+
var s = window.scrollY > 8;
|
|
147
|
+
queued = false;
|
|
148
|
+
records('header', function (r) { if (r.s !== s) r.el.classList.toggle('is-scrolled', (r.s = s)); });
|
|
149
|
+
}
|
|
150
|
+
function header(ctx) {
|
|
151
|
+
each(ctx, '[data-gw-header]', 'header', function (h) { return { s: false, stop: function () { h.classList.remove('is-scrolled'); } }; });
|
|
152
|
+
scrolled();
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function current(ctx) {
|
|
156
|
+
var links = within('.gw-nav__link[href], .gw-mega__link[href]', ctx);
|
|
157
|
+
within('#gw-mobile-menu, .gw-mobile-menu', ctx).forEach(function (m) { links = links.concat(all('a[href]', m)); });
|
|
158
|
+
function norm(p) { return p.replace(/\/index\.html?$/, '/').replace(/\.html?$/, '').replace(/\/+$/, '') || '/'; }
|
|
159
|
+
links.forEach(function (a) { if (mine.has(a)) { mine.delete(a); a.removeAttribute('aria-current'); } });
|
|
160
|
+
if (links.some(function (a) { return a.hasAttribute('aria-current'); })) return;
|
|
161
|
+
links.forEach(function (a) {
|
|
162
|
+
if (a.classList.contains('gw-btn') || a.hash || a.host !== location.host) return;
|
|
163
|
+
if (norm(a.pathname) === norm(location.pathname)) { a.setAttribute('aria-current', 'page'); mine.add(a); }
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
function segmented(ctx) {
|
|
168
|
+
each(ctx, '[data-gw-segmented]', 'segmented', function (g, on) {
|
|
169
|
+
var name = attr(g, 'data-gw-segmented', ''), opts = all('[role="radio"]', g);
|
|
170
|
+
if (!opts.length) return;
|
|
171
|
+
function pick(o, focus, said) {
|
|
172
|
+
var v = attr(o, 'value', '');
|
|
173
|
+
opts.forEach(function (x) { x.setAttribute('aria-checked', String(x === o)); x.setAttribute('tabindex', x === o ? '0' : '-1'); });
|
|
174
|
+
if (focus) o.focus();
|
|
175
|
+
all('[data-gw-show]').forEach(function (el) {
|
|
176
|
+
var own = attr(el, 'data-gw-show', '').split(/\s+/).filter(function (t) { return t.split(':')[0] === name; });
|
|
177
|
+
if (own.length) el.hidden = own.indexOf(name + ':' + v) < 0;
|
|
99
178
|
});
|
|
100
|
-
|
|
101
|
-
watch(sys, relabel);
|
|
102
|
-
relabel();
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// Reveal at 15% visible, once. Failsafe: all shown after 2.5s, or at once without IntersectionObserver.
|
|
106
|
-
function reveal() {
|
|
107
|
-
var els = all('.gw-reveal'), io = null;
|
|
108
|
-
function showAll() { els.forEach(function (el) { el.classList.add('is-in'); }); if (io) io.disconnect(); }
|
|
109
|
-
if (!els.length) return;
|
|
110
|
-
if (!window.IntersectionObserver || mq('(prefers-reduced-motion: reduce)').matches) return showAll();
|
|
111
|
-
io = new IntersectionObserver(function (list) {
|
|
112
|
-
list.forEach(function (en) { if (en.isIntersecting) { en.target.classList.add('is-in'); io.unobserve(en.target); } });
|
|
113
|
-
}, { threshold: 0.15 });
|
|
114
|
-
els.forEach(function (el) { io.observe(el); });
|
|
115
|
-
setTimeout(showAll, 2500);
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
// Header: .is-scrolled past 8px, read once per frame.
|
|
119
|
-
function header() {
|
|
120
|
-
var h = doc.querySelector('[data-gw-header]'), state = false, queued = false;
|
|
121
|
-
if (!h) return;
|
|
122
|
-
function update() {
|
|
123
|
-
var s = window.scrollY > 8;
|
|
124
|
-
queued = false;
|
|
125
|
-
if (s !== state) h.classList.toggle('is-scrolled', (state = s));
|
|
179
|
+
if (said) emit(g, 'gw:segmented', { name: name, value: v });
|
|
126
180
|
}
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
var links = all('.gw-nav__link[href], .gw-mega__link[href]').concat(menu ? all('a[href]', menu) : []);
|
|
135
|
-
function norm(p) { return p.replace(/\/index\.html?$/, '/').replace(/\.html?$/, '').replace(/\/+$/, '') || '/'; }
|
|
136
|
-
if (links.some(function (a) { return a.hasAttribute('aria-current'); })) return;
|
|
137
|
-
links.forEach(function (a) {
|
|
138
|
-
if (a.classList.contains('gw-btn') || a.hash || a.host !== location.host) return;
|
|
139
|
-
if (norm(a.pathname) === norm(location.pathname)) a.setAttribute('aria-current', 'page');
|
|
140
|
-
});
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
// Segmented control: a radio group, one Tab stop; arrows (Home, End) move and choose. What one option shows carries
|
|
144
|
-
// data-gw-show="group:value" and is hidden unless that option is chosen; without the script the markup's own choice shows.
|
|
145
|
-
function segmented() {
|
|
146
|
-
all('[data-gw-segmented]').forEach(function (g) {
|
|
147
|
-
var name = attr(g, 'data-gw-segmented', ''), opts = all('[role="radio"]', g);
|
|
148
|
-
if (!opts.length) return;
|
|
149
|
-
function pick(o, focus, said) {
|
|
150
|
-
var v = attr(o, 'value', '');
|
|
151
|
-
opts.forEach(function (x) { x.setAttribute('aria-checked', String(x === o)); x.setAttribute('tabindex', x === o ? '0' : '-1'); });
|
|
152
|
-
if (focus) o.focus();
|
|
153
|
-
all('[data-gw-show]').forEach(function (el) {
|
|
154
|
-
var mine = attr(el, 'data-gw-show', '').split(/\s+/).filter(function (t) { return t.split(':')[0] === name; });
|
|
155
|
-
if (mine.length) el.hidden = mine.indexOf(name + ':' + v) < 0;
|
|
156
|
-
});
|
|
157
|
-
if (said && window.CustomEvent) g.dispatchEvent(new CustomEvent('gw:segmented', { bubbles: true, detail: { name: name, value: v } }));
|
|
158
|
-
}
|
|
159
|
-
opts.forEach(function (o, i) {
|
|
160
|
-
on(o, 'click', function () { pick(o, false, true); });
|
|
161
|
-
on(o, 'keydown', function (e) {
|
|
162
|
-
var n = opts.length, k = { ArrowRight: i + 1, ArrowDown: i + 1, ArrowLeft: i - 1 + n, ArrowUp: i - 1 + n, Home: 0, End: n - 1 }[e.key];
|
|
163
|
-
if (k === undefined || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
164
|
-
e.preventDefault();
|
|
165
|
-
pick(opts[k % n], true, true);
|
|
166
|
-
});
|
|
181
|
+
opts.forEach(function (o, i) {
|
|
182
|
+
on(o, 'click', function () { pick(o, false, true); });
|
|
183
|
+
on(o, 'keydown', function (e) {
|
|
184
|
+
var n = opts.length, k = { ArrowRight: i + 1, ArrowDown: i + 1, ArrowLeft: i - 1 + n, ArrowUp: i - 1 + n, Home: 0, End: n - 1 }[e.key];
|
|
185
|
+
if (k === undefined || e.altKey || e.ctrlKey || e.metaKey) return;
|
|
186
|
+
e.preventDefault();
|
|
187
|
+
pick(opts[k % n], true, true);
|
|
167
188
|
});
|
|
168
|
-
pick(opts.filter(function (o) { return attr(o, 'aria-checked', '') === 'true'; })[0] || opts[0]);
|
|
169
189
|
});
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
});
|
|
184
|
-
|
|
185
|
-
|
|
190
|
+
pick(opts.filter(function (o) { return attr(o, 'aria-checked', '') === 'true'; })[0] || opts[0]);
|
|
191
|
+
return {};
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
function toc(ctx) {
|
|
196
|
+
each(ctx, '[data-gw-toc]', 'toc', function (nav, on) {
|
|
197
|
+
var box = nav.querySelector('details'), own = !!(box && box.open), cur = null, io = null;
|
|
198
|
+
var items = all('a[href]', nav).map(function (a) {
|
|
199
|
+
var id = attr(a, 'href', '');
|
|
200
|
+
if (id.charAt(0) !== '#') return null;
|
|
201
|
+
try { id = decodeURIComponent(id.slice(1)); } catch (e) { id = id.slice(1); }
|
|
202
|
+
return { a: a, h: doc.getElementById(id) };
|
|
203
|
+
}).filter(function (x) { return x && x.h; });
|
|
204
|
+
if (!items.length) return;
|
|
205
|
+
function update() {
|
|
206
|
+
var line = window.innerHeight * 0.3, top = -Infinity, next = null;
|
|
207
|
+
items.forEach(function (x) { var t = x.h.getBoundingClientRect().top; if (t <= line && t > top) { top = t; next = x; } });
|
|
208
|
+
if (next === cur) return;
|
|
209
|
+
if (cur) cur.a.removeAttribute('aria-current');
|
|
210
|
+
if (next) next.a.setAttribute('aria-current', 'true');
|
|
211
|
+
cur = next;
|
|
212
|
+
emit(nav, 'gw:toc', { id: next ? next.h.id : '' });
|
|
213
|
+
}
|
|
214
|
+
var r = {
|
|
215
|
+
fit: function () { if (box) box.open = wide.matches || own; },
|
|
216
|
+
stop: function () { if (io) io.disconnect(); if (cur) cur.a.removeAttribute('aria-current'); if (box) box.open = own; }
|
|
217
|
+
};
|
|
218
|
+
on(nav, 'click', function (e) { if (box && !wide.matches && link(e)) box.open = false; });
|
|
219
|
+
if (window.IntersectionObserver) {
|
|
220
|
+
io = new IntersectionObserver(update, { rootMargin: '100000px 0px -70% 0px' });
|
|
221
|
+
items.forEach(function (x) { io.observe(x.h); });
|
|
222
|
+
}
|
|
223
|
+
r.fit();
|
|
224
|
+
return r;
|
|
225
|
+
});
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
function words(el) { return el ? el.textContent.replace(/\s+/g, ' ').trim() : ''; }
|
|
229
|
+
function tables(ctx) {
|
|
230
|
+
var list = [];
|
|
231
|
+
within('.gw-prose', ctx).forEach(function (p) {
|
|
232
|
+
list = list.concat([].filter.call(p.children, function (t) { return t.tagName === 'TABLE'; }));
|
|
233
|
+
});
|
|
234
|
+
wire(list, 'table', function (t) {
|
|
235
|
+
var name = words(t.querySelector('caption')) || words(t.querySelector('th')) || words(t.querySelector('td'));
|
|
236
|
+
if (!name) return;
|
|
237
|
+
var box = doc.createElement('div'), had = t.classList.contains('is-wrapped');
|
|
238
|
+
box.className = 'gw-prose__table';
|
|
239
|
+
box.setAttribute('role', 'region');
|
|
240
|
+
box.setAttribute('tabindex', '0');
|
|
241
|
+
box.setAttribute('aria-label', name);
|
|
242
|
+
t.parentNode.insertBefore(box, t);
|
|
243
|
+
box.appendChild(t);
|
|
244
|
+
t.classList.add('is-wrapped');
|
|
245
|
+
return { stop: function () {
|
|
246
|
+
var p = box.parentNode;
|
|
247
|
+
if (p) { p.insertBefore(t, box); p.removeChild(box); }
|
|
248
|
+
if (!had) t.classList.remove('is-wrapped');
|
|
249
|
+
} };
|
|
250
|
+
});
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
function install() {
|
|
254
|
+
doc = document; root = doc.documentElement; mine = new WeakSet();
|
|
255
|
+
fine = mq('(hover: hover) and (pointer: fine)'); sys = mq('(prefers-color-scheme: dark)');
|
|
256
|
+
var stored = null;
|
|
257
|
+
wide = mq('(min-width: 1080px)');
|
|
258
|
+
on(doc, 'click', function (e) { if (megaOpen && !inside(megaOpen, e.target)) hideMega(); });
|
|
259
|
+
on(doc, 'keydown', function (e) { if (megaOpen && esc(e)) hideMega(inside(megaOpen, doc.activeElement) || megaOpen.mode === 'click'); });
|
|
260
|
+
on(doc, 'keydown', function (e) { if (esc(e)) closeMenus(true); });
|
|
261
|
+
watch(wide, function () { if (wide.matches) closeMenus(); records('toc', function (r) { r.fit(); }); });
|
|
262
|
+
on(window, 'pageshow', function (e) { if (e.persisted) closeMenus(); });
|
|
263
|
+
try { stored = localStorage.getItem('gw-theme'); } catch (e) { /* blocked */ }
|
|
264
|
+
if (!root.hasAttribute('data-theme') && /^(light|dark)$/.test(stored)) root.setAttribute('data-theme', stored);
|
|
265
|
+
watch(sys, function () { relabel(); if (!root.hasAttribute('data-theme')) emit(root, 'gw:theme', { theme: dark() ? 'dark' : 'light' }); });
|
|
266
|
+
on(window, 'scroll', function () { if (!queued) { queued = true; requestAnimationFrame(scrolled); } }, { passive: true });
|
|
267
|
+
on(doc, 'click', function (e) {
|
|
268
|
+
var b = e.target.closest && e.target.closest('.gw-btn[aria-busy="true"]');
|
|
269
|
+
if (b) { e.preventDefault(); e.stopPropagation(); }
|
|
270
|
+
}, true);
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
function run(fns, ctx) {
|
|
274
|
+
fns.forEach(function (f) { try { f(ctx); } catch (e) { console.error('[gw-website]', e); } });
|
|
275
|
+
}
|
|
276
|
+
function other() { var g = typeof window != 'undefined' && window.gwWebsite; return g && g !== api && g; }
|
|
277
|
+
|
|
278
|
+
/** Wires the kit's markup under root (default: the whole document). Safe to call again: wires only what is new. */
|
|
279
|
+
function init(ctx) {
|
|
280
|
+
if (typeof document == 'undefined') return;
|
|
281
|
+
var g = other();
|
|
282
|
+
if (g) return g.init && g.init(ctx);
|
|
283
|
+
window.gwWebsite = api;
|
|
284
|
+
if (!doc) run([install]);
|
|
285
|
+
live.slice().forEach(function (r) { if (r.el.isConnected === false) drop(r); });
|
|
286
|
+
run([mega, mobile, theme, reveal, header, current, segmented, toc, tables], ctx && ctx.querySelectorAll ? ctx : doc);
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
/** Takes back what init() wired under root (default: the whole document): listeners and data-gw-ready marks. */
|
|
290
|
+
function destroy(ctx) {
|
|
291
|
+
var g = other();
|
|
292
|
+
if (g) return g.destroy && g.destroy(ctx);
|
|
293
|
+
if (!doc) return;
|
|
294
|
+
ctx = ctx && ctx.querySelectorAll ? ctx : doc;
|
|
295
|
+
live.slice().forEach(function (r) { if (ctx === doc || ctx.contains(r.el)) drop(r); });
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
window.gwWebsite = api;
|
|
299
|
+
if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', function () { init(); }); else init();
|
|
186
300
|
})();
|