mirror of
https://github.com/qdrant/landing_page.git
synced 2026-09-25 14:08:30 +02:00
Copy heading URL to clipboard on anchor click (#2773)
The AnchorJS link icon already updated the address bar; it now also copies the absolute URL and shows a "Copied" toast at the bottom of the screen. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
0fccb0cac1
commit
d43d4196ca
@@ -113,3 +113,4 @@ body {
|
||||
@import 'partials/footer';
|
||||
@import 'partials/not-found';
|
||||
@import 'partials/go-to-top-button';
|
||||
@import 'partials/anchor-link';
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
// Bottom-of-screen "Copied" confirmation for the heading links added by
|
||||
// assets/js/vendor/anchor.js. That script creates and toggles the element.
|
||||
// Dark in both themes: a light chip is too bright against the dark theme.
|
||||
.anchor-copied-toast {
|
||||
position: fixed;
|
||||
left: 50%;
|
||||
bottom: 28px;
|
||||
z-index: 1000;
|
||||
transform: translate(-50%, 8px);
|
||||
padding: 8px 14px;
|
||||
border-radius: 4px;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
white-space: nowrap;
|
||||
color: $neutral-98;
|
||||
background: $neutral-30;
|
||||
box-shadow: 0 6px 20px rgba(0, 0, 0, 0.28);
|
||||
opacity: 0;
|
||||
pointer-events: none;
|
||||
transition:
|
||||
opacity 0.15s ease,
|
||||
transform 0.15s ease;
|
||||
}
|
||||
|
||||
.anchor-copied-toast--visible {
|
||||
opacity: 1;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
|
||||
// Respect reduced motion preference
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.anchor-copied-toast {
|
||||
transition: none;
|
||||
transform: translate(-50%, 0);
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,59 @@
|
||||
import AnchorJS from 'anchor-js';
|
||||
|
||||
const TOAST_CLASS = 'anchor-copied-toast';
|
||||
const TOAST_VISIBLE_CLASS = 'anchor-copied-toast--visible';
|
||||
const TOAST_DURATION = 1800;
|
||||
|
||||
const anchors = new AnchorJS();
|
||||
anchors.options.placement = 'left';
|
||||
anchors.options.class = 'text-decoration-none';
|
||||
|
||||
let toast = null;
|
||||
let toastTimeout = null;
|
||||
|
||||
// Kept empty until a copy happens, so the live region announces each one.
|
||||
function createToast() {
|
||||
toast = document.createElement('div');
|
||||
toast.className = TOAST_CLASS;
|
||||
toast.setAttribute('aria-live', 'polite');
|
||||
document.body.appendChild(toast);
|
||||
}
|
||||
|
||||
function showToast() {
|
||||
if (!toast) return;
|
||||
|
||||
clearTimeout(toastTimeout);
|
||||
toast.textContent = 'Copied';
|
||||
toast.classList.add(TOAST_VISIBLE_CLASS);
|
||||
|
||||
toastTimeout = setTimeout(() => {
|
||||
toast.classList.remove(TOAST_VISIBLE_CLASS);
|
||||
toast.textContent = '';
|
||||
}, TOAST_DURATION);
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', function (event) {
|
||||
anchors.add('.qdrant-post__body :is(h1, h2, h3, h4, h5, h6)');
|
||||
if (/documentation|articles|course/.test(window.location?.pathname)) {
|
||||
anchors.add('.documentation-article > :is(h1, h2, h3, h4, h5, h6)');
|
||||
}
|
||||
createToast();
|
||||
});
|
||||
|
||||
// Copy the heading URL on click, on top of the address bar update the link
|
||||
// already does natively. Delegated, because anchors.add() injects the links
|
||||
// after this script runs.
|
||||
document.addEventListener('click', async function (event) {
|
||||
const link = event.target.closest('.anchorjs-link');
|
||||
|
||||
if (!link) return;
|
||||
|
||||
try {
|
||||
// link.href is already absolute, and matches what the address bar gets.
|
||||
await navigator.clipboard.writeText(link.href);
|
||||
showToast();
|
||||
} catch (e) {
|
||||
// Clipboard access needs a secure context; the link still works without it.
|
||||
console.error(e);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user