Compare commits

..

4 Commits

Author SHA1 Message Date
Aaron Pham
7a335c7a5b chore: update in favor of prose
Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
2025-07-08 22:51:47 -04:00
Aaron Pham
863a394a37 Apply suggestion from @jackyzha0
Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
2025-07-08 22:51:13 -04:00
Aaron Pham
ba2b8bb0c5 Update .github/pull_request_template.md 2025-07-08 16:16:32 -04:00
Aaron Pham
79e7e782ac chore: add PR templates
Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
2025-07-08 15:44:41 -04:00
19 changed files with 443 additions and 551 deletions

View File

@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
name: Build Preview
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
fetch-depth: 0

View File

@@ -19,7 +19,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
fetch-depth: 0
@@ -53,7 +53,7 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Setup Node

View File

@@ -18,7 +18,7 @@ jobs:
name: Deploy Preview to Cloudflare Pages
steps:
- name: Download build artifact
uses: actions/download-artifact@v5
uses: actions/download-artifact@v4
id: preview-build-artifact
with:
name: preview-build

View File

@@ -21,11 +21,11 @@ jobs:
echo "OWNER_LOWERCASE=${OWNER,,}" >> ${GITHUB_ENV}
env:
OWNER: "${{ github.repository_owner }}"
- uses: actions/checkout@v5
- uses: actions/checkout@v4
with:
fetch-depth: 1
- name: Inject slug/short variables
uses: rlespinasse/github-slug-action@v5.2.0
uses: rlespinasse/github-slug-action@v5.1.0
- name: Set up QEMU
uses: docker/setup-qemu-action@v3
- name: Set up Docker Buildx
@@ -37,7 +37,7 @@ jobs:
network=host
- name: Install cosign
if: github.event_name != 'pull_request'
uses: sigstore/cosign-installer@v3.9.2
uses: sigstore/cosign-installer@v3.9.1
- name: Login to GitHub Container Registry
uses: docker/login-action@v3
if: github.event_name != 'pull_request'

View File

@@ -34,7 +34,6 @@ This part of the configuration concerns anything that can affect the whole site.
- `{ 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: '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.
- `{ provider: 'matomo', siteId: '<your-matomo-id-code', host: 'matomo.example.com' }`: use [Matomo](https://matomo.org/), without protocol.
- `locale`: used for [[i18n]] and date formatting
- `baseUrl`: this is used for sitemaps and RSS feeds that require an absolute URL to know where the canonical 'home' of your site lives. This is normally the deployed URL of your site (e.g. `quartz.jzhao.xyz` for this site). Do not include the protocol (i.e. `https://`) or any leading or trailing slashes.
- This should also include the subpath if you are [[hosting]] on GitHub pages without a custom domain. For example, if my repository is `jackyzha0/quartz`, GitHub pages would deploy to `https://jackyzha0.github.io/quartz` and the `baseUrl` would be `jackyzha0.github.io/quartz`.

816
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -2,7 +2,7 @@
"name": "@jackyzha0/quartz",
"description": "🌱 publish your digital garden and notes as a website",
"private": true,
"version": "4.5.2",
"version": "4.5.1",
"type": "module",
"author": "jackyzha0 <j.zhao2k19@gmail.com>",
"license": "MIT",
@@ -36,11 +36,12 @@
},
"dependencies": {
"@clack/prompts": "^0.11.0",
"@floating-ui/dom": "^1.7.3",
"@floating-ui/dom": "^1.7.0",
"@myriaddreamin/rehype-typst": "^0.6.0",
"@napi-rs/simple-git": "0.1.21",
"@napi-rs/simple-git": "0.1.19",
"@tweenjs/tween.js": "^25.0.0",
"ansi-truncate": "^1.3.0",
"@webgpu/types": "^0.1.61",
"ansi-truncate": "^1.2.0",
"async-mutex": "^0.5.0",
"chokidar": "^4.0.3",
"cli-spinner": "^0.2.10",
@@ -60,9 +61,9 @@
"mdast-util-to-hast": "^13.2.0",
"mdast-util-to-string": "^4.0.0",
"micromorph": "^0.4.5",
"minimatch": "^10.0.3",
"pixi.js": "^8.12.0",
"preact": "^10.27.0",
"minimatch": "^10.0.1",
"pixi.js": "^8.9.2",
"preact": "^10.26.7",
"preact-render-to-string": "^6.5.13",
"pretty-bytes": "^7.0.0",
"pretty-time": "^1.1.0",
@@ -83,9 +84,9 @@
"remark-rehype": "^11.1.2",
"remark-smartypants": "^3.0.2",
"rfdc": "^1.4.1",
"satori": "^0.16.2",
"satori": "^0.13.1",
"serve-handler": "^6.1.6",
"sharp": "^0.34.3",
"sharp": "^0.34.2",
"shiki": "^1.26.2",
"source-map-support": "^0.5.21",
"to-vfile": "^8.0.0",
@@ -93,22 +94,22 @@
"unified": "^11.0.5",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.3",
"workerpool": "^9.3.3",
"ws": "^8.18.3",
"workerpool": "^9.2.0",
"ws": "^8.18.2",
"yargs": "^18.0.0"
},
"devDependencies": {
"@types/d3": "^7.4.3",
"@types/hast": "^3.0.4",
"@types/js-yaml": "^4.0.9",
"@types/node": "^24.2.1",
"@types/node": "^22.15.23",
"@types/pretty-time": "^1.1.5",
"@types/source-map-support": "^0.5.10",
"@types/ws": "^8.18.1",
"@types/yargs": "^17.0.33",
"esbuild": "^0.25.8",
"prettier": "^3.6.2",
"tsx": "^4.20.3",
"typescript": "^5.9.2"
"esbuild": "^0.25.5",
"prettier": "^3.5.3",
"tsx": "^4.19.4",
"typescript": "^5.8.3"
}
}

View File

@@ -42,11 +42,6 @@ export type Analytics =
provider: "clarity"
projectId?: string
}
| {
provider: "matomo"
host: string
siteId: string
}
export interface GlobalConfiguration {
pageTitle: string

View File

@@ -55,14 +55,11 @@ export type FolderState = {
collapsed: boolean
}
let numExplorers = 0
export default ((userOpts?: Partial<Options>) => {
const opts: Options = { ...defaultOptions, ...userOpts }
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
const Explorer: QuartzComponent = ({ cfg, displayClass }: QuartzComponentProps) => {
const id = `explorer-${numExplorers++}`
return (
<div
class={classNames(displayClass, "explorer")}
@@ -80,7 +77,7 @@ export default ((userOpts?: Partial<Options>) => {
type="button"
class="explorer-toggle mobile-explorer hide-until-loaded"
data-mobile={true}
aria-controls={id}
aria-controls="explorer-content"
>
<svg
xmlns="http://www.w3.org/2000/svg"
@@ -119,7 +116,7 @@ export default ((userOpts?: Partial<Options>) => {
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<div id={id} class="explorer-content" aria-expanded={false} role="group">
<div class="explorer-content" aria-expanded={false}>
<OverflowList class="explorer-ul" />
</div>
<template id="template-file">

View File

@@ -12,9 +12,9 @@ const OverflowList = ({
)
}
let numLists = 0
let numExplorers = 0
export default () => {
const id = `list-${numLists++}`
const id = `list-${numExplorers++}`
return {
OverflowList: (props: JSX.HTMLAttributes<HTMLUListElement>) => (

View File

@@ -17,7 +17,6 @@ const defaultOptions: Options = {
layout: "modern",
}
let numTocs = 0
export default ((opts?: Partial<Options>) => {
const layout = opts?.layout ?? defaultOptions.layout
const { OverflowList, overflowListAfterDOMLoaded } = OverflowListFactory()
@@ -30,13 +29,12 @@ export default ((opts?: Partial<Options>) => {
return null
}
const id = `toc-${numTocs++}`
return (
<div class={classNames(displayClass, "toc")}>
<button
type="button"
class={fileData.collapseToc ? "collapsed toc-header" : "toc-header"}
aria-controls={id}
aria-controls="toc-content"
aria-expanded={!fileData.collapseToc}
>
<h3>{i18n(cfg.locale).components.tableOfContents.title}</h3>
@@ -55,10 +53,7 @@ export default ((opts?: Partial<Options>) => {
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<OverflowList
id={id}
class={fileData.collapseToc ? "collapsed toc-content" : "toc-content"}
>
<OverflowList class={fileData.collapseToc ? "collapsed toc-content" : "toc-content"}>
{fileData.toc.map((tocEntry) => (
<li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}>
<a href={`#${tocEntry.slug}`} data-for={tocEntry.slug}>

View File

@@ -68,6 +68,30 @@ type TweenNode = {
stop: () => void
}
// workaround for pixijs webgpu issue: https://github.com/pixijs/pixijs/issues/11389
async function determineGraphicsAPI(): Promise<"webgpu" | "webgl"> {
const adapter = await navigator.gpu?.requestAdapter().catch(() => null)
const device = adapter && (await adapter.requestDevice().catch(() => null))
if (!device) {
return "webgl"
}
const canvas = document.createElement("canvas")
const gl =
(canvas.getContext("webgl2") as WebGL2RenderingContext | null) ??
(canvas.getContext("webgl") as WebGLRenderingContext | null)
// we have to return webgl so pixijs automatically falls back to canvas
if (!gl) {
return "webgl"
}
const webglMaxTextures = gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS)
const webgpuMaxTextures = device.limits.maxSampledTexturesPerShaderStage
return webglMaxTextures === webgpuMaxTextures ? "webgpu" : "webgl"
}
async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
const slug = simplifySlug(fullSlug)
const visited = getVisited()
@@ -349,6 +373,7 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
tweens.forEach((tween) => tween.stop())
tweens.clear()
const pixiPreference = await determineGraphicsAPI()
const app = new Application()
await app.init({
width,
@@ -357,7 +382,7 @@ async function renderGraph(graph: HTMLElement, fullSlug: FullSlug) {
autoStart: false,
autoDensity: true,
backgroundAlpha: 0,
preference: "webgpu",
preference: pixiPreference,
resolution: window.devicePixelRatio,
eventMode: "static",
})

View File

@@ -220,7 +220,7 @@ async function setupSearch(searchElement: Element, currentSlug: FullSlug, data:
// If search is active, then we will render the first result and display accordingly
if (!container.classList.contains("active")) return
if (e.key === "Enter" && !e.isComposing) {
if (e.key === "Enter") {
// If result has focus, navigate to that one, otherwise pick first result
if (results.contains(document.activeElement)) {
const active = document.activeElement as HTMLInputElement

View File

@@ -51,7 +51,7 @@ export default {
},
search: {
title: "Szukaj",
searchBarPlaceholder: "Wpisz frazę wyszukiwania",
searchBarPlaceholder: "Search for something",
},
tableOfContents: {
title: "Spis treści",

View File

@@ -201,33 +201,6 @@ function addGlobalPageResources(ctx: BuildCtx, componentResources: ComponentReso
})(window, document, "clarity", "script", "${cfg.analytics.projectId}");\`
document.head.appendChild(clarityScript)
`)
} else if (cfg.analytics?.provider === "matomo") {
componentResources.afterDOMLoaded.push(`
const matomoScript = document.createElement("script");
matomoScript.innerHTML = \`
let _paq = window._paq = window._paq || [];
// Track SPA navigation
// https://developer.matomo.org/guides/spa-tracking
document.addEventListener("nav", () => {
_paq.push(['setCustomUrl', location.pathname]);
_paq.push(['setDocumentTitle', document.title]);
_paq.push(['trackPageView']);
});
_paq.push(['trackPageView']);
_paq.push(['enableLinkTracking']);
(function() {
const u="//${cfg.analytics.host}/";
_paq.push(['setTrackerUrl', u+'matomo.php']);
_paq.push(['setSiteId', ${cfg.analytics.siteId}]);
const d=document, g=d.createElement('script'), s=d.getElementsByTagName
('script')[0];
g.type='text/javascript'; g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s);
})();
\`
document.head.appendChild(matomoScript);
`)
}
if (cfg.enableSPA) {

View File

@@ -58,7 +58,7 @@ function generateRSSFeed(cfg: GlobalConfiguration, idx: ContentIndexMap, limit?:
<title>${escapeHTML(content.title)}</title>
<link>https://${joinSegments(base, encodeURI(slug))}</link>
<guid>https://${joinSegments(base, encodeURI(slug))}</guid>
<description><![CDATA[ ${content.richContent ?? content.description} ]]></description>
<description>${content.richContent ?? content.description}</description>
<pubDate>${content.date?.toUTCString()}</pubDate>
</item>`

View File

@@ -488,7 +488,16 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>>
{
data: { hProperties: { className: ["callout-content"] }, hName: "div" },
type: "blockquote",
children: [...calloutContent],
children: [
{
data: {
hProperties: { className: ["callout-content-inner"] },
hName: "div",
},
type: "blockquote",
children: [...calloutContent],
},
],
},
]
}

View File

@@ -39,9 +39,7 @@ li,
ol,
ul,
.katex,
.math,
.typst-doc,
.typst-doc * {
.math {
color: var(--darkgray);
fill: var(--darkgray);
hyphens: auto;
@@ -55,9 +53,7 @@ li,
ol,
ul,
.katex,
.math,
.typst-doc,
.typst-doc * {
.math {
overflow-wrap: anywhere;
/* tr and td removed from list of selectors for overflow-wrap, allowing them to use default 'normal' property value */
}

View File

@@ -11,11 +11,14 @@
& > .callout-content {
display: grid;
transition: grid-template-rows 0.1s cubic-bezier(0.02, 0.01, 0.47, 1);
overflow: hidden;
transition: grid-template-rows 0.3s ease;
& > :first-child {
margin-top: 0;
& > .callout-content-inner {
overflow: hidden;
& > :first-child {
margin-top: 0;
}
}
}
@@ -118,19 +121,8 @@
--callout-icon: var(--callout-icon-quote);
}
&.is-collapsed {
& > .callout-title > .fold-callout-icon {
transform: rotateZ(-90deg);
}
.callout-content > :first-child {
transition:
height 0.1s cubic-bezier(0.02, 0.01, 0.47, 1),
margin 0.1s cubic-bezier(0.02, 0.01, 0.47, 1);
overflow-y: clip;
height: 0;
margin-top: -1rem;
}
&.is-collapsed > .callout-title > .fold-callout-icon {
transform: rotateZ(-90deg);
}
}