diff --git a/site/docs.css b/site/docs.css
index 15f19d8..4b695df 100644
--- a/site/docs.css
+++ b/site/docs.css
@@ -14,6 +14,23 @@
.docs-header a { text-decoration: none; }
.docs-header a:hover { color: #171717; }
+.docs-page .docs-heading-link {
+ margin-left: 4px;
+ color: #88917e;
+ font: inherit;
+ text-decoration: none;
+ opacity: 0;
+}
+
+.docs-page :is(h1, h2, h3, summary):hover > .docs-heading-link,
+.docs-page .docs-heading-link:focus-visible { opacity: 1; }
+
+@media (hover: none) {
+ .docs-page .docs-heading-link { opacity: 1; }
+}
+
+.docs-page :is(h1, h2, h3)[id] { scroll-margin-top: 24px; }
+
.docs-header h1 {
margin: 104px 0 16px;
color: #292d24;
diff --git a/site/pages/docs.tsx b/site/pages/docs.tsx
index b028f54..07ca33b 100644
--- a/site/pages/docs.tsx
+++ b/site/pages/docs.tsx
@@ -11,9 +11,21 @@ const markdownDocs = 'https://github.com/huozhi/devjar/blob/main/docs/MARKDOWN.m
type Feature = { name: string, href: string, summary: string }
-const featureGroups: { title: string, features: Feature[] }[] = [
+function HeadingLink({ hash }: { hash: string }) {
+ return {
+ if (event.currentTarget.closest('summary')) {
+ event.preventDefault()
+ event.stopPropagation()
+ location.hash = hash
+ }
+ void navigator.clipboard?.writeText(new URL(`#${hash}`, location.href).href).catch(() => {})
+ }}>#
+}
+
+const featureGroups: { title: string, id: string, features: Feature[] }[] = [
{
title: 'Live previews',
+ id: 'live-previews',
features: [
{ name: 'DevJar component', href: '#devjar-component', summary: 'Render project files in a managed iframe.' },
{ name: 'useDevJar hook', href: '#use-devjar', summary: 'Own the iframe and decide when code runs.' },
@@ -25,6 +37,7 @@ const featureGroups: { title: string, features: Feature[] }[] = [
},
{
title: 'Static sites',
+ id: 'static-sites',
features: [
{ name: 'File-based routes', href: '#routes', summary: 'Pages, nested routes, and a custom 404.' },
{ name: 'Markdown pages', href: '#markdown', summary: 'Themed HTML pages with no React runtime.' },
@@ -61,7 +74,7 @@ export default function Docs() {