diff options
author | (quasar) nebula <qznebula@protonmail.com> | 2023-03-01 16:19:10 -0400 |
---|---|---|
committer | (quasar) nebula <qznebula@protonmail.com> | 2023-03-01 16:19:10 -0400 |
commit | 62f64b3aa019747e9c764eda853591b321850ca0 (patch) | |
tree | 62e183680ebb4bc5a0015eda957ba367ab11030c /src/static | |
parent | 7bf9489f14735f9e44af37f2ade14890a119b403 (diff) | |
parent | 1f0924cc94ea10320afe951a2e8fb4906b5e6106 (diff) |
Merge branch 'preview' into image-overlay
Diffstat (limited to 'src/static')
-rw-r--r-- | src/static/client.js | 77 | ||||
-rw-r--r-- | src/static/site3.css | 58 |
2 files changed, 131 insertions, 4 deletions
diff --git a/src/static/client.js b/src/static/client.js index 9ae5510a..47936d82 100644 --- a/src/static/client.js +++ b/src/static/client.js @@ -444,6 +444,81 @@ if (localStorage.tryInfoCards) { addInfoCardLinkHandlers('track'); } +// Custom hash links -------------------------------------- + +function addHashLinkHandlers() { + // Instead of defining a scroll offset (to account for the sticky heading) + // in JavaScript, we interface with the CSS property 'scroll-margin-top'. + // This lets the scroll offset be consolidated where it makes sense, and + // sets an appropriate offset when (re)loading a page with hash for free! + + let wasHighlighted; + + for (const a of document.links) { + const href = a.getAttribute('href'); + if (!href || !href.startsWith('#')) { + continue; + } + + a.addEventListener('click', handleHashLinkClicked); + } + + function handleHashLinkClicked(evt) { + if (evt.metaKey || evt.shiftKey || evt.ctrlKey || evt.altKey) { + return; + } + + const href = evt.target.getAttribute('href'); + const id = href.slice(1); + const linked = document.getElementById(id); + + if (!linked) { + return; + } + + // Hide skipper box right away, so the layout is updated on time for the + // math operations coming up next. + const skipper = document.getElementById('skippers'); + skipper.style.display = 'none'; + setTimeout(() => skipper.style.display = ''); + + const box = linked.getBoundingClientRect(); + const style = window.getComputedStyle(linked); + + const scrollY = + window.scrollY + + box.top + - style['scroll-margin-top'].replace('px', ''); + + evt.preventDefault(); + history.pushState({}, '', href); + window.scrollTo({top: scrollY, behavior: 'smooth'}); + linked.focus({preventScroll: true}); + + const maxScroll = + document.body.scrollHeight + - window.innerHeight; + + if (scrollY > maxScroll && linked.classList.contains('content-heading')) { + if (wasHighlighted) { + wasHighlighted.classList.remove('highlight-hash-link'); + } + + wasHighlighted = linked; + linked.classList.add('highlight-hash-link'); + linked.addEventListener('animationend', function handle(evt) { + if (evt.animationName === 'highlight-hash-link') { + linked.removeEventListener('animationend', handle); + linked.classList.remove('highlight-hash-link'); + wasHighlighted = null; + } + }); + } + } +} + +addHashLinkHandlers(); + // Sticky content heading --------------------------------- const stickyHeadingInfo = Array.from(document.querySelectorAll('.content-sticky-heading-container')) @@ -510,7 +585,7 @@ function updateStickyHeading() { for (let i = contentHeadings.length - 1; i >= 0; i--) { const heading = contentHeadings[i]; const headingRect = heading.getBoundingClientRect(); - if (headingRect.y + headingRect.height / 1.5 < stickyBottom) { + if (headingRect.y + headingRect.height / 1.5 < stickyBottom + 20) { closestHeading = heading; break; } diff --git a/src/static/site3.css b/src/static/site3.css index 7abb5351..449e6fad 100644 --- a/src/static/site3.css +++ b/src/static/site3.css @@ -208,7 +208,19 @@ body::before { box-shadow: 0 0 40px rgba(0, 0, 0, 0.5); } -#skippers > .skipper:not(:last-child)::after { +#skippers > * { + display: inline-block; +} + +#skippers > .skipper-list:not(:last-child)::after { + display: inline-block; + content: "\00a0"; + margin-left: 2px; + margin-right: -2px; + border-left: 1px dotted; +} + +#skippers .skipper-list > .skipper:not(:last-child)::after { content: " \00b7 "; font-weight: 800; } @@ -342,14 +354,13 @@ body::before { .sidebar > details summary { margin-top: 0.5em; padding-left: 5px; - user-select: none; } .sidebar > details summary .group-name { color: var(--primary-color); } -.sidebar > details summary:hover { +.sidebar > details summary > span:hover { cursor: pointer; text-decoration: underline; text-decoration-color: var(--primary-color); @@ -1138,8 +1149,49 @@ html[data-url-key="localized.home"] .carousel-container { margin-bottom: 0; } +/* Custom hash links */ + +.content-heading { + border-bottom: 3px double transparent; + margin-bottom: -3px; +} + +.content-heading.highlight-hash-link { + animation: highlight-hash-link 4s; + animation-delay: 125ms; +} + +/* This animation's name is referenced in JavaScript */ +@keyframes highlight-hash-link { + 0% { + border-bottom-color: transparent; + } + + 10% { + border-bottom-color: white; + } + + 25% { + border-bottom-color: white; + } + + 100% { + border-bottom-color: transparent; + } +} + /* Sticky heading */ +#content [id] { + /* Adjust scroll margin. */ + scroll-margin-top: calc( + 74px /* Sticky heading */ + + 33px /* Sticky subheading */ + - 1em /* One line of text (align bottom) */ + - 12px /* Padding for hanging letters & focus ring */ + ); +} + .content-sticky-heading-container { position: sticky; top: 0; |