astro-theme-popular 0.9.0 → 0.10.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/package.json
CHANGED
package/scripts/toc.js
CHANGED
|
@@ -13,8 +13,19 @@
|
|
|
13
13
|
var el = document.getElementById(id);
|
|
14
14
|
if (el) { map[id] = a; targets.push(el); }
|
|
15
15
|
});
|
|
16
|
+
/* The sidebar has its own scrollbar when it outgrows the viewport, so
|
|
17
|
+
follow the reader: keep the highlighted entry in view. Done by hand
|
|
18
|
+
rather than with scrollIntoView, which would also scroll the page. */
|
|
19
|
+
function reveal(a) {
|
|
20
|
+
if (!a || toc.scrollHeight <= toc.clientHeight) return;
|
|
21
|
+
var box = toc.getBoundingClientRect();
|
|
22
|
+
var item = a.getBoundingClientRect();
|
|
23
|
+
if (item.top < box.top) toc.scrollTop -= box.top - item.top;
|
|
24
|
+
else if (item.bottom > box.bottom) toc.scrollTop += item.bottom - box.bottom;
|
|
25
|
+
}
|
|
16
26
|
function setActive(id) {
|
|
17
27
|
links.forEach(function (a) { a.classList.toggle("is-active", a === map[id]); });
|
|
28
|
+
reveal(map[id]);
|
|
18
29
|
}
|
|
19
30
|
var obs = new IntersectionObserver(function (entries) {
|
|
20
31
|
entries.forEach(function (e) { if (e.isIntersecting) setActive(e.target.id); });
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
---
|
|
2
|
+
/** PreviewBar: fixed banner rendered ONLY when the config sets
|
|
3
|
+
* `SITE.previewMode` (a generator's throwaway build, shown in an iframe). The
|
|
4
|
+
* config written into an adopter's own repo never sets it, so the banner is
|
|
5
|
+
* structurally incapable of reaching a real site.
|
|
6
|
+
*
|
|
7
|
+
* Informational only, no controls: a preview is served with
|
|
8
|
+
* `sandbox="allow-scripts"` and no allow-same-origin, so a button here could
|
|
9
|
+
* not drive the surrounding page. Actions belong in the chrome outside the
|
|
10
|
+
* iframe. Unlike DemoBar this renders in dev too: someone running the same
|
|
11
|
+
* config locally is previewing as well. Twin of Hugo's preview-bar.html.
|
|
12
|
+
*
|
|
13
|
+
* previewMode accepts `true` or `{ note: 'Expires in 60 minutes.' }`, and
|
|
14
|
+
* POPULAR_PREVIEW_NOTE in the environment does the same for a build whose
|
|
15
|
+
* config someone else owns.
|
|
16
|
+
*/
|
|
17
|
+
import * as cfg from 'popular:config';
|
|
18
|
+
const { SITE, STRINGS } = cfg;
|
|
19
|
+
/* A generator owns the build but not the adopter's config, so the banner can
|
|
20
|
+
also be switched on from the environment: the counterpart of Hugo's
|
|
21
|
+
HUGO_PARAMS_PREVIEWMODE_NOTE. Read at build time, never shipped to the
|
|
22
|
+
client, and absent from any build that did not ask for it. */
|
|
23
|
+
const fromEnv = process.env.POPULAR_PREVIEW_NOTE;
|
|
24
|
+
const preview = (SITE as Record<string, any>).previewMode
|
|
25
|
+
?? (fromEnv ? { note: fromEnv } : null);
|
|
26
|
+
const note = typeof preview === 'object' && preview ? preview.note : undefined;
|
|
27
|
+
/* The demo bar occupies the same corner, and a previewed demo has both on, so
|
|
28
|
+
sit above it rather than on top of it. Matches DemoBar's own rule: it does
|
|
29
|
+
not render in dev. */
|
|
30
|
+
const stacked = !import.meta.env.DEV && !!((cfg as Record<string, any>).DEMO_BAR ?? null);
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
{preview && (
|
|
34
|
+
<>
|
|
35
|
+
<style>
|
|
36
|
+
.g-previewbar { position: fixed; bottom: 14px; left: 50%; transform: translateX(-50%); z-index: 90;
|
|
37
|
+
display: flex; align-items: center; gap: 8px; padding: 8px 16px; max-width: calc(100vw - 28px);
|
|
38
|
+
background: color-mix(in srgb, var(--ink-900) 92%, transparent); color: var(--ink-200);
|
|
39
|
+
border-radius: var(--radius-pill); box-shadow: var(--shadow-lg); font-size: var(--text-xs);
|
|
40
|
+
font-family: var(--font-sans); backdrop-filter: blur(8px); }
|
|
41
|
+
.g-previewbar__label { color: var(--ink-400); font-weight: var(--weight-semibold);
|
|
42
|
+
letter-spacing: var(--tracking-wide); text-transform: uppercase; font-size: 0.65rem; }
|
|
43
|
+
.g-previewbar__note { color: var(--ink-400); }
|
|
44
|
+
@media (max-width: 640px) { .g-previewbar__label { display: none; } }
|
|
45
|
+
/* Reserve space so the fixed bar never covers the footer credit. */
|
|
46
|
+
.g-footer__bottom { padding-bottom: 72px; }
|
|
47
|
+
/* Both bars on the same site: stack, and reserve for both. */
|
|
48
|
+
.g-previewbar--stacked { bottom: 62px; }
|
|
49
|
+
</style>
|
|
50
|
+
{stacked && <style>.g-footer__bottom {'{'} padding-bottom: 120px; {'}'}</style>}
|
|
51
|
+
<div class={`g-previewbar${stacked ? ' g-previewbar--stacked' : ''}`} role="status">
|
|
52
|
+
<i class="fa-solid fa-eye" aria-hidden="true"></i>
|
|
53
|
+
<span class="g-previewbar__label">{STRINGS.previewLabel}</span>
|
|
54
|
+
<span>{STRINGS.previewBanner}</span>
|
|
55
|
+
{note && <span class="g-previewbar__note">{note}</span>}
|
|
56
|
+
</div>
|
|
57
|
+
</>
|
|
58
|
+
)}
|
|
@@ -10,6 +10,7 @@ import '../styles/components.css';
|
|
|
10
10
|
import Header from 'popular:component/Header';
|
|
11
11
|
import Footer from 'popular:component/Footer';
|
|
12
12
|
import DemoBar from '../components/DemoBar.astro';
|
|
13
|
+
import PreviewBar from '../components/PreviewBar.astro';
|
|
13
14
|
import Notice from '../components/Notice.astro';
|
|
14
15
|
import { SITE, BRAND, STRINGS } from 'popular:config';
|
|
15
16
|
import { withBase, absoluteUrl } from '../lib/url';
|
|
@@ -111,5 +112,6 @@ const brandCss = `html:root{${vars.join(';')}}`;
|
|
|
111
112
|
</main>
|
|
112
113
|
<Footer />
|
|
113
114
|
<DemoBar />
|
|
115
|
+
<PreviewBar />
|
|
114
116
|
</body>
|
|
115
117
|
</html>
|
|
@@ -245,7 +245,13 @@ pre:hover .g-copy, .g-copy:focus-visible { opacity: 1; }
|
|
|
245
245
|
|
|
246
246
|
/* ---------- Docs (handbook / runbooks) ---------- */
|
|
247
247
|
.g-doc { display: grid; grid-template-columns: 260px 1fr; gap: var(--space-5); align-items: start; padding-block: var(--space-5) var(--space-6); }
|
|
248
|
-
|
|
248
|
+
/* The sidebar outgrows the viewport on a long page (every h2/h3 of the
|
|
249
|
+
current page nests under its entry). A sticky element taller than the
|
|
250
|
+
viewport cannot be scrolled to its end, so the entries below the fold,
|
|
251
|
+
including the links to the other docs pages, were unreachable without
|
|
252
|
+
scrolling through the whole article first. Cap it to the space under
|
|
253
|
+
the header and give it its own scrollbar. */
|
|
254
|
+
.g-doc-toc { position: sticky; top: 92px; max-height: calc(100vh - 92px - var(--space-4)); overflow-y: auto; overscroll-behavior: contain; scrollbar-width: thin; display: flex; flex-direction: column; gap: 0.15rem; }
|
|
249
255
|
.g-doc-toc__label { font-family: var(--font-display); font-size: var(--text-xs); font-weight: var(--weight-bold); letter-spacing: var(--tracking-wider); text-transform: uppercase; color: var(--text-muted); margin-bottom: 0.6rem; }
|
|
250
256
|
.g-doc-toc a { display: block; padding: 0.4rem 0.7rem; border-radius: var(--radius-md); font-size: var(--text-sm); line-height: 1.3; color: var(--text-body); border-left: 3px solid transparent; }
|
|
251
257
|
.g-doc-toc a:hover { color: var(--color-primary); }
|
|
@@ -306,7 +312,7 @@ pre:hover .g-copy, .g-copy:focus-visible { opacity: 1; }
|
|
|
306
312
|
/* Narrow screens: the sidebar becomes a pill row of sibling doc pages.
|
|
307
313
|
The column labels and per-heading anchors only make sense in a sticky
|
|
308
314
|
sidebar; the headings they point to sit directly below anyway. */
|
|
309
|
-
.g-doc-toc { position: static; flex-direction: row; flex-wrap: wrap; gap: 0.4rem; border-bottom: var(--border-width) solid var(--border-subtle); padding-bottom: 0.8rem; margin-bottom: 1rem; }
|
|
315
|
+
.g-doc-toc { position: static; max-height: none; overflow: visible; flex-direction: row; flex-wrap: wrap; gap: 0.4rem; border-bottom: var(--border-width) solid var(--border-subtle); padding-bottom: 0.8rem; margin-bottom: 1rem; }
|
|
310
316
|
.g-doc-toc__label { display: none; }
|
|
311
317
|
.g-doc-toc a[href^="#"] { display: none; }
|
|
312
318
|
.g-doc-toc a { border: var(--border-width) solid var(--border-subtle); border-radius: var(--radius-pill); padding: 0.3rem 0.8rem; }
|