mirror of
https://github.com/jackyzha0/quartz.git
synced 2025-12-13 08:09:01 +01:00
Compare commits
10 Commits
b00198b888
...
jackyzha0/
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d02bb0f044 | ||
|
|
e320324cf2 | ||
|
|
9f8a8c83e5 | ||
|
|
1176deab7e | ||
|
|
2802aa91f4 | ||
|
|
50efa14bd2 | ||
|
|
26ff78f81f | ||
|
|
0cacd48458 | ||
|
|
51790b3926 | ||
|
|
08717394ff |
@@ -31,13 +31,13 @@ If you prefer instructions in a video format you can try following Nicole van de
|
||||
|
||||
## 🔧 Features
|
||||
|
||||
- [[Obsidian compatibility]], [[full-text search]], [[graph view]], note transclusion, [[wikilinks]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[comments]] and [many more](./features/) right out of the box
|
||||
- [[Obsidian compatibility]], [[full-text search]], [[graph view]], note transclusion, [[wikilinks]], [[backlinks]], [[features/Latex|Latex]], [[syntax highlighting]], [[popover previews]], [[Docker Support]], [[i18n|internationalization]], [[comments]] and [many more](./features) right out of the box
|
||||
- Hot-reload for both configuration and content
|
||||
- Simple JSX layouts and [[creating components|page components]]
|
||||
- [[SPA Routing|Ridiculously fast page loads]] and tiny bundle sizes
|
||||
- Fully-customizable parsing, filtering, and page generation through [[making plugins|plugins]]
|
||||
|
||||
For a comprehensive list of features, visit the [features page](./features/). You can read more about the _why_ behind these features on the [[philosophy]] page and a technical overview on the [[architecture]] page.
|
||||
For a comprehensive list of features, visit the [features page](/features). You can read more about the _why_ behind these features on the [[philosophy]] page and a technical overview on the [[architecture]] page.
|
||||
|
||||
### 🚧 Troubleshooting + Updating
|
||||
|
||||
|
||||
@@ -32,3 +32,5 @@ Want to see what Quartz can do? Here are some cool community gardens:
|
||||
- [🌓 Projects & Privacy - FOSS, tech, law](https://be-far.com)
|
||||
- [Zen Browser Docs](https://docs.zen-browser.app)
|
||||
- [🪴8cat life](https://8cat.life)
|
||||
|
||||
If you want to see your own on here, submit a [Pull Request adding yourself to this file](https://github.com/jackyzha0/quartz/blob/v4/docs/showcase.md)!
|
||||
|
||||
1
index.d.ts
vendored
1
index.d.ts
vendored
@@ -10,5 +10,4 @@ interface CustomEventMap {
|
||||
themechange: CustomEvent<{ theme: "light" | "dark" }>
|
||||
}
|
||||
|
||||
type ContentIndex = Record<FullSlug, ContentDetails>
|
||||
declare const fetchData: Promise<ContentIndex>
|
||||
|
||||
407
package-lock.json
generated
407
package-lock.json
generated
@@ -25,11 +25,11 @@
|
||||
"globby": "^14.1.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"hast-util-to-html": "^9.0.5",
|
||||
"hast-util-to-jsx-runtime": "^2.3.6",
|
||||
"hast-util-to-jsx-runtime": "^2.3.5",
|
||||
"hast-util-to-string": "^3.0.1",
|
||||
"is-absolute-url": "^4.0.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lightningcss": "^1.29.2",
|
||||
"lightningcss": "^1.29.1",
|
||||
"mdast-util-find-and-replace": "^3.0.2",
|
||||
"mdast-util-to-hast": "^13.2.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
@@ -79,12 +79,12 @@
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^22.13.10",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/pretty-time": "^1.1.5",
|
||||
"@types/source-map-support": "^0.5.10",
|
||||
"@types/ws": "^8.18.0",
|
||||
"@types/ws": "^8.5.14",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"esbuild": "^0.25.1",
|
||||
"esbuild": "^0.25.0",
|
||||
"prettier": "^3.5.3",
|
||||
"tsx": "^4.19.3",
|
||||
"typescript": "^5.8.2"
|
||||
@@ -207,9 +207,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/aix-ppc64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz",
|
||||
"integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.0.tgz",
|
||||
"integrity": "sha512-O7vun9Sf8DFjH2UtqK8Ku3LkquL9SZL8OLY1T5NZkA34+wG3OQF7cl4Ql8vdNzM6fzBbYfLaiRLIOZ+2FOCgBQ==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -223,9 +223,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz",
|
||||
"integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.0.tgz",
|
||||
"integrity": "sha512-PTyWCYYiU0+1eJKmw21lWtC+d08JDZPQ5g+kFyxP0V+es6VPPSUhM6zk8iImp2jbV6GwjX4pap0JFbUQN65X1g==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -239,9 +239,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-grvv8WncGjDSyUBjN9yHXNt+cq0snxXbDxy5pJtzMKGmmpPxeAmAhWxXI+01lU5rwZomDgD3kJwulEnhTRUd6g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -255,9 +255,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/android-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-m/ix7SfKG5buCnxasr52+LI78SQ+wgdENi9CqyCXwjVR2X4Jkz+BpC3le3AoBPYTC9NHklwngVXvbJ9/Akhrfg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -271,9 +271,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-mVwdUb5SRkPayVadIOI78K7aAnPamoeFR2bT5nszFUZ9P8UpK4ratOdYbZZXYSqPKMHfS1wdHCJk1P1EZpRdvw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -287,9 +287,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/darwin-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-DgDaYsPWFTS4S3nWpFcMn/33ZZwAAeAFKNHNa1QN0rI4pUjgqf0f7ONmXf6d22tqTY+H9FNdgeaAa+YIFUn2Rg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -303,9 +303,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-VN4ocxy6dxefN1MepBx/iD1dH5K8qNtNe227I0mnTRjry8tj5MRk4zprLEdG8WPyAPb93/e4pSgi1SoHdgOa4w==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -319,9 +319,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/freebsd-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-mrSgt7lCh07FY+hDD1TxiTyIHyttn6vnjesnPoVDNmDfOmggTLXRv8Id5fNZey1gl/V2dyVK1VXXqVsQIiAk+A==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -335,9 +335,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz",
|
||||
"integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.0.tgz",
|
||||
"integrity": "sha512-vkB3IYj2IDo3g9xX7HqhPYxVkNQe8qTK55fraQyTzTX/fxaDtXiEnavv9geOsonh2Fd2RMB+i5cbhu2zMNWJwg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
@@ -351,9 +351,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-9QAQjTWNDM/Vk2bgBl17yWuZxZNQIF0OUUuPZRKoDtqF2k4EtYbpyiG5/Dk7nqeK6kIJWPYldkOcBqjXjrUlmg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -367,9 +367,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ia32": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz",
|
||||
"integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.0.tgz",
|
||||
"integrity": "sha512-43ET5bHbphBegyeqLb7I1eYn2P/JYGNmzzdidq/w0T8E2SsYL1U6un2NFROFRg1JZLTzdCoRomg8Rvf9M6W6Gg==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -383,9 +383,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-loong64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz",
|
||||
"integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.0.tgz",
|
||||
"integrity": "sha512-fC95c/xyNFueMhClxJmeRIj2yrSMdDfmqJnyOY4ZqsALkDrrKJfIg5NTMSzVBr5YW1jf+l7/cndBfP3MSDpoHw==",
|
||||
"cpu": [
|
||||
"loong64"
|
||||
],
|
||||
@@ -399,9 +399,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-mips64el": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz",
|
||||
"integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.0.tgz",
|
||||
"integrity": "sha512-nkAMFju7KDW73T1DdH7glcyIptm95a7Le8irTQNO/qtkoyypZAnjchQgooFUDQhNAy4iu08N79W4T4pMBwhPwQ==",
|
||||
"cpu": [
|
||||
"mips64el"
|
||||
],
|
||||
@@ -415,9 +415,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-ppc64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz",
|
||||
"integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.0.tgz",
|
||||
"integrity": "sha512-NhyOejdhRGS8Iwv+KKR2zTq2PpysF9XqY+Zk77vQHqNbo/PwZCzB5/h7VGuREZm1fixhs4Q/qWRSi5zmAiO4Fw==",
|
||||
"cpu": [
|
||||
"ppc64"
|
||||
],
|
||||
@@ -431,9 +431,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-riscv64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz",
|
||||
"integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.0.tgz",
|
||||
"integrity": "sha512-5S/rbP5OY+GHLC5qXp1y/Mx//e92L1YDqkiBbO9TQOvuFXM+iDqUNG5XopAnXoRH3FjIUDkeGcY1cgNvnXp/kA==",
|
||||
"cpu": [
|
||||
"riscv64"
|
||||
],
|
||||
@@ -447,9 +447,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-s390x": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz",
|
||||
"integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.0.tgz",
|
||||
"integrity": "sha512-XM2BFsEBz0Fw37V0zU4CXfcfuACMrppsMFKdYY2WuTS3yi8O1nFOhil/xhKTmE1nPmVyvQJjJivgDT+xh8pXJA==",
|
||||
"cpu": [
|
||||
"s390x"
|
||||
],
|
||||
@@ -463,9 +463,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/linux-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-9yl91rHw/cpwMCNytUDxwj2XjFpxML0y9HAOH9pNVQDpQrBxHy01Dx+vaMu0N1CKa/RzBD2hB4u//nfc+Sd3Cw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -479,9 +479,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-RuG4PSMPFfrkH6UwCAqBzauBWTygTvb1nxWasEJooGSJ/NwRw7b2HOwyRTQIU97Hq37l3npXoZGYMy3b3xYvPw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -495,9 +495,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/netbsd-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-jl+qisSB5jk01N5f7sPCsBENCOlPiS/xptD5yxOx2oqQfyourJwIKLRA2yqWdifj3owQZCL2sn6o08dBzZGQzA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -510,26 +510,10 @@
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/openbsd-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-2gwwriSMPcCFRlPlKx3zLQhfN/2WjJ2NSlg5TKLQOJdV0mSxIcYNTMhk3H3ulL/cak+Xj0lY1Ym9ysDV1igceg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -543,9 +527,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/sunos-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-bxI7ThgLzPrPz484/S9jLlvUAHYMzy6I0XiU1ZMeAEOBcS0VePBFxh1JjTQt3Xiat5b6Oh4x7UC7IwKQKIJRIg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -559,9 +543,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-arm64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz",
|
||||
"integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-ZUAc2YK6JW89xTbXvftxdnYy3m4iHIkDtK3CLce8wg8M2L+YZhIvO1DKpxrd0Yr59AeNNkTiic9YLf6FTtXWMw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
@@ -575,9 +559,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-ia32": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz",
|
||||
"integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.0.tgz",
|
||||
"integrity": "sha512-eSNxISBu8XweVEWG31/JzjkIGbGIJN/TrRoiSVZwZ6pkC6VX4Im/WV2cz559/TXLcYbcrDN8JtKgd9DJVIo8GA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
@@ -591,9 +575,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@esbuild/win32-x64": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz",
|
||||
"integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.0.tgz",
|
||||
"integrity": "sha512-ZENoHJBxA20C2zFzh6AI4fT6RraMzjYw4xKWemRTRmRVtN9c5DcH9r/f2ihEkMjOW5eGgrwCslG/+Y/3bL+DHQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
@@ -1932,9 +1916,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@types/node": {
|
||||
"version": "22.13.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.10.tgz",
|
||||
"integrity": "sha512-I6LPUvlRH+O6VRUqYOcMudhaIdUVWfsjnZavnsraHvpBwaEyMN29ry+0UVJhImYL16xsscu0aske3yA+uPOWfw==",
|
||||
"version": "22.13.9",
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.9.tgz",
|
||||
"integrity": "sha512-acBjXdRJ3A6Pb3tqnw9HZmyR3Fiol3aGxRCK1x3d+6CDAMjl7I649wpSd+yNURCjbOUGu9tqtLKnTGxmK6CyGw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -1962,9 +1946,9 @@
|
||||
"integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ=="
|
||||
},
|
||||
"node_modules/@types/ws": {
|
||||
"version": "8.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.0.tgz",
|
||||
"integrity": "sha512-8svvI3hMyvN0kKCJMvTJP/x6Y/EoQbepff882wL+Sn5QsXb3etnamgrJq4isrBxSJj5L2AuXcI0+bgkoAXGUJw==",
|
||||
"version": "8.5.14",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.14.tgz",
|
||||
"integrity": "sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
@@ -2870,12 +2854,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||
"license": "Apache-2.0",
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||
"integrity": "sha512-pGjwhsmsp4kL2RTz08wcOlGN83otlqHeD/Z5T8GXZB+/YcpQ/dgo+lbU8ZsGxV0HIvqqxo9l7mqYwyYMD9bKDg==",
|
||||
"bin": {
|
||||
"detect-libc": "bin/detect-libc.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/devlop": {
|
||||
@@ -2923,9 +2909,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild": {
|
||||
"version": "0.25.1",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz",
|
||||
"integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==",
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.0.tgz",
|
||||
"integrity": "sha512-BXq5mqc8ltbaN34cDqWuYKyNhX8D/Z0J1xdtdQ8UcIIIyJyz+ZMKUt58tF3SrZ85jcfN/PZYhjR5uDQAYNVbuw==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
@@ -2935,31 +2921,31 @@
|
||||
"node": ">=18"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@esbuild/aix-ppc64": "0.25.1",
|
||||
"@esbuild/android-arm": "0.25.1",
|
||||
"@esbuild/android-arm64": "0.25.1",
|
||||
"@esbuild/android-x64": "0.25.1",
|
||||
"@esbuild/darwin-arm64": "0.25.1",
|
||||
"@esbuild/darwin-x64": "0.25.1",
|
||||
"@esbuild/freebsd-arm64": "0.25.1",
|
||||
"@esbuild/freebsd-x64": "0.25.1",
|
||||
"@esbuild/linux-arm": "0.25.1",
|
||||
"@esbuild/linux-arm64": "0.25.1",
|
||||
"@esbuild/linux-ia32": "0.25.1",
|
||||
"@esbuild/linux-loong64": "0.25.1",
|
||||
"@esbuild/linux-mips64el": "0.25.1",
|
||||
"@esbuild/linux-ppc64": "0.25.1",
|
||||
"@esbuild/linux-riscv64": "0.25.1",
|
||||
"@esbuild/linux-s390x": "0.25.1",
|
||||
"@esbuild/linux-x64": "0.25.1",
|
||||
"@esbuild/netbsd-arm64": "0.25.1",
|
||||
"@esbuild/netbsd-x64": "0.25.1",
|
||||
"@esbuild/openbsd-arm64": "0.25.1",
|
||||
"@esbuild/openbsd-x64": "0.25.1",
|
||||
"@esbuild/sunos-x64": "0.25.1",
|
||||
"@esbuild/win32-arm64": "0.25.1",
|
||||
"@esbuild/win32-ia32": "0.25.1",
|
||||
"@esbuild/win32-x64": "0.25.1"
|
||||
"@esbuild/aix-ppc64": "0.25.0",
|
||||
"@esbuild/android-arm": "0.25.0",
|
||||
"@esbuild/android-arm64": "0.25.0",
|
||||
"@esbuild/android-x64": "0.25.0",
|
||||
"@esbuild/darwin-arm64": "0.25.0",
|
||||
"@esbuild/darwin-x64": "0.25.0",
|
||||
"@esbuild/freebsd-arm64": "0.25.0",
|
||||
"@esbuild/freebsd-x64": "0.25.0",
|
||||
"@esbuild/linux-arm": "0.25.0",
|
||||
"@esbuild/linux-arm64": "0.25.0",
|
||||
"@esbuild/linux-ia32": "0.25.0",
|
||||
"@esbuild/linux-loong64": "0.25.0",
|
||||
"@esbuild/linux-mips64el": "0.25.0",
|
||||
"@esbuild/linux-ppc64": "0.25.0",
|
||||
"@esbuild/linux-riscv64": "0.25.0",
|
||||
"@esbuild/linux-s390x": "0.25.0",
|
||||
"@esbuild/linux-x64": "0.25.0",
|
||||
"@esbuild/netbsd-arm64": "0.25.0",
|
||||
"@esbuild/netbsd-x64": "0.25.0",
|
||||
"@esbuild/openbsd-arm64": "0.25.0",
|
||||
"@esbuild/openbsd-x64": "0.25.0",
|
||||
"@esbuild/sunos-x64": "0.25.0",
|
||||
"@esbuild/win32-arm64": "0.25.0",
|
||||
"@esbuild/win32-ia32": "0.25.0",
|
||||
"@esbuild/win32-x64": "0.25.0"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild-sass-plugin": {
|
||||
@@ -2976,6 +2962,22 @@
|
||||
"sass-embedded": "^1.71.1"
|
||||
}
|
||||
},
|
||||
"node_modules/esbuild/node_modules/@esbuild/openbsd-arm64": {
|
||||
"version": "0.25.0",
|
||||
"resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.0.tgz",
|
||||
"integrity": "sha512-21sUNbq2r84YE+SJDfaQRvdgznTD8Xc0oc3p3iW/a1EVWeNj/SdUCbm5U0itZPQYRuRTW20fPMWMpcrciH2EJw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"openbsd"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz",
|
||||
@@ -3549,9 +3551,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/hast-util-to-jsx-runtime": {
|
||||
"version": "2.3.6",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.6.tgz",
|
||||
"integrity": "sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==",
|
||||
"version": "2.3.5",
|
||||
"resolved": "https://registry.npmjs.org/hast-util-to-jsx-runtime/-/hast-util-to-jsx-runtime-2.3.5.tgz",
|
||||
"integrity": "sha512-gHD+HoFxOMmmXLuq9f2dZDMQHVcplCVpMfBNRpJsF03yyLZvJGzsFORe8orVuYDX9k2w0VH0uF8oryFd1whqKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
@@ -3566,7 +3568,7 @@
|
||||
"mdast-util-mdxjs-esm": "^2.0.0",
|
||||
"property-information": "^7.0.0",
|
||||
"space-separated-tokens": "^2.0.0",
|
||||
"style-to-js": "^1.0.0",
|
||||
"style-to-object": "^1.0.0",
|
||||
"unist-util-position": "^5.0.0",
|
||||
"vfile-message": "^4.0.0"
|
||||
},
|
||||
@@ -3771,10 +3773,9 @@
|
||||
"integrity": "sha512-1hqclzwYwjRDFLjcFxOM5AYkkG0rpFPpr1RLPMEuGczoS7YA8gLhy8SWXYRAA/XwfEHpfo3cw5JGioS32fnMRw=="
|
||||
},
|
||||
"node_modules/inline-style-parser": {
|
||||
"version": "0.2.4",
|
||||
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.4.tgz",
|
||||
"integrity": "sha512-0aO8FkhNZlj/ZIbNi7Lxxr12obT7cL1moPfE4tg1LkX7LlLfC6DeX4l2ZEud1ukP9jNQyNnfzQVqwbwmAATY4Q==",
|
||||
"license": "MIT"
|
||||
"version": "0.2.2",
|
||||
"resolved": "https://registry.npmjs.org/inline-style-parser/-/inline-style-parser-0.2.2.tgz",
|
||||
"integrity": "sha512-EcKzdTHVe8wFVOGEYXiW9WmJXPjqi1T+234YpJr98RiFYKHV3cdy1+3mkTE+KHTHxFFLH51SfaGOoUdW+v7ViQ=="
|
||||
},
|
||||
"node_modules/internmap": {
|
||||
"version": "2.0.3",
|
||||
@@ -3987,12 +3988,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz",
|
||||
"integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==",
|
||||
"license": "MPL-2.0",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.1.tgz",
|
||||
"integrity": "sha512-FmGoeD4S05ewj+AkhTY+D+myDvXI6eL27FjHIjoyUkO/uw7WZD1fBVs0QxeYWa7E17CUHJaYX/RUGISCtcrG4Q==",
|
||||
"dependencies": {
|
||||
"detect-libc": "^2.0.3"
|
||||
"detect-libc": "^1.0.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 12.0.0"
|
||||
@@ -4002,26 +4002,25 @@
|
||||
"url": "https://opencollective.com/parcel"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"lightningcss-darwin-arm64": "1.29.2",
|
||||
"lightningcss-darwin-x64": "1.29.2",
|
||||
"lightningcss-freebsd-x64": "1.29.2",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.29.2",
|
||||
"lightningcss-linux-arm64-gnu": "1.29.2",
|
||||
"lightningcss-linux-arm64-musl": "1.29.2",
|
||||
"lightningcss-linux-x64-gnu": "1.29.2",
|
||||
"lightningcss-linux-x64-musl": "1.29.2",
|
||||
"lightningcss-win32-arm64-msvc": "1.29.2",
|
||||
"lightningcss-win32-x64-msvc": "1.29.2"
|
||||
"lightningcss-darwin-arm64": "1.29.1",
|
||||
"lightningcss-darwin-x64": "1.29.1",
|
||||
"lightningcss-freebsd-x64": "1.29.1",
|
||||
"lightningcss-linux-arm-gnueabihf": "1.29.1",
|
||||
"lightningcss-linux-arm64-gnu": "1.29.1",
|
||||
"lightningcss-linux-arm64-musl": "1.29.1",
|
||||
"lightningcss-linux-x64-gnu": "1.29.1",
|
||||
"lightningcss-linux-x64-musl": "1.29.1",
|
||||
"lightningcss-win32-arm64-msvc": "1.29.1",
|
||||
"lightningcss-win32-x64-msvc": "1.29.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-arm64": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz",
|
||||
"integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.1.tgz",
|
||||
"integrity": "sha512-HtR5XJ5A0lvCqYAoSv2QdZZyoHNttBpa5EP9aNuzBQeKGfbyH5+UipLWvVzpP4Uml5ej4BYs5I9Lco9u1fECqw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -4035,13 +4034,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-darwin-x64": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz",
|
||||
"integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.1.tgz",
|
||||
"integrity": "sha512-k33G9IzKUpHy/J/3+9MCO4e+PzaFblsgBjSGlpAaFikeBFm8B/CkO3cKU9oI4g+fjS2KlkLM/Bza9K/aw8wsNA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
@@ -4055,13 +4053,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-freebsd-x64": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz",
|
||||
"integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.1.tgz",
|
||||
"integrity": "sha512-0SUW22fv/8kln2LnIdOCmSuXnxgxVC276W5KLTwoehiO0hxkacBxjHOL5EtHD8BAXg2BvuhsJPmVMasvby3LiQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"freebsd"
|
||||
@@ -4075,13 +4072,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm-gnueabihf": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz",
|
||||
"integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.1.tgz",
|
||||
"integrity": "sha512-sD32pFvlR0kDlqsOZmYqH/68SqUMPNj+0pucGxToXZi4XZgZmqeX/NkxNKCPsswAXU3UeYgDSpGhu05eAufjDg==",
|
||||
"cpu": [
|
||||
"arm"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -4095,13 +4091,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-gnu": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz",
|
||||
"integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.1.tgz",
|
||||
"integrity": "sha512-0+vClRIZ6mmJl/dxGuRsE197o1HDEeeRk6nzycSy2GofC2JsY4ifCRnvUWf/CUBQmlrvMzt6SMQNMSEu22csWQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -4115,13 +4110,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-arm64-musl": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz",
|
||||
"integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.1.tgz",
|
||||
"integrity": "sha512-UKMFrG4rL/uHNgelBsDwJcBqVpzNJbzsKkbI3Ja5fg00sgQnHw/VrzUTEc4jhZ+AN2BvQYz/tkHu4vt1kLuJyw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -4135,13 +4129,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-gnu": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz",
|
||||
"integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.1.tgz",
|
||||
"integrity": "sha512-u1S+xdODy/eEtjADqirA774y3jLcm8RPtYztwReEXoZKdzgsHYPl0s5V52Tst+GKzqjebkULT86XMSxejzfISw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -4155,13 +4148,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-linux-x64-musl": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz",
|
||||
"integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.1.tgz",
|
||||
"integrity": "sha512-L0Tx0DtaNUTzXv0lbGCLB/c/qEADanHbu4QdcNOXLIe1i8i22rZRpbT3gpWYsCh9aSL9zFujY/WmEXIatWvXbw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
@@ -4175,13 +4167,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-arm64-msvc": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz",
|
||||
"integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.1.tgz",
|
||||
"integrity": "sha512-QoOVnkIEFfbW4xPi+dpdft/zAKmgLgsRHfJalEPYuJDOWf7cLQzYg0DEh8/sn737FaeMJxHZRc1oBreiwZCjog==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -4195,13 +4186,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/lightningcss-win32-x64-msvc": {
|
||||
"version": "1.29.2",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz",
|
||||
"integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==",
|
||||
"version": "1.29.1",
|
||||
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.1.tgz",
|
||||
"integrity": "sha512-NygcbThNBe4JElP+olyTI/doBNGJvLs3bFCRPdvuCcxZCcCZ71B858IHpdm7L1btZex0FvCmM17FK98Y9MRy1Q==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"license": "MPL-2.0",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
@@ -6616,6 +6606,15 @@
|
||||
"@img/sharp-win32-x64": "0.33.5"
|
||||
}
|
||||
},
|
||||
"node_modules/sharp/node_modules/detect-libc": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz",
|
||||
"integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==",
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
@@ -6861,22 +6860,12 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/style-to-js": {
|
||||
"version": "1.1.16",
|
||||
"resolved": "https://registry.npmjs.org/style-to-js/-/style-to-js-1.1.16.tgz",
|
||||
"integrity": "sha512-/Q6ld50hKYPH3d/r6nr117TZkHR0w0kGGIVfpG9N6D8NymRPM9RqCUv4pRpJ62E5DqOYx2AFpbZMyCPnjQCnOw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"style-to-object": "1.0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/style-to-object": {
|
||||
"version": "1.0.8",
|
||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.8.tgz",
|
||||
"integrity": "sha512-xT47I/Eo0rwJmaXC4oilDGDWLohVhR6o/xAQcPQN8q6QBuZVL8qMYL85kLmST5cPjAorwvqIA4qXTRQoYHaL6g==",
|
||||
"license": "MIT",
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/style-to-object/-/style-to-object-1.0.5.tgz",
|
||||
"integrity": "sha512-rDRwHtoDD3UMMrmZ6BzOW0naTjMsVZLIjsGleSKS/0Oz+cgCfAPRspaqJuE8rDzpKha/nEvnM0IF4seEAZUTKQ==",
|
||||
"dependencies": {
|
||||
"inline-style-parser": "0.2.4"
|
||||
"inline-style-parser": "0.2.2"
|
||||
}
|
||||
},
|
||||
"node_modules/supports-color": {
|
||||
|
||||
10
package.json
10
package.json
@@ -51,11 +51,11 @@
|
||||
"globby": "^14.1.0",
|
||||
"gray-matter": "^4.0.3",
|
||||
"hast-util-to-html": "^9.0.5",
|
||||
"hast-util-to-jsx-runtime": "^2.3.6",
|
||||
"hast-util-to-jsx-runtime": "^2.3.5",
|
||||
"hast-util-to-string": "^3.0.1",
|
||||
"is-absolute-url": "^4.0.1",
|
||||
"js-yaml": "^4.1.0",
|
||||
"lightningcss": "^1.29.2",
|
||||
"lightningcss": "^1.29.1",
|
||||
"mdast-util-find-and-replace": "^3.0.2",
|
||||
"mdast-util-to-hast": "^13.2.0",
|
||||
"mdast-util-to-string": "^4.0.0",
|
||||
@@ -102,12 +102,12 @@
|
||||
"@types/d3": "^7.4.3",
|
||||
"@types/hast": "^3.0.4",
|
||||
"@types/js-yaml": "^4.0.9",
|
||||
"@types/node": "^22.13.10",
|
||||
"@types/node": "^22.13.9",
|
||||
"@types/pretty-time": "^1.1.5",
|
||||
"@types/source-map-support": "^0.5.10",
|
||||
"@types/ws": "^8.18.0",
|
||||
"@types/ws": "^8.5.14",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"esbuild": "^0.25.1",
|
||||
"esbuild": "^0.25.0",
|
||||
"prettier": "^3.5.3",
|
||||
"tsx": "^4.19.3",
|
||||
"typescript": "^5.8.2"
|
||||
|
||||
@@ -19,7 +19,6 @@ import { options } from "./util/sourcemap"
|
||||
import { Mutex } from "async-mutex"
|
||||
import DepGraph from "./depgraph"
|
||||
import { getStaticResourcesFromPlugins } from "./plugins"
|
||||
import { randomIdNonSecure } from "./util/random"
|
||||
|
||||
type Dependencies = Record<string, DepGraph<FilePath> | null>
|
||||
|
||||
@@ -39,9 +38,13 @@ type BuildData = {
|
||||
|
||||
type FileEvent = "add" | "change" | "delete"
|
||||
|
||||
function newBuildId() {
|
||||
return Math.random().toString(36).substring(2, 8)
|
||||
}
|
||||
|
||||
async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) {
|
||||
const ctx: BuildCtx = {
|
||||
buildId: randomIdNonSecure(),
|
||||
buildId: newBuildId(),
|
||||
argv,
|
||||
cfg,
|
||||
allSlugs: [],
|
||||
@@ -159,7 +162,7 @@ async function partialRebuildFromEntrypoint(
|
||||
return
|
||||
}
|
||||
|
||||
const buildId = randomIdNonSecure()
|
||||
const buildId = newBuildId()
|
||||
ctx.buildId = buildId
|
||||
buildData.lastBuildMs = new Date().getTime()
|
||||
const release = await mut.acquire()
|
||||
@@ -356,7 +359,7 @@ async function rebuildFromEntrypoint(
|
||||
toRemove.add(filePath)
|
||||
}
|
||||
|
||||
const buildId = randomIdNonSecure()
|
||||
const buildId = newBuildId()
|
||||
ctx.buildId = buildId
|
||||
buildData.lastBuildMs = new Date().getTime()
|
||||
const release = await mut.acquire()
|
||||
|
||||
@@ -3,7 +3,7 @@ import style from "./styles/backlinks.scss"
|
||||
import { resolveRelative, simplifySlug } from "../util/path"
|
||||
import { i18n } from "../i18n"
|
||||
import { classNames } from "../util/lang"
|
||||
import OverflowListFactory from "./OverflowList"
|
||||
import OverflowList from "./OverflowList"
|
||||
|
||||
interface BacklinksOptions {
|
||||
hideWhenEmpty: boolean
|
||||
@@ -15,7 +15,6 @@ const defaultOptions: BacklinksOptions = {
|
||||
|
||||
export default ((opts?: Partial<BacklinksOptions>) => {
|
||||
const options: BacklinksOptions = { ...defaultOptions, ...opts }
|
||||
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
|
||||
|
||||
const Backlinks: QuartzComponent = ({
|
||||
fileData,
|
||||
@@ -31,7 +30,7 @@ export default ((opts?: Partial<BacklinksOptions>) => {
|
||||
return (
|
||||
<div class={classNames(displayClass, "backlinks")}>
|
||||
<h3>{i18n(cfg.locale).components.backlinks.title}</h3>
|
||||
<OverflowList>
|
||||
<OverflowList id="backlinks-ul">
|
||||
{backlinkFiles.length > 0 ? (
|
||||
backlinkFiles.map((f) => (
|
||||
<li>
|
||||
@@ -49,7 +48,7 @@ export default ((opts?: Partial<BacklinksOptions>) => {
|
||||
}
|
||||
|
||||
Backlinks.css = style
|
||||
Backlinks.afterDOMLoaded = overflowListAfterDOMLoaded
|
||||
Backlinks.afterDOMLoaded = OverflowList.afterDOMLoaded("backlinks-ul")
|
||||
|
||||
return Backlinks
|
||||
}) satisfies QuartzComponentConstructor
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
// @ts-ignore
|
||||
// @ts-ignore: this is safe, we don't want to actually make darkmode.inline.ts a module as
|
||||
// modules are automatically deferred and we don't want that to happen for critical beforeDOMLoads
|
||||
// see: https://v8.dev/features/modules#defer
|
||||
import darkmodeScript from "./scripts/darkmode.inline"
|
||||
import styles from "./styles/darkmode.scss"
|
||||
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
|
||||
@@ -7,12 +9,12 @@ import { classNames } from "../util/lang"
|
||||
|
||||
const Darkmode: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
|
||||
return (
|
||||
<button class={classNames(displayClass, "darkmode")}>
|
||||
<button class={classNames(displayClass, "darkmode")} id="darkmode">
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
class="dayIcon"
|
||||
id="dayIcon"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 35 35"
|
||||
@@ -27,7 +29,7 @@ const Darkmode: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps)
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlnsXlink="http://www.w3.org/1999/xlink"
|
||||
version="1.1"
|
||||
class="nightIcon"
|
||||
id="nightIcon"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 100 100"
|
||||
|
||||
@@ -6,8 +6,7 @@ import script from "./scripts/explorer.inline"
|
||||
import { classNames } from "../util/lang"
|
||||
import { i18n } from "../i18n"
|
||||
import { FileTrieNode } from "../util/fileTrie"
|
||||
import OverflowListFactory from "./OverflowList"
|
||||
import { concatenateResources } from "../util/resources"
|
||||
import OverflowList from "./OverflowList"
|
||||
|
||||
type OrderEntries = "sort" | "filter" | "map"
|
||||
|
||||
@@ -24,7 +23,7 @@ export interface Options {
|
||||
|
||||
const defaultOptions: Options = {
|
||||
folderDefaultState: "collapsed",
|
||||
folderClickBehavior: "link",
|
||||
folderClickBehavior: "collapse",
|
||||
useSavedState: true,
|
||||
mapFn: (node) => {
|
||||
return node
|
||||
@@ -57,7 +56,6 @@ export type FolderState = {
|
||||
|
||||
export default ((userOpts?: Partial<Options>) => {
|
||||
const opts: Options = { ...defaultOptions, ...userOpts }
|
||||
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
|
||||
|
||||
const Explorer: QuartzComponent = ({ cfg, displayClass }: QuartzComponentProps) => {
|
||||
return (
|
||||
@@ -75,7 +73,8 @@ export default ((userOpts?: Partial<Options>) => {
|
||||
>
|
||||
<button
|
||||
type="button"
|
||||
class="explorer-toggle mobile-explorer hide-until-loaded"
|
||||
id="mobile-explorer"
|
||||
class="explorer-toggle hide-until-loaded"
|
||||
data-mobile={true}
|
||||
aria-controls="explorer-content"
|
||||
>
|
||||
@@ -96,7 +95,8 @@ export default ((userOpts?: Partial<Options>) => {
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
class="title-button explorer-toggle desktop-explorer"
|
||||
id="desktop-explorer"
|
||||
class="title-button explorer-toggle"
|
||||
data-mobile={false}
|
||||
aria-expanded={true}
|
||||
>
|
||||
@@ -116,8 +116,8 @@ export default ((userOpts?: Partial<Options>) => {
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="explorer-content" aria-expanded={false}>
|
||||
<OverflowList class="explorer-ul" />
|
||||
<div id="explorer-content" aria-expanded={false}>
|
||||
<OverflowList id="explorer-ul" />
|
||||
</div>
|
||||
<template id="template-file">
|
||||
<li>
|
||||
@@ -157,6 +157,6 @@ export default ((userOpts?: Partial<Options>) => {
|
||||
}
|
||||
|
||||
Explorer.css = style
|
||||
Explorer.afterDOMLoaded = concatenateResources(script, overflowListAfterDOMLoaded)
|
||||
Explorer.afterDOMLoaded = script + OverflowList.afterDOMLoaded("explorer-ul")
|
||||
return Explorer
|
||||
}) satisfies QuartzComponentConstructor
|
||||
|
||||
@@ -48,7 +48,7 @@ const defaultOptions: GraphOptions = {
|
||||
depth: -1,
|
||||
scale: 0.9,
|
||||
repelForce: 0.5,
|
||||
centerForce: 0.2,
|
||||
centerForce: 0.3,
|
||||
linkDistance: 30,
|
||||
fontSize: 0.6,
|
||||
opacityScale: 1,
|
||||
@@ -67,8 +67,8 @@ export default ((opts?: Partial<GraphOptions>) => {
|
||||
<div class={classNames(displayClass, "graph")}>
|
||||
<h3>{i18n(cfg.locale).components.graph.title}</h3>
|
||||
<div class="graph-outer">
|
||||
<div class="graph-container" data-cfg={JSON.stringify(localGraph)}></div>
|
||||
<button class="global-graph-icon" aria-label="Global Graph">
|
||||
<div id="graph-container" data-cfg={JSON.stringify(localGraph)}></div>
|
||||
<button id="global-graph-icon" aria-label="Global Graph">
|
||||
<svg
|
||||
version="1.1"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -95,8 +95,8 @@ export default ((opts?: Partial<GraphOptions>) => {
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div class="global-graph-outer">
|
||||
<div class="global-graph-container" data-cfg={JSON.stringify(globalGraph)}></div>
|
||||
<div id="global-graph-outer">
|
||||
<div id="global-graph-container" data-cfg={JSON.stringify(globalGraph)}></div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -1,31 +1,22 @@
|
||||
import { JSX } from "preact"
|
||||
import { randomIdNonSecure } from "../util/random"
|
||||
|
||||
const OverflowList = ({
|
||||
children,
|
||||
...props
|
||||
}: JSX.HTMLAttributes<HTMLUListElement> & { id: string }) => {
|
||||
return (
|
||||
<ul {...props} class={[props.class, "overflow"].filter(Boolean).join(" ")} id={props.id}>
|
||||
<ul class="overflow" {...props}>
|
||||
{children}
|
||||
<li class="overflow-end" />
|
||||
</ul>
|
||||
)
|
||||
}
|
||||
|
||||
export default () => {
|
||||
const id = randomIdNonSecure()
|
||||
|
||||
return {
|
||||
OverflowList: (props: JSX.HTMLAttributes<HTMLUListElement>) => (
|
||||
<OverflowList {...props} id={id} />
|
||||
),
|
||||
overflowListAfterDOMLoaded: `
|
||||
OverflowList.afterDOMLoaded = (id: string) => `
|
||||
document.addEventListener("nav", (e) => {
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
for (const entry of entries) {
|
||||
const parentUl = entry.target.parentElement
|
||||
if (!parentUl) return
|
||||
if (entry.isIntersecting) {
|
||||
parentUl.classList.remove("gradient-active")
|
||||
} else {
|
||||
@@ -43,6 +34,6 @@ document.addEventListener("nav", (e) => {
|
||||
observer.observe(end)
|
||||
window.addCleanup(() => observer.disconnect())
|
||||
})
|
||||
`,
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
export default OverflowList
|
||||
|
||||
@@ -19,7 +19,7 @@ export default ((userOpts?: Partial<SearchOptions>) => {
|
||||
const searchPlaceholder = i18n(cfg.locale).components.search.searchBarPlaceholder
|
||||
return (
|
||||
<div class={classNames(displayClass, "search")}>
|
||||
<button class="search-button">
|
||||
<button class="search-button" id="search-button">
|
||||
<p>{i18n(cfg.locale).components.search.title}</p>
|
||||
<svg role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.9 19.7">
|
||||
<title>Search</title>
|
||||
@@ -29,17 +29,17 @@ export default ((userOpts?: Partial<SearchOptions>) => {
|
||||
</g>
|
||||
</svg>
|
||||
</button>
|
||||
<div class="search-container">
|
||||
<div class="search-space">
|
||||
<div id="search-container">
|
||||
<div id="search-space">
|
||||
<input
|
||||
autocomplete="off"
|
||||
class="search-bar"
|
||||
id="search-bar"
|
||||
name="search"
|
||||
type="text"
|
||||
aria-label={searchPlaceholder}
|
||||
placeholder={searchPlaceholder}
|
||||
/>
|
||||
<div class="search-layout" data-preview={opts.enablePreview}></div>
|
||||
<div id="search-layout" data-preview={opts.enablePreview}></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,8 +6,7 @@ import { classNames } from "../util/lang"
|
||||
// @ts-ignore
|
||||
import script from "./scripts/toc.inline"
|
||||
import { i18n } from "../i18n"
|
||||
import OverflowListFactory from "./OverflowList"
|
||||
import { concatenateResources } from "../util/resources"
|
||||
import OverflowList from "./OverflowList"
|
||||
|
||||
interface Options {
|
||||
layout: "modern" | "legacy"
|
||||
@@ -17,70 +16,42 @@ const defaultOptions: Options = {
|
||||
layout: "modern",
|
||||
}
|
||||
|
||||
export default ((opts?: Partial<Options>) => {
|
||||
const layout = opts?.layout ?? defaultOptions.layout
|
||||
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
|
||||
const TableOfContents: QuartzComponent = ({
|
||||
fileData,
|
||||
displayClass,
|
||||
cfg,
|
||||
}: QuartzComponentProps) => {
|
||||
if (!fileData.toc) {
|
||||
return null
|
||||
}
|
||||
|
||||
return (
|
||||
<div class={classNames(displayClass, "toc")}>
|
||||
<button
|
||||
type="button"
|
||||
class={fileData.collapseToc ? "collapsed toc-header" : "toc-header"}
|
||||
aria-controls="toc-content"
|
||||
aria-expanded={!fileData.collapseToc}
|
||||
>
|
||||
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="fold"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div class={fileData.collapseToc ? "collapsed toc-content" : "toc-content"}>
|
||||
<OverflowList>
|
||||
{fileData.toc.map((tocEntry) => (
|
||||
<li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}>
|
||||
<a href={`#${tocEntry.slug}`} data-for={tocEntry.slug}>
|
||||
{tocEntry.text}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</OverflowList>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
const TableOfContents: QuartzComponent = ({
|
||||
fileData,
|
||||
displayClass,
|
||||
cfg,
|
||||
}: QuartzComponentProps) => {
|
||||
if (!fileData.toc) {
|
||||
return null
|
||||
}
|
||||
|
||||
TableOfContents.css = modernStyle
|
||||
TableOfContents.afterDOMLoaded = concatenateResources(script, overflowListAfterDOMLoaded)
|
||||
|
||||
const LegacyTableOfContents: QuartzComponent = ({ fileData, cfg }: QuartzComponentProps) => {
|
||||
if (!fileData.toc) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<details class="toc" open={!fileData.collapseToc}>
|
||||
<summary>
|
||||
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
|
||||
</summary>
|
||||
<ul>
|
||||
return (
|
||||
<div class={classNames(displayClass, "toc")}>
|
||||
<button
|
||||
type="button"
|
||||
id="toc"
|
||||
class={fileData.collapseToc ? "collapsed" : ""}
|
||||
aria-controls="toc-content"
|
||||
aria-expanded={!fileData.collapseToc}
|
||||
>
|
||||
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="fold"
|
||||
>
|
||||
<polyline points="6 9 12 15 18 9"></polyline>
|
||||
</svg>
|
||||
</button>
|
||||
<div id="toc-content" class={fileData.collapseToc ? "collapsed" : ""}>
|
||||
<OverflowList id="toc-ul">
|
||||
{fileData.toc.map((tocEntry) => (
|
||||
<li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}>
|
||||
<a href={`#${tocEntry.slug}`} data-for={tocEntry.slug}>
|
||||
@@ -88,11 +59,38 @@ export default ((opts?: Partial<Options>) => {
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</details>
|
||||
)
|
||||
}
|
||||
LegacyTableOfContents.css = legacyStyle
|
||||
</OverflowList>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
TableOfContents.css = modernStyle
|
||||
TableOfContents.afterDOMLoaded = script + OverflowList.afterDOMLoaded("toc-ul")
|
||||
|
||||
const LegacyTableOfContents: QuartzComponent = ({ fileData, cfg }: QuartzComponentProps) => {
|
||||
if (!fileData.toc) {
|
||||
return null
|
||||
}
|
||||
return (
|
||||
<details id="toc" open={!fileData.collapseToc}>
|
||||
<summary>
|
||||
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
|
||||
</summary>
|
||||
<ul>
|
||||
{fileData.toc.map((tocEntry) => (
|
||||
<li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}>
|
||||
<a href={`#${tocEntry.slug}`} data-for={tocEntry.slug}>
|
||||
{tocEntry.text}
|
||||
</a>
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</details>
|
||||
)
|
||||
}
|
||||
LegacyTableOfContents.css = legacyStyle
|
||||
|
||||
export default ((opts?: Partial<Options>) => {
|
||||
const layout = opts?.layout ?? defaultOptions.layout
|
||||
return layout === "modern" ? TableOfContents : LegacyTableOfContents
|
||||
}) satisfies QuartzComponentConstructor
|
||||
|
||||
@@ -9,7 +9,6 @@ import { htmlToJsx } from "../../util/jsx"
|
||||
import { i18n } from "../../i18n"
|
||||
import { QuartzPluginData } from "../../plugins/vfile"
|
||||
import { ComponentChildren } from "preact"
|
||||
import { concatenateResources } from "../../util/resources"
|
||||
|
||||
interface FolderContentOptions {
|
||||
/**
|
||||
@@ -105,6 +104,6 @@ export default ((opts?: Partial<FolderContentOptions>) => {
|
||||
)
|
||||
}
|
||||
|
||||
FolderContent.css = concatenateResources(style, PageList.css)
|
||||
FolderContent.css = style + PageList.css
|
||||
return FolderContent
|
||||
}) satisfies QuartzComponentConstructor
|
||||
|
||||
@@ -7,7 +7,6 @@ import { Root } from "hast"
|
||||
import { htmlToJsx } from "../../util/jsx"
|
||||
import { i18n } from "../../i18n"
|
||||
import { ComponentChildren } from "preact"
|
||||
import { concatenateResources } from "../../util/resources"
|
||||
|
||||
interface TagContentOptions {
|
||||
sort?: SortFn
|
||||
@@ -125,6 +124,6 @@ export default ((opts?: Partial<TagContentOptions>) => {
|
||||
}
|
||||
}
|
||||
|
||||
TagContent.css = concatenateResources(style, PageList.css)
|
||||
TagContent.css = style + PageList.css
|
||||
return TagContent
|
||||
}) satisfies QuartzComponentConstructor
|
||||
|
||||
@@ -9,6 +9,9 @@ import { visit } from "unist-util-visit"
|
||||
import { Root, Element, ElementContent } from "hast"
|
||||
import { GlobalConfiguration } from "../cfg"
|
||||
import { i18n } from "../i18n"
|
||||
// @ts-ignore
|
||||
import mermaidScript from "./scripts/mermaid.inline"
|
||||
import mermaidStyle from "./styles/mermaid.inline.scss"
|
||||
import { QuartzPluginData } from "../plugins/vfile"
|
||||
|
||||
interface RenderComponents {
|
||||
@@ -55,6 +58,17 @@ export function pageResources(
|
||||
additionalHead: staticResources.additionalHead,
|
||||
}
|
||||
|
||||
if (fileData.hasMermaidDiagram) {
|
||||
resources.js.push({
|
||||
script: mermaidScript,
|
||||
loadTime: "afterDOMReady",
|
||||
moduleType: "module",
|
||||
contentType: "inline",
|
||||
})
|
||||
resources.css.push({ content: mermaidStyle, inline: true })
|
||||
}
|
||||
|
||||
// NOTE: we have to put this last to make sure spa.inline.ts is the last item.
|
||||
resources.js.push({
|
||||
src: joinSegments(baseDir, "postscript.js"),
|
||||
loadTime: "afterDOMReady",
|
||||
|
||||
@@ -28,15 +28,17 @@ function setupCallout() {
|
||||
) as HTMLCollectionOf<HTMLElement>
|
||||
for (const div of collapsible) {
|
||||
const title = div.firstElementChild
|
||||
if (!title) continue
|
||||
|
||||
title.addEventListener("click", toggleCallout)
|
||||
window.addCleanup(() => title.removeEventListener("click", toggleCallout))
|
||||
if (title) {
|
||||
title.addEventListener("click", toggleCallout)
|
||||
window.addCleanup(() => title.removeEventListener("click", toggleCallout))
|
||||
|
||||
const collapsed = div.classList.contains("is-collapsed")
|
||||
const height = collapsed ? title.scrollHeight : div.scrollHeight
|
||||
div.style.maxHeight = height + "px"
|
||||
const collapsed = div.classList.contains("is-collapsed")
|
||||
const height = collapsed ? title.scrollHeight : div.scrollHeight
|
||||
div.style.maxHeight = height + "px"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("nav", setupCallout)
|
||||
window.addEventListener("resize", setupCallout)
|
||||
|
||||
@@ -25,11 +25,12 @@ document.addEventListener("nav", () => {
|
||||
emitThemeChangeEvent(newTheme)
|
||||
}
|
||||
|
||||
for (const darkmodeButton of document.getElementsByClassName("darkmode")) {
|
||||
darkmodeButton.addEventListener("click", switchTheme)
|
||||
window.addCleanup(() => darkmodeButton.removeEventListener("click", switchTheme))
|
||||
// Darkmode toggle
|
||||
const themeButton = document.querySelector("#darkmode") as HTMLButtonElement
|
||||
if (themeButton) {
|
||||
themeButton.addEventListener("click", switchTheme)
|
||||
window.addCleanup(() => themeButton.removeEventListener("click", switchTheme))
|
||||
}
|
||||
|
||||
// Listen for changes in prefers-color-scheme
|
||||
const colorSchemeMediaQuery = window.matchMedia("(prefers-color-scheme: dark)")
|
||||
colorSchemeMediaQuery.addEventListener("change", themeChange)
|
||||
|
||||
@@ -21,13 +21,14 @@ type FolderState = {
|
||||
|
||||
let currentExplorerState: Array<FolderState>
|
||||
function toggleExplorer(this: HTMLElement) {
|
||||
const nearestExplorer = this.closest(".explorer") as HTMLElement
|
||||
if (!nearestExplorer) return
|
||||
nearestExplorer.classList.toggle("collapsed")
|
||||
nearestExplorer.setAttribute(
|
||||
"aria-expanded",
|
||||
nearestExplorer.getAttribute("aria-expanded") === "true" ? "false" : "true",
|
||||
)
|
||||
const explorers = document.querySelectorAll(".explorer")
|
||||
for (const explorer of explorers) {
|
||||
explorer.classList.toggle("collapsed")
|
||||
explorer.setAttribute(
|
||||
"aria-expanded",
|
||||
explorer.getAttribute("aria-expanded") === "true" ? "false" : "true",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFolder(evt: MouseEvent) {
|
||||
@@ -77,11 +78,11 @@ function createFileNode(currentSlug: FullSlug, node: FileTrieNode): HTMLLIElemen
|
||||
const clone = template.content.cloneNode(true) as DocumentFragment
|
||||
const li = clone.querySelector("li") as HTMLLIElement
|
||||
const a = li.querySelector("a") as HTMLAnchorElement
|
||||
a.href = resolveRelative(currentSlug, node.slug)
|
||||
a.dataset.for = node.slug
|
||||
a.href = resolveRelative(currentSlug, node.data?.slug!)
|
||||
a.dataset.for = node.data?.slug
|
||||
a.textContent = node.displayName
|
||||
|
||||
if (currentSlug === node.slug) {
|
||||
if (currentSlug === node.data?.slug) {
|
||||
a.classList.add("active")
|
||||
}
|
||||
|
||||
@@ -101,7 +102,7 @@ function createFolderNode(
|
||||
const folderOuter = li.querySelector(".folder-outer") as HTMLElement
|
||||
const ul = folderOuter.querySelector("ul") as HTMLUListElement
|
||||
|
||||
const folderPath = node.slug
|
||||
const folderPath = node.data?.slug!
|
||||
folderContainer.dataset.folderpath = folderPath
|
||||
|
||||
if (opts.folderClickBehavior === "link") {
|
||||
@@ -109,7 +110,7 @@ function createFolderNode(
|
||||
const button = titleContainer.querySelector(".folder-button") as HTMLElement
|
||||
const a = document.createElement("a")
|
||||
a.href = resolveRelative(currentSlug, folderPath)
|
||||
a.dataset.for = folderPath
|
||||
a.dataset.for = node.data?.slug
|
||||
a.className = "folder-title"
|
||||
a.textContent = node.displayName
|
||||
button.replaceWith(a)
|
||||
@@ -144,7 +145,7 @@ function createFolderNode(
|
||||
}
|
||||
|
||||
async function setupExplorer(currentSlug: FullSlug) {
|
||||
const allExplorers = document.querySelectorAll("div.explorer") as NodeListOf<HTMLElement>
|
||||
const allExplorers = document.querySelectorAll(".explorer") as NodeListOf<HTMLElement>
|
||||
|
||||
for (const explorer of allExplorers) {
|
||||
const dataFns = JSON.parse(explorer.dataset.dataFns || "{}")
|
||||
@@ -191,7 +192,7 @@ async function setupExplorer(currentSlug: FullSlug) {
|
||||
collapsed: oldIndex.get(path) === true,
|
||||
}))
|
||||
|
||||
const explorerUl = explorer.querySelector(".explorer-ul")
|
||||
const explorerUl = document.getElementById("explorer-ul")
|
||||
if (!explorerUl) continue
|
||||
|
||||
// Create and insert new content
|
||||
@@ -218,12 +219,14 @@ async function setupExplorer(currentSlug: FullSlug) {
|
||||
}
|
||||
|
||||
// Set up event handlers
|
||||
const explorerButtons = explorer.getElementsByClassName(
|
||||
"explorer-toggle",
|
||||
) as HTMLCollectionOf<HTMLElement>
|
||||
for (const button of explorerButtons) {
|
||||
button.addEventListener("click", toggleExplorer)
|
||||
window.addCleanup(() => button.removeEventListener("click", toggleExplorer))
|
||||
const explorerButtons = explorer.querySelectorAll(
|
||||
"button.explorer-toggle",
|
||||
) as NodeListOf<HTMLElement>
|
||||
if (explorerButtons) {
|
||||
window.addCleanup(() =>
|
||||
explorerButtons.forEach((button) => button.removeEventListener("click", toggleExplorer)),
|
||||
)
|
||||
explorerButtons.forEach((button) => button.addEventListener("click", toggleExplorer))
|
||||
}
|
||||
|
||||
// Set up folder click handlers
|
||||
@@ -232,8 +235,8 @@ async function setupExplorer(currentSlug: FullSlug) {
|
||||
"folder-button",
|
||||
) as HTMLCollectionOf<HTMLElement>
|
||||
for (const button of folderButtons) {
|
||||
button.addEventListener("click", toggleFolder)
|
||||
window.addCleanup(() => button.removeEventListener("click", toggleFolder))
|
||||
button.addEventListener("click", toggleFolder)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,15 +244,15 @@ async function setupExplorer(currentSlug: FullSlug) {
|
||||
"folder-icon",
|
||||
) as HTMLCollectionOf<HTMLElement>
|
||||
for (const icon of folderIcons) {
|
||||
icon.addEventListener("click", toggleFolder)
|
||||
window.addCleanup(() => icon.removeEventListener("click", toggleFolder))
|
||||
icon.addEventListener("click", toggleFolder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
document.addEventListener("prenav", async () => {
|
||||
document.addEventListener("prenav", async (e: CustomEventMap["prenav"]) => {
|
||||
// save explorer scrollTop position
|
||||
const explorer = document.querySelector(".explorer-ul")
|
||||
const explorer = document.getElementById("explorer-ul")
|
||||
if (!explorer) return
|
||||
sessionStorage.setItem("explorerScrollTop", explorer.scrollTop.toString())
|
||||
})
|
||||
@@ -259,8 +262,9 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
|
||||
await setupExplorer(currentSlug)
|
||||
|
||||
// if mobile hamburger is visible, collapse by default
|
||||
for (const explorer of document.getElementsByClassName("mobile-explorer")) {
|
||||
if (explorer.checkVisibility()) {
|
||||
const mobileExplorer = document.getElementById("mobile-explorer")
|
||||
if (mobileExplorer && mobileExplorer.checkVisibility()) {
|
||||
for (const explorer of document.querySelectorAll(".explorer")) {
|
||||
explorer.classList.add("collapsed")
|
||||
explorer.setAttribute("aria-expanded", "false")
|
||||
}
|
||||
|
||||
@@ -68,9 +68,11 @@ type TweenNode = {
|
||||
stop: () => void
|
||||
}
|
||||
|
||||
async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
async function renderGraph(container: string, fullSlug: FullSlug) {
|
||||
const slug = simplifySlug(fullSlug)
|
||||
const visited = getVisited()
|
||||
const graph = document.getElementById(container)
|
||||
if (!graph) return
|
||||
removeAllChildren(graph)
|
||||
|
||||
let {
|
||||
@@ -165,14 +167,16 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
const height = Math.max(graph.offsetHeight, 250)
|
||||
|
||||
// we virtualize the simulation and use pixi to actually render it
|
||||
// Calculate the radius of the container circle
|
||||
const radius = Math.min(width, height) / 2 - 40 // 40px padding
|
||||
const simulation: Simulation<NodeData, LinkData> = forceSimulation<NodeData>(graphData.nodes)
|
||||
.force("charge", forceManyBody().strength(-100 * repelForce))
|
||||
.force("center", forceCenter().strength(centerForce))
|
||||
.force("link", forceLink(graphData.links).distance(linkDistance))
|
||||
.force("collide", forceCollide<NodeData>((n) => nodeRadius(n)).iterations(3))
|
||||
|
||||
const radius = (Math.min(width, height) / 2) * 0.8
|
||||
if (enableRadial) simulation.force("radial", forceRadial(radius).strength(0.2))
|
||||
if (enableRadial)
|
||||
simulation.force("radial", forceRadial(radius * 0.8, width / 2, height / 2).strength(0.3))
|
||||
|
||||
// precompute style prop strings as pixi doesn't support css variables
|
||||
const cssVars = [
|
||||
@@ -520,9 +524,7 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
)
|
||||
}
|
||||
|
||||
let stopAnimation = false
|
||||
function animate(time: number) {
|
||||
if (stopAnimation) return
|
||||
for (const n of nodeRenderData) {
|
||||
const { x, y } = n.simulationData
|
||||
if (!x || !y) continue
|
||||
@@ -546,101 +548,61 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
|
||||
requestAnimationFrame(animate)
|
||||
return () => {
|
||||
stopAnimation = true
|
||||
app.destroy()
|
||||
}
|
||||
}
|
||||
|
||||
let localGraphCleanups: (() => void)[] = []
|
||||
let globalGraphCleanups: (() => void)[] = []
|
||||
|
||||
function cleanupLocalGraphs() {
|
||||
for (const cleanup of localGraphCleanups) {
|
||||
cleanup()
|
||||
}
|
||||
localGraphCleanups = []
|
||||
}
|
||||
|
||||
function cleanupGlobalGraphs() {
|
||||
for (const cleanup of globalGraphCleanups) {
|
||||
cleanup()
|
||||
}
|
||||
globalGraphCleanups = []
|
||||
const graphAnimationFrameHandle = requestAnimationFrame(animate)
|
||||
window.addCleanup(() => cancelAnimationFrame(graphAnimationFrameHandle))
|
||||
}
|
||||
|
||||
document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
|
||||
const slug = e.detail.url
|
||||
addToVisited(simplifySlug(slug))
|
||||
await renderGraph("graph-container", slug)
|
||||
|
||||
async function renderLocalGraph() {
|
||||
cleanupLocalGraphs()
|
||||
const localGraphContainers = document.getElementsByClassName("graph-container")
|
||||
for (const container of localGraphContainers) {
|
||||
localGraphCleanups.push(await renderGraph(container as HTMLElement, slug))
|
||||
}
|
||||
}
|
||||
|
||||
await renderLocalGraph()
|
||||
// Function to re-render the graph when the theme changes
|
||||
const handleThemeChange = () => {
|
||||
void renderLocalGraph()
|
||||
renderGraph("graph-container", slug)
|
||||
}
|
||||
|
||||
// event listener for theme change
|
||||
document.addEventListener("themechange", handleThemeChange)
|
||||
|
||||
// cleanup for the event listener
|
||||
window.addCleanup(() => {
|
||||
document.removeEventListener("themechange", handleThemeChange)
|
||||
})
|
||||
|
||||
const containers = [...document.getElementsByClassName("global-graph-outer")] as HTMLElement[]
|
||||
async function renderGlobalGraph() {
|
||||
const slug = getFullSlug(window)
|
||||
for (const container of containers) {
|
||||
container.classList.add("active")
|
||||
const sidebar = container.closest(".sidebar") as HTMLElement
|
||||
if (sidebar) {
|
||||
sidebar.style.zIndex = "1"
|
||||
}
|
||||
const container = document.getElementById("global-graph-outer")
|
||||
const sidebar = container?.closest(".sidebar") as HTMLElement
|
||||
|
||||
const graphContainer = container.querySelector(".global-graph-container") as HTMLElement
|
||||
registerEscapeHandler(container, hideGlobalGraph)
|
||||
if (graphContainer) {
|
||||
globalGraphCleanups.push(await renderGraph(graphContainer, slug))
|
||||
}
|
||||
function renderGlobalGraph() {
|
||||
const slug = getFullSlug(window)
|
||||
container?.classList.add("active")
|
||||
if (sidebar) {
|
||||
sidebar.style.zIndex = "1"
|
||||
}
|
||||
|
||||
renderGraph("global-graph-container", slug)
|
||||
registerEscapeHandler(container, hideGlobalGraph)
|
||||
}
|
||||
|
||||
function hideGlobalGraph() {
|
||||
cleanupGlobalGraphs()
|
||||
for (const container of containers) {
|
||||
container.classList.remove("active")
|
||||
const sidebar = container.closest(".sidebar") as HTMLElement
|
||||
if (sidebar) {
|
||||
sidebar.style.zIndex = ""
|
||||
}
|
||||
container?.classList.remove("active")
|
||||
if (sidebar) {
|
||||
sidebar.style.zIndex = ""
|
||||
}
|
||||
}
|
||||
|
||||
async function shortcutHandler(e: HTMLElementEventMap["keydown"]) {
|
||||
if (e.key === "g" && (e.ctrlKey || e.metaKey) && !e.shiftKey) {
|
||||
e.preventDefault()
|
||||
const anyGlobalGraphOpen = containers.some((container) =>
|
||||
container.classList.contains("active"),
|
||||
)
|
||||
anyGlobalGraphOpen ? hideGlobalGraph() : renderGlobalGraph()
|
||||
const globalGraphOpen = container?.classList.contains("active")
|
||||
globalGraphOpen ? hideGlobalGraph() : renderGlobalGraph()
|
||||
}
|
||||
}
|
||||
|
||||
const containerIcons = document.getElementsByClassName("global-graph-icon")
|
||||
Array.from(containerIcons).forEach((icon) => {
|
||||
icon.addEventListener("click", renderGlobalGraph)
|
||||
window.addCleanup(() => icon.removeEventListener("click", renderGlobalGraph))
|
||||
})
|
||||
const containerIcon = document.getElementById("global-graph-icon")
|
||||
containerIcon?.addEventListener("click", renderGlobalGraph)
|
||||
window.addCleanup(() => containerIcon?.removeEventListener("click", renderGlobalGraph))
|
||||
|
||||
document.addEventListener("keydown", shortcutHandler)
|
||||
window.addCleanup(() => {
|
||||
document.removeEventListener("keydown", shortcutHandler)
|
||||
cleanupLocalGraphs()
|
||||
cleanupGlobalGraphs()
|
||||
})
|
||||
window.addCleanup(() => document.removeEventListener("keydown", shortcutHandler))
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { registerEscapeHandler, removeAllChildren } from "./util"
|
||||
import { removeAllChildren } from "./util"
|
||||
|
||||
interface Position {
|
||||
x: number
|
||||
@@ -158,7 +158,7 @@ document.addEventListener("nav", async () => {
|
||||
)
|
||||
|
||||
mermaidImport ||= await import(
|
||||
// @ts-ignore
|
||||
//@ts-ignore
|
||||
"https://cdnjs.cloudflare.com/ajax/libs/mermaid/11.4.0/mermaid.esm.min.mjs"
|
||||
)
|
||||
const mermaid = mermaidImport.default
|
||||
@@ -237,12 +237,12 @@ document.addEventListener("nav", async () => {
|
||||
|
||||
closeBtn.addEventListener("click", hideMermaid)
|
||||
expandBtn.addEventListener("click", showMermaid)
|
||||
registerEscapeHandler(popupContainer, hideMermaid)
|
||||
document.addEventListener("keydown", handleEscape)
|
||||
|
||||
window.addCleanup(() => {
|
||||
closeBtn.removeEventListener("click", hideMermaid)
|
||||
expandBtn.removeEventListener("click", showMermaid)
|
||||
document.removeEventListener("keydown", handleEscape)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -82,8 +82,6 @@ async function mouseEnterHandler(
|
||||
const contents = await response.text()
|
||||
const html = p.parseFromString(contents, "text/html")
|
||||
normalizeRelativeURLs(html, targetUrl)
|
||||
// strip all IDs from elements to prevent duplicates
|
||||
html.querySelectorAll("[id]").forEach((el) => el.removeAttribute("id"))
|
||||
const elts = [...html.getElementsByClassName("popover-hint")]
|
||||
if (elts.length === 0) return
|
||||
|
||||
|
||||
@@ -143,75 +143,83 @@ function highlightHTML(searchTerm: string, el: HTMLElement) {
|
||||
return html.body
|
||||
}
|
||||
|
||||
async function setupSearch(searchElement: Element, currentSlug: FullSlug, data: ContentIndex) {
|
||||
const container = searchElement.querySelector(".search-container") as HTMLElement
|
||||
if (!container) return
|
||||
|
||||
const sidebar = container.closest(".sidebar") as HTMLElement
|
||||
if (!sidebar) return
|
||||
|
||||
const searchButton = searchElement.querySelector(".search-button") as HTMLButtonElement
|
||||
if (!searchButton) return
|
||||
|
||||
const searchBar = searchElement.querySelector(".search-bar") as HTMLInputElement
|
||||
if (!searchBar) return
|
||||
|
||||
const searchLayout = searchElement.querySelector(".search-layout") as HTMLElement
|
||||
if (!searchLayout) return
|
||||
|
||||
document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
|
||||
const currentSlug = e.detail.url
|
||||
const data = await fetchData
|
||||
const container = document.getElementById("search-container")
|
||||
const sidebar = container?.closest(".sidebar") as HTMLElement
|
||||
const searchButton = document.getElementById("search-button")
|
||||
const searchBar = document.getElementById("search-bar") as HTMLInputElement | null
|
||||
const searchLayout = document.getElementById("search-layout")
|
||||
const idDataMap = Object.keys(data) as FullSlug[]
|
||||
|
||||
const appendLayout = (el: HTMLElement) => {
|
||||
searchLayout.appendChild(el)
|
||||
if (searchLayout?.querySelector(`#${el.id}`) === null) {
|
||||
searchLayout?.appendChild(el)
|
||||
}
|
||||
}
|
||||
|
||||
const enablePreview = searchLayout.dataset.preview === "true"
|
||||
const enablePreview = searchLayout?.dataset?.preview === "true"
|
||||
let preview: HTMLDivElement | undefined = undefined
|
||||
let previewInner: HTMLDivElement | undefined = undefined
|
||||
const results = document.createElement("div")
|
||||
results.className = "results-container"
|
||||
results.id = "results-container"
|
||||
appendLayout(results)
|
||||
|
||||
if (enablePreview) {
|
||||
preview = document.createElement("div")
|
||||
preview.className = "preview-container"
|
||||
preview.id = "preview-container"
|
||||
appendLayout(preview)
|
||||
}
|
||||
|
||||
function hideSearch() {
|
||||
container.classList.remove("active")
|
||||
searchBar.value = "" // clear the input when we dismiss the search
|
||||
sidebar.style.zIndex = ""
|
||||
removeAllChildren(results)
|
||||
container?.classList.remove("active")
|
||||
if (searchBar) {
|
||||
searchBar.value = "" // clear the input when we dismiss the search
|
||||
}
|
||||
if (sidebar) {
|
||||
sidebar.style.zIndex = ""
|
||||
}
|
||||
if (results) {
|
||||
removeAllChildren(results)
|
||||
}
|
||||
if (preview) {
|
||||
removeAllChildren(preview)
|
||||
}
|
||||
searchLayout.classList.remove("display-results")
|
||||
if (searchLayout) {
|
||||
searchLayout.classList.remove("display-results")
|
||||
}
|
||||
|
||||
searchType = "basic" // reset search type after closing
|
||||
searchButton.focus()
|
||||
|
||||
searchButton?.focus()
|
||||
}
|
||||
|
||||
function showSearch(searchTypeNew: SearchType) {
|
||||
searchType = searchTypeNew
|
||||
sidebar.style.zIndex = "1"
|
||||
container.classList.add("active")
|
||||
searchBar.focus()
|
||||
if (sidebar) {
|
||||
sidebar.style.zIndex = "1"
|
||||
}
|
||||
container?.classList.add("active")
|
||||
searchBar?.focus()
|
||||
}
|
||||
|
||||
let currentHover: HTMLInputElement | null = null
|
||||
|
||||
async function shortcutHandler(e: HTMLElementEventMap["keydown"]) {
|
||||
if (e.key === "k" && (e.ctrlKey || e.metaKey) && !e.shiftKey) {
|
||||
e.preventDefault()
|
||||
const searchBarOpen = container.classList.contains("active")
|
||||
const searchBarOpen = container?.classList.contains("active")
|
||||
searchBarOpen ? hideSearch() : showSearch("basic")
|
||||
return
|
||||
} else if (e.shiftKey && (e.ctrlKey || e.metaKey) && e.key.toLowerCase() === "k") {
|
||||
// Hotkey to open tag search
|
||||
e.preventDefault()
|
||||
const searchBarOpen = container.classList.contains("active")
|
||||
const searchBarOpen = container?.classList.contains("active")
|
||||
searchBarOpen ? hideSearch() : showSearch("tags")
|
||||
|
||||
// add "#" prefix for tag search
|
||||
searchBar.value = "#"
|
||||
if (searchBar) searchBar.value = "#"
|
||||
return
|
||||
}
|
||||
|
||||
@@ -220,23 +228,23 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
}
|
||||
|
||||
// If search is active, then we will render the first result and display accordingly
|
||||
if (!container.classList.contains("active")) return
|
||||
if (!container?.classList.contains("active")) return
|
||||
if (e.key === "Enter") {
|
||||
// If result has focus, navigate to that one, otherwise pick first result
|
||||
if (results.contains(document.activeElement)) {
|
||||
if (results?.contains(document.activeElement)) {
|
||||
const active = document.activeElement as HTMLInputElement
|
||||
if (active.classList.contains("no-match")) return
|
||||
await displayPreview(active)
|
||||
active.click()
|
||||
} else {
|
||||
const anchor = document.getElementsByClassName("result-card")[0] as HTMLInputElement | null
|
||||
if (!anchor || anchor.classList.contains("no-match")) return
|
||||
if (!anchor || anchor?.classList.contains("no-match")) return
|
||||
await displayPreview(anchor)
|
||||
anchor.click()
|
||||
}
|
||||
} else if (e.key === "ArrowUp" || (e.shiftKey && e.key === "Tab")) {
|
||||
e.preventDefault()
|
||||
if (results.contains(document.activeElement)) {
|
||||
if (results?.contains(document.activeElement)) {
|
||||
// If an element in results-container already has focus, focus previous one
|
||||
const currentResult = currentHover
|
||||
? currentHover
|
||||
@@ -329,6 +337,8 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
}
|
||||
|
||||
async function displayResults(finalResults: Item[]) {
|
||||
if (!results) return
|
||||
|
||||
removeAllChildren(results)
|
||||
if (finalResults.length === 0) {
|
||||
results.innerHTML = `<a class="result-card no-match">
|
||||
@@ -384,7 +394,7 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
preview.replaceChildren(previewInner)
|
||||
|
||||
// scroll to longest
|
||||
const highlights = [...preview.getElementsByClassName("highlight")].sort(
|
||||
const highlights = [...preview.querySelectorAll(".highlight")].sort(
|
||||
(a, b) => b.innerHTML.length - a.innerHTML.length,
|
||||
)
|
||||
highlights[0]?.scrollIntoView({ block: "start" })
|
||||
@@ -450,23 +460,21 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
|
||||
|
||||
document.addEventListener("keydown", shortcutHandler)
|
||||
window.addCleanup(() => document.removeEventListener("keydown", shortcutHandler))
|
||||
searchButton.addEventListener("click", () => showSearch("basic"))
|
||||
window.addCleanup(() => searchButton.removeEventListener("click", () => showSearch("basic")))
|
||||
searchBar.addEventListener("input", onType)
|
||||
window.addCleanup(() => searchBar.removeEventListener("input", onType))
|
||||
searchButton?.addEventListener("click", () => showSearch("basic"))
|
||||
window.addCleanup(() => searchButton?.removeEventListener("click", () => showSearch("basic")))
|
||||
searchBar?.addEventListener("input", onType)
|
||||
window.addCleanup(() => searchBar?.removeEventListener("input", onType))
|
||||
|
||||
registerEscapeHandler(container, hideSearch)
|
||||
await fillDocument(data)
|
||||
}
|
||||
})
|
||||
|
||||
/**
|
||||
* Fills flexsearch document with data
|
||||
* @param index index to fill
|
||||
* @param data data to fill index with
|
||||
*/
|
||||
let indexPopulated = false
|
||||
async function fillDocument(data: ContentIndex) {
|
||||
if (indexPopulated) return
|
||||
async function fillDocument(data: { [key: FullSlug]: ContentDetails }) {
|
||||
let id = 0
|
||||
const promises: Array<Promise<unknown>> = []
|
||||
for (const [slug, fileData] of Object.entries<ContentDetails>(data)) {
|
||||
@@ -481,15 +489,5 @@ async function fillDocument(data: ContentIndex) {
|
||||
)
|
||||
}
|
||||
|
||||
await Promise.all(promises)
|
||||
indexPopulated = true
|
||||
return await Promise.all(promises)
|
||||
}
|
||||
|
||||
document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
|
||||
const currentSlug = e.detail.url
|
||||
const data = await fetchData
|
||||
const searchElement = document.getElementsByClassName("search")
|
||||
for (const element of searchElement) {
|
||||
await setupSearch(element, currentSlug, data)
|
||||
}
|
||||
})
|
||||
|
||||
@@ -56,10 +56,8 @@ function startLoading() {
|
||||
}, 100)
|
||||
}
|
||||
|
||||
let isNavigating = false
|
||||
let p: DOMParser
|
||||
async function _navigate(url: URL, isBack: boolean = false) {
|
||||
isNavigating = true
|
||||
async function navigate(url: URL, isBack: boolean = false) {
|
||||
startLoading()
|
||||
p = p || new DOMParser()
|
||||
const contents = await fetchCanonical(url)
|
||||
@@ -130,19 +128,6 @@ async function _navigate(url: URL, isBack: boolean = false) {
|
||||
delete announcer.dataset.persist
|
||||
}
|
||||
|
||||
async function navigate(url: URL, isBack: boolean = false) {
|
||||
if (isNavigating) return
|
||||
isNavigating = true
|
||||
try {
|
||||
await _navigate(url, isBack)
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
window.location.assign(url)
|
||||
} finally {
|
||||
isNavigating = false
|
||||
}
|
||||
}
|
||||
|
||||
window.spaNavigate = navigate
|
||||
|
||||
function createRouter() {
|
||||
@@ -160,13 +145,21 @@ function createRouter() {
|
||||
return
|
||||
}
|
||||
|
||||
navigate(url, false)
|
||||
try {
|
||||
navigate(url, false)
|
||||
} catch (e) {
|
||||
window.location.assign(url)
|
||||
}
|
||||
})
|
||||
|
||||
window.addEventListener("popstate", (event) => {
|
||||
const { url } = getOpts(event) ?? {}
|
||||
if (window.location.hash && window.location.pathname === url?.pathname) return
|
||||
navigate(new URL(window.location.toString()), true)
|
||||
try {
|
||||
navigate(new URL(window.location.toString()), true)
|
||||
} catch (e) {
|
||||
window.location.reload()
|
||||
}
|
||||
return
|
||||
})
|
||||
}
|
||||
|
||||
@@ -25,15 +25,16 @@ function toggleToc(this: HTMLElement) {
|
||||
}
|
||||
|
||||
function setupToc() {
|
||||
for (const toc of document.getElementsByClassName("toc")) {
|
||||
const button = toc.querySelector(".toc-header")
|
||||
const content = toc.querySelector(".toc-content")
|
||||
if (!button || !content) return
|
||||
button.addEventListener("click", toggleToc)
|
||||
window.addCleanup(() => button.removeEventListener("click", toggleToc))
|
||||
const toc = document.getElementById("toc")
|
||||
if (toc) {
|
||||
const content = toc.nextElementSibling as HTMLElement | undefined
|
||||
if (!content) return
|
||||
toc.addEventListener("click", toggleToc)
|
||||
window.addCleanup(() => toc.removeEventListener("click", toggleToc))
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("resize", setupToc)
|
||||
document.addEventListener("nav", () => {
|
||||
setupToc()
|
||||
|
||||
|
||||
@@ -29,19 +29,19 @@
|
||||
}
|
||||
|
||||
:root[saved-theme="dark"] .darkmode {
|
||||
& > .dayIcon {
|
||||
& > #dayIcon {
|
||||
display: none;
|
||||
}
|
||||
& > .nightIcon {
|
||||
& > #nightIcon {
|
||||
display: inline;
|
||||
}
|
||||
}
|
||||
|
||||
:root .darkmode {
|
||||
& > .dayIcon {
|
||||
& > #dayIcon {
|
||||
display: inline;
|
||||
}
|
||||
& > .nightIcon {
|
||||
& > #nightIcon {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.hide-until-loaded ~ .explorer-content {
|
||||
.hide-until-loaded ~ #explorer-content {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -30,8 +30,6 @@
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-y: hidden;
|
||||
|
||||
min-height: 1.2rem;
|
||||
flex: 0 1 auto;
|
||||
&.collapsed {
|
||||
flex: 0 1 1.2rem;
|
||||
@@ -54,20 +52,20 @@
|
||||
align-self: flex-start;
|
||||
}
|
||||
|
||||
button.mobile-explorer {
|
||||
button#mobile-explorer {
|
||||
display: none;
|
||||
}
|
||||
|
||||
button.desktop-explorer {
|
||||
button#desktop-explorer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
@media all and ($mobile) {
|
||||
button.mobile-explorer {
|
||||
button#mobile-explorer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
button.desktop-explorer {
|
||||
button#desktop-explorer {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
@@ -88,8 +86,8 @@
|
||||
}
|
||||
}
|
||||
|
||||
button.mobile-explorer,
|
||||
button.desktop-explorer {
|
||||
button#mobile-explorer,
|
||||
button#desktop-explorer {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
text-align: left;
|
||||
@@ -106,7 +104,7 @@ button.desktop-explorer {
|
||||
}
|
||||
}
|
||||
|
||||
.explorer-content {
|
||||
#explorer-content {
|
||||
list-style: none;
|
||||
overflow: hidden;
|
||||
overflow-y: auto;
|
||||
@@ -211,7 +209,7 @@ li:has(> .folder-outer:not(.open)) > .folder-container > svg {
|
||||
&.collapsed {
|
||||
flex: 0 0 34px;
|
||||
|
||||
& > .explorer-content {
|
||||
& > #explorer-content {
|
||||
transform: translateX(-100vw);
|
||||
visibility: hidden;
|
||||
}
|
||||
@@ -220,13 +218,13 @@ li:has(> .folder-outer:not(.open)) > .folder-container > svg {
|
||||
&:not(.collapsed) {
|
||||
flex: 0 0 34px;
|
||||
|
||||
& > .explorer-content {
|
||||
& > #explorer-content {
|
||||
transform: translateX(0);
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
.explorer-content {
|
||||
#explorer-content {
|
||||
box-sizing: border-box;
|
||||
z-index: 100;
|
||||
position: absolute;
|
||||
@@ -247,7 +245,7 @@ li:has(> .folder-outer:not(.open)) > .folder-container > svg {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.mobile-explorer {
|
||||
#mobile-explorer {
|
||||
margin: 0;
|
||||
padding: 5px;
|
||||
z-index: 101;
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
|
||||
& > .global-graph-icon {
|
||||
& > #global-graph-icon {
|
||||
cursor: pointer;
|
||||
background: none;
|
||||
border: none;
|
||||
@@ -38,7 +38,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
& > .global-graph-outer {
|
||||
& > #global-graph-outer {
|
||||
position: fixed;
|
||||
z-index: 9999;
|
||||
left: 0;
|
||||
@@ -53,7 +53,7 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
& > .global-graph-container {
|
||||
& > #global-graph-container {
|
||||
border: 1px solid var(--lightgray);
|
||||
background-color: var(--light);
|
||||
border-radius: 5px;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
details.toc {
|
||||
details#toc {
|
||||
& summary {
|
||||
cursor: pointer;
|
||||
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
& > .search-container {
|
||||
& > #search-container {
|
||||
position: fixed;
|
||||
contain: layout;
|
||||
z-index: 999;
|
||||
@@ -58,7 +58,7 @@
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
& > .search-space {
|
||||
& > #search-space {
|
||||
width: 65%;
|
||||
margin-top: 12vh;
|
||||
margin-left: auto;
|
||||
@@ -91,7 +91,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
& > .search-layout {
|
||||
& > #search-layout {
|
||||
display: none;
|
||||
flex-direction: row;
|
||||
border: 1px solid var(--lightgray);
|
||||
@@ -102,7 +102,7 @@
|
||||
display: flex;
|
||||
}
|
||||
|
||||
&[data-preview] > .results-container {
|
||||
&[data-preview] > #results-container {
|
||||
flex: 0 0 min(30%, 450px);
|
||||
}
|
||||
|
||||
@@ -150,7 +150,7 @@
|
||||
scroll-margin-top: 2rem;
|
||||
}
|
||||
|
||||
& > .preview-container {
|
||||
& > #preview-container {
|
||||
flex-grow: 1;
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
@@ -171,7 +171,7 @@
|
||||
}
|
||||
}
|
||||
|
||||
& > .results-container {
|
||||
& > #results-container {
|
||||
overflow-y: auto;
|
||||
|
||||
& .result-card {
|
||||
|
||||
@@ -5,20 +5,19 @@
|
||||
flex-direction: column;
|
||||
|
||||
overflow-y: hidden;
|
||||
min-height: 4rem;
|
||||
flex: 0 1 auto;
|
||||
&:has(button.toc-header.collapsed) {
|
||||
&:has(button#toc.collapsed) {
|
||||
flex: 0 1 1.2rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media all and not ($mobile) {
|
||||
.toc-header {
|
||||
.toc {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
button.toc-header {
|
||||
button#toc {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
text-align: left;
|
||||
@@ -45,7 +44,7 @@ button.toc-header {
|
||||
}
|
||||
}
|
||||
|
||||
.toc-content {
|
||||
#toc-content {
|
||||
list-style: none;
|
||||
position: relative;
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { ComponentType, JSX } from "preact"
|
||||
import { StaticResources, StringResource } from "../util/resources"
|
||||
import { StaticResources } from "../util/resources"
|
||||
import { QuartzPluginData } from "../plugins/vfile"
|
||||
import { GlobalConfiguration } from "../cfg"
|
||||
import { Node } from "hast"
|
||||
@@ -19,9 +19,9 @@ export type QuartzComponentProps = {
|
||||
}
|
||||
|
||||
export type QuartzComponent = ComponentType<QuartzComponentProps> & {
|
||||
css?: StringResource
|
||||
beforeDOMLoaded?: StringResource
|
||||
afterDOMLoaded?: StringResource
|
||||
css?: string
|
||||
beforeDOMLoaded?: string
|
||||
afterDOMLoaded?: string
|
||||
}
|
||||
|
||||
export type QuartzComponentConstructor<Options extends object | undefined = undefined> = (
|
||||
|
||||
@@ -36,21 +36,17 @@ function getComponentResources(ctx: BuildCtx): ComponentResources {
|
||||
afterDOMLoaded: new Set<string>(),
|
||||
}
|
||||
|
||||
function normalizeResource(resource: string | string[] | undefined): string[] {
|
||||
if (!resource) return []
|
||||
if (Array.isArray(resource)) return resource
|
||||
return [resource]
|
||||
}
|
||||
|
||||
for (const component of allComponents) {
|
||||
const { css, beforeDOMLoaded, afterDOMLoaded } = component
|
||||
const normalizedCss = normalizeResource(css)
|
||||
const normalizedBeforeDOMLoaded = normalizeResource(beforeDOMLoaded)
|
||||
const normalizedAfterDOMLoaded = normalizeResource(afterDOMLoaded)
|
||||
|
||||
normalizedCss.forEach((c) => componentResources.css.add(c))
|
||||
normalizedBeforeDOMLoaded.forEach((b) => componentResources.beforeDOMLoaded.add(b))
|
||||
normalizedAfterDOMLoaded.forEach((a) => componentResources.afterDOMLoaded.add(a))
|
||||
if (css) {
|
||||
componentResources.css.add(css)
|
||||
}
|
||||
if (beforeDOMLoaded) {
|
||||
componentResources.beforeDOMLoaded.add(beforeDOMLoaded)
|
||||
}
|
||||
if (afterDOMLoaded) {
|
||||
componentResources.afterDOMLoaded.add(afterDOMLoaded)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
|
||||
@@ -16,12 +16,9 @@ import path from "path"
|
||||
import { splitAnchor } from "../../util/path"
|
||||
import { JSResource, CSSResource } from "../../util/resources"
|
||||
// @ts-ignore
|
||||
import calloutScript from "../../components/scripts/callout.inline"
|
||||
import calloutScript from "../../components/scripts/callout.inline.ts"
|
||||
// @ts-ignore
|
||||
import checkboxScript from "../../components/scripts/checkbox.inline"
|
||||
// @ts-ignore
|
||||
import mermaidScript from "../../components/scripts/mermaid.inline"
|
||||
import mermaidStyle from "../../components/styles/mermaid.inline.scss"
|
||||
import checkboxScript from "../../components/scripts/checkbox.inline.ts"
|
||||
import { FilePath, pathToRoot, slugTag, slugifyFilePath } from "../../util/path"
|
||||
import { toHast } from "mdast-util-to-hast"
|
||||
import { toHtml } from "hast-util-to-html"
|
||||
@@ -809,20 +806,6 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>>
|
||||
})
|
||||
}
|
||||
|
||||
if (opts.mermaid) {
|
||||
js.push({
|
||||
script: mermaidScript,
|
||||
loadTime: "afterDOMReady",
|
||||
contentType: "inline",
|
||||
moduleType: "module",
|
||||
})
|
||||
|
||||
css.push({
|
||||
content: mermaidStyle,
|
||||
inline: true,
|
||||
})
|
||||
}
|
||||
|
||||
return { js, css }
|
||||
},
|
||||
}
|
||||
|
||||
@@ -351,10 +351,6 @@ h6 {
|
||||
&[id]:hover > a {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
&:not([id]) > a[role="anchor"] {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
// typography improvements
|
||||
@@ -542,7 +538,7 @@ video {
|
||||
}
|
||||
|
||||
.spacer {
|
||||
flex: 2 1 auto;
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
div:has(> .overflow) {
|
||||
@@ -555,14 +551,17 @@ ol.overflow {
|
||||
max-height: 100%;
|
||||
overflow-y: auto;
|
||||
width: 100%;
|
||||
margin-bottom: 0;
|
||||
|
||||
// clearfix
|
||||
content: "";
|
||||
clear: both;
|
||||
|
||||
& > li:last-of-type {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
|
||||
& > li.overflow-end {
|
||||
height: 1rem;
|
||||
height: 4px;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,15 +11,16 @@ describe("FileTrie", () => {
|
||||
let trie: FileTrieNode<TestData>
|
||||
|
||||
beforeEach(() => {
|
||||
trie = new FileTrieNode<TestData>([])
|
||||
trie = new FileTrieNode<TestData>("")
|
||||
})
|
||||
|
||||
describe("constructor", () => {
|
||||
test("should create an empty trie", () => {
|
||||
assert.deepStrictEqual(trie.children, [])
|
||||
assert.strictEqual(trie.slug, "")
|
||||
assert.strictEqual(trie.slugSegment, "")
|
||||
assert.strictEqual(trie.displayName, "")
|
||||
assert.strictEqual(trie.data, null)
|
||||
assert.strictEqual(trie.depth, 0)
|
||||
})
|
||||
|
||||
test("should set displayName from data title", () => {
|
||||
@@ -42,7 +43,7 @@ describe("FileTrie", () => {
|
||||
|
||||
trie.add(data)
|
||||
assert.strictEqual(trie.children.length, 1)
|
||||
assert.strictEqual(trie.children[0].slug, "test")
|
||||
assert.strictEqual(trie.children[0].slugSegment, "test")
|
||||
assert.strictEqual(trie.children[0].data, data)
|
||||
})
|
||||
|
||||
@@ -71,20 +72,20 @@ describe("FileTrie", () => {
|
||||
trie.add(data1)
|
||||
trie.add(data2)
|
||||
assert.strictEqual(trie.children.length, 2)
|
||||
assert.strictEqual(trie.children[0].slug, "folder/index")
|
||||
assert.strictEqual(trie.children[0].slugSegment, "folder")
|
||||
assert.strictEqual(trie.children[0].children.length, 1)
|
||||
assert.strictEqual(trie.children[0].children[0].slug, "folder/test")
|
||||
assert.strictEqual(trie.children[0].children[0].slugSegment, "test")
|
||||
assert.strictEqual(trie.children[0].children[0].data, data1)
|
||||
|
||||
assert.strictEqual(trie.children[1].slug, "a/index")
|
||||
assert.strictEqual(trie.children[1].slugSegment, "a")
|
||||
assert.strictEqual(trie.children[1].children.length, 1)
|
||||
assert.strictEqual(trie.children[1].data, null)
|
||||
|
||||
assert.strictEqual(trie.children[1].children[0].slug, "a/b/index")
|
||||
assert.strictEqual(trie.children[1].children[0].slugSegment, "b")
|
||||
assert.strictEqual(trie.children[1].children[0].children.length, 1)
|
||||
assert.strictEqual(trie.children[1].children[0].data, null)
|
||||
|
||||
assert.strictEqual(trie.children[1].children[0].children[0].slug, "a/b/c/index")
|
||||
assert.strictEqual(trie.children[1].children[0].children[0].slugSegment, "c")
|
||||
assert.strictEqual(trie.children[1].children[0].children[0].data, data2)
|
||||
assert.strictEqual(trie.children[1].children[0].children[0].children.length, 0)
|
||||
})
|
||||
@@ -98,9 +99,9 @@ describe("FileTrie", () => {
|
||||
trie.add(data1)
|
||||
trie.add(data2)
|
||||
|
||||
trie.filter((node) => node.slug !== "test1")
|
||||
trie.filter((node) => node.slugSegment !== "test1")
|
||||
assert.strictEqual(trie.children.length, 1)
|
||||
assert.strictEqual(trie.children[0].slug, "test2")
|
||||
assert.strictEqual(trie.children[0].slugSegment, "test2")
|
||||
})
|
||||
})
|
||||
|
||||
@@ -114,7 +115,7 @@ describe("FileTrie", () => {
|
||||
|
||||
trie.map((node) => {
|
||||
if (node.data) {
|
||||
node.data.title = "Modified"
|
||||
node.displayName = "Modified"
|
||||
}
|
||||
})
|
||||
|
||||
@@ -135,7 +136,7 @@ describe("FileTrie", () => {
|
||||
assert.deepStrictEqual(
|
||||
entries.map(([path, node]) => [path, node.data]),
|
||||
[
|
||||
["index", trie.data],
|
||||
["", trie.data],
|
||||
["test1", data1],
|
||||
["a/index", null],
|
||||
["a/b/index", null],
|
||||
@@ -165,12 +166,7 @@ describe("FileTrie", () => {
|
||||
trie.add(data3)
|
||||
const paths = trie.getFolderPaths()
|
||||
|
||||
assert.deepStrictEqual(paths, [
|
||||
"index",
|
||||
"folder/index",
|
||||
"folder/subfolder/index",
|
||||
"abc/index",
|
||||
])
|
||||
assert.deepStrictEqual(paths, ["folder/index", "folder/subfolder/index", "abc/index"])
|
||||
})
|
||||
})
|
||||
|
||||
@@ -184,9 +180,9 @@ describe("FileTrie", () => {
|
||||
trie.add(data1)
|
||||
trie.add(data2)
|
||||
|
||||
trie.sort((a, b) => a.slug.localeCompare(b.slug))
|
||||
trie.sort((a, b) => a.slugSegment.localeCompare(b.slugSegment))
|
||||
assert.deepStrictEqual(
|
||||
trie.children.map((n) => n.slug),
|
||||
trie.children.map((n) => n.slugSegment),
|
||||
["a", "b", "c"],
|
||||
)
|
||||
})
|
||||
|
||||
@@ -7,64 +7,55 @@ interface FileTrieData {
|
||||
}
|
||||
|
||||
export class FileTrieNode<T extends FileTrieData = ContentDetails> {
|
||||
isFolder: boolean
|
||||
children: Array<FileTrieNode<T>>
|
||||
|
||||
private slugSegments: string[]
|
||||
slugSegment: string
|
||||
displayName: string
|
||||
data: T | null
|
||||
depth: number
|
||||
isFolder: boolean
|
||||
|
||||
constructor(segments: string[], data?: T) {
|
||||
constructor(segment: string, data?: T, depth: number = 0) {
|
||||
this.children = []
|
||||
this.slugSegments = segments
|
||||
this.slugSegment = segment
|
||||
this.displayName = data?.title ?? segment
|
||||
this.data = data ?? null
|
||||
this.isFolder = false
|
||||
}
|
||||
|
||||
get displayName(): string {
|
||||
return this.data?.title ?? this.slugSegment ?? ""
|
||||
}
|
||||
|
||||
get slug(): FullSlug {
|
||||
const path = joinSegments(...this.slugSegments) as FullSlug
|
||||
if (this.isFolder) {
|
||||
return joinSegments(path, "index") as FullSlug
|
||||
}
|
||||
|
||||
return path
|
||||
}
|
||||
|
||||
get slugSegment(): string {
|
||||
return this.slugSegments[this.slugSegments.length - 1]
|
||||
}
|
||||
|
||||
private makeChild(path: string[], file?: T) {
|
||||
const fullPath = [...this.slugSegments, path[0]]
|
||||
const child = new FileTrieNode<T>(fullPath, file)
|
||||
this.children.push(child)
|
||||
return child
|
||||
this.depth = depth
|
||||
this.isFolder = segment === "index"
|
||||
}
|
||||
|
||||
private insert(path: string[], file: T) {
|
||||
if (path.length === 0) {
|
||||
throw new Error("path is empty")
|
||||
if (path.length === 0) return
|
||||
|
||||
const nextSegment = path[0]
|
||||
|
||||
// base case, insert here
|
||||
if (path.length === 1) {
|
||||
if (nextSegment === "index") {
|
||||
// index case (we are the root and we just found index.md)
|
||||
this.data ??= file
|
||||
const title = file.title
|
||||
if (title !== "index") {
|
||||
this.displayName = title
|
||||
}
|
||||
} else {
|
||||
// direct child
|
||||
this.children.push(new FileTrieNode(nextSegment, file, this.depth + 1))
|
||||
this.isFolder = true
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// if we are inserting, we are a folder
|
||||
this.isFolder = true
|
||||
const segment = path[0]
|
||||
if (path.length === 1) {
|
||||
// base case, we are at the end of the path
|
||||
if (segment === "index") {
|
||||
this.data ??= file
|
||||
} else {
|
||||
this.makeChild(path, file)
|
||||
}
|
||||
} else if (path.length > 1) {
|
||||
// recursive case, we are not at the end of the path
|
||||
const child =
|
||||
this.children.find((c) => c.slugSegment === segment) ?? this.makeChild(path, undefined)
|
||||
child.insert(path.slice(1), file)
|
||||
// find the right child to insert into, creating it if it doesn't exist
|
||||
path = path.splice(1)
|
||||
let child = this.children.find((c) => c.slugSegment === nextSegment)
|
||||
if (!child) {
|
||||
child = new FileTrieNode<T>(nextSegment, undefined, this.depth + 1)
|
||||
this.children.push(child)
|
||||
child.isFolder = true
|
||||
}
|
||||
|
||||
child.insert(path, file)
|
||||
}
|
||||
|
||||
// Add new file to trie
|
||||
@@ -97,7 +88,7 @@ export class FileTrieNode<T extends FileTrieData = ContentDetails> {
|
||||
}
|
||||
|
||||
static fromEntries<T extends FileTrieData>(entries: [FullSlug, T][]) {
|
||||
const trie = new FileTrieNode<T>([])
|
||||
const trie = new FileTrieNode<T>("")
|
||||
entries.forEach(([, entry]) => trie.add(entry))
|
||||
return trie
|
||||
}
|
||||
@@ -107,12 +98,22 @@ export class FileTrieNode<T extends FileTrieData = ContentDetails> {
|
||||
* in the a flat array including the full path and the node
|
||||
*/
|
||||
entries(): [FullSlug, FileTrieNode<T>][] {
|
||||
const traverse = (node: FileTrieNode<T>): [FullSlug, FileTrieNode<T>][] => {
|
||||
const result: [FullSlug, FileTrieNode<T>][] = [[node.slug, node]]
|
||||
return result.concat(...node.children.map(traverse))
|
||||
const traverse = (
|
||||
node: FileTrieNode<T>,
|
||||
currentPath: string,
|
||||
): [FullSlug, FileTrieNode<T>][] => {
|
||||
const segments = [currentPath, node.slugSegment]
|
||||
const fullPath = joinSegments(...segments) as FullSlug
|
||||
|
||||
const indexQualifiedPath =
|
||||
node.isFolder && node.depth > 0 ? (joinSegments(fullPath, "index") as FullSlug) : fullPath
|
||||
|
||||
const result: [FullSlug, FileTrieNode<T>][] = [[indexQualifiedPath, node]]
|
||||
|
||||
return result.concat(...node.children.map((child) => traverse(child, fullPath)))
|
||||
}
|
||||
|
||||
return traverse(this)
|
||||
return traverse(this, "")
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export function randomIdNonSecure() {
|
||||
return Math.random().toString(36).substring(2, 8)
|
||||
}
|
||||
@@ -65,10 +65,3 @@ export interface StaticResources {
|
||||
js: JSResource[]
|
||||
additionalHead: (JSX.Element | ((pageData: QuartzPluginData) => JSX.Element))[]
|
||||
}
|
||||
|
||||
export type StringResource = string | string[] | undefined
|
||||
export function concatenateResources(...resources: StringResource[]): StringResource {
|
||||
return resources
|
||||
.filter((resource): resource is string | string[] => resource !== undefined)
|
||||
.flat()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user