Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions astro.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ export default defineConfig({
apiDocsOnly(rehypeAutolinkHeadings),
{
behavior: "append",
// Only h2+ get anchors. The page's <h1> is its title and getting a
// link to it is meaningless — the page URL already points there.
test: ["h2", "h3", "h4", "h5", "h6"],
properties: {
className: ["heading-anchor"],
"data-anchor-link": true,
Expand Down
90 changes: 90 additions & 0 deletions src/components/docs/heading-anchor-assets.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
---
// Heading-anchor styles + clipboard/scroll JS. Loaded by docs-layout.astro
// only on /docs/api-documentation/ pages.
---

<style is:global>
.heading-anchor {
color: inherit;
text-decoration: none;
}
.heading-anchor:hover,
.heading-anchor:focus {
text-decoration: none;
}
.heading-anchor-icon {
display: inline-block;
margin-left: 0.4em;
font-weight: 400;
color: currentColor;
opacity: 0;
transition:
opacity 150ms ease,
color 150ms ease;
user-select: none;
}
:where(h1, h2, h3, h4, h5, h6):hover .heading-anchor-icon,
.heading-anchor:focus-visible .heading-anchor-icon {
opacity: 0.45;
}
.heading-anchor:hover .heading-anchor-icon {
opacity: 0.85;
}
.heading-anchor[data-copied="true"] .heading-anchor-icon {
opacity: 1;
color: #16a34a;
}
html.dark .heading-anchor[data-copied="true"] .heading-anchor-icon {
color: #4ade80;
}
/* Offset sticky-header height when scrolling to any in-page heading via
URL hash. Mirrors the per-section scroll-mt-28 used on the API reference
page so other docs land below the docs header on refresh. */
:where(h1, h2, h3, h4, h5, h6)[id] {
scroll-margin-top: 7rem;
}
</style>

<script>
// Heading anchor links: native <a href="#id"> handles scroll + URL hash.
// We additionally copy the full deep-link URL to the clipboard and show a
// brief green-checkmark state so users can paste directly into Slack/etc.
document.addEventListener("click", (event) => {
const target = event.target as HTMLElement | null;
const link = target?.closest<HTMLAnchorElement>("[data-anchor-link]");
if (!link) return;
const href = link.getAttribute("href");
if (!href?.startsWith("#")) return;
const url = `${window.location.origin}${window.location.pathname}${href}`;
navigator.clipboard
?.writeText(url)
.then(() => {
link.setAttribute("data-copied", "true");
window.setTimeout(() => link.removeAttribute("data-copied"), 1500);
})
.catch(() => {});
});

// On initial page load with a hash, the browser's native scroll-to-anchor
// sometimes lands before late layout (font loading, hydration of fixed
// panels) settles — leaving the target behind the sticky header. Re-run
// the scroll after `load` and on any hashchange.
function scrollToHash() {
const hash = window.location.hash;
if (!hash || hash.length < 2) return;
let id: string;
try {
id = decodeURIComponent(hash.slice(1));
} catch {
id = hash.slice(1);
}
const el = document.getElementById(id);
if (el) el.scrollIntoView({ block: "start" });
}
if (document.readyState === "complete") {
scrollToHash();
} else {
window.addEventListener("load", scrollToHash, { once: true });
}
window.addEventListener("hashchange", scrollToHash);
</script>
107 changes: 2 additions & 105 deletions src/layouts/docs-layout.astro
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
---
import HeadingAnchorAssets from "@/components/docs/heading-anchor-assets.astro";
import Header from "@/components/docs/header.astro";
import MarketingHeader from "@/components/header/header.astro";

Expand Down Expand Up @@ -55,108 +56,4 @@ const isApiDocs = Astro.url.pathname.startsWith("/docs/api-documentation/");
</div>
</BaseLayout>

{/*
Shareable heading anchors: rehype-autolink-headings injects
<a class="heading-anchor" data-anchor-link><span class="heading-anchor-icon">#</span></a>
after every heading in MD/MDX under api-documentation; .astro pages add
the same markup manually. Styles + clipboard/scroll behaviour are gated
to API docs so non-API docs keep their original heading behaviour.
*/}
{
isApiDocs && (
<style is:global>
{`
.heading-anchor {
color: inherit;
text-decoration: none;
}
.heading-anchor:hover,
.heading-anchor:focus {
text-decoration: none;
}
.heading-anchor-icon {
display: inline-block;
margin-left: 0.4em;
font-weight: 400;
color: currentColor;
opacity: 0;
transition:
opacity 150ms ease,
color 150ms ease;
user-select: none;
}
:where(h1, h2, h3, h4, h5, h6):hover .heading-anchor-icon,
.heading-anchor:focus-visible .heading-anchor-icon {
opacity: 0.45;
}
.heading-anchor:hover .heading-anchor-icon {
opacity: 0.85;
}
.heading-anchor[data-copied="true"] .heading-anchor-icon {
opacity: 1;
color: #16a34a;
}
html.dark .heading-anchor[data-copied="true"] .heading-anchor-icon {
color: #4ade80;
}
/* Offset sticky-header height when scrolling to any in-page heading via
URL hash. Mirrors the per-section scroll-mt-28 used on the API reference
page so other docs land below the docs header on refresh. */
:where(h1, h2, h3, h4, h5, h6)[id] {
scroll-margin-top: 7rem;
}
`}
</style>
)
}

{
isApiDocs && (
<script>
{`
// Heading anchor links: native <a href="#id"> handles scroll + URL hash.
// We additionally copy the full deep-link URL to the clipboard and show a
// brief green-checkmark state so users can paste directly into Slack/etc.
document.addEventListener("click", (event) => {
const target = event.target;
const link = target && target.closest && target.closest("[data-anchor-link]");
if (!link) return;
const href = link.getAttribute("href");
if (!href || !href.startsWith("#")) return;
const url = window.location.origin + window.location.pathname + href;
if (!navigator.clipboard) return;
navigator.clipboard
.writeText(url)
.then(function () {
link.setAttribute("data-copied", "true");
window.setTimeout(function () { link.removeAttribute("data-copied"); }, 1500);
})
.catch(function () {});
});

// On initial page load with a hash, the browser's native scroll-to-anchor
// sometimes lands before late layout (font loading, hydration of fixed
// panels) settles — leaving the target behind the sticky header. Re-run the
// scroll after \`load\` and on any hashchange.
function scrollToHash() {
const hash = window.location.hash;
if (!hash || hash.length < 2) return;
let id;
try {
id = decodeURIComponent(hash.slice(1));
} catch (e) {
id = hash.slice(1);
}
const el = document.getElementById(id);
if (el) el.scrollIntoView({ block: "start" });
}
if (document.readyState === "complete") {
scrollToHash();
} else {
window.addEventListener("load", scrollToHash, { once: true });
}
window.addEventListener("hashchange", scrollToHash);
`}
</script>
)
}
{isApiDocs && <HeadingAnchorAssets />}
12 changes: 2 additions & 10 deletions src/pages/docs/api-documentation/console-api/api-reference.astro
Original file line number Diff line number Diff line change
Expand Up @@ -314,18 +314,10 @@ const sectionsLite = sections.map((s) => ({ id: s.id, title: s.title }));
<Breadcrumbs pathname={pathname} />

<h1
class="group/heading text-3xl font-bold text-foreground md:text-4xl lg:text-5xl"
class="text-3xl font-bold text-foreground md:text-4xl lg:text-5xl"
id="overview"
>
<a
href="#overview"
class="heading-anchor"
data-anchor-link
aria-label={`Link to ${pageTitle}`}
>
{pageTitle}
<span class="heading-anchor-icon" aria-hidden="true">#</span>
</a>
{pageTitle}
</h1>

<p class="mt-4 max-w-3xl text-base text-para md:text-lg">
Expand Down
10 changes: 1 addition & 9 deletions src/pages/docs/api-documentation/getting-started.astro
Original file line number Diff line number Diff line change
Expand Up @@ -236,15 +236,7 @@ const helpLinks = [
<div class="container-reader px-5 md:mt-10">
<div class="flex flex-col items-start">
<h1 id="overview" class="text-3xl font-bold md:text-4xl lg:text-5xl">
<a
href="#overview"
class="heading-anchor"
data-anchor-link
aria-label={`Link to ${pageTitle}`}
>
{pageTitle}
<span class="heading-anchor-icon" aria-hidden="true">#</span>
</a>
{pageTitle}
</h1>
<p class="mt-6 text-base text-para md:text-lg">{pageDescription}</p>
</div>
Expand Down
Loading