This commit is contained in:
Ryan Kes 2024-09-17 17:16:48 +08:00
commit 5a13e44daf
8 changed files with 74 additions and 69 deletions

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
> - `--port`: what port to run the local preview server on
> - `--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]].

21
package-lock.json generated
View file

@ -83,7 +83,7 @@
"esbuild": "^0.19.9",
"prettier": "^3.3.3",
"tsx": "^4.19.0",
"typescript": "^5.5.4"
"typescript": "^5.6.2"
},
"engines": {
"node": "20 || >=22",
@ -4790,9 +4790,9 @@
}
},
"node_modules/preact-render-to-string": {
"version": "6.5.10",
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.10.tgz",
"integrity": "sha512-BJdypTQaBA5UbTF9NKZS3zP93Sw33tZOxNXIfuHofqOZFoMdsquNkVebs/HkEw0in/Qbi6Ep/Anngnj+VsHeBQ==",
"version": "6.5.11",
"resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz",
"integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==",
"peerDependencies": {
"preact": ">=10"
}
@ -6261,9 +6261,9 @@
}
},
"node_modules/typescript": {
"version": "5.5.4",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.4.tgz",
"integrity": "sha512-Mtq29sKDAEYP7aljRgtPOpTvOfbwRWlS6dPRzwjdE+C0R4brX/GUyhHSecbHMFLNBLcJIPt9nl9yG5TZ1weH+Q==",
"version": "5.6.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.6.2.tgz",
"integrity": "sha512-NW8ByodCSNCwZeghjN3o+JX5OFH0Ojg6sadjEKY4huZ52TqbJTJnDo5+Tw98lSy63NZvi4n+ez5m2u5d4PkZyw==",
"dev": true,
"bin": {
"tsc": "bin/tsc",
@ -6475,12 +6475,11 @@
}
},
"node_modules/vfile": {
"version": "6.0.2",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.2.tgz",
"integrity": "sha512-zND7NlS8rJYb/sPqkb13ZvbbUoExdbi4w3SfRrMq6R3FvnLQmmfpajJNITuuYm6AZ5uao9vy4BAos3EXBPf2rg==",
"version": "6.0.3",
"resolved": "https://registry.npmjs.org/vfile/-/vfile-6.0.3.tgz",
"integrity": "sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==",
"dependencies": {
"@types/unist": "^3.0.0",
"unist-util-stringify-position": "^4.0.0",
"vfile-message": "^4.0.0"
},
"funding": {

View file

@ -106,6 +106,6 @@
"esbuild": "^0.19.9",
"prettier": "^3.3.3",
"tsx": "^4.19.0",
"typescript": "^5.5.4"
"typescript": "^5.6.2"
}
}

View file

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

View file

@ -7,6 +7,7 @@ import { ExplorerNode, FileNode, Options } from "./ExplorerNode"
import { QuartzPluginData } from "../plugins/vfile"
import { classNames } from "../util/lang"
import { i18n } from "../i18n"
import { VNode } from "preact"
// Options interface defined in `ExplorerNode` to avoid circular dependency
const defaultOptions = {
@ -44,6 +45,7 @@ export default ((userOpts?: Partial<Options>) => {
// memoized
let fileTree: FileNode
let jsonTree: string
let component: VNode
let lastBuildId: string = ""
function constructFileTree(allFiles: QuartzPluginData[]) {
@ -82,44 +84,46 @@ export default ((userOpts?: Partial<Options>) => {
if (ctx.buildId !== lastBuildId) {
lastBuildId = ctx.buildId
constructFileTree(allFiles)
const tree = ExplorerNode({ node: fileTree, opts, fileData })
component = (
<div class={classNames(displayClass, "explorer")}>
<button
type="button"
id="explorer"
data-behavior={opts.folderClickBehavior}
data-collapsed={opts.folderDefaultState}
data-savestate={opts.useSavedState}
data-tree={jsonTree}
aria-controls="explorer-content"
aria-expanded={opts.folderDefaultState === "open"}
>
<h2>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h2>
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="5 8 14 8"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="fold"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<div id="explorer-content">
<ul class="overflow" id="explorer-ul">
{tree}
<li id="explorer-end" />
</ul>
</div>
</div>
)
}
return (
<div class={classNames(displayClass, "explorer")}>
<button
type="button"
id="explorer"
data-behavior={opts.folderClickBehavior}
data-collapsed={opts.folderDefaultState}
data-savestate={opts.useSavedState}
data-tree={jsonTree}
aria-controls="explorer-content"
aria-expanded={opts.folderDefaultState === "open"}
>
<h2>{opts.title ?? i18n(cfg.locale).components.explorer.title}</h2>
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="5 8 14 8"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="fold"
>
<polyline points="6 9 12 15 18 9"></polyline>
</svg>
</button>
<div id="explorer-content">
<ul class="overflow" id="explorer-ul">
<ExplorerNode node={fileTree} opts={opts} fileData={fileData} />
<li id="explorer-end" />
</ul>
</div>
</div>
)
return component
}
Explorer.css = explorerStyle

View file

@ -224,15 +224,10 @@ export function ExplorerNode({ node, opts, fullPath, fileData }: ExplorerNodePro
class="content"
data-folderul={folderPath}
>
{node.children.map((childNode, i) => (
<ExplorerNode
node={childNode}
key={i}
opts={opts}
fullPath={folderPath}
fileData={fileData}
/>
))}
{node.children.map((childNode) =>
// eagerly render children so we can memoize properly
ExplorerNode({ node: childNode, opts, fileData, fullPath: folderPath }),
)}
</ul>
</div>
</li>

View file

@ -67,6 +67,7 @@ export const CrawlLinks: QuartzTransformerPlugin<Partial<Options>> = (userOpts)
properties: {
"aria-hidden": "true",
class: "external-icon",
style: "max-width:0.8em;max-height:0.8em",
viewBox: "0 0 512 512",
},
children: [

View file

@ -324,8 +324,8 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>>
replacements.push([
tagRegex,
(_value: string, tag: string) => {
// Check if the tag only includes numbers
if (/^\d+$/.test(tag)) {
// Check if the tag only includes numbers and slashes
if (/^[\/\d]+$/.test(tag)) {
return false
}