This commit is contained in:
SemanticData 2024-03-05 17:12:59 -06:00
commit 421cd4820e
12 changed files with 261 additions and 112 deletions

View File

@ -73,10 +73,10 @@ You can customize the behaviour of Quartz by adding, removing and reordering plu
> [!note]
> Each node is modified by every transformer _in order_. Some transformers are position sensitive, so you may need to pay particular attention to whether they need to come before or after certain other plugins.
You should take care to add the plugin to the right entry corresponding to its plugin type. For example, to add the [[ExplicitPublish]] plugin (a [[tags/plugin/transformer|Transformer]], you would add the following line:
You should take care to add the plugin to the right entry corresponding to its plugin type. For example, to add the [[ExplicitPublish]] plugin (a [[tags/plugin/filter|Filter]]), you would add the following line:
```ts title="quartz.config.ts"
transformers: [
filters: [
...
Plugin.ExplicitPublish(),
...

View File

@ -61,7 +61,7 @@ export class FileNode {
children: FileNode[] // children of current node
name: string // last part of slug
displayName: string // what actually should be displayed in the explorer
file: QuartzPluginData | null // set if node is a file, see `QuartzPluginData` for more detail
file: QuartzPluginData | null // if node is a file, this is the file's metadata. See `QuartzPluginData` for more detail
depth: number // depth of current node
... // rest of implementation
@ -167,6 +167,19 @@ Component.Explorer({
You can customize this by changing the entries of the `omit` set. Simply add all folder or file names you want to remove.
### Remove files by tag
You can access the frontmatter of a file by `node.file?.frontmatter?`. This allows you to filter out files based on their frontmatter, for example by their tags.
```ts title="quartz.layout.ts"
Component.Explorer({
filterFn: (node) => {
// exclude files with the tag "explorerexclude"
return node.file?.frontmatter?.tags?.includes("explorerexclude") !== true
},
})
```
### Show every element in explorer
To override the default filter function that removes the `tags` folder from the explorer, you can set the filter function to `undefined`.

View File

@ -14,6 +14,7 @@ If the frontmatter contains a `description` property, it is used (see [[authorin
This plugin accepts the following configuration options:
- `descriptionLength`: the maximum length of the generated description. Default is 150 characters. The cut off happens after the first _sentence_ that ends after the given length.
- `replaceExternalLinks`: If `true` (default), replace external links with their domain and path in the description (e.g. `https://domain.tld/some_page/another_page?query=hello&target=world` is replaced with `domain.tld/some_page/another_page`).
## API

View File

@ -13,6 +13,6 @@ This plugin has no configuration options.
## API
- Category: Emitter
- Category: Filter
- Function name: `Plugin.ExplicitPublish()`.
- Source: [`quartz/plugins/filters/explicit.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/filters/explicit.ts).

155
package-lock.json generated
View File

@ -14,7 +14,7 @@
"@napi-rs/simple-git": "0.1.16",
"async-mutex": "^0.4.1",
"chalk": "^5.3.0",
"chokidar": "^3.5.3",
"chokidar": "^3.6.0",
"cli-spinner": "^0.2.10",
"d3": "^7.8.5",
"esbuild-sass-plugin": "^2.16.1",
@ -27,13 +27,13 @@
"hast-util-to-string": "^3.0.0",
"is-absolute-url": "^4.0.1",
"js-yaml": "^4.1.0",
"lightningcss": "^1.23.0",
"lightningcss": "^1.24.0",
"mdast-util-find-and-replace": "^3.0.1",
"mdast-util-to-hast": "^13.1.0",
"mdast-util-to-string": "^4.0.0",
"micromorph": "^0.4.5",
"preact": "^10.19.5",
"preact-render-to-string": "^6.3.1",
"preact": "^10.19.6",
"preact-render-to-string": "^6.4.0",
"pretty-bytes": "^6.1.1",
"pretty-time": "^1.1.0",
"reading-time": "^1.5.0",
@ -50,11 +50,11 @@
"remark-math": "^6.0.0",
"remark-parse": "^11.0.0",
"remark-rehype": "^11.1.0",
"remark-smartypants": "^2.0.0",
"remark-smartypants": "^2.1.0",
"rfdc": "^1.3.1",
"rimraf": "^5.0.5",
"serve-handler": "^6.1.5",
"shiki": "^1.1.6",
"shiki": "^1.1.7",
"source-map-support": "^0.5.21",
"to-vfile": "^8.0.0",
"toml": "^3.0.0",
@ -743,9 +743,9 @@
}
},
"node_modules/@shikijs/core": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.1.6.tgz",
"integrity": "sha512-kt9hhvrWTm0EPtRDIsoAZnSsFlIDBVBBI5CQewpA/NZCPin+MOKRXg+JiWc4y+8fZ/v0HzfDhu/UC+OTZGMt7A=="
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/@shikijs/core/-/core-1.1.7.tgz",
"integrity": "sha512-gTYLUIuD1UbZp/11qozD3fWpUTuMqPSf3svDMMrL0UmlGU7D9dPw/V1FonwAorCUJBltaaESxq90jrSjQyGixg=="
},
"node_modules/@sindresorhus/merge-streams": {
"version": "2.3.0",
@ -1344,15 +1344,9 @@
}
},
"node_modules/chokidar": {
"version": "3.5.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz",
"integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==",
"funding": [
{
"type": "individual",
"url": "https://paulmillr.com/funding/"
}
],
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
"dependencies": {
"anymatch": "~3.1.2",
"braces": "~3.0.2",
@ -1365,6 +1359,9 @@
"engines": {
"node": ">= 8.10.0"
},
"funding": {
"url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
@ -3035,9 +3032,9 @@
}
},
"node_modules/lightningcss": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.23.0.tgz",
"integrity": "sha512-SEArWKMHhqn/0QzOtclIwH5pXIYQOUEkF8DgICd/105O+GCgd7jxjNod/QPnBCSWvpRHQBGVz5fQ9uScby03zA==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.24.0.tgz",
"integrity": "sha512-y36QEEDVx4IM7/yIZNsZJMRREIu26WzTsauIysf5s76YeCmlSbRZS7aC97IGPuoFRnyZ5Wx43OBsQBFB5Ne7ng==",
"dependencies": {
"detect-libc": "^1.0.3"
},
@ -3049,21 +3046,21 @@
"url": "https://opencollective.com/parcel"
},
"optionalDependencies": {
"lightningcss-darwin-arm64": "1.23.0",
"lightningcss-darwin-x64": "1.23.0",
"lightningcss-freebsd-x64": "1.23.0",
"lightningcss-linux-arm-gnueabihf": "1.23.0",
"lightningcss-linux-arm64-gnu": "1.23.0",
"lightningcss-linux-arm64-musl": "1.23.0",
"lightningcss-linux-x64-gnu": "1.23.0",
"lightningcss-linux-x64-musl": "1.23.0",
"lightningcss-win32-x64-msvc": "1.23.0"
"lightningcss-darwin-arm64": "1.24.0",
"lightningcss-darwin-x64": "1.24.0",
"lightningcss-freebsd-x64": "1.24.0",
"lightningcss-linux-arm-gnueabihf": "1.24.0",
"lightningcss-linux-arm64-gnu": "1.24.0",
"lightningcss-linux-arm64-musl": "1.24.0",
"lightningcss-linux-x64-gnu": "1.24.0",
"lightningcss-linux-x64-musl": "1.24.0",
"lightningcss-win32-x64-msvc": "1.24.0"
}
},
"node_modules/lightningcss-darwin-arm64": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.23.0.tgz",
"integrity": "sha512-kl4Pk3Q2lnE6AJ7Qaij47KNEfY2/UXRZBT/zqGA24B8qwkgllr/j7rclKOf1axcslNXvvUdztjo4Xqh39Yq1aA==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.24.0.tgz",
"integrity": "sha512-rTNPkEiynOu4CfGdd5ZfVOQe2gd2idfQd4EfX1l2ZUUwd+2SwSdbb7cG4rlwfnZckbzCAygm85xkpekRE5/wFw==",
"cpu": [
"arm64"
],
@ -3080,9 +3077,9 @@
}
},
"node_modules/lightningcss-darwin-x64": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.23.0.tgz",
"integrity": "sha512-KeRFCNoYfDdcolcFXvokVw+PXCapd2yHS1Diko1z1BhRz/nQuD5XyZmxjWdhmhN/zj5sH8YvWsp0/lPLVzqKpg==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.24.0.tgz",
"integrity": "sha512-4KCeF2RJjzp9xdGY8zIH68CUtptEg8uz8PfkHvsIdrP4t9t5CIgfDBhiB8AmuO75N6SofdmZexDZIKdy9vA7Ww==",
"cpu": [
"x64"
],
@ -3099,9 +3096,9 @@
}
},
"node_modules/lightningcss-freebsd-x64": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.23.0.tgz",
"integrity": "sha512-xhnhf0bWPuZxcqknvMDRFFo2TInrmQRWZGB0f6YoAsZX8Y+epfjHeeOIGCfAmgF0DgZxHwYc8mIR5tQU9/+ROA==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.24.0.tgz",
"integrity": "sha512-FJAYlek1wXuVTsncNU0C6YD41q126dXcIUm97KAccMn9C4s/JfLSqGWT2gIzAblavPFkyGG2gIADTWp3uWfN1g==",
"cpu": [
"x64"
],
@ -3118,9 +3115,9 @@
}
},
"node_modules/lightningcss-linux-arm-gnueabihf": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.23.0.tgz",
"integrity": "sha512-fBamf/bULvmWft9uuX+bZske236pUZEoUlaHNBjnueaCTJ/xd8eXgb0cEc7S5o0Nn6kxlauMBnqJpF70Bgq3zg==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.24.0.tgz",
"integrity": "sha512-N55K6JqzMx7C0hYUu1YmWqhkHwzEJlkQRMA6phY65noO0I1LOAvP4wBIoFWrzRE+O6zL0RmXJ2xppqyTbk3sYw==",
"cpu": [
"arm"
],
@ -3137,9 +3134,9 @@
}
},
"node_modules/lightningcss-linux-arm64-gnu": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.23.0.tgz",
"integrity": "sha512-RS7sY77yVLOmZD6xW2uEHByYHhQi5JYWmgVumYY85BfNoVI3DupXSlzbw+b45A9NnVKq45+oXkiN6ouMMtTwfg==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.24.0.tgz",
"integrity": "sha512-MqqUB2TpYtFWeBvvf5KExDdClU3YGLW5bHKs50uKKootcvG9KoS7wYwd5UichS+W3mYLc5yXUPGD1DNWbLiYKw==",
"cpu": [
"arm64"
],
@ -3156,9 +3153,9 @@
}
},
"node_modules/lightningcss-linux-arm64-musl": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.23.0.tgz",
"integrity": "sha512-cU00LGb6GUXCwof6ACgSMKo3q7XYbsyTj0WsKHLi1nw7pV0NCq8nFTn6ZRBYLoKiV8t+jWl0Hv8KkgymmK5L5g==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.24.0.tgz",
"integrity": "sha512-5wn4d9tFwa5bS1ao9mLexYVJdh3nn09HNIipsII6ZF7z9ZA5J4dOEhMgKoeCl891axTGTUYd8Kxn+Hn3XUSYRQ==",
"cpu": [
"arm64"
],
@ -3175,9 +3172,9 @@
}
},
"node_modules/lightningcss-linux-x64-gnu": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.23.0.tgz",
"integrity": "sha512-q4jdx5+5NfB0/qMbXbOmuC6oo7caPnFghJbIAV90cXZqgV8Am3miZhC4p+sQVdacqxfd+3nrle4C8icR3p1AYw==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.24.0.tgz",
"integrity": "sha512-3j5MdTh+LSDF3o6uDwRjRUgw4J+IfDCVtdkUrJvKxL79qBLUujXY7CTe5X3IQDDLKEe/3wu49r8JKgxr0MfjbQ==",
"cpu": [
"x64"
],
@ -3194,9 +3191,9 @@
}
},
"node_modules/lightningcss-linux-x64-musl": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.23.0.tgz",
"integrity": "sha512-G9Ri3qpmF4qef2CV/80dADHKXRAQeQXpQTLx7AiQrBYQHqBjB75oxqj06FCIe5g4hNCqLPnM9fsO4CyiT1sFSQ==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.24.0.tgz",
"integrity": "sha512-HI+rNnvaLz0o36z6Ki0gyG5igVGrJmzczxA5fznr6eFTj3cHORoR/j2q8ivMzNFR4UKJDkTWUH5LMhacwOHWBA==",
"cpu": [
"x64"
],
@ -3213,9 +3210,9 @@
}
},
"node_modules/lightningcss-win32-x64-msvc": {
"version": "1.23.0",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.23.0.tgz",
"integrity": "sha512-1rcBDJLU+obPPJM6qR5fgBUiCdZwZLafZM5f9kwjFLkb/UBNIzmae39uCSmh71nzPCTXZqHbvwu23OWnWEz+eg==",
"version": "1.24.0",
"resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.24.0.tgz",
"integrity": "sha512-oeije/t7OZ5N9vSs6amyW/34wIYoBCpE6HUlsSKcP2SR1CVgx9oKEM00GtQmtqNnYiMIfsSm7+ppMb4NLtD5vg==",
"cpu": [
"x64"
],
@ -4459,18 +4456,18 @@
}
},
"node_modules/preact": {
"version": "10.19.5",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.19.5.tgz",
"integrity": "sha512-OPELkDmSVbKjbFqF9tgvOowiiQ9TmsJljIzXRyNE8nGiis94pwv1siF78rQkAP1Q1738Ce6pellRg/Ns/CtHqQ==",
"version": "10.19.6",
"resolved": "https://registry.npmjs.org/preact/-/preact-10.19.6.tgz",
"integrity": "sha512-gympg+T2Z1fG1unB8NH29yHJwnEaCH37Z32diPDku316OTnRPeMbiRV9kTrfZpocXjdfnWuFUl/Mj4BHaf6gnw==",
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/preact"
}
},
"node_modules/preact-render-to-string": {
"version": "6.3.1",
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.3.1.tgz",
"integrity": "sha512-NQ28WrjLtWY6lKDlTxnFpKHZdpjfF+oE6V4tZ0rTrunHrtZp6Dm0oFrcJalt/5PNeqJz4j1DuZDS0Y6rCBoqDA==",
"version": "6.4.0",
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.4.0.tgz",
"integrity": "sha512-pzDwezZaLbK371OiJjXDsZJwVOALzFX5M1wEh2Kr0pEApq5AV6bRH/DFbA/zNA7Lck/duyREPQLLvzu2G6hEQQ==",
"dependencies": {
"pretty-format": "^3.8.0"
},
@ -4869,32 +4866,18 @@
}
},
"node_modules/remark-smartypants": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-2.0.0.tgz",
"integrity": "sha512-Rc0VDmr/yhnMQIz8n2ACYXlfw/P/XZev884QU1I5u+5DgJls32o97Vc1RbK3pfumLsJomS2yy8eT4Fxj/2MDVA==",
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/remark-smartypants/-/remark-smartypants-2.1.0.tgz",
"integrity": "sha512-qoF6Vz3BjU2tP6OfZqHOvCU0ACmu/6jhGaINSQRI9mM7wCxNQTKB3JUAN4SVoN2ybElEDTxBIABRep7e569iJw==",
"dependencies": {
"retext": "^8.1.0",
"retext-smartypants": "^5.1.0",
"unist-util-visit": "^4.1.0"
"retext-smartypants": "^5.2.0",
"unist-util-visit": "^5.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
}
},
"node_modules/remark-smartypants/node_modules/unist-util-visit": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/unist-util-visit/-/unist-util-visit-4.1.2.tgz",
"integrity": "sha512-MSd8OUGISqHdVvfY9TPhyK2VdUrPgxkUtWSuMHF6XAAFuL4LokseigBnZtPnJMu+FbynTkFNnFlyjxpVKujMRg==",
"dependencies": {
"@types/unist": "^2.0.0",
"unist-util-is": "^5.0.0",
"unist-util-visit-parents": "^5.1.1"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/unified"
}
},
"node_modules/remark-stringify": {
"version": "11.0.0",
"resolved": "https://registry.npmjs.org/remark-stringify/-/remark-stringify-11.0.0.tgz",
@ -5327,11 +5310,11 @@
}
},
"node_modules/shiki": {
"version": "1.1.6",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.1.6.tgz",
"integrity": "sha512-j4pcpvaQWHb42cHeV+W6P+X/VcK7Y2ctvEham6zB8wsuRQroT6cEMIkiUmBU2Nqg2qnHZDH6ZyRdVldcy0l6xw==",
"version": "1.1.7",
"resolved": "https://registry.npmjs.org/shiki/-/shiki-1.1.7.tgz",
"integrity": "sha512-9kUTMjZtcPH3i7vHunA6EraTPpPOITYTdA5uMrvsJRexktqP0s7P3s9HVK80b4pP42FRVe03D7fT3NmJv2yYhw==",
"dependencies": {
"@shikijs/core": "1.1.6"
"@shikijs/core": "1.1.7"
}
},
"node_modules/signal-exit": {

View File

@ -17,6 +17,7 @@ export interface D3Config {
opacityScale: number
removeTags: string[]
showTags: boolean
focusOnHover?: boolean
}
interface GraphOptions {
@ -37,6 +38,7 @@ const defaultOptions: GraphOptions = {
opacityScale: 1,
showTags: true,
removeTags: [],
focusOnHover: false,
},
globalGraph: {
drag: true,
@ -50,6 +52,7 @@ const defaultOptions: GraphOptions = {
opacityScale: 1,
showTags: true,
removeTags: [],
focusOnHover: true,
},
}

View File

@ -44,6 +44,7 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
opacityScale,
removeTags,
showTags,
focusOnHover,
} = JSON.parse(graph.dataset["cfg"]!)
const data: Map<SimpleSlug, ContentDetails> = new Map(
@ -189,6 +190,8 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
return 2 + Math.sqrt(numLinks)
}
let connectedNodes: SimpleSlug[] = []
// draw individual nodes
const node = graphNode
.append("circle")
@ -202,17 +205,25 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
window.spaNavigate(new URL(targ, window.location.toString()))
})
.on("mouseover", function (_, d) {
const neighbours: SimpleSlug[] = data.get(slug)?.links ?? []
const neighbourNodes = d3
.selectAll<HTMLElement, NodeData>(".node")
.filter((d) => neighbours.includes(d.id))
const currentId = d.id
const linkNodes = d3
.selectAll(".link")
.filter((d: any) => d.source.id === currentId || d.target.id === currentId)
// highlight neighbour nodes
neighbourNodes.transition().duration(200).attr("fill", color)
if (focusOnHover) {
// fade out non-neighbour nodes
connectedNodes = linkNodes.data().flatMap((d: any) => [d.source.id, d.target.id])
d3.selectAll<HTMLElement, NodeData>(".link")
.transition()
.duration(200)
.style("opacity", 0.2)
d3.selectAll<HTMLElement, NodeData>(".node")
.filter((d) => !connectedNodes.includes(d.id))
.transition()
.duration(200)
.style("opacity", 0.2)
}
// highlight links
linkNodes.transition().duration(200).attr("stroke", "var(--gray)").attr("stroke-width", 1)
@ -231,6 +242,10 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
.style("font-size", bigFont + "em")
})
.on("mouseleave", function (_, d) {
if (focusOnHover) {
d3.selectAll<HTMLElement, NodeData>(".link").transition().duration(200).style("opacity", 1)
d3.selectAll<HTMLElement, NodeData>(".node").transition().duration(200).style("opacity", 1)
}
const currentId = d.id
const linkNodes = d3
.selectAll(".link")

View File

@ -12,6 +12,7 @@ import uk from "./locales/uk-UA"
import ru from "./locales/ru-RU"
import ko from "./locales/ko-KR"
import zh from "./locales/zh-CN"
import vi from "./locales/vi-VN"
export const TRANSLATIONS = {
"en-US": en,
@ -48,6 +49,7 @@ export const TRANSLATIONS = {
"ru-RU": ru,
"ko-KR": ko,
"zh-CN": zh,
"vi-VN": vi,
} as const
export const defaultTranslation = "en-US"

View File

@ -0,0 +1,83 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Không có tiêu đề",
description: "Không có mô tả được cung cấp",
},
components: {
callout: {
note: "Ghi Chú",
abstract: "Tóm Tắt",
info: "Thông tin",
todo: "Cần Làm",
tip: "Gợi Ý",
success: "Thành Công",
question: "Nghi Vấn",
warning: "Cảnh Báo",
failure: "Thất Bại",
danger: "Nguy Hiểm",
bug: "Lỗi",
example: "Ví Dụ",
quote: "Trích Dẫn",
},
backlinks: {
title: "Liên Kết Ngược",
noBacklinksFound: "Không có liên kết ngược được tìm thấy",
},
themeToggle: {
lightMode: "Sáng",
darkMode: "Tối",
},
explorer: {
title: "Trong bài này",
},
footer: {
createdWith: "Được tạo bởi",
},
graph: {
title: "Biểu Đồ",
},
recentNotes: {
title: "Bài viết gần đây",
seeRemainingMore: ({ remaining }) => `Xem ${remaining} thêm →`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `Bao gồm ${targetSlug}`,
linkToOriginal: "Liên Kết Gốc",
},
search: {
title: "Tìm Kiếm",
searchBarPlaceholder: "Tìm kiếm thông tin",
},
tableOfContents: {
title: "Bảng Nội Dung",
},
contentMeta: {
readingTime: ({ minutes }) => `đọc ${minutes} phút`,
},
},
pages: {
rss: {
recentNotes: "Những bài gần đây",
lastFewNotes: ({ count }) => `${count} Bài gần đây`,
},
error: {
title: "Không Tìm Thấy",
notFound: "Trang này được bảo mật hoặc không tồn tại.",
},
folderContent: {
folder: "Thư Mục",
itemsUnderFolder: ({ count }) =>
count === 1 ? "1 mục trong thư mục này." : `${count} mục trong thư mục này.`,
},
tagContent: {
tag: "Thẻ",
tagIndex: "Thẻ Mục Lục",
itemsUnderTag: ({ count }) =>
count === 1 ? "1 mục gắn thẻ này." : `${count} mục gắn thẻ này.`,
showingFirst: ({ count }) => `Hiển thị trước ${count} thẻ.`,
totalTags: ({ count }) => `Tìm thấy ${count} thẻ tổng cộng.`,
},
},
} as const satisfies Translation

View File

@ -120,7 +120,7 @@ function addGlobalPageResources(
} else if (cfg.analytics?.provider === "umami") {
componentResources.afterDOMLoaded.push(`
const umamiScript = document.createElement("script")
umamiScript.src = "${cfg.analytics.host}" ?? "https://analytics.umami.is/script.js"
umamiScript.src = "${cfg.analytics.host ?? "https://analytics.umami.is"}/script.js"
umamiScript.setAttribute("data-website-id", "${cfg.analytics.websiteId}")
umamiScript.async = true

View File

@ -5,12 +5,19 @@ import { escapeHTML } from "../../util/escape"
export interface Options {
descriptionLength: number
replaceExternalLinks: boolean
}
const defaultOptions: Options = {
descriptionLength: 150,
replaceExternalLinks: true,
}
const urlRegex = new RegExp(
/(https?:\/\/)?(?<domain>([\da-z\.-]+)\.([a-z\.]{2,6})(:\d+)?)(?<path>[\/\w\.-]*)(\?[\/\w\.=&;-]*)?/,
"g",
)
export const Description: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => {
const opts = { ...defaultOptions, ...userOpts }
return {
@ -19,19 +26,39 @@ export const Description: QuartzTransformerPlugin<Partial<Options> | undefined>
return [
() => {
return async (tree: HTMLRoot, file) => {
const frontMatterDescription = file.data.frontmatter?.description
const text = escapeHTML(toString(tree))
let frontMatterDescription = file.data.frontmatter?.description
let text = escapeHTML(toString(tree))
if (opts.replaceExternalLinks) {
frontMatterDescription = frontMatterDescription?.replace(
urlRegex,
"$<domain>" + "$<path>",
)
text = text.replace(urlRegex, "$<domain>" + "$<path>")
}
const desc = frontMatterDescription ?? text
const sentences = desc.replace(/\s+/g, " ").split(".")
const sentences = desc.replace(/\s+/g, " ").split(/\.\s/)
let finalDesc = ""
let sentenceIdx = 0
const len = opts.descriptionLength
while (finalDesc.length < len) {
const sentence = sentences[sentenceIdx]
if (!sentence) break
finalDesc += sentence + "."
sentenceIdx++
if (sentences[0] !== undefined && sentences[0].length >= len) {
const firstSentence = sentences[0].split(" ")
while (finalDesc.length < len) {
const sentence = firstSentence[sentenceIdx]
if (!sentence) break
finalDesc += sentence + " "
sentenceIdx++
}
finalDesc = finalDesc.trimEnd() + "..."
} else {
while (finalDesc.length < len) {
const sentence = sentences[sentenceIdx]
if (!sentence) break
finalDesc += sentence.endsWith(".") ? sentence : sentence + "."
sentenceIdx++
}
}
file.data.description = finalDesc

View File

@ -1,5 +1,5 @@
import { QuartzTransformerPlugin } from "../types"
import { Blockquote, Root, Html, BlockContent, DefinitionContent, Paragraph, Code } from "mdast"
import { Root, Html, BlockContent, DefinitionContent, Paragraph, Code } from "mdast"
import { Element, Literal, Root as HtmlRoot } from "hast"
import { ReplaceFunction, findAndReplace as mdastFindReplace } from "mdast-util-find-and-replace"
import { slug as slugAnchor } from "github-slugger"
@ -17,7 +17,6 @@ import { toHtml } from "hast-util-to-html"
import { PhrasingContent } from "mdast-util-find-and-replace/lib"
import { capitalize } from "../../util/lang"
import { PluggableList } from "unified"
import { ValidCallout, i18n } from "../../i18n"
export interface Options {
comments: boolean
@ -528,12 +527,35 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
last.value = last.value.slice(0, -matches[0].length)
const block = matches[0].slice(1)
if (!Object.keys(file.data.blocks!).includes(block)) {
node.properties = {
...node.properties,
id: block,
if (last.value === "") {
// this is an inline block ref but the actual block
// is the previous element above it
let idx = (index ?? 1) - 1
while (idx >= 0) {
const element = parent?.children.at(idx)
if (!element) break
if (element.type !== "element") {
idx -= 1
} else {
if (!Object.keys(file.data.blocks!).includes(block)) {
element.properties = {
...element.properties,
id: block,
}
file.data.blocks![block] = element
}
return
}
}
} else {
// normal paragraph transclude
if (!Object.keys(file.data.blocks!).includes(block)) {
node.properties = {
...node.properties,
id: block,
}
file.data.blocks![block] = node
}
file.data.blocks![block] = node
}
}
}