Compare commits

...

158 Commits
v4 ... drone-v4

Author SHA1 Message Date
a7b7a5c797
telegram
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-26 19:01:40 +03:00
ea0d791657
telegram
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-26 18:52:05 +03:00
851e05a571
Merge remote-tracking branch 'origin/v4' into drone-v4
All checks were successful
continuous-integration/drone/push Build is passing
# Conflicts:
#	quartz/components/styles/backlinks.scss
2024-10-11 20:56:51 +03:00
2f25a1ba0a
update 4.4.0
All checks were successful
continuous-integration/drone/push Build is passing
2024-10-11 20:43:11 +03:00
b460b61375
Merge tag 'v4.4.0' into drone-v4
v4.4.0

# Conflicts:
#	quartz/components/styles/backlinks.scss
#	quartz/plugins/transformers/links.ts
2024-10-11 20:42:05 +03:00
Pierre Lairez
0d1f15d37c
feat(ofm): Allow for dashes in custom callout label (#1493)
* [OFM] Allow for dashes in custom callout label

For compatibility with Obsidian's behavior, a custom callout like
[!see-also] is possible. Previously, this was parsed by Quartz as a
callout “see” with metadata “-also”. Instead, this is should be a
callout “see-also” with title “See also” (capitalization + replace
dashes by spaces).

* prettier
2024-10-10 07:15:23 -04:00
dependabot[bot]
11c23a137a
chore(deps): bump the production-dependencies group with 9 updates (#1495)
Bumps the production-dependencies group with 9 updates:

| Package | From | To |
| --- | --- | --- |
| [chokidar](https://github.com/paulmillr/chokidar) | `3.6.0` | `4.0.1` |
| [esbuild-sass-plugin](https://github.com/glromeo/esbuild-sass-plugin) | `2.16.1` | `3.3.1` |
| [lightningcss](https://github.com/parcel-bundler/lightningcss) | `1.26.0` | `1.27.0` |
| [preact](https://github.com/preactjs/preact) | `10.24.1` | `10.24.2` |
| [rehype-citation](https://github.com/timlrx/rehype-citation) | `2.1.1` | `2.1.2` |
| [shiki](https://github.com/shikijs/shiki/tree/HEAD/packages/shiki) | `1.18.0` | `1.22.0` |
| [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) | `22.7.4` | `22.7.5` |
| [esbuild](https://github.com/evanw/esbuild) | `0.19.12` | `0.24.0` |
| [typescript](https://github.com/microsoft/TypeScript) | `5.6.2` | `5.6.3` |


Updates `chokidar` from 3.6.0 to 4.0.1
- [Release notes](https://github.com/paulmillr/chokidar/releases)
- [Commits](https://github.com/paulmillr/chokidar/compare/3.6.0...4.0.1)

Updates `esbuild-sass-plugin` from 2.16.1 to 3.3.1
- [Release notes](https://github.com/glromeo/esbuild-sass-plugin/releases)
- [Commits](https://github.com/glromeo/esbuild-sass-plugin/compare/v2.16.1...v3.3.1)

Updates `lightningcss` from 1.26.0 to 1.27.0
- [Release notes](https://github.com/parcel-bundler/lightningcss/releases)
- [Commits](https://github.com/parcel-bundler/lightningcss/compare/v1.26.0...v1.27.0)

Updates `preact` from 10.24.1 to 10.24.2
- [Release notes](https://github.com/preactjs/preact/releases)
- [Commits](https://github.com/preactjs/preact/compare/10.24.1...10.24.2)

Updates `rehype-citation` from 2.1.1 to 2.1.2
- [Release notes](https://github.com/timlrx/rehype-citation/releases)
- [Commits](https://github.com/timlrx/rehype-citation/compare/v2.1.1...v2.1.2)

Updates `shiki` from 1.18.0 to 1.22.0
- [Release notes](https://github.com/shikijs/shiki/releases)
- [Changelog](https://github.com/shikijs/shiki/blob/main/CHANGELOG.md)
- [Commits](https://github.com/shikijs/shiki/commits/v1.22.0/packages/shiki)

Updates `@types/node` from 22.7.4 to 22.7.5
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

Updates `esbuild` from 0.19.12 to 0.24.0
- [Release notes](https://github.com/evanw/esbuild/releases)
- [Changelog](https://github.com/evanw/esbuild/blob/main/CHANGELOG.md)
- [Commits](https://github.com/evanw/esbuild/compare/v0.19.12...v0.24.0)

Updates `typescript` from 5.6.2 to 5.6.3
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.6.2...v5.6.3)

---
updated-dependencies:
- dependency-name: chokidar
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: production-dependencies
- dependency-name: esbuild-sass-plugin
  dependency-type: direct:production
  update-type: version-update:semver-major
  dependency-group: production-dependencies
- dependency-name: lightningcss
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: preact
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: rehype-citation
  dependency-type: direct:production
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: shiki
  dependency-type: direct:production
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: "@types/node"
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
- dependency-name: esbuild
  dependency-type: direct:development
  update-type: version-update:semver-minor
  dependency-group: production-dependencies
- dependency-name: typescript
  dependency-type: direct:development
  update-type: version-update:semver-patch
  dependency-group: production-dependencies
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-09 14:57:33 -07:00
Aaron Pham
8a95c865c8
chore(citations): passthrough options (#1429) 2024-10-09 14:14:44 -04:00
Aaron Pham
fe4b039b60
chore(ci): group dependabot upgrade (#1491)
Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
2024-10-09 09:52:49 -07:00
Aaron Pham
497d51973a
chore(ci): remove signing and vuln (#1484)
Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
2024-10-07 02:52:14 -04:00
Aaron Pham
66d7dd8677
fix(ci): run build on tags (#1483)
* fix(ci): run build on tags

Signed-off-by: Aaron Pham <contact@aarnphm.xyz>

* chore: update docker warning and not push on PR

Signed-off-by: Aaron Pham <contact@aarnphm.xyz>

---------

Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
2024-10-06 22:34:31 -04:00
Julia van der Kris
313cef60ee
infra: build quartz docker image to GHCR (#1192)
* Add GitHub action to build & push Docker image to GHCR

* Use double quotes to keep `prettier` happy :)

* Don't run Docker build & push on forks

* -1 char commit lmao

* Add git metadata to Docker image

* Apply Aaron's patch

* chore: run prettier

---------

Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
Co-authored-by: Aaron Pham <contact@aarnphm.xyz>
2024-10-06 22:15:19 -04:00
KurekMartin
af14ca7c4f
i18n: add Czech translation (#1477)
* add Czech translation

* fix formatting
2024-10-04 09:10:40 -07:00
dependabot[bot]
e06f681ce7
chore(deps): bump preact from 10.24.0 to 10.24.1 (#1464)
Bumps [preact](https://github.com/preactjs/preact) from 10.24.0 to 10.24.1.
- [Release notes](https://github.com/preactjs/preact/releases)
- [Commits](https://github.com/preactjs/preact/compare/10.24.0...10.24.1)

---
updated-dependencies:
- dependency-name: preact
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 04:42:14 -04:00
dependabot[bot]
62906eebd3
chore(deps-dev): bump @types/node from 22.5.5 to 22.7.4 (#1465)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.5.5 to 22.7.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 04:42:02 -04:00
dependabot[bot]
9cd072bfc3
chore(deps): bump hast-util-to-string from 3.0.0 to 3.0.1 (#1466)
Bumps [hast-util-to-string](https://github.com/rehypejs/rehype-minify) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/rehypejs/rehype-minify/releases)
- [Changelog](https://github.com/rehypejs/rehype-minify/blob/main/changelog.md)
- [Commits](https://github.com/rehypejs/rehype-minify/commits)

---
updated-dependencies:
- dependency-name: hast-util-to-string
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 04:41:50 -04:00
dependabot[bot]
319b4497bc
chore(deps-dev): bump tsx from 4.19.0 to 4.19.1 (#1467)
Bumps [tsx](https://github.com/privatenumber/tsx) from 4.19.0 to 4.19.1.
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](https://github.com/privatenumber/tsx/compare/v4.19.0...v4.19.1)

---
updated-dependencies:
- dependency-name: tsx
  dependency-type: direct:development
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-10-02 04:41:36 -04:00
Emile Bangma
b0c079f24a
fix(layout): restore footer to the proper position (#1470)
* fix(layout): restore footer to the proper position

* align ToC scrollbar properly on short headers
2024-10-01 08:49:13 -07:00
dependabot[bot]
1b122a1da0
chore(deps): bump @floating-ui/dom from 1.6.10 to 1.6.11 (#1463)
Bumps [@floating-ui/dom](https://github.com/floating-ui/floating-ui/tree/HEAD/packages/dom) from 1.6.10 to 1.6.11.
- [Release notes](https://github.com/floating-ui/floating-ui/releases)
- [Changelog](https://github.com/floating-ui/floating-ui/blob/master/packages/dom/CHANGELOG.md)
- [Commits](https://github.com/floating-ui/floating-ui/commits/@floating-ui/dom@1.6.11/packages/dom)

---
updated-dependencies:
- dependency-name: "@floating-ui/dom"
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-30 20:10:05 -04:00
Malcolm Mielle
b8c46ba81a
feat(analytics): clarity (#1446)
Add the code necessary for support of Microsoft clarity
2024-09-30 10:06:37 -07:00
Emile Bangma
1416f62a47
fix(layout): backlinks grid triage (#1447)
* fix: mobile backlinks orientation

* temp: hide broken list gradient

* fix: backlinks overflow
2024-09-29 22:24:15 -04:00
Jacky Zhao
8889ab63eb fix: provide default pageTitleSuffix (closes #1452) 2024-09-28 09:38:19 -07:00
Emile Bangma
5eec1e98e6
fix(layout): grid triage with backlinks (#1442) 2024-09-25 18:15:07 -04:00
Emile Bangma
a7a0dcad22
fix(layout): grid triage and regression (#1440)
* fix(table of contents): multiple scrollbars (https://github.com/jackyzha0/quartz/issues/1388)

* fix(center): Main content mininum width (https://github.com/jackyzha0/quartz/issues/1439)

* fix(code block): Horizontal overflow fix (https://github.com/jackyzha0/quartz/issues/1438, https://github.com/jackyzha0/quartz/issues/1353)

* WIP fix for ul/ol .overflow

* Fix: restore former scrollbar behavior for overflow lists (https://github.com/jackyzha0/quartz/issues/1437)

* Fix: code block overflow-x

* fix: Table of Content overflow (https://github.com/jackyzha0/quartz/issues/1437)

* Address feedback

* Move max-height toggle from js to css
2024-09-25 17:20:58 -04:00
threehymns
921f45cf70
feat: add a config option for a pageTitleSuffix (#1320)
* feat: add a config option for a pageTitleSuffix

* Run Prettier on Head.tsx

* Make pageTitleSuffix optional

Co-authored-by: Aaron Pham <Aaronpham0103@gmail.com>

---------

Co-authored-by: Aaron Pham <Aaronpham0103@gmail.com>
2024-09-24 20:20:36 -04:00
dependabot[bot]
90c187587f
chore(deps): bump pixi.js from 8.3.4 to 8.4.1 (#1432)
Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.3.4 to 8.4.1.
- [Release notes](https://github.com/pixijs/pixijs/releases)
- [Commits](https://github.com/pixijs/pixijs/compare/v8.3.4...v8.4.1)

---
updated-dependencies:
- dependency-name: pixi.js
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-24 20:19:48 -04:00
dependabot[bot]
08e20a7006
chore(deps): bump remark-rehype from 11.1.0 to 11.1.1 (#1435)
Bumps [remark-rehype](https://github.com/remarkjs/remark-rehype) from 11.1.0 to 11.1.1.
- [Release notes](https://github.com/remarkjs/remark-rehype/releases)
- [Commits](https://github.com/remarkjs/remark-rehype/compare/11.1.0...11.1.1)

---
updated-dependencies:
- dependency-name: remark-rehype
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-24 20:19:37 -04:00
dependabot[bot]
9e32016508
chore(deps): bump rehype-pretty-code from 0.13.2 to 0.14.0 (#1433)
Bumps [rehype-pretty-code](https://github.com/rehype-pretty/rehype-pretty-code/tree/HEAD/packages/core) from 0.13.2 to 0.14.0.
- [Release notes](https://github.com/rehype-pretty/rehype-pretty-code/releases)
- [Changelog](https://github.com/rehype-pretty/rehype-pretty-code/blob/master/packages/core/CHANGELOG.md)
- [Commits](https://github.com/rehype-pretty/rehype-pretty-code/commits/rehype-pretty-code@0.14.0/packages/core)

---
updated-dependencies:
- dependency-name: rehype-pretty-code
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-24 20:19:25 -04:00
dependabot[bot]
8a050c0be0
chore(deps): bump hast-util-to-html from 9.0.2 to 9.0.3 (#1434)
Bumps [hast-util-to-html](https://github.com/syntax-tree/hast-util-to-html) from 9.0.2 to 9.0.3.
- [Release notes](https://github.com/syntax-tree/hast-util-to-html/releases)
- [Commits](https://github.com/syntax-tree/hast-util-to-html/compare/9.0.2...9.0.3)

---
updated-dependencies:
- dependency-name: hast-util-to-html
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-24 20:19:12 -04:00
dependabot[bot]
0aacd8ed2e
chore(deps): bump shiki from 1.12.1 to 1.18.0 (#1436)
Bumps [shiki](https://github.com/shikijs/shiki/tree/HEAD/packages/shiki) from 1.12.1 to 1.18.0.
- [Release notes](https://github.com/shikijs/shiki/releases)
- [Changelog](https://github.com/shikijs/shiki/blob/main/CHANGELOG.md)
- [Commits](https://github.com/shikijs/shiki/commits/v1.18.0/packages/shiki)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-24 20:18:55 -04:00
Emile Bangma
7d7e334976
feat: responsive design grid (#1354)
* Responsive design grid

* Addressed PR feedback

* Bump Quartz version 4.3.1 => 4.4.0

* Moved page-header into center

* Updated docs with new layouts

* Sync updated version number with package-lock

* Table of Content scrollbar auto

* Reset node_modules

* Updated layout images

* Fixed tablet layout

* Finilazed layout images
2024-09-23 13:40:12 -07:00
Jacky Zhao
9cefcd0dd1 Revert "perf: eagerly compute explorer nodes to avoid re-render in memoized value"
This reverts commit 16a9caa555.
2024-09-20 15:48:14 -07:00
Gustavo de Paula
4aaeb768d8
update cabin url (#1428) 2024-09-20 09:23:19 -07:00
d7b034e20b
added openssh-client
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-18 19:30:02 +03:00
ca678d0237
подробнее 2024-09-17 22:09:20 +03:00
bf31677330
Добавил кириллицу
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-17 21:49:30 +03:00
e03c526ddb
strong style
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-17 08:18:44 +03:00
dependabot[bot]
743ef712d5
chore(deps): bump preact-render-to-string from 6.5.10 to 6.5.11 (#1417)
Bumps [preact-render-to-string](https://github.com/preactjs/preact-render-to-string) from 6.5.10 to 6.5.11.
- [Release notes](https://github.com/preactjs/preact-render-to-string/releases)
- [Changelog](https://github.com/preactjs/preact-render-to-string/blob/main/CHANGELOG.md)
- [Commits](https://github.com/preactjs/preact-render-to-string/compare/v6.5.10...v6.5.11)

---
updated-dependencies:
- dependency-name: preact-render-to-string
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 22:24:03 -04:00
dependabot[bot]
9a6e4e2f80
chore(deps-dev): bump typescript from 5.5.4 to 5.6.2 (#1418)
Bumps [typescript](https://github.com/microsoft/TypeScript) from 5.5.4 to 5.6.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Changelog](https://github.com/microsoft/TypeScript/blob/main/azure-pipelines.release.yml)
- [Commits](https://github.com/microsoft/TypeScript/compare/v5.5.4...v5.6.2)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 19:56:14 -04:00
dependabot[bot]
14cb50de9b
chore(deps): bump preact from 10.23.2 to 10.24.0 (#1419)
Bumps [preact](https://github.com/preactjs/preact) from 10.23.2 to 10.24.0.
- [Release notes](https://github.com/preactjs/preact/releases)
- [Commits](https://github.com/preactjs/preact/compare/10.23.2...10.24.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 19:56:00 -04:00
dependabot[bot]
dad0ae4e3f
chore(deps-dev): bump @types/node from 22.5.4 to 22.5.5 (#1420)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.5.4 to 22.5.5.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 19:55:42 -04:00
dependabot[bot]
9c060f3cf2
chore(deps): bump vfile from 6.0.2 to 6.0.3 (#1421)
Bumps [vfile](https://github.com/vfile/vfile) from 6.0.2 to 6.0.3.
- [Release notes](https://github.com/vfile/vfile/releases)
- [Changelog](https://github.com/vfile/vfile/blob/main/changelog.md)
- [Commits](https://github.com/vfile/vfile/compare/6.0.2...6.0.3)

---
updated-dependencies:
- dependency-name: vfile
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-16 19:55:23 -04:00
Jacky Zhao
16a9caa555 perf: eagerly compute explorer nodes to avoid re-render in memoized value 2024-09-15 18:05:17 -07:00
Alexander Weichart
b1c60b8833
Add alexanderweichart.de to showcase.md (#1378)
Added my own website ^^

Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
2024-09-15 17:03:22 -07:00
Jacky Zhao
50a78bafa5 docs: clarify prod hosting 2024-09-15 16:47:11 -07:00
Jacky Zhao
6ea359e55e perf: have more than 1ms granularity for rebuild detection 2024-09-15 16:42:07 -07:00
Emile Bangma
cd3bb25626
fix: account for subtags in numerical tags (closes #1408) (#1410) 2024-09-15 11:25:31 -04:00
bfahrenfort
eb9bbd1666
fix: constrain link icon size (#1409) 2024-09-14 10:10:01 -07:00
dependabot[bot]
c36551310d
chore(deps): bump preact-render-to-string from 6.5.9 to 6.5.10 (#1390)
Bumps [preact-render-to-string](https://github.com/preactjs/preact-render-to-string) from 6.5.9 to 6.5.10.
- [Release notes](https://github.com/preactjs/preact-render-to-string/releases)
- [Changelog](https://github.com/preactjs/preact-render-to-string/blob/main/CHANGELOG.md)
- [Commits](https://github.com/preactjs/preact-render-to-string/compare/v6.5.9...v6.5.10)

---
updated-dependencies:
- dependency-name: preact-render-to-string
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 14:46:22 -07:00
Jacky Zhao
6215dd5565 docs: fix roam research docs 2024-09-11 14:45:04 -07:00
dependabot[bot]
c89c76b40a
chore(deps-dev): bump tsx from 4.18.0 to 4.19.0 (#1391)
Bumps [tsx](https://github.com/privatenumber/tsx) from 4.18.0 to 4.19.0.
- [Release notes](https://github.com/privatenumber/tsx/releases)
- [Changelog](https://github.com/privatenumber/tsx/blob/master/release.config.cjs)
- [Commits](https://github.com/privatenumber/tsx/compare/v4.18.0...v4.19.0)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 03:30:44 -04:00
dependabot[bot]
a145e320d0
chore(deps): bump hast-util-to-html from 9.0.1 to 9.0.2 (#1393)
Bumps [hast-util-to-html](https://github.com/syntax-tree/hast-util-to-html) from 9.0.1 to 9.0.2.
- [Release notes](https://github.com/syntax-tree/hast-util-to-html/releases)
- [Commits](https://github.com/syntax-tree/hast-util-to-html/compare/9.0.1...9.0.2)

---
updated-dependencies:
- dependency-name: hast-util-to-html
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 03:30:28 -04:00
dependabot[bot]
082cbb74c3
chore(deps-dev): bump @types/node from 22.5.0 to 22.5.4 (#1403)
Bumps [@types/node](https://github.com/DefinitelyTyped/DefinitelyTyped/tree/HEAD/types/node) from 22.5.0 to 22.5.4.
- [Release notes](https://github.com/DefinitelyTyped/DefinitelyTyped/releases)
- [Commits](https://github.com/DefinitelyTyped/DefinitelyTyped/commits/HEAD/types/node)

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

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 03:29:51 -04:00
dependabot[bot]
93b2481261
chore(deps): bump pixi.js from 8.3.3 to 8.3.4 (#1394)
Bumps [pixi.js](https://github.com/pixijs/pixijs) from 8.3.3 to 8.3.4.
- [Release notes](https://github.com/pixijs/pixijs/releases)
- [Commits](https://github.com/pixijs/pixijs/compare/v8.3.3...v8.3.4)

---
updated-dependencies:
- dependency-name: pixi.js
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-09-11 03:29:36 -04:00
Matt Vogel
d2414b3903
feat(markdown): Roam Research flavour (#985)
* feat: Roam Research flavor markdown

* docs: Roam Research transformer

* use markdownPlugins

* fix roam matching

* cleanup: Roam Plugin

---------

Co-authored-by: Matt Vogel <>
2024-09-11 03:29:07 -04:00
e6795bdea4
checkbox style
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-09 20:19:03 +03:00
fd1cadaa65
popover-hint
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 22:20:46 +03:00
91c1afeaf0
change favicon
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 22:11:23 +03:00
e3f2929bf0
backlinks
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 22:07:19 +03:00
942c5f16f1
header size
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 21:22:41 +03:00
7154af060d
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 16:20:04 +03:00
545e39fdd2
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 15:41:35 +03:00
3056b74cb9
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 15:38:57 +03:00
b5ec2662fc
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 15:01:01 +03:00
29b60d6264
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 14:55:35 +03:00
1bc0820daf
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 14:44:44 +03:00
f02f6c01b7
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 14:38:50 +03:00
cba2e5a1c6
_SocialShare.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 14:30:35 +03:00
a574b10e55
code block style
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 14:02:57 +03:00
51f31934d1
custom.scss
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-08 01:07:10 +03:00
f5c1ce115f
Revert "update Tags"
All checks were successful
continuous-integration/drone/push Build is passing
This reverts commit 7438fca363.
2024-09-08 00:59:39 +03:00
7438fca363
update Tags
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-07 23:43:08 +03:00
04b9cff4fe
randompage
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 20:10:55 +03:00
441148fe84
fixed lastmod.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 19:29:51 +03:00
7e8995ef2e
fixed lastmod.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 17:36:30 +03:00
0f02b9ba3d
fixed lastmod.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 17:29:31 +03:00
22f5e4d213
fixed lastmod.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 12:34:06 +03:00
22f1b7a476
fixed lastmod.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 12:00:56 +03:00
296787d242
fixed lastmod.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 11:46:48 +03:00
b4654a24e2
fixed lastmod.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 11:40:05 +03:00
74ae3057f3
fixed .dockerignore 2024-09-07 11:36:44 +03:00
738dd0024a
fixed .dockerignore 2024-09-07 11:30:42 +03:00
26e0e5dd22
fixed .dockerignore
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 11:22:27 +03:00
e3c4262834
fixed .dockerignore
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 11:15:27 +03:00
145acf4128
попытка настроить время материала
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 11:06:53 +03:00
c2b3b77dcc
Revert "попытка настроить время материала"
This reverts commit 038aad9015.
2024-09-07 11:06:21 +03:00
6f04db5d09
Упрощение сборки 2024-09-07 11:04:55 +03:00
038aad9015
попытка настроить время материала 2024-09-07 11:04:55 +03:00
a7fc2b4ab2
update
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 01:19:00 +03:00
a1505797e7
remark
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-07 01:15:49 +03:00
0d35db3843
remark
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 00:48:52 +03:00
98679a6aac
styles
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-07 00:41:53 +03:00
07923196fb
remark
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-07 00:24:29 +03:00
2e1d270837
recent-notes
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-07 00:20:29 +03:00
130acb922e
recent-notes
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 23:43:31 +03:00
81a5ebc419
hearders styles
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-06 23:40:51 +03:00
61c6720285
text-highlight
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 23:15:24 +03:00
3256f3eba1
update _Remark.tsx
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-06 17:44:40 +03:00
a8c42da44a
update _Remark.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 16:35:53 +03:00
320ab1896f
update ads
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-06 16:23:14 +03:00
8df0eb6473
update ads
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 16:01:03 +03:00
55ce3dd934
.article-title
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 01:44:04 +03:00
2e47bf6d04
.article-title
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-06 01:43:03 +03:00
b9e4c6f74e
font-size: 1.1em;
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 01:19:01 +03:00
be47c4a10a
Улучшение страницы тегов
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-06 01:14:27 +03:00
91313ee4b1
Возможность отключать комментарии
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 00:59:08 +03:00
bd0273e94d
updated Ads
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-06 00:36:24 +03:00
3a4307e24d
updated Ads
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 23:42:38 +03:00
691755ac0b
updated Ads
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 23:26:26 +03:00
63e82e5765
updated Ads
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 22:31:34 +03:00
5899506986
updated Ads
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 22:26:41 +03:00
4fbaa69a5a
added YandexMetrika
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 22:18:41 +03:00
41109cec4f
added _Ads
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 21:57:39 +03:00
17ade1f8bd
updated Backlinks.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 04:26:57 +03:00
5742c813e8
updated Footer.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 03:45:44 +03:00
0eefe283d9
updated Footer.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 03:32:27 +03:00
9d8ce1fd58
updated Footer.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 03:20:34 +03:00
9533c27baf
updated Footer.tsx 2024-09-05 03:20:21 +03:00
7f3f5bb174
updated _GithubSource.tsx
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 03:17:53 +03:00
99ad1dfc9f
updated _GithubSource.tsx
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 03:11:28 +03:00
58ac6e8153
updated Footer
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 02:37:49 +03:00
6c56d46980
updated _GithubSource.tsx
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 02:36:35 +03:00
eea2bb1465
fixed Remark.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 02:21:06 +03:00
f0d099da8d
fixed Backlinks.tsx
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 02:18:52 +03:00
656af4a884
fixed _GithubSource.tsx
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 02:11:45 +03:00
5ec339cc4c
fixed index.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 01:43:59 +03:00
08d94b6ce3
fixed index.ts
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 01:27:25 +03:00
c7607067db
fixed Backlinks.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 00:58:39 +03:00
2fa8800f15
import new components
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 00:51:44 +03:00
230e6b4175
added _ScrollToTop.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-05 00:11:30 +03:00
ae7f306356
changed randompage
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 00:07:22 +03:00
264667683b
changed 404
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-05 00:04:26 +03:00
6f5b5b9a18
added _GithubSource.tsx
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 23:56:25 +03:00
6cbe8bffbc
Dockerfile added git
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 23:33:45 +03:00
01256a5ae1
custom css
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 22:35:03 +03:00
764c15cd90
custom css
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-04 22:31:55 +03:00
79a33c8271
custom css
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-04 22:30:30 +03:00
3e70f7c79a
custom css
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-04 22:26:09 +03:00
b3afab86fd
custom css
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-04 22:23:03 +03:00
b6cde7ac96
custom css
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 21:54:51 +03:00
c299e1e3e3
quartz deleted
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 21:33:35 +03:00
92ac595aa6
changed icon
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-04 21:29:00 +03:00
743d34fe5d
changed icon
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-04 21:26:51 +03:00
133a34259b
changed recentNotes.scss
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-04 20:16:07 +03:00
269b89e7de
added remark42
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-03 16:48:33 +03:00
db4b14d53c
added remark42
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-03 16:47:35 +03:00
db3eba231f
added zip_image.sh
All checks were successful
continuous-integration/drone/push Build is passing
2024-09-03 15:09:18 +03:00
11cd9295b2
added remark42
Some checks failed
continuous-integration/drone/push Build is failing
2024-09-03 08:56:05 +03:00
becfc27348
fixed Dockerfile
Some checks failed
continuous-integration/drone/push Build is failing
continuous-integration/drone/tag Build is passing
2024-09-01 17:44:29 +03:00
02f1f6e56a
Revert "fixed Dockerfile"
All checks were successful
continuous-integration/drone/tag Build is passing
This reverts commit 650596f88b.
2024-09-01 16:52:46 +03:00
650596f88b
fixed Dockerfile
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-01 16:52:08 +03:00
d82b9d059b
fixed Dockerfile 2024-09-01 16:51:31 +03:00
3c37ee024b
fixed Dockerfile
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build was killed
2024-09-01 16:43:44 +03:00
b748adc8a9
fixed Dockerfile
Some checks are pending
continuous-integration/drone/push Build is pending
continuous-integration/drone/tag Build is passing
2024-09-01 16:01:31 +03:00
f56ed6f78b
fixed Dockerfile
Some checks reported errors
continuous-integration/drone/tag Build was killed
continuous-integration/drone/push Build was killed
2024-09-01 15:54:25 +03:00
5dccc2e4cf
fixed Dockerfile
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build is passing
2024-09-01 15:16:11 +03:00
e9ebe3dfe1
fixed cicd
Some checks reported errors
continuous-integration/drone/push Build was killed
continuous-integration/drone/tag Build is failing
2024-09-01 14:23:20 +03:00
44acdbb47e
added cicd
Some checks reported errors
continuous-integration/drone/push Build was killed
2024-09-01 14:20:13 +03:00
72 changed files with 3452 additions and 536 deletions

21
.dockerignore Normal file
View File

@ -0,0 +1,21 @@
.git
.github
.drone.yml
.gitattributes
.idea
.vscode
*.swp
.DS_Store
Thumbs.db
*.log
*.tmp
*.md
docs
.gitignore
LICENSE.txt
CODE_OF_CONDUCT.md
Dockerfile
.dockerignore
quartz.config.ts
quartz.layout.ts
content

100
.drone.yml Normal file
View File

@ -0,0 +1,100 @@
---
kind: pipeline
type: docker
name: docker-build-and-push
trigger:
branch:
- drone-v4
image_pull_secrets:
- DOCKER_AUTH
services:
- name: docker
# https://hub.docker.com/r/library/docker
image: hub.docker.struchkov.dev/docker:27.3.1-dind-alpine3.20
privileged: true
volumes:
- name: dockersock
path: /var/run
volumes:
- name: dockersock
temp: {}
steps:
- name: docker build an publish
# https://hub.docker.com/r/library/docker
image: docker.struchkov.dev/docker-buildx:latest
environment:
DOCKER_REGISTRY_TOKEN:
from_secret: DOCKER_REGISTRY_TOKEN
DOCKER_REGISTRY_USER:
from_secret: DOCKER_REGISTRY_USER
volumes:
- name: dockersock
path: /var/run
commands:
- sleep 15
- echo "$DOCKER_REGISTRY_TOKEN" | docker login docker.struchkov.dev --username $DOCKER_REGISTRY_USER --password-stdin
- echo "$DOCKER_REGISTRY_TOKEN" | docker login hub.docker.struchkov.dev --username $DOCKER_REGISTRY_USER --password-stdin
- docker build -t "docker.struchkov.dev/quartz:develop" .
- docker push docker.struchkov.dev/quartz:develop
# - docker buildx create --use
# - docker buildx build --push --platform linux/arm/v7,linux/arm64/v8,linux/amd64 -t "docker.struchkov.dev/quartz:develop" .
---
kind: pipeline
type: docker
name: docker-build-and-push-release
trigger:
ref:
- refs/tags/v*
image_pull_secrets:
- DOCKER_AUTH
volumes:
- name: node_cache_quartz
host:
path: /drone/volume/node_modules/quartz_release
- name: dockersock
temp: {}
services:
- name: docker
# https://hub.docker.com/r/library/docker
image: hub.docker.struchkov.dev/docker:27.3.1-dind-alpine3.20
privileged: true
volumes:
- name: dockersock
path: /var/run
steps:
- name: docker build an publish
image: docker.struchkov.dev/docker-buildx:latest
environment:
DOCKER_REGISTRY_TOKEN:
from_secret: DOCKER_REGISTRY_TOKEN
DOCKER_REGISTRY_USER:
from_secret: DOCKER_REGISTRY_USER
volumes:
- name: node_cache_quartz
path: ${DRONE_WORKSPACE}/node_modules
- name: dockersock
path: /var/run
commands:
- sleep 15
- echo "$DOCKER_REGISTRY_TOKEN" | docker login docker.struchkov.dev --username $DOCKER_REGISTRY_USER --password-stdin
- echo "$DOCKER_REGISTRY_TOKEN" | docker login hub.docker.struchkov.dev --username $DOCKER_REGISTRY_USER --password-stdin
- docker buildx create --use
- docker buildx build --push --platform linux/arm/v7,linux/arm64/v8,linux/amd64 -t "docker.struchkov.dev/quartz:latest" -t "docker.struchkov.dev/quartz:$DRONE_TAG" .
# drone sign --save DockerFiles/quartz
---
kind: signature
hmac: e9c189beaff93f08b6126416d28bbf1bef7675454c8fa5338fcbb28397c0c538
...

View File

@ -1,11 +1,11 @@
# To get started with Dependabot version updates, you'll need to specify which
# package ecosystems to update and where the package manifests are located.
# Please see the documentation for all configuration options:
# https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file
version: 2 version: 2
updates: updates:
- package-ecosystem: "npm" - package-ecosystem: "npm"
directory: "/" directory: "/"
schedule: schedule:
interval: "weekly" interval: "weekly"
groups:
production-dependencies:
applies-to: "version-updates"
patterns:
- "*"

View File

@ -0,0 +1,88 @@
name: Docker build & push image
on:
push:
branches: [v4]
tags: ["v*"]
pull_request:
branches: [v4]
paths:
- .github/workflows/docker-build-push.yaml
- quartz/**
workflow_dispatch:
jobs:
build:
if: ${{ github.repository == 'jackyzha0/quartz' }} # Comment this out if you want to publish your own images on a fork!
runs-on: ubuntu-latest
steps:
- name: Set lowercase repository owner environment variable
run: |
echo "OWNER_LOWERCASE=${OWNER,,}" >> ${GITHUB_ENV}
env:
OWNER: "${{ github.repository_owner }}"
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Inject slug/short variables
uses: rlespinasse/github-slug-action@v4.4.1
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
with:
install: true
driver-opts: |
image=moby/buildkit:master
network=host
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@v3.7.0
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
if: github.event_name != 'pull_request'
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata tags and labels on PRs
if: github.event_name == 'pull_request'
id: meta-pr
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ env.OWNER_LOWERCASE }}/quartz
tags: |
type=raw,value=sha-${{ env.GITHUB_SHA_SHORT }}
labels: |
org.opencontainers.image.source="https://github.com/${{ github.repository_owner }}/quartz"
- name: Extract metadata tags and labels for main, release or tag
if: github.event_name != 'pull_request'
id: meta
uses: docker/metadata-action@v5
with:
flavor: |
latest=auto
images: ghcr.io/${{ env.OWNER_LOWERCASE }}/quartz
tags: |
type=semver,pattern={{version}}
type=semver,pattern={{major}}.{{minor}}
type=semver,pattern={{major}}.{{minor}}.{{patch}}
type=raw,value=latest,enable=${{ github.ref == format('refs/heads/{0}', github.event.repository.default_branch) }}
type=raw,value=sha-${{ env.GITHUB_SHA_SHORT }}
labels: |
maintainer=${{ github.repository_owner }}
org.opencontainers.image.source="https://github.com/${{ github.repository_owner }}/quartz"
- name: Build and push Docker image
id: build-and-push
uses: docker/build-push-action@v6
with:
push: ${{ github.event_name != 'pull_request' }}
build-args: |
GIT_SHA=${{ env.GITHUB_SHA }}
DOCKER_LABEL=sha-${{ env.GITHUB_SHA_SHORT }}
tags: ${{ steps.meta.outputs.tags || steps.meta-pr.outputs.tags }}
labels: ${{ steps.meta.outputs.labels || steps.meta-pr.outputs.labels }}
cache-from: type=gha
cache-to: type=gha

View File

@ -1,11 +1,24 @@
FROM node:20-slim as builder FROM node:20-slim AS builder
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY package.json . COPY package.json .
COPY package-lock.json* . COPY package-lock.json* .
RUN npm ci RUN npm ci
FROM node:20-slim FROM node:20-alpine
RUN apk update && apk add --no-cache \
optipng \
advancecomp \
pngcrush \
jpegoptim \
libwebp-tools \
findutils \
bash \
git \
openssh-client \
coreutils
WORKDIR /usr/src/app WORKDIR /usr/src/app
COPY --from=builder /usr/src/app/ /usr/src/app/ COPY --from=builder /usr/src/app/ /usr/src/app/
COPY . . COPY . .
CMD ["npx", "quartz", "build", "--serve"] #RUN chmod +x zip_image.sh
ENTRYPOINT ["npx", "quartz"]

View File

@ -21,3 +21,7 @@ This will start a local web server to run your Quartz on your computer. Open a w
> - `--serve`: run a local hot-reloading server to preview your Quartz > - `--serve`: run a local hot-reloading server to preview your Quartz
> - `--port`: what port to run the local preview server on > - `--port`: what port to run the local preview server on
> - `--concurrency`: how many threads to use to parse notes > - `--concurrency`: how many threads to use to parse notes
> [!warning] Not to be used for production
> Serve mode is intended for local previews only.
> For production workloads, see the page on [[hosting]].

View File

@ -21,6 +21,7 @@ const config: QuartzConfig = {
This part of the configuration concerns anything that can affect the whole site. The following is a list breaking down all the things you can configure: This part of the configuration concerns anything that can affect the whole site. The following is a list breaking down all the things you can configure:
- `pageTitle`: title of the site. This is also used when generating the [[RSS Feed]] for your site. - `pageTitle`: title of the site. This is also used when generating the [[RSS Feed]] for your site.
- `pageTitleSuffix`: a string added to the end of the page title. This only applies to the browser tab title, not the title shown at the top of the page.
- `enableSPA`: whether to enable [[SPA Routing]] on your site. - `enableSPA`: whether to enable [[SPA Routing]] on your site.
- `enablePopovers`: whether to enable [[popover previews]] on your site. - `enablePopovers`: whether to enable [[popover previews]] on your site.
- `analytics`: what to use for analytics on your site. Values can be - `analytics`: what to use for analytics on your site. Values can be
@ -32,6 +33,7 @@ This part of the configuration concerns anything that can affect the whole site.
- `{ provider: 'posthog', apiKey: '<your-posthog-project-apiKey>', host: '<your-posthog-host>' }`: use [Posthog](https://posthog.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: '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: 'cabin' }` or `{ provider: 'cabin', host: 'https://cabin.example.com' }` (custom domain): use [Cabin](https://withcabin.com);
- `{provider: 'clarity', projectId: '<your-clarity-id-code' }`: use [Microsoft clarity](https://clarity.microsoft.com/). The project id can be found on top of the overview page.
- `locale`: used for [[i18n]] and date formatting - `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. - `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`. - 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`.
@ -101,7 +103,7 @@ transformers: [
] ]
``` ```
Some plugins are included by default in the[ `quartz.config.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz.config.ts), but there are more available. Some plugins are included by default in the [`quartz.config.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz.config.ts), but there are more available.
You can see a list of all plugins and their configuration options [[tags/plugin|here]]. You can see a list of all plugins and their configuration options [[tags/plugin|here]].

View File

@ -0,0 +1,28 @@
---
title: "Roam Research Compatibility"
tags:
- feature/transformer
---
[Roam Research](https://roamresearch.com) is a note-taking tool that organizes your knowledge graph in a unique and interconnected way.
Quartz supports transforming the special Markdown syntax from Roam Research (like `{{[[components]]}}` and other formatting) into
regular Markdown via the [[RoamFlavoredMarkdown]] plugin.
```typescript title="quartz.config.ts"
plugins: {
transformers: [
// ...
Plugin.RoamFlavoredMarkdown(),
Plugin.ObsidianFlavoredMarkdown(),
// ...
],
},
```
> [!warning]
> As seen above placement of `Plugin.RoamFlavoredMarkdown()` within `quartz.config.ts` is very important. It must come before `Plugin.ObsidianFlavoredMarkdown()`.
## Customization
This functionality is provided by the [[RoamFlavoredMarkdown]] plugin. See the plugin page for customization options.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -13,15 +13,19 @@ export interface FullPageLayout {
beforeBody: QuartzComponent[] // laid out vertically beforeBody: QuartzComponent[] // laid out vertically
pageBody: QuartzComponent // single component pageBody: QuartzComponent // single component
afterBody: QuartzComponent[] // laid out vertically afterBody: QuartzComponent[] // laid out vertically
left: QuartzComponent[] // vertical on desktop, horizontal on mobile left: QuartzComponent[] // vertical on desktop and tablet, horizontal on mobile
right: QuartzComponent[] // vertical on desktop, horizontal on mobile right: QuartzComponent[] // vertical on desktop, horizontal on tablet and mobile
footer: QuartzComponent // single component footer: QuartzComponent // single component
} }
``` ```
These correspond to following parts of the page: These correspond to following parts of the page:
![[quartz layout.png|800]] | Layout | Preview |
| ------------------------------- | ----------------------------------- |
| Desktop (width > 1200px) | ![[quartz-layout-desktop.png\|800]] |
| Tablet (800px < width < 1200px) | ![[quartz-layout-tablet.png\|800]] |
| Mobile (width < 800px) | ![[quartz-layout-mobile.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.
@ -33,6 +37,23 @@ Quartz **components**, like plugins, can take in additional properties as config
See [a list of all the components](component.md) for all available components along with their configuration options. You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz. See [a list of all the components](component.md) for all available components along with their configuration options. You can also checkout the guide on [[creating components]] if you're interested in further customizing the behaviour of Quartz.
### Layout breakpoints
Quartz has different layouts depending on the width the screen viewing the website.
The breakpoints for layouts can be configured in `variables.scss`.
- `mobile`: screen width below this size will use mobile layout.
- `desktop`: screen width above this size will use desktop layout.
- Screen width between `mobile` and `desktop` width will use the tablet layout.
```scss
$breakpoints: (
mobile: 800px,
desktop: 1200px,
);
```
### Style ### Style
Most meaningful style changes like colour scheme and font can be done simply through the [[configuration#General Configuration|general configuration]] options. However, if you'd like to make more involved style changes, you can do this by writing your own styles. Quartz 4, like Quartz 3, uses [Sass](https://sass-lang.com/guide/) for styling. Most meaningful style changes like colour scheme and font can be done simply through the [[configuration#General Configuration|general configuration]] options. However, if you'd like to make more involved style changes, you can do this by writing your own styles. Quartz 4, like Quartz 3, uses [Sass](https://sass-lang.com/guide/) for styling.

View File

@ -0,0 +1,26 @@
---
title: RoamFlavoredMarkdown
tags:
- plugin/transformer
---
This plugin provides support for [Roam Research](https://roamresearch.com) compatibility. See [[Roam Research Compatibility]] for more information.
> [!note]
> For information on how to add, remove or configure plugins, see the [[Configuration#Plugins|Configuration]] page.
This plugin accepts the following configuration options:
- `orComponent`: If `true` (default), converts Roam `{{ or:ONE|TWO|THREE }}` shortcodes into HTML Dropdown options.
- `TODOComponent`: If `true` (default), converts Roam `{{[[TODO]]}}` shortcodes into HTML check boxes.
- `DONEComponent`: If `true` (default), converts Roam `{{[[DONE]]}}` shortcodes into checked HTML check boxes.
- `videoComponent`: If `true` (default), converts Roam `{{[[video]]:URL}}` shortcodes into embeded HTML video.
- `audioComponent`: If `true` (default), converts Roam `{{[[audio]]:URL}}` shortcodes into embeded HTML audio.
- `pdfComponent`: If `true` (default), converts Roam `{{[[pdf]]:URL}}` shortcodes into embeded HTML PDF viewer.
- `blockquoteComponent`: If `true` (default), converts Roam `{{[[>]]}}` shortcodes into Quartz blockquotes.
## API
- Category: Transformer
- Function name: `Plugin.RoamFlavoredMarkdown()`.
- Source: [`quartz/plugins/transformers/roam.ts`](https://github.com/jackyzha0/quartz/blob/v4/quartz/plugins/transformers/roam.ts).

1066
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -2,7 +2,7 @@
"name": "@jackyzha0/quartz", "name": "@jackyzha0/quartz",
"description": "🌱 publish your digital garden and notes as a website", "description": "🌱 publish your digital garden and notes as a website",
"private": true, "private": true,
"version": "4.3.1", "version": "4.4.0",
"type": "module", "type": "module",
"author": "jackyzha0 <j.zhao2k19@gmail.com>", "author": "jackyzha0 <j.zhao2k19@gmail.com>",
"license": "MIT", "license": "MIT",
@ -36,40 +36,40 @@
}, },
"dependencies": { "dependencies": {
"@clack/prompts": "^0.7.0", "@clack/prompts": "^0.7.0",
"@floating-ui/dom": "^1.6.10", "@floating-ui/dom": "^1.6.11",
"@napi-rs/simple-git": "0.1.19", "@napi-rs/simple-git": "0.1.19",
"@tweenjs/tween.js": "^25.0.0", "@tweenjs/tween.js": "^25.0.0",
"async-mutex": "^0.5.0", "async-mutex": "^0.5.0",
"chalk": "^5.3.0", "chalk": "^5.3.0",
"chokidar": "^3.6.0", "chokidar": "^4.0.1",
"cli-spinner": "^0.2.10", "cli-spinner": "^0.2.10",
"d3": "^7.9.0", "d3": "^7.9.0",
"esbuild-sass-plugin": "^2.16.1", "esbuild-sass-plugin": "^3.3.1",
"flexsearch": "0.7.43", "flexsearch": "0.7.43",
"github-slugger": "^2.0.0", "github-slugger": "^2.0.0",
"globby": "^14.0.2", "globby": "^14.0.2",
"gray-matter": "^4.0.3", "gray-matter": "^4.0.3",
"hast-util-to-html": "^9.0.1", "hast-util-to-html": "^9.0.3",
"hast-util-to-jsx-runtime": "^2.3.0", "hast-util-to-jsx-runtime": "^2.3.0",
"hast-util-to-string": "^3.0.0", "hast-util-to-string": "^3.0.1",
"is-absolute-url": "^4.0.1", "is-absolute-url": "^4.0.1",
"js-yaml": "^4.1.0", "js-yaml": "^4.1.0",
"lightningcss": "^1.26.0", "lightningcss": "^1.27.0",
"mdast-util-find-and-replace": "^3.0.1", "mdast-util-find-and-replace": "^3.0.1",
"mdast-util-to-hast": "^13.2.0", "mdast-util-to-hast": "^13.2.0",
"mdast-util-to-string": "^4.0.0", "mdast-util-to-string": "^4.0.0",
"micromorph": "^0.4.5", "micromorph": "^0.4.5",
"pixi.js": "^8.3.3", "pixi.js": "^8.4.1",
"preact": "^10.23.2", "preact": "^10.24.2",
"preact-render-to-string": "^6.5.9", "preact-render-to-string": "^6.5.11",
"pretty-bytes": "^6.1.1", "pretty-bytes": "^6.1.1",
"pretty-time": "^1.1.0", "pretty-time": "^1.1.0",
"reading-time": "^1.5.0", "reading-time": "^1.5.0",
"rehype-autolink-headings": "^7.1.0", "rehype-autolink-headings": "^7.1.0",
"rehype-citation": "^2.1.1", "rehype-citation": "^2.1.2",
"rehype-katex": "^7.0.1", "rehype-katex": "^7.0.1",
"rehype-mathjax": "^6.0.0", "rehype-mathjax": "^6.0.0",
"rehype-pretty-code": "^0.13.2", "rehype-pretty-code": "^0.14.0",
"rehype-raw": "^7.0.0", "rehype-raw": "^7.0.0",
"rehype-slug": "^6.0.0", "rehype-slug": "^6.0.0",
"remark": "^15.0.1", "remark": "^15.0.1",
@ -78,18 +78,18 @@
"remark-gfm": "^4.0.0", "remark-gfm": "^4.0.0",
"remark-math": "^6.0.0", "remark-math": "^6.0.0",
"remark-parse": "^11.0.0", "remark-parse": "^11.0.0",
"remark-rehype": "^11.1.0", "remark-rehype": "^11.1.1",
"remark-smartypants": "^3.0.2", "remark-smartypants": "^3.0.2",
"rfdc": "^1.4.1", "rfdc": "^1.4.1",
"rimraf": "^6.0.1", "rimraf": "^6.0.1",
"serve-handler": "^6.1.5", "serve-handler": "^6.1.5",
"shiki": "^1.12.1", "shiki": "^1.22.0",
"source-map-support": "^0.5.21", "source-map-support": "^0.5.21",
"to-vfile": "^8.0.0", "to-vfile": "^8.0.0",
"toml": "^3.0.0", "toml": "^3.0.0",
"unified": "^11.0.5", "unified": "^11.0.5",
"unist-util-visit": "^5.0.0", "unist-util-visit": "^5.0.0",
"vfile": "^6.0.2", "vfile": "^6.0.3",
"workerpool": "^9.1.3", "workerpool": "^9.1.3",
"ws": "^8.18.0", "ws": "^8.18.0",
"yargs": "^17.7.2" "yargs": "^17.7.2"
@ -99,14 +99,14 @@
"@types/d3": "^7.4.3", "@types/d3": "^7.4.3",
"@types/hast": "^3.0.4", "@types/hast": "^3.0.4",
"@types/js-yaml": "^4.0.9", "@types/js-yaml": "^4.0.9",
"@types/node": "^22.5.0", "@types/node": "^22.7.5",
"@types/pretty-time": "^1.1.5", "@types/pretty-time": "^1.1.5",
"@types/source-map-support": "^0.5.10", "@types/source-map-support": "^0.5.10",
"@types/ws": "^8.5.12", "@types/ws": "^8.5.12",
"@types/yargs": "^17.0.33", "@types/yargs": "^17.0.33",
"esbuild": "^0.19.9", "esbuild": "^0.24.0",
"prettier": "^3.3.3", "prettier": "^3.3.3",
"tsx": "^4.18.0", "tsx": "^4.19.1",
"typescript": "^5.5.4" "typescript": "^5.6.3"
} }
} }

View File

@ -9,6 +9,7 @@ import * as Plugin from "./quartz/plugins"
const config: QuartzConfig = { const config: QuartzConfig = {
configuration: { configuration: {
pageTitle: "🪴 Quartz 4.0", pageTitle: "🪴 Quartz 4.0",
pageTitleSuffix: "",
enableSPA: true, enableSPA: true,
enablePopovers: true, enablePopovers: true,
analytics: { analytics: {

View File

@ -39,7 +39,7 @@ type BuildData = {
type FileEvent = "add" | "change" | "delete" type FileEvent = "add" | "change" | "delete"
function newBuildId() { function newBuildId() {
return new Date().toISOString() return Math.random().toString(36).substring(2, 8)
} }
async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) { async function buildQuartz(argv: Argv, mut: Mutex, clientRefresh: () => void) {
@ -162,17 +162,19 @@ async function partialRebuildFromEntrypoint(
return return
} }
const buildStart = new Date().getTime() const buildId = newBuildId()
buildData.lastBuildMs = buildStart ctx.buildId = buildId
buildData.lastBuildMs = new Date().getTime()
const release = await mut.acquire() const release = await mut.acquire()
if (buildData.lastBuildMs > buildStart) {
// if there's another build after us, release and let them do it
if (ctx.buildId !== buildId) {
release() release()
return return
} }
const perf = new PerfTimer() const perf = new PerfTimer()
console.log(chalk.yellow("Detected change, rebuilding...")) console.log(chalk.yellow("Detected change, rebuilding..."))
ctx.buildId = newBuildId()
// UPDATE DEP GRAPH // UPDATE DEP GRAPH
const fp = joinSegments(argv.directory, toPosixPath(filepath)) as FilePath const fp = joinSegments(argv.directory, toPosixPath(filepath)) as FilePath
@ -357,19 +359,19 @@ async function rebuildFromEntrypoint(
toRemove.add(filePath) toRemove.add(filePath)
} }
const buildStart = new Date().getTime() const buildId = newBuildId()
buildData.lastBuildMs = buildStart ctx.buildId = buildId
buildData.lastBuildMs = new Date().getTime()
const release = await mut.acquire() const release = await mut.acquire()
// there's another build after us, release and let them do it // there's another build after us, release and let them do it
if (buildData.lastBuildMs > buildStart) { if (ctx.buildId !== buildId) {
release() release()
return return
} }
const perf = new PerfTimer() const perf = new PerfTimer()
console.log(chalk.yellow("Detected change, rebuilding...")) console.log(chalk.yellow("Detected change, rebuilding..."))
ctx.buildId = newBuildId()
try { try {
const filesToRebuild = [...toRebuild].filter((fp) => !toRemove.has(fp)) const filesToRebuild = [...toRebuild].filter((fp) => !toRemove.has(fp))
@ -405,10 +407,10 @@ async function rebuildFromEntrypoint(
} }
} }
release()
clientRefresh() clientRefresh()
toRebuild.clear() toRebuild.clear()
toRemove.clear() toRemove.clear()
release()
} }
export default async (argv: Argv, mut: Mutex, clientRefresh: () => void) => { export default async (argv: Argv, mut: Mutex, clientRefresh: () => void) => {

View File

@ -38,9 +38,14 @@ export type Analytics =
provider: "cabin" provider: "cabin"
host?: string host?: string
} }
| {
provider: "clarity"
projectId?: string
}
export interface GlobalConfiguration { export interface GlobalConfiguration {
pageTitle: string pageTitle: string
pageTitleSuffix?: string
/** Whether to enable single-page-app style rendering. this prevents flashes of unstyled content and improves smoothness of Quartz */ /** Whether to enable single-page-app style rendering. this prevents flashes of unstyled content and improves smoothness of Quartz */
enableSPA: boolean enableSPA: boolean
/** Whether to display Wikipedia-style popovers when hovering over links */ /** Whether to display Wikipedia-style popovers when hovering over links */

View File

@ -12,24 +12,20 @@ const Backlinks: QuartzComponent = ({
}: QuartzComponentProps) => { }: QuartzComponentProps) => {
const slug = simplifySlug(fileData.slug!) const slug = simplifySlug(fileData.slug!)
const backlinkFiles = allFiles.filter((file) => file.links?.includes(slug)) const backlinkFiles = allFiles.filter((file) => file.links?.includes(slug))
return ( return backlinkFiles.length <= 0 ? null : (
<div class={classNames(displayClass, "backlinks")}> <div class={classNames(displayClass, "backlinks")}>
<h3>{i18n(cfg.locale).components.backlinks.title}</h3> <h3>{i18n(cfg.locale).components.backlinks.title}</h3>
<ul class="overflow"> <ul class="overflow">
{backlinkFiles.length > 0 ? ( {backlinkFiles.map((f) => (
backlinkFiles.map((f) => ( <li key={f.slug}>
<li> <a href={resolveRelative(fileData.slug!, f.slug!)} class="internal">
<a href={resolveRelative(fileData.slug!, f.slug!)} class="internal"> {f.frontmatter?.title}
{f.frontmatter?.title} </a>
</a> </li>
</li> ))}
))
) : (
<li>{i18n(cfg.locale).components.backlinks.noBacklinksFound}</li>
)}
</ul> </ul>
</div> </div>
) );
} }
Backlinks.css = style Backlinks.css = style

View File

@ -30,7 +30,8 @@ export default ((opts?: Partial<ContentMetaOptions>) => {
const segments: (string | JSX.Element)[] = [] const segments: (string | JSX.Element)[] = []
if (fileData.dates) { if (fileData.dates) {
segments.push(formatDate(getDate(cfg, fileData)!, cfg.locale)) segments.push("Обновлена: " + formatDate(fileData.dates.modified!, cfg.locale))
segments.push("Создана: " + formatDate(fileData.dates.created!, cfg.locale))
} }
// Display reading time if enabled // Display reading time if enabled

View File

@ -2,6 +2,7 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro
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"
import script from "./scripts/_randomPage.inline"
interface Options { interface Options {
links: Record<string, string> links: Record<string, string>
@ -14,8 +15,7 @@ export default ((opts?: Options) => {
return ( return (
<footer class={`${displayClass ?? ""}`}> <footer class={`${displayClass ?? ""}`}>
<p> <p>
{i18n(cfg.locale).components.footer.createdWith}{" "} Автор: <a href="https://mark.struchkov.dev">Стручков Марк</a>, если не указано иное. © {year}
<a href="https://quartz.jzhao.xyz/">Quartz v{version}</a> © {year}
</p> </p>
<ul> <ul>
{Object.entries(links).map(([text, link]) => ( {Object.entries(links).map(([text, link]) => (
@ -24,10 +24,25 @@ export default ((opts?: Options) => {
</li> </li>
))} ))}
</ul> </ul>
<hr style="margin-top: 1rem;" />
<ul>
<li>
<a href="#">
Наверх
</a>
</li>
<li>
<a id="random-page-button">
Мне повезет 🎲
</a>
</li>
</ul>
<script src="static/share.js"></script>
</footer> </footer>
) )
} }
Footer.css = style Footer.css = style
Footer.afterDOMLoaded = script
return Footer return Footer
}) satisfies QuartzComponentConstructor }) satisfies QuartzComponentConstructor

View File

@ -6,7 +6,9 @@ import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } fro
export default (() => { export default (() => {
const Head: QuartzComponent = ({ cfg, fileData, externalResources }: QuartzComponentProps) => { const Head: QuartzComponent = ({ cfg, fileData, externalResources }: QuartzComponentProps) => {
const title = fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title const titleSuffix = cfg.pageTitleSuffix ?? ""
const title =
(fileData.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title) + titleSuffix
const description = const description =
fileData.description?.trim() ?? i18n(cfg.locale).propertyDefaults.description fileData.description?.trim() ?? i18n(cfg.locale).propertyDefaults.description
const { css, js } = externalResources const { css, js } = externalResources
@ -16,7 +18,7 @@ export default (() => {
const baseDir = fileData.slug === "404" ? path : pathToRoot(fileData.slug!) const baseDir = 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.webp`
return ( return (
<head> <head>
@ -37,7 +39,6 @@ export default (() => {
<meta property="og:height" content="675" /> <meta property="og:height" content="675" />
<link rel="icon" href={iconPath} /> <link rel="icon" href={iconPath} />
<meta name="description" content={description} /> <meta name="description" content={description} />
<meta name="generator" content="Quartz" />
{css.map((href) => ( {css.map((href) => (
<link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve /> <link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve />
))} ))}

View File

@ -37,7 +37,7 @@ export default ((userOpts?: Partial<Options>) => {
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>{opts.title ?? i18n(cfg.locale).components.recentNotes.title}</h3> <h4>{opts.title ?? i18n(cfg.locale).components.recentNotes.title}</h4>
<ul class="recent-ul"> <ul class="recent-ul">
{pages.slice(0, opts.limit).map((page) => { {pages.slice(0, opts.limit).map((page) => {
const title = page.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title const title = page.frontmatter?.title ?? i18n(cfg.locale).propertyDefaults.title
@ -47,11 +47,11 @@ export default ((userOpts?: Partial<Options>) => {
<li class="recent-li"> <li class="recent-li">
<div class="section"> <div class="section">
<div class="desc"> <div class="desc">
<h3> <span>
<a href={resolveRelative(fileData.slug!, page.slug!)} class="internal"> <a href={resolveRelative(fileData.slug!, page.slug!)} class="internal">
{title} {title}
</a> </a>
</h3> </span>
</div> </div>
{page.dates && ( {page.dates && (
<p class="meta"> <p class="meta">

View File

@ -0,0 +1,21 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
// @ts-ignore
import { classNames } from "../util/lang"
const Ads: QuartzComponent = ({ displayClass, fileData }: QuartzComponentProps) => {
return (
<blockquote className="callout tip desktop-only" data-callout="tip">
<div className="callout-title">
<div className="callout-icon"></div>
<div className="callout-title-inner"><p>Спонсор: VDSina</p></div>
</div>
<div className="callout-content">
<p>Хостинг провайдер, которым пользуюсь сам. Сервера на территории РФ и Нидерландов, 2 ТБ трафика на
сервер.<br />
<br /><a href="https://vdsina.ru/?partner=3yw9q78nd5" rel="nofollow">Вечная скидка 10% при
регистрации.</a></p>
</div>
</blockquote>
)
}
export default (() => Ads) satisfies QuartzComponentConstructor

View File

@ -0,0 +1,52 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import style from "./styles/_githubSource.scss"
// @ts-ignore
import { classNames } from "../util/lang"
interface GithubSourceOptions {
repoLink: string
branch: string
}
const defaultOptions: GithubSourceOptions = {
repoLink: "github.com",
branch: "v4"
}
export default ((opts?: Partial<GithubSourceOptions>) => {
// Merge options with defaults
const options: GithubSourceOptions = { ...defaultOptions, ...opts }
const GithubSource: QuartzComponent = ({
displayClass,
fileData
}: QuartzComponentProps) => {
return (
<div class={classNames(displayClass, "github-source")}>
<h3>Инструменты</h3>
<ul>
<li>
<a href={`${options?.repoLink}/blob/${options?.branch}/${fileData.filePath!.replace(/^content\//, "")}`}
className="external">
Редактировать
</a>
</li>
<li>
<a href={`${options?.repoLink}/commits/${options?.branch}/${fileData.filePath!.replace(/^content\//, "")}`}
className="external">
🕒 История изменений
</a>
</li>
<li>
<a href={`${options?.repoLink}/blame/${options?.branch}/${fileData.filePath!.replace(/^content\//, "")}`}
className="external">
🧑💻 Авторы
</a>
</li>
</ul>
</div>
)
}
GithubSource.css = style
return GithubSource
}) satisfies QuartzComponentConstructor

View File

@ -0,0 +1,33 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
// @ts-ignore
import script from "./scripts/_randomPage.inline"
import style from "./styles/_randomPage.scss"
import { classNames } from "../util/lang"
const RandomPageButton: QuartzComponent = ({ displayClass, fileData }: QuartzComponentProps) => {
return (
<div id="random-page-button" class={classNames(displayClass, "random-page")}>
{/* <ul>
<li> */}
<svg y="0px" x="0px" viewBox="0 0 316 316">
<title>Random page</title>
<g>
<rect class="random-page-square" stroke-width="15" rx="30" height="300" width="300" y="8" x="8" fill="none" />
<ellipse class="random-page-ellipse" ry="20" rx="20" cy="83" cx="108" />
<ellipse class="random-page-ellipse" ry="20" rx="20" cy="83" cx="208" />
<ellipse class="random-page-ellipse" ry="20" rx="20" cy="233" cx="208" />
<ellipse class="random-page-ellipse" ry="20" rx="20" cy="233" cx="108" />
<ellipse class="random-page-ellipse" ry="20" rx="20" cy="158" cx="208" />
<ellipse class="random-page-ellipse" ry="20" rx="20" cy="158" cx="108" />
</g>
</svg>
{/* </li>
</ul> */}
{/* <h3>Go to a random page 🎲</h3> */}
</div>
)
}
RandomPageButton.css = style
RandomPageButton.afterDOMLoaded = script
export default (() => RandomPageButton) satisfies QuartzComponentConstructor

View File

@ -0,0 +1,74 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
// @ts-ignore
// import script from "./scripts/comments.inline"
type Options = {
options: {
host: string
siteId: string
locale: string
}
}
// function boolToStringBool(b: boolean): string {
// return b ? "1" : "0"
// }
export default ((opts: Options) => {
const Remark: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
const remarkConfig = `
var remark_config = {
host: "${opts.options.host}",
site_id: "${opts.options.siteId}",
components: ["embed"],
locale: "${opts.options.locale}",
theme: localStorage.theme,
show_email_subscription: false,
simple_view: false
};
`
const embedScript = `
!function(e,n){
for(var o=0;o<e.length;o++){
var r=n.createElement("script"),
c=".js",
d=n.head||n.body;
"noModule" in r ? (r.type="module",c=".mjs") : r.async=!0,
r.defer=!0,
r.src=remark_config.host+"/web/"+e[o]+c,
d.appendChild(r)
}
}(remark_config.components||["embed"], document);
`
return (
<>
<hr />
<a className="notice notice-telegram" href="https://t.me/struchkov_dev" target="_blank">
<div className="notice__head">
<svg className="notice__head-icon" fill="currentColor" viewBox="0 0 190 170">
<path
d="M152.531 170c-1.48 0-2.95-.438-4.21-1.293l-47.642-32.316-25.552 18.386a7.502 7.502 0 01-11.633-4.174l-12.83-48.622L4.821 84.452a7.501 7.501 0 01-.094-13.975L179.04 1.117a7.503 7.503 0 0110.282 8.408l-29.423 154.379a7.499 7.499 0 01-7.367 6.096zm-47.669-48.897l42.437 28.785 22.894-120.124-82.687 79.566 17.156 11.638c.07.043.135.089.2.135zm-35.327-6.401l5.682 21.53 12.242-8.809-16.03-10.874a7.478 7.478 0 01-1.894-1.847zM28.136 77.306l31.478 12.035a7.5 7.5 0 014.573 5.092l3.992 15.129a7.504 7.504 0 012.26-4.624l78.788-75.814z"></path>
</svg>
<div className="notice__head-text">Подписывайся</div>
</div>
<div className="notice__tail">
<div className="notice__tail-text">на Struchkov.Dev в Telegram</div>
</div>
<div className="notice__skin">
<svg className="notice__skin-icon" fill="currentColor" viewBox="0 0 448 376">
<path
d="M446.684 34.522l-67.6 318.8c-5.1 22.5-18.4 28.1-37.3 17.5l-103-75.9-49.7 47.8c-5.5 5.5-10.1 10.1-20.7 10.1l7.4-104.9 190.9-172.5c8.3-7.4-1.8-11.5-12.9-4.1l-236 148.6-101.6-31.8c-22.1-6.9-22.5-22.1 4.6-32.7l397.4-153.1c18.4-6.9 34.5 4.1 28.5 32.2z"></path>
</svg>
</div>
</a>
<div id="remark42" style="margin-top: 2rem"></div>
<script dangerouslySetInnerHTML={{ __html: remarkConfig }}></script>
<script dangerouslySetInnerHTML={{ __html: embedScript }}></script>
</>
)
}
return Remark
}) satisfies QuartzComponentConstructor<Options>

View File

@ -0,0 +1,31 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
import style from "./styles/_scrollToTop.scss"
// @ts-ignore
import script from "./scripts/_randomPage.inline"
import { classNames } from "../util/lang"
import { i18n } from "../i18n"
const ScrollToTop: QuartzComponent = ({ displayClass, fileData }: QuartzComponentProps) => {
return (
<div class={classNames(displayClass, "scroll-to-top")}>
<h3>Utilities</h3>
<ul>
<li>
<a href="#">
Scroll to top
</a>
</li>
<li>
<a id="random-page-button">
Random Page 🎲
</a>
</li>
</ul>
</div>
)}
ScrollToTop.css = style
ScrollToTop.afterDOMLoaded = script
export default (() => ScrollToTop) satisfies QuartzComponentConstructor

View File

@ -0,0 +1,78 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types"
// @ts-ignore
import style from "./styles/_socialshare.scss"
const SocialShare: QuartzComponent = ({ displayClass, fileData }: QuartzComponentProps) => {
return (
<>
<div className="post-share">
<div className="share-link">
<a className="share-icon share-telegram"
href="javascript:void(0);"
title="Поделиться в Telegram"
data-sharer="telegram"
data-url="{{url absolute=" true"}}"
data-title="{{title}}"
data-caption="{{custom_excerpt}}">
<span className="svg-social-icon icon-telegram"></span>
</a>
</div>
<div className="share-link">
<a className="share-icon share-twitter"
href="javascript:void(0);"
title="Поделиться в Twitter"
data-sharer="twitter"
data-url="{{url absolute=" true"}}"
data-title="{{title}}">
<span className="svg-social-icon icon-twitter"></span>
</a>
</div>
<!-- <div class="share-link">-->
<!-- <a class="share-icon share-whatsapp"-->
<!-- href="javascript:void(0);"-->
<!-- title="Поделиться в WhatsApp"-->
<!-- data-sharer="whatsapp"-->
<!-- data-url="{{url absolute="true"}}"-->
<!-- data-title="{{title}}"-->
<!-- data-web="">-->
<!-- <span class="svg-social-icon icon-whatsapp"></span>-->
<!-- </a>-->
<!-- </div>-->
<!-- <div class="share-link">-->
<!-- <a class="share-icon share-vk"-->
<!-- href="javascript:void(0);"-->
<!-- title="Поделиться в VK"-->
<!-- data-sharer="vk"-->
<!-- data-url="{{url absolute="true"}}"-->
<!-- data-title="{{title}}"-->
<!-- data-caption="{{custom_excerpt}}">-->
<!-- <span class="svg-social-icon icon-vk"></span>-->
<!-- </a>-->
<!-- </div>-->
<div className="share-link">
<a className="share-icon share-pocket"
href="javascript:void(0);"
title="Поделиться в Pocket"
data-title="{{title}}"
data-sharer="pocket"
data-url="{{url absolute=" true"}}">
<span className="svg-social-icon icon-pocket"></span>
</a>
</div>
<div className="share-link">
<a className="share-icon share-skype"
href="javascript:void(0);"
title="Поделиться в Skype"
data-sharer="skype"
data-url="{{url absolute=" true"}}"
data-title="{{title}}">
<span className="svg-social-icon icon-skype"></span>
</a>
</div>
</div>
</>
)
}
SocialShare.css = style;
export default (() => SocialShare) satisfies QuartzComponentConstructor;

View File

@ -0,0 +1,34 @@
import { QuartzComponent, QuartzComponentConstructor, QuartzComponentProps } from "./types";
const YandexMetrika: QuartzComponent = ({ displayClass, cfg }: QuartzComponentProps) => {
const embedScript = `
(function(m,e,t,r,i,k,a){m[i]=m[i]||function(){(m[i].a=m[i].a||[]).push(arguments)};
m[i].l=1*new Date();
for (var j = 0; j < document.scripts.length; j++) {if (document.scripts[j].src === r) { return; }}
k=e.createElement(t),a=e.getElementsByTagName(t)[0],k.async=1,k.src=r,a.parentNode.insertBefore(k,a)})
(window, document, "script", "https://mc.yandex.ru/metrika/tag.js", "ym");
ym(98254050, "init", {
clickmap: true,
trackLinks: true,
accurateTrackBounce: true
});
`;
return (
<>
<script type="text/javascript" dangerouslySetInnerHTML={{ __html: embedScript }}></script>
<noscript>
<div>
<img
src="https://mc.yandex.ru/watch/98254050"
style={{ position: "absolute", left: "-9999px" }}
alt=""
/>
</div>
</noscript>
</>
);
};
export default (() => YandexMetrika) satisfies QuartzComponentConstructor;

View File

@ -20,6 +20,13 @@ import MobileOnly from "./MobileOnly"
import RecentNotes from "./RecentNotes" import RecentNotes from "./RecentNotes"
import Breadcrumbs from "./Breadcrumbs" import Breadcrumbs from "./Breadcrumbs"
import Comments from "./Comments" import Comments from "./Comments"
import Remark from "./_Remark"
import ScrollToTop from "./_ScrollToTop"
import GithubSource from "./_GithubSource"
import RandomPageButton from "./_RandomPageButton"
import Ads from "./_Ads"
import YandexMetrika from "./_YandexMetrika"
// import SocialShare from "./_SocialShare"
export { export {
ArticleTitle, ArticleTitle,
@ -44,4 +51,11 @@ export {
NotFound, NotFound,
Breadcrumbs, Breadcrumbs,
Comments, Comments,
Remark,
GithubSource,
ScrollToTop,
RandomPageButton,
Ads,
YandexMetrika,
// SocialShare
} }

View File

@ -11,6 +11,7 @@ const NotFound: QuartzComponent = ({ cfg }: QuartzComponentProps) => {
<h1>404</h1> <h1>404</h1>
<p>{i18n(cfg.locale).pages.error.notFound}</p> <p>{i18n(cfg.locale).pages.error.notFound}</p>
<a href={baseDir}>{i18n(cfg.locale).pages.error.home}</a> <a href={baseDir}>{i18n(cfg.locale).pages.error.home}</a>
<pre><code> _________________<br/> | You got lost... |<br/> 🗩 <br/> 🗩<br/> <br/> <br/> <br/> <br/> <br/> <br/><br/><br/><br/> <br/> <br/></code></pre>
</article> </article>
) )
} }

View File

@ -234,7 +234,6 @@ export function renderPage(
</div> </div>
</div> </div>
<Content {...componentData} /> <Content {...componentData} />
<hr />
<div class="page-footer"> <div class="page-footer">
{afterBody.map((BodyComponent) => ( {afterBody.map((BodyComponent) => (
<BodyComponent {...componentData} /> <BodyComponent {...componentData} />
@ -242,8 +241,8 @@ export function renderPage(
</div> </div>
</div> </div>
{RightComponent} {RightComponent}
<Footer {...componentData} />
</Body> </Body>
<Footer {...componentData} />
</div> </div>
</body> </body>
{pageResources.js {pageResources.js

View File

@ -0,0 +1,28 @@
import { FullSlug, getFullSlug, pathToRoot, simplifySlug } from "../../util/path"
function getRandomInt(max: number) {
return Math.floor(Math.random() * max);
}
async function navigateToRandomPage() {
const fullSlug = getFullSlug(window)
const data = await fetchData
const allPosts = Object.keys(data).map((slug) => simplifySlug(slug as FullSlug))
// window.location.href = `${pathToRoot(fullSlug)}/${allPosts[getRandomInt(allPosts.length - 1)]}`
let newSlug = `${pathToRoot(fullSlug)}/${allPosts[getRandomInt(allPosts.length - 1)]}`;
if (newSlug === fullSlug) {
// Generate a new random slug until it's different from the starting fullSlug
do {
newSlug = `${pathToRoot(fullSlug)}/${allPosts[getRandomInt(allPosts.length - 1)]}`;
} while (newSlug === fullSlug);
}
window.location.href = newSlug;
}
document.addEventListener("nav", async (e: unknown) => {
// const slug = (e as CustomEventMap["nav"]).detail.url
const button = document.getElementById("random-page-button")
button?.removeEventListener("click", navigateToRandomPage)
button?.addEventListener("click", navigateToRandomPage)
})

View File

@ -25,7 +25,6 @@ function toggleExplorer(this: HTMLElement) {
if (!content) return if (!content) return
content.classList.toggle("collapsed") content.classList.toggle("collapsed")
content.style.maxHeight = content.style.maxHeight === "0px" ? content.scrollHeight + "px" : "0px"
} }
function toggleFolder(evt: MouseEvent) { function toggleFolder(evt: MouseEvent) {

View File

@ -23,7 +23,6 @@ function toggleToc(this: HTMLElement) {
const content = this.nextElementSibling as HTMLElement | undefined const content = this.nextElementSibling as HTMLElement | undefined
if (!content) return if (!content) return
content.classList.toggle("collapsed") content.classList.toggle("collapsed")
content.style.maxHeight = content.style.maxHeight === "0px" ? content.scrollHeight + "px" : "0px"
} }
function setupToc() { function setupToc() {
@ -32,7 +31,6 @@ function setupToc() {
const collapsed = toc.classList.contains("collapsed") const collapsed = toc.classList.contains("collapsed")
const content = toc.nextElementSibling as HTMLElement | undefined const content = toc.nextElementSibling as HTMLElement | undefined
if (!content) return if (!content) return
content.style.maxHeight = collapsed ? "0px" : content.scrollHeight + "px"
toc.addEventListener("click", toggleToc) toc.addEventListener("click", toggleToc)
window.addCleanup(() => toc.removeEventListener("click", toggleToc)) window.addCleanup(() => toc.removeEventListener("click", toggleToc))
} }

View File

@ -0,0 +1,27 @@
.github-source {
&>h3 {
font-size: 1rem;
margin: 0;
}
&>ul {
list-style: none;
padding: 0;
margin: 0.5rem 0;
&>li {
&>a {
background-color: transparent;
}
}
}
}
.external-icon {
height: 1ex;
margin: 0 0.15em;
> path {
fill: var(--dark);
}
}

View File

@ -0,0 +1,41 @@
.random-page {
position: relative;
width: 20px;
height: 20px;
margin-left: auto;
margin: 0 10px;
&>ul {
list-style: none;
padding: 0;
margin: 0.5rem 0;
}
> svg {
cursor: pointer;
position: absolute;
width: 20px;
height: 20px;
top: calc(50% - 10px);
}
&:hover {
opacity: 0.7; /* Decrease opacity on hover */
cursor: pointer;
}
&>h3 {
font-size: 1rem;
margin: 0;
}
}
.random-page-ellipse {
stroke: var(--darkgray);
fill: var(--darkgray);
transition: stroke 0.5s ease;
}
.random-page-square {
stroke: var(--darkgray);
transition: stroke 0.5s ease;
}

View File

@ -0,0 +1,31 @@
.scroll-to-top {
&>h3 {
font-size: 1rem;
margin: 0;
}
&>ul {
list-style: none;
padding: 0;
margin: 0.5rem 0;
&>li {
&>a {
background-color: transparent;
}
}
}
}
a {
text-decoration: none;
}
.external-icon {
height: 1ex;
margin: 0 0.15em;
> path {
fill: var(--dark);
}
}

View File

@ -0,0 +1,507 @@
a.share-icon {
border-bottom: 2px solid;
}
.post-share {
a.share-icon:hover {
background: white;
.svg-social-icon {
background-image: var(--sprite-share-icon-color);
}
}
}
.share-link {
margin-top: 15px;
margin-right: 8px;
display: inline-block;
a.share-telegram {
background: #2CA5E0;
border-color: #2CA5E0;
}
a.share-twitter {
background: #1DA1F2;
border-color: #1DA1F2;
}
a.share-vk {
background: #4680C2;
border-color: #4680C2;
}
a.share-whatsapp {
background: #25D366;
border-color: #25D366;
}
a.share-pocket {
background: #EF3F56;
border-color: #EF3F56;
}
a.share-linkedin {
background: #0077B5;
border-color: #0077B5;
}
a.share-viber {
background: #665CAC;
border-color: #665CAC;
}
a.share-pinterest {
background: #BD081C;
border-color: #BD081C;
}
a.share-tumblr {
background: #36465D;
border-color: #36465D;
}
a.share-reddit {
background: #FF4500;
border-color: #FF4500;
}
a.share-buffer {
background: #168EEA;
border-color: #168EEA;
}
a.share-xing {
background: #006567;
border-color: #006567;
}
a.share-line {
background: #00C300;
border-color: #00C300;
}
a.share-instapaper {
background: #1F1F1F;
border-color: #1F1F1F;
}
a.share-digg {
background: #000000;
border-color: #000000;
}
a.share-stumbleupon {
background: #FD8235;
border-color: #FD8235;
}
a.share-flipboard {
background: #E12828;
border-color: #E12828;
}
a.share-weibo {
background: #20B8E5;
border-color: #20B8E5;
}
a.share-renren {
background: #217DC6;
border-color: #217DC6;
}
a.share-myspace {
background: #030303;
border-color: #030303;
}
a.share-blogger {
background: #FF5722;
border-color: #FF5722;
}
a.share-baidu {
background: #2319DC;
border-color: #2319DC;
}
a.share-ok {
background: #EE8208;
border-color: #EE8208;
}
a.share-evernote {
background: #00A82D;
border-color: #00A82D;
}
a.share-skype {
background: #00AFF0;
border-color: #00AFF0;
}
a.share-trello {
background: #0079BF;
border-color: #0079BF;
}
a.share-mix {
background: #FF8126;
border-color: #FF8126;
}
a.share-hackernews {
background: #FF8126;
border-color: #FF8126;
}
}
.share-text {
font-size: 30px;
margin-bottom: 10px;
}
.share-icon {
border-radius: 6px;
padding: 10px 12px 4px 12px;
border: 2px solid;
}
.svg-social-icon {
display: inline-block;
background-repeat: no-repeat;
background-image: var(--sprite-share-icon);
width: 20px;
height: 20px;
}
.svg-social-icon-color {
display: inline-block;
background-repeat: no-repeat;
background-image: var(--sprite-share-icon-color);
width: 20px;
height: 20px;
}
.icon-rss {
background-position: 0 0;
}
.icon-mail-dot-ru {
background-position: -25px 0;
}
.icon-udemy {
background-position: -50px 0;
}
.icon-discord {
background-position: -75px 0;
}
.icon-docker {
background-position: -100px 0;
}
.icon-matrix {
background-position: -125px 0;
}
.icon-xmpp {
background-position: -150px 0;
}
.icon-gitea {
background-position: -175px 0;
}
.icon-mastodon {
background-position: -200px 0;
}
.icon-researchgate {
background-position: -225px 0;
}
.icon-google {
background-position: 0 -25px;
}
.icon-vine {
background-position: -25px -25px;
}
.icon-wordpress {
background-position: -50px -25px;
}
.icon-dribbble {
background-position: -75px -25px;
}
.icon-behance {
background-position: -100px -25px;
}
.icon-deviantart {
background-position: -125px -25px;
}
.icon-jsfiddle {
background-position: -150px -25px;
}
.icon-angellist {
background-position: -175px -25px;
}
.icon-zhihu {
background-position: -200px -25px;
}
.icon-strava {
background-position: -225px -25px;
}
.icon-twitch {
background-position: 0 -50px;
}
.icon-steam {
background-position: -25px -50px;
}
.icon-patreon {
background-position: -50px -50px;
}
.icon-kickstarter {
background-position: -75px -50px;
}
.icon-foursquare {
background-position: -100px -50px;
}
.icon-last-dot-fm {
background-position: -125px -50px;
}
.icon-goodreads {
background-position: -150px -50px;
}
.icon-500px {
background-position: -175px -50px;
}
.icon-paypal {
background-position: -200px -50px;
}
.icon-bandcamp {
background-position: -225px -50px;
}
.icon-spotify {
background-position: 0 -75px;
}
.icon-soundcloud {
background-position: -25px -75px;
}
.icon-snapchat {
background-position: -50px -75px;
}
.icon-xing {
background-position: -75px -75px;
}
.icon-flickr {
background-position: -100px -75px;
}
.icon-stackoverflow {
background-position: -125px -75px;
}
.icon-bitbucket {
background-position: -150px -75px;
}
.icon-freecodecamp {
background-position: -175px -75px;
}
.icon-codepen {
background-position: -200px -75px;
}
.icon-pinterest {
background-position: -225px -75px;
}
.icon-keybase {
background-position: 0 -100px;
}
.icon-quora {
background-position: -25px -100px;
}
.icon-tumblr {
background-position: -50px -100px;
}
.icon-youtube {
background-position: -75px -100px;
}
.icon-gitlab {
background-position: -100px -100px;
}
.icon-medium {
background-position: -125px -100px;
}
.icon-instagram {
background-position: -150px -100px;
}
.icon-linkedin {
background-position: -175px -100px;
}
.icon-github {
background-position: -200px -100px;
}
.icon-mixer {
background-position: -225px -100px;
}
.icon-trello {
background-position: 0 -125px;
}
.icon-skype {
background-position: -25px -125px;
}
.icon-evernote {
background-position: -50px -125px;
}
.icon-odnoklassniki {
background-position: -75px -125px;
}
.icon-baidu {
background-position: -100px -125px;
}
.icon-blogger {
background-position: -125px -125px;
}
.icon-myspace {
background-position: -150px -125px;
}
.icon-renren {
background-position: -175px -125px;
}
.icon-sinaweibo {
background-position: -200px -125px;
}
.icon-flipboard {
background-position: -225px -125px;
}
.icon-digg {
background-position: 0 -150px;
}
.icon-pocket {
background-position: -25px -150px;
}
.icon-instapaper {
background-position: -50px -150px;
}
.icon-line {
background-position: -75px -150px;
}
.icon-xing1 {
background-position: -100px -150px;
}
.icon-buffer {
background-position: -125px -150px;
}
.icon-reddit {
background-position: -150px -150px;
}
.icon-tumblr1 {
background-position: -175px -150px;
}
.icon-pinterest1 {
background-position: -200px -150px;
}
.icon-viber {
background-position: -225px -150px;
}
.icon-linkedin1 {
background-position: 0 -175px;
}
.icon-telegram {
background-position: -25px -175px;
}
.icon-whatsapp {
background-position: -50px -175px;
}
.icon-vk {
background-position: -100px -175px;
}
.icon-twitter {
background-position: -125px -175px;
}
.icon-leanpub {
width: 23px;
height: 20px;
background-position: 0 -200px;
}
.icon-hacker-news {
width: 17px;
height: 20px;
background-position: -50px -200px;
}
.icon-stumbleupon {
width: 21px;
height: 20px;
background-position: -75px -200px;
}

View File

@ -1,15 +1,28 @@
@use "../../styles/variables.scss" as *;
.backlinks { .backlinks {
position: relative; flex-direction: column;
/*&:after {
pointer-events: none;
content: "";
width: 100%;
height: 50px;
position: absolute;
left: 0;
bottom: 0;
opacity: 1;
transition: opacity 0.3s ease;
background: linear-gradient(transparent 0px, var(--light));
}*/
& > h3 { & > h3 {
font-size: 1rem; font-size: 1rem;
margin: 0; margin: 0;
} }
& > ul { & > ul {
list-style: none; list-style: none;
padding: 0; margin: 0.5rem 0;
margin: 0.5rem 0;
& > li { & > li {
& > a { & > a {
@ -17,4 +30,14 @@
} }
} }
} }
& > .overflow {
&:after {
display: none;
}
height: auto;
@media all and ($desktop) {
height: 250px;
}
}
} }

View File

@ -1,5 +1,28 @@
@use "../../styles/variables.scss" as *; @use "../../styles/variables.scss" as *;
.explorer {
display: flex;
flex-direction: column;
overflow-y: hidden;
&.desktop-only {
@media all and not ($mobile) {
display: flex;
}
}
/*&:after {
pointer-events: none;
content: "";
width: 100%;
height: 50px;
position: absolute;
left: 0;
bottom: 0;
opacity: 1;
transition: opacity 0.3s ease;
background: linear-gradient(transparent 0px, var(--light));
}*/
}
button#explorer { button#explorer {
background-color: transparent; background-color: transparent;
border: none; border: none;
@ -44,7 +67,8 @@ button#explorer {
#explorer-content { #explorer-content {
list-style: none; list-style: none;
overflow: hidden; overflow: hidden;
max-height: none; overflow-y: auto;
max-height: 100%;
transition: transition:
max-height 0.35s ease, max-height 0.35s ease,
visibility 0s linear 0s; visibility 0s linear 0s;
@ -52,16 +76,13 @@ button#explorer {
visibility: visible; visibility: visible;
&.collapsed { &.collapsed {
max-height: 0;
transition: transition:
max-height 0.35s ease, max-height 0.35s ease,
visibility 0s linear 0.35s; visibility 0s linear 0.35s;
visibility: hidden; visibility: hidden;
} }
&.collapsed > .overflow::after {
opacity: 0;
}
& ul { & ul {
list-style: none; list-style: none;
margin: 0.08rem 0; margin: 0.08rem 0;
@ -76,6 +97,9 @@ button#explorer {
pointer-events: all; pointer-events: all;
} }
} }
> #explorer-ul {
max-height: none;
}
} }
svg { svg {

View File

@ -65,7 +65,7 @@
height: 80vh; height: 80vh;
width: 80vw; width: 80vw;
@media all and (max-width: $fullPageWidth) { @media all and ($desktop) {
width: 90%; width: 90%;
} }
} }

View File

@ -13,7 +13,7 @@ li.section-li {
display: grid; display: grid;
grid-template-columns: fit-content(8em) 3fr 1fr; grid-template-columns: fit-content(8em) 3fr 1fr;
@media all and (max-width: $mobileBreakpoint) { @media all and ($mobile) {
& > .tags { & > .tags {
display: none; display: none;
} }

View File

@ -70,7 +70,7 @@
opacity 0.3s ease, opacity 0.3s ease,
visibility 0.3s ease; visibility 0.3s ease;
@media all and (max-width: $mobileBreakpoint) { @media all and ($mobile) {
display: none !important; display: none !important;
} }
} }

View File

@ -1,24 +1,31 @@
.recent-notes { .recent-notes>h3 {
& > h3 { margin: .5rem 0 0;
margin: 0.5rem 0 0 0; font-size: 1rem
font-size: 1rem;
}
& > ul.recent-ul {
list-style: none;
margin-top: 1rem;
padding-left: 0;
& > li {
margin: 1rem 0;
.section > .desc > h3 > a {
background-color: transparent;
}
.section > .meta {
margin: 0 0 0.5rem 0;
opacity: 0.6;
}
}
}
} }
.recent-notes>ul.recent-ul {
margin-top: 1rem;
padding-left: 0;
list-style: none
}
.recent-notes>ul.recent-ul>li {
margin: 1rem 0
}
.recent-notes>ul.recent-ul>li .section>.desc>h3>a {
background-color: #0000
}
.recent-notes>ul.recent-ul>li .section>.meta {
opacity: .6;
margin: 0 0 .5rem
}
.left .recent-notes:nth-last-child(2) {
grid-area: 3/1/3/3
}
.left .recent-notes:last-child {
grid-area: 4/1/4/3
}

View File

@ -3,7 +3,9 @@
.search { .search {
min-width: fit-content; min-width: fit-content;
max-width: 14rem; max-width: 14rem;
flex-grow: 0.3; @media all and ($mobile) {
flex-grow: 0.3;
}
& > .search-button { & > .search-button {
background-color: var(--lightgray); background-color: var(--lightgray);
@ -62,7 +64,7 @@
margin-left: auto; margin-left: auto;
margin-right: auto; margin-right: auto;
@media all and (max-width: $fullPageWidth) { @media all and ($desktop) {
width: 90%; width: 90%;
} }
@ -104,7 +106,7 @@
flex: 0 0 min(30%, 450px); flex: 0 0 min(30%, 450px);
} }
@media all and (min-width: $tabletBreakpoint) { @media all and not ($tablet) {
&[data-preview] { &[data-preview] {
& .result-card > p.preview { & .result-card > p.preview {
display: none; display: none;
@ -130,7 +132,7 @@
border-radius: 5px; border-radius: 5px;
} }
@media all and (max-width: $tabletBreakpoint) { @media all and ($tablet) {
& > #preview-container { & > #preview-container {
display: none !important; display: none !important;
} }

View File

@ -1,3 +1,12 @@
.toc {
display: flex;
flex-direction: column;
&.desktop-only {
display: flex;
max-height: 40%;
}
}
button#toc { button#toc {
background-color: transparent; background-color: transparent;
border: none; border: none;
@ -28,17 +37,19 @@ button#toc {
#toc-content { #toc-content {
list-style: none; list-style: none;
overflow: hidden; overflow: hidden;
max-height: none; overflow-y: auto;
max-height: 100%;
transition: transition:
max-height 0.5s ease, max-height 0.35s ease,
visibility 0s linear 0s; visibility 0s linear 0s;
position: relative; position: relative;
visibility: visible; visibility: visible;
&.collapsed { &.collapsed {
max-height: 0;
transition: transition:
max-height 0.5s ease, max-height 0.35s ease,
visibility 0s linear 0.5s; visibility 0s linear 0.35s;
visibility: hidden; visibility: hidden;
} }
@ -61,6 +72,10 @@ button#toc {
} }
} }
} }
> ul.overflow {
max-height: none;
width: 100%;
}
@for $i from 0 through 6 { @for $i from 0 through 6 {
& .depth-#{$i} { & .depth-#{$i} {

View File

@ -19,6 +19,7 @@ import pt from "./locales/pt-BR"
import hu from "./locales/hu-HU" import hu from "./locales/hu-HU"
import fa from "./locales/fa-IR" import fa from "./locales/fa-IR"
import pl from "./locales/pl-PL" import pl from "./locales/pl-PL"
import cs from "./locales/cs-CZ"
export const TRANSLATIONS = { export const TRANSLATIONS = {
"en-US": enUs, "en-US": enUs,
@ -62,6 +63,7 @@ export const TRANSLATIONS = {
"hu-HU": hu, "hu-HU": hu,
"fa-IR": fa, "fa-IR": fa,
"pl-PL": pl, "pl-PL": pl,
"cs-CZ": cs,
} as const } as const
export const defaultTranslation = "en-US" export const defaultTranslation = "en-US"

View File

@ -0,0 +1,84 @@
import { Translation } from "./definition"
export default {
propertyDefaults: {
title: "Bez názvu",
description: "Nebyl uveden žádný popis",
},
components: {
callout: {
note: "Poznámka",
abstract: "Abstract",
info: "Info",
todo: "Todo",
tip: "Tip",
success: "Úspěch",
question: "Otázka",
warning: "Upozornění",
failure: "Chyba",
danger: "Nebezpečí",
bug: "Bug",
example: "Příklad",
quote: "Citace",
},
backlinks: {
title: "Příchozí odkazy",
noBacklinksFound: "Nenalezeny žádné příchozí odkazy",
},
themeToggle: {
lightMode: "Světlý režim",
darkMode: "Tmavý režim",
},
explorer: {
title: "Procházet",
},
footer: {
createdWith: "Vytvořeno pomocí",
},
graph: {
title: "Graf",
},
recentNotes: {
title: "Nejnovější poznámky",
seeRemainingMore: ({ remaining }) => `Zobraz ${remaining} dalších →`,
},
transcludes: {
transcludeOf: ({ targetSlug }) => `Zobrazení ${targetSlug}`,
linkToOriginal: "Odkaz na původní dokument",
},
search: {
title: "Hledat",
searchBarPlaceholder: "Hledejte něco",
},
tableOfContents: {
title: "Obsah",
},
contentMeta: {
readingTime: ({ minutes }) => `${minutes} min čtení`,
},
},
pages: {
rss: {
recentNotes: "Nejnovější poznámky",
lastFewNotes: ({ count }) => `Posledních ${count} poznámek`,
},
error: {
title: "Nenalezeno",
notFound: "Tato stránka je buď soukromá, nebo neexistuje.",
home: "Návrat na domovskou stránku",
},
folderContent: {
folder: "Složka",
itemsUnderFolder: ({ count }) =>
count === 1 ? "1 položka v této složce." : `${count} položek v této složce.`,
},
tagContent: {
tag: "Tag",
tagIndex: "Rejstřík tagů",
itemsUnderTag: ({ count }) =>
count === 1 ? "1 položka s tímto tagem." : `${count} položek s tímto tagem.`,
showingFirst: ({ count }) => `Zobrazují se první ${count} tagy.`,
totalTags: ({ count }) => `Nalezeno celkem ${count} tagů.`,
},
},
} as const satisfies Translation

View File

@ -45,7 +45,7 @@ export default {
}, },
transcludes: { transcludes: {
transcludeOf: ({ targetSlug }) => `Переход из ${targetSlug}`, transcludeOf: ({ targetSlug }) => `Переход из ${targetSlug}`,
linkToOriginal: "Ссылка на оригинал", linkToOriginal: "Подробнее",
}, },
search: { search: {
title: "Поиск", title: "Поиск",

View File

@ -147,11 +147,20 @@ function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentReso
} else if (cfg.analytics?.provider === "cabin") { } else if (cfg.analytics?.provider === "cabin") {
componentResources.afterDOMLoaded.push(` componentResources.afterDOMLoaded.push(`
const cabinScript = document.createElement("script") const cabinScript = document.createElement("script")
cabinScript.src = "${cfg.analytics.host ?? "https://scripts.cabin.dev"}/cabin.js" cabinScript.src = "${cfg.analytics.host ?? "https://scripts.withcabin.com"}/hello.js"
cabinScript.defer = true cabinScript.defer = true
cabinScript.async = true cabinScript.async = true
document.head.appendChild(cabinScript) document.head.appendChild(cabinScript)
`) `)
} else if (cfg.analytics?.provider === "clarity") {
componentResources.afterDOMLoaded.push(`
const clarityScript = document.createElement("script")
clarityScript.innerHTML= \`(function(c,l,a,r,i,t,y){c[a]=c[a]||function(){(c[a].q=c[a].q||[]).push(arguments)};
t=l.createElement(r);t.async=1;t.src="https://www.clarity.ms/tag/"+i;
y=l.getElementsByTagName(r)[0];y.parentNode.insertBefore(t,y);
})(window, document, "clarity", "script", "${cfg.analytics.projectId}");\`
document.head.appendChild(clarityScript)
`)
} }
if (cfg.enableSPA) { if (cfg.enableSPA) {

View File

@ -83,7 +83,6 @@ function generateRSSFeed(cfg: GlobalConfiguration, idx: ContentIndex, limit?: nu
<description>${!!limit ? i18n(cfg.locale).pages.rss.lastFewNotes({ count: limit }) : i18n(cfg.locale).pages.rss.recentNotes} on ${escapeHTML( <description>${!!limit ? i18n(cfg.locale).pages.rss.lastFewNotes({ count: limit }) : i18n(cfg.locale).pages.rss.recentNotes} on ${escapeHTML(
cfg.pageTitle, cfg.pageTitle,
)}</description> )}</description>
<generator>Quartz -- quartz.jzhao.xyz</generator>
${items} ${items}
</channel> </channel>
</rss>` </rss>`

View File

@ -21,7 +21,7 @@ export const Citations: QuartzTransformerPlugin<Partial<Options>> = (userOpts) =
const opts = { ...defaultOptions, ...userOpts } const opts = { ...defaultOptions, ...userOpts }
return { return {
name: "Citations", name: "Citations",
htmlPlugins() { htmlPlugins(ctx) {
const plugins: PluggableList = [] const plugins: PluggableList = []
// Add rehype-citation to the list of plugins // Add rehype-citation to the list of plugins
@ -31,6 +31,8 @@ export const Citations: QuartzTransformerPlugin<Partial<Options>> = (userOpts) =
bibliography: opts.bibliographyFile, bibliography: opts.bibliographyFile,
suppressBibliography: opts.suppressBibliography, suppressBibliography: opts.suppressBibliography,
linkCitations: opts.linkCitations, linkCitations: opts.linkCitations,
csl: opts.csl,
lang: ctx.cfg.configuration.locale ?? "en-US",
}, },
]) ])

View File

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

View File

@ -10,3 +10,4 @@ export { OxHugoFlavouredMarkdown } from "./oxhugofm"
export { SyntaxHighlighting } from "./syntax" export { SyntaxHighlighting } from "./syntax"
export { TableOfContents } from "./toc" export { TableOfContents } from "./toc"
export { HardLineBreaks } from "./linebreaks" export { HardLineBreaks } from "./linebreaks"
export { RoamFlavoredMarkdown } from "./roam"

View File

@ -58,18 +58,19 @@ export const CreatedModifiedDate: QuartzTransformerPlugin<Partial<Options>> = (u
// Get a reference to the main git repo. // Get a reference to the main git repo.
// It's either the same as the workdir, // It's either the same as the workdir,
// or 1+ level higher in case of a submodule/subtree setup // or 1+ level higher in case of a submodule/subtree setup
repo = Repository.discover(file.cwd) try {
repo = await Repository.discover(path.join(file.cwd, 'content'), { search: true });
console.log(chalk.green(`Git repository found at: ${repo.path()}`));
} catch (error) {
console.log(chalk.red(`Error discovering Git repository: ${error.message}`));
repo = undefined;
}
} }
try { try {
modified ||= await repo.getFileLatestModifiedDateAsync(file.data.filePath!) modified ||= await repo.getFileLatestModifiedDateAsync(file.data.filePath!.replace(/^content\//, ''));
} catch { } catch (error) {
console.log( console.log(chalk.red(`Error retrieving latest modified date for ${file.data.filePath}: ${error.message}`));
chalk.yellow(
`\nWarning: ${file.data
.filePath!} isn't yet tracked by git, last modification date is not available for this file`,
),
)
} }
} }
} }

View File

@ -60,28 +60,6 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
const isExternal = isAbsoluteUrl(dest) const isExternal = isAbsoluteUrl(dest)
classes.push(isExternal ? "external" : "internal") classes.push(isExternal ? "external" : "internal")
if (isExternal && opts.externalLinkIcon) {
node.children.push({
type: "element",
tagName: "svg",
properties: {
"aria-hidden": "true",
class: "external-icon",
viewBox: "0 0 512 512",
},
children: [
{
type: "element",
tagName: "path",
properties: {
d: "M320 0H288V64h32 82.7L201.4 265.4 178.7 288 224 333.3l22.6-22.6L448 109.3V192v32h64V192 32 0H480 320zM32 32H0V64 480v32H32 456h32V480 352 320H424v32 96H64V96h96 32V32H160 32z",
},
children: [],
},
],
})
}
// Check if the link has alias text // Check if the link has alias text
if ( if (
node.children.length === 1 && node.children.length === 1 &&

View File

@ -119,7 +119,7 @@ export const tableWikilinkRegex = new RegExp(/(!?\[\[[^\]]*?\]\])/g)
const highlightRegex = new RegExp(/==([^=]+)==/g) const highlightRegex = new RegExp(/==([^=]+)==/g)
const commentRegex = new RegExp(/%%[\s\S]*?%%/g) const commentRegex = new RegExp(/%%[\s\S]*?%%/g)
// from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts // from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts
const calloutRegex = new RegExp(/^\[\!(\w+)\|?(.+?)?\]([+-]?)/) const calloutRegex = new RegExp(/^\[\!([\w-]+)\|?(.+?)?\]([+-]?)/)
const calloutLineRegex = new RegExp(/^> *\[\!\w+\|?.*?\][+-]?.*$/gm) const calloutLineRegex = new RegExp(/^> *\[\!\w+\|?.*?\][+-]?.*$/gm)
// (?:^| ) -> non-capturing group, tag should start be separated by a space or be the start of the line // (?:^| ) -> 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 # // #(...) -> capturing group, tag itself must start with #
@ -128,7 +128,7 @@ const calloutLineRegex = new RegExp(/^> *\[\!\w+\|?.*?\][+-]?.*$/gm)
const tagRegex = new RegExp( const tagRegex = new RegExp(
/(?:^| )#((?:[-_\p{L}\p{Emoji}\p{M}\d])+(?:\/[-_\p{L}\p{Emoji}\p{M}\d]+)*)/gu, /(?:^| )#((?:[-_\p{L}\p{Emoji}\p{M}\d])+(?:\/[-_\p{L}\p{Emoji}\p{M}\d]+)*)/gu,
) )
const blockReferenceRegex = new RegExp(/\^([-_A-Za-z0-9]+)$/g) const blockReferenceRegex = new RegExp(/\^([-_A-Za-z0-9\u0400-\u04FF]+)$/g);
const ytLinkRegex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/ const ytLinkRegex = /^.*(youtu.be\/|v\/|u\/\w\/|embed\/|watch\?v=|\&v=)([^#\&\?]*).*/
const ytPlaylistLinkRegex = /[?&]list=([^#?&]*)/ const ytPlaylistLinkRegex = /[?&]list=([^#?&]*)/
const videoExtensionRegex = new RegExp(/\.(mp4|webm|ogg|avi|mov|flv|wmv|mkv|mpg|mpeg|3gp|m4v)$/) const videoExtensionRegex = new RegExp(/\.(mp4|webm|ogg|avi|mov|flv|wmv|mkv|mpg|mpeg|3gp|m4v)$/)
@ -324,8 +324,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>>
replacements.push([ replacements.push([
tagRegex, tagRegex,
(_value: string, tag: string) => { (_value: string, tag: string) => {
// Check if the tag only includes numbers // Check if the tag only includes numbers and slashes
if (/^\d+$/.test(tag)) { if (/^[\/\d]+$/.test(tag)) {
return false return false
} }
@ -430,7 +430,9 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>>
children: [ children: [
{ {
type: "text", type: "text",
value: useDefaultTitle ? capitalize(typeString) : titleContent + " ", value: useDefaultTitle
? capitalize(typeString).replace(/-/g, " ")
: titleContent + " ",
}, },
...restOfTitle, ...restOfTitle,
], ],

View File

@ -0,0 +1,224 @@
import { QuartzTransformerPlugin } from "../types"
import { PluggableList } from "unified"
import { SKIP, visit } from "unist-util-visit"
import { ReplaceFunction, findAndReplace as mdastFindReplace } from "mdast-util-find-and-replace"
import { Root, Html, Paragraph, Text, Link, Parent } from "mdast"
import { Node } from "unist"
import { VFile } from "vfile"
import { BuildVisitor } from "unist-util-visit"
export interface Options {
orComponent: boolean
TODOComponent: boolean
DONEComponent: boolean
videoComponent: boolean
audioComponent: boolean
pdfComponent: boolean
blockquoteComponent: boolean
tableComponent: boolean
attributeComponent: boolean
}
const defaultOptions: Options = {
orComponent: true,
TODOComponent: true,
DONEComponent: true,
videoComponent: true,
audioComponent: true,
pdfComponent: true,
blockquoteComponent: true,
tableComponent: true,
attributeComponent: true,
}
const orRegex = new RegExp(/{{or:(.*?)}}/, "g")
const TODORegex = new RegExp(/{{.*?\bTODO\b.*?}}/, "g")
const DONERegex = new RegExp(/{{.*?\bDONE\b.*?}}/, "g")
const videoRegex = new RegExp(/{{.*?\[\[video\]\].*?\:(.*?)}}/, "g")
const youtubeRegex = new RegExp(
/{{.*?\[\[video\]\].*?(https?:\/\/(?:www\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?[\w\?=]*)?)}}/,
"g",
)
// const multimediaRegex = new RegExp(/{{.*?\b(video|audio)\b.*?\:(.*?)}}/, "g")
const audioRegex = new RegExp(/{{.*?\[\[audio\]\].*?\:(.*?)}}/, "g")
const pdfRegex = new RegExp(/{{.*?\[\[pdf\]\].*?\:(.*?)}}/, "g")
const blockquoteRegex = new RegExp(/(\[\[>\]\])\s*(.*)/, "g")
const roamHighlightRegex = new RegExp(/\^\^(.+)\^\^/, "g")
const roamItalicRegex = new RegExp(/__(.+)__/, "g")
const tableRegex = new RegExp(/- {{.*?\btable\b.*?}}/, "g") /* TODO */
const attributeRegex = new RegExp(/\b\w+(?:\s+\w+)*::/, "g") /* TODO */
function isSpecialEmbed(node: Paragraph): boolean {
if (node.children.length !== 2) return false
const [textNode, linkNode] = node.children
return (
textNode.type === "text" &&
textNode.value.startsWith("{{[[") &&
linkNode.type === "link" &&
linkNode.children[0].type === "text" &&
linkNode.children[0].value.endsWith("}}")
)
}
function transformSpecialEmbed(node: Paragraph, opts: Options): Html | null {
const [textNode, linkNode] = node.children as [Text, Link]
const embedType = textNode.value.match(/\{\{\[\[(.*?)\]\]:/)?.[1]?.toLowerCase()
const url = linkNode.url.slice(0, -2) // Remove the trailing '}}'
switch (embedType) {
case "audio":
return opts.audioComponent
? {
type: "html",
value: `<audio controls>
<source src="${url}" type="audio/mpeg">
<source src="${url}" type="audio/ogg">
Your browser does not support the audio tag.
</audio>`,
}
: null
case "video":
if (!opts.videoComponent) return null
// Check if it's a YouTube video
const youtubeMatch = url.match(
/(?:https?:\/\/)?(?:www\.)?(?:youtube\.com|youtu\.be)\/(?:watch\?v=)?(.+)/,
)
if (youtubeMatch) {
const videoId = youtubeMatch[1].split("&")[0] // Remove additional parameters
const playlistMatch = url.match(/[?&]list=([^#\&\?]*)/)
const playlistId = playlistMatch ? playlistMatch[1] : null
return {
type: "html",
value: `<iframe
class="external-embed youtube"
width="600px"
height="350px"
src="https://www.youtube.com/embed/${videoId}${playlistId ? `?list=${playlistId}` : ""}"
frameborder="0"
allow="fullscreen"
></iframe>`,
}
} else {
return {
type: "html",
value: `<video controls>
<source src="${url}" type="video/mp4">
<source src="${url}" type="video/webm">
Your browser does not support the video tag.
</video>`,
}
}
case "pdf":
return opts.pdfComponent
? {
type: "html",
value: `<embed src="${url}" type="application/pdf" width="100%" height="600px" />`,
}
: null
default:
return null
}
}
export const RoamFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options> | undefined> = (
userOpts,
) => {
const opts = { ...defaultOptions, ...userOpts }
return {
name: "RoamFlavoredMarkdown",
markdownPlugins() {
const plugins: PluggableList = []
plugins.push(() => {
return (tree: Root, file: VFile) => {
const replacements: [RegExp, ReplaceFunction][] = []
// Handle special embeds (audio, video, PDF)
if (opts.audioComponent || opts.videoComponent || opts.pdfComponent) {
visit(tree, "paragraph", ((node: Paragraph, index: number, parent: Parent | null) => {
if (isSpecialEmbed(node)) {
const transformedNode = transformSpecialEmbed(node, opts)
if (transformedNode && parent) {
parent.children[index] = transformedNode
}
}
}) as BuildVisitor<Root, "paragraph">)
}
// Roam italic syntax
replacements.push([
roamItalicRegex,
(_value: string, match: string) => ({
type: "emphasis",
children: [{ type: "text", value: match }],
}),
])
// Roam highlight syntax
replacements.push([
roamHighlightRegex,
(_value: string, inner: string) => ({
type: "html",
value: `<span class="text-highlight">${inner}</span>`,
}),
])
if (opts.orComponent) {
replacements.push([
orRegex,
(match: string) => {
const matchResult = match.match(/{{or:(.*?)}}/)
if (matchResult === null) {
return { type: "html", value: "" }
}
const optionsString: string = matchResult[1]
const options: string[] = optionsString.split("|")
const selectHtml: string = `<select>${options.map((option: string) => `<option value="${option}">${option}</option>`).join("")}</select>`
return { type: "html", value: selectHtml }
},
])
}
if (opts.TODOComponent) {
replacements.push([
TODORegex,
() => ({
type: "html",
value: `<input type="checkbox" disabled>`,
}),
])
}
if (opts.DONEComponent) {
replacements.push([
DONERegex,
() => ({
type: "html",
value: `<input type="checkbox" checked disabled>`,
}),
])
}
if (opts.blockquoteComponent) {
replacements.push([
blockquoteRegex,
(_match: string, _marker: string, content: string) => ({
type: "html",
value: `<blockquote>${content.trim()}</blockquote>`,
}),
])
}
mdastFindReplace(tree, replacements)
}
})
return plugins
},
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 38 KiB

BIN
quartz/static/og-image.webp Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

455
quartz/static/share.js Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 66 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 66 KiB

View File

@ -12,7 +12,6 @@ html {
body, body,
section { section {
margin: 0; margin: 0;
max-width: 100%;
box-sizing: border-box; box-sizing: border-box;
background-color: var(--light); background-color: var(--light);
font-family: var(--bodyFont); font-family: var(--bodyFont);
@ -97,37 +96,25 @@ a {
} }
} }
&.external .external-icon {
height: 1ex;
margin: 0 0.15em;
> path {
fill: var(--dark);
}
}
} }
.desktop-only { .desktop-only {
display: initial; display: initial;
@media all and (max-width: $fullPageWidth) { @media all and ($mobile) {
display: none; display: none;
} }
} }
.mobile-only { .mobile-only {
display: none; display: none;
@media all and (max-width: $fullPageWidth) { @media all and ($mobile) {
display: initial; display: initial;
} }
} }
.page { .page {
@media all and (max-width: $fullPageWidth) { max-width: calc(#{map-get($breakpoints, desktop)} + 300px);
margin: 0 auto; margin: 0 auto;
padding: 0 1rem;
max-width: $pageWidth;
}
& article { & article {
& > h1 { & > h1 {
font-size: 2rem; font-size: 2rem;
@ -155,79 +142,119 @@ a {
} }
& > #quartz-body { & > #quartz-body {
width: 100%; display: grid;
display: flex; grid-template-columns: #{map-get($desktopGrid, templateColumns)};
@media all and (max-width: $fullPageWidth) { grid-template-rows: #{map-get($desktopGrid, templateRows)};
flex-direction: column; column-gap: #{map-get($desktopGrid, columnGap)};
row-gap: #{map-get($desktopGrid, rowGap)};
grid-template-areas: #{map-get($desktopGrid, templateAreas)};
@media all and ($desktop) {
grid-template-columns: #{map-get($tabletGrid, templateColumns)};
grid-template-rows: #{map-get($tabletGrid, templateRows)};
column-gap: #{map-get($tabletGrid, columnGap)};
row-gap: #{map-get($tabletGrid, rowGap)};
grid-template-areas: #{map-get($tabletGrid, templateAreas)};
}
@media all and ($mobile) {
grid-template-columns: #{map-get($mobileGrid, templateColumns)};
grid-template-rows: #{map-get($mobileGrid, templateRows)};
column-gap: #{map-get($mobileGrid, columnGap)};
row-gap: #{map-get($mobileGrid, rowGap)};
grid-template-areas: #{map-get($mobileGrid, templateAreas)};
}
@media all and ($desktop) {
padding: 0 1rem;
}
@media all and ($mobile) {
margin: 0 auto;
} }
& .sidebar { & .sidebar {
flex: 1;
display: flex;
flex-direction: column;
gap: 2rem; gap: 2rem;
top: 0; top: 0;
width: $sidePanelWidth;
margin-top: $topSpacing;
box-sizing: border-box; box-sizing: border-box;
padding: 0 4rem; padding: $topSpacing 2rem 2rem 2rem;
position: fixed; display: flex;
@media all and (max-width: $fullPageWidth) { height: 100vh;
position: initial; position: sticky;
flex-direction: row;
padding: 0;
width: initial;
margin-top: 2rem;
}
} }
& .sidebar.left { & .sidebar.left {
z-index: 1; z-index: 1;
left: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); grid-area: grid-sidebar-left;
@media all and (max-width: $fullPageWidth) { flex-direction: column;
@media all and ($mobile) {
gap: 0; gap: 0;
align-items: center; align-items: center;
position: initial;
display: flex;
height: unset;
flex-direction: row;
padding: 0;
padding-top: 2rem;
} }
} }
& .sidebar.right { & .sidebar.right {
right: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); grid-area: grid-sidebar-right;
flex-wrap: wrap; margin-right: 0;
& > * { flex-direction: column;
@media all and (max-width: $fullPageWidth) { @media all and ($mobile) {
margin-left: inherit;
margin-right: inherit;
}
@media all and ($desktop) {
position: initial;
height: unset;
width: 100%;
flex-direction: row;
padding: 0;
& > * {
flex: 1; flex: 1;
min-width: 140px; }
& > .toc {
display: none;
} }
} }
} }
} & .page-header,
& .page-footer {
& .page-header, margin-top: 1rem;
& .page-footer {
width: $pageWidth;
margin-top: 1rem;
@media all and (max-width: $fullPageWidth) {
width: initial;
} }
}
& .page-header { & .page-header {
margin: $topSpacing auto 0 auto; grid-area: grid-header;
@media all and (max-width: $fullPageWidth) { margin: $topSpacing 0 0 0;
margin-top: 2rem; @media all and ($mobile) {
margin-top: 0;
padding: 0;
}
} }
}
& .center, & .center > article {
& footer { grid-area: grid-center;
margin-left: auto; }
margin-right: auto;
width: $pageWidth; & footer {
@media all and (max-width: $fullPageWidth) { grid-area: grid-footer;
width: initial; }
& .center,
& footer {
max-width: 100%;
min-width: 100%;
margin-left: auto;
margin-right: auto;
@media all and ($desktop) {
margin-right: 0;
}
@media all and ($mobile) {
margin-left: 0;
}
}
& footer {
margin-left: 0; margin-left: 0;
margin-right: 0;
} }
} }
} }
@ -383,7 +410,7 @@ pre {
counter-increment: line 0; counter-increment: line 0;
display: grid; display: grid;
padding: 0.5rem 0; padding: 0.5rem 0;
overflow-x: scroll; overflow-x: auto;
& [data-highlighted-chars] { & [data-highlighted-chars] {
background-color: var(--highlight); background-color: var(--highlight);
@ -502,12 +529,14 @@ video {
} }
div:has(> .overflow) { div:has(> .overflow) {
position: relative; display: flex;
overflow-y: auto;
max-height: 100%;
} }
ul.overflow, ul.overflow,
ol.overflow { ol.overflow {
max-height: 400; max-height: 100%;
overflow-y: auto; overflow-y: auto;
// clearfix // clearfix
@ -517,8 +546,7 @@ ol.overflow {
& > li:last-of-type { & > li:last-of-type {
margin-bottom: 30px; margin-bottom: 30px;
} }
/*&:after {
&:after {
pointer-events: none; pointer-events: none;
content: ""; content: "";
width: 100%; width: 100%;
@ -529,7 +557,7 @@ ol.overflow {
opacity: 1; opacity: 1;
transition: opacity 0.3s ease; transition: opacity 0.3s ease;
background: linear-gradient(transparent 0px, var(--light)); background: linear-gradient(transparent 0px, var(--light));
} }*/
} }
.transclude { .transclude {

View File

@ -1,3 +1,232 @@
@use "./base.scss"; @use "./base.scss";
// put your custom CSS here! a[href^=http]:not([href*=garden\.struchkov\.dev]):not([href*=t\.me\/struchkov_dev]):after {
content: " ↗"
}
article {
font-size: 1.1rem;
}
a.external {
text-decoration: none;
border-bottom: 1.3px dashed;
}
a.internal {
border-radius: .1875rem;
padding: 0 .3rem;
}
.recent-notes>ul.recent-ul>li .section>.desc>span>a {
padding: 0;
background: none;
}
.search>#search-container {
background-color: #23252f33;
backdrop-filter: blur(8px);
}
.backlinks>ul {
list-style: disc;
}
.github-source {
a {
border-bottom: 0;
}
}
li.section-li>.section .meta {
margin: 0;
}
.article-title {
margin: 0.5rem 0 0;
}
.text-highlight {
margin: -3px -3px -6px;
padding: 3px 3px 6px;
}
h1 {
font-size: 1.8rem;
}
h2 {
margin-top: 6rem;
font-size: 1.6rem;
}
h3 {
margin-top: 4rem;
font-size: 1.4rem;
}
.backlinks {
h3 {
margin-top: 4rem;
font-size: 1.4rem;
}
}
h4 {
margin-top: 2rem;
font-size: 1.2rem;
}
article strong {
color: var(--secondary);
}
:not(pre)>code {
background: #e5eff5;
border: 1px solid var(--secondary);
border-radius: 6px;
color: #903;
font-size: .85em;
padding: .24rem .4rem .19rem;
text-shadow: none;
vertical-align: 0;
white-space: normal;
word-break: break-word;
}
.popover-hint {
margin-top: 3rem;
}
input[type="checkbox"] {
border-color: var(--secondary);
}
.notice {
align-items: flex-start;
border-radius: 8px;
display: flex;
flex-direction: column;
overflow: hidden;
padding: 1rem;
position: relative
}
.notice.notice-telegram {
background-color: #5381bd
}
.notice.notice-twitter {
background-color: #1da1f2
}
.notice.notice-comments {
background-color: #2c678d
}
.notice.notice-donate {
background-color: #ee5162;
background-color: var(--notice-donate)
}
.notice__head {
align-items: center;
border: 1px dashed rgba(206,226,241,.85);
border-radius: 6px;
display: flex;
padding: .5rem 2rem
}
.notice__head-icon {
color: #fff;
width: 1.25rem
}
.notice__head-text {
color: #fff;
font-size: .9375rem;
letter-spacing: .0625rem;
margin: 0 0 0 1rem
}
.kg-width-wide .notice__head-text {
font-size: 1.1rem
}
.notice__tail {
margin: .5rem 0 0
}
.notice__tail-left {
margin: 0 .5rem
}
.notice__tail-text {
color: #fff;
font-size: .9375rem;
letter-spacing: .03125rem
}
.kg-width-wide .notice__tail-text {
font-size: 1.3rem
}
.notice__skin {
position: absolute;
right: 1rem;
top: 1rem
}
.notice__skin-icon {
color: rgba(206,226,241,.15);
width: 10rem
}
@media only screen and (min-width: 36em) {
.notice {
align-items:center;
flex-direction: row
}
}
@media only screen and (min-width: 48em) {
.notice {
padding:1rem 3rem
}
.kg-width-wide .notice {
padding: 2rem 3rem
}
}
@media only screen and (min-width: 36em) {
.notice__tail {
margin:0 0 0 1.25rem
}
.notice__tail-left {
margin: 0 1.25rem 0 0
}
.notice__tail-text {
font-size: 1.0625rem
}
}
@media only screen and (min-width: 48em) {
.notice__skin {
right:3rem
}
}
@media (max-width: 700px) {
.notice__tail-left {
display:none
}
}
@media (max-width: 980px) {
.footer-notice .notice {
border-radius:0
}
}

View File

@ -1,9 +1,56 @@
$pageWidth: 750px; /**
$mobileBreakpoint: 600px; * Layout breakpoints
$tabletBreakpoint: 1000px; * $mobile: screen width below this value will use mobile styles
$sidePanelWidth: 380px; * $desktop: screen width above this value will use desktop styles
* Screen width between $mobile and $desktop width will use the tablet layout.
* assuming mobile < desktop
*/
$breakpoints: (
mobile: 800px,
desktop: 1200px,
);
$mobile: "(max-width: #{map-get($breakpoints, mobile)})";
$tablet: "(min-width: #{map-get($breakpoints, mobile)}) and (max-width: #{map-get($breakpoints, desktop)})";
$desktop: "(max-width: #{map-get($breakpoints, desktop)})";
$pageWidth: #{map-get($breakpoints, mobile)};
$sidePanelWidth: 320px; //380px;
$topSpacing: 6rem; $topSpacing: 6rem;
$fullPageWidth: $pageWidth + 2 * $sidePanelWidth;
$boldWeight: 700; $boldWeight: 700;
$semiBoldWeight: 600; $semiBoldWeight: 600;
$normalWeight: 400; $normalWeight: 400;
$mobileGrid: (
templateRows: "auto auto auto auto auto",
templateColumns: "auto",
rowGap: "5px",
columnGap: "5px",
templateAreas:
'"grid-sidebar-left"\
"grid-header"\
"grid-center"\
"grid-sidebar-right"\
"grid-footer"',
);
$tabletGrid: (
templateRows: "auto auto auto auto",
templateColumns: "#{$sidePanelWidth} auto",
rowGap: "5px",
columnGap: "5px",
templateAreas:
'"grid-sidebar-left grid-header"\
"grid-sidebar-left grid-center"\
"grid-sidebar-left grid-sidebar-right"\
"grid-sidebar-left grid-footer"',
);
$desktopGrid: (
templateRows: "auto auto auto",
templateColumns: "#{$sidePanelWidth} auto #{$sidePanelWidth}",
rowGap: "5px",
columnGap: "5px",
templateAreas:
'"grid-sidebar-left grid-header grid-sidebar-right"\
"grid-sidebar-left grid-center grid-sidebar-right"\
"grid-sidebar-left grid-footer grid-sidebar-right"',
);

View File

@ -8,6 +8,7 @@ export interface ColorScheme {
tertiary: string tertiary: string
highlight: string highlight: string
textHighlight: string textHighlight: string
shareIcon: string
} }
interface Colors { interface Colors {
@ -51,6 +52,7 @@ ${stylesheet.join("\n\n")}
--tertiary: ${theme.colors.lightMode.tertiary}; --tertiary: ${theme.colors.lightMode.tertiary};
--highlight: ${theme.colors.lightMode.highlight}; --highlight: ${theme.colors.lightMode.highlight};
--textHighlight: ${theme.colors.lightMode.textHighlight}; --textHighlight: ${theme.colors.lightMode.textHighlight};
--sprite-share-icon-color: ${theme.colors.lightMode.shareIcon};
--headerFont: "${theme.typography.header}", ${DEFAULT_SANS_SERIF}; --headerFont: "${theme.typography.header}", ${DEFAULT_SANS_SERIF};
--bodyFont: "${theme.typography.body}", ${DEFAULT_SANS_SERIF}; --bodyFont: "${theme.typography.body}", ${DEFAULT_SANS_SERIF};
@ -67,6 +69,7 @@ ${stylesheet.join("\n\n")}
--tertiary: ${theme.colors.darkMode.tertiary}; --tertiary: ${theme.colors.darkMode.tertiary};
--highlight: ${theme.colors.darkMode.highlight}; --highlight: ${theme.colors.darkMode.highlight};
--textHighlight: ${theme.colors.darkMode.textHighlight}; --textHighlight: ${theme.colors.darkMode.textHighlight};
--sprite-share-icon: ${theme.colors.darkMode.shareIcon};
} }
` `
} }

34
zip_image.sh Normal file
View File

@ -0,0 +1,34 @@
#!/bin/bash
file=comp.flag
if [ -f "$file" ]; then
option="-newer $file"
fi
find ./images/ -type f -not -path "./images/comp/*" ! -name "*-no-comp.*" $option -iname "*.png" -exec sh -c '
png_file="${1/\/images\//\/images\/comp\/}"
png_dir="$(dirname "$png_file")"
mkdir -p "$png_dir"
cp "$1" "${png_file}"
optipng -o7 "${png_file}"
advpng -z4 "${png_file}"
pngcrush -rem gAMA -rem alla -rem cHRM -rem iCCP -rem sRGB -rem time -ow "${png_file}"
' _ {} \;
find ./images/ -type f -not -path "./images/comp/*" ! -name "*-no-comp.*" $option -iregex '.*\.\(jpg\|jpeg\)' -exec sh -c '
jpg_file="${1/\/images\//\/images\/comp\/}"
jpg_dir="$(dirname "$jpg_file")"
mkdir -p "$jpg_dir"
cp "$1" "${jpg_file}"
jpegoptim --all-progressive "${jpg_file}"
' _ {} \;
find ./images/comp -type f -iregex '.*\.\(jpg\|jpeg\|png\)' -not -iregex '.*no-comp\.\(jpg\|jpeg\|png\)' $option -exec sh -c '
webp_file="${1/\/images\/comp\//\/images\/webp\/}"
webp_dir="$(dirname "$webp_file")"
mkdir -p "$webp_dir"
cwebp -mt -af -progress -m 6 -q 75 -pass 10 "$1" -o "${webp_file%.*}.webp"
' _ {} \;
touch $file
echo "$(date)" > $file