Squashed commit of the following:

commit 7164857f6e
Author: Aaron Pham <29749331+aarnphm@users.noreply.github.com>
Date:   Fri Mar 15 21:17:42 2024 -0400

    chore(ofm): remove unused (#999)

    Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com>

commit 47024022e8
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Fri Mar 15 18:29:14 2024 -0400

    chore(deps-dev): bump @types/node from 20.11.24 to 20.11.25 (#990)

    Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 20.11.24 to 20.11.25.
    - [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
    - [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

    ---
    updated-dependencies:
    - dependency-name: "@types/node"
      dependency-type: direct:development
      update-type: version-update:semver-patch
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit b98e4be665
Author: Mara-Li <lili.simonetti@outlook.fr>
Date:   Fri Mar 15 23:28:31 2024 +0100

    feat(i18n): Add French translation for reading time (#998)

    Signed-off-by: Mara-Li <lili.simonetti@outlook.fr>

commit 8be51a0504
Author: catcodeme <1020082805@qq.com>
Date:   Fri Mar 15 14:25:01 2024 +0800

    fix: wikiLink in table (#993)

    * fix: wikiLink in table

    - update regexp to make '\' to group in alias
    - handle alias using block_id

    * style: format with prettier

    * style: add comment for block_ref(without alias) in table

    ---------

    Co-authored-by: hulinjiang <hulinjiang@58.com>

commit 92cc23dc45
Author: Linus Sehn <37184648+linozen@users.noreply.github.com>
Date:   Wed Mar 13 08:59:37 2024 +0100

    feat(plugin): citations (#984)

    * feat: add rehype-citations

    * feat: add citations transformer plugin

    * feat: add rehype-rewrite

    * feat: add csl option and add no-popover to citation links

    * revert: add rehype-rewrite

    04b2692 'feat: add rehype-rewrite'

    * feat: use existing package for html manipulation

    * fix: remove `console.log()`

commit 097abc3cda
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon Mar 11 13:41:48 2024 -0700

    chore(deps): bump async-mutex from 0.4.1 to 0.5.0 (#991)

    Bumps [async-mutex](https://github.com/DirtyHairy/async-mutex) from 0.4.1 to 0.5.0.
    - [Changelog](https://github.com/DirtyHairy/async-mutex/blob/master/CHANGELOG.md)
    - [Commits](https://github.com/DirtyHairy/async-mutex/compare/v0.4.1...v0.5.0)

    ---
    updated-dependencies:
    - dependency-name: async-mutex
      dependency-type: direct:production
      update-type: version-update:semver-minor
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit a00324ddfd
Author: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Date:   Mon Mar 11 13:41:41 2024 -0700

    chore(deps-dev): bump typescript from 5.3.3 to 5.4.2 (#989)

    Bumps [typescript](https://github.com/Microsoft/TypeScript) from 5.3.3 to 5.4.2.
    - [Release notes](https://github.com/Microsoft/TypeScript/releases)
    - [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
    - [Commits](https://github.com/Microsoft/TypeScript/compare/v5.3.3...v5.4.2)

    ---
    updated-dependencies:
    - dependency-name: typescript
      dependency-type: direct:development
      update-type: version-update:semver-minor
    ...

    Signed-off-by: dependabot[bot] <support@github.com>
    Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>

commit 9fff6d7d0d
Author: Mara-Li <lili.simonetti@outlook.fr>
Date:   Mon Mar 11 17:46:53 2024 +0100

    fix: spelling error (#987)

    I really don't know why I translated this like that into "pas trouvé", and it bugged me a lot. I finally fixed it…

    Signed-off-by: Mara-Li <lili.simonetti@outlook.fr>

commit 0f5a9d7b66
Author: Matt Vogel <mainmoniker@googlemail.com>
Date:   Sun Mar 10 12:57:10 2024 -0400

    feat: separated content meta (#929)

    to allow for CSS styling

commit b4236e5142
Author: kabirgh <15871468+kabirgh@users.noreply.github.com>
Date:   Sun Mar 10 00:42:23 2024 +0000

    feat(perf:fast-rebuilds): Stop mutating resources param in ComponentResources emitter (#977)

    * Stop mutating resources param in ComponentResources emitter

    * Add done rebuilding log for fast rebuilds

    * Move google font loading to Head component

    * Simplify code and fix comment

commit 6e0c102970
Author: Emile Bangma <ewjbangma@hotmail.com>
Date:   Sun Mar 10 01:14:31 2024 +0100

    fix(transclusion): prevent duplicate transclusion if multiple transclusions are present. (#982)

commit 94a54698ab
Author: Emile Bangma <ewjbangma@hotmail.com>
Date:   Sat Mar 9 17:59:55 2024 +0100

    fix(resources): Use full path to font when cdnCache is false (#976)

commit 2e9a0c21db
Author: Emile Bangma <ewjbangma@hotmail.com>
Date:   Sat Mar 9 17:43:40 2024 +0100

    fix(description): first sentence no longer repeats until max length (#981)

commit b30a200bd4
Author: Aaron Pham <29749331+aarnphm@users.noreply.github.com>
Date:   Fri Mar 8 12:14:22 2024 -0500

    fix(i18n): make sure to use correct fileData for manual localization (#975)

    Signed-off-by: Aaron <29749331+aarnphm@users.noreply.github.com>

commit 6d59aa8201
Author: Emile Bangma <ewjbangma@hotmail.com>
Date:   Fri Mar 8 10:04:44 2024 +0100

    fix(description): counts characters instead of words (#972)

    * fix(description): make sure description counts characters instead of words

    * ref: removed duplicate ternary
This commit is contained in:
Ben Schlegel 2024-08-01 15:17:51 +02:00
parent 1313d9b1d8
commit e4496c3c1f
17 changed files with 408 additions and 183 deletions

291
package-lock.json generated
View File

@ -12,7 +12,7 @@
"@clack/prompts": "^0.7.0", "@clack/prompts": "^0.7.0",
"@floating-ui/dom": "^1.6.3", "@floating-ui/dom": "^1.6.3",
"@napi-rs/simple-git": "0.1.16", "@napi-rs/simple-git": "0.1.16",
"async-mutex": "^0.4.1", "async-mutex": "^0.5.0",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"cli-spinner": "^0.2.10", "cli-spinner": "^0.2.10",
@ -38,6 +38,7 @@
"pretty-time": "^1.1.0", "pretty-time": "^1.1.0",
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-citation": "^2.0.0",
"rehype-katex": "^7.0.0", "rehype-katex": "^7.0.0",
"rehype-mathjax": "^6.0.0", "rehype-mathjax": "^6.0.0",
"rehype-pretty-code": "^0.13.0", "rehype-pretty-code": "^0.13.0",
@ -75,7 +76,7 @@
"@types/d3": "^7.4.3", "@types/d3": "^7.4.3",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"@types/node": "^20.11.24", "@types/node": "^20.11.25",
"@types/pretty-time": "^1.1.5", "@types/pretty-time": "^1.1.5",
"@types/source-map-support": "^0.5.10", "@types/source-map-support": "^0.5.10",
"@types/ws": "^8.5.10", "@types/ws": "^8.5.10",
@ -83,7 +84,7 @@
"esbuild": "^0.19.9", "esbuild": "^0.19.9",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"tsx": "^4.7.1", "tsx": "^4.7.1",
"typescript": "^5.3.3" "typescript": "^5.4.2"
}, },
"engines": { "engines": {
"node": ">=18.14", "node": ">=18.14",
@ -100,6 +101,82 @@
"is-potential-custom-element-name": "^1.0.1" "is-potential-custom-element-name": "^1.0.1"
} }
}, },
"node_modules/@citation-js/core": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@citation-js/core/-/core-0.7.9.tgz",
"integrity": "sha512-fSbkB32JayDChZnAYC/kB+sWHRvxxL7ibVetyBOyzOc+5aCnjb6UVsbcfhnkOIEyAMoRRvWDyFmakEoTtA5ttQ==",
"dependencies": {
"@citation-js/date": "^0.5.0",
"@citation-js/name": "^0.4.2",
"fetch-ponyfill": "^7.1.0",
"sync-fetch": "^0.4.1"
},
"engines": {
"node": ">=16.0.0"
}
},
"node_modules/@citation-js/date": {
"version": "0.5.1",
"resolved": "https://registry.npmjs.org/@citation-js/date/-/date-0.5.1.tgz",
"integrity": "sha512-1iDKAZ4ie48PVhovsOXQ+C6o55dWJloXqtznnnKy6CltJBQLIuLLuUqa8zlIvma0ZigjVjgDUhnVaNU1MErtZw==",
"engines": {
"node": ">=10.0.0"
}
},
"node_modules/@citation-js/name": {
"version": "0.4.2",
"resolved": "https://registry.npmjs.org/@citation-js/name/-/name-0.4.2.tgz",
"integrity": "sha512-brSPsjs2fOVzSnARLKu0qncn6suWjHVQtrqSUrnqyaRH95r/Ad4wPF5EsoWr+Dx8HzkCGb/ogmoAzfCsqlTwTQ==",
"engines": {
"node": ">=6"
}
},
"node_modules/@citation-js/plugin-bibjson": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@citation-js/plugin-bibjson/-/plugin-bibjson-0.7.9.tgz",
"integrity": "sha512-YNCWIrkhqZ3cZKewHkLBixABo2PvOWnU+8dBx6KfN47ysdECR76xENe86YYpJ0ska2D5ZnTP0jKZIrUHQoxYfQ==",
"dependencies": {
"@citation-js/date": "^0.5.0",
"@citation-js/name": "^0.4.2"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@citation-js/core": "^0.7.0"
}
},
"node_modules/@citation-js/plugin-bibtex": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@citation-js/plugin-bibtex/-/plugin-bibtex-0.7.9.tgz",
"integrity": "sha512-gIJpCd6vmmTOcRfDrSOjtoNhw2Mi94UwFxmgJ7GwkXyTYcNheW5VlMMo1tlqjakJGARQ0eOsKcI57gSPqJSS2g==",
"dependencies": {
"@citation-js/date": "^0.5.0",
"@citation-js/name": "^0.4.2",
"moo": "^0.5.1"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@citation-js/core": "^0.7.0"
}
},
"node_modules/@citation-js/plugin-csl": {
"version": "0.7.9",
"resolved": "https://registry.npmjs.org/@citation-js/plugin-csl/-/plugin-csl-0.7.9.tgz",
"integrity": "sha512-mbD7CnUiPOuVnjeJwo+d0RGUcY0PE8n01gHyjq0qpTeS42EGmQ9+LzqfsTUVWWBndTwc6zLRuIF1qFAUHKE4oA==",
"dependencies": {
"@citation-js/date": "^0.5.0",
"citeproc": "^2.4.6"
},
"engines": {
"node": ">=16.0.0"
},
"peerDependencies": {
"@citation-js/core": "^0.7.0"
}
},
"node_modules/@clack/core": { "node_modules/@clack/core": {
"version": "0.3.3", "version": "0.3.3",
"resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.3.tgz", "resolved": "https://registry.npmjs.org/@clack/core/-/core-0.3.3.tgz",
@ -1110,9 +1187,9 @@
} }
}, },
"node_modules/@types/node": { "node_modules/@types/node": {
"version": "20.11.24", "version": "20.11.25",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.24.tgz", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.25.tgz",
"integrity": "sha512-Kza43ewS3xoLgCEpQrsT+xRo/EJej1y0kVYGiLFE1NEODXGzTfwiC6tXTLMQskn1X4/Rjlh0MQUvx9W+L9long==", "integrity": "sha512-TBHyJxk2b7HceLVGFcpAUjsa5zIdsPWlR6XHfyGzd0SFu+/NFgQgMAl96MSDZgQDvJAvV6BKsFOrt6zIL09JDw==",
"dev": true, "dev": true,
"dependencies": { "dependencies": {
"undici-types": "~5.26.4" "undici-types": "~5.26.4"
@ -1230,9 +1307,9 @@
} }
}, },
"node_modules/async-mutex": { "node_modules/async-mutex": {
"version": "0.4.1", "version": "0.5.0",
"resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.4.1.tgz", "resolved": "https://registry.npmjs.org/async-mutex/-/async-mutex-0.5.0.tgz",
"integrity": "sha512-WfoBo4E/TbCX1G95XTjbWTE3X2XLG0m1Xbv2cwOtuPdyH9CZvnaA5nCt1ucjaKEgW2A5IF71hxrRhr83Je5xjA==", "integrity": "sha512-1A94B18jkJ3DYq284ohPxoXbfTA5HsQ7/Mf4DEhcyLx3Bz27Rh59iScbB6EPiP+B+joue6YCxcMXSbFC1tZKwA==",
"dependencies": { "dependencies": {
"tslib": "^2.4.0" "tslib": "^2.4.0"
} }
@ -1262,12 +1339,23 @@
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
}, },
"node_modules/base64-js": { "node_modules/base64-js": {
"version": "0.0.8", "version": "1.5.1",
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==", "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
"engines": { "funding": [
"node": ">= 0.4" {
} "type": "github",
"url": "https://github.com/sponsors/feross"
},
{
"type": "patreon",
"url": "https://www.patreon.com/feross"
},
{
"type": "consulting",
"url": "https://feross.org/support"
}
]
}, },
"node_modules/bidi-js": { "node_modules/bidi-js": {
"version": "1.0.3", "version": "1.0.3",
@ -1456,10 +1544,10 @@
"fsevents": "~2.3.2" "fsevents": "~2.3.2"
} }
}, },
"node_modules/chownr": { "node_modules/citeproc": {
"version": "1.1.4", "version": "2.4.63",
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", "resolved": "https://registry.npmjs.org/citeproc/-/citeproc-2.4.63.tgz",
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==" "integrity": "sha512-68F95Bp4UbgZU/DBUGQn0qV3HDZLCdI9+Bb2ByrTaNJDL5VEm9LqaiNaxljsvoaExSLEXe1/r6n2Z06SCzW3/Q=="
}, },
"node_modules/cli-spinner": { "node_modules/cli-spinner": {
"version": "0.2.10", "version": "0.2.10",
@ -1613,6 +1701,14 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/cross-fetch": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-4.0.0.tgz",
"integrity": "sha512-e4a5N8lVvuLgAWgnCrLr2PP0YyDOTHa9H/Rj54dirp61qXnNq46m82bRhNqIA5VccJtWBvPTFRV3TtvHUKPB1g==",
"dependencies": {
"node-fetch": "^2.6.12"
}
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.3", "version": "7.0.3",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
@ -2364,10 +2460,51 @@
"url": "https://github.com/sponsors/wooorm" "url": "https://github.com/sponsors/wooorm"
} }
}, },
"node_modules/fflate": { "node_modules/fetch-ponyfill": {
"version": "0.7.4", "version": "7.1.0",
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz", "resolved": "https://registry.npmjs.org/fetch-ponyfill/-/fetch-ponyfill-7.1.0.tgz",
"integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==" "integrity": "sha512-FhbbL55dj/qdVO3YNK7ZEkshvj3eQ7EuIGV2I6ic/2YiocvyWv+7jg2s4AyS0wdRU75s3tA8ZxI/xPigb0v5Aw==",
"dependencies": {
"node-fetch": "~2.6.1"
}
},
"node_modules/fetch-ponyfill/node_modules/node-fetch": {
"version": "2.6.13",
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.13.tgz",
"integrity": "sha512-StxNAxh15zr77QvvkmveSQ8uCQ4+v5FkvNTj0OESmiHu+VRi/gXArXtkWMElOsOUNLtUEvI4yS+rdtOHZTwlQA==",
"dependencies": {
"whatwg-url": "^5.0.0"
},
"engines": {
"node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
}
},
"node_modules/fetch-ponyfill/node_modules/tr46": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/fetch-ponyfill/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/fetch-ponyfill/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}, },
"node_modules/fill-range": { "node_modules/fill-range": {
"version": "7.0.1", "version": "7.0.1",
@ -4596,10 +4733,10 @@
"resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz", "resolved": "https://registry.npmjs.org/mj-context-menu/-/mj-context-menu-0.6.1.tgz",
"integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA==" "integrity": "sha512-7NO5s6n10TIV96d4g2uDpG7ZDpIhMh0QNfGdJw/W47JswFcosz457wqz/b5sAKvl12sxINGFCn80NZHKwxQEXA=="
}, },
"node_modules/mkdirp-classic": { "node_modules/moo": {
"version": "0.5.3", "version": "0.5.2",
"resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", "resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
"integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" "integrity": "sha512-iSAJLHYKnX41mKcJKjqvnAN9sf0LMDTXDEvFv+ffuRR9a1MIuXLjMNL6EsnDHSkKLTWNqQQ5uo61P4EbU4NU+Q=="
}, },
"node_modules/ms": { "node_modules/ms": {
"version": "2.1.2", "version": "2.1.2",
@ -4623,21 +4760,43 @@
"url": "https://opencollective.com/unified" "url": "https://opencollective.com/unified"
} }
}, },
"node_modules/node-abi": { "node_modules/node-fetch": {
"version": "3.54.0", "version": "2.7.0",
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.54.0.tgz", "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz",
"integrity": "sha512-p7eGEiQil0YUV3ItH4/tBb781L5impVmmx2E9FRKF7d18XXzp4PGT2tdYMFY6wQqgxD0IwNZOiSJ0/K0fSi/OA==", "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
"dependencies": { "dependencies": {
"semver": "^7.3.5" "whatwg-url": "^5.0.0"
}, },
"engines": { "engines": {
"node": ">=10" "node": "4.x || >=6.0.0"
},
"peerDependencies": {
"encoding": "^0.1.0"
},
"peerDependenciesMeta": {
"encoding": {
"optional": true
}
} }
}, },
"node_modules/node-addon-api": { "node_modules/node-fetch/node_modules/tr46": {
"version": "6.1.0", "version": "0.0.3",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
"integrity": "sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==" "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
},
"node_modules/node-fetch/node_modules/webidl-conversions": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
"integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
},
"node_modules/node-fetch/node_modules/whatwg-url": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
"integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
"dependencies": {
"tr46": "~0.0.3",
"webidl-conversions": "^3.0.0"
}
}, },
"node_modules/normalize-path": { "node_modules/normalize-path": {
"version": "3.0.0", "version": "3.0.0",
@ -5031,6 +5190,27 @@
"url": "https://opencollective.com/unified" "url": "https://opencollective.com/unified"
} }
}, },
"node_modules/rehype-citation": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/rehype-citation/-/rehype-citation-2.0.0.tgz",
"integrity": "sha512-rGawTBI8SJA1Y4IRyROvpYF6oXBVNFXlJYHIJ2jJH3HgeuCbAC9AO8wE/NMPLDOPQ8+Q8QkZm93fKsnUNbvwZA==",
"dependencies": {
"@citation-js/core": "^0.7.1",
"@citation-js/date": "^0.5.1",
"@citation-js/name": "^0.4.2",
"@citation-js/plugin-bibjson": "^0.7.2",
"@citation-js/plugin-bibtex": "^0.7.2",
"@citation-js/plugin-csl": "^0.7.2",
"citeproc": "^2.4.63",
"cross-fetch": "^4.0.0",
"hast-util-from-dom": "^5.0.0",
"hast-util-from-parse5": "^8.0.1",
"js-yaml": "^4.1.0",
"parse5": "^7.1.2",
"unified": "^11.0.0",
"unist-util-visit": "^5.0.0"
}
},
"node_modules/rehype-katex": { "node_modules/rehype-katex": {
"version": "7.0.0", "version": "7.0.0",
"resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.0.tgz", "resolved": "https://registry.npmjs.org/rehype-katex/-/rehype-katex-7.0.0.tgz",
@ -6150,31 +6330,18 @@
"resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
"integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==" "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
}, },
"node_modules/tar-fs": { "node_modules/sync-fetch": {
"version": "3.0.4", "version": "0.4.5",
"resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-3.0.4.tgz", "resolved": "https://registry.npmjs.org/sync-fetch/-/sync-fetch-0.4.5.tgz",
"integrity": "sha512-5AFQU8b9qLfZCX9zp2duONhPmZv0hGYiBPJsyUdqMjzq/mqVpy/rEUSeHk1+YitmxugaptgBh5oDGU3VsAJq4w==", "integrity": "sha512-esiWJ7ixSKGpd9DJPBTC4ckChqdOjIwJfYhVHkcQ2Gnm41323p1TRmEI+esTQ9ppD+b5opps2OTEGTCGX5kF+g==",
"dependencies": { "dependencies": {
"mkdirp-classic": "^0.5.2", "buffer": "^5.7.1",
"pump": "^3.0.0", "node-fetch": "^2.6.1"
"tar-stream": "^3.1.5" },
"engines": {
"node": ">=14"
} }
}, },
"node_modules/tar-stream": {
"version": "3.1.7",
"resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
"integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
"dependencies": {
"b4a": "^1.6.4",
"fast-fifo": "^1.2.0",
"streamx": "^2.15.0"
}
},
"node_modules/tiny-inflate": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
},
"node_modules/to-regex-range": { "node_modules/to-regex-range": {
"version": "5.0.1", "version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
@ -6298,9 +6465,9 @@
} }
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "5.3.3", "version": "5.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.2.tgz",
"integrity": "sha512-pXWcraxM0uxAS+tN0AG/BF2TyqmHO014Z070UsJ+pFvYuRSq8KH8DmWpnbXe0pEPDHXZV3FcAbJkijJ5oNEnWw==", "integrity": "sha512-+2/g0Fds1ERlP6JsakQQDXjZdZMM+rqpamFZJEKh4kwTIn3iDkgKtby0CeNd5ATNZ4Ry1ax15TMx0W2V+miizQ==",
"dev": true, "dev": true,
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",

View File

@ -37,7 +37,7 @@
"@clack/prompts": "^0.7.0", "@clack/prompts": "^0.7.0",
"@floating-ui/dom": "^1.6.3", "@floating-ui/dom": "^1.6.3",
"@napi-rs/simple-git": "0.1.16", "@napi-rs/simple-git": "0.1.16",
"async-mutex": "^0.4.1", "async-mutex": "^0.5.0",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"chokidar": "^3.6.0", "chokidar": "^3.6.0",
"cli-spinner": "^0.2.10", "cli-spinner": "^0.2.10",
@ -63,6 +63,7 @@
"pretty-time": "^1.1.0", "pretty-time": "^1.1.0",
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-citation": "^2.0.0",
"rehype-katex": "^7.0.0", "rehype-katex": "^7.0.0",
"rehype-mathjax": "^6.0.0", "rehype-mathjax": "^6.0.0",
"rehype-pretty-code": "^0.13.0", "rehype-pretty-code": "^0.13.0",
@ -97,7 +98,7 @@
"@types/d3": "^7.4.3", "@types/d3": "^7.4.3",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"@types/node": "^20.11.24", "@types/node": "^20.11.25",
"@types/pretty-time": "^1.1.5", "@types/pretty-time": "^1.1.5",
"@types/source-map-support": "^0.5.10", "@types/source-map-support": "^0.5.10",
"@types/ws": "^8.5.10", "@types/ws": "^8.5.10",
@ -105,6 +106,6 @@
"esbuild": "^0.19.9", "esbuild": "^0.19.9",
"prettier": "^3.2.4", "prettier": "^3.2.4",
"tsx": "^4.7.1", "tsx": "^4.7.1",
"typescript": "^5.3.3" "typescript": "^5.4.2"
} }
} }

View File

@ -20,6 +20,7 @@ const config: QuartzConfig = {
defaultDateType: "created", defaultDateType: "created",
generateSocialImages: false, generateSocialImages: false,
theme: { theme: {
fontOrigin: "googleFonts",
cdnCaching: true, cdnCaching: true,
typography: { typography: {
header: "Schibsted Grotesk", header: "Schibsted Grotesk",
@ -73,7 +74,7 @@ const config: QuartzConfig = {
filters: [Plugin.RemoveDrafts()], filters: [Plugin.RemoveDrafts()],
emitters: [ emitters: [
Plugin.AliasRedirects(), Plugin.AliasRedirects(),
Plugin.ComponentResources({ fontOrigin: "googleFonts" }), Plugin.ComponentResources(),
Plugin.ContentPage(), Plugin.ContentPage(),
Plugin.FolderPage(), Plugin.FolderPage(),
Plugin.TagPage(), Plugin.TagPage(),

View File

@ -309,6 +309,8 @@ async function partialRebuildFromEntrypoint(
} }
await rimraf([...destinationsToDelete]) await rimraf([...destinationsToDelete])
console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
toRemove.clear() toRemove.clear()
release() release()
clientRefresh() clientRefresh()

View File

@ -3,16 +3,20 @@ import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
import readingTime from "reading-time" import readingTime from "reading-time"
import { classNames } from "../util/lang" import { classNames } from "../util/lang"
import { i18n } from "../i18n" import { i18n } from "../i18n"
import { JSX } from "preact"
import style from "./styles/contentMeta.scss"
interface ContentMetaOptions { interface ContentMetaOptions {
/** /**
* Whether to display reading time * Whether to display reading time
*/ */
showReadingTime: boolean showReadingTime: boolean
showComma: boolean
} }
const defaultOptions: ContentMetaOptions = { const defaultOptions: ContentMetaOptions = {
showReadingTime: true, showReadingTime: true,
showComma: true,
} }
export default ((opts?: Partial<ContentMetaOptions>) => { export default ((opts?: Partial<ContentMetaOptions>) => {
@ -23,7 +27,7 @@ export default ((opts?: Partial<ContentMetaOptions>) => {
const text = fileData.text const text = fileData.text
if (text) { if (text) {
const segments: string[] = [] const segments: (string | JSX.Element)[] = []
if (fileData.dates) { if (fileData.dates) {
segments.push(formatDate(getDate(cfg, fileData)!, cfg.locale)) segments.push(formatDate(getDate(cfg, fileData)!, cfg.locale))
@ -38,17 +42,19 @@ export default ((opts?: Partial<ContentMetaOptions>) => {
segments.push(displayedTime) segments.push(displayedTime)
} }
return <p class={classNames(displayClass, "content-meta")}>{segments.join(", ")}</p> const segmentsElements = segments.map((segment) => <span>{segment}</span>)
return (
<p show-comma={options.showComma} class={classNames(displayClass, "content-meta")}>
{segmentsElements}
</p>
)
} else { } else {
return null return null
} }
} }
ContentMetadata.css = ` ContentMetadata.css = style
.content-meta {
margin-top: 0;
color: var(--gray);
}
`
return ContentMetadata return ContentMetadata
}) satisfies QuartzComponentConstructor }) satisfies QuartzComponentConstructor

View File

@ -1,6 +1,7 @@
import { i18n } from "../i18n" import { i18n } from "../i18n"
import { FullSlug, joinSegments, pathToRoot } from "../util/path" import { FullSlug, joinSegments, pathToRoot } from "../util/path"
import { JSResourceToScriptElement } from "../util/resources" import { JSResourceToScriptElement } from "../util/resources"
import { googleFontHref } from "../util/theme"
import { QuartzComponentConstructor, QuartzComponentProps } from "./types" import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
import satori, { SatoriOptions } from "satori" import satori, { SatoriOptions } from "satori"
import fs from "fs" import fs from "fs"
@ -150,10 +151,11 @@ export default (() => {
<head> <head>
<title>{title}</title> <title>{title}</title>
<meta charSet="utf-8" /> <meta charSet="utf-8" />
{cfg.theme.cdnCaching && ( {cfg.theme.cdnCaching && cfg.theme.fontOrigin === "googleFonts" && (
<> <>
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" />
<link rel="stylesheet" href={googleFontHref(cfg.theme)} />
</> </>
)} )}
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />

View File

@ -118,11 +118,12 @@ export function renderPage(
// skip until we find the blockref that matches // skip until we find the blockref that matches
if (el.properties?.id === blockRef) { if (el.properties?.id === blockRef) {
startIdx = i startIdx = i
startDepth = Number(el.tagName.substring(1)) startDepth = depth
} }
} else if (depth <= startDepth) { } else if (depth <= startDepth) {
// looking for new header that is same level or higher // looking for new header that is same level or higher
endIdx = i endIdx = i
break
} }
} }
@ -209,7 +210,7 @@ export function renderPage(
</div> </div>
) )
const lang = componentData.frontmatter?.lang ?? cfg.locale?.split("-")[0] ?? "en" const lang = componentData.fileData.frontmatter?.lang ?? cfg.locale?.split("-")[0] ?? "en"
const doc = ( const doc = (
<html lang={lang}> <html lang={lang}>
<Head {...componentData} /> <Head {...componentData} />

View File

@ -0,0 +1,14 @@
.content-meta {
margin-top: 0;
color: var(--gray);
&[show-comma="true"] {
> span:not(:last-child) {
margin-right: 8px;
&::after {
content: ",";
}
}
}
}

View File

@ -54,7 +54,7 @@ export default {
title: "Table des Matières", title: "Table des Matières",
}, },
contentMeta: { contentMeta: {
readingTime: ({ minutes }) => `${minutes} min read`, readingTime: ({ minutes }) => `${minutes} min de lecture`,
}, },
}, },
pages: { pages: {
@ -63,7 +63,7 @@ export default {
lastFewNotes: ({ count }) => `Les dernières ${count} notes`, lastFewNotes: ({ count }) => `Les dernières ${count} notes`,
}, },
error: { error: {
title: "Pas trouvé", title: "Introuvable",
notFound: "Cette page est soit privée, soit elle n'existe pas.", notFound: "Cette page est soit privée, soit elle n'existe pas.",
}, },
folderContent: { folderContent: {

View File

@ -8,7 +8,6 @@ import popoverScript from "../../components/scripts/popover.inline"
import styles from "../../styles/custom.scss" import styles from "../../styles/custom.scss"
import popoverStyle from "../../components/styles/popover.scss" import popoverStyle from "../../components/styles/popover.scss"
import { BuildCtx } from "../../util/ctx" import { BuildCtx } from "../../util/ctx"
import { StaticResources } from "../../util/resources"
import { QuartzComponent } from "../../components/types" import { QuartzComponent } from "../../components/types"
import { googleFontHref, joinStyles } from "../../util/theme" import { googleFontHref, joinStyles } from "../../util/theme"
import { Features, transform } from "lightningcss" import { Features, transform } from "lightningcss"
@ -69,13 +68,8 @@ async function joinScripts(scripts: string[]): Promise<string> {
return res.code return res.code
} }
function addGlobalPageResources( function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentResources) {
ctx: BuildCtx,
staticResources: StaticResources,
componentResources: ComponentResources,
) {
const cfg = ctx.cfg.configuration const cfg = ctx.cfg.configuration
const reloadScript = ctx.argv.serve
// popovers // popovers
if (cfg.enablePopovers) { if (cfg.enablePopovers) {
@ -85,12 +79,12 @@ function addGlobalPageResources(
if (cfg.analytics?.provider === "google") { if (cfg.analytics?.provider === "google") {
const tagId = cfg.analytics.tagId const tagId = cfg.analytics.tagId
staticResources.js.push({
src: `https://www.googletagmanager.com/gtag/js?id=${tagId}`,
contentType: "external",
loadTime: "afterDOMReady",
})
componentResources.afterDOMLoaded.push(` componentResources.afterDOMLoaded.push(`
const gtagScript = document.createElement("script")
gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${tagId}"
gtagScript.async = true
document.head.appendChild(gtagScript)
window.dataLayer = window.dataLayer || []; window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); } function gtag() { dataLayer.push(arguments); }
gtag("js", new Date()); gtag("js", new Date());
@ -147,115 +141,72 @@ function addGlobalPageResources(
document.dispatchEvent(event) document.dispatchEvent(event)
`) `)
} }
let wsUrl = `ws://localhost:${ctx.argv.wsPort}`
if (ctx.argv.remoteDevHost) {
wsUrl = `wss://${ctx.argv.remoteDevHost}:${ctx.argv.wsPort}`
}
if (reloadScript) {
staticResources.js.push({
loadTime: "afterDOMReady",
contentType: "inline",
script: `
const socket = new WebSocket('${wsUrl}')
// reload(true) ensures resources like images and scripts are fetched again in firefox
socket.addEventListener('message', () => document.location.reload(true))
`,
})
}
} }
interface Options { // This emitter should not update the `resources` parameter. If it does, partial
fontOrigin: "googleFonts" | "local" // rebuilds may not work as expected.
} export const ComponentResources: QuartzEmitterPlugin = () => {
const defaultOptions: Options = {
fontOrigin: "googleFonts",
}
export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<Options>) => {
const { fontOrigin } = { ...defaultOptions, ...opts }
return { return {
name: "ComponentResources", name: "ComponentResources",
getQuartzComponents() { getQuartzComponents() {
return [] return []
}, },
async getDependencyGraph(ctx, content, _resources) { async getDependencyGraph(_ctx, _content, _resources) {
// This emitter adds static resources to the `resources` parameter. One return new DepGraph<FilePath>()
// important resource this emitter adds is the code to start a websocket
// connection and listen to rebuild messages, which triggers a page reload.
// The resources parameter with the reload logic is later used by the
// ContentPage emitter while creating the final html page. In order for
// the reload logic to be included, and so for partial rebuilds to work,
// we need to run this emitter for all markdown files.
const graph = new DepGraph<FilePath>()
for (const [_tree, file] of content) {
const sourcePath = file.data.filePath!
const slug = file.data.slug!
graph.addEdge(sourcePath, joinSegments(ctx.argv.output, slug + ".html") as FilePath)
}
return graph
}, },
async emit(ctx, _content, resources): Promise<FilePath[]> { async emit(ctx, _content, _resources): Promise<FilePath[]> {
const promises: Promise<FilePath>[] = [] const promises: Promise<FilePath>[] = []
const cfg = ctx.cfg.configuration const cfg = ctx.cfg.configuration
// component specific scripts and styles // component specific scripts and styles
const componentResources = getComponentResources(ctx) const componentResources = getComponentResources(ctx)
let googleFontsStyleSheet = "" let googleFontsStyleSheet = ""
if (fontOrigin === "local") { if (cfg.theme.fontOrigin === "local") {
// let the user do it themselves in css // let the user do it themselves in css
} else if (fontOrigin === "googleFonts") { } else if (cfg.theme.fontOrigin === "googleFonts" && !cfg.theme.cdnCaching) {
if (cfg.theme.cdnCaching) { // when cdnCaching is true, we link to google fonts in Head.tsx
resources.css.push(googleFontHref(cfg.theme)) let match
} else {
let match
const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
googleFontsStyleSheet = await ( googleFontsStyleSheet = await (
await fetch(googleFontHref(ctx.cfg.configuration.theme)) await fetch(googleFontHref(ctx.cfg.configuration.theme))
).text() ).text()
while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) { while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
// match[0] is the `url(path)`, match[1] is the `path` // match[0] is the `url(path)`, match[1] is the `path`
const url = match[1] const url = match[1]
// the static name of this file. // the static name of this file.
const [filename, ext] = url.split("/").pop()!.split(".") const [filename, ext] = url.split("/").pop()!.split(".")
googleFontsStyleSheet = googleFontsStyleSheet.replace( googleFontsStyleSheet = googleFontsStyleSheet.replace(
url, url,
`/static/fonts/${filename}.ttf`, `https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
) )
promises.push( promises.push(
fetch(url) fetch(url)
.then((res) => { .then((res) => {
if (!res.ok) { if (!res.ok) {
throw new Error(`Failed to fetch font`) throw new Error(`Failed to fetch font`)
} }
return res.arrayBuffer() return res.arrayBuffer()
}) })
.then((buf) => .then((buf) =>
write({ write({
ctx, ctx,
slug: joinSegments("static", "fonts", filename) as FullSlug, slug: joinSegments("static", "fonts", filename) as FullSlug,
ext: `.${ext}`, ext: `.${ext}`,
content: Buffer.from(buf), content: Buffer.from(buf),
}), }),
), ),
) )
}
} }
} }
// important that this goes *after* component scripts // important that this goes *after* component scripts
// as the "nav" event gets triggered here and we should make sure // as the "nav" event gets triggered here and we should make sure
// that everyone else had the chance to register a listener for it // that everyone else had the chance to register a listener for it
addGlobalPageResources(ctx, resources, componentResources) addGlobalPageResources(ctx, componentResources)
const stylesheet = joinStyles( const stylesheet = joinStyles(
ctx.cfg.configuration.theme, ctx.cfg.configuration.theme,

View File

@ -18,6 +18,23 @@ export function getStaticResourcesFromPlugins(ctx: BuildCtx) {
} }
} }
// if serving locally, listen for rebuilds and reload the page
if (ctx.argv.serve) {
const wsUrl = ctx.argv.remoteDevHost
? `wss://${ctx.argv.remoteDevHost}:${ctx.argv.wsPort}`
: `ws://localhost:${ctx.argv.wsPort}`
staticResources.js.push({
loadTime: "afterDOMReady",
contentType: "inline",
script: `
const socket = new WebSocket('${wsUrl}')
// reload(true) ensures resources like images and scripts are fetched again in firefox
socket.addEventListener('message', () => document.location.reload(true))
`,
})
}
return staticResources return staticResources
} }

View File

@ -0,0 +1,52 @@
import rehypeCitation from "rehype-citation"
import { PluggableList } from "unified"
import { visit } from "unist-util-visit"
import { QuartzTransformerPlugin } from "../types"
export interface Options {
bibliographyFile: string
suppressBibliography: boolean
linkCitations: boolean
csl: string
}
const defaultOptions: Options = {
bibliographyFile: "./bibliography.bib",
suppressBibliography: false,
linkCitations: false,
csl: "apa",
}
export const Citations: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => {
const opts = { ...defaultOptions, ...userOpts }
return {
name: "Citations",
htmlPlugins() {
const plugins: PluggableList = []
// Add rehype-citation to the list of plugins
plugins.push([
rehypeCitation,
{
bibliography: opts.bibliographyFile,
suppressBibliography: opts.suppressBibliography,
linkCitations: opts.linkCitations,
},
])
// Transform the HTML of the citattions; add data-no-popover property to the citation links
// using https://github.com/syntax-tree/unist-util-visit as they're just anochor links
plugins.push(() => {
return (tree, _file) => {
visit(tree, "element", (node, index, parent) => {
if (node.tagName === "a" && node.properties?.href?.startsWith("#bib")) {
node.properties["data-no-popover"] = true
}
})
}
})
return plugins
},
}
}

View File

@ -42,21 +42,25 @@ export const Description: QuartzTransformerPlugin<Partial<Options> | undefined>
const finalDesc: string[] = [] const finalDesc: string[] = []
const len = opts.descriptionLength const len = opts.descriptionLength
let sentenceIdx = 0 let sentenceIdx = 0
let currentDescriptionLength = 0
if (sentences[0] !== undefined && sentences[0].length >= len) { if (sentences[0] !== undefined && sentences[0].length >= len) {
const firstSentence = sentences[0].split(" ") const firstSentence = sentences[0].split(" ")
while (finalDesc.length < len) { while (currentDescriptionLength < len) {
const sentence = firstSentence[sentenceIdx] const sentence = firstSentence[sentenceIdx]
if (!sentence) break if (!sentence) break
finalDesc.push(sentence) finalDesc.push(sentence)
currentDescriptionLength += sentence.length
sentenceIdx++ sentenceIdx++
} }
finalDesc.push("...") finalDesc.push("...")
} else { } else {
while (finalDesc.length < len) { while (currentDescriptionLength < len) {
const sentence = sentences[sentenceIdx] const sentence = sentences[sentenceIdx]
if (!sentence) break if (!sentence) break
finalDesc.push(sentence.endsWith(".") ? sentence : sentence + ".") const currentSentence = sentence.endsWith(".") ? sentence : sentence + "."
finalDesc.push(currentSentence)
currentDescriptionLength += currentSentence.length
sentenceIdx++ sentenceIdx++
} }
} }

View File

@ -90,6 +90,7 @@ declare module "vfile" {
description: string description: string
publish: boolean publish: boolean
draft: boolean draft: boolean
lang: string
enableToc: string enableToc: string
cssclasses: string[] cssclasses: string[]
}> }>

View File

@ -1,5 +1,6 @@
export { FrontMatter } from "./frontmatter" export { FrontMatter } from "./frontmatter"
export { GitHubFlavoredMarkdown } from "./gfm" export { GitHubFlavoredMarkdown } from "./gfm"
export { Citations } from "./citations"
export { CreatedModifiedDate } from "./lastmod" export { CreatedModifiedDate } from "./lastmod"
export { Latex } from "./latex" export { Latex } from "./latex"
export { Description } from "./description" export { Description } from "./description"

View File

@ -103,9 +103,9 @@ export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/, "g")
// \[\[ -> open brace // \[\[ -> open brace
// ([^\[\]\|\#]+) -> one or more non-special characters ([,],|, or #) (name) // ([^\[\]\|\#]+) -> one or more non-special characters ([,],|, or #) (name)
// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link) // (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
// (\|[^\[\]\#]+)? -> | then one or more non-special characters (alias) // (\|[^\[\]\#]+)? -> \| then one or more non-special characters (alias)
export const wikilinkRegex = new RegExp( export const wikilinkRegex = new RegExp(
/!?\[\[([^\[\]\|\#]+)?(#+[^\[\]\|\#]+)?(\|[^\[\]\#]+)?\]\]/, /!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]/,
"g", "g",
) )
const highlightRegex = new RegExp(/==([^=]+)==/, "g") const highlightRegex = new RegExp(/==([^=]+)==/, "g")
@ -176,22 +176,26 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
const anchor = rawHeader?.trim().replace(/^#+/, "") const anchor = rawHeader?.trim().replace(/^#+/, "")
const blockRef = Boolean(anchor?.startsWith("^")) ? "^" : "" const blockRef = Boolean(anchor?.startsWith("^")) ? "^" : ""
const displayAnchor = anchor ? `#${blockRef}${slugAnchor(anchor)}` : "" const displayAnchor = anchor ? `#${blockRef}${slugAnchor(anchor)}` : ""
const displayAlias = rawAlias ?? rawHeader?.replace("#", "|") ?? "" let displayAlias = rawAlias ?? rawHeader?.replace("#", "|") ?? ""
const embedDisplay = value.startsWith("!") ? "!" : "" const embedDisplay = value.startsWith("!") ? "!" : ""
if (rawFp?.match(externalLinkRegex)) { if (rawFp?.match(externalLinkRegex)) {
return `${embedDisplay}[${displayAlias.replace(/^\|/, "")}](${rawFp})` return `${embedDisplay}[${displayAlias.replace(/^\|/, "")}](${rawFp})`
} }
//transform `[[note#^block_ref|^block_ref]]` to `[[note#^block_ref\|^block_ref]]`, display correctly in table.
if (displayAlias && displayAlias.startsWith("|")) {
displayAlias = `\\${displayAlias}`
}
return `${embedDisplay}[[${fp}${displayAnchor}${displayAlias}]]` return `${embedDisplay}[[${fp}${displayAnchor}${displayAlias}]]`
}) })
} }
return src return src
}, },
markdownPlugins(ctx) { markdownPlugins(_ctx) {
const plugins: PluggableList = [] const plugins: PluggableList = []
const cfg = ctx.cfg.configuration
// regex replacements // regex replacements
plugins.push(() => { plugins.push(() => {

View File

@ -22,6 +22,7 @@ export interface Theme {
} }
cdnCaching: boolean cdnCaching: boolean
colors: Colors colors: Colors
fontOrigin: "googleFonts" | "local"
} }
export type ThemeKey = keyof Colors export type ThemeKey = keyof Colors