diff --git a/astro.config.mts b/astro.config.mts index 383fd44..265d163 100644 --- a/astro.config.mts +++ b/astro.config.mts @@ -18,6 +18,10 @@ import icon from 'astro-icon'; import pagefind from 'astro-pagefind'; +import rehypeSlug from 'rehype-slug'; + +import rehypeAutolinkHeadings from 'rehype-autolink-headings'; + import { astroOgImagesGenerator } from 'og-images-generator/astro'; import { paths } from './og-images.config'; @@ -66,6 +70,25 @@ export default defineConfig({ defaultColor: false, transformers: [copyButton()], }, + rehypePlugins: [ + rehypeSlug, + [ + rehypeAutolinkHeadings, + { + behavior: 'prepend', + content: { + type: 'text', + value: '#', + }, + headingProperties: { + className: ['anchor'], + }, + properties: { + className: ['anchor-link'], + }, + }, + ], + ], }, vite: { resolve: { diff --git a/package-lock.json b/package-lock.json index 6576e44..b880646 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,8 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "reading-time": "^1.5.0", + "rehype-autolink-headings": "^7.1.0", + "rehype-slug": "^6.0.0", "swr": "^2.3.0", "tailwindcss": "^3.4.17", "typescript": "^5.7.2" @@ -6076,6 +6078,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-heading-rank": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-3.0.0.tgz", + "integrity": "sha512-EJKb8oMUXVHcWZTDepnr+WNbfnXKFNf9duMesmr4S8SXTJBJ9M4Yok08pu9vxdJwdlGRhVumk9mEhkEvKGifwA==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-is-element": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz", @@ -6234,6 +6249,19 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/hast-util-to-string": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/hast-util-to-string/-/hast-util-to-string-3.0.1.tgz", + "integrity": "sha512-XelQVTDWvqcl3axRfI0xSeoVKzyIFPwsAGSLIsKdJKQMXDYJS4WYrBNF/8J7RdhIcFI2BOHgAifggsvsxp/3+A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/hast-util-to-text": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/hast-util-to-text/-/hast-util-to-text-4.0.2.tgz", @@ -9385,6 +9413,24 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-autolink-headings": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/rehype-autolink-headings/-/rehype-autolink-headings-7.1.0.tgz", + "integrity": "sha512-rItO/pSdvnvsP4QRB1pmPiNHUskikqtPojZKJPPPAVx9Hj8i8TwMBhofrrAYRhYOOBZH9tgmG5lPqDLuIWPWmw==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "@ungap/structured-clone": "^1.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-is-element": "^3.0.0", + "unified": "^11.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-parse": { "version": "9.0.1", "resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-9.0.1.tgz", @@ -9428,6 +9474,23 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/rehype-slug": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/rehype-slug/-/rehype-slug-6.0.0.tgz", + "integrity": "sha512-lWyvf/jwu+oS5+hL5eClVd3hNdmwM1kAC0BUvEGD19pajQMIzcNUd/k9GsfQ+FfECvX+JE+e9/btsKH0EjJT6A==", + "license": "MIT", + "dependencies": { + "@types/hast": "^3.0.0", + "github-slugger": "^2.0.0", + "hast-util-heading-rank": "^3.0.0", + "hast-util-to-string": "^3.0.0", + "unist-util-visit": "^5.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/unified" + } + }, "node_modules/rehype-stringify": { "version": "10.0.1", "resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-10.0.1.tgz", diff --git a/package.json b/package.json index 67913e0..7e2fd9b 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,8 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "reading-time": "^1.5.0", + "rehype-autolink-headings": "^7.1.0", + "rehype-slug": "^6.0.0", "swr": "^2.3.0", "tailwindcss": "^3.4.17", "typescript": "^5.7.2" diff --git a/src/styles/global.scss b/src/styles/global.scss index 6a59709..11809bf 100644 --- a/src/styles/global.scss +++ b/src/styles/global.scss @@ -259,6 +259,10 @@ a, @apply text-blue-800 hover:text-blue-700 focus:text-blue-700 dark:text-blue-300 dark:hover:text-blue-200 dark:focus:text-blue-200; } +.anchor-link { + @apply -ml-6 w-6 inline-block no-underline; +} + [id] { scroll-margin-top: 6rem; }