This commit is contained in:
semanticdata 2024-08-14 16:10:38 -05:00
commit 16c4b476e8
55 changed files with 429 additions and 156 deletions

View File

@ -26,7 +26,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 18
node-version: 20
- name: Cache dependencies
uses: actions/cache@v4
@ -59,7 +59,7 @@ jobs:
- name: Setup Node
uses: actions/setup-node@v4
with:
node-version: 18
node-version: 20
- name: Get package version
run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV
- name: Create release tag

1
.node-version Normal file
View File

@ -0,0 +1 @@
v20.9.0

View File

@ -52,6 +52,7 @@ This part of the configuration concerns anything that can affect the whole site.
- `secondary`: link colour, current [[graph view|graph]] node
- `tertiary`: hover states and visited [[graph view|graph]] nodes
- `highlight`: internal link background, highlighted text, [[syntax highlighting|highlighted lines of code]]
- `textHighlight`: markdown highlighted text background
## Plugins

83
docs/features/comments.md Normal file
View File

@ -0,0 +1,83 @@
---
title: Comments
tags:
- component
---
Quartz also has the ability to hook into various providers to enable readers to leave comments on your site.
![[giscus-example.png]]
As of today, only [Giscus](https://giscus.app/) is supported out of the box but PRs to support other providers are welcome!
## Providers
### Giscus
First, make sure that the [[setting up your GitHub repository|GitHub]] repository you are using for your Quartz meets the following requirements:
1. The **repository is [public](https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/setting-repository-visibility#making-a-repository-public)**, otherwise visitors will not be able to view the discussion.
2. The **[giscus](https://github.com/apps/giscus) app is installed**, otherwise visitors will not be able to comment and react.
3. The **Discussions feature is turned on** by [enabling it for your repository](https://docs.github.com/en/github/administering-a-repository/managing-repository-settings/enabling-or-disabling-github-discussions-for-a-repository).
Then, use the [Giscus site](https://giscus.app/#repository) to figure out what your `repoId` and `categoryId` should be. Make sure you select `Announcements` for the Discussion category.
![[giscus-repo.png]]
![[giscus-discussion.png]]
After entering both your repository and selecting the discussion category, Giscus will compute some IDs that you'll need to provide back to Quartz. You won't need to manually add the script yourself as Quartz will handle that part for you but will need these values in the next step!
![[giscus-results.png]]
Finally, in `quartz.layout.ts`, edit the `afterBody` field of `sharedPageComponents` to include the following options but with the values you got from above:
```ts title="quartz.layout.ts"
afterBody: [
Component.Comments({
provider: 'giscus',
options: {
// from data-repo
repo: 'jackyzha0/quartz',
// from data-repo-id
repoId: 'MDEwOlJlcG9zaXRvcnkzODcyMTMyMDg',
// from data-category
category: 'Announcements',
// from data-category-id
categoryId: 'DIC_kwDOFxRnmM4B-Xg6',
}
}),
],
```
### Customization
Quartz also exposes a few of the other Giscus options as well and you can provide them the same way `repo`, `repoId`, `category`, and `categoryId` are provided.
```ts
type Options = {
provider: "giscus"
options: {
repo: `${string}/${string}`
repoId: string
category: string
categoryId: string
// how to map pages -> discussions
// defaults to 'url'
mapping?: "url" | "title" | "og:title" | "specific" | "number" | "pathname"
// use strict title matching
// defaults to true
strict?: boolean
// whether to enable reactions for the main post
// defaults to true
reactionsEnabled?: boolean
// where to put the comment input box relative to the comments
// defaults to 'bottom'
inputPosition?: "top" | "bottom"
}
}
```

View File

@ -30,4 +30,4 @@ As with folder listings, you can also provide a description and title for a tag
## Customization
The folder listings are a functionality of the [[FolderPage]] plugin, the tag listings of the [[TagPage]] plugin. See the plugin pages for customization options.
Quartz allows you to define a custom sort ordering for content on both page types. The folder listings are a functionality of the [[FolderPage]] plugin, the tag listings of the [[TagPage]] plugin. See the plugin pages for customization options.

View File

@ -2,22 +2,12 @@
draft: true
---
## high priority backlog
- static dead link detection
- block links: https://help.obsidian.md/Linking+notes+and+files/Internal+links#Link+to+a+block+in+a+note
- note/header/block transcludes: https://help.obsidian.md/Linking+notes+and+files/Embedding+files
- docker support
## misc backlog
- breadcrumbs component
- static dead link detection
- cursor chat extension
- https://giscus.app/ extension
- sidenotes? https://github.com/capnfabs/paperesque
- direct match in search using double quotes
- https://help.obsidian.md/Advanced+topics/Using+Obsidian+URI
- audio/video embed styling
- Canvas
- parse all images in page: use this for page lists if applicable?
- CV mode? with print stylesheet

View File

@ -58,6 +58,8 @@ jobs:
with:
fetch-depth: 0 # Fetch all history for git info
- uses: actions/setup-node@v4
with:
node-version: 22
- name: Install Dependencies
run: npm ci
- name: Build Quartz
@ -180,7 +182,7 @@ stages:
- build
- deploy
image: node:18
image: node:20
cache: # Cache modules in between jobs
key: $CI_COMMIT_REF_SLUG
paths:

Binary file not shown.

After

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

BIN
docs/images/giscus-repo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 108 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

After

Width:  |  Height:  |  Size: 65 KiB

View File

@ -6,7 +6,7 @@ Quartz is a fast, batteries-included static-site generator that transforms Markd
## 🪴 Get Started
Quartz requires **at least [Node](https://nodejs.org/) v18.14** and `npm` v9.3.1 to function correctly. Ensure you have this installed on your machine before continuing.
Quartz requires **at least [Node](https://nodejs.org/) v20** and `npm` v9.3.1 to function correctly. Ensure you have this installed on your machine before continuing.
Then, in your terminal of choice, enter the following commands line by line:
@ -30,7 +30,7 @@ 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]] 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

View File

@ -12,6 +12,7 @@ export interface FullPageLayout {
header: QuartzComponent[] // laid out horizontally
beforeBody: QuartzComponent[] // laid out vertically
pageBody: QuartzComponent // single component
afterBody: QuartzComponent[] // laid out vertically
left: QuartzComponent[] // vertical on desktop, horizontal on mobile
right: QuartzComponent[] // vertical on desktop, horizontal on mobile
footer: QuartzComponent // single component

View File

@ -10,7 +10,7 @@ This plugin determines the created, modified, and published dates for a document
This plugin accepts the following configuration options:
- `priority`: The data sources to consult for date information. Highest priority first. Possible values are `"frontmatter"`, `"git"`, and `"filesystem"`. Defaults to `"frontmatter", "git", "filesystem"]`.
- `priority`: The data sources to consult for date information. Highest priority first. Possible values are `"frontmatter"`, `"git"`, and `"filesystem"`. Defaults to `["frontmatter", "git", "filesystem"]`.
> [!warning] If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in `quartz.config.ts`.
>

View File

@ -10,10 +10,12 @@ Example: [[advanced/|Advanced]]
> [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options.
The pages are displayed using the `defaultListPageLayout` in `quartz.layouts.ts`. For the content, the `FolderContent` component is used. If you want to modify the layout, you must edit it directly (`quartz/components/pages/FolderContent.tsx`).
This plugin accepts the following configuration options:
- `sort`: A function of type `(f1: QuartzPluginData, f2: QuartzPluginData) => number{:ts}` used to sort entries. Defaults to sorting by date and tie-breaking on lexographical order.
## API
- Category: Emitter

View File

@ -11,6 +11,7 @@ This plugin adds LaTeX support to Quartz. See [[features/Latex|Latex]] for more
This plugin accepts the following configuration options:
- `renderEngine`: the engine to use to render LaTeX equations. Can be `"katex"` for [KaTeX](https://katex.org/) or `"mathjax"` for [MathJax](https://www.mathjax.org/) [SVG rendering](https://docs.mathjax.org/en/latest/output/svg.html). Defaults to KaTeX.
- `customMacros`: custom macros for all LaTeX blocks. It takes the form of a key-value pair where the key is a new command name and the value is the expansion of the macro. For example: `{"\\R": "\\mathbb{R}"}`
## API

View File

@ -8,10 +8,12 @@ This plugin emits dedicated pages for each tag used in the content. See [[folder
> [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options.
The pages are displayed using the `defaultListPageLayout` in `quartz.layouts.ts`. For the content, the `TagContent` component is used. If you want to modify the layout, you must edit it directly (`quartz/components/pages/TagContent.tsx`).
This plugin accepts the following configuration options:
- `sort`: A function of type `(f1: QuartzPluginData, f2: QuartzPluginData) => number{:ts}` used to sort entries. Defaults to sorting by date and tie-breaking on lexographical order.
## API
- Category: Emitter

View File

@ -7,27 +7,24 @@ Want to see what Quartz can do? Here are some cool community gardens:
- [Quartz Documentation (this site!)](https://quartz.jzhao.xyz/)
- [Jacky Zhao's Garden](https://jzhao.xyz/)
- [Socratica Toolbox](https://toolbox.socratica.info/)
- [oldwinter の数字花园](https://garden.oldwinter.top/)
- [Morrowind Modding Wiki](https://morrowind-modding.github.io/)
- [Aaron Pham's Garden](https://aarnphm.xyz/)
- [The Quantum Garden](https://quantumgardener.blog/)
- [Abhijeet's Math Wiki](https://abhmul.github.io/quartz/Math-Wiki/)
- [Matt Dunn's Second Brain](https://mattdunn.info/)
- [Pelayo Arbues' Notes](https://pelayoarbues.github.io/)
- [Vince Imbat's Talahardin](https://vinceimbat.com/)
- [Pelayo Arbues' Notes](https://pelayoarbues.com/)
- [Stanford CME 302 Numerical Linear Algebra](https://ericdarve.github.io/NLA/)
- [A Pattern Language - Christopher Alexander (Architecture)](https://patternlanguage.cc/)
- [oldwinter の数字花园](https://garden.oldwinter.top/)
- [Eilleen's Everything Notebook](https://quartz.eilleeenz.com/)
- [🧠🌳 Chad's Mind Garden](https://www.chadly.net/)
- [Pedro MC Fernandes's Topo da Mente](https://www.pmcf.xyz/topo-da-mente/)
- [Mau Camargo's Notkesto](https://notes.camargomau.com/)
- [Caicai's Novels](https://imoko.cc/blog/caicai/)
- [🌊 Collapsed Wave](https://collapsedwave.com/)
- [Sideny's 3D Artist's Handbook](https://sidney-eliot.github.io/3d-artists-handbook/)
- [Mike's AI Garden 🤖🪴](https://mwalton.me/)
- [Brandon Boswell's Garden](https://brandonkboswell.com)
- [Scaling Synthesis - A hypertext research notebook](https://scalingsynthesis.com/)
- [Data Dictionary 🧠](https://glossary.airbyte.com/)
- [sspaeti.com's Second Brain](https://brain.sspaeti.com/)
- [🪴Aster's notebook](https://notes.asterhu.com)
- [🥷🏻🌳🍃 Computer Science & Thinkering Garden](https://notes.yxy.ninja)
- [A Pattern Language - Christopher Alexander (Architecture)](https://patternlanguage.cc/)
- [Gatekeeper Wiki](https://www.gatekeeper.wiki)
- [Ellie's Notes](https://ellie.wtf)
- [🥷🏻🌳🍃 Computer Science & Thinkering Garden](https://notes.yxy.ninja)
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)!

99
package-lock.json generated
View File

@ -1,12 +1,12 @@
{
"name": "@jackyzha0/quartz",
"version": "4.2.3",
"version": "4.3.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@jackyzha0/quartz",
"version": "4.2.3",
"version": "4.3.0",
"license": "MIT",
"bin": {
"quartz": "quartz/bootstrap-cli.mjs"
@ -83,7 +83,7 @@
"yargs": "^17.7.2"
},
"engines": {
"node": ">=18.14",
"node": "20 || >=22",
"npm": ">=9.3.1"
}
},
@ -1243,7 +1243,7 @@
"integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==",
"dev": true,
"dependencies": {
"undici-types": "~5.26.4"
"undici-types": "~6.13.0"
}
},
"node_modules/@types/pretty-time": {
@ -1268,9 +1268,9 @@
"dev": true
},
"node_modules/@types/ws": {
"version": "8.5.10",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz",
"integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==",
"version": "8.5.12",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.12.tgz",
"integrity": "sha512-3tPRkv1EtkDpzlgyKyI8pGsGZAGPEaXeu0DOj5DI25Ja91bdAYddYHbADRYVrZMRbfW+1l5YwXVDKohDJNQxkQ==",
"dev": true,
"dependencies": {
"@types/node": "*"
@ -3322,7 +3322,7 @@
"@isaacs/cliui": "^8.0.2"
},
"engines": {
"node": ">=14"
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@ -3674,7 +3674,7 @@
"integrity": "sha512-CQl19J/g+Hbjbv4Y3mFNNXFEL/5t/KCg8POCuUqd4rMKjGG+j1ybER83hxV58zL+dFI1PTkt3GNFSHRt+d8qEQ==",
"dev": true,
"engines": {
"node": "14 || >=16.14"
"node": "20 || >=22"
}
},
"node_modules/markdown-table": {
@ -4688,7 +4688,7 @@
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@ -4727,7 +4727,7 @@
"integrity": "sha512-63mVyqaqt0cmn2VcI2aH6kxe1rLAmSROqHMA0i4qqg1tidkfExgpb0FGMikMCn86mw5dFtBtEANfmSSK7TjNHw==",
"dev": true,
"dependencies": {
"@types/nlcst": "^1.0.0"
"@types/nlcst": "^2.0.0"
},
"funding": {
"type": "opencollective",
@ -4801,15 +4801,23 @@
"integrity": "sha512-b/K8ExXaWC9t34kKeDV8kGXBkXZ1HCSAZRYE7HR14eA1GlXX5L8iWhs8USJNhQU9q5ci413jCKF0gOyovvyRBg==",
"dev": true,
"dependencies": {
"nlcst-to-string": "^3.0.0",
"unist-util-modify-children": "^3.0.0",
"unist-util-visit-children": "^2.0.0"
"@types/nlcst": "^2.0.0",
"@types/unist": "^3.0.0",
"nlcst-to-string": "^4.0.0",
"unist-util-modify-children": "^4.0.0",
"unist-util-visit-children": "^3.0.0",
"vfile": "^6.0.0"
},
"funding": {
"type": "github",
"url": "https://github.com/sponsors/wooorm"
}
},
"node_modules/parse-latin/node_modules/@types/unist": {
"version": "3.0.2",
"resolved": "https://registry.npmjs.org/@types/unist/-/unist-3.0.2.tgz",
"integrity": "sha512-dqId9J8K/vGi5Zr7oo212BGii5m3q5Hxlkwy3WpYuKPklmBEvsbMYYyLxAQpSffdLl/gdW0XUpKWFvYmyoWCoQ=="
},
"node_modules/parse-numeric-range": {
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/parse-numeric-range/-/parse-numeric-range-1.3.0.tgz",
@ -4921,9 +4929,9 @@
}
},
"node_modules/prettier": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.2.tgz",
"integrity": "sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-3.3.3.tgz",
"integrity": "sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==",
"dev": true,
"bin": {
"prettier": "bin/prettier.cjs"
@ -5297,12 +5305,13 @@
"integrity": "sha512-qoF6Vz3BjU2tP6OfZqHOvCU0ACmu/6jhGaINSQRI9mM7wCxNQTKB3JUAN4SVoN2ybElEDTxBIABRep7e569iJw==",
"dev": true,
"dependencies": {
"retext": "^8.1.0",
"retext-smartypants": "^5.2.0",
"retext": "^9.0.0",
"retext-smartypants": "^6.0.0",
"unified": "^11.0.4",
"unist-util-visit": "^5.0.0"
},
"engines": {
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
"node": ">=16.0.0"
}
},
"node_modules/remark-stringify": {
@ -5376,10 +5385,10 @@
"integrity": "sha512-N9/Kq7YTn6ZpzfiGW45WfEGJqFf1IM1q8OsRa1CGzIebCJBNCANDRmOrholiDRGKo/We7ofKR4SEvcGAWEMD3Q==",
"dev": true,
"dependencies": {
"@types/nlcst": "^1.0.0",
"retext-latin": "^3.0.0",
"retext-stringify": "^3.0.0",
"unified": "^10.0.0"
"@types/nlcst": "^2.0.0",
"retext-latin": "^4.0.0",
"retext-stringify": "^4.0.0",
"unified": "^11.0.0"
},
"funding": {
"type": "opencollective",
@ -5446,10 +5455,9 @@
"integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.0",
"is-buffer": "^2.0.0",
"unist-util-stringify-position": "^3.0.0",
"vfile-message": "^3.0.0"
"@types/nlcst": "^2.0.0",
"parse-latin": "^7.0.0",
"unified": "^11.0.0"
},
"funding": {
"type": "opencollective",
@ -5572,10 +5580,9 @@
"integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.0",
"is-buffer": "^2.0.0",
"unist-util-stringify-position": "^3.0.0",
"vfile-message": "^3.0.0"
"@types/nlcst": "^2.0.0",
"nlcst-to-string": "^4.0.0",
"unist-util-visit": "^5.0.0"
},
"funding": {
"type": "opencollective",
@ -5723,10 +5730,9 @@
"integrity": "sha512-r7qlzkgErKjobAmyNIkkSpizsFPYiUPuJb5pNW1RB4JcYVZhs4lIbVqk8XPk033CV/1z8ss5pkax8SuhGpcG8g==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.0",
"is-buffer": "^2.0.0",
"unist-util-stringify-position": "^3.0.0",
"vfile-message": "^3.0.0"
"@types/nlcst": "^2.0.0",
"nlcst-to-string": "^4.0.0",
"unified": "^11.0.0"
},
"funding": {
"type": "opencollective",
@ -5769,13 +5775,14 @@
"integrity": "sha512-nV6YcJo5wbLW77m+8KjH8aB/7/rxQy9SZ0HY5shnwULfS+9nmTtVXAJET5NdZmCzA4fPI/Hm1wo/Po/4mopOdg==",
"dev": true,
"dependencies": {
"glob": "^10.3.7"
"glob": "^11.0.0",
"package-json-from-dist": "^1.0.0"
},
"bin": {
"rimraf": "dist/esm/bin.mjs"
},
"engines": {
"node": ">=14.18"
"node": "20 || >=22"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
@ -6303,9 +6310,9 @@
"dev": true
},
"node_modules/tsx": {
"version": "4.16.0",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.0.tgz",
"integrity": "sha512-MPgN+CuY+4iKxGoJNPv+1pyo5YWZAQ5XfsyobUG+zoKG7IkvCPLZDEyoIb8yLS2FcWci1nlxAqmvPlFWD5AFiQ==",
"version": "4.16.2",
"resolved": "https://registry.npmjs.org/tsx/-/tsx-4.16.2.tgz",
"integrity": "sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ==",
"dev": true,
"dependencies": {
"esbuild": "~0.21.5",
@ -6741,9 +6748,9 @@
}
},
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"version": "6.13.0",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.13.0.tgz",
"integrity": "sha512-xtFJHudx8S2DSoujjMd1WeWvn7KKWFRESZTMeL1RptAYERu29D6jphMjjY+vn96jvN3kVPDNxU/E13VTaXj6jg==",
"dev": true
},
"node_modules/unherit": {
@ -6820,7 +6827,7 @@
"integrity": "sha512-yXi4Lm+TG5VG+qvokP6tpnk+r1EPwyYL04JWDxLvgvPV40jANh7nm3udk65OOWquvbMDe+PL9+LmkxDpTv/7BA==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.0",
"@types/unist": "^3.0.0",
"array-iterate": "^2.0.0"
},
"funding": {
@ -6895,7 +6902,7 @@
"integrity": "sha512-+LWpMFqyUwLGpsQxpumsQ9o9DG2VGLFrpz+rpVXYIEdPy57GSy5HioC0g3bg/8WP9oCLlapQtklOzQ8uLS496Q==",
"dev": true,
"dependencies": {
"@types/unist": "^2.0.0"
"@types/unist": "^3.0.0"
},
"funding": {
"type": "opencollective",

View File

@ -2,7 +2,7 @@
"name": "@jackyzha0/quartz",
"description": "🌱 publish your digital garden and notes as a website",
"private": true,
"version": "4.2.3",
"version": "4.3.0",
"type": "module",
"author": "jackyzha0 <j.zhao2k19@gmail.com>",
"license": "MIT",
@ -25,7 +25,7 @@
},
"engines": {
"npm": ">=9.3.1",
"node": ">=18.14"
"node": "20 || >=22"
},
"keywords": [
"site generator",

View File

@ -6,6 +6,7 @@ export const sharedPageComponents: SharedLayout = {
head: Component.Head(),
// header: [Component.PageTitle(), Component.Search(), Component.Darkmode()],
header: [],
afterBody: [],
footer: Component.Footer({
links: {
About: "/About",

View File

@ -38,8 +38,13 @@ type BuildData = {
type FileEvent = "add" | "change" | "delete"
function newBuildId() {
return new Date().toISOString()
}
async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) {
const ctx: BuildCtx = {
buildId: newBuildId(),
argv,
cfg,
allSlugs: [],
@ -187,6 +192,7 @@ async function partialRebuildFromEntrypoint(
const perf = new PerfTimer()
console.log(chalk.yellow("Detected change, rebuilding..."))
ctx.buildId = newBuildId()
// UPDATE DEP GRAPH
const fp = joinSegments(argv.directory, toPosixPath(filepath)) as FilePath
@ -412,6 +418,8 @@ async function rebuildFromEntrypoint(
const perf = new PerfTimer()
console.log(chalk.yellow("Detected change, rebuilding..."))
ctx.buildId = newBuildId()
try {
const filesToRebuild = [...toRebuild].filter((fp) => !toRemove.has(fp))
@ -437,6 +445,13 @@ async function rebuildFromEntrypoint(
const parsedFiles = [...contentMap.values()]
const filteredContent = filterContent(ctx, parsedFiles)
// re-update slugs
const trackedSlugs = [...new Set([...contentMap.keys(), ...toRebuild, ...trackedAssets])]
.filter((fp) => !toRemove.has(fp))
.map((fp) => slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath))
ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])]
// TODO: we can probably traverse the link graph to figure out what's safe to delete here
// instead of just deleting everything
await rimraf(path.join(argv.output, ".*"), {glob: true})

View File

@ -77,10 +77,11 @@ export interface FullPageLayout {
header: QuartzComponent[]
beforeBody: QuartzComponent[]
pageBody: QuartzComponent
afterBody: QuartzComponent[]
left: QuartzComponent[]
right: QuartzComponent[]
footer: QuartzComponent
}
export type PageLayout = Pick<FullPageLayout, "beforeBody" | "left" | "right">
export type SharedLayout = Pick<FullPageLayout, "head" | "header" | "footer">
export type SharedLayout = Pick<FullPageLayout, "head" | "header" | "footer" | "afterBody">

View File

@ -0,0 +1,44 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import { classNames } from "../util/lang"
// @ts-ignore
import script from "./scripts/comments.inline"
type Options = {
provider: "giscus"
options: {
repo: `${string}/${string}`
repoId: string
category: string
categoryId: string
mapping?: "url" | "title" | "og:title" | "specific" | "number" | "pathname"
strict?: boolean
reactionsEnabled?: boolean
inputPosition?: "top" | "bottom"
}
}
function boolToStringBool(b: boolean): string {
return b ? "1" : "0"
}
export default ((opts: Options) => {
const Comments: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
return (
<div
class={classNames(displayClass, "giscus")}
data-repo={opts.options.repo}
data-repo-id={opts.options.repoId}
data-category={opts.options.category}
data-category-id={opts.options.categoryId}
data-mapping={opts.options.mapping ?? "url"}
data-strict={boolToStringBool(opts.options.strict ?? true)}
data-reactions-enabled={boolToStringBool(opts.options.reactionsEnabled ?? true)}
data-input-position={opts.options.inputPosition ?? "bottom"}
></div>
)
}
Comments.afterDOMLoaded = script
return Comments
}) satisfies QuartzComponentConstructor<Options>

View File

@ -48,12 +48,9 @@ export default ((userOpts?: Partial<Options>) => {
// memoized
let fileTree: FileNode
let jsonTree: string
let lastBuildId: string = ""
function constructFileTree(allFiles: QuartzPluginData[]) {
if (fileTree) {
return
}
// Construct tree from allFiles
fileTree = new FileNode("")
allFiles.forEach((file) => fileTree.add(file))
@ -82,12 +79,17 @@ export default ((userOpts?: Partial<Options>) => {
}
const Explorer: QuartzComponent = ({
ctx,
cfg,
allFiles,
displayClass,
fileData,
}: QuartzComponentProps) => {
constructFileTree(allFiles)
if (ctx.buildId !== lastBuildId) {
lastBuildId = ctx.buildId
constructFileTree(allFiles)
}
return (
<div class={classNames(displayClass, "explorer")}>
<button

View File

@ -20,7 +20,6 @@ export default ((opts?: Options) => {
const links = opts?.links ?? []
return (
<footer class={`${displayClass ?? ""}`}>
<hr />
<p>
© {year} Miguel Pimentel · Created with{" "}
<a href="https://quartz.jzhao.xyz/">Quartz</a>.

View File

@ -4,9 +4,9 @@ import {Date, getDate} from "./Date"
import {QuartzComponent, QuartzComponentProps} from "./types"
import {GlobalConfiguration} from "../cfg"
export function byDateAndAlphabetical(
cfg: GlobalConfiguration,
): (f1: QuartzPluginData, f2: QuartzPluginData) => number {
export type SortFn = (f1: QuartzPluginData, f2: QuartzPluginData) => number
export function byDateAndAlphabetical(cfg: GlobalConfiguration): SortFn {
return (f1, f2) => {
if (f1.dates && f2.dates) {
// sort descending
@ -27,6 +27,7 @@ export function byDateAndAlphabetical(
type Props = {
limit?: number
sort?: SortFn
} & QuartzComponentProps
export const PageList: QuartzComponent = ({

View File

@ -15,14 +15,15 @@ const PageTitle: QuartzComponent = ({
const title = cfg?.pageTitle ?? i18n(cfg.locale).propertyDefaults.title
const baseDir = pathToRoot(fileData.slug!)
return (
<h1 class={classNames(displayClass, "page-title")}>
<h2 class={classNames(displayClass, "page-title")}>
<a href={baseDir}>{title}</a>
</h1>
</h2>
)
}
PageTitle.css = `
.page-title {
font-size: 1.75rem;
margin: 0;
}
`

View File

@ -43,7 +43,7 @@ export default ((userOpts?: Partial<SearchOptions>) => {
<circle cx="8" cy="8" r="7" />
</g>
</svg>
</div>
</button>
<div id="search-container">
<div id="search-space">
<input

View File

@ -19,6 +19,7 @@ import DesktopOnly from "./DesktopOnly"
import MobileOnly from "./MobileOnly"
import RecentNotes from "./RecentNotes"
import Breadcrumbs from "./Breadcrumbs"
import Comments from "./Comments"
export {
ArticleTitle,
@ -42,4 +43,5 @@ export {
RecentNotes,
NotFound,
Breadcrumbs,
Comments,
}

View File

@ -17,6 +17,7 @@ interface FolderContentOptions {
* Whether to display number of folders
*/
showFolderCount: boolean
sort?: SortFn
}
const defaultOptions: FolderContentOptions = {
@ -42,6 +43,7 @@ export default ((opts?: Partial<FolderContentOptions>) => {
const classes = ["popover-hint", ...cssClasses].join(" ")
const listProps = {
...props,
sort: options.sort,
allFiles: allPagesInFolder,
}

View File

@ -96,18 +96,17 @@ const TagContent: QuartzComponent = (props: QuartzComponentProps) => {
</p>
<PageList limit={numPages} {...listProps} />
</div>
</div>
)
})}
)
})}
</div>
</div>
</div>
)
} else {
const pages = allPagesWithTag(tag)
const listProps = {
...props,
allFiles: pages,
}
)
} else {
const pages = allPagesWithTag(tag)
const listProps = {
...props,
allFiles: pages,
}
return (
<div class={classes}>
@ -122,10 +121,10 @@ const TagContent: QuartzComponent = (props: QuartzComponentProps) => {
<PageList {...listProps} />
</div>
</div>
</div>
)
)
}
}
}
TagContent.css = style + PageList.css
export default (() => TagContent) satisfies QuartzComponentConstructor
TagContent.css = style + PageList.css
return TagContent
}) satisfies QuartzComponentConstructor

View File

@ -20,6 +20,7 @@ interface RenderComponents {
header: QuartzComponent[]
beforeBody: QuartzComponent[]
pageBody: QuartzComponent
afterBody: QuartzComponent[]
left: QuartzComponent[]
right: QuartzComponent[]
footer: QuartzComponent
@ -217,6 +218,7 @@ export function renderPage(
header,
beforeBody,
pageBody: Content,
afterBody,
left,
right,
footer: Footer,
@ -265,6 +267,12 @@ export function renderPage(
</div>
</div>
<Content {...componentData} />
<hr />
<div class="page-footer">
{afterBody.map((BodyComponent) => (
<BodyComponent {...componentData} />
))}
</div>
</div>
{RightComponent}
</Body>

View File

@ -0,0 +1,67 @@
const changeTheme = (e: CustomEventMap["themechange"]) => {
const theme = e.detail.theme
const iframe = document.querySelector("iframe.giscus-frame") as HTMLIFrameElement
if (!iframe) {
return
}
if (!iframe.contentWindow) {
return
}
iframe.contentWindow.postMessage(
{
giscus: {
setConfig: {
theme: theme,
},
},
},
"https://giscus.app",
)
}
type GiscusElement = Omit<HTMLElement, "dataset"> & {
dataset: DOMStringMap & {
repo: `${string}/${string}`
repoId: string
category: string
categoryId: string
mapping: "url" | "title" | "og:title" | "specific" | "number" | "pathname"
strict: string
reactionsEnabled: string
inputPosition: "top" | "bottom"
}
}
document.addEventListener("nav", () => {
const giscusContainer = document.querySelector(".giscus") as GiscusElement
if (!giscusContainer) {
return
}
const giscusScript = document.createElement("script")
giscusScript.src = "https://giscus.app/client.js"
giscusScript.async = true
giscusScript.crossOrigin = "anonymous"
giscusScript.setAttribute("data-loading", "lazy")
giscusScript.setAttribute("data-emit-metadata", "0")
giscusScript.setAttribute("data-repo", giscusContainer.dataset.repo)
giscusScript.setAttribute("data-repo-id", giscusContainer.dataset.repoId)
giscusScript.setAttribute("data-category", giscusContainer.dataset.category)
giscusScript.setAttribute("data-category-id", giscusContainer.dataset.categoryId)
giscusScript.setAttribute("data-mapping", giscusContainer.dataset.mapping)
giscusScript.setAttribute("data-strict", giscusContainer.dataset.strict)
giscusScript.setAttribute("data-reactions-enabled", giscusContainer.dataset.reactionsEnabled)
giscusScript.setAttribute("data-input-position", giscusContainer.dataset.inputPosition)
const theme = document.documentElement.getAttribute("saved-theme")
if (theme) {
giscusScript.setAttribute("data-theme", theme)
}
giscusContainer.appendChild(giscusScript)
document.addEventListener("themechange", changeTheme)
window.addCleanup(() => document.removeEventListener("themechange", changeTheme))
})

View File

@ -17,6 +17,10 @@ const observer = new IntersectionObserver((entries) => {
function toggleExplorer(this: HTMLElement) {
this.classList.toggle("collapsed")
this.setAttribute(
"aria-expanded",
this.getAttribute("aria-expanded") === "true" ? "false" : "true",
)
const content = this.nextElementSibling as MaybeHTMLElement
if (!content) return

View File

@ -33,7 +33,7 @@ async function mouseEnterHandler(
thisUrl.hash = ""
thisUrl.search = ""
const targetUrl = new URL(link.href)
const hash = targetUrl.hash
const hash = decodeURIComponent(targetUrl.hash)
targetUrl.hash = ""
targetUrl.search = ""

View File

@ -209,6 +209,8 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
}
searchType = "basic" // reset search type after closing
searchButton?.focus()
}
function showSearch(searchTypeNew: SearchType) {

View File

@ -16,6 +16,10 @@ const observer = new IntersectionObserver((entries) => {
function toggleToc(this: HTMLElement) {
this.classList.toggle("collapsed")
this.setAttribute(
"aria-expanded",
this.getAttribute("aria-expanded") === "true" ? "false" : "true",
)
const content = this.nextElementSibling as HTMLElement | undefined
if (!content) return
content.classList.toggle("collapsed")

View File

@ -6,6 +6,7 @@ export function registerEscapeHandler(
function click(this: HTMLElement, e: HTMLElementEventMap["click"]) {
if (e.target !== this) return
e.preventDefault()
e.stopPropagation()
cb()
}

View File

@ -1,7 +1,6 @@
@use "../../styles/variables.scss" as *;
button#explorer {
all: unset;
background-color: transparent;
border: none;
text-align: left;
@ -11,7 +10,7 @@ button#explorer {
display: flex;
align-items: center;
& h1 {
& h2 {
font-size: 1rem;
display: inline-block;
margin: 0;
@ -46,8 +45,18 @@ button#explorer {
list-style: none;
overflow: hidden;
max-height: none;
transition: max-height 0.35s ease;
transition:
max-height 0.35s ease,
visibility 0s linear 0s;
margin-top: 0.5rem;
visibility: visible;
&.collapsed {
transition:
max-height 0.35s ease,
visibility 0s linear 0.35s;
visibility: hidden;
}
&.collapsed > .overflow::after {
opacity: 0;

View File

@ -5,18 +5,21 @@
max-width: 14rem;
flex-grow: 0.3;
& > #search-icon {
& > .search-button {
background-color: var(--lightgray);
border: none;
border-radius: 4px;
font-family: inherit;
font-size: inherit;
height: 2rem;
padding: 0;
display: flex;
align-items: center;
text-align: inherit;
cursor: pointer;
white-space: nowrap;
& > div {
flex-grow: 1;
}
width: 100%;
justify-content: space-between;
& > p {
display: inline;

View File

@ -29,8 +29,18 @@ button#toc {
list-style: none;
overflow: hidden;
max-height: none;
transition: max-height 0.5s ease;
transition:
max-height 0.5s ease,
visibility 0s linear 0s;
position: relative;
visibility: visible;
&.collapsed {
transition:
max-height 0.5s ease,
visibility 0s linear 0.5s;
visibility: hidden;
}
&.collapsed > .overflow::after {
opacity: 0;

View File

@ -20,8 +20,8 @@ import fa from "./locales/fa-IR"
import pl from "./locales/pl-PL"
export const TRANSLATIONS = {
"en-US": en,
"en-GB": en,
"en-US": enUs,
"en-GB": enGb,
"fr-FR": fr,
"it-IT": it,
"ja-JP": ja,

View File

@ -30,7 +30,7 @@ export const FolderPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (
const opts: FullPageLayout = {
...sharedPageComponents,
...defaultListPageLayout,
pageBody: FolderContent(),
pageBody: FolderContent({ sort: userOpts?.sort }),
...userOpts,
}

View File

@ -27,7 +27,7 @@ export const TagPage: QuartzEmitterPlugin<Partial<FullPageLayout>> = (
const opts: FullPageLayout = {
...sharedPageComponents,
...defaultListPageLayout,
pageBody: TagContent(),
pageBody: TagContent({ sort: userOpts?.sort }),
...userOpts,
}

View File

@ -30,10 +30,10 @@ export function getStaticResourcesFromPlugins(ctx: BuildCtx) {
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))
`,
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))
`,
})
}

View File

@ -5,10 +5,16 @@ import {QuartzTransformerPlugin} from "../types"
interface Options {
renderEngine: "katex" | "mathjax"
customMacros: MacroType
}
export const Latex: QuartzTransformerPlugin<Options> = (opts?: Options) => {
interface MacroType {
[key: string]: string
}
export const Latex: QuartzTransformerPlugin<Partial<Options>> = (opts) => {
const engine = opts?.renderEngine ?? "katex"
const macros = opts?.customMacros ?? {}
return {
name: "Latex",
markdownPlugins() {
@ -18,7 +24,7 @@ export const Latex: QuartzTransformerPlugin<Options> = (opts?: Options) => {
if (engine === "katex") {
return [[rehypeKatex, {output: "html"}]]
} else {
return [rehypeMathjax]
return [[rehypeMathjax, { macros }]]
}
},
externalResources() {

View File

@ -8,7 +8,6 @@ import {
simplifySlug,
splitAnchor,
transformLink,
joinSegments,
} from "../../util/path"
import path from "path"
import {visit} from "unist-util-visit"
@ -68,6 +67,7 @@ export const CrawlLinks: QuartzTransformerPlugin<
type: "element",
tagName: "svg",
properties: {
"aria-hidden": "true",
class: "external-icon",
viewBox: "0 0 512 512",
},

View File

@ -109,7 +109,7 @@ function canonicalizeCallout(calloutName: string): keyof typeof calloutMapping {
export const externalLinkRegex = /^https?:\/\//i
export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/, "g")
export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/g)
// !? -> optional embedding
// \[\[ -> open brace
@ -117,33 +117,28 @@ export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/, "g")
// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
// (\\?\|[^\[\]\#]+)? -> optional escape \ then | then one or more non-special characters (alias)
export const wikilinkRegex = new RegExp(
/!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]/,
"g",
/!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]/g,
)
// ^\|([^\n])+\|\n(\|) -> matches the header row
// ( ?:?-{3,}:? ?\|)+ -> matches the header row separator
// (\|([^\n])+\|\n)+ -> matches the body rows
export const tableRegex = new RegExp(
/^\|([^\n])+\|\n(\|)( ?:?-{3,}:? ?\|)+\n(\|([^\n])+\|\n?)+/,
"gm",
)
export const tableRegex = new RegExp(/^\|([^\n])+\|\n(\|)( ?:?-{3,}:? ?\|)+\n(\|([^\n])+\|\n?)+/gm)
// matches any wikilink, only used for escaping wikilinks inside tables
export const tableWikilinkRegex = new RegExp(/(!?\[\[[^\]]*?\]\])/, "g")
export const tableWikilinkRegex = new RegExp(/(!?\[\[[^\]]*?\]\])/g)
const highlightRegex = new RegExp(/==([^=]+)==/, "g")
const commentRegex = new RegExp(/%%[\s\S]*?%%/, "g")
const highlightRegex = new RegExp(/==([^=]+)==/g)
const commentRegex = new RegExp(/%%[\s\S]*?%%/g)
// from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts
const calloutRegex = new RegExp(/^\[\!(\w+)\|?(.+?)?\]([+-]?)/)
const calloutLineRegex = new RegExp(/^> *\[\!\w+\|?.*?\][+-]?.*$/, "gm")
const calloutLineRegex = new RegExp(/^> *\[\!\w+\|?.*?\][+-]?.*$/gm)
// (?:^| ) -> non-capturing group, tag should start be separated by a space or be the start of the line
// #(...) -> capturing group, tag itself must start with #
// (?:[-_\p{L}\d\p{Z}])+ -> non-capturing group, non-empty string of (Unicode-aware) alpha-numeric characters and symbols, hyphens and/or underscores
// (?:\/[-_\p{L}\d\p{Z}]+)*) -> non-capturing group, matches an arbitrary number of tag strings separated by "/"
const tagRegex = new RegExp(
/(?:^| )#((?:[-_\p{L}\p{Emoji}\p{M}\d])+(?:\/[-_\p{L}\p{Emoji}\p{M}\d]+)*)/,
"gu",
/(?:^| )#((?:[-_\p{L}\p{Emoji}\p{M}\d])+(?:\/[-_\p{L}\p{Emoji}\p{M}\d]+)*)/gu,
)
const blockReferenceRegex = new RegExp(/\^([-_A-Za-z0-9]+)$/, "g")
const ytLinkRegex =
@ -199,8 +194,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<
// replace all wikilinks inside a table first
src = src.replace(tableRegex, (value) => {
// escape all aliases and headers in wikilinks inside a table
return value.replace(tableWikilinkRegex, (value, ...capture) => {
const [raw]: (string | undefined)[] = capture
return value.replace(tableWikilinkRegex, (_value, raw) => {
// const [raw]: (string | undefined)[] = capture
let escaped = raw ?? ""
escaped = escaped.replace("#", "\\#")
// escape pipe characters if they are not already escaped
@ -305,7 +300,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<
} else if ([".pdf"].includes(ext)) {
return {
type: "html",
value: `<iframe src="${url}"></iframe>`,
value: `<iframe src="${url}" class="pdf"></iframe>`,
}
} else {
const block = anchor
@ -689,11 +684,10 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<
// YouTube video (with optional playlist)
node.tagName = "iframe"
node.properties = {
class: "external-embed",
class: "external-embed youtube",
allow: "fullscreen",
frameborder: 0,
width: "600px",
height: "350px",
src: playlistId
? `https://www.youtube.com/embed/${videoId}?list=${playlistId}`
: `https://www.youtube.com/embed/${videoId}`,
@ -702,11 +696,10 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<
// YouTube playlist only.
node.tagName = "iframe"
node.properties = {
class: "external-embed",
class: "external-embed youtube",
allow: "fullscreen",
frameborder: 0,
width: "600px",
height: "350px",
src: `https://www.youtube.com/embed/videoseries?list=${playlistId}`,
}
}

View File

@ -158,7 +158,7 @@ export async function parseMarkdown(
const childPromises: WorkerPromise<ProcessedContent[]>[] = []
for (const chunk of chunks(fps, CHUNK_SIZE)) {
childPromises.push(pool.exec("parseFiles", [argv, chunk, ctx.allSlugs]))
childPromises.push(pool.exec("parseFiles", [ctx.buildId, argv, chunk, ctx.allSlugs]))
}
const results: ProcessedContent[][] = await WorkerPromise.all(

View File

@ -20,11 +20,10 @@ section {
}
.text-highlight {
background-color: #fff23688;
background-color: var(--textHighlight);
padding: 0 0.1rem;
border-radius: 5px;
}
::selection {
background: color-mix(in srgb, var(--tertiary) 60%, rgba(255, 255, 255, 0));
color: var(--darkgray);
@ -181,11 +180,19 @@ a {
}
}
& .page-header {
& .page-header,
& .page-footer {
width: $pageWidth;
margin: $topSpacing auto 0 auto;
margin-top: 1rem;
@media all and (max-width: $fullPageWidth) {
width: initial;
}
}
& .page-header {
margin: $topSpacing auto 0 auto;
@media all and (max-width: $fullPageWidth) {
margin-top: 2rem;
}
}

View File

@ -14,6 +14,7 @@ export interface Argv {
}
export interface BuildCtx {
buildId: string
argv: Argv
cfg: QuartzConfig
allSlugs: FullSlug[]

View File

@ -7,6 +7,7 @@ export interface ColorScheme {
secondary: string
tertiary: string
highlight: string
textHighlight: string
}
interface Colors {
@ -49,6 +50,7 @@ ${stylesheet.join("\n\n")}
--secondary: ${theme.colors.lightMode.secondary};
--tertiary: ${theme.colors.lightMode.tertiary};
--highlight: ${theme.colors.lightMode.highlight};
--textHighlight: ${theme.colors.lightMode.textHighlight};
--headerFont: "${theme.typography.header}", ${DEFAULT_SANS_SERIF};
--bodyFont: "${theme.typography.body}", ${DEFAULT_SANS_SERIF};
@ -64,6 +66,7 @@ ${stylesheet.join("\n\n")}
--secondary: ${theme.colors.darkMode.secondary};
--tertiary: ${theme.colors.darkMode.tertiary};
--highlight: ${theme.colors.darkMode.highlight};
--textHighlight: ${theme.colors.darkMode.textHighlight};
}
`
}

View File

@ -13,6 +13,7 @@ export async function parseFiles(
allSlugs: FullSlug[],
) {
const ctx: BuildCtx = {
buildId,
cfg,
argv,
allSlugs,