pnpm run format

This commit is contained in:
semanticdata 2024-03-14 12:28:44 -05:00
parent bea7d9fccc
commit 75d6af9422
234 changed files with 11896 additions and 12550 deletions

View File

@ -6,22 +6,18 @@ labels: bug
assignees: "" assignees: ""
--- ---
**Describe the bug** **Describe the bug** A clear and concise description of what the bug is.
A clear and concise description of what the bug is.
**To Reproduce** **To Reproduce** Steps to reproduce the behavior:
Steps to reproduce the behavior:
1. Go to '...' 1. Go to '...'
2. Click on '....' 2. Click on '....'
3. Scroll down to '....' 3. Scroll down to '....'
4. See error 4. See error
**Expected behavior** **Expected behavior** A clear and concise description of what you expected to happen.
A clear and concise description of what you expected to happen.
**Screenshots and Source** **Screenshots and Source** If applicable, add screenshots to help explain your problem.
If applicable, add screenshots to help explain your problem.
You can help speed up fixing the problem by either You can help speed up fixing the problem by either
@ -36,5 +32,4 @@ You can help speed up fixing the problem by either
- OS: [e.g. iOS] - OS: [e.g. iOS]
- Browser [e.g. chrome, safari] - Browser [e.g. chrome, safari]
**Additional context** **Additional context** Add any other context about the problem here.
Add any other context about the problem here.

View File

@ -6,14 +6,10 @@ labels: enhancement
assignees: "" assignees: ""
--- ---
**Is your feature request related to a problem? Please describe.** **Is your feature request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like** **Describe the solution you'd like** A clear and concise description of what you want to happen.
A clear and concise description of what you want to happen.
**Describe alternatives you've considered** **Describe alternatives you've considered** A clear and concise description of any alternative solutions or features you've considered.
A clear and concise description of any alternative solutions or features you've considered.
**Additional context** **Additional context** Add any other context or screenshots about the feature request here.
Add any other context or screenshots about the feature request here.

View File

@ -1,10 +1,6 @@
# 🌱 Forgetful Notes # 🌱 Forgetful Notes
![code size](https://img.shields.io/github/languages/code-size/semanticdata/forgetful-notes) ![code size](https://img.shields.io/github/languages/code-size/semanticdata/forgetful-notes) ![repository size](https://img.shields.io/github/repo-size/semanticdata/forgetful-notes) ![commits](https://img.shields.io/github/commit-activity/t/semanticdata/forgetful-notes) ![last commit](https://img.shields.io/github/last-commit/semanticdata/forgetful-notes) ![is website up?](https://img.shields.io/website/https/forgetfulnotes.com.svg)
![repository size](https://img.shields.io/github/repo-size/semanticdata/forgetful-notes)
![commits](https://img.shields.io/github/commit-activity/t/semanticdata/forgetful-notes)
![last commit](https://img.shields.io/github/last-commit/semanticdata/forgetful-notes)
![is website up?](https://img.shields.io/website/https/forgetfulnotes.com.svg)
This repository holds the source code for [Forgetful Notes](https://forgetfulnotes.com)—my digital garden of knowledge. It serves as a platform for my learning and creative endeavours. A space for thinking through, building upon, and coming back to. This repository holds the source code for [Forgetful Notes](https://forgetfulnotes.com)—my digital garden of knowledge. It serves as a platform for my learning and creative endeavours. A space for thinking through, building upon, and coming back to.
@ -107,7 +103,7 @@ You can add custom CSS code within `/quartz/styles/custom.scss`. You will then n
### Fonts ### Fonts
| Used in: | Font Family | Previous Font | | Used in: | Font Family | Previous Font |
| -------- | :------------------------------------------------------: | :----------------------------------------------------------------------: | | --- | :-: | :-: |
| Headers | [Bitter](https://fonts.google.com/specimen/Bitter) | [Schibsted Grotesk](https://fonts.google.com/specimen/Schibsted+Grotesk) | | Headers | [Bitter](https://fonts.google.com/specimen/Bitter) | [Schibsted Grotesk](https://fonts.google.com/specimen/Schibsted+Grotesk) |
| Body | [Bitter](https://fonts.google.com/specimen/Bitter) | [Source Sans Pro](https://fonts.google.com/specimen/Source+Sans+3) | | Body | [Bitter](https://fonts.google.com/specimen/Bitter) | [Source Sans Pro](https://fonts.google.com/specimen/Source+Sans+3) |
| Code | [Fira Mono](https://fonts.google.com/specimen/Fira+Mono) | [IBM Plex Mono](https://fonts.google.com/specimen/IBM+Plex+Mono) | | Code | [Fira Mono](https://fonts.google.com/specimen/Fira+Mono) | [IBM Plex Mono](https://fonts.google.com/specimen/IBM+Plex+Mono) |

View File

@ -27,7 +27,7 @@ Here are some places you can find me on the web. You'll probably be able to find
### Past Titles and Roles ### Past Titles and Roles
| Title | Description | | Title | Description |
| :------------------------------------- | :-------------------------------------------------------------------------------------------------- | | :-- | :-- |
| Civil Engineering Technician | Work under Engineers and Architects providing daily site visits and technical design assistance. | | Civil Engineering Technician | Work under Engineers and Architects providing daily site visits and technical design assistance. |
| Crew Lead | Lead small construction crew throughout mountain road culverts installation. | | Crew Lead | Lead small construction crew throughout mountain road culverts installation. |
| Construction Materials Technician | Materials Lab - Asphalt, Concrete, and Soil testing. Nuclear gauge certified. | | Construction Materials Technician | Materials Lab - Asphalt, Concrete, and Soil testing. Nuclear gauge certified. |

View File

@ -13,8 +13,7 @@ They can be connected to another atomic note or idea in some way. By breaking do
## Example Atomic Note ## Example Atomic Note
Title: Atomic Note: Importance of Exercise Title: Atomic Note: Importance of Exercise Tags: #exercise #health #wellness
Tags: #exercise #health #wellness
Regular exercise confers numerous health benefits, including: Regular exercise confers numerous health benefits, including:

View File

@ -64,8 +64,7 @@ Below are maps showing the most southern extent of where aurora might be observa
### July 12th, 2023 ### July 12th, 2023
![NOAA Space Weather Prediction Center - G-Kp](https://www.swpc.noaa.gov/sites/default/files/images/u2/Aurora_Kp_MapNorthAm.png) ![NOAA Space Weather Prediction Center - G-Kp](https://www.swpc.noaa.gov/sites/default/files/images/u2/Aurora_Kp_MapNorthAm.png) G is NOAA Geomagnetic Storm Index (05)
G is NOAA Geomagnetic Storm Index (05)
Kp is Planetary K Index (09) Kp is Planetary K Index (09)
### September 18th, 2023 ### September 18th, 2023

View File

@ -32,8 +32,7 @@ The MV Derbyshire was a British ore-bulk-oil combination carrier built in 1976.
## Rogue Waves ## Rogue Waves
Rogue waves are unusually large, unpredictable, and suddenly appearing surface waves that can be extremely dangerous to ships, even to large ones. Rogue waves are unusually large, unpredictable, and suddenly appearing surface waves that can be extremely dangerous to ships, even to large ones. In oceanography, rogue waves are more precisely defined as waves whose height is more than twice the significant wave height (Hs or SWH), which is itself defined as the mean of the largest third of waves in a wave record. Therefore, rogue waves are not necessarily the biggest waves found on the water; they are, rather, unusually large waves for a given sea state.
In oceanography, rogue waves are more precisely defined as waves whose height is more than twice the significant wave height (Hs or SWH), which is itself defined as the mean of the largest third of waves in a wave record. Therefore, rogue waves are not necessarily the biggest waves found on the water; they are, rather, unusually large waves for a given sea state.
[Source](https://en.wikipedia.org/wiki/Rogue_wave) [Source](https://en.wikipedia.org/wiki/Rogue_wave)
## Sea Sickness ## Sea Sickness

View File

@ -15,23 +15,13 @@ When you are looking at a tab, you will see six horizontal lines. These lines re
An [[./Arpeggio|arpeggio]] is a type of [[./Chords|broken chord]] in which the notes that compose a chord are individually sounded in a progressive rising or descending order. Arpeggios on keyboard instruments may be called _rolled chords_. An [[./Arpeggio|arpeggio]] is a type of [[./Chords|broken chord]] in which the notes that compose a chord are individually sounded in a progressive rising or descending order. Arpeggios on keyboard instruments may be called _rolled chords_.
```md ```md
e|--------2-----------------| e|--------2-----------------| B|------3---3---------------| G|----2-------2-------------| D|--0-----------------------| A|--------------------------| E|--------------------------|
B|------3---3---------------|
G|----2-------2-------------|
D|--0-----------------------|
A|--------------------------|
E|--------------------------|
``` ```
### Metallica Enter the Sandman (Intro) ### Metallica Enter the Sandman (Intro)
```md ```md
e|---------------------|------------------|---------------|--------------------| e|---------------------|------------------|---------------|--------------------| B|---------------------|------------------|---------------|--------------------| G|---------------------|------------------|---------------|--------------------| D|-------5-------------|----5-------------|----5----------|--------------------| A|----7-----------7----|-7-----------7----|-7-----------7-|--------------------| E|-0--------6--5-----0-|-------6--5-----0-|-------6--5----|--------------------|
B|---------------------|------------------|---------------|--------------------|
G|---------------------|------------------|---------------|--------------------|
D|-------5-------------|----5-------------|----5----------|--------------------|
A|----7-----------7----|-7-----------7----|-7-----------7-|--------------------|
E|-0--------6--5-----0-|-------6--5-----0-|-------6--5----|--------------------|
``` ```
### Pasted ### Pasted

View File

@ -59,8 +59,7 @@ You can [link](https://example.dom/) to external pages. and other internal [[./M
> 1. This is the first list item. > 1. This is the first list item.
> 2. This is the second list item. > 2. This is the second list item.
> >
> Here's some example code: > Here's some example code: `Markdown.generate();`
> `Markdown.generate();`
## Lists ## Lists
@ -140,7 +139,7 @@ In arcu magna, aliquet vel pretium et, molestie et arcu. Mauris lobortis nulla e
### Simple Example ### Simple Example
| Title 1 | Title 2 | Title 3 | Title 4 | | Title 1 | Title 2 | Title 3 | Title 4 |
| --------------------- | --------------------- | --------------------- | --------------------- | | --- | --- | --- | --- |
| lorem | lorem ipsum | lorem ipsum dolor | lorem ipsum dolor sit | | lorem | lorem ipsum | lorem ipsum dolor | lorem ipsum dolor sit |
| lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit | | lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit |
| lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit | | lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit | lorem ipsum dolor sit |
@ -149,7 +148,7 @@ In arcu magna, aliquet vel pretium et, molestie et arcu. Mauris lobortis nulla e
### Longer Example ### Longer Example
| Title 1 | Title 2 | Title 3 | Title 4 | | Title 1 | Title 2 | Title 3 | Title 4 |
| -------------------------- | -------------------------------------- | -------------------------- | -------------------------------------- | | --- | --- | --- | --- |
| lorem | lorem ipsum | lorem ipsum dolor | lorem ipsum dolor sit | | lorem | lorem ipsum | lorem ipsum dolor | lorem ipsum dolor sit |
| lorem ipsum dolor sit amet | lorem ipsum dolor sit amet consectetur | lorem ipsum dolor sit amet | lorem ipsum dolor sit | | lorem ipsum dolor sit amet | lorem ipsum dolor sit amet consectetur | lorem ipsum dolor sit amet | lorem ipsum dolor sit |
| lorem ipsum dolor | lorem ipsum | lorem | lorem ipsum | | lorem ipsum dolor | lorem ipsum | lorem | lorem ipsum |
@ -158,7 +157,7 @@ In arcu magna, aliquet vel pretium et, molestie et arcu. Mauris lobortis nulla e
### Inline Markdown Within Tables ### Inline Markdown Within Tables
| Inline    | Markdown    | In    | Table | | Inline    | Markdown    | In    | Table |
| ------------------------ | -------------------------- | ----------------------------------- | ------ | | --- | --- | --- | --- |
| _italics_ | **bold** | ~~strikethrough~~    | `code` | | _italics_ | **bold** | ~~strikethrough~~    | `code` |
## Horizontal Rule ## Horizontal Rule

View File

@ -9,8 +9,7 @@ tags: [stub]
Markdown is a lightweight [[./Markup Language|Markup Language]] that you can use to add formatting elements to plaintext text documents. Created by [John Gruber](https://daringfireball.net/projects/markdown/) in 2004, Markdown is now one of the world's most popular markup languages. Markdown is a lightweight [[./Markup Language|Markup Language]] that you can use to add formatting elements to plaintext text documents. Created by [John Gruber](https://daringfireball.net/projects/markdown/) in 2004, Markdown is now one of the world's most popular markup languages.
> [!Note] > [!Note] This website's content is exclusively written in Markdown.
> This website's content is exclusively written in Markdown.
## Markdown Flavors ## Markdown Flavors

View File

@ -80,7 +80,7 @@ NeoVim is a fork of Vim focused on extensibility and usability. This is my short
## Plugins ## Plugins
| Author/Plugin | Description | | Author/Plugin | Description |
| ------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------- | | --- | --- |
| [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim) | A snazzy bufferline for Neovim. | | [akinsho/bufferline.nvim](https://github.com/akinsho/bufferline.nvim) | A snazzy bufferline for Neovim. |
| [akinsho/toggleterm.nvim](https://github.com/akinsho/toggleterm.nvim) | A neovim lua plugin to help easily manage multiple terminal windows. | | [akinsho/toggleterm.nvim](https://github.com/akinsho/toggleterm.nvim) | A neovim lua plugin to help easily manage multiple terminal windows. |
| [ap/vim-css-color](https://github.com/ap/vim-css-color) | Preview colours in source code while editing. | | [ap/vim-css-color](https://github.com/ap/vim-css-color) | Preview colours in source code while editing. |

View File

@ -22,10 +22,7 @@ Sometimes poetry is most impactful when it's listened to rather than read. Take
> [!quote] The Cold Wind Blows by Kelly Roper > [!quote] The Cold Wind Blows by Kelly Roper
> >
> Who knows why the cold wind blows > Who knows why the cold wind blows Or where it goes, or what it knows. It only flows in passionate throes Until it finally slows and settles in repose.
> Or where it goes, or what it knows.
> It only flows in passionate throes
> Until it finally slows and settles in repose.
Poets create _sound_ in a variety of ways, like alliteration, assonance, and consonance. Poets create _sound_ in a variety of ways, like alliteration, assonance, and consonance.
@ -41,15 +38,7 @@ Stressed and unstressed syllables aren't the only way you can create rhythm in y
> [!quote] Still I Rise by Maya Angelou > [!quote] Still I Rise by Maya Angelou
> >
> Leaving behind nights of terror and fear > Leaving behind nights of terror and fear I rise Into a daybreak that's wondrously clear I rise Bringing the gifts that my ancestors gave, I am the dream and the hope of the slave. I rise I rise I rise.
> I rise
> Into a daybreak that's wondrously clear
> I rise
> Bringing the gifts that my ancestors gave,
> I am the dream and the hope of the slave.
> I rise
> I rise
> I rise.
## Time to Rhyme ## Time to Rhyme
@ -57,10 +46,7 @@ With poetry, rhythm and rhyme go hand in hand. Both create musicality in the poe
> [!quote] Jabberwocky by Lewis Carrol > [!quote] Jabberwocky by Lewis Carrol
> >
> One, two! One, two! And through and through > One, two! One, two! And through and through The vorpal blade went snicker-snack! He left it dead, and with its head He went galumphing back.
> The vorpal blade went snicker-snack!
> He left it dead, and with its head
> He went galumphing back.
## Formatting ## Formatting

View File

@ -39,10 +39,7 @@ compartir: true
## Ashtavakra Gita ## Ashtavakra Gita
> "The wise man knows the Self, > "The wise man knows the Self, And he plays the game of life. But the fool lives in the world Like a beast of burden."
> And he plays the game of life.
> But the fool lives in the world
> Like a beast of burden."
## Big Mouth ## Big Mouth
@ -130,8 +127,7 @@ compartir: true
> >
> I don't know. The only thing I do know… is that we have to be kind. > I don't know. The only thing I do know… is that we have to be kind.
> >
> Please. Be kind… especially when we don't know what's going on. > Please. Be kind… especially when we don't know what's going on. I know you see yourself as a fighter. Well, I see myself as one too. This is how I fight."
> I know you see yourself as a fighter. Well, I see myself as one too. This is how I fight."
## Yuval Noah Harari ## Yuval Noah Harari

View File

@ -9,8 +9,7 @@ tags: [stub]
Rhizomatic learning is a variety of pedagogical practices informed by the work of Gilles Deleuze and Félix Guattari. It takes it's name from the rhizome. Rhizomatic learning is a variety of pedagogical practices informed by the work of Gilles Deleuze and Félix Guattari. It takes it's name from the rhizome.
> [!Rhizome] > [!Rhizome] Underground stem in which various plants asexually reproduce via budding.
> Underground stem in which various plants asexually reproduce via budding.
## Background ## Background

View File

@ -48,8 +48,7 @@ Let's break it down:
### Price ### Price
Based on price per $1. Based on price per $1. Selected $0.10 as the baseline after averaging some calculations.
Selected $0.10 as the baseline after averaging some calculations.
- 1 point for every $0.01 / GB below $0.10 - 1 point for every $0.01 / GB below $0.10
@ -120,7 +119,7 @@ Selected $0.10 as the baseline after averaging some calculations.
### SSD ### SSD
| Description | $ / GB | 1 per cent | 1 per GB | Coefficient | Score | | Description | $ / GB | 1 per cent | 1 per GB | Coefficient | Score |
| ------------------------- | :----: | :--------: | :------: | :---------: | :---: | | --- | :-: | :-: | :-: | :-: | :-: |
| Inland 1TB $50 TLC | 0.050 | 5 | 1000 | 1 | 1005 | | Inland 1TB $50 TLC | 0.050 | 5 | 1000 | 1 | 1005 |
| Inland 512GB $25 TLC | 0.049 | 5.1 | 512 | 1 | 517 | | Inland 512GB $25 TLC | 0.049 | 5.1 | 512 | 1 | 517 |
| Platinum 2TB $80 TLC | 0.040 | 6 | 2000 | 1 | 2006 | | Platinum 2TB $80 TLC | 0.040 | 6 | 2000 | 1 | 2006 |

View File

@ -13,6 +13,6 @@ In typography and lettering, a "sans-serif", "sans serif", "gothic", or simply "
```css ```css
font-family: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir, font-family: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir,
"Nimbus Sans L", Roboto, Noto, "Segoe UI", Arial, Helvetica, "Nimbus Sans L", Roboto, Noto, "Segoe UI", Arial, Helvetica, "Helvetica Neue",
"Helvetica Neue", sans-serif; sans-serif;
``` ```

View File

@ -14,8 +14,7 @@ compartir: true
### Anodyne (adjective) ### Anodyne (adjective)
1. Capable of soothing or eliminating pain. 1. Capable of soothing or eliminating pain.
2. Not likely to offend or arouse tensions. 2. Not likely to offend or arouse tensions. Also used as a _noun_ to describe something that soothes, calms, or comforts.
Also used as a _noun_ to describe something that soothes, calms, or comforts.
### Arete (noun) ### Arete (noun)

View File

@ -2,8 +2,7 @@
title: Creating your own Quartz components title: Creating your own Quartz components
--- ---
> [!warning] > [!warning] This guide assumes you have experience writing JavaScript and are familiar with TypeScript.
> This guide assumes you have experience writing JavaScript and are familiar with TypeScript.
Normally on the web, we write layout code using HTML which looks something like the following: Normally on the web, we write layout code using HTML which looks something like the following:
@ -40,7 +39,7 @@ const defaultOptions: Options = {
} }
export default ((userOpts?: Options) => { export default ((userOpts?: Options) => {
const opts = { ...userOpts, ...defaultOpts } const opts = {...userOpts, ...defaultOpts}
function YourComponent(props: QuartzComponentProps) { function YourComponent(props: QuartzComponentProps) {
if (opts.favouriteNumber < 0) { if (opts.favouriteNumber < 0) {
return null return null
@ -116,8 +115,7 @@ export default (() => {
}) satisfies QuartzComponentConstructor }) satisfies QuartzComponentConstructor
``` ```
> [!warning] > [!warning] Quartz does not use CSS modules so any styles you declare here apply _globally_. If you only want it to apply to your component, make sure you use specific class names and selectors.
> Quartz does not use CSS modules so any styles you declare here apply _globally_. If you only want it to apply to your component, make sure you use specific class names and selectors.
### Scripts and Interactivity ### Scripts and Interactivity
@ -142,8 +140,7 @@ export default (() => {
}) satisfies QuartzComponentConstructor }) satisfies QuartzComponentConstructor
``` ```
> [!hint] > [!hint] For those coming from React, Quartz components are different from React components in that it only uses JSX for templating and layout. Hooks like `useEffect`, `useState`, etc. are not rendered and other properties that accept functions like `onClick` handlers will not work. Instead, do it using a regular JS script that modifies the DOM element directly.
> For those coming from React, Quartz components are different from React components in that it only uses JSX for templating and layout. Hooks like `useEffect`, `useState`, etc. are not rendered and other properties that accept functions like `onClick` handlers will not work. Instead, do it using a regular JS script that modifies the DOM element directly.
As the names suggest, the `.beforeDOMLoaded` scripts are executed _before_ the page is done loading so it doesn't have access to any elements on the page. This is mostly used to prefetch any critical data. As the names suggest, the `.beforeDOMLoaded` scripts are executed _before_ the page is done loading so it doesn't have access to any elements on the page. This is mostly used to prefetch any critical data.
@ -157,12 +154,11 @@ document.addEventListener("nav", () => {
// e.g. attach event listeners // e.g. attach event listeners
const toggleSwitch = document.querySelector("#switch") as HTMLInputElement const toggleSwitch = document.querySelector("#switch") as HTMLInputElement
toggleSwitch.removeEventListener("change", switchTheme) toggleSwitch.removeEventListener("change", switchTheme)
toggleSwitch.addEventListener("change", switchTheme, { passive: true }) toggleSwitch.addEventListener("change", switchTheme, {passive: true})
}) })
``` ```
It is best practice to track any event handlers via `window.addCleanup` to prevent memory leaks. It is best practice to track any event handlers via `window.addCleanup` to prevent memory leaks. This will get called on page navigation.
This will get called on page navigation.
#### Importing Code #### Importing Code
@ -206,7 +202,7 @@ import Content from "./pages/Content"
import Darkmode from "./Darkmode" import Darkmode from "./Darkmode"
import YourComponent from "./YourComponent" import YourComponent from "./YourComponent"
export { ArticleTitle, Content, Darkmode, YourComponent } export {ArticleTitle, Content, Darkmode, YourComponent}
``` ```
Then, you can use it like any other component in `quartz.layout.ts` via `Component.YourComponent()`. See the [[configuration#Layout|layout]] section for more details. Then, you can use it like any other component in `quartz.layout.ts` via `Component.YourComponent()`. See the [[configuration#Layout|layout]] section for more details.
@ -230,5 +226,4 @@ export default (() => {
}) satisfies QuartzComponentConstructor }) satisfies QuartzComponentConstructor
``` ```
> [!hint] > [!hint] Look in `quartz/components` for more examples of components in Quartz as reference for your own components!
> Look in `quartz/components` for more examples of components in Quartz as reference for your own components!

View File

@ -2,8 +2,7 @@
title: Making your own plugins title: Making your own plugins
--- ---
> [!warning] > [!warning] This part of the documentation will assume you have working knowledge in TypeScript and will include code snippets that describe the interface of what Quartz plugins should look like.
> This part of the documentation will assume you have working knowledge in TypeScript and will include code snippets that describe the interface of what Quartz plugins should look like.
Quartz's plugins are a series of transformations over content. This is illustrated in the diagram of the processing pipeline below: Quartz's plugins are a series of transformations over content. This is illustrated in the diagram of the processing pipeline below:
@ -61,7 +60,7 @@ A good example of a transformer plugin that borrows from the `remark` and `rehyp
import remarkMath from "remark-math" import remarkMath from "remark-math"
import rehypeKatex from "rehype-katex" import rehypeKatex from "rehype-katex"
import rehypeMathjax from "rehype-mathjax/svg" import rehypeMathjax from "rehype-mathjax/svg"
import { QuartzTransformerPlugin } from "../types" import {QuartzTransformerPlugin} from "../types"
interface Options { interface Options {
renderEngine: "katex" | "mathjax" renderEngine: "katex" | "mathjax"
@ -78,7 +77,7 @@ export const Latex: QuartzTransformerPlugin<Options> = (opts?: Options) => {
if (engine === "katex") { if (engine === "katex") {
// if you need to pass options into a plugin, you // if you need to pass options into a plugin, you
// can use a tuple of [plugin, options] // can use a tuple of [plugin, options]
return [[rehypeKatex, { output: "html" }]] return [[rehypeKatex, {output: "html"}]]
} else { } else {
return [rehypeMathjax] return [rehypeMathjax]
} }
@ -199,7 +198,7 @@ A filter plugin must define a `name` field and a `shouldPublish` function that t
For example, here is the built-in plugin for removing drafts: For example, here is the built-in plugin for removing drafts:
```ts title="quartz/plugins/filters/draft.ts" ```ts title="quartz/plugins/filters/draft.ts"
import { QuartzFilterPlugin } from "../types" import {QuartzFilterPlugin} from "../types"
export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({ export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({
name: "RemoveDrafts", name: "RemoveDrafts",
@ -266,7 +265,7 @@ export const ContentPage: QuartzEmitterPlugin = () => {
...defaultContentPageLayout, ...defaultContentPageLayout,
pageBody: Content(), pageBody: Content(),
} }
const { head, header, beforeBody, pageBody, left, right, footer } = layout const {head, header, beforeBody, pageBody, left, right, footer} = layout
return { return {
name: "ContentPage", name: "ContentPage",
getQuartzComponents() { getQuartzComponents() {
@ -319,5 +318,4 @@ export const ContentPage: QuartzEmitterPlugin = () => {
Note that it takes in a `FullPageLayout` as the options. It's made by combining a `SharedLayout` and a `PageLayout` both of which are provided through the `quartz.layout.ts` file. Note that it takes in a `FullPageLayout` as the options. It's made by combining a `SharedLayout` and a `PageLayout` both of which are provided through the `quartz.layout.ts` file.
> [!hint] > [!hint] Look in `quartz/plugins` for more examples of plugins in Quartz as reference for your own plugins!
> Look in `quartz/plugins` for more examples of plugins in Quartz as reference for your own plugins!

View File

@ -15,7 +15,7 @@ Luckily, we can mimic nominal typing using [brands](https://www.typescriptlang.o
type FullSlug = string type FullSlug = string
// we do // we do
type FullSlug = string & { __brand: "full" } type FullSlug = string & {__brand: "full"}
// that way, the following will fail typechecking // that way, the following will fail typechecking
const slug: FullSlug = "some random string" const slug: FullSlug = "some random string"

View File

@ -36,8 +36,7 @@ Some common frontmatter fields that are natively supported by Quartz:
## Syncing your Content ## Syncing your Content
When your Quartz is at a point you're happy with, you can save your changes to GitHub. When your Quartz is at a point you're happy with, you can save your changes to GitHub. First, make sure you've [[setting up your GitHub repository|already setup your GitHub repository]] and then do `npx quartz sync`.
First, make sure you've [[setting up your GitHub repository|already setup your GitHub repository]] and then do `npx quartz sync`.
## Customization ## Customization

View File

@ -10,8 +10,7 @@ npx quartz build --serve
This will start a local web server to run your Quartz on your computer. Open a web browser and visit `http://localhost:8080/` to view it. This will start a local web server to run your Quartz on your computer. Open a web browser and visit `http://localhost:8080/` to view it.
> [!hint] Flags and options > [!hint] Flags and options For full help options, you can run `npx quartz build --help`.
> For full help options, you can run `npx quartz build --help`.
> >
> Most of these have sensible defaults but you can override them if you have a custom setup: > Most of these have sensible defaults but you can override them if you have a custom setup:
> >

View File

@ -4,8 +4,7 @@ title: Configuration
Quartz is meant to be extremely configurable, even if you don't know any coding. Most of the configuration you should need can be done by just editing `quartz.config.ts` or changing [[layout|the layout]] in `quartz.layout.ts`. Quartz is meant to be extremely configurable, even if you don't know any coding. Most of the configuration you should need can be done by just editing `quartz.config.ts` or changing [[layout|the layout]] in `quartz.layout.ts`.
> [!tip] > [!tip] If you edit Quartz configuration using a text-editor that has TypeScript language support like VSCode, it will warn you when you you've made an error in your configuration, helping you avoid configuration mistakes!
> If you edit Quartz configuration using a text-editor that has TypeScript language support like VSCode, it will warn you when you you've made an error in your configuration, helping you avoid configuration mistakes!
The configuration of Quartz can be broken down into two main parts: The configuration of Quartz can be broken down into two main parts:
@ -71,8 +70,7 @@ plugins: {
You can customize the behaviour of Quartz by adding, removing and reordering plugins in the `transformers`, `filters` and `emitters` fields. You can customize the behaviour of Quartz by adding, removing and reordering plugins in the `transformers`, `filters` and `emitters` fields.
> [!note] > [!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.
> 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/filter|Filter]]), 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:
@ -93,7 +91,7 @@ For example, the [[plugins/Latex|Latex]] plugin allows you to pass in a field sp
```ts title="quartz.config.ts" ```ts title="quartz.config.ts"
transformers: [ transformers: [
Plugin.FrontMatter(), // use default options Plugin.FrontMatter(), // use default options
Plugin.Latex({ renderEngine: "katex" }), // set some custom options Plugin.Latex({renderEngine: "katex"}), // set some custom options
] ]
``` ```

View File

@ -39,8 +39,7 @@ a & b & c
\end{bmatrix} \end{bmatrix}
$$ $$
> [!warn] > [!warn] Due to limitations in the [underlying parsing library](https://github.com/remarkjs/remark-math), block math in Quartz requires the `$$` delimiters to be on newlines like above.
> Due to limitations in the [underlying parsing library](https://github.com/remarkjs/remark-math), block math in Quartz requires the `$$` delimiters to be on newlines like above.
### Inline Math ### Inline Math
@ -59,8 +58,7 @@ For example:
### Using mhchem ### Using mhchem
Add the following import to the top of `quartz/plugins/transformers/latex.ts` (before all the other Add the following import to the top of `quartz/plugins/transformers/latex.ts` (before all the other imports):
imports):
```ts title="quartz/plugins/transformers/latex.ts" ```ts title="quartz/plugins/transformers/latex.ts"
import "katex/contrib/mhchem" import "katex/contrib/mhchem"

View File

@ -8,8 +8,7 @@ Quartz supports Mermaid which allows you to add diagrams and charts to your note
By default, Quartz will render Mermaid diagrams to match the site theme. By default, Quartz will render Mermaid diagrams to match the site theme.
> [!warning] > [!warning] Wondering why Mermaid diagrams may not be showing up even if you have them enabled? You may need to reorder your plugins so that [[ObsidianFlavoredMarkdown]] is _after_ [[SyntaxHighlighting]].
> Wondering why Mermaid diagrams may not be showing up even if you have them enabled? You may need to reorder your plugins so that [[ObsidianFlavoredMarkdown]] is _after_ [[SyntaxHighlighting]].
## Syntax ## Syntax

View File

@ -18,8 +18,7 @@ This includes
See [documentation on supported types and syntax here](https://help.obsidian.md/Editing+and+formatting/Callouts). See [documentation on supported types and syntax here](https://help.obsidian.md/Editing+and+formatting/Callouts).
> [!warning] > [!warning] Wondering why callouts may not be showing up even if you have them enabled? You may need to reorder your plugins so that [[ObsidianFlavoredMarkdown]] is _after_ [[SyntaxHighlighting]].
> Wondering why callouts may not be showing up even if you have them enabled? You may need to reorder your plugins so that [[ObsidianFlavoredMarkdown]] is _after_ [[SyntaxHighlighting]].
## Customization ## Customization
@ -42,13 +41,11 @@ By default, custom callouts are handled by applying the `note` style. To make fa
} }
``` ```
> [!warning] > [!warning] Don't forget to ensure that the SVG is URL encoded before putting it in the CSS. You can use tools like [this one](https://yoksel.github.io/url-encoder/) to help you do that.
> Don't forget to ensure that the SVG is URL encoded before putting it in the CSS. You can use tools like [this one](https://yoksel.github.io/url-encoder/) to help you do that.
## Showcase ## Showcase
> [!info] > [!info] Default title
> Default title
> [!question]+ Can callouts be _nested_? > [!question]+ Can callouts be _nested_?
> >
@ -56,41 +53,28 @@ By default, custom callouts are handled by applying the `note` style. To make fa
> > > >
> > > [!example] You can even use multiple layers of nesting. > > > [!example] You can even use multiple layers of nesting.
> [!note] > [!note] Aliases: "note"
> Aliases: "note"
> [!abstract] > [!abstract] Aliases: "abstract", "summary", "tldr"
> Aliases: "abstract", "summary", "tldr"
> [!info] > [!info] Aliases: "info"
> Aliases: "info"
> [!todo] > [!todo] Aliases: "todo"
> Aliases: "todo"
> [!tip] > [!tip] Aliases: "tip", "hint", "important"
> Aliases: "tip", "hint", "important"
> [!success] > [!success] Aliases: "success", "check", "done"
> Aliases: "success", "check", "done"
> [!question] > [!question] Aliases: "question", "help", "faq"
> Aliases: "question", "help", "faq"
> [!warning] > [!warning] Aliases: "warning", "attention", "caution"
> Aliases: "warning", "attention", "caution"
> [!failure] > [!failure] Aliases: "failure", "missing", "fail"
> Aliases: "failure", "missing", "fail"
> [!danger] > [!danger] Aliases: "danger", "error"
> Aliases: "danger", "error"
> [!bug] > [!bug] Aliases: "bug"
> Aliases: "bug"
> [!example] > [!example] Aliases: "example"
> Aliases: "example"
> [!quote] > [!quote] Aliases: "quote", "cite"
> Aliases: "quote", "cite"

View File

@ -10,8 +10,7 @@ By default, it shows all folders and files on your page. To display the explorer
Display names for folders get determined by the `title` frontmatter field in `folder/index.md` (more detail in [[authoring content | Authoring Content]]). If this file does not exist or does not contain frontmatter, the local folder name will be used instead. Display names for folders get determined by the `title` frontmatter field in `folder/index.md` (more detail in [[authoring content | Authoring Content]]). If this file does not exist or does not contain frontmatter, the local folder name will be used instead.
> [!info] > [!info] The explorer uses local storage by default to save the state of your explorer. This is done to ensure a smooth experience when navigating to different pages.
> The explorer uses local storage by default to save the state of your explorer. This is done to ensure a smooth experience when navigating to different pages.
> >
> To clear/delete the explorer state from local storage, delete the `fileTree` entry (guide on how to delete a key from local storage in chromium based browsers can be found [here](https://docs.devolutions.net/kb/general-knowledge-base/clear-browser-local-storage/clear-chrome-local-storage/)). You can disable this by passing `useSavedState: false` as an argument. > To clear/delete the explorer state from local storage, delete the `fileTree` entry (guide on how to delete a key from local storage in chromium based browsers can be found [here](https://docs.devolutions.net/kb/general-knowledge-base/clear-browser-local-storage/clear-chrome-local-storage/)). You can disable this by passing `useSavedState: false` as an argument.
@ -53,8 +52,7 @@ Want to customize it even more?
## Advanced customization ## Advanced customization
This component allows you to fully customize all of its behavior. You can pass a custom `sort`, `filter` and `map` function. This component allows you to fully customize all of its behavior. You can pass a custom `sort`, `filter` and `map` function. All functions you can pass work with the `FileNode` class, which has the following properties:
All functions you can pass work with the `FileNode` class, which has the following properties:
```ts title="quartz/components/ExplorerNode.tsx" {2-5} ```ts title="quartz/components/ExplorerNode.tsx" {2-5}
export class FileNode { export class FileNode {
@ -105,8 +103,7 @@ filterFn: (node: FileNode) => boolean
mapFn: (node: FileNode) => void mapFn: (node: FileNode) => void
``` ```
> [!tip] > [!tip] You can check if a `FileNode` is a folder or a file like this:
> You can check if a `FileNode` is a folder or a file like this:
> >
> ```ts > ```ts
> if (node.file) { > if (node.file) {
@ -175,9 +172,7 @@ You can access the frontmatter of a file by `node.file?.frontmatter?`. This allo
Component.Explorer({ Component.Explorer({
filterFn: (node) => { filterFn: (node) => {
// exclude files with the tag "explorerexclude" // exclude files with the tag "explorerexclude"
return ( return node.file?.frontmatter?.tags?.includes("explorerexclude") !== true
node.file?.frontmatter?.tags?.includes("explorerexclude") !== true
)
}, },
}) })
``` ```
@ -194,12 +189,10 @@ Component.Explorer({
## Advanced examples ## Advanced examples
> [!tip] > [!tip] When writing more complicated functions, the `layout` file can start to look very cramped. You can fix this by defining your functions in another file.
> When writing more complicated functions, the `layout` file can start to look very cramped.
> You can fix this by defining your functions in another file.
> >
> ```ts title="functions.ts" > ```ts title="functions.ts"
> import { Options } from "./quartz/components/ExplorerNode" > import {Options} from "./quartz/components/ExplorerNode"
> export const mapFn: Options["mapFn"] = (node) => { > export const mapFn: Options["mapFn"] = (node) => {
> // implement your function here > // implement your function here
> } > }
@ -214,7 +207,7 @@ Component.Explorer({
> You can then import them like this: > You can then import them like this:
> >
> ```ts title="quartz.layout.ts" > ```ts title="quartz.layout.ts"
> import { mapFn, filterFn, sortFn } from "./functions.ts" > import {mapFn, filterFn, sortFn} from "./functions.ts"
> Component.Explorer({ > Component.Explorer({
> mapFn: mapFn, > mapFn: mapFn,
> filterFn: filterFn, > filterFn: filterFn,

View File

@ -12,8 +12,7 @@ To search content by tags, you can either press `⌘`/`ctrl` + `shift` + `K` or
This component is also keyboard accessible: Tab and Shift+Tab will cycle forward and backward through search results and Enter will navigate to the highlighted result (first result by default). You are also able to navigate search results using `ArrowUp` and `ArrowDown`. This component is also keyboard accessible: Tab and Shift+Tab will cycle forward and backward through search results and Enter will navigate to the highlighted result (first result by default). You are also able to navigate search results using `ArrowUp` and `ArrowDown`.
> [!info] > [!info] Search requires the `ContentIndex` emitter plugin to be present in the [[configuration]].
> Search requires the `ContentIndex` emitter plugin to be present in the [[configuration]].
### Indexing Behaviour ### Indexing Behaviour

View File

@ -13,8 +13,7 @@ By default, the node radius is proportional to the total number of incoming and
Additionally, similar to how browsers highlight visited links a different colour, the graph view will also show nodes that you have visited in a different colour. Additionally, similar to how browsers highlight visited links a different colour, the graph view will also show nodes that you have visited in a different colour.
> [!info] > [!info] Graph View requires the `ContentIndex` emitter plugin to be present in the [[configuration]].
> Graph View requires the `ContentIndex` emitter plugin to be present in the [[configuration]].
## Customization ## Customization

View File

@ -9,8 +9,7 @@ The locale field generally follows a certain format: `{language}-{REGION}`
- `{language}` is usually a [2-letter lowercase language code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes). - `{language}` is usually a [2-letter lowercase language code](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes).
- `{REGION}` is usually a [2-letter uppercase region code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2) - `{REGION}` is usually a [2-letter uppercase region code](https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2)
> [!tip] Interested in contributing? > [!tip] Interested in contributing? We [gladly welcome translation PRs](https://github.com/jackyzha0/quartz/tree/v4/quartz/i18n/locales)! To contribute a translation, do the following things:
> We [gladly welcome translation PRs](https://github.com/jackyzha0/quartz/tree/v4/quartz/i18n/locales)! To contribute a translation, do the following things:
> >
> 1. In the `quartz/i18n/locales` folder, copy the `en-US.ts` file. > 1. In the `quartz/i18n/locales` folder, copy the `en-US.ts` file.
> 2. Rename it to `{language}-{REGION}.ts` so it matches a locale of the format shown above. > 2. Rename it to `{language}-{REGION}.ts` so it matches a locale of the format shown above.

View File

@ -12,8 +12,7 @@ There may be some notes you want to avoid publishing as a website. Quartz suppor
If you'd like to only publish a select number of notes, you can instead use [[ExplicitPublish]] which will filter out all notes except for any that have `publish: true` in the frontmatter. If you'd like to only publish a select number of notes, you can instead use [[ExplicitPublish]] which will filter out all notes except for any that have `publish: true` in the frontmatter.
> [!warning] > [!warning] Regardless of the filter plugin used, **all non-markdown files will be emitted and available publically in the final build.** This includes files such as images, voice recordings, PDFs, etc. One way to prevent this and still be able to embed local images is to create a folder specifically for public media and add the following two patterns to the ignorePatterns array.
> Regardless of the filter plugin used, **all non-markdown files will be emitted and available publically in the final build.** This includes files such as images, voice recordings, PDFs, etc. One way to prevent this and still be able to embed local images is to create a folder specifically for public media and add the following two patterns to the ignorePatterns array.
> >
> `"!(PublicMedia)**/!(*.md)", "!(*.md)"` > `"!(PublicMedia)**/!(*.md)", "!(*.md)"`
@ -21,8 +20,7 @@ If you'd like to only publish a select number of notes, you can instead use [[Ex
This is a field in `quartz.config.ts` under the main [[configuration]] which allows you to specify a list of patterns to effectively exclude from parsing all together. Any valid [fast-glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) pattern works here. This is a field in `quartz.config.ts` under the main [[configuration]] which allows you to specify a list of patterns to effectively exclude from parsing all together. Any valid [fast-glob](https://github.com/mrmlnc/fast-glob#pattern-syntax) pattern works here.
> [!note] > [!note] Bash's glob syntax is slightly different from fast-glob's and using bash's syntax may lead to unexpected results.
> Bash's glob syntax is slightly different from fast-glob's and using bash's syntax may lead to unexpected results.
Common examples include: Common examples include:
@ -31,5 +29,4 @@ Common examples include:
- `!*.md` exclude all files that _don't_ have a `.md` extension - `!*.md` exclude all files that _don't_ have a `.md` extension
- `**/private`: exclude any files or folders named `private` at any level of nesting - `**/private`: exclude any files or folders named `private` at any level of nesting
> [!warning] > [!warning] Marking something as private via either a plugin or through the `ignorePatterns` pattern will only prevent a page from being included in the final built site. If your GitHub repository is public, also be sure to include an ignore for those in the `.gitignore` of your Quartz. See the `git` [documentation](https://git-scm.com/docs/gitignore#_pattern_format) for more information.
> Marking something as private via either a plugin or through the `ignorePatterns` pattern will only prevent a page from being included in the final built site. If your GitHub repository is public, also be sure to include an ignore for those in the `.gitignore` of your Quartz. See the `git` [documentation](https://git-scm.com/docs/gitignore#_pattern_format) for more information.

View File

@ -10,8 +10,7 @@ And, unlike some client-side highlighters, it has a full TextMate parser grammar
In short, it generates HTML that looks exactly like your code in an editor like VS Code. Under the hood, it's powered by [Rehype Pretty Code](https://rehype-pretty-code.netlify.app/) which uses [Shiki](https://github.com/shikijs/shiki). In short, it generates HTML that looks exactly like your code in an editor like VS Code. Under the hood, it's powered by [Rehype Pretty Code](https://rehype-pretty-code.netlify.app/) which uses [Shiki](https://github.com/shikijs/shiki).
> [!warning] > [!warning] Syntax highlighting does have an impact on build speed if you have a lot of code snippets in your notes.
> Syntax highlighting does have an impact on build speed if you have a lot of code snippets in your notes.
## Formatting ## Formatting

View File

@ -6,11 +6,9 @@ Quartz effectively turns your Markdown files and other resources into a bundle o
However, if you'd like to publish your site to the world, you need a way to host it online. This guide will detail how to deploy with common hosting providers but any service that allows you to deploy static HTML should work as well. However, if you'd like to publish your site to the world, you need a way to host it online. This guide will detail how to deploy with common hosting providers but any service that allows you to deploy static HTML should work as well.
> [!warning] > [!warning] The rest of this guide assumes that you've already created your own GitHub repository for Quartz. If you haven't already, [[setting up your GitHub repository|make sure you do so]].
> The rest of this guide assumes that you've already created your own GitHub repository for Quartz. If you haven't already, [[setting up your GitHub repository|make sure you do so]].
> [!hint] > [!hint] Some Quartz features (like [[RSS Feed]] and sitemap generation) require `baseUrl` to be configured properly in your [[configuration]] to work properly. Make sure you set this before deploying!
> Some Quartz features (like [[RSS Feed]] and sitemap generation) require `baseUrl` to be configured properly in your [[configuration]] to work properly. Make sure you set this before deploying!
## Cloudflare Pages ## Cloudflare Pages
@ -29,8 +27,7 @@ Press "Save and deploy" and Cloudflare should have a deployed version of your si
To add a custom domain, check out [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/custom-domains/). To add a custom domain, check out [Cloudflare's documentation](https://developers.cloudflare.com/pages/platform/custom-domains/).
> [!warning] > [!warning] Cloudflare Pages performs a shallow clone by default, so if you rely on `git` for timestamps, it is recommended that you add `git fetch --unshallow &&` to the beginning of the build command (e.g., `git fetch --unshallow && npx quartz build`).
> Cloudflare Pages performs a shallow clone by default, so if you rely on `git` for timestamps, it is recommended that you add `git fetch --unshallow &&` to the beginning of the build command (e.g., `git fetch --unshallow && npx quartz build`).
## GitHub Pages ## GitHub Pages
@ -89,13 +86,11 @@ Then:
1. Head to "Settings" tab of your forked repository and in the sidebar, click "Pages". Under "Source", select "GitHub Actions". 1. Head to "Settings" tab of your forked repository and in the sidebar, click "Pages". Under "Source", select "GitHub Actions".
2. Commit these changes by doing `npx quartz sync`. This should deploy your site to `<github-username>.github.io/<repository-name>`. 2. Commit these changes by doing `npx quartz sync`. This should deploy your site to `<github-username>.github.io/<repository-name>`.
> [!hint] > [!hint] If you get an error about not being allowed to deploy to `github-pages` due to environment protection rules, make sure you remove any existing GitHub pages environments.
> If you get an error about not being allowed to deploy to `github-pages` due to environment protection rules, make sure you remove any existing GitHub pages environments.
> >
> You can do this by going to your Settings page on your GitHub fork and going to the Environments tab and pressing the trash icon. The GitHub action will recreate the environment for you correctly the next time you sync your Quartz. > You can do this by going to your Settings page on your GitHub fork and going to the Environments tab and pressing the trash icon. The GitHub action will recreate the environment for you correctly the next time you sync your Quartz.
> [!info] > [!info] Quartz generates files in the format of `file.html` instead of `file/index.html` which means the trailing slashes for _non-folder paths_ are dropped. As GitHub pages does not do this redirect, this may cause existing links to your site that use trailing slashes to break. If not breaking existing links is important to you (e.g. you are migrating from Quartz 3), consider using [[#Cloudflare Pages]].
> Quartz generates files in the format of `file.html` instead of `file/index.html` which means the trailing slashes for _non-folder paths_ are dropped. As GitHub pages does not do this redirect, this may cause existing links to your site that use trailing slashes to break. If not breaking existing links is important to you (e.g. you are migrating from Quartz 3), consider using [[#Cloudflare Pages]].
### Custom Domain ### Custom Domain
@ -116,8 +111,7 @@ Here's how to add a custom domain to your GitHub pages deployment.
See the [GitHub documentation](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain) for more detail about how to setup your own custom domain with GitHub Pages. See the [GitHub documentation](https://docs.github.com/en/pages/configuring-a-custom-domain-for-your-github-pages-site/managing-a-custom-domain-for-your-github-pages-site#configuring-a-subdomain) for more detail about how to setup your own custom domain with GitHub Pages.
> [!question] Why aren't my changes showing up? > [!question] Why aren't my changes showing up? There could be many different reasons why your changes aren't showing up but the most likely reason is that you forgot to push your changes to GitHub.
> There could be many different reasons why your changes aren't showing up but the most likely reason is that you forgot to push your changes to GitHub.
> >
> Make sure you save your changes to Git and sync it to GitHub by doing `npx quartz sync`. This will also make sure to pull any updates you may have made from other devices so you have them locally. > Make sure you save your changes to Git and sync it to GitHub by doing `npx quartz sync`. This will also make sure to pull any updates you may have made from other devices so you have them locally.
@ -150,8 +144,7 @@ Before deploying to Vercel, a `vercel.json` file is required at the root of the
### Custom Domain ### Custom Domain
> [!note] > [!note] If there is something already hosted on the domain, these steps will not work without replacing the previous content. As a workaround, you could use Next.js rewrites or use the next section to create a subdomain.
> If there is something already hosted on the domain, these steps will not work without replacing the previous content. As a workaround, you could use Next.js rewrites or use the next section to create a subdomain.
1. Update the `baseUrl` in `quartz.config.js` if necessary. 1. Update the `baseUrl` in `quartz.config.js` if necessary.
2. Go to the [Domains - Dashboard](https://vercel.com/dashboard/domains) page in Vercel. 2. Go to the [Domains - Dashboard](https://vercel.com/dashboard/domains) page in Vercel.

View File

@ -26,8 +26,7 @@ This will guide you through initializing your Quartz with content. Once you've d
5. Sync your changes with [[setting up your GitHub repository|GitHub]] 5. Sync your changes with [[setting up your GitHub repository|GitHub]]
6. [[hosting|Host]] Quartz online 6. [[hosting|Host]] Quartz online
If you prefer instructions in a video format you can try following Nicole van der Hoeven's If you prefer instructions in a video format you can try following Nicole van der Hoeven's [video guide on how to set up Quartz!](https://www.youtube.com/watch?v=6s6DT1yN4dw&t=227s)
[video guide on how to set up Quartz!](https://www.youtube.com/watch?v=6s6DT1yN4dw&t=227s)
## 🔧 Features ## 🔧 Features

View File

@ -22,8 +22,7 @@ These correspond to following parts of the page:
![[quartz layout.png|800]] ![[quartz layout.png|800]]
> [!note] > [!note] There are two additional layout fields that are _not_ shown in the above diagram.
> There are two additional layout fields that are _not_ shown in the above diagram.
> >
> 1. `head` is a single component that renders the `<head>` [tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) in the HTML. This doesn't appear visually on the page and is only is responsible for metadata about the document like the tab title, scripts, and styles. > 1. `head` is a single component that renders the `<head>` [tag](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/head) in the HTML. This doesn't appear visually on the page and is only is responsible for metadata about the document like the tab title, scripts, and styles.
> 2. `header` is a set of components that are laid out horizontally and appears _before_ the `beforeBody` section. This enables you to replicate the old Quartz 3 header bar where the title, search bar, and dark mode toggle. By default, Quartz 4 doesn't place any components in the `header`. > 2. `header` is a set of components that are laid out horizontally and appears _before_ the `beforeBody` section. This enables you to replicate the old Quartz 3 header bar where the title, search bar, and dark mode toggle. By default, Quartz 4 doesn't place any components in the `header`.
@ -38,5 +37,4 @@ Most meaningful style changes like colour scheme and font can be done simply thr
You can see the base style sheet in `quartz/styles/base.scss` and write your own in `quartz/styles/custom.scss`. You can see the base style sheet in `quartz/styles/base.scss` and write your own in `quartz/styles/custom.scss`.
> [!note] > [!note] Some components may provide their own styling as well! For example, `quartz/components/Darkmode.tsx` imports styles from `quartz/components/styles/darkmode.scss`. If you'd like to customize styling for a specific component, double check the component definition to see how its styles are defined.
> Some components may provide their own styling as well! For example, `quartz/components/Darkmode.tsx` imports styles from `quartz/components/styles/darkmode.scss`. If you'd like to customize styling for a specific component, double check the component definition to see how its styles are defined.

View File

@ -20,8 +20,7 @@ git remote add upstream https://github.com/jackyzha0/quartz.git
When running `npx quartz create`, you will be prompted as to how to initialize your content folder. Here, you can choose to import or link your previous content folder and Quartz should work just as you expect it to. When running `npx quartz create`, you will be prompted as to how to initialize your content folder. Here, you can choose to import or link your previous content folder and Quartz should work just as you expect it to.
> [!note] > [!note] If the existing content folder you'd like to use is at the _same_ path on a different branch, clone the repo again somewhere at a _different_ path in order to use it.
> If the existing content folder you'd like to use is at the _same_ path on a different branch, clone the repo again somewhere at a _different_ path in order to use it.
## Key changes ## Key changes

View File

@ -24,8 +24,7 @@ The goal of digital gardening should be to tap into your networks collective
Quartz is designed first and foremost as a tool for publishing [digital gardens](https://jzhao.xyz/posts/networked-thought) to the web. To me, digital gardening is not just passive knowledge collection. Its a form of expression and sharing. Quartz is designed first and foremost as a tool for publishing [digital gardens](https://jzhao.xyz/posts/networked-thought) to the web. To me, digital gardening is not just passive knowledge collection. Its a form of expression and sharing.
> “[One] who works with the door open gets all kinds of interruptions, but [they] also occasionally gets clues as to what the world is and what might be important.” > “[One] who works with the door open gets all kinds of interruptions, but [they] also occasionally gets clues as to what the world is and what might be important.” — Richard Hamming
> — Richard Hamming
**The goal of Quartz is to make sharing your digital garden free and simple.** **The goal of Quartz is to make sharing your digital garden free and simple.**

View File

@ -25,8 +25,7 @@ The emitter supports the following aliases:
- `aliases` - `aliases`
- `alias` - `alias`
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -8,8 +8,7 @@ This plugin emits all non-Markdown static assets in your content folder (like im
Note that all static assets will then be accessible through its path on your generated site, i.e: `host.me/path/to/static.pdf` Note that all static assets will then be accessible through its path on your generated site, i.e: `host.me/path/to/static.pdf`
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -10,8 +10,7 @@ If you want to use a custom domain name like `quartz.example.com` for the site,
See [[Hosting]] for more information. See [[Hosting]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -6,8 +6,7 @@ tags:
This plugin manages and emits the static resources required for the Quartz framework. This includes CSS stylesheets and JavaScript scripts that enhance the functionality and aesthetics of the generated site. See also the `cdnCaching` option in the `theme` section of the [[configuration]]. This plugin manages and emits the static resources required for the Quartz framework. This includes CSS stylesheets and JavaScript scripts that enhance the functionality and aesthetics of the generated site. See also the `cdnCaching` option in the `theme` section of the [[configuration]].
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -8,8 +8,7 @@ This plugin emits both RSS and an XML sitemap for your site. The [[RSS Feed]] al
This plugin emits a comprehensive index of the site's content, generating additional resources such as a sitemap, an RSS feed, and a This plugin emits a comprehensive index of the site's content, generating additional resources such as a sitemap, an RSS feed, and a
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:

View File

@ -6,8 +6,7 @@ tags:
This plugin is a core component of the Quartz framework. It generates the HTML pages for each piece of Markdown content. It emits the full-page [[layout]], including headers, footers, and body content, among others. This plugin is a core component of the Quartz framework. It generates the HTML pages for each piece of Markdown content. It emits the full-page [[layout]], including headers, footers, and body content, among others.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -6,8 +6,7 @@ tags:
This plugin parses links and processes them to point to the right places. It is also needed for embedded links (like images). See [[Obsidian compatibility]] for more information. This plugin parses links and processes them to point to the right places. It is also needed for embedded links (like images). See [[Obsidian compatibility]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
@ -20,8 +19,7 @@ This plugin accepts the following configuration options:
- `lazyLoad`: If `true`, adds lazy loading to resource elements (`img`, `video`, etc.) to improve page load performance. Defaults to `false`. - `lazyLoad`: If `true`, adds lazy loading to resource elements (`img`, `video`, etc.) to improve page load performance. Defaults to `false`.
- `externalLinkIcon`: Adds an icon next to external links when `true` (default) to visually distinguishing them from internal links. - `externalLinkIcon`: Adds an icon next to external links when `true` (default) to visually distinguishing them from internal links.
> [!warning] > [!warning] Removing this plugin is _not_ recommended and will likely break the page.
> Removing this plugin is _not_ recommended and will likely break the page.
## API ## API

View File

@ -6,15 +6,13 @@ tags:
This plugin determines the created, modified, and published dates for a document using three potential data sources: frontmatter metadata, Git history, and the filesystem. See [[authoring content#Syntax]] for more information. This plugin determines the created, modified, and published dates for a document using three potential data sources: frontmatter metadata, Git history, and the filesystem. See [[authoring content#Syntax]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: 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] > [!warning] If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in `quartz.config.ts`.
> If you rely on `git` for dates, make sure `defaultDateType` is set to `modified` in `quartz.config.ts`.
> >
> Depending on how you [[hosting|host]] your Quartz, the `filesystem` dates of your local files may not match the final dates. In these cases, it may be better to use `git` or `frontmatter` to guarantee correct dates. > Depending on how you [[hosting|host]] your Quartz, the `filesystem` dates of your local files may not match the final dates. In these cases, it may be better to use `git` or `frontmatter` to guarantee correct dates.

View File

@ -8,8 +8,7 @@ This plugin generates descriptions that are used as metadata for the HTML `head`
If the frontmatter contains a `description` property, it is used (see [[authoring content#Syntax]]). Otherwise, the plugin will do its best to use the first few sentences of the content to reach the target description length. If the frontmatter contains a `description` property, it is used (see [[authoring content#Syntax]]). Otherwise, the plugin will do its best to use the first few sentences of the content to reach the target description length.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:

View File

@ -6,8 +6,7 @@ tags:
This plugin filters content based on an explicit `publish` flag in the frontmatter, allowing only content that is explicitly marked for publication to pass through. It's the opt-in version of [[RemoveDrafts]]. See [[private pages]] for more information. This plugin filters content based on an explicit `publish` flag in the frontmatter, allowing only content that is explicitly marked for publication to pass through. It's the opt-in version of [[RemoveDrafts]]. See [[private pages]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -8,8 +8,7 @@ This plugin generates index pages for folders, creating a listing page for each
Example: [[advanced/|Advanced]] Example: [[advanced/|Advanced]]
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -6,16 +6,14 @@ tags:
This plugin parses the frontmatter of the page using the [gray-matter](https://github.com/jonschlinkert/gray-matter) library. See [[authoring content#Syntax]], [[Obsidian compatibility]] and [[OxHugo compatibility]] for more information. This plugin parses the frontmatter of the page using the [gray-matter](https://github.com/jonschlinkert/gray-matter) library. See [[authoring content#Syntax]], [[Obsidian compatibility]] and [[OxHugo compatibility]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
- `delimiters`: the delimiters to use for the frontmatter. Can have one value (e.g. `"---"`) or separate values for opening and closing delimiters (e.g. `["---", "~~~"]`). Defaults to `"---"`. - `delimiters`: the delimiters to use for the frontmatter. Can have one value (e.g. `"---"`) or separate values for opening and closing delimiters (e.g. `["---", "~~~"]`). Defaults to `"---"`.
- `language`: the language to use for parsing the frontmatter. Can be `yaml` (default) or `toml`. - `language`: the language to use for parsing the frontmatter. Can be `yaml` (default) or `toml`.
> [!warning] > [!warning] This plugin must not be removed, otherwise Quartz will break.
> This plugin must not be removed, otherwise Quartz will break.
## API ## API

View File

@ -8,8 +8,7 @@ This plugin enhances Markdown processing to support GitHub Flavored Markdown (GF
In addition, this plugin adds optional features for typographic refinement (such as converting straight quotes to curly quotes, dashes to en-dashes/em-dashes, and ellipses) and automatic heading links as a symbol that appears next to the heading on hover. In addition, this plugin adds optional features for typographic refinement (such as converting straight quotes to curly quotes, dashes to en-dashes/em-dashes, and ellipses) and automatic heading links as a symbol that appears next to the heading on hover.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:

View File

@ -6,8 +6,7 @@ tags:
This plugin automatically converts single line breaks in Markdown text into hard line breaks in the HTML output. This plugin is not enabled by default as this doesn't follow the semantics of actual Markdown but you may enable it if you'd like parity with [[Obsidian compatibility|Obsidian]]. This plugin automatically converts single line breaks in Markdown text into hard line breaks in the HTML output. This plugin is not enabled by default as this doesn't follow the semantics of actual Markdown but you may enable it if you'd like parity with [[Obsidian compatibility|Obsidian]].
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -6,8 +6,7 @@ tags:
This plugin adds LaTeX support to Quartz. See [[features/Latex|Latex]] for more information. This plugin adds LaTeX support to Quartz. See [[features/Latex|Latex]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:

View File

@ -6,8 +6,7 @@ tags:
This plugin emits a 404 (Not Found) page for broken or non-existent URLs. This plugin emits a 404 (Not Found) page for broken or non-existent URLs.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -6,8 +6,7 @@ tags:
This plugin provides support for [[Obsidian compatibility]]. This plugin provides support for [[Obsidian compatibility]].
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
@ -24,8 +23,7 @@ This plugin accepts the following configuration options:
- `enableVideoEmbed`: If `true` (default), enables the embedding of video files. - `enableVideoEmbed`: If `true` (default), enables the embedding of video files.
- `enableCheckbox`: If `true`, adds support for interactive checkboxes in content. Defaults to `false`. - `enableCheckbox`: If `true`, adds support for interactive checkboxes in content. Defaults to `false`.
> [!warning] > [!warning] Don't remove this plugin if you're using [[Obsidian compatibility|Obsidian]] to author the content!
> Don't remove this plugin if you're using [[Obsidian compatibility|Obsidian]] to author the content!
## API ## API

View File

@ -6,8 +6,7 @@ tags:
This plugin provides support for [ox-hugo](https://github.com/kaushalmodi/ox-hugo) compatibility. See [[OxHugo compatibility]] for more information. This plugin provides support for [ox-hugo](https://github.com/kaushalmodi/ox-hugo) compatibility. See [[OxHugo compatibility]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
@ -17,8 +16,7 @@ This plugin accepts the following configuration options:
- `replaceFigureWithMdImg`: If `true` (default), replaces `<figure/>` with `![]()`. - `replaceFigureWithMdImg`: If `true` (default), replaces `<figure/>` with `![]()`.
- `replaceOrgLatex`: If `true` (default), converts Org-mode [[features/Latex|Latex]] fragments to Quartz-compatible LaTeX wrapped in `$` (for inline) and `$$` (for block equations). - `replaceOrgLatex`: If `true` (default), converts Org-mode [[features/Latex|Latex]] fragments to Quartz-compatible LaTeX wrapped in `$` (for inline) and `$$` (for block equations).
> [!warning] > [!warning] While you can use this together with [[ObsidianFlavoredMarkdown]], it's not recommended because it might mutate the file in unexpected ways. Use with caution.
> While you can use this together with [[ObsidianFlavoredMarkdown]], it's not recommended because it might mutate the file in unexpected ways. Use with caution.
> >
> If you use `toml` frontmatter, make sure to configure the [[Frontmatter]] plugin accordingly. See [[OxHugo compatibility]] for an example. > If you use `toml` frontmatter, make sure to configure the [[Frontmatter]] plugin accordingly. See [[OxHugo compatibility]] for an example.

View File

@ -6,8 +6,7 @@ tags:
This plugin filters out content from your vault, so that only finalized content is made available. This prevents [[private pages]] from being published. By default, it filters out all pages with `draft: true` in the frontmatter and leaves all other pages intact. This plugin filters out content from your vault, so that only finalized content is made available. This prevents [[private pages]] from being published. By default, it filters out all pages with `draft: true` in the frontmatter and leaves all other pages intact.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -6,11 +6,9 @@ tags:
This plugin emits all static resources needed by Quartz. This is used, for example, for fonts and images that need a stable position, such as banners and icons. The plugin respects the `ignorePatterns` in the global [[configuration]]. This plugin emits all static resources needed by Quartz. This is used, for example, for fonts and images that need a stable position, such as banners and icons. The plugin respects the `ignorePatterns` in the global [[configuration]].
> [!important] > [!important] This is different from [[Assets]]. The resources from the [[Static]] plugin are located under `quartz/static`, whereas [[Assets]] renders all static resources under `content` and is used for images, videos, audio, etc. that are directly referenced by your markdown content.
> This is different from [[Assets]]. The resources from the [[Static]] plugin are located under `quartz/static`, whereas [[Assets]] renders all static resources under `content` and is used for images, videos, audio, etc. that are directly referenced by your markdown content.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -6,8 +6,7 @@ tags:
This plugin is used to add syntax highlighting to code blocks in Quartz. See [[syntax highlighting]] for more information. This plugin is used to add syntax highlighting to code blocks in Quartz. See [[syntax highlighting]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:

View File

@ -6,8 +6,7 @@ tags:
This plugin generates a table of contents (TOC) for Markdown documents. See [[table of contents]] for more information. This plugin generates a table of contents (TOC) for Markdown documents. See [[table of contents]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options: This plugin accepts the following configuration options:
@ -16,8 +15,7 @@ This plugin accepts the following configuration options:
- `showByDefault`: If `true` (default), the TOC should be displayed by default. Can be overridden by frontmatter settings. - `showByDefault`: If `true` (default), the TOC should be displayed by default. Can be overridden by frontmatter settings.
- `collapseByDefault`: If `true`, the TOC will start in a collapsed state. Default is `false`. - `collapseByDefault`: If `true`, the TOC will start in a collapsed state. Default is `false`.
> [!warning] > [!warning] This plugin needs the `Component.TableOfContents` component in `quartz.layout.ts` to determine where to display the TOC. Without it, nothing will be displayed. They should always be added or removed together.
> This plugin needs the `Component.TableOfContents` component in `quartz.layout.ts` to determine where to display the TOC. Without it, nothing will be displayed. They should always be added or removed together.
## API ## API

View File

@ -6,8 +6,7 @@ tags:
This plugin emits dedicated pages for each tag used in the content. See [[folder and tag listings]] for more information. This plugin emits dedicated pages for each tag used in the content. See [[folder and tag listings]] for more information.
> [!note] > [!note] For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin has no configuration options. This plugin has no configuration options.

View File

@ -31,13 +31,11 @@ Then, you can sync the content to upload it to your repository. This is a helper
npx quartz sync --no-pull npx quartz sync --no-pull
``` ```
> [!warning]- `fatal: --[no-]autostash option is only valid with --rebase` > [!warning]- `fatal: --[no-]autostash option is only valid with --rebase` You may have an outdated version of `git`. Updating `git` should fix this issue.
> You may have an outdated version of `git`. Updating `git` should fix this issue.
In future updates, you can simply run `npx quartz sync` every time you want to push updates to your repository. In future updates, you can simply run `npx quartz sync` every time you want to push updates to your repository.
> [!hint] Flags and options > [!hint] Flags and options For full help options, you can run `npx quartz sync --help`.
> For full help options, you can run `npx quartz sync --help`.
> >
> Most of these have sensible defaults but you can override them if you have a custom setup: > Most of these have sensible defaults but you can override them if you have a custom setup:
> >

View File

@ -2,8 +2,7 @@
title: "Upgrading Quartz" title: "Upgrading Quartz"
--- ---
> [!note] > [!note] This is specifically a guide for upgrading Quartz 4 version to a more recent update. If you are coming from Quartz 3, check out the [[migrating from Quartz 3|migration guide]] for more info.
> This is specifically a guide for upgrading Quartz 4 version to a more recent update. If you are coming from Quartz 3, check out the [[migrating from Quartz 3|migration guide]] for more info.
To fetch the latest Quartz updates, simply run To fetch the latest Quartz updates, simply run
@ -13,7 +12,6 @@ npx quartz update
As Quartz uses [git](https://git-scm.com/) under the hood for versioning, updating effectively 'pulls' in the updates from the official Quartz GitHub repository. If you have local changes that might conflict with the updates, you may need to resolve these manually yourself (or, pull manually using `git pull origin upstream`). As Quartz uses [git](https://git-scm.com/) under the hood for versioning, updating effectively 'pulls' in the updates from the official Quartz GitHub repository. If you have local changes that might conflict with the updates, you may need to resolve these manually yourself (or, pull manually using `git pull origin upstream`).
> [!hint] > [!hint] Quartz will try to cache your content before updating to try and prevent merge conflicts. If you get a conflict mid-merge, you can stop the merge and then run `npx quartz restore` to restore your content from the cache.
> Quartz will try to cache your content before updating to try and prevent merge conflicts. If you get a conflict mid-merge, you can stop the merge and then run `npx quartz restore` to restore your content from the cache.
If you have the [GitHub desktop app](https://desktop.github.com/), this will automatically open to help you resolve the conflicts. Otherwise, you will need to resolve this in a text editor like VSCode. For more help on resolving conflicts manually, check out the [GitHub guide on resolving merge conflicts](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line#competing-line-change-merge-conflicts). If you have the [GitHub desktop app](https://desktop.github.com/), this will automatically open to help you resolve the conflicts. Otherwise, you will need to resolve this in a text editor like VSCode. For more help on resolving conflicts manually, check out the [GitHub guide on resolving merge conflicts](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/resolving-a-merge-conflict-using-the-command-line#competing-line-change-merge-conflicts).

4
index.d.ts vendored
View File

@ -5,8 +5,8 @@ declare module "*.scss" {
// dom custom event // dom custom event
interface CustomEventMap { interface CustomEventMap {
nav: CustomEvent<{ url: FullSlug }> nav: CustomEvent<{url: FullSlug}>
themechange: CustomEvent<{ theme: "light" | "dark" }> themechange: CustomEvent<{theme: "light" | "dark"}>
} }
declare const fetchData: Promise<ContentIndex> declare const fetchData: Promise<ContentIndex>

View File

@ -1,4 +1,4 @@
import { QuartzConfig } from "./quartz/cfg" import {QuartzConfig} from "./quartz/cfg"
import * as Plugin from "./quartz/plugins" import * as Plugin from "./quartz/plugins"
/** /**
@ -60,7 +60,7 @@ const config: QuartzConfig = {
Plugin.ObsidianFlavoredMarkdown(), Plugin.ObsidianFlavoredMarkdown(),
Plugin.GitHubFlavoredMarkdown(), Plugin.GitHubFlavoredMarkdown(),
Plugin.TableOfContents(), Plugin.TableOfContents(),
Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }), Plugin.CrawlLinks({markdownLinkResolution: "shortest"}),
Plugin.Description(), Plugin.Description(),
], ],
filters: [Plugin.RemoveDrafts()], filters: [Plugin.RemoveDrafts()],

View File

@ -1,4 +1,4 @@
import { PageLayout, SharedLayout } from "./quartz/cfg" import {PageLayout, SharedLayout} from "./quartz/cfg"
import * as Component from "./quartz/components" import * as Component from "./quartz/components"
// components shared across all pages // components shared across all pages

View File

@ -1,6 +1,6 @@
#!/usr/bin/env node #!/usr/bin/env node
import yargs from "yargs" import yargs from "yargs"
import { hideBin } from "yargs/helpers" import {hideBin} from "yargs/helpers"
import { import {
handleBuild, handleBuild,
handleCreate, handleCreate,
@ -8,8 +8,8 @@ import {
handleRestore, handleRestore,
handleSync, handleSync,
} from "./cli/handlers.js" } from "./cli/handlers.js"
import { CommonArgv, BuildArgv, CreateArgv, SyncArgv } from "./cli/args.js" import {CommonArgv, BuildArgv, CreateArgv, SyncArgv} from "./cli/args.js"
import { version } from "./cli/constants.js" import {version} from "./cli/constants.js"
yargs(hideBin(process.argv)) yargs(hideBin(process.argv))
.scriptName("quartz") .scriptName("quartz")

View File

@ -1,7 +1,7 @@
#!/usr/bin/env node #!/usr/bin/env node
import workerpool from "workerpool" import workerpool from "workerpool"
const cacheFile = "./.quartz-cache/transpiled-worker.mjs" const cacheFile = "./.quartz-cache/transpiled-worker.mjs"
const { parseFiles } = await import(cacheFile) const {parseFiles} = await import(cacheFile)
workerpool.worker({ workerpool.worker({
parseFiles, parseFiles,
}) })

View File

@ -1,24 +1,24 @@
import sourceMapSupport from "source-map-support" import sourceMapSupport from "source-map-support"
sourceMapSupport.install(options) sourceMapSupport.install(options)
import path from "path" import path from "path"
import { PerfTimer } from "./util/perf" import {PerfTimer} from "./util/perf"
import { rimraf } from "rimraf" import {rimraf} from "rimraf"
import { GlobbyFilterFunction, isGitIgnored } from "globby" import {GlobbyFilterFunction, isGitIgnored} from "globby"
import chalk from "chalk" import chalk from "chalk"
import { parseMarkdown } from "./processors/parse" import {parseMarkdown} from "./processors/parse"
import { filterContent } from "./processors/filter" import {filterContent} from "./processors/filter"
import { emitContent } from "./processors/emit" import {emitContent} from "./processors/emit"
import cfg from "../quartz.config" import cfg from "../quartz.config"
import { FilePath, FullSlug, joinSegments, slugifyFilePath } from "./util/path" import {FilePath, FullSlug, joinSegments, slugifyFilePath} from "./util/path"
import chokidar from "chokidar" import chokidar from "chokidar"
import { ProcessedContent } from "./plugins/vfile" import {ProcessedContent} from "./plugins/vfile"
import { Argv, BuildCtx } from "./util/ctx" import {Argv, BuildCtx} from "./util/ctx"
import { glob, toPosixPath } from "./util/glob" import {glob, toPosixPath} from "./util/glob"
import { trace } from "./util/trace" import {trace} from "./util/trace"
import { options } from "./util/sourcemap" import {options} from "./util/sourcemap"
import { Mutex } from "async-mutex" import {Mutex} from "async-mutex"
import DepGraph from "./depgraph" import DepGraph from "./depgraph"
import { getStaticResourcesFromPlugins } from "./plugins" import {getStaticResourcesFromPlugins} from "./plugins"
type Dependencies = Record<string, DepGraph<FilePath> | null> type Dependencies = Record<string, DepGraph<FilePath> | null>
@ -60,7 +60,7 @@ async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) {
const release = await mut.acquire() const release = await mut.acquire()
perf.addEvent("clean") perf.addEvent("clean")
await rimraf(path.join(output, "*"), { glob: true }) await rimraf(path.join(output, "*"), {glob: true})
console.log( console.log(
`Cleaned output directory \`${output}\` in ${perf.timeSince("clean")}`, `Cleaned output directory \`${output}\` in ${perf.timeSince("clean")}`,
) )
@ -101,9 +101,7 @@ async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) {
await emitContent(ctx, filteredContent) await emitContent(ctx, filteredContent)
console.log( console.log(
chalk.green( chalk.green(`Done processing ${fps.length} files in ${perf.timeSince()}`),
`Done processing ${fps.length} files in ${perf.timeSince()}`,
),
) )
release() release()
@ -120,7 +118,7 @@ async function startServing(
clientRefresh: () => void, clientRefresh: () => void,
dependencies: Dependencies, // emitter name: dep graph dependencies: Dependencies, // emitter name: dep graph
) { ) {
const { argv } = ctx const {argv} = ctx
// cache file parse results // cache file parse results
const contentMap = new Map<FilePath, ProcessedContent>() const contentMap = new Map<FilePath, ProcessedContent>()
@ -171,8 +169,8 @@ async function partialRebuildFromEntrypoint(
clientRefresh: () => void, clientRefresh: () => void,
buildData: BuildData, // note: this function mutates buildData buildData: BuildData, // note: this function mutates buildData
) { ) {
const { ctx, ignored, dependencies, contentMap, mut, toRemove } = buildData const {ctx, ignored, dependencies, contentMap, mut, toRemove} = buildData
const { argv, cfg } = ctx const {argv, cfg} = ctx
// don't do anything for gitignored files // don't do anything for gitignored files
if (ignored(filepath)) { if (ignored(filepath)) {
@ -303,9 +301,7 @@ async function partialRebuildFromEntrypoint(
// //
// if a.md changes, we need to re-emit contentIndex.json, // if a.md changes, we need to re-emit contentIndex.json,
// and supply [a.md, b.md] to the emitter // and supply [a.md, b.md] to the emitter
const upstreams = [ const upstreams = [...depGraph.getLeafNodeAncestors(fp)] as FilePath[]
...depGraph.getLeafNodeAncestors(fp),
] as FilePath[]
const upstreamContent = upstreams const upstreamContent = upstreams
// filter out non-markdown files // filter out non-markdown files
@ -378,7 +374,7 @@ async function rebuildFromEntrypoint(
trackedAssets, trackedAssets,
} = buildData } = buildData
const { argv } = ctx const {argv} = ctx
// don't do anything for gitignored files // don't do anything for gitignored files
if (ignored(fp)) { if (ignored(fp)) {
@ -424,9 +420,7 @@ async function rebuildFromEntrypoint(
] ]
.filter((fp) => !toRemove.has(fp)) .filter((fp) => !toRemove.has(fp))
.map((fp) => .map((fp) =>
slugifyFilePath( slugifyFilePath(path.posix.relative(argv.directory, fp) as FilePath),
path.posix.relative(argv.directory, fp) as FilePath,
),
) )
ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])] ctx.allSlugs = [...new Set([...initialSlugs, ...trackedSlugs])]
@ -445,14 +439,12 @@ async function rebuildFromEntrypoint(
// TODO: we can probably traverse the link graph to figure out what's safe to delete here // TODO: we can probably traverse the link graph to figure out what's safe to delete here
// instead of just deleting everything // instead of just deleting everything
await rimraf(path.join(argv.output, ".*"), { glob: true }) await rimraf(path.join(argv.output, ".*"), {glob: true})
await emitContent(ctx, filteredContent) await emitContent(ctx, filteredContent)
console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`)) console.log(chalk.green(`Done rebuilding in ${perf.timeSince()}`))
} catch (err) { } catch (err) {
console.log( console.log(
chalk.yellow( chalk.yellow(`Rebuild failed. Waiting on a change to fix the error...`),
`Rebuild failed. Waiting on a change to fix the error...`,
),
) )
if (argv.verbose) { if (argv.verbose) {
console.log(chalk.red(err)) console.log(chalk.red(err))

View File

@ -1,8 +1,8 @@
import { ValidDateType } from "./components/Date" import {ValidDateType} from "./components/Date"
import { QuartzComponent } from "./components/types" import {QuartzComponent} from "./components/types"
import { ValidLocale } from "./i18n" import {ValidLocale} from "./i18n"
import { PluginTypes } from "./plugins/types" import {PluginTypes} from "./plugins/types"
import { Theme } from "./util/theme" import {Theme} from "./util/theme"
export type Analytics = export type Analytics =
| null | null

View File

@ -1,5 +1,5 @@
import path from "path" import path from "path"
import { readFileSync } from "fs" import {readFileSync} from "fs"
/** /**
* All constants relating to helpers or handlers * All constants relating to helpers or handlers
@ -11,5 +11,5 @@ export const cwd = process.cwd()
export const cacheDir = path.join(cwd, ".quartz-cache") export const cacheDir = path.join(cwd, ".quartz-cache")
export const cacheFile = "./quartz/.quartz-cache/transpiled-build.mjs" export const cacheFile = "./quartz/.quartz-cache/transpiled-build.mjs"
export const fp = "./quartz/build.ts" export const fp = "./quartz/build.ts"
export const { version } = JSON.parse(readFileSync("./package.json").toString()) export const {version} = JSON.parse(readFileSync("./package.json").toString())
export const contentCacheFolder = path.join(cacheDir, "content-cache") export const contentCacheFolder = path.join(cacheDir, "content-cache")

View File

@ -1,20 +1,20 @@
import { promises } from "fs" import {promises} from "fs"
import path from "path" import path from "path"
import esbuild from "esbuild" import esbuild from "esbuild"
import chalk from "chalk" import chalk from "chalk"
import { sassPlugin } from "esbuild-sass-plugin" import {sassPlugin} from "esbuild-sass-plugin"
import fs from "fs" import fs from "fs"
import { intro, outro, select, text } from "@clack/prompts" import {intro, outro, select, text} from "@clack/prompts"
import { rimraf } from "rimraf" import {rimraf} from "rimraf"
import chokidar from "chokidar" import chokidar from "chokidar"
import prettyBytes from "pretty-bytes" import prettyBytes from "pretty-bytes"
import { execSync, spawnSync } from "child_process" import {execSync, spawnSync} from "child_process"
import http from "http" import http from "http"
import serveHandler from "serve-handler" import serveHandler from "serve-handler"
import { WebSocketServer } from "ws" import {WebSocketServer} from "ws"
import { randomUUID } from "crypto" import {randomUUID} from "crypto"
import { Mutex } from "async-mutex" import {Mutex} from "async-mutex"
import { CreateArgv } from "./args.js" import {CreateArgv} from "./args.js"
import { import {
exitIfCancel, exitIfCancel,
escapePath, escapePath,
@ -92,7 +92,7 @@ export async function handleCreate(argv) {
await select({ await select({
message: `Choose how to initialize the content in \`${contentFolder}\``, message: `Choose how to initialize the content in \`${contentFolder}\``,
options: [ options: [
{ value: "new", label: "Empty Quartz" }, {value: "new", label: "Empty Quartz"},
{ {
value: "copy", value: "copy",
label: "Copy an existing folder", label: "Copy an existing folder",
@ -129,8 +129,7 @@ export async function handleCreate(argv) {
originalFolder = escapePath( originalFolder = escapePath(
exitIfCancel( exitIfCancel(
await text({ await text({
message: message: "Enter the full path to existing content folder",
"Enter the full path to existing content folder",
placeholder: placeholder:
"On most terminal emulators, you can drag and drop a folder into the window and it will paste the full path", "On most terminal emulators, you can drag and drop a folder into the window and it will paste the full path",
validate(fp) { validate(fp) {
@ -207,7 +206,7 @@ See the [documentation](https://quartz.jzhao.xyz) for how to get started.
// setup remote // setup remote
execSync( execSync(
`git remote show upstream || git remote add upstream https://github.com/jackyzha0/quartz.git`, `git remote show upstream || git remote add upstream https://github.com/jackyzha0/quartz.git`,
{ stdio: "ignore" }, {stdio: "ignore"},
) )
outro(`You're all set! Not sure what to do next? Try: outro(`You're all set! Not sure what to do next? Try:
@ -246,22 +245,14 @@ export async function handleBuild(argv) {
{ {
name: "inline-script-loader", name: "inline-script-loader",
setup(build) { setup(build) {
build.onLoad( build.onLoad({filter: /\.inline\.(ts|js)$/}, async (args) => {
{ filter: /\.inline\.(ts|js)$/ }, let text = await promises.readFile(args.path, "utf8")
async (args) => {
let text = await promises.readFile(
args.path,
"utf8",
)
// remove default exports that we manually inserted // remove default exports that we manually inserted
text = text.replace("export default", "") text = text.replace("export default", "")
text = text.replace("export", "") text = text.replace("export", "")
const sourcefile = path.relative( const sourcefile = path.relative(path.resolve("."), args.path)
path.resolve("."),
args.path,
)
const resolveDir = path.dirname(sourcefile) const resolveDir = path.dirname(sourcefile)
const transpiled = await esbuild.build({ const transpiled = await esbuild.build({
stdin: { stdin: {
@ -281,8 +272,7 @@ export async function handleBuild(argv) {
contents: rawMod, contents: rawMod,
loader: "text", loader: "text",
} }
}, })
)
}, },
}, },
], ],
@ -303,9 +293,7 @@ export async function handleBuild(argv) {
if (cleanupBuild) { if (cleanupBuild) {
await cleanupBuild() await cleanupBuild()
console.log( console.log(
chalk.yellow( chalk.yellow("Detected a source code change, doing a hard rebuild..."),
"Detected a source code change, doing a hard rebuild...",
),
) )
} }
@ -326,14 +314,12 @@ export async function handleBuild(argv) {
meta.bytes, meta.bytes,
)})`, )})`,
) )
console.log( console.log(await esbuild.analyzeMetafile(result.metafile, {color: true}))
await esbuild.analyzeMetafile(result.metafile, { color: true }),
)
} }
// bypass module cache // bypass module cache
// https://github.com/nodejs/modules/issues/307 // https://github.com/nodejs/modules/issues/307
const { default: buildQuartz } = await import( const {default: buildQuartz} = await import(
`../../${cacheFile}?update=${randomUUID()}` `../../${cacheFile}?update=${randomUUID()}`
) )
// ^ this import is relative, so base "cacheFile" path can't be used // ^ this import is relative, so base "cacheFile" path can't be used
@ -375,9 +361,7 @@ export async function handleBuild(argv) {
headers: [ headers: [
{ {
source: "**/*.*", source: "**/*.*",
headers: [ headers: [{key: "Content-Disposition", value: "inline"}],
{ key: "Content-Disposition", value: "inline" },
],
}, },
], ],
}) })
@ -386,9 +370,7 @@ export async function handleBuild(argv) {
status >= 200 && status < 300 status >= 200 && status < 300
? chalk.green(`[${status}]`) ? chalk.green(`[${status}]`)
: chalk.red(`[${status}]`) : chalk.red(`[${status}]`)
console.log( console.log(statusString + chalk.grey(` ${argv.baseDir}${req.url}`))
statusString + chalk.grey(` ${argv.baseDir}${req.url}`),
)
release() release()
} }
@ -446,7 +428,7 @@ export async function handleBuild(argv) {
return serve() return serve()
}) })
server.listen(argv.port) server.listen(argv.port)
const wss = new WebSocketServer({ port: argv.wsPort }) const wss = new WebSocketServer({port: argv.wsPort})
wss.on("connection", (ws) => connections.push(ws)) wss.on("connection", (ws) => connections.push(ws))
console.log( console.log(
chalk.cyan( chalk.cyan(
@ -493,7 +475,7 @@ export async function handleUpdate(argv) {
await popContentFolder(contentFolder) await popContentFolder(contentFolder)
console.log("Ensuring dependencies are up to date") console.log("Ensuring dependencies are up to date")
const res = spawnSync("npm", ["i"], { stdio: "inherit" }) const res = spawnSync("npm", ["i"], {stdio: "inherit"})
if (res.status === 0) { if (res.status === 0) {
console.log(chalk.green("Done!")) console.log(chalk.green("Done!"))
} else { } else {
@ -546,8 +528,8 @@ export async function handleSync(argv) {
timeStyle: "short", timeStyle: "short",
}) })
const commitMessage = argv.message ?? `Quartz sync: ${currentTimestamp}` const commitMessage = argv.message ?? `Quartz sync: ${currentTimestamp}`
spawnSync("git", ["add", "."], { stdio: "inherit" }) spawnSync("git", ["add", "."], {stdio: "inherit"})
spawnSync("git", ["commit", "-m", commitMessage], { stdio: "inherit" }) spawnSync("git", ["commit", "-m", commitMessage], {stdio: "inherit"})
if (contentStat.isSymbolicLink()) { if (contentStat.isSymbolicLink()) {
// put symlink back // put symlink back
@ -564,9 +546,7 @@ export async function handleSync(argv) {
try { try {
gitPull(ORIGIN_NAME, QUARTZ_SOURCE_BRANCH) gitPull(ORIGIN_NAME, QUARTZ_SOURCE_BRANCH)
} catch { } catch {
console.log( console.log(chalk.red("An error occurred above while pulling updates."))
chalk.red("An error occurred above while pulling updates."),
)
await popContentFolder(contentFolder) await popContentFolder(contentFolder)
return return
} }

View File

@ -1,7 +1,7 @@
import { isCancel, outro } from "@clack/prompts" import {isCancel, outro} from "@clack/prompts"
import chalk from "chalk" import chalk from "chalk"
import { contentCacheFolder } from "./constants.js" import {contentCacheFolder} from "./constants.js"
import { spawnSync } from "child_process" import {spawnSync} from "child_process"
import fs from "fs" import fs from "fs"
export function escapePath(fp) { export function escapePath(fp) {
@ -22,14 +22,14 @@ export function exitIfCancel(val) {
} }
export async function stashContentFolder(contentFolder) { export async function stashContentFolder(contentFolder) {
await fs.promises.rm(contentCacheFolder, { force: true, recursive: true }) await fs.promises.rm(contentCacheFolder, {force: true, recursive: true})
await fs.promises.cp(contentFolder, contentCacheFolder, { await fs.promises.cp(contentFolder, contentCacheFolder, {
force: true, force: true,
recursive: true, recursive: true,
verbatimSymlinks: true, verbatimSymlinks: true,
preserveTimestamps: true, preserveTimestamps: true,
}) })
await fs.promises.rm(contentFolder, { force: true, recursive: true }) await fs.promises.rm(contentFolder, {force: true, recursive: true})
} }
export function gitPull(origin, branch) { export function gitPull(origin, branch) {
@ -53,12 +53,12 @@ export function gitPull(origin, branch) {
} }
export async function popContentFolder(contentFolder) { export async function popContentFolder(contentFolder) {
await fs.promises.rm(contentFolder, { force: true, recursive: true }) await fs.promises.rm(contentFolder, {force: true, recursive: true})
await fs.promises.cp(contentCacheFolder, contentFolder, { await fs.promises.cp(contentCacheFolder, contentFolder, {
force: true, force: true,
recursive: true, recursive: true,
verbatimSymlinks: true, verbatimSymlinks: true,
preserveTimestamps: true, preserveTimestamps: true,
}) })
await fs.promises.rm(contentCacheFolder, { force: true, recursive: true }) await fs.promises.rm(contentCacheFolder, {force: true, recursive: true})
} }

View File

@ -3,7 +3,7 @@ import {
QuartzComponentConstructor, QuartzComponentConstructor,
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
const ArticleTitle: QuartzComponent = ({ const ArticleTitle: QuartzComponent = ({
fileData, fileData,
@ -11,9 +11,7 @@ const ArticleTitle: QuartzComponent = ({
}: QuartzComponentProps) => { }: QuartzComponentProps) => {
const title = fileData.frontmatter?.title const title = fileData.frontmatter?.title
if (title) { if (title) {
return ( return <h1 class={classNames(displayClass, "article-title")}>{title}</h1>
<h1 class={classNames(displayClass, "article-title")}>{title}</h1>
)
} else { } else {
return null return null
} }

View File

@ -4,9 +4,9 @@ import {
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import style from "./styles/backlinks.scss" import style from "./styles/backlinks.scss"
import { resolveRelative, simplifySlug } from "../util/path" import {resolveRelative, simplifySlug} from "../util/path"
import { i18n } from "../i18n" import {i18n} from "../i18n"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
const Backlinks: QuartzComponent = ({ const Backlinks: QuartzComponent = ({
fileData, fileData,
@ -25,16 +25,13 @@ const Backlinks: QuartzComponent = ({
<li> <li>
<a <a
href={resolveRelative(fileData.slug!, f.slug!)} href={resolveRelative(fileData.slug!, f.slug!)}
class="internal" class="internal">
>
{f.frontmatter?.title} {f.frontmatter?.title}
</a> </a>
</li> </li>
)) ))
) : ( ) : (
<li> <li>{i18n(cfg.locale).components.backlinks.noBacklinksFound}</li>
{i18n(cfg.locale).components.backlinks.noBacklinksFound}
</li>
)} )}
</ul> </ul>
</div> </div>

View File

@ -7,7 +7,7 @@ import {
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
const Body: QuartzComponent = ({ children }: QuartzComponentProps) => { const Body: QuartzComponent = ({children}: QuartzComponentProps) => {
return <div id="quartz-body">{children}</div> return <div id="quartz-body">{children}</div>
} }

View File

@ -4,14 +4,9 @@ import {
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import breadcrumbsStyle from "./styles/breadcrumbs.scss" import breadcrumbsStyle from "./styles/breadcrumbs.scss"
import { import {FullSlug, SimpleSlug, joinSegments, resolveRelative} from "../util/path"
FullSlug, import {QuartzPluginData} from "../plugins/vfile"
SimpleSlug, import {classNames} from "../util/lang"
joinSegments,
resolveRelative,
} from "../util/path"
import { QuartzPluginData } from "../plugins/vfile"
import { classNames } from "../util/lang"
type CrumbData = { type CrumbData = {
displayName: string displayName: string
@ -62,7 +57,7 @@ function formatCrumb(
export default ((opts?: Partial<BreadcrumbOptions>) => { export default ((opts?: Partial<BreadcrumbOptions>) => {
// Merge options with defaults // Merge options with defaults
const options: BreadcrumbOptions = { ...defaultOptions, ...opts } const options: BreadcrumbOptions = {...defaultOptions, ...opts}
// computed index of folder name to its associated file data // computed index of folder name to its associated file data
let folderIndex: Map<string, QuartzPluginData> | undefined let folderIndex: Map<string, QuartzPluginData> | undefined
@ -127,8 +122,7 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
const crumb = formatCrumb( const crumb = formatCrumb(
curPathSegment, curPathSegment,
fileData.slug!, fileData.slug!,
(currentPath + (currentPath + (includeTrailingSlash ? "/" : "")) as SimpleSlug,
(includeTrailingSlash ? "/" : "")) as SimpleSlug,
) )
crumbs.push(crumb) crumbs.push(crumb)
} }
@ -145,8 +139,7 @@ export default ((opts?: Partial<BreadcrumbOptions>) => {
return ( return (
<nav <nav
class={classNames(displayClass, "breadcrumb-container")} class={classNames(displayClass, "breadcrumb-container")}
aria-label="breadcrumbs" aria-label="breadcrumbs">
>
{crumbs.map((crumb, index) => ( {crumbs.map((crumb, index) => (
<div class="breadcrumb-element"> <div class="breadcrumb-element">
<a href={crumb.path}>{crumb.displayName}</a> <a href={crumb.path}>{crumb.displayName}</a>

View File

@ -1,9 +1,9 @@
import { formatDate, getDate } from "./Date" import {formatDate, getDate} from "./Date"
import { QuartzComponentConstructor, QuartzComponentProps } from "./types" 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 {JSX} from "preact"
import style from "./styles/contentMeta.scss" import style from "./styles/contentMeta.scss"
interface ContentMetaOptions { interface ContentMetaOptions {
@ -21,7 +21,7 @@ const defaultOptions: ContentMetaOptions = {
export default ((opts?: Partial<ContentMetaOptions>) => { export default ((opts?: Partial<ContentMetaOptions>) => {
// Merge options with defaults // Merge options with defaults
const options: ContentMetaOptions = { ...defaultOptions, ...opts } const options: ContentMetaOptions = {...defaultOptions, ...opts}
function ContentMetadata({ function ContentMetadata({
cfg, cfg,
@ -39,7 +39,7 @@ export default ((opts?: Partial<ContentMetaOptions>) => {
// Display reading time if enabled // Display reading time if enabled
if (options.showReadingTime) { if (options.showReadingTime) {
const { minutes, words: _words } = readingTime(text) const {minutes, words: _words} = readingTime(text)
const displayedTime = i18n( const displayedTime = i18n(
cfg.locale, cfg.locale,
).components.contentMeta.readingTime({ ).components.contentMeta.readingTime({
@ -48,15 +48,12 @@ export default ((opts?: Partial<ContentMetaOptions>) => {
segments.push(displayedTime) segments.push(displayedTime)
} }
const segmentsElements = segments.map((segment) => ( const segmentsElements = segments.map((segment) => <span>{segment}</span>)
<span>{segment}</span>
))
return ( return (
<p <p
show-comma={options.showComma} show-comma={options.showComma}
class={classNames(displayClass, "content-meta")} class={classNames(displayClass, "content-meta")}>
>
{segmentsElements} {segmentsElements}
</p> </p>
) )

View File

@ -8,8 +8,8 @@ import {
QuartzComponentConstructor, QuartzComponentConstructor,
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import { i18n } from "../i18n" import {i18n} from "../i18n"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
const Darkmode: QuartzComponent = ({ const Darkmode: QuartzComponent = ({
displayClass, displayClass,
@ -33,11 +33,8 @@ const Darkmode: QuartzComponent = ({
y="0px" y="0px"
viewBox="0 0 35 35" viewBox="0 0 35 35"
style="enable-background:new 0 0 35 35" style="enable-background:new 0 0 35 35"
xmlSpace="preserve" xmlSpace="preserve">
> <title>{i18n(cfg.locale).components.themeToggle.darkMode}</title>
<title>
{i18n(cfg.locale).components.themeToggle.darkMode}
</title>
<path d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5 S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5 C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6 C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9 c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44 l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5 c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06 L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2 C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29 c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7 C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5 c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z"></path> <path d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5 S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5 C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6 C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9 c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44 l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5 c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06 L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2 C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29 c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7 C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5 c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z"></path>
</svg> </svg>
</label> </label>
@ -51,11 +48,8 @@ const Darkmode: QuartzComponent = ({
y="0px" y="0px"
viewBox="0 0 100 100" viewBox="0 0 100 100"
style="enable-background:new 0 0 100 100" style="enable-background:new 0 0 100 100"
xmlSpace="preserve" xmlSpace="preserve">
> <title>{i18n(cfg.locale).components.themeToggle.lightMode}</title>
<title>
{i18n(cfg.locale).components.themeToggle.lightMode}
</title>
<path d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571 C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23 c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9.447,9.447-14.65,22.008-14.65,35.369 c0,13.36,5.203,25.921,14.65,35.368s22.008,14.65,35.368,14.65c13.361,0,25.921-5.203,35.369-14.65 c3.872-3.871,7.064-8.328,9.491-13.246C97.826,68.608,97.611,67.309,96.76,66.458z"></path> <path d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571 C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23 c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9.447,9.447-14.65,22.008-14.65,35.369 c0,13.36,5.203,25.921,14.65,35.368s22.008,14.65,35.368,14.65c13.361,0,25.921-5.203,35.369-14.65 c3.872-3.871,7.064-8.328,9.491-13.246C97.826,68.608,97.611,67.309,96.76,66.458z"></path>
</svg> </svg>
</label> </label>

View File

@ -1,6 +1,6 @@
import { GlobalConfiguration } from "../cfg" import {GlobalConfiguration} from "../cfg"
import { ValidLocale } from "../i18n" import {ValidLocale} from "../i18n"
import { QuartzPluginData } from "../plugins/vfile" import {QuartzPluginData} from "../plugins/vfile"
interface Props { interface Props {
date: Date date: Date
@ -29,6 +29,6 @@ export function formatDate(d: Date, locale: ValidLocale = "en-US"): string {
}) })
} }
export function Date({ date, locale }: Props) { export function Date({date, locale}: Props) {
return <>{formatDate(date, locale)}</> return <>{formatDate(date, locale)}</>
} }

View File

@ -7,10 +7,10 @@ import explorerStyle from "./styles/explorer.scss"
// @ts-ignore // @ts-ignore
import script from "./scripts/explorer.inline" import script from "./scripts/explorer.inline"
import { ExplorerNode, FileNode, Options } from "./ExplorerNode" import {ExplorerNode, FileNode, Options} from "./ExplorerNode"
import { QuartzPluginData } from "../plugins/vfile" import {QuartzPluginData} from "../plugins/vfile"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
import { i18n } from "../i18n" import {i18n} from "../i18n"
// Options interface defined in `ExplorerNode` to avoid circular dependency // Options interface defined in `ExplorerNode` to avoid circular dependency
const defaultOptions = { const defaultOptions = {
@ -43,7 +43,7 @@ const defaultOptions = {
export default ((userOpts?: Partial<Options>) => { export default ((userOpts?: Partial<Options>) => {
// Parse config // Parse config
const opts: Options = { ...defaultOptions, ...userOpts } const opts: Options = {...defaultOptions, ...userOpts}
// memoized // memoized
let fileTree: FileNode let fileTree: FileNode
@ -96,12 +96,8 @@ export default ((userOpts?: Partial<Options>) => {
data-behavior={opts.folderClickBehavior} data-behavior={opts.folderClickBehavior}
data-collapsed={opts.folderDefaultState} data-collapsed={opts.folderDefaultState}
data-savestate={opts.useSavedState} data-savestate={opts.useSavedState}
data-tree={jsonTree} data-tree={jsonTree}>
> <h1>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h1>
<h1>
{opts.title ??
i18n(cfg.locale).components.explorer.title}
</h1>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
width="14" width="14"
@ -112,18 +108,13 @@ export default ((userOpts?: Partial<Options>) => {
stroke-width="2" stroke-width="2"
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
class="fold" class="fold">
>
<polyline points="6 9 12 15 18 9"></polyline> <polyline points="6 9 12 15 18 9"></polyline>
</svg> </svg>
</button> </button>
<div id="explorer-content"> <div id="explorer-content">
<ul class="overflow" id="explorer-ul"> <ul class="overflow" id="explorer-ul">
<ExplorerNode <ExplorerNode node={fileTree} opts={opts} fileData={fileData} />
node={fileTree}
opts={opts}
fileData={fileData}
/>
<li id="explorer-end" /> <li id="explorer-end" />
</ul> </ul>
</div> </div>

View File

@ -1,5 +1,5 @@
// @ts-ignore // @ts-ignore
import { QuartzPluginData } from "../plugins/vfile" import {QuartzPluginData} from "../plugins/vfile"
import { import {
joinSegments, joinSegments,
resolveRelative, resolveRelative,
@ -59,8 +59,7 @@ export class FileNode {
) { ) {
this.children = [] this.children = []
this.name = slugSegment this.name = slugSegment
this.displayName = this.displayName = displayName ?? file?.frontmatter?.title ?? slugSegment
displayName ?? file?.frontmatter?.title ?? slugSegment
this.file = file ? clone(file) : null this.file = file ? clone(file) : null
this.depth = depth ?? 0 this.depth = depth ?? 0
} }
@ -83,12 +82,7 @@ export class FileNode {
} else { } else {
// direct child // direct child
this.children.push( this.children.push(
new FileNode( new FileNode(nextSegment, undefined, fileData.file, this.depth + 1),
nextSegment,
undefined,
fileData.file,
this.depth + 1,
),
) )
} }
@ -115,7 +109,7 @@ export class FileNode {
// Add new file to tree // Add new file to tree
add(file: QuartzPluginData) { add(file: QuartzPluginData) {
this.insert({ file: file, path: simplifySlug(file.slug!).split("/") }) this.insert({file: file, path: simplifySlug(file.slug!).split("/")})
} }
/** /**
@ -149,7 +143,7 @@ export class FileNode {
if (!node.file) { if (!node.file) {
const folderPath = joinSegments(currentPath, node.name) const folderPath = joinSegments(currentPath, node.name)
if (folderPath !== "") { if (folderPath !== "") {
folderPaths.push({ path: folderPath, collapsed }) folderPaths.push({path: folderPath, collapsed})
} }
node.children.forEach((child) => traverse(child, folderPath)) node.children.forEach((child) => traverse(child, folderPath))
@ -201,8 +195,7 @@ export function ExplorerNode({
<li key={node.file.slug}> <li key={node.file.slug}>
<a <a
href={resolveRelative(fileData.slug!, node.file.slug!)} href={resolveRelative(fileData.slug!, node.file.slug!)}
data-for={node.file.slug} data-for={node.file.slug}>
>
{node.displayName} {node.displayName}
</a> </a>
</li> </li>
@ -222,8 +215,7 @@ export function ExplorerNode({
stroke-width="2" stroke-width="2"
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
class="folder-icon" class="folder-icon">
>
<polyline points="6 9 12 15 18 9"></polyline> <polyline points="6 9 12 15 18 9"></polyline>
</svg> </svg>
{/* render <a> tag if folderBehavior is "link", otherwise render <button> with collapse click event */} {/* render <a> tag if folderBehavior is "link", otherwise render <button> with collapse click event */}
@ -235,15 +227,12 @@ export function ExplorerNode({
folderPath as SimpleSlug, folderPath as SimpleSlug,
)} )}
data-for={node.name} data-for={node.name}
class="folder-title" class="folder-title">
>
{node.displayName} {node.displayName}
</a> </a>
) : ( ) : (
<button class="folder-button"> <button class="folder-button">
<span class="folder-title"> <span class="folder-title">{node.displayName}</span>
{node.displayName}
</span>
</button> </button>
)} )}
</div> </div>
@ -251,16 +240,14 @@ export function ExplorerNode({
)} )}
{/* Recursively render children of folder */} {/* Recursively render children of folder */}
<div <div
class={`folder-outer ${node.depth === 0 || isDefaultOpen ? "open" : ""}`} class={`folder-outer ${node.depth === 0 || isDefaultOpen ? "open" : ""}`}>
>
<ul <ul
// Inline style for left folder paddings // Inline style for left folder paddings
style={{ style={{
paddingLeft: node.name !== "" ? "1.4rem" : "0", paddingLeft: node.name !== "" ? "1.4rem" : "0",
}} }}
class="content" class="content"
data-folderul={folderPath} data-folderul={folderPath}>
>
{node.children.map((childNode, i) => ( {node.children.map((childNode, i) => (
<ExplorerNode <ExplorerNode
node={childNode} node={childNode}

View File

@ -4,8 +4,8 @@ import {
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import style from "./styles/footer.scss" import style from "./styles/footer.scss"
import { version } from "../../package.json" import {version} from "../../package.json"
import { i18n } from "../i18n" import {i18n} from "../i18n"
interface Options { interface Options {
links: Record<string, string> links: Record<string, string>

View File

@ -6,8 +6,8 @@ import {
// @ts-ignore // @ts-ignore
import script from "./scripts/graph.inline" import script from "./scripts/graph.inline"
import style from "./styles/graph.scss" import style from "./styles/graph.scss"
import { i18n } from "../i18n" import {i18n} from "../i18n"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
export interface D3Config { export interface D3Config {
drag: boolean drag: boolean
@ -65,7 +65,7 @@ export default ((opts?: GraphOptions) => {
displayClass, displayClass,
cfg, cfg,
}: QuartzComponentProps) => { }: QuartzComponentProps) => {
const localGraph = { ...defaultOptions.localGraph, ...opts?.localGraph } const localGraph = {...defaultOptions.localGraph, ...opts?.localGraph}
const globalGraph = { const globalGraph = {
...defaultOptions.globalGraph, ...defaultOptions.globalGraph,
...opts?.globalGraph, ...opts?.globalGraph,
@ -74,10 +74,7 @@ export default ((opts?: GraphOptions) => {
<div class={classNames(displayClass, "graph")}> <div class={classNames(displayClass, "graph")}>
<h2>{i18n(cfg.locale).components.graph.title}</h2> <h2>{i18n(cfg.locale).components.graph.title}</h2>
<div class="graph-outer"> <div class="graph-outer">
<div <div id="graph-container" data-cfg={JSON.stringify(localGraph)}></div>
id="graph-container"
data-cfg={JSON.stringify(localGraph)}
></div>
<svg <svg
version="1.1" version="1.1"
id="global-graph-icon" id="global-graph-icon"
@ -87,8 +84,7 @@ export default ((opts?: GraphOptions) => {
y="0px" y="0px"
viewBox="0 0 55 55" viewBox="0 0 55 55"
fill="currentColor" fill="currentColor"
xmlSpace="preserve" xmlSpace="preserve">
>
<path <path
d="M49,0c-3.309,0-6,2.691-6,6c0,1.035,0.263,2.009,0.726,2.86l-9.829,9.829C32.542,17.634,30.846,17,29,17 d="M49,0c-3.309,0-6,2.691-6,6c0,1.035,0.263,2.009,0.726,2.86l-9.829,9.829C32.542,17.634,30.846,17,29,17
s-3.542,0.634-4.898,1.688l-7.669-7.669C16.785,10.424,17,9.74,17,9c0-2.206-1.794-4-4-4S9,6.794,9,9s1.794,4,4,4 s-3.542,0.634-4.898,1.688l-7.669-7.669C16.785,10.424,17,9.74,17,9c0-2.206-1.794-4-4-4S9,6.794,9,9s1.794,4,4,4
@ -107,8 +103,7 @@ export default ((opts?: GraphOptions) => {
<div id="global-graph-outer"> <div id="global-graph-outer">
<div <div
id="global-graph-container" id="global-graph-container"
data-cfg={JSON.stringify(globalGraph)} data-cfg={JSON.stringify(globalGraph)}></div>
></div>
</div> </div>
</div> </div>
) )

View File

@ -1,7 +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 {googleFontHref} from "../util/theme"
import { import {
QuartzComponent, QuartzComponent,
QuartzComponentConstructor, QuartzComponentConstructor,
@ -15,17 +15,15 @@ export default (() => {
externalResources, externalResources,
}: QuartzComponentProps) => { }: QuartzComponentProps) => {
const title = const title =
fileData.frontmatter?.title ?? fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title
i18n(cfg.locale).propertyDefaults.title
const description = const description =
fileData.description?.trim() ?? fileData.description?.trim() ??
i18n(cfg.locale).propertyDefaults.description i18n(cfg.locale).propertyDefaults.description
const { css, js } = externalResources const {css, js} = externalResources
const url = new URL(`https://${cfg.baseUrl ?? "example.com"}`) const url = new URL(`https://${cfg.baseUrl ?? "example.com"}`)
const path = url.pathname as FullSlug const path = url.pathname as FullSlug
const baseDir = const baseDir = fileData.slug === "404" ? path : pathToRoot(fileData.slug!)
fileData.slug === "404" ? path : pathToRoot(fileData.slug!)
const iconPath = joinSegments(baseDir, "static/icon.png") const iconPath = joinSegments(baseDir, "static/icon.png")
const ogImagePath = `https://${cfg.baseUrl}/static/og-image.png` const ogImagePath = `https://${cfg.baseUrl}/static/og-image.png`
@ -34,32 +32,17 @@ 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" && (
cfg.theme.fontOrigin === "googleFonts" && (
<> <>
<link <link rel="preconnect" href="https://fonts.googleapis.com" />
rel="preconnect" <link rel="preconnect" href="https://fonts.gstatic.com" />
href="https://fonts.googleapis.com" <link rel="stylesheet" href={googleFontHref(cfg.theme)} />
/>
<link
rel="preconnect"
href="https://fonts.gstatic.com"
/>
<link
rel="stylesheet"
href={googleFontHref(cfg.theme)}
/>
</> </>
)} )}
<meta <meta name="viewport" content="width=device-width, initial-scale=1.0" />
name="viewport"
content="width=device-width, initial-scale=1.0"
/>
<meta property="og:title" content={title} /> <meta property="og:title" content={title} />
<meta property="og:description" content={description} /> <meta property="og:description" content={description} />
{cfg.baseUrl && ( {cfg.baseUrl && <meta property="og:image" content={ogImagePath} />}
<meta property="og:image" content={ogImagePath} />
)}
<meta property="og:width" content="1200" /> <meta property="og:width" content="1200" />
<meta property="og:height" content="675" /> <meta property="og:height" content="675" />
<link rel="icon" href={iconPath} /> <link rel="icon" href={iconPath} />
@ -75,9 +58,7 @@ export default (() => {
/> />
))} ))}
{js {js
.filter( .filter((resource) => resource.loadTime === "beforeDOMReady")
(resource) => resource.loadTime === "beforeDOMReady",
)
.map((res) => JSResourceToScriptElement(res, true))} .map((res) => JSResourceToScriptElement(res, true))}
</head> </head>
) )

View File

@ -4,7 +4,7 @@ import {
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
const Header: QuartzComponent = ({ children }: QuartzComponentProps) => { const Header: QuartzComponent = ({children}: QuartzComponentProps) => {
return children.length > 0 ? <header>{children}</header> : null return children.length > 0 ? <header>{children}</header> : null
} }

View File

@ -1,8 +1,8 @@
import { FullSlug, resolveRelative } from "../util/path" import {FullSlug, resolveRelative} from "../util/path"
import { QuartzPluginData } from "../plugins/vfile" import {QuartzPluginData} from "../plugins/vfile"
import { Date, getDate } from "./Date" import {Date, getDate} from "./Date"
import { QuartzComponent, QuartzComponentProps } from "./types" import {QuartzComponent, QuartzComponentProps} from "./types"
import { GlobalConfiguration } from "../cfg" import {GlobalConfiguration} from "../cfg"
export function byDateAndAlphabetical( export function byDateAndAlphabetical(
cfg: GlobalConfiguration, cfg: GlobalConfiguration,
@ -51,21 +51,14 @@ export const PageList: QuartzComponent = ({
<div class="section"> <div class="section">
{page.dates && ( {page.dates && (
<p class="meta"> <p class="meta">
<Date <Date date={getDate(cfg, page)!} locale={cfg.locale} />
date={getDate(cfg, page)!}
locale={cfg.locale}
/>
</p> </p>
)} )}
<div class="desc"> <div class="desc">
<h3> <h3>
<a <a
href={resolveRelative( href={resolveRelative(fileData.slug!, page.slug!)}
fileData.slug!, class="internal">
page.slug!,
)}
class="internal"
>
{title} {title}
</a> </a>
</h3> </h3>
@ -78,8 +71,7 @@ export const PageList: QuartzComponent = ({
href={resolveRelative( href={resolveRelative(
fileData.slug!, fileData.slug!,
`tags/${tag}` as FullSlug, `tags/${tag}` as FullSlug,
)} )}>
>
{tag} {tag}
</a> </a>
</li> </li>

View File

@ -1,11 +1,11 @@
import { pathToRoot } from "../util/path" import {pathToRoot} from "../util/path"
import { import {
QuartzComponent, QuartzComponent,
QuartzComponentConstructor, QuartzComponentConstructor,
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
import { i18n } from "../i18n" import {i18n} from "../i18n"
const PageTitle: QuartzComponent = ({ const PageTitle: QuartzComponent = ({
fileData, fileData,

View File

@ -3,14 +3,14 @@ import {
QuartzComponentConstructor, QuartzComponentConstructor,
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import { FullSlug, SimpleSlug, resolveRelative } from "../util/path" import {FullSlug, SimpleSlug, resolveRelative} from "../util/path"
import { QuartzPluginData } from "../plugins/vfile" import {QuartzPluginData} from "../plugins/vfile"
import { byDateAndAlphabetical } from "./PageList" import {byDateAndAlphabetical} from "./PageList"
import style from "./styles/recentNotes.scss" import style from "./styles/recentNotes.scss"
import { Date, getDate } from "./Date" import {Date, getDate} from "./Date"
import { GlobalConfiguration } from "../cfg" import {GlobalConfiguration} from "../cfg"
import { i18n } from "../i18n" import {i18n} from "../i18n"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
interface Options { interface Options {
title?: string title?: string
@ -34,20 +34,16 @@ export default ((userOpts?: Partial<Options>) => {
displayClass, displayClass,
cfg, cfg,
}: QuartzComponentProps) => { }: QuartzComponentProps) => {
const opts = { ...defaultOptions(cfg), ...userOpts } const opts = {...defaultOptions(cfg), ...userOpts}
const pages = allFiles.filter(opts.filter).sort(opts.sort) const pages = allFiles.filter(opts.filter).sort(opts.sort)
const remaining = Math.max(0, pages.length - opts.limit) const remaining = Math.max(0, pages.length - opts.limit)
return ( return (
<div class={classNames(displayClass, "recent-notes")}> <div class={classNames(displayClass, "recent-notes")}>
<h3> <h3>{opts.title ?? i18n(cfg.locale).components.recentNotes.title}</h3>
{opts.title ??
i18n(cfg.locale).components.recentNotes.title}
</h3>
<ul class="recent-ul"> <ul class="recent-ul">
{pages.slice(0, opts.limit).map((page) => { {pages.slice(0, opts.limit).map((page) => {
const title = const title =
page.frontmatter?.title ?? page.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title
i18n(cfg.locale).propertyDefaults.title
const tags = page.frontmatter?.tags ?? [] const tags = page.frontmatter?.tags ?? []
return ( return (
@ -56,22 +52,15 @@ export default ((userOpts?: Partial<Options>) => {
<div class="desc"> <div class="desc">
<h3> <h3>
<a <a
href={resolveRelative( href={resolveRelative(fileData.slug!, page.slug!)}
fileData.slug!, class="internal">
page.slug!,
)}
class="internal"
>
{title} {title}
</a> </a>
</h3> </h3>
</div> </div>
{page.dates && ( {page.dates && (
<p class="meta"> <p class="meta">
<Date <Date date={getDate(cfg, page)!} locale={cfg.locale} />
date={getDate(cfg, page)!}
locale={cfg.locale}
/>
</p> </p>
)} )}
<ul class="tags"> <ul class="tags">
@ -82,8 +71,7 @@ export default ((userOpts?: Partial<Options>) => {
href={resolveRelative( href={resolveRelative(
fileData.slug!, fileData.slug!,
`tags/${tag}` as FullSlug, `tags/${tag}` as FullSlug,
)} )}>
>
{tag} {tag}
</a> </a>
</li> </li>
@ -96,15 +84,8 @@ export default ((userOpts?: Partial<Options>) => {
</ul> </ul>
{opts.linkToMore && remaining > 0 && ( {opts.linkToMore && remaining > 0 && (
<p> <p>
<a <a href={resolveRelative(fileData.slug!, opts.linkToMore)}>
href={resolveRelative( {i18n(cfg.locale).components.recentNotes.seeRemainingMore({
fileData.slug!,
opts.linkToMore,
)}
>
{i18n(
cfg.locale,
).components.recentNotes.seeRemainingMore({
remaining, remaining,
})} })}
</a> </a>

View File

@ -6,8 +6,8 @@ import {
import style from "./styles/search.scss" import style from "./styles/search.scss"
// @ts-ignore // @ts-ignore
import script from "./scripts/search.inline" import script from "./scripts/search.inline"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
import { i18n } from "../i18n" import {i18n} from "../i18n"
export interface SearchOptions { export interface SearchOptions {
enablePreview: boolean enablePreview: boolean
@ -22,7 +22,7 @@ export default ((userOpts?: Partial<SearchOptions>) => {
displayClass, displayClass,
cfg, cfg,
}: QuartzComponentProps) => { }: QuartzComponentProps) => {
const opts = { ...defaultOptions, ...userOpts } const opts = {...defaultOptions, ...userOpts}
const searchPlaceholder = i18n(cfg.locale).components.search const searchPlaceholder = i18n(cfg.locale).components.search
.searchBarPlaceholder .searchBarPlaceholder
return ( return (
@ -35,15 +35,11 @@ export default ((userOpts?: Partial<SearchOptions>) => {
aria-labelledby="title desc" aria-labelledby="title desc"
role="img" role="img"
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 19.9 19.7" viewBox="0 0 19.9 19.7">
>
<title id="title">Search</title> <title id="title">Search</title>
<desc id="desc">Search</desc> <desc id="desc">Search</desc>
<g class="search-path" fill="none"> <g class="search-path" fill="none">
<path <path stroke-linecap="square" d="M18.5 18.3l-5.4-5.4" />
stroke-linecap="square"
d="M18.5 18.3l-5.4-5.4"
/>
<circle cx="8" cy="8" r="7" /> <circle cx="8" cy="8" r="7" />
</g> </g>
</svg> </svg>
@ -58,10 +54,7 @@ export default ((userOpts?: Partial<SearchOptions>) => {
aria-label={searchPlaceholder} aria-label={searchPlaceholder}
placeholder={searchPlaceholder} placeholder={searchPlaceholder}
/> />
<div <div id="search-layout" data-preview={opts.enablePreview}></div>
id="search-layout"
data-preview={opts.enablePreview}
></div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -1,7 +1,7 @@
import { QuartzComponentConstructor, QuartzComponentProps } from "./types" import {QuartzComponentConstructor, QuartzComponentProps} from "./types"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
function Spacer({ displayClass }: QuartzComponentProps) { function Spacer({displayClass}: QuartzComponentProps) {
return <div class={classNames(displayClass, "spacer")}></div> return <div class={classNames(displayClass, "spacer")}></div>
} }

View File

@ -5,11 +5,11 @@ import {
} from "./types" } from "./types"
import legacyStyle from "./styles/legacyToc.scss" import legacyStyle from "./styles/legacyToc.scss"
import modernStyle from "./styles/toc.scss" import modernStyle from "./styles/toc.scss"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
// @ts-ignore // @ts-ignore
import script from "./scripts/toc.inline" import script from "./scripts/toc.inline"
import { i18n } from "../i18n" import {i18n} from "../i18n"
interface Options { interface Options {
layout: "modern" | "legacy" layout: "modern" | "legacy"
@ -33,8 +33,7 @@ const TableOfContents: QuartzComponent = ({
<button <button
type="button" type="button"
id="toc" id="toc"
class={fileData.collapseToc ? "collapsed" : ""} class={fileData.collapseToc ? "collapsed" : ""}>
>
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3> <h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
<svg <svg
xmlns="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg"
@ -46,22 +45,15 @@ const TableOfContents: QuartzComponent = ({
stroke-width="2" stroke-width="2"
stroke-linecap="round" stroke-linecap="round"
stroke-linejoin="round" stroke-linejoin="round"
class="fold" class="fold">
>
<polyline points="6 9 12 15 18 9"></polyline> <polyline points="6 9 12 15 18 9"></polyline>
</svg> </svg>
</button> </button>
<div id="toc-content"> <div id="toc-content">
<ul class="overflow"> <ul class="overflow">
{fileData.toc.map((tocEntry) => ( {fileData.toc.map((tocEntry) => (
<li <li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}>
key={tocEntry.slug} <a href={`#${tocEntry.slug}`} data-for={tocEntry.slug}>
class={`depth-${tocEntry.depth}`}
>
<a
href={`#${tocEntry.slug}`}
data-for={tocEntry.slug}
>
{tocEntry.text} {tocEntry.text}
</a> </a>
</li> </li>

View File

@ -1,10 +1,10 @@
import { pathToRoot, slugTag } from "../util/path" import {pathToRoot, slugTag} from "../util/path"
import { import {
QuartzComponent, QuartzComponent,
QuartzComponentConstructor, QuartzComponentConstructor,
QuartzComponentProps, QuartzComponentProps,
} from "./types" } from "./types"
import { classNames } from "../util/lang" import {classNames} from "../util/lang"
const TagList: QuartzComponent = ({ const TagList: QuartzComponent = ({
fileData, fileData,

View File

@ -1,11 +1,11 @@
import { i18n } from "../../i18n" import {i18n} from "../../i18n"
import { import {
QuartzComponent, QuartzComponent,
QuartzComponentConstructor, QuartzComponentConstructor,
QuartzComponentProps, QuartzComponentProps,
} from "../types" } from "../types"
const NotFound: QuartzComponent = ({ cfg }: QuartzComponentProps) => { const NotFound: QuartzComponent = ({cfg}: QuartzComponentProps) => {
return ( return (
<article class="popover-hint"> <article class="popover-hint">
<h1>404</h1> <h1>404</h1>

View File

@ -1,11 +1,11 @@
import { htmlToJsx } from "../../util/jsx" import {htmlToJsx} from "../../util/jsx"
import { import {
QuartzComponent, QuartzComponent,
QuartzComponentConstructor, QuartzComponentConstructor,
QuartzComponentProps, QuartzComponentProps,
} from "../types" } from "../types"
const Content: QuartzComponent = ({ fileData, tree }: QuartzComponentProps) => { const Content: QuartzComponent = ({fileData, tree}: QuartzComponentProps) => {
const content = htmlToJsx(fileData.filePath!, tree) const content = htmlToJsx(fileData.filePath!, tree)
const classes: string[] = fileData.frontmatter?.cssclasses ?? [] const classes: string[] = fileData.frontmatter?.cssclasses ?? []
const classString = ["popover-hint", ...classes].join(" ") const classString = ["popover-hint", ...classes].join(" ")

View File

@ -6,11 +6,11 @@ import {
import path from "path" import path from "path"
import style from "../styles/listPage.scss" import style from "../styles/listPage.scss"
import { PageList } from "../PageList" import {PageList} from "../PageList"
import { stripSlashes, simplifySlug } from "../../util/path" import {stripSlashes, simplifySlug} from "../../util/path"
import { Root } from "hast" import {Root} from "hast"
import { htmlToJsx } from "../../util/jsx" import {htmlToJsx} from "../../util/jsx"
import { i18n } from "../../i18n" import {i18n} from "../../i18n"
interface FolderContentOptions { interface FolderContentOptions {
/** /**
@ -24,10 +24,10 @@ const defaultOptions: FolderContentOptions = {
} }
export default ((opts?: Partial<FolderContentOptions>) => { export default ((opts?: Partial<FolderContentOptions>) => {
const options: FolderContentOptions = { ...defaultOptions, ...opts } const options: FolderContentOptions = {...defaultOptions, ...opts}
const FolderContent: QuartzComponent = (props: QuartzComponentProps) => { const FolderContent: QuartzComponent = (props: QuartzComponentProps) => {
const { tree, fileData, allFiles, cfg } = props const {tree, fileData, allFiles, cfg} = props
const folderSlug = stripSlashes(simplifySlug(fileData.slug!)) const folderSlug = stripSlashes(simplifySlug(fileData.slug!))
const allPagesInFolder = allFiles.filter((file) => { const allPagesInFolder = allFiles.filter((file) => {
const fileSlug = stripSlashes(simplifySlug(file.slug!)) const fileSlug = stripSlashes(simplifySlug(file.slug!))
@ -58,9 +58,7 @@ export default ((opts?: Partial<FolderContentOptions>) => {
<div class="page-listing"> <div class="page-listing">
{options.showFolderCount && ( {options.showFolderCount && (
<p> <p>
{i18n( {i18n(cfg.locale).pages.folderContent.itemsUnderFolder({
cfg.locale,
).pages.folderContent.itemsUnderFolder({
count: allPagesInFolder.length, count: allPagesInFolder.length,
})} })}
</p> </p>

View File

@ -4,16 +4,16 @@ import {
QuartzComponentProps, QuartzComponentProps,
} from "../types" } from "../types"
import style from "../styles/listPage.scss" import style from "../styles/listPage.scss"
import { PageList } from "../PageList" import {PageList} from "../PageList"
import { FullSlug, getAllSegmentPrefixes, simplifySlug } from "../../util/path" import {FullSlug, getAllSegmentPrefixes, simplifySlug} from "../../util/path"
import { QuartzPluginData } from "../../plugins/vfile" import {QuartzPluginData} from "../../plugins/vfile"
import { Root } from "hast" import {Root} from "hast"
import { htmlToJsx } from "../../util/jsx" import {htmlToJsx} from "../../util/jsx"
import { i18n } from "../../i18n" import {i18n} from "../../i18n"
const numPages = 10 const numPages = 10
const TagContent: QuartzComponent = (props: QuartzComponentProps) => { const TagContent: QuartzComponent = (props: QuartzComponentProps) => {
const { tree, fileData, allFiles, cfg } = props const {tree, fileData, allFiles, cfg} = props
const slug = fileData.slug const slug = fileData.slug
if (!(slug?.startsWith("tags/") || slug === "tags")) { if (!(slug?.startsWith("tags/") || slug === "tags")) {
@ -73,30 +73,23 @@ const TagContent: QuartzComponent = (props: QuartzComponentProps) => {
return ( return (
<div> <div>
<h2> <h2>
<a <a class="internal tag-link" href={`../tags/${tag}`}>
class="internal tag-link"
href={`../tags/${tag}`}
>
{tag} {tag}
</a> </a>
</h2> </h2>
{content && <p>{content}</p>} {content && <p>{content}</p>}
<div class="page-listing"> <div class="page-listing">
<p> <p>
{i18n( {i18n(cfg.locale).pages.tagContent.itemsUnderTag({
cfg.locale,
).pages.tagContent.itemsUnderTag({
count: pages.length, count: pages.length,
})} })}
{pages.length > numPages && ( {pages.length > numPages && (
<> <>
{" "} {" "}
<span> <span>
{i18n( {i18n(cfg.locale).pages.tagContent.showingFirst({
cfg.locale, count: numPages,
).pages.tagContent.showingFirst( })}
{ count: numPages },
)}
</span> </span>
</> </>
)} )}

View File

@ -1,8 +1,8 @@
import { render } from "preact-render-to-string" import {render} from "preact-render-to-string"
import { QuartzComponent, QuartzComponentProps } from "./types" import {QuartzComponent, QuartzComponentProps} from "./types"
import HeaderConstructor from "./Header" import HeaderConstructor from "./Header"
import BodyConstructor from "./Body" import BodyConstructor from "./Body"
import { JSResourceToScriptElement, StaticResources } from "../util/resources" import {JSResourceToScriptElement, StaticResources} from "../util/resources"
import { import {
clone, clone,
FullSlug, FullSlug,
@ -10,10 +10,10 @@ import {
joinSegments, joinSegments,
normalizeHastElement, normalizeHastElement,
} from "../util/path" } from "../util/path"
import { visit } from "unist-util-visit" import {visit} from "unist-util-visit"
import { Root, Element, ElementContent } from "hast" import {Root, Element, ElementContent} from "hast"
import { GlobalConfiguration } from "../cfg" import {GlobalConfiguration} from "../cfg"
import { i18n } from "../i18n" import {i18n} from "../i18n"
interface RenderComponents { interface RenderComponents {
head: QuartzComponent head: QuartzComponent
@ -75,9 +75,7 @@ export function renderPage(
const classNames = (node.properties?.className ?? []) as string[] const classNames = (node.properties?.className ?? []) as string[]
if (classNames.includes("transclude")) { if (classNames.includes("transclude")) {
const inner = node.children[0] as Element const inner = node.children[0] as Element
const transcludeTarget = inner.properties[ const transcludeTarget = inner.properties["data-slug"] as FullSlug
"data-slug"
] as FullSlug
const page = componentData.allFiles.find( const page = componentData.allFiles.find(
(f) => f.slug === transcludeTarget, (f) => f.slug === transcludeTarget,
) )
@ -101,11 +99,7 @@ export function renderPage(
} }
node.children = [ node.children = [
normalizeHastElement( normalizeHastElement(blockNode, slug, transcludeTarget),
blockNode,
slug,
transcludeTarget,
),
{ {
type: "element", type: "element",
tagName: "a", tagName: "a",
@ -116,8 +110,8 @@ export function renderPage(
children: [ children: [
{ {
type: "text", type: "text",
value: i18n(cfg.locale).components value: i18n(cfg.locale).components.transcludes
.transcludes.linkToOriginal, .linkToOriginal,
}, },
], ],
}, },
@ -131,20 +125,12 @@ export function renderPage(
let endIdx = undefined let endIdx = undefined
for (const [i, el] of page.htmlAst.children.entries()) { for (const [i, el] of page.htmlAst.children.entries()) {
// skip non-headers // skip non-headers
if ( if (!(el.type === "element" && el.tagName.match(headerRegex)))
!(
el.type === "element" &&
el.tagName.match(headerRegex)
)
)
continue continue
const depth = Number(el.tagName.substring(1)) const depth = Number(el.tagName.substring(1))
// lookin for our blockref // lookin for our blockref
if ( if (startIdx === undefined || startDepth === undefined) {
startIdx === undefined ||
startDepth === undefined
) {
// 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
@ -163,16 +149,9 @@ export function renderPage(
node.children = [ node.children = [
...( ...(
page.htmlAst.children.slice( page.htmlAst.children.slice(startIdx, endIdx) as ElementContent[]
startIdx,
endIdx,
) as ElementContent[]
).map((child) => ).map((child) =>
normalizeHastElement( normalizeHastElement(child as Element, slug, transcludeTarget),
child as Element,
slug,
transcludeTarget,
),
), ),
{ {
type: "element", type: "element",
@ -184,8 +163,7 @@ export function renderPage(
children: [ children: [
{ {
type: "text", type: "text",
value: i18n(cfg.locale).components value: i18n(cfg.locale).components.transcludes.linkToOriginal,
.transcludes.linkToOriginal,
}, },
], ],
}, },
@ -202,21 +180,14 @@ export function renderPage(
type: "text", type: "text",
value: value:
page.frontmatter?.title ?? page.frontmatter?.title ??
i18n( i18n(cfg.locale).components.transcludes.transcludeOf({
cfg.locale,
).components.transcludes.transcludeOf({
targetSlug: page.slug!, targetSlug: page.slug!,
}), }),
}, },
], ],
}, },
...(page.htmlAst.children as ElementContent[]).map( ...(page.htmlAst.children as ElementContent[]).map((child) =>
(child) => normalizeHastElement(child as Element, slug, transcludeTarget),
normalizeHastElement(
child as Element,
slug,
transcludeTarget,
),
), ),
{ {
type: "element", type: "element",
@ -228,8 +199,7 @@ export function renderPage(
children: [ children: [
{ {
type: "text", type: "text",
value: i18n(cfg.locale).components value: i18n(cfg.locale).components.transcludes.linkToOriginal,
.transcludes.linkToOriginal,
}, },
], ],
}, },

View File

@ -33,9 +33,7 @@ function setupCallout() {
if (title) { if (title) {
title.addEventListener("click", toggleCallout) title.addEventListener("click", toggleCallout)
window.addCleanup(() => window.addCleanup(() => title.removeEventListener("click", toggleCallout))
title.removeEventListener("click", toggleCallout),
)
const collapsed = div.classList.contains("is-collapsed") const collapsed = div.classList.contains("is-collapsed")
const height = collapsed ? title.scrollHeight : div.scrollHeight const height = collapsed ? title.scrollHeight : div.scrollHeight

View File

@ -1,4 +1,4 @@
import { getFullSlug } from "../../util/path" import {getFullSlug} from "../../util/path"
const checkboxId = (index: number) => `${getFullSlug(window)}-checkbox-${index}` const checkboxId = (index: number) => `${getFullSlug(window)}-checkbox-${index}`

View File

@ -28,9 +28,7 @@ document.addEventListener("nav", () => {
) )
} }
button.addEventListener("click", onClick) button.addEventListener("click", onClick)
window.addCleanup(() => window.addCleanup(() => button.removeEventListener("click", onClick))
button.removeEventListener("click", onClick),
)
els[i].prepend(button) els[i].prepend(button)
} }
} }

Some files were not shown because too many files have changed in this diff Show More