1
0
Fork 0

Compare commits

..

34 commits

Author SHA1 Message Date
a3316d369c update content 2024-03-08 21:52:54 +01:00
25571074bd add Locale callout 2024-03-08 21:52:54 +01:00
204a7d196f Format wiki in popover 2024-03-08 21:52:54 +01:00
5806c5ad40 disable reading time 2024-03-08 21:52:53 +01:00
0858459a41 udpate 2024-03-08 21:52:53 +01:00
71e78f07c0 content 2024-03-08 21:52:53 +01:00
96e737484b format on save 2024-03-08 21:52:53 +01:00
3f79c5030b format 2024-03-08 21:52:53 +01:00
e73bc1a0af WIP:options in FolderContent 2024-03-08 21:52:53 +01:00
1dd4bc524b remove background from internal links 2024-03-08 21:52:52 +01:00
380dc5feb1 Update wiki callout 2024-03-08 21:52:52 +01:00
c90e48d8aa update content 2024-03-08 21:52:52 +01:00
030f199e89 Add wiki callout 2024-03-08 21:52:52 +01:00
4452eaba01 Prettier 2024-03-08 21:52:52 +01:00
3eb31e1a0d Update statblock icon 2024-03-08 21:52:51 +01:00
290d700d0e add diversion as backup 2024-03-08 21:52:51 +01:00
667d706537 change css for statblocks 2024-03-08 21:52:51 +01:00
d233935ff5 Enable custom callout
make a callout custom defaulted to a note one.
2024-03-08 21:52:51 +01:00
e9c58c0b3f Add statblock callout 2024-03-08 21:52:50 +01:00
11881cf70c update css 2024-03-08 21:52:50 +01:00
0166acdaad update content 2024-03-08 21:52:50 +01:00
fbdab137b9 Make books float 2024-03-08 21:52:50 +01:00
56ab40d96d Make it positive ! 🌞 2024-03-08 21:52:50 +01:00
371dee7019 Remove ContentMeta override from quartz.layout.ts 2024-03-08 21:52:49 +01:00
90203ac7cd Update 2024-03-08 21:52:49 +01:00
a769ff6fcb update content 2024-03-08 21:52:49 +01:00
cf04104cf7 Make img centered 2024-03-08 21:52:49 +01:00
32f0d1ec06 hide reading time 2024-03-08 21:52:49 +01:00
bef7809b95 add an option to display or not reading time from notes 2024-03-08 21:52:49 +01:00
6c7b78bdb3 Update content 2024-03-08 21:52:48 +01:00
3e1ed97b4b Update content 2024-03-08 21:52:48 +01:00
580212ad9b Initial config 2024-03-08 21:52:48 +01:00
f8e4ea1d63 add script to build 2024-03-08 21:51:40 +01:00
1c8e3de5c2 Add Submodule 2024-03-08 21:51:40 +01:00
84 changed files with 370 additions and 1806 deletions

View file

@ -7,7 +7,6 @@ on:
push:
branches:
- v4
workflow_dispatch:
jobs:
build-and-test:
@ -19,17 +18,17 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18
- name: Cache dependencies
uses: actions/cache@v4
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
@ -48,22 +47,22 @@ jobs:
run: npx quartz build --bundleInfo
publish-tag:
if: ${{ github.repository == 'jackyzha0/quartz' && github.ref == 'refs/heads/v4' }}
if: ${{ github.repository == 'jackyzha0/quartz' }}
runs-on: ubuntu-latest
permissions:
contents: write
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Setup Node
uses: actions/setup-node@v4
uses: actions/setup-node@v3
with:
node-version: 18
- name: Get package version
run: node -p -e '`PACKAGE_VERSION=${require("./package.json").version}`' >> $GITHUB_ENV
- name: Create release tag
uses: pkgdeps/git-tag-action@v3
uses: pkgdeps/git-tag-action@v2
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
github_repo: ${{ github.repository }}

View file

@ -129,11 +129,11 @@ export default (() => {
return <button id="btn">Click me</button>
}
YourComponent.beforeDOMLoaded = `
YourComponent.beforeDOM = `
console.log("hello from before the page loads!")
`
YourComponent.afterDOMLoaded = `
YourComponent.afterDOM = `
document.getElementById('btn').onclick = () => {
alert('button clicked!')
}
@ -180,7 +180,7 @@ export default (() => {
return <button id="btn">Click me</button>
}
YourComponent.afterDOMLoaded = script
YourComponent.afterDOM = script
return YourComponent
}) satisfies QuartzComponentConstructor
```

View file

@ -48,4 +48,4 @@ Here are the main types of slugs with a rough description of each type of path:
- `SimpleSlug`: cannot be relative and shouldn't have `/index` as an ending or a file extension. It _can_ however have a trailing slash to indicate a folder path.
- `RelativeURL`: must start with `.` or `..` to indicate it's a relative URL. Shouldn't have `/index` as an ending or a file extension but can contain a trailing slash.
To get a clearer picture of how these relate to each other, take a look at the path tests in `quartz/util/path.test.ts`.
To get a clearer picture of how these relate to each other, take a look at the path tests in `quartz/path.test.ts`.

View file

@ -28,10 +28,7 @@ This part of the configuration concerns anything that can affect the whole site.
- `{ provider: 'google', tagId: '<your-google-tag>' }`: use Google Analytics;
- `{ provider: 'plausible' }` (managed) or `{ provider: 'plausible', host: '<your-plausible-host>' }` (self-hosted): use [Plausible](https://plausible.io/);
- `{ provider: 'umami', host: '<your-umami-host>', websiteId: '<your-umami-website-id>' }`: use [Umami](https://umami.is/);
- `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id' }` (managed) or `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id', host: 'my-goatcounter-domain.com', scriptSrc: 'https://my-url.to/counter.js' }` (self-hosted) use [GoatCounter](https://goatcounter.com);
- `{ provider: 'posthog', apiKey: '<your-posthog-project-apiKey>', host: '<your-posthog-host>' }`: use [Posthog](https://posthog.com/);
- `{ provider: 'tinylytics', siteId: '<your-site-id>' }`: use [Tinylytics](https://tinylytics.app/);
- `{ provider: 'cabin' }` or `{ provider: 'cabin', host: 'https://cabin.example.com' }` (custom domain): use [Cabin](https://withcabin.com);
- `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id' }` (managed) or `{ provider: 'goatcounter', websiteId: 'my-goatcounter-id', host: 'my-goatcounter-domain.com', scriptSrc: 'https://my-url.to/counter.js' }` (self-hosted) use [GoatCounter](https://goatcounter.com)
- `locale`: used for [[i18n]] and date formatting
- `baseUrl`: this is used for sitemaps and RSS feeds that require an absolute URL to know where the canonical 'home' of your site lives. This is normally the deployed URL of your site (e.g. `quartz.jzhao.xyz` for this site). Do not include the protocol (i.e. `https://`) or any leading or trailing slashes.
- This should also include the subpath if you are [[hosting]] on GitHub pages without a custom domain. For example, if my repository is `jackyzha0/quartz`, GitHub pages would deploy to `https://jackyzha0.github.io/quartz` and the `baseUrl` would be `jackyzha0.github.io/quartz`.

View file

@ -39,17 +39,6 @@ a & b & c
\end{bmatrix}
$$
$$
\begin{array}{rll}
E \psi &= H\psi & \text{Expanding the Hamiltonian Operator} \\
&= -\frac{\hbar^2}{2m}\frac{\partial^2}{\partial x^2} \psi + \frac{1}{2}m\omega x^2 \psi & \text{Using the ansatz $\psi(x) = e^{-kx^2}f(x)$, hoping to cancel the $x^2$ term} \\
&= -\frac{\hbar^2}{2m} [4k^2x^2f(x)+2(-2kx)f'(x) + f''(x)]e^{-kx^2} + \frac{1}{2}m\omega x^2 f(x)e^{-kx^2} &\text{Removing the $e^{-kx^2}$ term from both sides} \\
& \Downarrow \\
Ef(x) &= -\frac{\hbar^2}{2m} [4k^2x^2f(x)-4kxf'(x) + f''(x)] + \frac{1}{2}m\omega x^2 f(x) & \text{Choosing $k=\frac{im}{2}\sqrt{\frac{\omega}{\hbar}}$ to cancel the $x^2$ term, via $-\frac{\hbar^2}{2m}4k^2=\frac{1}{2}m \omega$} \\
&= -\frac{\hbar^2}{2m} [-4kxf'(x) + f''(x)] \\
\end{array}
$$
> [!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.

View file

@ -9,7 +9,6 @@ Quartz can generate a list of recent notes based on some filtering and sorting c
- Changing the title from "Recent notes": pass in an additional parameter to `Component.RecentNotes({ title: "Recent writing" })`
- Changing the number of recent notes: pass in an additional parameter to `Component.RecentNotes({ limit: 5 })`
- Display the note's tags (defaults to true): `Component.RecentNotes({ showTags: false })`
- Show a 'see more' link: pass in an additional parameter to `Component.RecentNotes({ linkToMore: "tags/components" })`. This field should be a full slug to a page that exists.
- Customize filtering: pass in an additional parameter to `Component.RecentNotes({ filter: someFilterFunction })`. The filter function should be a function that has the signature `(f: QuartzPluginData) => boolean`.
- Customize sorting: pass in an additional parameter to `Component.RecentNotes({ sort: someSortFunction })`. By default, Quartz will sort by date and then tie break lexographically. The sort function should be a function that has the signature `(f1: QuartzPluginData, f2: QuartzPluginData) => number`. See `byDateAndAlphabetical` in `quartz/components/PageList.tsx` for an example.

View file

@ -95,16 +95,6 @@ const [age, setAge] = useState(50)
const [name, setName] = useState("Taylor")
```
### Inline Highlighting
Append {:lang} to the end of inline code to highlight it like a regular code block.
```
This is an array `[1, 2, 3]{:js}` of numbers 1 through 3.
```
This is an array `[1, 2, 3]{:js}` of numbers 1 through 3.
### Line numbers
Syntax highlighting has line numbers configured automatically. If you want to start line numbers at a specific number, use `showLineNumbers{number}`:

View file

@ -57,16 +57,18 @@ jobs:
build:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v4
- uses: actions/checkout@v3
with:
fetch-depth: 0 # Fetch all history for git info
- uses: actions/setup-node@v4
- uses: actions/setup-node@v3
with:
node-version: 18.14
- name: Install Dependencies
run: npm ci
- name: Build Quartz
run: npx quartz build
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
uses: actions/upload-pages-artifact@v2
with:
path: public
@ -79,7 +81,7 @@ jobs:
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
uses: actions/deploy-pages@v2
```
Then:
@ -180,31 +182,35 @@ Using `docs.example.com` is an example of a subdomain. They're a simple way of c
## GitLab Pages
In your local Quartz, create a new file `.gitlab-ci.yml`.
In your local Quartz, create a new file `.gitlab-ci.yaml`.
```yaml title=".gitlab-ci.yml"
```yaml title=".gitlab-ci.yaml"
stages:
- build
- deploy
image: node:18
cache: # Cache modules in between jobs
key: $CI_COMMIT_REF_SLUG
paths:
- .npm/
variables:
NODE_VERSION: "18.14"
build:
stage: build
rules:
- if: '$CI_COMMIT_REF_NAME == "v4"'
before_script:
- apt-get update -q && apt-get install -y nodejs npm
- npm install -g n
- n $NODE_VERSION
- hash -r
- npm ci --cache .npm --prefer-offline
- npm ci
script:
- npx quartz build
artifacts:
paths:
- public
cache:
paths:
- ~/.npm/
key: "${CI_COMMIT_REF_SLUG}-node-${CI_COMMIT_REF_NAME}"
tags:
- docker
@ -244,21 +250,3 @@ server {
}
}
```
### Using Caddy
Here's and example of how to do this with Caddy:
```caddy title="Caddyfile"
example.com {
root * /path/to/quartz/public
try_files {path} {path}.html {path}/ =404
file_server
encode gzip
handle_errors {
rewrite * /{err.status_code}.html
file_server
}
}
```

View file

@ -26,7 +26,7 @@ The emitter supports the following aliases:
- `alias`
> [!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.

View file

@ -9,7 +9,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]
> 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.

View file

@ -8,10 +8,10 @@ This plugin emits a `CNAME` record that points your subdomain to the default dom
If you want to use a custom domain name like `quartz.example.com` for the site, then this is needed.
See [[hosting|Hosting]] for more information.
See [[Hosting]] for more information.
> [!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.

View file

@ -7,7 +7,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]].
> [!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.

View file

@ -9,7 +9,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
> [!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:

View file

@ -7,7 +7,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.
> [!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.

View file

@ -7,7 +7,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.
> [!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:

View file

@ -7,7 +7,7 @@ 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.
> [!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:

View file

@ -9,7 +9,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.
> [!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:

View file

@ -7,7 +7,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.
> [!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.

View file

@ -9,7 +9,7 @@ This plugin generates index pages for folders, creating a listing page for each
Example: [[advanced/|Advanced]]
> [!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.

View file

@ -7,7 +7,7 @@ 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.
> [!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:

View file

@ -9,7 +9,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.
> [!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:

View file

@ -7,7 +7,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]].
> [!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.

View file

@ -7,7 +7,7 @@ tags:
This plugin adds LaTeX support to Quartz. See [[features/Latex|Latex]] for more information.
> [!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:

View file

@ -7,7 +7,7 @@ tags:
This plugin emits a 404 (Not Found) page for broken or non-existent URLs.
> [!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.

View file

@ -7,7 +7,7 @@ tags:
This plugin provides support for [[Obsidian compatibility]].
> [!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:

View file

@ -7,7 +7,7 @@ tags:
This plugin provides support for [ox-hugo](https://github.com/kaushalmodi/ox-hugo) compatibility. See [[OxHugo compatibility]] for more information.
> [!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:

View file

@ -7,7 +7,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.
> [!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.

View file

@ -10,7 +10,7 @@ This plugin emits all static resources needed by Quartz. This is used, for examp
> 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]
> 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.

View file

@ -7,7 +7,7 @@ tags:
This plugin is used to add syntax highlighting to code blocks in Quartz. See [[syntax highlighting]] for more information.
> [!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:

View file

@ -7,7 +7,7 @@ tags:
This plugin generates a table of contents (TOC) for Markdown documents. See [[table of contents]] for more information.
> [!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:

View file

@ -7,7 +7,7 @@ tags:
This plugin emits dedicated pages for each tag used in the content. See [[folder and tag listings]] for more information.
> [!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.

View file

@ -26,8 +26,5 @@ Want to see what Quartz can do? Here are some cool community gardens:
- [Data Dictionary 🧠](https://glossary.airbyte.com/)
- [sspaeti.com's Second Brain](https://brain.sspaeti.com/)
- [🪴Aster's notebook](https://notes.asterhu.com)
- [🥷🏻🌳🍃 Computer Science & Thinkering Garden](https://notes.yxy.ninja)
- [A Pattern Language - Christopher Alexander (Architecture)](https://patternlanguage.cc/)
- [Gatekeeper Wiki](https://www.gatekeeper.wiki)
If you want to see your own on here, submit a [Pull Request adding yourself to this file](https://github.com/jackyzha0/quartz/blob/v4/docs/showcase.md)!

909
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -12,7 +12,6 @@
"url": "https://github.com/jackyzha0/quartz.git"
},
"scripts": {
"quartz": "./quartz/bootstrap-cli.mjs",
"docs": "npx quartz build --serve -d docs",
"dev": "npx quartz build --serve",
"check": "tsc --noEmit && npx prettier . --check",
@ -37,38 +36,37 @@
},
"dependencies": {
"@clack/prompts": "^0.7.0",
"@floating-ui/dom": "^1.6.5",
"@floating-ui/dom": "^1.6.3",
"@napi-rs/simple-git": "0.1.16",
"async-mutex": "^0.5.0",
"async-mutex": "^0.4.1",
"chalk": "^5.3.0",
"chokidar": "^3.6.0",
"cli-spinner": "^0.2.10",
"d3": "^7.9.0",
"d3": "^7.8.5",
"esbuild-sass-plugin": "^2.16.1",
"flexsearch": "0.7.43",
"github-slugger": "^2.0.0",
"globby": "^14.0.1",
"gray-matter": "^4.0.3",
"hast-util-to-html": "^9.0.1",
"hast-util-to-html": "^9.0.0",
"hast-util-to-jsx-runtime": "^2.3.0",
"hast-util-to-string": "^3.0.0",
"is-absolute-url": "^4.0.1",
"js-yaml": "^4.1.0",
"lightningcss": "^1.24.1",
"lightningcss": "^1.24.0",
"mdast-util-find-and-replace": "^3.0.1",
"mdast-util-to-hast": "^13.1.0",
"mdast-util-to-string": "^4.0.0",
"micromorph": "^0.4.5",
"preact": "^10.22.0",
"preact-render-to-string": "^6.5.5",
"preact": "^10.19.6",
"preact-render-to-string": "^6.4.0",
"pretty-bytes": "^6.1.1",
"pretty-time": "^1.1.0",
"reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.1.0",
"rehype-citation": "^2.0.0",
"rehype-katex": "^7.0.0",
"rehype-mathjax": "^6.0.0",
"rehype-pretty-code": "^0.13.2",
"rehype-pretty-code": "^0.13.0",
"rehype-raw": "^7.0.0",
"rehype-slug": "^6.0.0",
"remark": "^15.0.1",
@ -80,17 +78,17 @@
"remark-rehype": "^11.1.0",
"remark-smartypants": "^2.1.0",
"rfdc": "^1.3.1",
"rimraf": "^5.0.7",
"rimraf": "^5.0.5",
"serve-handler": "^6.1.5",
"shiki": "^1.6.0",
"shiki": "^1.1.7",
"source-map-support": "^0.5.21",
"to-vfile": "^8.0.0",
"toml": "^3.0.0",
"unified": "^11.0.4",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.1",
"workerpool": "^9.1.2",
"ws": "^8.17.1",
"workerpool": "^9.1.0",
"ws": "^8.15.1",
"yargs": "^17.7.2"
},
"devDependencies": {
@ -98,14 +96,14 @@
"@types/d3": "^7.4.3",
"@types/hast": "^3.0.4",
"@types/js-yaml": "^4.0.9",
"@types/node": "^20.12.5",
"@types/node": "^20.11.24",
"@types/pretty-time": "^1.1.5",
"@types/source-map-support": "^0.5.10",
"@types/ws": "^8.5.10",
"@types/yargs": "^17.0.32",
"esbuild": "^0.19.9",
"prettier": "^3.3.2",
"tsx": "^4.11.2",
"typescript": "^5.4.5"
"prettier": "^3.2.4",
"tsx": "^4.7.1",
"typescript": "^5.3.3"
}
}

View file

@ -20,7 +20,6 @@ const config: QuartzConfig = {
ignorePatterns: ["private", "templates", ".obsidian"],
defaultDateType: "modified",
theme: {
fontOrigin: "googleFonts",
cdnCaching: true,
typography: {
header: "Quintessential",
@ -59,6 +58,7 @@ const config: QuartzConfig = {
// if you do rely on git for dates, ensure defaultDateType is 'modified'
priority: ["frontmatter", "filesystem", "git"],
}),
Plugin.Latex({ renderEngine: "katex" }),
Plugin.SyntaxHighlighting({
theme: {
light: "github-light",
@ -71,12 +71,11 @@ const config: QuartzConfig = {
Plugin.TableOfContents(),
Plugin.CrawlLinks({ markdownLinkResolution: "shortest" }),
Plugin.Description(),
Plugin.Latex({ renderEngine: "katex" }),
],
filters: [Plugin.RemoveDrafts()],
emitters: [
Plugin.AliasRedirects(),
Plugin.ComponentResources(),
Plugin.ComponentResources({ fontOrigin: "googleFonts" }),
Plugin.ContentPage(),
Plugin.FolderPage({
pageBody: FolderContent({

View file

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

View file

@ -25,19 +25,6 @@ export type Analytics =
host?: string
scriptSrc?: string
}
| {
provider: "posthog"
apiKey: string
host?: string
}
| {
provider: "tinylytics"
siteId: string
}
| {
provider: "cabin"
host?: string
}
export interface GlobalConfiguration {
pageTitle: string

View file

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

View file

@ -168,8 +168,10 @@ export function ExplorerNode({ node, opts, fullPath, fileData }: ExplorerNodePro
const isDefaultOpen = opts.folderDefaultState === "open"
// Calculate current folderPath
const folderPath = node.name !== "" ? joinSegments(fullPath ?? "", node.name) : ""
const href = resolveRelative(fileData.slug!, folderPath as SimpleSlug) + "/"
let folderPath = ""
if (node.name !== "") {
folderPath = joinSegments(fullPath ?? "", node.name)
}
return (
<>
@ -203,7 +205,11 @@ export function ExplorerNode({ node, opts, fullPath, fileData }: ExplorerNodePro
{/* render <a> tag if folderBehavior is "link", otherwise render <button> with collapse click event */}
<div key={node.name} data-folderpath={folderPath}>
{folderBehavior === "link" ? (
<a href={href} data-for={node.name} class="folder-title">
<a
href={resolveRelative(fileData.slug!, folderPath as SimpleSlug)}
data-for={node.name}
class="folder-title"
>
{node.displayName}
</a>
) : (

View file

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

View file

@ -12,7 +12,6 @@ interface Options {
title?: string
limit: number
linkToMore: SimpleSlug | false
showTags: boolean
filter: (f: QuartzPluginData) => boolean
sort: (f1: QuartzPluginData, f2: QuartzPluginData) => number
}
@ -20,7 +19,6 @@ interface Options {
const defaultOptions = (cfg: GlobalConfiguration): Options => ({
limit: 3,
linkToMore: false,
showTags: true,
filter: () => true,
sort: byDateAndAlphabetical(cfg),
})
@ -58,20 +56,18 @@ export default ((userOpts?: Partial<Options>) => {
<Date date={getDate(cfg, page)!} locale={cfg.locale} />
</p>
)}
{opts.showTags && (
<ul class="tags">
{tags.map((tag) => (
<li>
<a
class="internal tag-link"
href={resolveRelative(fileData.slug!, `tags/${tag}` as FullSlug)}
>
{tag}
</a>
</li>
))}
</ul>
)}
<ul class="tags">
{tags.map((tag) => (
<li>
<a
class="internal tag-link"
href={resolveRelative(fileData.slug!, `tags/${tag}` as FullSlug)}
>
{tag}
</a>
</li>
))}
</ul>
</div>
</li>
)

View file

@ -2,15 +2,10 @@ import { i18n } from "../../i18n"
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "../types"
const NotFound: QuartzComponent = ({ cfg }: QuartzComponentProps) => {
// If baseUrl contains a pathname after the domain, use this as the home link
const url = new URL(`https://${cfg.baseUrl ?? "example.com"}`)
const baseDir = url.pathname
return (
<article class="popover-hint">
<h1>404</h1>
<p>{i18n(cfg.locale).pages.error.notFound}</p>
<a href={baseDir}>{i18n(cfg.locale).pages.error.home}</a>
</article>
)
}

View file

@ -47,7 +47,9 @@ export default ((opts?: Partial<FolderContentOptions>) => {
return (
<div class={classes}>
<article>{content}</article>
<article>
<p>{content}</p>
</article>
<div class="page-listing">
{options.showFolderCount && (
<p>

View file

@ -52,14 +52,8 @@ const TagContent: QuartzComponent = (props: QuartzComponentProps) => {
allFiles: pages,
}
const contentPage = allFiles.filter((file) => file.slug === `tags/${tag}`).at(0)
const root = contentPage?.htmlAst
const content =
!root || root?.children.length === 0
? contentPage?.description
: htmlToJsx(contentPage.filePath!, root)
const contentPage = allFiles.filter((file) => file.slug === `tags/${tag}`)[0]
const content = contentPage?.description
return (
<div>
<h2>

View file

@ -118,12 +118,11 @@ export function renderPage(
// skip until we find the blockref that matches
if (el.properties?.id === blockRef) {
startIdx = i
startDepth = depth
startDepth = Number(el.tagName.substring(1))
}
} else if (depth <= startDepth) {
// looking for new header that is same level or higher
endIdx = i
break
}
}

View file

@ -223,18 +223,6 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
.transition()
.duration(200)
.style("opacity", 0.2)
d3.selectAll<HTMLElement, NodeData>(".node")
.filter((d) => !connectedNodes.includes(d.id))
.nodes()
.map((it) => d3.select(it.parentNode as HTMLElement).select("text"))
.forEach((it) => {
let opacity = parseFloat(it.style("opacity"))
it.transition()
.duration(200)
.attr("opacityOld", opacity)
.style("opacity", Math.min(opacity, 0.2))
})
}
// highlight links
@ -257,12 +245,6 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
if (focusOnHover) {
d3.selectAll<HTMLElement, NodeData>(".link").transition().duration(200).style("opacity", 1)
d3.selectAll<HTMLElement, NodeData>(".node").transition().duration(200).style("opacity", 1)
d3.selectAll<HTMLElement, NodeData>(".node")
.filter((d) => !connectedNodes.includes(d.id))
.nodes()
.map((it) => d3.select(it.parentNode as HTMLElement).select("text"))
.forEach((it) => it.transition().duration(200).style("opacity", it.attr("opacityOld")))
}
const currentId = d.id
const linkNodes = d3
@ -282,13 +264,6 @@ async function renderGraph(container: string, fullSlug: FullSlug) {
// @ts-ignore
.call(drag(simulation))
// make tags hollow circles
node
.filter((d) => d.id.startsWith("tags/"))
.attr("stroke", color)
.attr("stroke-width", 2)
.attr("fill", "var(--light)")
// draw labels
const labels = graphNode
.append("text")
@ -361,7 +336,7 @@ function renderGlobalGraph() {
document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
const slug = e.detail.url
addToVisited(simplifySlug(slug))
addToVisited(slug)
await renderGraph("graph-container", slug)
const containerIcon = document.getElementById("global-graph-icon")

View file

@ -21,7 +21,6 @@ let index = new FlexSearch.Document<Item>({
encode: encoder,
document: {
id: "id",
tag: "tags",
index: [
{
field: "title",
@ -406,33 +405,11 @@ document.addEventListener("nav", async (e: CustomEventMap["nav"]) => {
let searchResults: FlexSearch.SimpleDocumentSearchResultSetUnit[]
if (searchType === "tags") {
currentSearchTerm = currentSearchTerm.substring(1).trim()
const separatorIndex = currentSearchTerm.indexOf(" ")
if (separatorIndex != -1) {
// search by title and content index and then filter by tag (implemented in flexsearch)
const tag = currentSearchTerm.substring(0, separatorIndex)
const query = currentSearchTerm.substring(separatorIndex + 1).trim()
searchResults = await index.searchAsync({
query: query,
// return at least 10000 documents, so it is enough to filter them by tag (implemented in flexsearch)
limit: Math.max(numSearchResults, 10000),
index: ["title", "content"],
tag: tag,
})
for (let searchResult of searchResults) {
searchResult.result = searchResult.result.slice(0, numSearchResults)
}
// set search type to basic and remove tag from term for proper highlightning and scroll
searchType = "basic"
currentSearchTerm = query
} else {
// default search by tags index
searchResults = await index.searchAsync({
query: currentSearchTerm,
limit: numSearchResults,
index: ["tags"],
})
}
searchResults = await index.searchAsync({
query: currentSearchTerm.substring(1),
limit: numSearchResults,
index: ["tags"],
})
} else if (searchType === "basic") {
searchResults = await index.searchAsync({
query: currentSearchTerm,

View file

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

View file

@ -11,7 +11,7 @@ li.section-li {
& > .section {
display: grid;
grid-template-columns: fit-content(8em) 3fr 1fr;
grid-template-columns: 6em 3fr 1fr;
@media all and (max-width: $mobileBreakpoint) {
& > .tags {
@ -24,7 +24,8 @@ li.section-li {
}
& > .meta {
margin: 0 1em 0 0;
margin: 0;
flex-basis: 6em;
opacity: 0.6;
}
}
@ -32,8 +33,7 @@ li.section-li {
// modifications in popover context
.popover .section {
grid-template-columns: fit-content(8em) 1fr !important;
grid-template-columns: 6em 1fr !important;
& > .tags {
display: none;
}

View file

@ -6,7 +6,6 @@ import ja from "./locales/ja-JP"
import de from "./locales/de-DE"
import nl from "./locales/nl-NL"
import ro from "./locales/ro-RO"
import ca from "./locales/ca-ES"
import es from "./locales/es-ES"
import ar from "./locales/ar-SA"
import uk from "./locales/uk-UA"
@ -14,14 +13,9 @@ import ru from "./locales/ru-RU"
import ko from "./locales/ko-KR"
import zh from "./locales/zh-CN"
import vi from "./locales/vi-VN"
import pt from "./locales/pt-BR"
import hu from "./locales/hu-HU"
import fa from "./locales/fa-IR"
import pl from "./locales/pl-PL"
export const TRANSLATIONS = {
"en-US": en,
"en-GB": en,
"fr-FR": fr,
"it-IT": it,
"ja-JP": ja,
@ -30,7 +24,6 @@ export const TRANSLATIONS = {
"nl-BE": nl,
"ro-RO": ro,
"ro-MD": ro,
"ca-ES": ca,
"es-ES": es,
"ar-SA": ar,
"ar-AE": ar,
@ -57,10 +50,6 @@ export const TRANSLATIONS = {
"ko-KR": ko,
"zh-CN": zh,
"vi-VN": vi,
"pt-BR": pt,
"hu-HU": hu,
"fa-IR": fa,
"pl-PL": pl,
} as const
export const defaultTranslation = "en-US"

View file

@ -70,7 +70,6 @@ export default {
error: {
title: "غير موجود",
notFound: "إما أن هذه الصفحة خاصة أو غير موجودة.",
home: "العوده للصفحة الرئيسية",
},
folderContent: {
folder: "مجلد",

View file

@ -1,84 +0,0 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Sense títol",
description: "Sense descripció",
},
components: {
callout: {
note: "Nota",
abstract: "Resum",
info: "Informació",
todo: "Per fer",
tip: "Consell",
success: "Èxit",
question: "Pregunta",
warning: "Advertència",
failure: "Fall",
danger: "Perill",
bug: "Error",
example: "Exemple",
quote: "Cita",
},
backlinks: {
title: "Retroenllaç",
noBacklinksFound: "No s'han trobat retroenllaços",
},
themeToggle: {
lightMode: "Mode clar",
darkMode: "Mode fosc",
},
explorer: {
title: "Explorador",
},
footer: {
createdWith: "Creat amb",
},
graph: {
title: "Vista Gràfica",
},
recentNotes: {
title: "Notes Recents",
seeRemainingMore: ({ remaining }) => `Vegi ${remaining} més →`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `Transcluit de ${targetSlug}`,
linkToOriginal: "Enllaç a l'original",
},
search: {
title: "Cercar",
searchBarPlaceholder: "Cerca alguna cosa",
},
tableOfContents: {
title: "Taula de Continguts",
},
contentMeta: {
readingTime: ({ minutes }) => `Es llegeix en ${minutes} min`,
},
},
pages: {
rss: {
recentNotes: "Notes recents",
lastFewNotes: ({ count }) => `Últimes ${count} notes`,
},
error: {
title: "No s'ha trobat.",
notFound: "Aquesta pàgina és privada o no existeix.",
home: "Torna a la pàgina principal",
},
folderContent: {
folder: "Carpeta",
itemsUnderFolder: ({ count }) =>
count === 1 ? "1 article en aquesta carpeta." : `${count} articles en esta carpeta.`,
},
tagContent: {
tag: "Etiqueta",
tagIndex: "índex d'Etiquetes",
itemsUnderTag: ({ count }) =>
count === 1 ? "1 article amb aquesta etiqueta." : `${count} article amb aquesta etiqueta.`,
showingFirst: ({ count }) => `Mostrant les primeres ${count} etiquetes.`,
totalTags: ({ count }) => `S'han trobat ${count} etiquetes en total.`,
},
},
} as const satisfies Translation

View file

@ -65,7 +65,6 @@ export default {
error: {
title: "Nicht gefunden",
notFound: "Diese Seite ist entweder nicht öffentlich oder existiert nicht.",
home: "Return to Homepage",
},
folderContent: {
folder: "Ordner",

View file

@ -67,7 +67,6 @@ export interface Translation {
error: {
title: string
notFound: string
home: string
}
folderContent: {
folder: string

View file

@ -1,84 +0,0 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Untitled",
description: "No description provided",
},
components: {
callout: {
note: "Note",
abstract: "Abstract",
info: "Info",
todo: "To-Do",
tip: "Tip",
success: "Success",
question: "Question",
warning: "Warning",
failure: "Failure",
danger: "Danger",
bug: "Bug",
example: "Example",
quote: "Quote",
},
backlinks: {
title: "Backlinks",
noBacklinksFound: "No backlinks found",
},
themeToggle: {
lightMode: "Light mode",
darkMode: "Dark mode",
},
explorer: {
title: "Explorer",
},
footer: {
createdWith: "Created with",
},
graph: {
title: "Graph View",
},
recentNotes: {
title: "Recent Notes",
seeRemainingMore: ({ remaining }) => `See ${remaining} more →`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `Transclude of ${targetSlug}`,
linkToOriginal: "Link to original",
},
search: {
title: "Search",
searchBarPlaceholder: "Search for something",
},
tableOfContents: {
title: "Table of Contents",
},
contentMeta: {
readingTime: ({ minutes }) => `${minutes} min read`,
},
},
pages: {
rss: {
recentNotes: "Recent notes",
lastFewNotes: ({ count }) => `Last ${count} notes`,
},
error: {
title: "Not Found",
notFound: "Either this page is private or doesn't exist.",
home: "Return to Homepage",
},
folderContent: {
folder: "Folder",
itemsUnderFolder: ({ count }) =>
count === 1 ? "1 item under this folder." : `${count} items under this folder.`,
},
tagContent: {
tag: "Tag",
tagIndex: "Tag Index",
itemsUnderTag: ({ count }) =>
count === 1 ? "1 item with this tag." : `${count} items with this tag.`,
showingFirst: ({ count }) => `Showing first ${count} tags.`,
totalTags: ({ count }) => `Found ${count} total tags.`,
},
},
} as const satisfies Translation

View file

@ -65,7 +65,6 @@ export default {
error: {
title: "Not Found",
notFound: "Either this page is private or doesn't exist.",
home: "Return to Homepage",
},
folderContent: {
folder: "Folder",

View file

@ -22,8 +22,8 @@ export default {
quote: "Cita",
},
backlinks: {
title: "Retroenlaces",
noBacklinksFound: "No se han encontrado retroenlaces",
title: "Enlaces de Retroceso",
noBacklinksFound: "No se han encontrado enlaces traseros",
},
themeToggle: {
lightMode: "Modo claro",
@ -54,18 +54,17 @@ export default {
title: "Tabla de Contenidos",
},
contentMeta: {
readingTime: ({ minutes }) => `Se lee en ${minutes} min`,
readingTime: ({ minutes }) => `${minutes} min read`,
},
},
pages: {
rss: {
recentNotes: "Notas recientes",
lastFewNotes: ({ count }) => `Últimas ${count} notas`,
lastFewNotes: ({ count }) => `Últimás ${count} notas`,
},
error: {
title: "No se ha encontrado.",
title: "No se encontró.",
notFound: "Esta página es privada o no existe.",
home: "Regresa a la página principal",
},
folderContent: {
folder: "Carpeta",
@ -78,7 +77,7 @@ export default {
itemsUnderTag: ({ count }) =>
count === 1 ? "1 artículo con esta etiqueta." : `${count} artículos con esta etiqueta.`,
showingFirst: ({ count }) => `Mostrando las primeras ${count} etiquetas.`,
totalTags: ({ count }) => `Se han encontrado ${count} etiquetas en total.`,
totalTags: ({ count }) => `Se encontraron ${count} etiquetas en total.`,
},
},
} as const satisfies Translation

View file

@ -1,84 +0,0 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "بدون عنوان",
description: "توضیح خاصی اضافه نشده است",
},
components: {
callout: {
note: "یادداشت",
abstract: "چکیده",
info: "اطلاعات",
todo: "اقدام",
tip: "نکته",
success: "تیک",
question: "سؤال",
warning: "هشدار",
failure: "شکست",
danger: "خطر",
bug: "باگ",
example: "مثال",
quote: "نقل قول",
},
backlinks: {
title: "بک‌لینک‌ها",
noBacklinksFound: "بدون بک‌لینک",
},
themeToggle: {
lightMode: "حالت روشن",
darkMode: "حالت تاریک",
},
explorer: {
title: "مطالب",
},
footer: {
createdWith: "ساخته شده با",
},
graph: {
title: "نمای گراف",
},
recentNotes: {
title: "یادداشت‌های اخیر",
seeRemainingMore: ({ remaining }) => `${remaining} یادداشت دیگر →`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `از ${targetSlug}`,
linkToOriginal: "پیوند به اصلی",
},
search: {
title: "جستجو",
searchBarPlaceholder: "مطلبی را جستجو کنید",
},
tableOfContents: {
title: "فهرست",
},
contentMeta: {
readingTime: ({ minutes }) => `زمان تقریبی مطالعه: ${minutes} دقیقه`,
},
},
pages: {
rss: {
recentNotes: "یادداشت‌های اخیر",
lastFewNotes: ({ count }) => `${count} یادداشت اخیر`,
},
error: {
title: "یافت نشد",
notFound: "این صفحه یا خصوصی است یا وجود ندارد",
home: "بازگشت به صفحه اصلی",
},
folderContent: {
folder: "پوشه",
itemsUnderFolder: ({ count }) =>
count === 1 ? ".یک مطلب در این پوشه است" : `${count} مطلب در این پوشه است.`,
},
tagContent: {
tag: "برچسب",
tagIndex: "فهرست برچسب‌ها",
itemsUnderTag: ({ count }) =>
count === 1 ? "یک مطلب با این برچسب" : `${count} مطلب با این برچسب.`,
showingFirst: ({ count }) => `در حال نمایش ${count} برچسب.`,
totalTags: ({ count }) => `${count} برچسب یافت شد.`,
},
},
} as const satisfies Translation

View file

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

View file

@ -1,82 +0,0 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Névtelen",
description: "Nincs leírás",
},
components: {
callout: {
note: "Jegyzet",
abstract: "Abstract",
info: "Információ",
todo: "Tennivaló",
tip: "Tipp",
success: "Siker",
question: "Kérdés",
warning: "Figyelmeztetés",
failure: "Hiba",
danger: "Veszély",
bug: "Bug",
example: "Példa",
quote: "Idézet",
},
backlinks: {
title: "Visszautalások",
noBacklinksFound: "Nincs visszautalás",
},
themeToggle: {
lightMode: "Világos mód",
darkMode: "Sötét mód",
},
explorer: {
title: "Fájlböngésző",
},
footer: {
createdWith: "Készítve ezzel:",
},
graph: {
title: "Grafikonnézet",
},
recentNotes: {
title: "Legutóbbi jegyzetek",
seeRemainingMore: ({ remaining }) => `${remaining} további megtekintése →`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `${targetSlug} áthivatkozása`,
linkToOriginal: "Hivatkozás az eredetire",
},
search: {
title: "Keresés",
searchBarPlaceholder: "Keress valamire",
},
tableOfContents: {
title: "Tartalomjegyzék",
},
contentMeta: {
readingTime: ({ minutes }) => `${minutes} perces olvasás`,
},
},
pages: {
rss: {
recentNotes: "Legutóbbi jegyzetek",
lastFewNotes: ({ count }) => `Legutóbbi ${count} jegyzet`,
},
error: {
title: "Nem található",
notFound: "Ez a lap vagy privát vagy nem létezik.",
home: "Vissza a kezdőlapra",
},
folderContent: {
folder: "Mappa",
itemsUnderFolder: ({ count }) => `Ebben a mappában ${count} elem található.`,
},
tagContent: {
tag: "Címke",
tagIndex: "Címke index",
itemsUnderTag: ({ count }) => `${count} elem található ezzel a címkével.`,
showingFirst: ({ count }) => `Első ${count} címke megjelenítve.`,
totalTags: ({ count }) => `Összesen ${count} címke található.`,
},
},
} as const satisfies Translation

View file

@ -65,7 +65,6 @@ export default {
error: {
title: "Non trovato",
notFound: "Questa pagina è privata o non esiste.",
home: "Ritorna alla home page",
},
folderContent: {
folder: "Cartella",

View file

@ -65,7 +65,6 @@ export default {
error: {
title: "Not Found",
notFound: "ページが存在しないか、非公開設定になっています。",
home: "ホームページに戻る",
},
folderContent: {
folder: "フォルダ",

View file

@ -65,7 +65,6 @@ export default {
error: {
title: "Not Found",
notFound: "페이지가 존재하지 않거나 비공개 설정이 되어 있습니다.",
home: "홈페이지로 돌아가기",
},
folderContent: {
folder: "폴더",

View file

@ -66,7 +66,6 @@ export default {
error: {
title: "Niet gevonden",
notFound: "Deze pagina is niet zichtbaar of bestaat niet.",
home: "Keer terug naar de start pagina",
},
folderContent: {
folder: "Map",

View file

@ -1,84 +0,0 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Bez nazwy",
description: "Brak opisu",
},
components: {
callout: {
note: "Notatka",
abstract: "Streszczenie",
info: "informacja",
todo: "Do zrobienia",
tip: "Wskazówka",
success: "Zrobione",
question: "Pytanie",
warning: "Ostrzeżenie",
failure: "Usterka",
danger: "Niebiezpieczeństwo",
bug: "Błąd w kodzie",
example: "Przykład",
quote: "Cytat",
},
backlinks: {
title: "Odnośniki zwrotne",
noBacklinksFound: "Brak połączeń zwrotnych",
},
themeToggle: {
lightMode: "Trzyb jasny",
darkMode: "Tryb ciemny",
},
explorer: {
title: "Przeglądaj",
},
footer: {
createdWith: "Stworzone z użyciem",
},
graph: {
title: "Graf",
},
recentNotes: {
title: "Najnowsze notatki",
seeRemainingMore: ({ remaining }) => `Zobacz ${remaining} nastepnych →`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `Osadzone ${targetSlug}`,
linkToOriginal: "Łącze do oryginału",
},
search: {
title: "Szukaj",
searchBarPlaceholder: "Search for something",
},
tableOfContents: {
title: "Spis treści",
},
contentMeta: {
readingTime: ({ minutes }) => `${minutes} min. czytania `,
},
},
pages: {
rss: {
recentNotes: "Najnowsze notatki",
lastFewNotes: ({ count }) => `Ostatnie ${count} notatek`,
},
error: {
title: "Nie znaleziono",
notFound: "Ta strona jest prywatna lub nie istnieje.",
home: "Powrót do strony głównej",
},
folderContent: {
folder: "Folder",
itemsUnderFolder: ({ count }) =>
count === 1 ? "W tym folderze jest 1 element." : `Elementów w folderze: ${count}.`,
},
tagContent: {
tag: "Znacznik",
tagIndex: "Spis znaczników",
itemsUnderTag: ({ count }) =>
count === 1 ? "Oznaczony 1 element." : `Elementów z tym znacznikiem: ${count}.`,
showingFirst: ({ count }) => `Pokazuje ${count} pierwszych znaczników.`,
totalTags: ({ count }) => `Znalezionych wszystkich znaczników: ${count}.`,
},
},
} as const satisfies Translation

View file

@ -1,84 +0,0 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Sem título",
description: "Sem descrição",
},
components: {
callout: {
note: "Nota",
abstract: "Abstrato",
info: "Info",
todo: "Pendência",
tip: "Dica",
success: "Sucesso",
question: "Pergunta",
warning: "Aviso",
failure: "Falha",
danger: "Perigo",
bug: "Bug",
example: "Exemplo",
quote: "Citação",
},
backlinks: {
title: "Backlinks",
noBacklinksFound: "Sem backlinks encontrados",
},
themeToggle: {
lightMode: "Tema claro",
darkMode: "Tema escuro",
},
explorer: {
title: "Explorador",
},
footer: {
createdWith: "Criado com",
},
graph: {
title: "Visão de gráfico",
},
recentNotes: {
title: "Notas recentes",
seeRemainingMore: ({ remaining }) => `Veja mais ${remaining}`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `Transcrever de ${targetSlug}`,
linkToOriginal: "Link ao original",
},
search: {
title: "Pesquisar",
searchBarPlaceholder: "Pesquisar por algo",
},
tableOfContents: {
title: "Sumário",
},
contentMeta: {
readingTime: ({ minutes }) => `Leitura de ${minutes} min`,
},
},
pages: {
rss: {
recentNotes: "Notas recentes",
lastFewNotes: ({ count }) => `Últimas ${count} notas`,
},
error: {
title: "Não encontrado",
notFound: "Esta página é privada ou não existe.",
home: "Retornar a página inicial",
},
folderContent: {
folder: "Arquivo",
itemsUnderFolder: ({ count }) =>
count === 1 ? "1 item neste arquivo." : `${count} items neste arquivo.`,
},
tagContent: {
tag: "Tag",
tagIndex: "Sumário de Tags",
itemsUnderTag: ({ count }) =>
count === 1 ? "1 item com esta tag." : `${count} items com esta tag.`,
showingFirst: ({ count }) => `Mostrando as ${count} primeiras tags.`,
totalTags: ({ count }) => `Encontradas ${count} tags.`,
},
},
} as const satisfies Translation

View file

@ -66,7 +66,6 @@ export default {
error: {
title: "Pagina nu a fost găsită",
notFound: "Fie această pagină este privată, fie nu există.",
home: "Reveniți la pagina de pornire",
},
folderContent: {
folder: "Dosar",

View file

@ -67,7 +67,6 @@ export default {
error: {
title: "Страница не найдена",
notFound: "Эта страница приватная или не существует",
home: "Вернуться на главную страницу",
},
folderContent: {
folder: "Папка",

View file

@ -54,7 +54,7 @@ export default {
title: "Зміст",
},
contentMeta: {
readingTime: ({ minutes }) => `${minutes} хв читання`,
readingTime: ({ minutes }) => `${minutes} min read`,
},
},
pages: {
@ -65,20 +65,19 @@ export default {
error: {
title: "Не знайдено",
notFound: "Ця сторінка або приватна, або не існує.",
home: "Повернутися на головну сторінку",
},
folderContent: {
folder: "Тека",
folder: "Папка",
itemsUnderFolder: ({ count }) =>
count === 1 ? "У цій теці 1 елемент." : `Елементів у цій теці: ${count}.`,
count === 1 ? "У цій папці 1 елемент." : `Елементів у цій папці: ${count}.`,
},
tagContent: {
tag: "Мітка",
tagIndex: "Індекс мітки",
tag: "Тег",
tagIndex: "Індекс тегу",
itemsUnderTag: ({ count }) =>
count === 1 ? "1 елемент з цією міткою." : `Елементів з цією міткою: ${count}.`,
showingFirst: ({ count }) => `Показ перших ${count} міток.`,
totalTags: ({ count }) => `Всього знайдено міток: ${count}.`,
count === 1 ? "1 елемент з цим тегом." : `Елементів з цим тегом: ${count}.`,
showingFirst: ({ count }) => `Показ перших ${count} тегів.`,
totalTags: ({ count }) => `Всього знайдено тегів: ${count}.`,
},
},
} as const satisfies Translation

View file

@ -65,7 +65,6 @@ export default {
error: {
title: "Không Tìm Thấy",
notFound: "Trang này được bảo mật hoặc không tồn tại.",
home: "Trở về trang chủ",
},
folderContent: {
folder: "Thư Mục",

View file

@ -65,7 +65,6 @@ export default {
error: {
title: "无法找到",
notFound: "私有笔记或笔记不存在。",
home: "返回首页",
},
folderContent: {
folder: "文件夹",

View file

@ -8,6 +8,7 @@ import popoverScript from "../../components/scripts/popover.inline"
import styles from "../../styles/custom.scss"
import popoverStyle from "../../components/styles/popover.scss"
import { BuildCtx } from "../../util/ctx"
import { StaticResources } from "../../util/resources"
import { QuartzComponent } from "../../components/types"
import { googleFontHref, joinStyles } from "../../util/theme"
import { Features, transform } from "lightningcss"
@ -68,8 +69,13 @@ async function joinScripts(scripts: string[]): Promise<string> {
return res.code
}
function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentResources) {
function addGlobalPageResources(
ctx: BuildCtx,
staticResources: StaticResources,
componentResources: ComponentResources,
) {
const cfg = ctx.cfg.configuration
const reloadScript = ctx.argv.serve
// popovers
if (cfg.enablePopovers) {
@ -79,12 +85,12 @@ function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentReso
if (cfg.analytics?.provider === "google") {
const tagId = cfg.analytics.tagId
staticResources.js.push({
src: `https://www.googletagmanager.com/gtag/js?id=${tagId}`,
contentType: "external",
loadTime: "afterDOMReady",
})
componentResources.afterDOMLoaded.push(`
const gtagScript = document.createElement("script")
gtagScript.src = "https://www.googletagmanager.com/gtag/js?id=${tagId}"
gtagScript.async = true
document.head.appendChild(gtagScript)
window.dataLayer = window.dataLayer || [];
function gtag() { dataLayer.push(arguments); }
gtag("js", new Date());
@ -129,29 +135,6 @@ function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentReso
"https://${cfg.analytics.websiteId}.${cfg.analytics.host ?? "goatcounter.com"}/count")
document.head.appendChild(goatcounterScript)
`)
} else if (cfg.analytics?.provider === "posthog") {
componentResources.afterDOMLoaded.push(`
const posthogScript = document.createElement("script")
posthogScript.innerHTML= \`!function(t,e){var o,n,p,r;e.__SV||(window.posthog=e,e._i=[],e.init=function(i,s,a){function g(t,e){var o=e.split(".");2==o.length&&(t=t[o[0]],e=o[1]),t[e]=function(){t.push([e].concat(Array.prototype.slice.call(arguments,0)))}}(p=t.createElement("script")).type="text/javascript",p.async=!0,p.src=s.api_host+"/static/array.js",(r=t.getElementsByTagName("script")[0]).parentNode.insertBefore(p,r);var u=e;for(void 0!==a?u=e[a]=[]:a="posthog",u.people=u.people||[],u.toString=function(t){var e="posthog";return"posthog"!==a&&(e+="."+a),t||(e+=" (stub)"),e},u.people.toString=function(){return u.toString(1)+".people (stub)"},o="capture identify alias people.set people.set_once set_config register register_once unregister opt_out_capturing has_opted_out_capturing opt_in_capturing reset isFeatureEnabled onFeatureFlags getFeatureFlag getFeatureFlagPayload reloadFeatureFlags group updateEarlyAccessFeatureEnrollment getEarlyAccessFeatures getActiveMatchingSurveys getSurveys onSessionId".split(" "),n=0;n<o.length;n++)g(u,o[n]);e._i.push([i,s,a])},e.__SV=1)}(document,window.posthog||[]);
posthog.init('${cfg.analytics.apiKey}',{api_host:'${cfg.analytics.host ?? "https://app.posthog.com"}'})\`
document.head.appendChild(posthogScript)
`)
} else if (cfg.analytics?.provider === "tinylytics") {
const siteId = cfg.analytics.siteId
componentResources.afterDOMLoaded.push(`
const tinylyticsScript = document.createElement("script")
tinylyticsScript.src = "https://tinylytics.app/embed/${siteId}.js"
tinylyticsScript.defer = true
document.head.appendChild(tinylyticsScript)
`)
} else if (cfg.analytics?.provider === "cabin") {
componentResources.afterDOMLoaded.push(`
const cabinScript = document.createElement("script")
cabinScript.src = "${cfg.analytics.host ?? "https://scripts.cabin.dev"}/cabin.js"
cabinScript.defer = true
cabinScript.async = true
document.head.appendChild(cabinScript)
`)
}
if (cfg.enableSPA) {
@ -164,72 +147,115 @@ function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentReso
document.dispatchEvent(event)
`)
}
let wsUrl = `ws://localhost:${ctx.argv.wsPort}`
if (ctx.argv.remoteDevHost) {
wsUrl = `wss://${ctx.argv.remoteDevHost}:${ctx.argv.wsPort}`
}
if (reloadScript) {
staticResources.js.push({
loadTime: "afterDOMReady",
contentType: "inline",
script: `
const socket = new WebSocket('${wsUrl}')
// reload(true) ensures resources like images and scripts are fetched again in firefox
socket.addEventListener('message', () => document.location.reload(true))
`,
})
}
}
// This emitter should not update the `resources` parameter. If it does, partial
// rebuilds may not work as expected.
export const ComponentResources: QuartzEmitterPlugin = () => {
interface Options {
fontOrigin: "googleFonts" | "local"
}
const defaultOptions: Options = {
fontOrigin: "googleFonts",
}
export const ComponentResources: QuartzEmitterPlugin<Options> = (opts?: Partial<Options>) => {
const { fontOrigin } = { ...defaultOptions, ...opts }
return {
name: "ComponentResources",
getQuartzComponents() {
return []
},
async getDependencyGraph(_ctx, _content, _resources) {
return new DepGraph<FilePath>()
async getDependencyGraph(ctx, content, _resources) {
// This emitter adds static resources to the `resources` parameter. One
// important resource this emitter adds is the code to start a websocket
// connection and listen to rebuild messages, which triggers a page reload.
// The resources parameter with the reload logic is later used by the
// ContentPage emitter while creating the final html page. In order for
// the reload logic to be included, and so for partial rebuilds to work,
// we need to run this emitter for all markdown files.
const graph = new DepGraph<FilePath>()
for (const [_tree, file] of content) {
const sourcePath = file.data.filePath!
const slug = file.data.slug!
graph.addEdge(sourcePath, joinSegments(ctx.argv.output, slug + ".html") as FilePath)
}
return graph
},
async emit(ctx, _content, _resources): Promise<FilePath[]> {
async emit(ctx, _content, resources): Promise<FilePath[]> {
const promises: Promise<FilePath>[] = []
const cfg = ctx.cfg.configuration
// component specific scripts and styles
const componentResources = getComponentResources(ctx)
let googleFontsStyleSheet = ""
if (cfg.theme.fontOrigin === "local") {
if (fontOrigin === "local") {
// let the user do it themselves in css
} else if (cfg.theme.fontOrigin === "googleFonts" && !cfg.theme.cdnCaching) {
// when cdnCaching is true, we link to google fonts in Head.tsx
let match
} else if (fontOrigin === "googleFonts") {
if (cfg.theme.cdnCaching) {
resources.css.push(googleFontHref(cfg.theme))
} else {
let match
const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
const fontSourceRegex = /url\((https:\/\/fonts.gstatic.com\/s\/[^)]+\.(woff2|ttf))\)/g
googleFontsStyleSheet = await (
await fetch(googleFontHref(ctx.cfg.configuration.theme))
).text()
googleFontsStyleSheet = await (
await fetch(googleFontHref(ctx.cfg.configuration.theme))
).text()
while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
// match[0] is the `url(path)`, match[1] is the `path`
const url = match[1]
// the static name of this file.
const [filename, ext] = url.split("/").pop()!.split(".")
while ((match = fontSourceRegex.exec(googleFontsStyleSheet)) !== null) {
// match[0] is the `url(path)`, match[1] is the `path`
const url = match[1]
// the static name of this file.
const [filename, ext] = url.split("/").pop()!.split(".")
googleFontsStyleSheet = googleFontsStyleSheet.replace(
url,
`https://${cfg.baseUrl}/static/fonts/${filename}.ttf`,
)
googleFontsStyleSheet = googleFontsStyleSheet.replace(
url,
`/static/fonts/${filename}.ttf`,
)
promises.push(
fetch(url)
.then((res) => {
if (!res.ok) {
throw new Error(`Failed to fetch font`)
}
return res.arrayBuffer()
})
.then((buf) =>
write({
ctx,
slug: joinSegments("static", "fonts", filename) as FullSlug,
ext: `.${ext}`,
content: Buffer.from(buf),
}),
),
)
promises.push(
fetch(url)
.then((res) => {
if (!res.ok) {
throw new Error(`Failed to fetch font`)
}
return res.arrayBuffer()
})
.then((buf) =>
write({
ctx,
slug: joinSegments("static", "fonts", filename) as FullSlug,
ext: `.${ext}`,
content: Buffer.from(buf),
}),
),
)
}
}
}
// important that this goes *after* component scripts
// as the "nav" event gets triggered here and we should make sure
// that everyone else had the chance to register a listener for it
addGlobalPageResources(ctx, componentResources)
addGlobalPageResources(ctx, resources, componentResources)
const stylesheet = joinStyles(
ctx.cfg.configuration.theme,

View file

@ -3,7 +3,7 @@ import { QuartzFilterPlugin } from "../types"
export const RemoveDrafts: QuartzFilterPlugin<{}> = () => ({
name: "RemoveDrafts",
shouldPublish(_ctx, [_tree, vfile]) {
const draftFlag: boolean = vfile.data?.frontmatter?.draft || false
const draftFlag: boolean = vfile.data?.frontmatter?.draft ?? false
return !draftFlag
},
})

View file

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

View file

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

View file

@ -61,7 +61,6 @@ export const Description: QuartzTransformerPlugin<Partial<Options> | undefined>
const currentSentence = sentence.endsWith(".") ? sentence : sentence + "."
finalDesc.push(currentSentence)
currentDescriptionLength += currentSentence.length
sentenceIdx++
}
}

View file

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

View file

@ -93,7 +93,7 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options> | undefined> =
}
node.properties.className = classes
if (isExternal && opts.openLinksInNewTab) {
if (opts.openLinksInNewTab) {
node.properties.target = "_blank"
}

View file

@ -6,7 +6,6 @@ import { slug as slugAnchor } from "github-slugger"
import rehypeRaw from "rehype-raw"
import { SKIP, visit } from "unist-util-visit"
import path from "path"
import { splitAnchor } from "../../util/path"
import { JSResource } from "../../util/resources"
// @ts-ignore
import calloutScript from "../../components/scripts/callout.inline.ts"
@ -100,32 +99,20 @@ export const externalLinkRegex = /^https?:\/\//i
export const arrowRegex = new RegExp(/(-{1,2}>|={1,2}>|<-{1,2}|<={1,2})/, "g")
// !? -> optional embedding
// \[\[ -> open brace
// ([^\[\]\|\#]+) -> one or more non-special characters ([,],|, or #) (name)
// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
// (\\?\|[^\[\]\#]+)? -> optional escape \ then | then one or more non-special characters (alias)
// !? -> optional embedding
// \[\[ -> open brace
// ([^\[\]\|\#]+) -> one or more non-special characters ([,],|, or #) (name)
// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
// (\|[^\[\]\#]+)? -> | then one or more non-special characters (alias)
export const wikilinkRegex = new RegExp(
/!?\[\[([^\[\]\|\#\\]+)?(#+[^\[\]\|\#\\]+)?(\\?\|[^\[\]\#]+)?\]\]/,
/!?\[\[([^\[\]\|\#]+)?(#+[^\[\]\|\#]+)?(\|[^\[\]\#]+)?\]\]/,
"g",
)
// ^\|([^\n])+\|\n(\|) -> matches the header row
// ( ?:?-{3,}:? ?\|)+ -> matches the header row separator
// (\|([^\n])+\|\n)+ -> matches the body rows
export const tableRegex = new RegExp(
/^\|([^\n])+\|\n(\|)( ?:?-{3,}:? ?\|)+\n(\|([^\n])+\|\n?)+/,
"gm",
)
// matches any wikilink, only used for escaping wikilinks inside tables
export const tableWikilinkRegex = new RegExp(/(!?\[\[[^\]]*?\]\])/, "g")
const highlightRegex = new RegExp(/==([^=]+)==/, "g")
const commentRegex = new RegExp(/%%[\s\S]*?%%/, "g")
// from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts
const calloutRegex = new RegExp(/^\[\!(\w+)\|?(.+?)?\]([+-]?)/)
const calloutLineRegex = new RegExp(/^> *\[\!\w+\|?.*?\][+-]?.*$/, "gm")
const calloutRegex = new RegExp(/^\[\!(\w+)\]([+-]?)/)
const calloutLineRegex = new RegExp(/^> *\[\!\w+\][+-]?.*$/, "gm")
// (?:^| ) -> non-capturing group, tag should start be separated by a space or be the start of the line
// #(...) -> capturing group, tag itself must start with #
// (?:[-_\p{L}\d\p{Z}])+ -> non-capturing group, non-empty string of (Unicode-aware) alpha-numeric characters and symbols, hyphens and/or underscores
@ -182,27 +169,13 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
src = src.toString()
}
// replace all wikilinks inside a table first
src = src.replace(tableRegex, (value) => {
// escape all aliases and headers in wikilinks inside a table
return value.replace(tableWikilinkRegex, (value, ...capture) => {
const [raw]: (string | undefined)[] = capture
let escaped = raw ?? ""
escaped = escaped.replace("#", "\\#")
// escape pipe characters if they are not already escaped
escaped = escaped.replace(/((^|[^\\])(\\\\)*)\|/g, "$1\\|")
return escaped
})
})
// replace all other wikilinks
src = src.replace(wikilinkRegex, (value, ...capture) => {
const [rawFp, rawHeader, rawAlias]: (string | undefined)[] = capture
const [fp, anchor] = splitAnchor(`${rawFp ?? ""}${rawHeader ?? ""}`)
const fp = rawFp ?? ""
const anchor = rawHeader?.trim().replace(/^#+/, "")
const blockRef = Boolean(anchor?.startsWith("^")) ? "^" : ""
const displayAnchor = anchor ? `#${blockRef}${anchor.trim().replace(/^#+/, "")}` : ""
const displayAnchor = anchor ? `#${blockRef}${slugAnchor(anchor)}` : ""
const displayAlias = rawAlias ?? rawHeader?.replace("#", "|") ?? ""
const embedDisplay = value.startsWith("!") ? "!" : ""
@ -216,8 +189,9 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
return src
},
markdownPlugins(_ctx) {
markdownPlugins(ctx) {
const plugins: PluggableList = []
const cfg = ctx.cfg.configuration
// regex replacements
plugins.push(() => {
@ -414,8 +388,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
return
}
// find first line and callout content
const [firstChild, ...calloutContent] = node.children
// find first line
const firstChild = node.children[0]
if (firstChild.type !== "paragraph" || firstChild.children[0]?.type !== "text") {
return
}
@ -427,7 +401,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
const match = firstLine.match(calloutRegex)
if (match && match.input) {
const [calloutDirective, typeString, calloutMetaData, collapseChar] = match
const [calloutDirective, typeString, collapseChar] = match
const calloutType = canonicalizeCallout(typeString.toLowerCase())
const collapse = collapseChar === "+" || collapseChar === "-"
const defaultState = collapseChar === "-" ? "collapsed" : "expanded"
@ -489,24 +463,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
className: classNames.join(" "),
"data-callout": calloutType,
"data-callout-fold": collapse,
"data-callout-metadata": calloutMetaData,
},
}
// Add callout-content class to callout body if it has one.
if (calloutContent.length > 0) {
const contentData: BlockContent | DefinitionContent = {
data: {
hProperties: {
className: "callout-content",
},
hName: "div",
},
type: "blockquote",
children: [...calloutContent],
}
node.children = [node.children[0], contentData]
}
}
})
}

View file

@ -488,10 +488,6 @@ video {
flex: 1 1 auto;
}
div:has(> .overflow) {
position: relative;
}
ul.overflow,
ol.overflow {
max-height: 400;
@ -524,8 +520,3 @@ ol.overflow {
padding-left: 1rem;
}
}
.katex-display {
overflow-x: auto;
overflow-y: hidden;
}

View file

@ -10,7 +10,7 @@
transition: max-height 0.3s ease;
box-sizing: border-box;
& > .callout-content > :first-child {
& > *:nth-child(2) {
margin-top: 0;
}

View file

@ -168,9 +168,6 @@ export function resolveRelative(current: FullSlug, target: FullSlug | SimpleSlug
export function splitAnchor(link: string): [string, string] {
let [fp, anchor] = link.split("#", 2)
if (fp.endsWith(".pdf")) {
return [fp, anchor === undefined ? "" : `#${anchor}`]
}
anchor = anchor === undefined ? "" : "#" + slugAnchor(anchor)
return [fp, anchor]
}

View file

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

View file

@ -13,8 +13,8 @@
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true,
"jsx": "react-jsx",
"jsxImportSource": "preact"
"jsxImportSource": "preact",
},
"include": ["**/*.ts", "**/*.tsx", "./package.json"],
"exclude": ["build/**/*.d.ts"]
"exclude": ["build/**/*.d.ts"],
}