feat: improved ToC highlighting
This commit is contained in:
parent
b93eddea6b
commit
c2fa587935
16 changed files with 636 additions and 115 deletions
|
@ -14,6 +14,7 @@ import rehypePrettyCode from 'rehype-pretty-code'
|
||||||
import remarkEmoji from 'remark-emoji'
|
import remarkEmoji from 'remark-emoji'
|
||||||
import remarkMath from 'remark-math'
|
import remarkMath from 'remark-math'
|
||||||
import remarkToc from 'remark-toc'
|
import remarkToc from 'remark-toc'
|
||||||
|
import sectionize from '@hbsnow/rehype-sectionize'
|
||||||
|
|
||||||
// https://astro.build/config
|
// https://astro.build/config
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
@ -31,6 +32,8 @@ export default defineConfig({
|
||||||
rehypePlugins: [
|
rehypePlugins: [
|
||||||
rehypeHeadingIds,
|
rehypeHeadingIds,
|
||||||
rehypeKatex,
|
rehypeKatex,
|
||||||
|
// @ts-expect-error
|
||||||
|
sectionize,
|
||||||
[
|
[
|
||||||
rehypePrettyCode,
|
rehypePrettyCode,
|
||||||
{
|
{
|
||||||
|
|
442
package-lock.json
generated
442
package-lock.json
generated
|
@ -17,6 +17,7 @@
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.0",
|
||||||
"@fontsource/geist-mono": "^5.0.3",
|
"@fontsource/geist-mono": "^5.0.3",
|
||||||
"@fontsource/geist-sans": "^5.0.3",
|
"@fontsource/geist-sans": "^5.0.3",
|
||||||
|
"@hbsnow/rehype-sectionize": "^1.0.7",
|
||||||
"@radix-ui/react-avatar": "^1.1.0",
|
"@radix-ui/react-avatar": "^1.1.0",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
|
@ -1182,6 +1183,328 @@
|
||||||
"integrity": "sha512-oGwoSIqNPMvjtCwj1lZaEr47MeiG27XPhypwkF643u1TQduvwbm3V3hYB01JekeaT34SAGP4I1h+WCdRpJkcwA==",
|
"integrity": "sha512-oGwoSIqNPMvjtCwj1lZaEr47MeiG27XPhypwkF643u1TQduvwbm3V3hYB01JekeaT34SAGP4I1h+WCdRpJkcwA==",
|
||||||
"license": "OFL-1.1"
|
"license": "OFL-1.1"
|
||||||
},
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize": {
|
||||||
|
"version": "1.0.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/@hbsnow/rehype-sectionize/-/rehype-sectionize-1.0.7.tgz",
|
||||||
|
"integrity": "sha512-twbVxCFf4YwgTm6FIdGtHfJ14vvIHedk2fqZTpE3X6+vszEeZlMTy7tOyI9KaP/6S2DN2Jnk7zZGtZANTD+vEg==",
|
||||||
|
"dependencies": {
|
||||||
|
"hast-util-heading": "^2.0.1",
|
||||||
|
"hast-util-heading-rank": "^2.1.1",
|
||||||
|
"rehype": "^12.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/@types/hast": {
|
||||||
|
"version": "2.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
|
||||||
|
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/@types/unist": {
|
||||||
|
"version": "2.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
|
||||||
|
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/hast-util-from-parse5": {
|
||||||
|
"version": "7.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-from-parse5/-/hast-util-from-parse5-7.1.2.tgz",
|
||||||
|
"integrity": "sha512-Nz7FfPBuljzsN3tCQ4kCBKqdNhQE2l0Tn+X1ubgKBPRoiDIu1mL08Cfw4k7q71+Duyaw7DXDN+VTAp4Vh3oCOw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"hastscript": "^7.0.0",
|
||||||
|
"property-information": "^6.0.0",
|
||||||
|
"vfile": "^5.0.0",
|
||||||
|
"vfile-location": "^4.0.0",
|
||||||
|
"web-namespaces": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/hast-util-parse-selector": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-parse-selector/-/hast-util-parse-selector-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-jdlwBjEexy1oGz0aJ2f4GKMaVKkA9jwjr4MjAAI22E5fM/TXVZHuS5OpONtdeIkRKqAaryQ2E9xNQxijoThSZA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/hast-util-raw": {
|
||||||
|
"version": "7.2.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-raw/-/hast-util-raw-7.2.3.tgz",
|
||||||
|
"integrity": "sha512-RujVQfVsOrxzPOPSzZFiwofMArbQke6DJjnFfceiEbFh7S05CbPt0cYN+A5YeD3pso0JQk6O1aHBnx9+Pm2uqg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"@types/parse5": "^6.0.0",
|
||||||
|
"hast-util-from-parse5": "^7.0.0",
|
||||||
|
"hast-util-to-parse5": "^7.0.0",
|
||||||
|
"html-void-elements": "^2.0.0",
|
||||||
|
"parse5": "^6.0.0",
|
||||||
|
"unist-util-position": "^4.0.0",
|
||||||
|
"unist-util-visit": "^4.0.0",
|
||||||
|
"vfile": "^5.0.0",
|
||||||
|
"web-namespaces": "^2.0.0",
|
||||||
|
"zwitch": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/hast-util-to-html": {
|
||||||
|
"version": "8.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-to-html/-/hast-util-to-html-8.0.4.tgz",
|
||||||
|
"integrity": "sha512-4tpQTUOr9BMjtYyNlt0P50mH7xj0Ks2xpo8M943Vykljf99HW6EzulIoJP1N3eKOSScEHzyzi9dm7/cn0RfGwA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"ccount": "^2.0.0",
|
||||||
|
"comma-separated-tokens": "^2.0.0",
|
||||||
|
"hast-util-raw": "^7.0.0",
|
||||||
|
"hast-util-whitespace": "^2.0.0",
|
||||||
|
"html-void-elements": "^2.0.0",
|
||||||
|
"property-information": "^6.0.0",
|
||||||
|
"space-separated-tokens": "^2.0.0",
|
||||||
|
"stringify-entities": "^4.0.0",
|
||||||
|
"zwitch": "^2.0.4"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/hast-util-to-parse5": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-to-parse5/-/hast-util-to-parse5-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-YNRgAJkH2Jky5ySkIqFXTQiaqcAtJyVE+D5lkN6CdtOqrnkLfGYYrEcKuHOJZlp+MwjSwuD3fZuawI+sic/RBw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"comma-separated-tokens": "^2.0.0",
|
||||||
|
"property-information": "^6.0.0",
|
||||||
|
"space-separated-tokens": "^2.0.0",
|
||||||
|
"web-namespaces": "^2.0.0",
|
||||||
|
"zwitch": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/hast-util-whitespace": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-whitespace/-/hast-util-whitespace-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==",
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/hastscript": {
|
||||||
|
"version": "7.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/hastscript/-/hastscript-7.2.0.tgz",
|
||||||
|
"integrity": "sha512-TtYPq24IldU8iKoJQqvZOuhi5CyCQRAbvDOX0x1eW6rsHSxa/1i2CCiptNTotGHJ3VoHRGmqiv6/D3q113ikkw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"comma-separated-tokens": "^2.0.0",
|
||||||
|
"hast-util-parse-selector": "^3.0.0",
|
||||||
|
"property-information": "^6.0.0",
|
||||||
|
"space-separated-tokens": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/html-void-elements": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/html-void-elements/-/html-void-elements-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-0quDb7s97CfemeJAnW9wC0hw78MtW7NU3hqtCD75g2vFlDLt36llsYD7uB7SUzojLMP24N5IatXf7ylGXiGG9A==",
|
||||||
|
"funding": {
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/wooorm"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/parse5": {
|
||||||
|
"version": "6.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/parse5/-/parse5-6.0.1.tgz",
|
||||||
|
"integrity": "sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw=="
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/rehype": {
|
||||||
|
"version": "12.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rehype/-/rehype-12.0.1.tgz",
|
||||||
|
"integrity": "sha512-ey6kAqwLM3X6QnMDILJthGvG1m1ULROS9NT4uG9IDCuv08SFyLlreSuvOa//DgEvbXx62DS6elGVqusWhRUbgw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"rehype-parse": "^8.0.0",
|
||||||
|
"rehype-stringify": "^9.0.0",
|
||||||
|
"unified": "^10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/rehype-parse": {
|
||||||
|
"version": "8.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/rehype-parse/-/rehype-parse-8.0.5.tgz",
|
||||||
|
"integrity": "sha512-Ds3RglaY/+clEX2U2mHflt7NlMA72KspZ0JLUJgBBLpRddBcEw3H8uYZQliQriku22NZpYMfjDdSgHcjxue24A==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"hast-util-from-parse5": "^7.0.0",
|
||||||
|
"parse5": "^6.0.0",
|
||||||
|
"unified": "^10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/rehype-stringify": {
|
||||||
|
"version": "9.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/rehype-stringify/-/rehype-stringify-9.0.4.tgz",
|
||||||
|
"integrity": "sha512-Uk5xu1YKdqobe5XpSskwPvo1XeHUUucWEQSl8hTrXt5selvca1e8K1EZ37E6YoZ4BT8BCqCdVfQW7OfHfthtVQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"hast-util-to-html": "^8.0.0",
|
||||||
|
"unified": "^10.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/unified": {
|
||||||
|
"version": "10.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/unified/-/unified-10.1.2.tgz",
|
||||||
|
"integrity": "sha512-pUSWAi/RAnVy1Pif2kAoeWNBa3JVrx0MId2LASj8G+7AiHWoKZNTomq6LG326T68U7/e263X6fTdcXIy7XnF7Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"bail": "^2.0.0",
|
||||||
|
"extend": "^3.0.0",
|
||||||
|
"is-buffer": "^2.0.0",
|
||||||
|
"is-plain-obj": "^4.0.0",
|
||||||
|
"trough": "^2.0.0",
|
||||||
|
"vfile": "^5.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/unist-util-is": {
|
||||||
|
"version": "5.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-is/-/unist-util-is-5.2.1.tgz",
|
||||||
|
"integrity": "sha512-u9njyyfEh43npf1M+yGKDGVPbY/JWEemg5nH05ncKPfi+kBbKBJoTdsogMu33uhytuLlv9y0O7GH7fEdwLdLQw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/unist-util-position": {
|
||||||
|
"version": "4.0.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-position/-/unist-util-position-4.0.4.tgz",
|
||||||
|
"integrity": "sha512-kUBE91efOWfIVBo8xzh/uZQ7p9ffYRtUbMRZBNFYwf0RK8koUMx6dGUfwylLOKmaT2cs4wSW96QoYUSXAyEtpg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/unist-util-stringify-position": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-stringify-position/-/unist-util-stringify-position-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-k5GzIBZ/QatR8N5X2y+drfpWG8IDBzdnVj6OInRNWm1oXrzydiaAT2OQiA8DPRRZyAKb9b6I2a6PxYklZD0gKg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/unist-util-visit": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"unist-util-is": "^5.0.0",
|
||||||
|
"unist-util-visit-parents": "^5.1.1"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/unist-util-visit-parents": {
|
||||||
|
"version": "5.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/unist-util-visit-parents/-/unist-util-visit-parents-5.1.3.tgz",
|
||||||
|
"integrity": "sha512-x6+y8g7wWMyQhL1iZfhIPhDAs7Xwbn9nRosDXl7qoPTSCy0yNxnKc+hWokFifWQIDGi154rdUqKvbCa4+1kLhg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"unist-util-is": "^5.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/vfile": {
|
||||||
|
"version": "5.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile/-/vfile-5.3.7.tgz",
|
||||||
|
"integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"is-buffer": "^2.0.0",
|
||||||
|
"unist-util-stringify-position": "^3.0.0",
|
||||||
|
"vfile-message": "^3.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/vfile-location": {
|
||||||
|
"version": "4.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile-location/-/vfile-location-4.1.0.tgz",
|
||||||
|
"integrity": "sha512-YF23YMyASIIJXpktBa4vIGLJ5Gs88UB/XePgqPmTa7cDA+JeO3yclbpheQYCHjVHBn/yePzrXuygIL+xbvRYHw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"vfile": "^5.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@hbsnow/rehype-sectionize/node_modules/vfile-message": {
|
||||||
|
"version": "3.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/vfile-message/-/vfile-message-3.1.4.tgz",
|
||||||
|
"integrity": "sha512-fa0Z6P8HUrQN4BZaX05SIVXic+7kE3b05PWAtPuYP9QLHsLKYR7/AlLW3NtOrpXRLeawpDLMsVkmk5DG0NXgWw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2.0.0",
|
||||||
|
"unist-util-stringify-position": "^3.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@img/sharp-darwin-arm64": {
|
"node_modules/@img/sharp-darwin-arm64": {
|
||||||
"version": "0.33.4",
|
"version": "0.33.4",
|
||||||
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz",
|
"resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.4.tgz",
|
||||||
|
@ -2867,6 +3190,11 @@
|
||||||
"undici-types": "~5.26.4"
|
"undici-types": "~5.26.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@types/parse5": {
|
||||||
|
"version": "6.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/parse5/-/parse5-6.0.3.tgz",
|
||||||
|
"integrity": "sha512-SuT16Q1K51EAVPz1K29DJ/sXjhSQ0zjvsypYJ6tlwVsRV9jwW5Adq2ch8Dq8kDBCkYnELS7N7VNCSB5nC56t/g=="
|
||||||
|
},
|
||||||
"node_modules/@types/prop-types": {
|
"node_modules/@types/prop-types": {
|
||||||
"version": "15.7.12",
|
"version": "15.7.12",
|
||||||
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
"resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.12.tgz",
|
||||||
|
@ -4087,10 +4415,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/dset": {
|
"node_modules/dset": {
|
||||||
"version": "3.1.3",
|
"version": "3.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/dset/-/dset-3.1.4.tgz",
|
||||||
"integrity": "sha512-20TuZZHCEZ2O71q9/+8BwKwZ0QtD9D8ObhrihJPr+vLLYlSuAU3/zL4cSlgbfeoGHTjCSJBa7NGcrF9/Bx/WJQ==",
|
"integrity": "sha512-2QF/g9/zTaPDc3BjNcVTGoBbXBgYfMTTceLaYcFJ/W9kggFUkhxD/hMEeuLKbugyef9SqAx8cpgwlIP/jinUTA==",
|
||||||
"license": "MIT",
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=4"
|
"node": ">=4"
|
||||||
}
|
}
|
||||||
|
@ -4371,9 +4698,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/fast-xml-parser": {
|
"node_modules/fast-xml-parser": {
|
||||||
"version": "4.4.0",
|
"version": "4.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.5.0.tgz",
|
||||||
"integrity": "sha512-kLY3jFlwIYwBNDojclKsNAC12sfD6NwW74QB2CoNGPvtVxjliYehVunB3HYyNi+n4Tt1dAcgwYvmKF/Z18flqg==",
|
"integrity": "sha512-/PlTQCI96+fZMAOLMZK4CWG1ItCbfZ/0jx7UIJFChPNrx7tcEgerUgWbeieCM9MfHInUDyK8DWYZ+YrywDJuTg==",
|
||||||
"funding": [
|
"funding": [
|
||||||
{
|
{
|
||||||
"type": "github",
|
"type": "github",
|
||||||
|
@ -4384,7 +4711,6 @@
|
||||||
"url": "https://paypal.me/naturalintelligence"
|
"url": "https://paypal.me/naturalintelligence"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"strnum": "^1.0.5"
|
"strnum": "^1.0.5"
|
||||||
},
|
},
|
||||||
|
@ -4731,6 +5057,70 @@
|
||||||
"url": "https://opencollective.com/unified"
|
"url": "https://opencollective.com/unified"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/hast-util-heading": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-heading/-/hast-util-heading-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-nwRggTanShzHRYMUX46lm6pbJ2c1+TUQCETahENb6yR6c8ro8MkE0hRJm8G0IqAZl35ONgJiW8RC8+D3484vYg==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"hast-util-is-element": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hast-util-heading-rank": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-heading-rank/-/hast-util-heading-rank-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-iAuRp+ESgJoRFJbSyaqsfvJDY6zzmFoEnL1gtz1+U8gKtGGj1p0CVlysuUAUjq95qlZESHINLThwJzNGmgGZxA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hast-util-heading-rank/node_modules/@types/hast": {
|
||||||
|
"version": "2.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
|
||||||
|
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hast-util-heading-rank/node_modules/@types/unist": {
|
||||||
|
"version": "2.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
|
||||||
|
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="
|
||||||
|
},
|
||||||
|
"node_modules/hast-util-heading/node_modules/@types/hast": {
|
||||||
|
"version": "2.3.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/hast/-/hast-2.3.10.tgz",
|
||||||
|
"integrity": "sha512-McWspRw8xx8J9HurkVBfYj0xKoE25tOFlHGdx4MJ5xORQrMGZNqJhVQWaIbm6Oyla5kYOXtDiopzKRJzEOkwJw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/unist": "^2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/hast-util-heading/node_modules/@types/unist": {
|
||||||
|
"version": "2.0.11",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.11.tgz",
|
||||||
|
"integrity": "sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA=="
|
||||||
|
},
|
||||||
|
"node_modules/hast-util-heading/node_modules/hast-util-is-element": {
|
||||||
|
"version": "2.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-2.1.3.tgz",
|
||||||
|
"integrity": "sha512-O1bKah6mhgEq2WtVMk+Ta5K7pPMqsBBlmzysLdcwKVrqzZQ0CHqUPiIVspNhAG1rvxpvJjtGee17XfauZYKqVA==",
|
||||||
|
"dependencies": {
|
||||||
|
"@types/hast": "^2.0.0",
|
||||||
|
"@types/unist": "^2.0.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/unified"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/hast-util-is-element": {
|
"node_modules/hast-util-is-element": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/hast-util-is-element/-/hast-util-is-element-3.0.0.tgz",
|
||||||
|
@ -5051,6 +5441,28 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/is-buffer": {
|
||||||
|
"version": "2.0.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz",
|
||||||
|
"integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==",
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "patreon",
|
||||||
|
"url": "https://www.patreon.com/feross"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "consulting",
|
||||||
|
"url": "https://feross.org/support"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/is-core-module": {
|
"node_modules/is-core-module": {
|
||||||
"version": "2.14.0",
|
"version": "2.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.14.0.tgz",
|
||||||
|
@ -6687,10 +7099,9 @@
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
"node_modules/micromatch": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.7",
|
"version": "4.0.8",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
|
||||||
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
|
"integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
|
||||||
"license": "MIT",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"braces": "^3.0.3",
|
"braces": "^3.0.3",
|
||||||
"picomatch": "^2.3.1"
|
"picomatch": "^2.3.1"
|
||||||
|
@ -7156,10 +7567,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/path-to-regexp": {
|
"node_modules/path-to-regexp": {
|
||||||
"version": "6.2.2",
|
"version": "6.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz",
|
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz",
|
||||||
"integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==",
|
"integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ=="
|
||||||
"license": "MIT"
|
|
||||||
},
|
},
|
||||||
"node_modules/periscopic": {
|
"node_modules/periscopic": {
|
||||||
"version": "3.1.0",
|
"version": "3.1.0",
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
"@astrojs/tailwind": "^5.1.0",
|
"@astrojs/tailwind": "^5.1.0",
|
||||||
"@fontsource/geist-mono": "^5.0.3",
|
"@fontsource/geist-mono": "^5.0.3",
|
||||||
"@fontsource/geist-sans": "^5.0.3",
|
"@fontsource/geist-sans": "^5.0.3",
|
||||||
|
"@hbsnow/rehype-sectionize": "^1.0.7",
|
||||||
"@radix-ui/react-avatar": "^1.1.0",
|
"@radix-ui/react-avatar": "^1.1.0",
|
||||||
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
"@radix-ui/react-dropdown-menu": "^2.1.1",
|
||||||
"@radix-ui/react-icons": "^1.3.0",
|
"@radix-ui/react-icons": "^1.3.0",
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
import { Image } from 'astro:assets'
|
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
import Link from '@components/Link.astro'
|
import Link from '@components/Link.astro'
|
||||||
|
import { Image } from 'astro:assets'
|
||||||
import type { CollectionEntry } from 'astro:content'
|
import type { CollectionEntry } from 'astro:content'
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
|
@ -11,7 +11,9 @@ type Props = {
|
||||||
const { project } = Astro.props
|
const { project } = Astro.props
|
||||||
---
|
---
|
||||||
|
|
||||||
<div class="overflow-hidden rounded-xl border transition-colors duration-300 ease-in-out hover:bg-secondary/50">
|
<div
|
||||||
|
class="overflow-hidden rounded-xl border transition-colors duration-300 ease-in-out hover:bg-secondary/50"
|
||||||
|
>
|
||||||
<Link href={project.data.link} class="block">
|
<Link href={project.data.link} class="block">
|
||||||
<Image
|
<Image
|
||||||
src={project.data.image}
|
src={project.data.image}
|
||||||
|
@ -22,11 +24,17 @@ const { project } = Astro.props
|
||||||
/>
|
/>
|
||||||
<div class="p-4">
|
<div class="p-4">
|
||||||
<h3 class="mb-2 text-lg font-semibold">{project.data.name}</h3>
|
<h3 class="mb-2 text-lg font-semibold">{project.data.name}</h3>
|
||||||
<p class="mb-4 text-sm text-muted-foreground">{project.data.description}</p>
|
<p class="mb-4 text-sm text-muted-foreground">
|
||||||
|
{project.data.description}
|
||||||
|
</p>
|
||||||
<div class="flex flex-wrap gap-2">
|
<div class="flex flex-wrap gap-2">
|
||||||
{project.data.tags.map((tag) => (
|
{
|
||||||
<Badge variant="secondary" showHash={false}>{tag}</Badge>
|
project.data.tags.map((tag) => (
|
||||||
))}
|
<Badge variant="secondary" showHash={false}>
|
||||||
|
{tag}
|
||||||
|
</Badge>
|
||||||
|
))
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
|
|
|
@ -1,28 +1,37 @@
|
||||||
---
|
---
|
||||||
|
import { ChevronDown } from 'lucide-react'
|
||||||
import TableOfContentsHeading from './TableOfContentsHeading.astro'
|
import TableOfContentsHeading from './TableOfContentsHeading.astro'
|
||||||
|
|
||||||
// https://kld.dev/building-table-of-contents/
|
|
||||||
const { headings } = Astro.props
|
|
||||||
const toc = buildToc(headings)
|
|
||||||
|
|
||||||
export interface Heading {
|
export interface Heading {
|
||||||
depth: number
|
depth: number
|
||||||
slug: string
|
slug: string
|
||||||
text: string
|
text: string
|
||||||
|
subheadings: Heading[]
|
||||||
}
|
}
|
||||||
|
|
||||||
function buildToc(headings: Heading[]) {
|
const { headings } = Astro.props
|
||||||
|
const toc = buildToc(headings)
|
||||||
|
|
||||||
|
function buildToc(headings: Heading[]): Heading[] {
|
||||||
const toc: Heading[] = []
|
const toc: Heading[] = []
|
||||||
const parentHeadings = new Map()
|
const stack: Heading[] = []
|
||||||
|
|
||||||
headings.forEach((h) => {
|
headings.forEach((h) => {
|
||||||
const heading = { ...h, subheadings: [] }
|
const heading = { ...h, subheadings: [] }
|
||||||
parentHeadings.set(heading.depth, heading)
|
|
||||||
if (heading.depth === 2) {
|
while (stack.length > 0 && stack[stack.length - 1].depth >= heading.depth) {
|
||||||
|
stack.pop()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stack.length === 0) {
|
||||||
toc.push(heading)
|
toc.push(heading)
|
||||||
} else {
|
} else {
|
||||||
parentHeadings.get(heading.depth - 1).subheadings.push(heading)
|
stack[stack.length - 1].subheadings.push(heading)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
stack.push(heading)
|
||||||
})
|
})
|
||||||
|
|
||||||
return toc
|
return toc
|
||||||
}
|
}
|
||||||
---
|
---
|
||||||
|
@ -32,17 +41,9 @@ function buildToc(headings: Heading[]) {
|
||||||
class="flex cursor-pointer items-center justify-between text-xl font-semibold"
|
class="flex cursor-pointer items-center justify-between text-xl font-semibold"
|
||||||
>
|
>
|
||||||
Table of Contents
|
Table of Contents
|
||||||
<svg
|
<ChevronDown
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
className="size-5 transition-transform group-open:rotate-180"
|
||||||
class="size-5 transition-transform group-open:rotate-180"
|
/>
|
||||||
viewBox="0 0 20 20"
|
|
||||||
fill="currentColor"
|
|
||||||
>
|
|
||||||
<path
|
|
||||||
fill-rule="evenodd"
|
|
||||||
d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z"
|
|
||||||
clip-rule="evenodd"></path>
|
|
||||||
</svg>
|
|
||||||
</summary>
|
</summary>
|
||||||
<nav>
|
<nav>
|
||||||
<ul class="pt-3">
|
<ul class="pt-3">
|
||||||
|
@ -50,11 +51,15 @@ function buildToc(headings: Heading[]) {
|
||||||
</ul>
|
</ul>
|
||||||
</nav>
|
</nav>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
<nav
|
<nav
|
||||||
class="overflow-wrap-break-word sticky top-16 hidden h-0 w-[calc(50vw-50%-4rem)] translate-x-[calc(-100%-2em)] text-xs leading-4 xl:block"
|
class="overflow-wrap-break-word sticky top-16 hidden h-0 w-[calc(50vw-50%-4rem)] translate-x-[calc(-100%-2em)] text-xs leading-4 xl:block"
|
||||||
>
|
>
|
||||||
<div class="mr-6 flex justify-end">
|
<div class="mr-6 flex justify-end">
|
||||||
<ul class="max-h-[calc(100vh-8rem)] space-y-2 overflow-y-auto">
|
<ul
|
||||||
|
class="max-h-[calc(100vh-8rem)] space-y-2 overflow-y-auto"
|
||||||
|
id="toc-container"
|
||||||
|
>
|
||||||
<li>
|
<li>
|
||||||
<h2 class="mb-2 text-lg font-semibold">Table of Contents</h2>
|
<h2 class="mb-2 text-lg font-semibold">Table of Contents</h2>
|
||||||
</li>
|
</li>
|
||||||
|
@ -62,3 +67,32 @@ function buildToc(headings: Heading[]) {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
function setupToc() {
|
||||||
|
const observer = new IntersectionObserver((sections) => {
|
||||||
|
sections.forEach((section) => {
|
||||||
|
const heading = section.target.querySelector('h2, h3, h4, h5, h6')
|
||||||
|
if (!heading) return
|
||||||
|
|
||||||
|
const id = heading.getAttribute('id')
|
||||||
|
const link = document.querySelector(
|
||||||
|
`#toc-container li a[href="#${id}"]`,
|
||||||
|
)
|
||||||
|
if (!link) return
|
||||||
|
|
||||||
|
const addRemove = section.intersectionRatio > 0 ? 'add' : 'remove'
|
||||||
|
link.classList[addRemove]('font-semibold')
|
||||||
|
link.classList[addRemove]('text-foreground')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
const sections = document.querySelectorAll('.prose section')
|
||||||
|
sections.forEach((section) => {
|
||||||
|
observer.observe(section)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
document.addEventListener('astro:page-load', setupToc)
|
||||||
|
document.addEventListener('astro:after-swap', setupToc)
|
||||||
|
</script>
|
||||||
|
|
|
@ -8,7 +8,10 @@ const { heading } = Astro.props
|
||||||
<li
|
<li
|
||||||
class="mr-2 list-inside list-disc px-6 py-1.5 text-sm text-foreground/60 xl:list-none xl:p-0"
|
class="mr-2 list-inside list-disc px-6 py-1.5 text-sm text-foreground/60 xl:list-none xl:p-0"
|
||||||
>
|
>
|
||||||
<Link href={'#' + heading.slug} class="toc-link" data-heading={heading.slug}>
|
<Link
|
||||||
|
href={'#' + heading.slug}
|
||||||
|
class="toc-link transition-colors duration-200"
|
||||||
|
>
|
||||||
{heading.text}
|
{heading.text}
|
||||||
</Link>
|
</Link>
|
||||||
{
|
{
|
||||||
|
@ -21,33 +24,3 @@ const { heading } = Astro.props
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
<script>
|
|
||||||
function updateActiveHeading() {
|
|
||||||
const headings = document.querySelectorAll('h2, h3, h4, h5, h6')
|
|
||||||
const tocLinks = document.querySelectorAll('.toc-link')
|
|
||||||
|
|
||||||
let currentHeading = ''
|
|
||||||
|
|
||||||
headings.forEach((heading) => {
|
|
||||||
const top = heading.getBoundingClientRect().top
|
|
||||||
if (top < 200) {
|
|
||||||
currentHeading = heading.id
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
tocLinks.forEach((link) => {
|
|
||||||
const headingSlug = link.getAttribute('data-heading')
|
|
||||||
if (headingSlug === currentHeading) {
|
|
||||||
link.classList.add('underline')
|
|
||||||
link.classList.add('text-foreground')
|
|
||||||
} else {
|
|
||||||
link.classList.remove('underline')
|
|
||||||
link.classList.remove('text-foreground')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
window.addEventListener('scroll', updateActiveHeading)
|
|
||||||
window.addEventListener('load', updateActiveHeading)
|
|
||||||
</script>
|
|
||||||
|
|
|
@ -7,7 +7,7 @@ const Card = React.forwardRef<
|
||||||
>(({ className, ...props }, ref) => (
|
>(({ className, ...props }, ref) => (
|
||||||
<div
|
<div
|
||||||
ref={ref}
|
ref={ref}
|
||||||
className={cn('bg-background rounded-xl border', className)}
|
className={cn('rounded-xl border bg-background', className)}
|
||||||
{...props}
|
{...props}
|
||||||
/>
|
/>
|
||||||
))
|
))
|
||||||
|
|
|
@ -28,7 +28,9 @@ export function ModeToggle() {
|
||||||
|
|
||||||
document.documentElement.classList[isDark ? 'add' : 'remove']('dark')
|
document.documentElement.classList[isDark ? 'add' : 'remove']('dark')
|
||||||
|
|
||||||
window.getComputedStyle(document.documentElement).getPropertyValue('opacity')
|
window
|
||||||
|
.getComputedStyle(document.documentElement)
|
||||||
|
.getPropertyValue('opacity')
|
||||||
|
|
||||||
requestAnimationFrame(() => {
|
requestAnimationFrame(() => {
|
||||||
document.documentElement.classList.remove('disable-transitions')
|
document.documentElement.classList.remove('disable-transitions')
|
||||||
|
|
|
@ -8,3 +8,35 @@ authors: ['enscribe', 'jktrn']
|
||||||
---
|
---
|
||||||
|
|
||||||
This is a dummy post written in the year 2024.
|
This is a dummy post written in the year 2024.
|
||||||
|
|
||||||
|
## Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
||||||
|
### Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
||||||
|
#### Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
||||||
|
#### Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
||||||
|
### Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
||||||
|
#### Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
||||||
|
###### Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
||||||
|
### Test
|
||||||
|
|
||||||
|
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Neque porro quisquam est, qui dolorem ipsum quia dolor sit amet, consectetur, adipisci velit, sed quia non numquam eius modi tempora incidunt ut labore et dolore magnam aliquam quaerat voluptatem. Ut enim ad minima veniam, quis nostrum exercitationem ullam corporis suscipit laboriosam, nisi ut aliquid ex ea commodi consequatur? Quis autem vel eum iure reprehenderit qui in ea voluptate velit esse quam nihil molestiae consequatur, vel illum qui dolorem eum fugiat quo voluptas nulla pariatur?
|
||||||
|
|
|
@ -106,6 +106,54 @@ Within the blog itself (as in the layout, appearance, and navigation) are featur
|
||||||
- You can specify multiple post authors via frontmatter. If this post author's slug is found within the `Authors` collection, then it will render particular info from that author's frontmatter file, `[author-name].md` (e.g. avatar, link to profile). For example, the previous post (2024 Post) has two authors: "enscribe" and "jktrn", where "enscribe" is the only author with a custom avatar since "jktrn" is unregistered.
|
- You can specify multiple post authors via frontmatter. If this post author's slug is found within the `Authors` collection, then it will render particular info from that author's frontmatter file, `[author-name].md` (e.g. avatar, link to profile). For example, the previous post (2024 Post) has two authors: "enscribe" and "jktrn", where "enscribe" is the only author with a custom avatar since "jktrn" is unregistered.
|
||||||
- Each author will have their own page, which lists all of their posts. If you're the only author throughout the entire blog then you can simply disregard all aspects regarding both inserting authors and the `Authors` collection.
|
- Each author will have their own page, which lists all of their posts. If you're the only author throughout the entire blog then you can simply disregard all aspects regarding both inserting authors and the `Authors` collection.
|
||||||
- Each tag will also have their own page, which lists all of the posts under that tag!
|
- Each tag will also have their own page, which lists all of the posts under that tag!
|
||||||
|
- $\LaTeX$ is fully supported with [KaTeX](https://katex.org/):
|
||||||
|
|
||||||
|
<blockquote>
|
||||||
|
|
||||||
|
To solve the cubic equation $t^3 + pt + q = 0$ (where the real numbers
|
||||||
|
$p, q$ satisfy ${4p^3 + 27q^2} > 0$) one can use Cardano's formula:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\sqrt[{3}]{
|
||||||
|
-\frac{q}{2}
|
||||||
|
+\sqrt{\frac{q^2}{4} + {\frac{p^{3}}{27}}}
|
||||||
|
}+
|
||||||
|
\sqrt[{3}]{
|
||||||
|
-\frac{q}{2}
|
||||||
|
-\sqrt{\frac{q^2}{4} + {\frac{p^{3}}{27}}}
|
||||||
|
}
|
||||||
|
$$
|
||||||
|
|
||||||
|
For any $u_1, \dots, u_n \in \mathbb{C}$ and
|
||||||
|
$v_1, \dots, v_n \in \mathbb{C}$, the Cauchy–Bunyakovsky–Schwarz
|
||||||
|
inequality can be written as follows:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\left| \sum_{k=1}^n {u_k \bar{v_k}} \right|^2
|
||||||
|
\leq
|
||||||
|
{
|
||||||
|
\left( \sum_{k=1}^n {|u_k|} \right)^2
|
||||||
|
\left( \sum_{k=1}^n {|v_k|} \right)^2
|
||||||
|
}
|
||||||
|
$$
|
||||||
|
|
||||||
|
Finally, the determinant of a Vandermonde matrix can be calculated
|
||||||
|
using the following expression:
|
||||||
|
|
||||||
|
$$
|
||||||
|
\begin{vmatrix}
|
||||||
|
1 & x_1 & x_1^2 & \dots & x_1^{n-1} \\
|
||||||
|
1 & x_2 & x_2^2 & \dots & x_2^{n-1} \\
|
||||||
|
1 & x_3 & x_3^2 & \dots & x_3^{n-1} \\
|
||||||
|
\vdots & \vdots & \vdots & \ddots & \vdots \\
|
||||||
|
1 & x_n & x_n^2 & \dots & x_n^{n-1} \\
|
||||||
|
\end{vmatrix}
|
||||||
|
= {\prod_{1 \leq {i,j} \leq n} {(x_i - x_j)}}
|
||||||
|
$$
|
||||||
|
|
||||||
|
—<cite>[Three famous mathematical formulas](https://developer.mozilla.org/en-US/docs/Learn/MathML/First_steps/Three_famous_mathematical_formulas) (Mozilla Docs)</cite>
|
||||||
|
|
||||||
|
</blockquote>
|
||||||
|
|
||||||
## Foregoing some slop
|
## Foregoing some slop
|
||||||
|
|
||||||
|
@ -117,3 +165,15 @@ Within the blog itself (as in the layout, appearance, and navigation) are featur
|
||||||
- You really don't need a <abbr title="Content Management System">CMS</abbr> unless you have thousands of posts and/or are willing to navigate through a clunky management interface. Markdown and folders is really all you need, which you can organize to your preference via folder or file naming conventions.
|
- You really don't need a <abbr title="Content Management System">CMS</abbr> unless you have thousands of posts and/or are willing to navigate through a clunky management interface. Markdown and folders is really all you need, which you can organize to your preference via folder or file naming conventions.
|
||||||
- If you have literally anything involving an `.env` file in a blogging site, please think about what you are doing very carefully.
|
- If you have literally anything involving an `.env` file in a blogging site, please think about what you are doing very carefully.
|
||||||
- Please do not override the browser's <kbd>Ctrl</kbd> + <kbd>K</kbd> functionality to open up a command palette. There should not be a single reason why a user would use a small context menu to browse your blog over the `/blog` route. Most of the time, command palettes on sites do nothing more than regurgitate shortcuts that are already on the same page you're hiding with the palette's modal.
|
- Please do not override the browser's <kbd>Ctrl</kbd> + <kbd>K</kbd> functionality to open up a command palette. There should not be a single reason why a user would use a small context menu to browse your blog over the `/blog` route. Most of the time, command palettes on sites do nothing more than regurgitate shortcuts that are already on the same page you're hiding with the palette's modal.
|
||||||
|
|
||||||
|
## Something important
|
||||||
|
|
||||||
|
Before we wrap up, I want to emphasize that everything that I've shared here is based on my own personal opinions and experiences. While I believe these practices and choices lead to a better blogging experience, you're absolutely free to disagree.
|
||||||
|
|
||||||
|
The web development community, especially in spaces like Twitter and various online forums, is constantly engaged in heated debates about what constitutes "best practices." You'll find a wide spectrum of viewpoints:
|
||||||
|
|
||||||
|
1. Fundamentalists who adhere strictly to established patterns and completely disregard change,
|
||||||
|
2. Accelerationists who gobble up whatever Vercel cooks as if it's the second coming of Christ,
|
||||||
|
3. and everyone in between this spectrum who just wants to ship.
|
||||||
|
|
||||||
|
I'm just another guy who loves to blog, and I wanted to share what particular technology stack worked the best for me in this particular use case. A stack for one project can be completely unusable for another. If you vehemently hate any of the design choices I've made then simply get rid of them. MIT license! Happy blogging.
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: "Project A"
|
name: 'Project A'
|
||||||
description: "This is an example project description! You should replace this with a description of your own project."
|
description: 'This is an example project description! You should replace this with a description of your own project.'
|
||||||
tags: ["Framework A", "Library B", "Tool C", "Resource D"]
|
tags: ['Framework A', 'Library B', 'Tool C', 'Resource D']
|
||||||
image: "../../../public/static/1200x630.png"
|
image: '../../../public/static/1200x630.png'
|
||||||
link: "https://example.com"
|
link: 'https://example.com'
|
||||||
---
|
---
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: "Project B"
|
name: 'Project B'
|
||||||
description: "This is an example project description! You should replace this with a description of your own project."
|
description: 'This is an example project description! You should replace this with a description of your own project.'
|
||||||
tags: ["Framework A", "Library B", "Tool C", "Resource D"]
|
tags: ['Framework A', 'Library B', 'Tool C', 'Resource D']
|
||||||
image: "../../../public/static/1200x630.png"
|
image: '../../../public/static/1200x630.png'
|
||||||
link: "https://example.com"
|
link: 'https://example.com'
|
||||||
---
|
---
|
|
@ -1,7 +1,7 @@
|
||||||
---
|
---
|
||||||
name: "Project C"
|
name: 'Project C'
|
||||||
description: "This is an example project description! You should replace this with a description of your own project."
|
description: 'This is an example project description! You should replace this with a description of your own project.'
|
||||||
tags: ["Framework A", "Library B", "Tool C", "Resource D"]
|
tags: ['Framework A', 'Library B', 'Tool C', 'Resource D']
|
||||||
image: "../../../public/static/1200x630.png"
|
image: '../../../public/static/1200x630.png'
|
||||||
link: "https://example.com"
|
link: 'https://example.com'
|
||||||
---
|
---
|
|
@ -16,16 +16,14 @@ const projects = await getCollection('projects')
|
||||||
<section>
|
<section>
|
||||||
<div class="min-w-full">
|
<div class="min-w-full">
|
||||||
<h1 class="mb-4 text-3xl font-bold">Some more about us</h1>
|
<h1 class="mb-4 text-3xl font-bold">Some more about us</h1>
|
||||||
<p class="prose prose-neutral dark:prose-invert mb-8">
|
<p class="prose prose-neutral mb-8 dark:prose-invert">
|
||||||
{SITE.TITLE} is an opinionated, no-frills static blogging template built
|
{SITE.TITLE} is an opinionated, no-frills static blogging template built
|
||||||
with Astro.
|
with Astro.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h2 class="mb-4 text-2xl font-semibold">Our Projects</h2>
|
<h2 class="mb-4 text-2xl font-semibold">Our Projects</h2>
|
||||||
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
<div class="grid gap-6 sm:grid-cols-2 lg:grid-cols-3">
|
||||||
{projects.map((project) => (
|
{projects.map((project) => <ProjectCard project={project} />)}
|
||||||
<ProjectCard project={project} />
|
|
||||||
))}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -11,18 +11,18 @@ const authors = await getCollection('authors')
|
||||||
<Layout title="Authors" description="A list of authors on this site.">
|
<Layout title="Authors" description="A list of authors on this site.">
|
||||||
<Container class="flex flex-col gap-y-6">
|
<Container class="flex flex-col gap-y-6">
|
||||||
<Breadcrumbs items={[{ label: 'Authors' }]} />
|
<Breadcrumbs items={[{ label: 'Authors' }]} />
|
||||||
{authors.length > 0 ? (
|
|
||||||
<ul class="not-prose flex flex-col gap-4">
|
|
||||||
{
|
{
|
||||||
authors.map((author) => (
|
authors.length > 0 ? (
|
||||||
|
<ul class="not-prose flex flex-col gap-4">
|
||||||
|
{authors.map((author) => (
|
||||||
<li>
|
<li>
|
||||||
<AuthorCard author={author} />
|
<AuthorCard author={author} />
|
||||||
</li>
|
</li>
|
||||||
))
|
))}
|
||||||
}
|
|
||||||
</ul>
|
</ul>
|
||||||
) : (
|
) : (
|
||||||
<p class="text-center text-muted-foreground">No authors found.</p>
|
<p class="text-center text-muted-foreground">No authors found.</p>
|
||||||
)}
|
)
|
||||||
|
}
|
||||||
</Container>
|
</Container>
|
||||||
</Layout>
|
</Layout>
|
||||||
|
|
|
@ -38,7 +38,7 @@ export async function getStaticPaths() {
|
||||||
>
|
>
|
||||||
<Container class="flex flex-col gap-y-6">
|
<Container class="flex flex-col gap-y-6">
|
||||||
<Breadcrumbs items={[{ href: '/tags', label: 'Tags' }, { label: tag }]} />
|
<Breadcrumbs items={[{ href: '/tags', label: 'Tags' }, { label: tag }]} />
|
||||||
<div class="flex items-center flex-wrap gap-2">
|
<div class="flex flex-wrap items-center gap-2">
|
||||||
<h1 class="text-3xl font-semibold">Posts tagged with</h1>
|
<h1 class="text-3xl font-semibold">Posts tagged with</h1>
|
||||||
<span
|
<span
|
||||||
class="flex items-center gap-x-1 rounded-full bg-secondary px-4 py-2 text-2xl font-bold"
|
class="flex items-center gap-x-1 rounded-full bg-secondary px-4 py-2 text-2xl font-bold"
|
||||||
|
|
Loading…
Add table
Reference in a new issue