Compare commits

...

67 Commits
v3.3 ... hugo

Author SHA1 Message Date
Jacky Zhao
66dd6bcf2d deprecate quartz v3 2023-08-19 18:49:50 -07:00
Gimbles
bb3877998a Add font fallbacks (#341) 2023-07-07 12:20:18 -07:00
Morgan Patterson
9450278680 Update Dockerfile (#335)
Fix #305
2023-07-07 12:20:03 -07:00
BSD-Yassin
7b1da7a845 i18n: Update fr.toml (#313) 2023-04-27 11:12:56 -07:00
Jacky Zhao
e482fa1097 fix: graph and tooltip sometimes not showing 2023-04-06 15:06:01 -07:00
Mattia Ippoliti
ba7a968881 fix: padding for empty title callouts (#308) 2023-04-01 13:50:08 -07:00
Md Jawad Noor Asif
db27557aa3 fix: search highlight not showing because for trailing slash (#306) 2023-03-30 07:14:06 -04:00
Mike Walton
b7c305e002 adding myself to the showcase (#301) 2023-03-23 00:56:20 -05:00
Daniel Lazaro
74fe4d6813 docs: Update link to callouts documentation (#300) 2023-03-18 09:20:56 -07:00
Jacky Zhao
d6c31595b3 deps: bump hugo-obsidian 2023-03-16 10:33:01 -07:00
Jacky Zhao
aa5ab03d4a docs: update to account for github changes 2023-03-02 09:14:29 -08:00
Jacky Zhao
ecba6071b8 deps: bump hugo-obsidian 2023-02-25 13:04:15 -08:00
Jacky Zhao
983efab94c fix: recent notes partial sorting 2023-02-12 16:46:11 -08:00
Dev Uni
10e41743e5 fix: Bad UI due to head.html (#284) 2023-02-07 08:38:20 -08:00
Simon Späti
bde44fadf2 feat: Adding Twitter and Social image preview including description (#207) 2023-02-07 00:16:15 -08:00
Jacky Zhao
6885651f7b feat: max-width for large screens 2023-02-06 12:58:34 -08:00
Jacky Zhao
7df2bb6f5e fix: fix duplicate link click tracking 2023-02-05 12:01:49 -08:00
Jacky Zhao
11959de11c feat: add more plausible events 2023-02-05 11:34:39 -08:00
Jacky Zhao
a73aca8ed9 feat: switch from GA to Plausible for analytics 2023-02-05 10:39:58 -08:00
Adam Brangenberg
93610e232b feat: Remove leading slash of folders in graph view (#282) 2023-02-01 12:34:18 -08:00
Jacky Zhao
712dab5c8c docs: remove broken links from showcase 2023-01-31 11:00:28 -08:00
Olivér Falvai
77b3907b23 docs: Clarify Obsidian settings (#280) 2023-01-31 10:48:20 -08:00
herrwinfried
8fc63586c4 feat: Added Turkish translation (#275) 2023-01-29 12:14:11 -08:00
Apoorv Khandelwal
24c9777a52 feat: Embedding multimodal assets (#274) 2023-01-21 10:01:05 -08:00
Quadrubo
7a8811a184 added the liveReloadPort as an option for docker (#272) 2023-01-18 08:25:01 -08:00
chaosarium
eb2f6aeca8 Fix callout behaviour inconsistent with Obsidian (closes #168) (#268) 2023-01-09 14:14:11 -08:00
Md Jawad Noor Asif
b78008532f feat: Added Bangla translations (#266) 2023-01-09 14:12:52 -08:00
Md Jawad Noor Asif
c5b103c85f fix: fix unicode broken tags (#261) 2023-01-03 22:10:25 -05:00
Adam Brangenberg
614a6222a1 refactor: General performance/style improvements (#262) 2022-12-29 10:43:41 -05:00
chaosarium
dc43737896 fix edge cases link processing (#258)
Fixes https://github.com/jackyzha0/quartz/issues/176
2022-12-24 12:10:59 -05:00
toof
ea37486309 fix: fix misspelling (#259) 2022-12-24 10:38:49 -05:00
chaosarium
c1b0eafce6 feat: Added simplified Chinese translations (#257) 2022-12-22 10:34:21 -08:00
Jacky Zhao
ce5df837f5 feat: latex in search results 2022-12-03 21:03:12 -08:00
Jacky Zhao
4cd6f7efdf fix: text highlighting 2022-11-30 18:00:12 -08:00
Apoorv Khandelwal
5a7936e23a fix: Replacing "internal-link broken" with link to asset (#232) 2022-11-30 17:41:05 -08:00
Jon Erling Hustadnes
5fd707714f feat: Added Norwegian localization (#242) 2022-11-27 10:55:43 -08:00
Filippo Andrea Sighinolfi
717a13a580 feat: Added italian localization in i18n/it.toml (#239) 2022-11-27 10:55:13 -08:00
Brendan Ang
5f3d430699 feat: add support for mermaid diagrams (#244) 2022-11-27 10:53:52 -08:00
Jacky Zhao
66f3e249fe fix: only run docker publish on main repository 2022-11-23 08:34:19 -08:00
Jacky Zhao
e374e3abd4 fix: jump to search for operand 2022-11-21 23:36:27 -08:00
SafEight
f08a76a738 fix: External links ending in .md don't get trimmed (#236)
Co-authored-by: SAF <saf@saf.saf>
fixes https://github.com/jackyzha0/quartz/issues/229
2022-11-21 13:05:46 -08:00
Morgan Gallant
d80f6946c8 fix: Semantic Search: Use Operand Beta API (#235) 2022-11-21 08:54:45 -08:00
Jacky Zhao
120d104230 update config for search 2022-11-20 15:14:48 -08:00
Jacky Zhao
e9aa6ae9e7 feat: docker docs, semantic search alpha 2022-11-20 15:09:58 -08:00
Apoorv Khandelwal
c12af32a5a feat: Dockerfile and automated container build (#230) 2022-11-20 14:03:53 -08:00
SafEight
de2b6b9a1b feat: Replace == with <mark> (#234)
Co-authored-by: SAF <saf@saf.saf>
2022-11-19 13:17:55 -08:00
Jacky Zhao
7f9f58860d feat: allow enableToc to override default no TOC on a per-page basis 2022-11-19 11:18:57 -08:00
jet457
151b9851d6 docs: add Abhijeet's math-wiki to the showcase (#228) 2022-11-19 11:10:41 -08:00
saucecoat
d56a58044d Added German translation (#223) 2022-10-29 23:08:44 -07:00
Conor
689201bfbd feat: Add French translation (#221) 2022-10-26 09:12:35 -07:00
Jacky Zhao
9b72edcd9c Merge branch 'hugo' of https://github.com/jackyzha0/quartz into hugo 2022-10-25 13:14:13 -07:00
Jacky Zhao
8704edcca2 deps: bump ubuntu version (closes #218) 2022-10-25 13:14:06 -07:00
Evan Cater
0a602eda1b fix euler's identity (#220) 2022-10-24 09:13:35 -07:00
Javier Zaleta Martínez
72571a7588 feat: Add Spanish translation (#217) 2022-10-18 17:25:55 -07:00
Charles Chamberlain
3409a49f15 fix: Apply monospace style to all meta in a popover (#216) 2022-10-16 09:43:43 -07:00
Pavol Komlos
666ffebe90 Decode the heading id from split link (#214) 2022-10-12 08:21:28 -07:00
Seth
8ea1525df4 Add SethMB Work (#203) 2022-10-03 11:45:54 -07:00
Jacky Zhao
dd11d56dd9 Merge branch 'hugo' of https://github.com/jackyzha0/quartz into hugo 2022-09-23 10:17:34 -07:00
Jacky Zhao
cd7e2088d5 feat: hide TOC when no headers (closes #204) 2022-09-23 10:17:28 -07:00
Simon Späti
169ef442b9 Adding reference projects (#196)
Co-authored-by: Jacky Zhao <j.zhao2k19@gmail.com>
2022-09-14 10:05:51 -07:00
DongDong Chen
8e3042df49 add my showcase : oldwinterの数字花园 (#192) 2022-09-14 10:05:20 -07:00
Jacky Zhao
2145e92b00 fix: make latex rendering size more simialr to obsidian 2022-09-12 11:08:07 -07:00
Jacky Zhao
e6c7a4e1e2 fix: latex rendering bugs + patch for #195 2022-09-11 18:03:55 -07:00
Nikola Georgiev
ca84da5b31 feat: Hide full path to file in Wikilinks by default (#195) 2022-09-11 17:05:14 -07:00
Jacky Zhao
0d1670adba Merge branch 'hugo' of https://github.com/jackyzha0/quartz into hugo 2022-08-29 14:23:19 -04:00
Jacky Zhao
5c770f965a Update Quartz version in documentation 2022-08-29 14:23:04 -04:00
Andrii Yefremov
ce55eca73b Add Ukrainian translation (#191) 2022-08-29 14:15:18 -04:00
56 changed files with 1205 additions and 261 deletions

View File

@@ -7,14 +7,14 @@ on:
jobs: jobs:
deploy: deploy:
runs-on: ubuntu-18.04 runs-on: ubuntu-20.04
steps: steps:
- uses: actions/checkout@v2 - uses: actions/checkout@v2
with: with:
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
- name: Build Link Index - name: Build Link Index
uses: jackyzha0/hugo-obsidian@v2.18 uses: jackyzha0/hugo-obsidian@v2.20
with: with:
index: true index: true
input: content input: content
@@ -36,4 +36,4 @@ jobs:
github_token: ${{ secrets.GITHUB_TOKEN }} github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public publish_dir: ./public
publish_branch: master # deploying branch publish_branch: master # deploying branch
cname: quartz.jzhao.xyz cname: three.quartz.jzhao.xyz

42
.github/workflows/docker-publish.yaml vendored Normal file
View File

@@ -0,0 +1,42 @@
name: Create and publish a Docker image
on:
push:
branches: ['hugo']
env:
REGISTRY: ghcr.io
IMAGE_NAME: ${{ github.repository }}
jobs:
build-and-push-image:
if: github.repository == 'jackyzha0/quartz'
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: Log in to the Container registry
uses: docker/login-action@f054a8b539a109f9f41c372932f1ae047eff08c9
with:
registry: ${{ env.REGISTRY }}
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Extract metadata (tags, labels) for Docker
id: meta
uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
with:
images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
- name: Build and push Docker image
uses: docker/build-push-action@ad44023a93711e3deb337508980b4b5e9bcdc5dc
with:
context: .
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}

11
Dockerfile Normal file
View File

@@ -0,0 +1,11 @@
FROM alpine:3.16
RUN apk add --no-cache go hugo git make perl
RUN git config --global --add safe.directory '/quartz'
RUN go install github.com/jackyzha0/hugo-obsidian@latest
ENV PATH="/root/go/bin:$PATH"
RUN git clone https://github.com/jackyzha0/quartz.git /quartz
WORKDIR /quartz
CMD ["make", "serve"]

View File

@@ -17,4 +17,8 @@ update-force: ## Forcefully pull all changes and don't ask to patch
git checkout upstream/hugo -- layouts .github Makefile assets/js assets/styles/base.scss assets/styles/darkmode.scss config.toml data git checkout upstream/hugo -- layouts .github Makefile assets/js assets/styles/base.scss assets/styles/darkmode.scss config.toml data
serve: ## Serve Quartz locally serve: ## Serve Quartz locally
hugo-obsidian -input=content -output=assets/indices -index -root=. && hugo server --enableGitInfo --minify hugo-obsidian -input=content -output=assets/indices -index -root=.
hugo server --enableGitInfo --minify --bind=$(or $(HUGO_BIND),0.0.0.0) --baseURL=$(or $(HUGO_BASEURL),http://localhost) --port=$(or $(HUGO_PORT),1313) --appendPort=$(or $(HUGO_APPENDPORT),true) --liveReloadPort=$(or $(HUGO_LIVERELOADPORT),-1)
docker: ## Serve locally using Docker
docker run -it --volume=$(shell pwd):/quartz -p 1313:1313 ghcr.io/jackyzha0/quartz:hugo

View File

@@ -1,18 +1,22 @@
# Quartz # Quartz 3
> [!warning]
> Quartz v3 is now deprecated and will no longer be maintained.
> See how to migrate to [Quartz 4](https://quartz.jzhao.xyz)
Host your second brain and [digital garden](https://jzhao.xyz/posts/networked-thought) for free. Quartz features Host your second brain and [digital garden](https://jzhao.xyz/posts/networked-thought) for free. Quartz features
1. Extremely fast full-text search by pressing `Ctrl` + `k` 1. Extremely fast natural-language search
2. Customizable and hackable design based on Hugo 2. Customizable and hackable design based on Hugo
3. Automatically generated backlinks, link previews, and local graph 3. Automatically generated backlinks, link previews, and local graph
4. Built-in CJK + Latex Support 4. Built-in CJK + Latex Support and Admonition-style callouts
5. Support for both Markdown Links and Wikilinks 5. Support for both Markdown Links and Wikilinks
Check out some of the [amazing gardens that community members](https://quartz.jzhao.xyz/notes/showcase/) have published with Quartz! Check out some of the [amazing gardens that community members](https://quartz.jzhao.xyz/notes/showcase/) have published with Quartz!
> “[One] who works with the door open gets all kinds of interruptions, but [they] also occasionally gets clues as to what the world is and what might be important.” — Richard Hamming > “[One] who works with the door open gets all kinds of interruptions, but [they] also occasionally gets clues as to what the world is and what might be important.” — Richard Hamming
🔗 Get Started: https://quartz.jzhao.xyz/ 🔗 Get Started: https://three.quartz.jzhao.xyz/
![Quartz Example Screenshot](./screenshot.png)*Quartz Example Screenshot* ![Quartz Example Screenshot](./screenshot.png)*Quartz Example Screenshot*

View File

@@ -8,33 +8,38 @@ const addCopyButtons = () => {
let els = document.getElementsByClassName("highlight"); let els = document.getElementsByClassName("highlight");
// for each highlight // for each highlight
for (let i = 0; i < els.length; i++) { for (let i = 0; i < els.length; i++) {
if (els[i].getElementsByClassName("clipboard-button").length) continue; try {
if (els[i].getElementsByClassName("clipboard-button").length) continue;
// find pre > code inside els[i] // find pre > code inside els[i]
let codeBlocks = els[i].getElementsByTagName("code"); let codeBlocks = els[i].getElementsByTagName("code");
// line numbers are inside first code block // line numbers are inside first code block
let lastCodeBlock = codeBlocks[codeBlocks.length - 1]; let lastCodeBlock = codeBlocks[codeBlocks.length - 1];
const button = document.createElement("button"); const button = document.createElement("button");
button.className = "clipboard-button"; button.className = "clipboard-button";
button.type = "button"; button.type = "button";
button.innerHTML = svgCopy; button.innerHTML = svgCopy;
// remove every second newline from lastCodeBlock.innerText button.ariaLabel = "opy the shown code";
button.addEventListener("click", () => { // remove every second newline from lastCodeBlock.innerText
navigator.clipboard.writeText(lastCodeBlock.innerText.replace(/\n\n/g, "\n")).then( button.addEventListener("click", () => {
() => { navigator.clipboard.writeText(lastCodeBlock.innerText.replace(/\n\n/g, "\n")).then(
button.blur(); () => {
button.innerHTML = svgCheck; button.blur();
setTimeout(() => { button.innerHTML = svgCheck;
button.innerHTML = svgCopy setTimeout(() => {
button.style.borderColor = "" button.innerHTML = svgCopy
}, 2000); button.style.borderColor = ""
}, }, 2000);
(error) => (button.innerHTML = "Error") },
); (error) => (button.innerHTML = "Error")
}); );
// find chroma inside els[i] });
let chroma = els[i].getElementsByClassName("chroma")[0]; // find chroma inside els[i]
els[i].insertBefore(button, chroma); let chroma = els[i].getElementsByClassName("chroma")[0];
els[i].insertBefore(button, chroma);
} catch(error) {
console.debug(error);
}
} }
} }

View File

@@ -1,13 +1,17 @@
function addTitleToCodeBlocks() { function addTitleToCodeBlocks() {
var els = document.getElementsByClassName("highlight"); const els = document.getElementsByClassName("highlight");
for (var i = 0; i < els.length; i++) { for (let i = 0; i < els.length; i++) {
if (els[i].title.length) { try {
let div = document.createElement("div"); if (els[i].title.length) {
if (els[i].getElementsByClassName("code-title").length) continue; let div = document.createElement("div");
div.textContent=els[i].title; if (els[i].getElementsByClassName("code-title").length) continue;
div.classList.add("code-title") div.textContent = els[i].title;
els[i].insertBefore(div, els[i].firstChild); div.classList.add("code-title")
els[i].insertBefore(div, els[i].firstChild);
}
} catch (error) {
console.debug(error);
} }
} }
}; }

View File

@@ -35,7 +35,7 @@
}) })
registerHandlers((e) => { registerHandlers((e) => {
term = e.target.value const term = e.target.value
const searchResults = contentIndex.search(term, [ const searchResults = contentIndex.search(term, [
{ {
field: "content", field: "content",
@@ -56,6 +56,6 @@
} }
const allIds = new Set([...getByField("title"), ...getByField("content")]) const allIds = new Set([...getByField("title"), ...getByField("content")])
const finalResults = [...allIds].map(formatForDisplay) const finalResults = [...allIds].map(formatForDisplay)
displayResults(finalResults, true) displayResults(term, finalResults, true)
}) })
})() })()

View File

@@ -1,14 +1,14 @@
async function drawGraph(baseUrl, isHome, pathColors, graphConfig) { async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
let { let {
depth, depth,
enableDrag, enableDrag,
enableLegend, enableLegend,
enableZoom, enableZoom,
opacityScale, opacityScale,
scale, scale,
repelForce, repelForce,
fontSize} = graphConfig; fontSize } = graphConfig;
const container = document.getElementById("graph-container") const container = document.getElementById("graph-container")
const { index, links, content } = await fetchData const { index, links, content } = await fetchData
@@ -85,7 +85,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
d.fy = null d.fy = null
} }
const noop = () => {} const noop = () => { }
return d3 return d3
.drag() .drag()
.on("start", enableDrag ? dragstarted : noop) .on("start", enableDrag ? dragstarted : noop)
@@ -113,7 +113,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
.append("svg") .append("svg")
.attr("width", width) .attr("width", width)
.attr("height", height) .attr("height", height)
.attr('viewBox', [-width / 2 * 1 / scale, -height / 2 * 1 / scale, width * 1 / scale, height * 1 / scale]) .attr('viewBox', [-width / 2 / scale, -height / 2 / scale, width / scale, height / scale])
if (enableLegend) { if (enableLegend) {
const legend = [{ Current: "var(--g-node-active)" }, { Note: "var(--g-node)" }, ...pathColors] const legend = [{ Current: "var(--g-node-active)" }, { Note: "var(--g-node)" }, ...pathColors]
@@ -168,9 +168,18 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
.style("cursor", "pointer") .style("cursor", "pointer")
.on("click", (_, d) => { .on("click", (_, d) => {
// SPA navigation // SPA navigation
window.Million.navigate(new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`), ".singlePage") const targ = `${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`
window.Million.navigate(new URL(targ), ".singlePage")
plausible("Link Click", {
props: {
href: targ,
broken: false,
internal: true,
graph: true,
}
})
}) })
.on("mouseover", function (_, d) { .on("mouseover", function(_, d) {
d3.selectAll(".node").transition().duration(100).attr("fill", "var(--g-node-inactive)") d3.selectAll(".node").transition().duration(100).attr("fill", "var(--g-node-inactive)")
const neighbours = parseIdsFromLinks([ const neighbours = parseIdsFromLinks([
@@ -190,7 +199,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
// highlight links // highlight links
linkNodes.transition().duration(200).attr("stroke", "var(--g-link-active)") linkNodes.transition().duration(200).attr("stroke", "var(--g-link-active)")
const bigFont = fontSize*1.5 const bigFont = fontSize * 1.5
// show text for self // show text for self
d3.select(this.parentNode) d3.select(this.parentNode)
@@ -200,10 +209,10 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
.duration(200) .duration(200)
.attr('opacityOld', d3.select(this.parentNode).select('text').style("opacity")) .attr('opacityOld', d3.select(this.parentNode).select('text').style("opacity"))
.style('opacity', 1) .style('opacity', 1)
.style('font-size', bigFont+'em') .style('font-size', bigFont + 'em')
.attr('dy', d => nodeRadius(d) + 20 + 'px') // radius is in px .attr('dy', d => nodeRadius(d) + 20 + 'px') // radius is in px
}) })
.on("mouseleave", function (_, d) { .on("mouseleave", function(_, d) {
d3.selectAll(".node").transition().duration(200).attr("fill", color) d3.selectAll(".node").transition().duration(200).attr("fill", color)
const currentId = d.id const currentId = d.id
@@ -214,12 +223,12 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
linkNodes.transition().duration(200).attr("stroke", "var(--g-link)") linkNodes.transition().duration(200).attr("stroke", "var(--g-link)")
d3.select(this.parentNode) d3.select(this.parentNode)
.select("text") .select("text")
.transition() .transition()
.duration(200) .duration(200)
.style('opacity', d3.select(this.parentNode).select('text').attr("opacityOld")) .style('opacity', d3.select(this.parentNode).select('text').attr("opacityOld"))
.style('font-size', fontSize+'em') .style('font-size', fontSize + 'em')
.attr('dy', d => nodeRadius(d) + 8 + 'px') // radius is in px .attr('dy', d => nodeRadius(d) + 8 + 'px') // radius is in px
}) })
.call(drag(simulation)) .call(drag(simulation))
@@ -229,10 +238,10 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
.attr("dx", 0) .attr("dx", 0)
.attr("dy", (d) => nodeRadius(d) + 8 + "px") .attr("dy", (d) => nodeRadius(d) + 8 + "px")
.attr("text-anchor", "middle") .attr("text-anchor", "middle")
.text((d) => content[d.id]?.title || d.id.replace("-", " ")) .text((d) => content[d.id]?.title || (d.id.charAt(1).toUpperCase() + d.id.slice(2)).replace("-", " "))
.style('opacity', (opacityScale - 1) / 3.75) .style('opacity', (opacityScale - 1) / 3.75)
.style("pointer-events", "none") .style("pointer-events", "none")
.style('font-size', fontSize+'em') .style('font-size', fontSize + 'em')
.raise() .raise()
.call(drag(simulation)) .call(drag(simulation))

View File

@@ -5,14 +5,14 @@ function htmlToElement(html) {
return template.content.firstChild return template.content.firstChild
} }
function initPopover(baseURL, useContextualBacklinks, renderLatex) { function initPopover(baseURL, useContextualBacklinks) {
const basePath = baseURL.replace(window.location.origin, "") const basePath = baseURL.replace(window.location.origin, "")
fetchData.then(({ content }) => { fetchData.then(({ content }) => {
const links = [...document.getElementsByClassName("internal-link")] const links = [...document.getElementsByClassName("internal-link")]
links links
.filter(li => li.dataset.src || (li.dataset.idx && useContextualBacklinks)) .filter(li => li.dataset.src || (li.dataset.idx && useContextualBacklinks))
.forEach(li => { .forEach(li => {
var el let el
if (li.dataset.ctx) { if (li.dataset.ctx) {
const linkDest = content[li.dataset.src] const linkDest = content[li.dataset.src]
const popoverElement = `<div class="popover"> const popoverElement = `<div class="popover">
@@ -27,7 +27,7 @@ function initPopover(baseURL, useContextualBacklinks, renderLatex) {
let splitLink = li.href.split("#") let splitLink = li.href.split("#")
let cleanedContent = removeMarkdown(linkDest.content) let cleanedContent = removeMarkdown(linkDest.content)
if (splitLink.length > 1) { if (splitLink.length > 1) {
let headingName = splitLink[1].replace(/\-/g, " ") let headingName = decodeURIComponent(splitLink[1]).replace(/\-/g, " ")
let headingIndex = cleanedContent.toLowerCase().indexOf("<b>" + headingName + "</b>") let headingIndex = cleanedContent.toLowerCase().indexOf("<b>" + headingName + "</b>")
cleanedContent = cleanedContent.substring(headingIndex, cleanedContent.length) cleanedContent = cleanedContent.substring(headingIndex, cleanedContent.length)
} }
@@ -42,13 +42,11 @@ function initPopover(baseURL, useContextualBacklinks, renderLatex) {
if (el) { if (el) {
li.appendChild(el) li.appendChild(el)
if (renderLatex) { if (LATEX_ENABLED) {
renderMathInElement(el, { renderMathInElement(el, {
delimiters: [ delimiters: [
{ left: '$$', right: '$$', display: false }, { left: '$$', right: '$$', display: false },
{ left: '$', right: '$', display: false }, { left: '$', right: '$', display: false },
{ left: '\\(', right: '\\)', display: false },
{ left: '\\[', right: '\\]', display: false }
], ],
throwOnError: false throwOnError: false
}) })
@@ -66,6 +64,11 @@ function initPopover(baseURL, useContextualBacklinks, renderLatex) {
}) })
el.classList.add("visible") el.classList.add("visible")
plausible("Popover Hover", {
props: {
href: li.dataset.src
}
})
}) })
li.addEventListener("mouseout", () => { li.addEventListener("mouseout", () => {
el.classList.remove("visible") el.classList.remove("visible")

View File

@@ -15,7 +15,6 @@ export const attachSPARouting = (init, rerender) => {
} }
const render = () => requestAnimationFrame(rerender) const render = () => requestAnimationFrame(rerender)
window.addEventListener("DOMContentLoaded", () => { window.addEventListener("DOMContentLoaded", () => {
apply((doc) => init(doc)) apply((doc) => init(doc))
init() init()

View File

@@ -1,38 +1,54 @@
const apiKey = "{{$.Site.Data.config.operandApiKey}}" // Note: Currently, we use the REST API for Operand because of some unpkg/webpack issues.
// In the future, we'd like to use the SDK (https://github.com/operandinc/typescript-sdk).
// If someone knows how to do this w/o breaking the Operand typescript-sdk for npm users,
// please let Morgan (@morgallant) and/or (@_jzhao) know! <3
const apiKey = "{{$.Site.Data.config.search.operandApiKey}}"
const indexId = "{{$.Site.Data.config.search.operandIndexId}}"
function parseSearchResults(searchResults) {
return searchResults.matches.map((m) => ({
content: m.content,
title: searchResults.objects[m.objectId].properties.properties._title.text,
url: searchResults.objects[m.objectId].properties.properties._url.text,
}))
}
async function searchContents(query) { async function searchContents(query) {
const response = await fetch('https://prod.operand.ai/v3/search/objects', { const result = await fetch("https://api.operand.ai/operand.v1.ObjectService/SearchWithin", {
method: 'POST', method: "POST",
headers: { headers: {
'Content-Type': 'application/json', "Content-Type": "application/json",
Authorization: apiKey, Authorization: `${apiKey}`,
"Operand-Index-ID": `${indexId}`,
}, },
body: JSON.stringify({ body: JSON.stringify({
query, query: query,
max: 10 limit: 10,
}), }),
}); })
return (await response.json()); if (result.ok) {
return parseSearchResults(await result.json())
} else {
console.error(result)
}
} }
function debounce(func, timeout = 200) { function debounce(func, timeout = 200) {
let timer; let timer
return (...args) => { return (...args) => {
clearTimeout(timer) clearTimeout(timer)
timer = setTimeout(() => { func.apply(this, args); }, timeout) timer = setTimeout(() => {
}; func.apply(this, args)
}, timeout)
}
} }
registerHandlers(debounce((e) => { registerHandlers(
term = e.target.value debounce((e) => {
if (term !== "") { let term = e.target.value
searchContents(term) if (term !== "") {
.then((res) => res.results.map(entry => ({ searchContents(term).then((results) => displayResults(term, results))
url: entry.object.properties.url, }
content: entry.snippet, }),
title: entry.object.metadata.title )
})
))
.then(results => displayResults(results))
}
}))

View File

@@ -40,8 +40,8 @@ const removeMarkdown = (
.replace(/^\s{0,3}>\s?/g, "") .replace(/^\s{0,3}>\s?/g, "")
.replace(/(^|\n)\s{0,3}>\s?/g, "\n\n") .replace(/(^|\n)\s{0,3}>\s?/g, "\n\n")
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, "") .replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, "")
.replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, "$2") .replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2")
.replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, "$2") .replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2")
.replace(/(`{3,})(.*?)\1/gm, "$2") .replace(/(`{3,})(.*?)\1/gm, "$2")
.replace(/`(.+?)`/g, "$1") .replace(/`(.+?)`/g, "$1")
.replace(/\n{2,}/g, "\n\n") .replace(/\n{2,}/g, "\n\n")
@@ -65,7 +65,7 @@ const highlight = (content, term) => {
.split(" ") .split(" ")
.slice(0, h) .slice(0, h)
return ( return (
(before.length == h ? `...${before.join(" ")}` : before.join(" ")) + (before.length === h ? `...${before.join(" ")}` : before.join(" ")) +
`<span class="search-highlight">${term}</span>` + `<span class="search-highlight">${term}</span>` +
after.join(" ") after.join(" ")
) )
@@ -115,12 +115,19 @@ const resultToHTML = ({ url, title, content }) => {
} }
const redir = (id, term) => { const redir = (id, term) => {
// SPA navigation const shouldTrim = PRODUCTION && SEARCH_ENABLED
const baseURLPrefix = shouldTrim ? "" : BASE_URL.replace(/\/$/g, "")
const urlString = `${baseURLPrefix}${id}#:~:text=${encodeURIComponent(term)}`
window.Million.navigate( window.Million.navigate(
new URL(`${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/`), new URL(urlString),
".singlePage", ".singlePage",
) )
closeSearch() closeSearch()
plausible("Search", {
props: {
term
}
})
} }
function openSearch() { function openSearch() {
@@ -179,7 +186,7 @@ const registerHandlers = (onInputFn) => {
}) })
} }
const displayResults = (finalResults, extractHighlight = false) => { const displayResults = (term, finalResults, extractHighlight = false) => {
const results = document.getElementById("results-container") const results = document.getElementById("results-container")
if (finalResults.length === 0) { if (finalResults.length === 0) {
results.innerHTML = `<button class="result-card"> results.innerHTML = `<button class="result-card">
@@ -189,18 +196,28 @@ const displayResults = (finalResults, extractHighlight = false) => {
} else { } else {
results.innerHTML = finalResults results.innerHTML = finalResults
.map((result) => { .map((result) => {
if (extractHighlight) { if (extractHighlight) {
return resultToHTML({ return resultToHTML({
url: result.url, url: result.url,
title: highlight(result.title, term), title: highlight(result.title, term),
content: highlight(removeMarkdown(result.content), term) content: highlight(removeMarkdown(result.content), term)
}) })
} else { } else {
return resultToHTML(result) return resultToHTML(result)
}
} }
}
) )
.join("\n") .join("\n")
if (LATEX_ENABLED) {
renderMathInElement(results, {
delimiters: [
{ left: '$$', right: '$$', display: false },
{ left: '$', right: '$', display: false },
],
throwOnError: false
})
}
const anchors = [...document.getElementsByClassName("result-card")] const anchors = [...document.getElementsByClassName("result-card")]
anchors.forEach((anchor) => { anchors.forEach((anchor) => {
anchor.onclick = () => redir(anchor.id, term) anchor.onclick = () => redir(anchor.id, term)

View File

@@ -114,6 +114,10 @@ blockquote[class*="-callout"] > p:first-child {
} }
} }
blockquote[class*="-callout"] > p:empty {
padding: 1.2em 35px;
}
$summary: summary, abstract, tldr; $summary: summary, abstract, tldr;
$bug: bug; $bug: bug;
$danger: danger, error; $danger: danger, error;

View File

@@ -1,9 +1,9 @@
// Replace this with your own font imports! // Replace this with your own font imports!
@import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&family=Inter:wght@400;600;700&family=Source+Sans+Pro:wght@400;600&display=swap'); @import url('https://fonts.googleapis.com/css2?family=Fira+Code:wght@400;700&family=Inter:wght@400;600;700&family=Source+Sans+Pro:wght@400;600&display=swap');
:root { :root {
--font-body: "Source Sans Pro"; --font-body: "Source Sans Pro", sans-serif;
--font-header: "Inter"; --font-header: "Inter", sans-serif;
--font-mono: "Fira Code" --font-mono: "Fira Code", monospace;
} }
// typography // typography
@@ -22,6 +22,8 @@ html {
.singlePage { .singlePage {
padding: 4em 30vw; padding: 4em 30vw;
margin: 0 auto;
max-width: 1000px;
@media all and (max-width: 1200px) { @media all and (max-width: 1200px) {
padding: 25px 5vw; padding: 25px 5vw;
} }
@@ -89,7 +91,7 @@ tbody, li, p {
#TableOfContents > ol { #TableOfContents > ol {
counter-reset: section; counter-reset: section;
margin-left: 0em; margin-left: 0;
padding-left: 1.5em; padding-left: 1.5em;
& > li { & > li {
counter-increment: section; counter-increment: section;
@@ -142,7 +144,7 @@ sup {
} }
blockquote { blockquote {
margin-left: 0em; margin-left: 0;
border-left: 3px solid var(--secondary); border-left: 3px solid var(--secondary);
padding-left: 1em; padding-left: 1em;
transition: border-color 0.2s ease; transition: border-color 0.2s ease;
@@ -183,7 +185,7 @@ article {
margin-top: 2em; margin-top: 2em;
font-size: 2em; font-size: 2em;
} }
& > .meta { & > .meta {
margin: 0 0 1em 0; margin: 0 0 1em 0;
opacity: 0.7; opacity: 0.7;
@@ -201,11 +203,11 @@ article {
&.broken { &.broken {
opacity: 0.5; opacity: 0.5;
background-color: transparent; background-color: transparent;
} }
} }
} }
& p { & p {
overflow-wrap: anywhere; overflow-wrap: anywhere;
} }
@@ -295,17 +297,15 @@ footer {
text-align: center; text-align: center;
& ul { & ul {
padding-left: 0; padding-left: 0;
} }
} }
hr { hr {
width: 25%; width: 100%;
margin: 4em auto; margin: 2em auto;
height: 2px; height: 1px;
border-radius: 1px; border: none;
border-width: 0; background-color: var(--outlinegray);
color: var(--dark);
background-color: var(--dark);
} }
.page-end { .page-end {
@@ -509,7 +509,7 @@ header {
& > .section { & > .section {
display: flex; display: flex;
align-items: center; align-items: center;
@media all and (max-width: 600px) { @media all and (max-width: 600px) {
& .tags { & .tags {
@@ -521,18 +521,18 @@ header {
font-weight: 700; font-weight: 700;
margin: 0; margin: 0;
} }
& p { & p {
margin: 0; margin: 0;
padding-right: 1em; padding-right: 1em;
flex-basis: 6em; flex-basis: 6em;
} }
} }
& h3 { & h3 {
opacity: 1; opacity: 1;
font-weight: 700; font-weight: 700;
margin: 0em; margin: 0;
} }
& .meta { & .meta {
@@ -570,7 +570,7 @@ header {
transition: opacity 0.2s ease, transform 0.2s ease; transition: opacity 0.2s ease, transform 0.2s ease;
user-select: none; user-select: none;
overflow-wrap: anywhere; overflow-wrap: anywhere;
box-shadow: 6px 6px 36px 0px rgba(0,0,0,0.25); box-shadow: 6px 6px 36px 0 rgba(0,0,0,0.25);
@media all and (max-width: 600px) { @media all and (max-width: 600px) {
display: none !important; display: none !important;
@@ -588,7 +588,7 @@ header {
margin: 0.25rem 0; margin: 0.25rem 0;
} }
& > .meta { & .meta {
margin-top: 0.25rem; margin-top: 0.25rem;
opacity: 0.5; opacity: 0.5;
font-family: var(--font-mono); font-family: var(--font-mono);
@@ -598,7 +598,7 @@ header {
& > p { & > p {
margin: 0; margin: 0;
padding: 0.5rem 0; padding: 0.5rem 0;
} }
& > p, & > a { & > p, & > a {
font-size: 1rem; font-size: 1rem;
@@ -619,3 +619,7 @@ header {
} }
} }
mark {
background-color: var(--highlighted);
color: var(--gray);
}

View File

@@ -11,6 +11,7 @@
--lightgray: #f0f0f0; --lightgray: #f0f0f0;
--outlinegray: #dadada; --outlinegray: #dadada;
--million-progress-bar-color: var(--secondary); --million-progress-bar-color: var(--secondary);
--highlighted: #f5dfaf88;
} }
[saved-theme="dark"] { [saved-theme="dark"] {
@@ -23,6 +24,7 @@
--gray: #d4d4d4 !important; --gray: #d4d4d4 !important;
--lightgray: #292633 !important; --lightgray: #292633 !important;
--outlinegray: #343434 !important; --outlinegray: #343434 !important;
--highlighted: #574010;
} }

View File

@@ -60,3 +60,7 @@
pre.chroma { pre.chroma {
-moz-tab-size:4;-o-tab-size:4;tab-size:4; -moz-tab-size:4;-o-tab-size:4;tab-size:4;
} }
.katex {
font-size: 1.1em !important;
}

View File

@@ -1,6 +1,5 @@
baseURL = "https://quartz.jzhao.xyz/" baseURL = "https://three.quartz.jzhao.xyz/"
languageCode = "en-us" languageCode = "en-us"
googleAnalytics = "G-XYFD95KB4J"
relativeURLs = false relativeURLs = false
disablePathToLower = true disablePathToLower = true
ignoreFiles = [ ignoreFiles = [

View File

@@ -1,10 +1,11 @@
--- ---
title: 🪴 Quartz 3.2 title: 🪴 Quartz 3.3
enableToc: false
--- ---
Host your second brain and [digital garden](https://jzhao.xyz/posts/networked-thought) for free. Quartz features Host your second brain and [digital garden](https://jzhao.xyz/posts/networked-thought) for free. Quartz features
1. Extremely fast natural-language [[notes/search|search]] 1. Extremely fast natural-language [[notes/search]]
2. Customizable and hackable design based on [Hugo](https://gohugo.io/) 2. Customizable and hackable design based on [Hugo](https://gohugo.io/)
3. Automatically generated backlinks, link previews, and local graph 3. Automatically generated backlinks, link previews, and local graph
4. Built-in [[notes/CJK + Latex Support (测试) | CJK + Latex Support]] and [[notes/callouts | Admonition-style callouts]] 4. Built-in [[notes/CJK + Latex Support (测试) | CJK + Latex Support]] and [[notes/callouts | Admonition-style callouts]]

View File

@@ -17,7 +17,7 @@ $$f(x) = \int_{-\infty}^\infty
f\hat(\xi),e^{2 \pi i \xi x} f\hat(\xi),e^{2 \pi i \xi x}
\,d\xi$$ \,d\xi$$
Inline math also works with single dollar signs `$...$`. For example, Euler's identity but inline: $e^{i\pi} = 0$ Inline math also works with single dollar signs `$...$`. For example, Euler's identity but inline: $e^{i\pi} = -1$
Aligned equations work quite well: Aligned equations work quite well:

View File

@@ -10,7 +10,7 @@ This includes
- 12 Distinct callout types (each with several aliases) - 12 Distinct callout types (each with several aliases)
- Collapsable callouts - Collapsable callouts
See [documentation on supported types and syntax here](https://help.obsidian.md/How+to/Use+callouts#Types). See [documentation on supported types and syntax here](https://help.obsidian.md/Editing+and+formatting/Callouts).
## Showcase ## Showcase

View File

@@ -57,11 +57,16 @@ enableRecentNotes: false
enableGitHubEdit: true enableGitHubEdit: true
GitHubLink: https://github.com/jackyzha0/quartz/tree/hugo/content GitHubLink: https://github.com/jackyzha0/quartz/tree/hugo/content
# whether to render mermaid diagrams
enableMermaid: true
# whether to use Operand to power semantic search # whether to use Operand to power semantic search
# IMPORTANT: replace this API key with your own if you plan on using # IMPORTANT: replace this API key with your own if you plan on using
# Operand search! # Operand search!
enableSemanticSearch: false search:
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY" enableSemanticSearch: false
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY"
operandIndexId: "REPLACE-WITH-YOUR-OPERAND-INDEX-ID"
# page description used for SEO # page description used for SEO
description: description:
@@ -70,7 +75,7 @@ description:
# title of the home page (also for SEO) # title of the home page (also for SEO)
page_title: page_title:
"🪴 Quartz 3.2" "🪴 Quartz 3.3"
# links to show in the footer # links to show in the footer
links: links:

57
content/notes/docker.md Normal file
View File

@@ -0,0 +1,57 @@
---
title: "Hosting with Docker"
tags:
- setup
---
If you want to host Quartz on a machine without using a webpage hosting service, it may be easier to [install Docker Compose](https://docs.docker.com/compose/install/) and follow the instructions below than to [install Quartz's dependencies manually](notes/preview%20changes.md).
## Hosting Quartz Locally
You can serve Quartz locally at `http://localhost:1313` with the following script, replacing `/path/to/quartz` with the
actual path to your Quartz folder.
docker-compose.yml
```
services:
quartz-hugo:
image: ghcr.io/jackyzha0/quartz:hugo
container_name: quartz-hugo
volumes:
- /path/to/quartz:/quartz
ports:
- 1313:1313
# optional
environment:
- HUGO_BIND=0.0.0.0
- HUGO_BASEURL=http://localhost
- HUGO_PORT=1313
- HUGO_APPENDPORT=true
- HUGO_LIVERELOADPORT=-1
```
Then run with: `docker-compose up -d` in the same directory as your `docker-compose.yml` file.
While the container is running, you can update the `quartz` fork with: `docker exec -it quartz-hugo make update`.
## Exposing Your Container to the Internet
### To Your Public IP Address with Port Forwarding (insecure)
Assuming you are already familiar with [port forwarding](https://en.wikipedia.org/wiki/Port_forwarding) and [setting it up with your router model](https://portforward.com):
1. You should set the environment variable `HUGO_BASEURL=http://your-public-ip` and then start your container.
2. Set up port forwarding on your router from port `p` to `your-local-ip:1313`.
3. You should now be able to access Quartz from outside your local network at `http://your-public-ip:p`.
However, your HTTP connection will be unencrypted and **this method is not secure**.
### To a Domain using Cloudflare Proxy
1. Port forward 443 (HTTPS) from your machine.
2. Buy a custom domain (say, `your-domain.com`) from [Cloudflare](https://www.cloudflare.com/products/registrar/). Point a DNS A record from `your-domain.com` to your public IP address and enable the proxy.
3. Set the environment variables `HUGO_BASEURL=https://your-domain.com`, `HUGO_PORT=443`, and `HUGO_APPENDPORT=false`. Change `1313:1313` to `443:443` for the `ports` in `docker-compose.yml`.
4. Spin up your Quartz container and enjoy it at `https://your-domain.com`!
### To a Domain using a Reverse Proxy
If you want to serve more than just Quartz to the internet on this machine (or don't want to use the Cloudflare registrar and proxy), you should follow the steps in the section above (as appropriate) and also set up a reverse proxy, like [Traefik](https://doc.traefik.io/traefik). Be sure to configure your TLS certificates too!

View File

@@ -15,24 +15,10 @@ Here's a rough overview of what's what.
**To edit the main home page, open `/content/_index.md`.** **To edit the main home page, open `/content/_index.md`.**
To create a link between notes in your garden, just create a normal link using Markdown pointing to the document in question. Please note that **all links should be relative to the root `/content` path**.
```markdown
For example, I want to link this current document to `notes/config.md`.
[A link to the config page](notes/config.md)
```
Similarly, you can put local images anywhere in the `/content` folder.
```markdown
Example image (source is in content/notes/images/example.png)
![Example Image](/content/notes/images/example.png)
```
You can also use wikilinks if that is what you are more comfortable with!
### Front Matter ### Front Matter
Hugo is picky when it comes to metadata for files. Make sure that your title is double-quoted and that you have a title defined at the top of your file like so. You can also add tags here as well. Hugo is picky when it comes to metadata for files. Make sure that your title is double-quoted and that you have a title defined at the top of your file like so, otherwise the generated page will not have a title!
You can also add tags here as well.
```yaml ```yaml
--- ---

View File

@@ -10,10 +10,13 @@ aliases:
## Hosting on GitHub Pages ## Hosting on GitHub Pages
Quartz is designed to be effortless to deploy. If you forked and cloned Quartz directly from the repository, everything should already be good to go! Follow the steps below. Quartz is designed to be effortless to deploy. If you forked and cloned Quartz directly from the repository, everything should already be good to go! Follow the steps below.
### Enable GitHub Actions ### Enable GitHub Actions Permissions
By default, GitHub disables workflows from running automatically on Forked Repostories. Head to the 'Actions' tab of your forked repository and Enable Workflows to setup deploying your Quartz site! By default, GitHub disables workflows from modifying your files (for good reason!). However, Quartz needs this to write the actual site files back to GitHub.
![Enable GitHub Actions](notes/images/github-actions.png)*Enable GitHub Actions* Head to `Settings > Action > General > Workflow Permissions` and choose `Read and Write Permissions`
![[notes/images/github-actions.png]]
*Enable GitHub Actions*
### Enable GitHub Pages ### Enable GitHub Pages
@@ -83,6 +86,10 @@ Only want to publish a subset of all of your notes? Don't worry, Quartz makes th
❌ [Excluding pages from being published](notes/ignore%20notes.md) ❌ [Excluding pages from being published](notes/ignore%20notes.md)
## Docker Support
If you don't want to use a hosting service, you can host using [Docker](notes/docker.md) instead!
I would *not use this method* unless you know what you are doing.
--- ---
Now that your Quartz is live, let's figure out how to make Quartz really *yours*! Now that your Quartz is live, let's figure out how to make Quartz really *yours*!

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 116 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 44 KiB

View File

@@ -17,16 +17,21 @@ The easiest way to use an existing Vault is to copy all of your files (directory
## Settings ## Settings
Great, now that you have your Obsidian linked to your Quartz, let's fix some settings so that they play well. Great, now that you have your Obsidian linked to your Quartz, let's fix some settings so that they play well.
1. Under Options > Files and Links, set the New link format to always use Absolute Path in Vault. Open Settings > Files & Links and look for these two items:
2. Go to Settings > Files & Links > Turn "on" automatically update internal links.
![Obsidian Settings](/notes/images/obsidian-settings.png)*Obsidian Settings* 1. Set the **New link format** to **Absolute Path in vault**. If you have a completely flat vault (no folders), this step isn't necessary.
2. Turn **on** the **Automatically update internal links** setting.
![[notes/images/obsidian-settings.png]]*Obsidian Settings*
## Templates ## Templates
Inserting front matter everytime you want to create a new Note gets annoying really quickly. Luckily, Obsidian supports templates which makes inserting new content really easily. Inserting front matter everytime you want to create a new Note gets annoying really quickly. Luckily, Obsidian supports templates which makes inserting new content really easily.
**If you decide to overwrite the `/content` folder completely, don't remove the `/content/templates` folder!** > [!WARNING]
>
> **If you decide to overwrite the `/content` folder completely, don't remove the `/content/templates` folder!**
Head over to Options > Core Plugins and enable the Templates plugin. Then go to Options > Hotkeys and set a hotkey for 'Insert Template' (I recommend `[cmd]+T`). That way, when you create a new note, you can just press the hotkey for a new template and be ready to go! Head over to Options > Core Plugins and enable the Templates plugin. Then go to Options > Hotkeys and set a hotkey for 'Insert Template' (I recommend `[cmd]+T`). That way, when you create a new note, you can just press the hotkey for a new template and be ready to go!
> 👀 Step 4: [Preview Quartz Changes](notes/preview%20changes.md) > 👀 Step 4: [Preview Quartz Changes](notes/preview%20changes.md)

View File

@@ -5,9 +5,9 @@ tags:
weight: -2 weight: -2
--- ---
If you'd like to preview what your Quartz site looks like before deploying it to the internet, here's exactly how to do that! If you'd like to preview what your Quartz site looks like before deploying it to the internet, the following
instructions guide you through installing the proper dependencies to run it locally.
Note that both of these steps need to be completed.
## Install `hugo-obsidian` ## Install `hugo-obsidian`
This step will generate the list of backlinks for Hugo to parse. Ensure you have [Go](https://golang.org/doc/install) (>= 1.16) installed. This step will generate the list of backlinks for Hugo to parse. Ensure you have [Go](https://golang.org/doc/install) (>= 1.16) installed.
@@ -17,9 +17,7 @@ This step will generate the list of backlinks for Hugo to parse. Ensure you have
go install github.com/jackyzha0/hugo-obsidian@latest go install github.com/jackyzha0/hugo-obsidian@latest
``` ```
If you are running into an error saying that `command not found: hugo-obsidian`, make sure you set your `GOPATH` correctly! This will allow your terminal to correctly recognize hugo-obsidian as an executable. If you are running into an error saying that `command not found: hugo-obsidian`, make sure you set your `GOPATH` correctly (see [[notes/troubleshooting#`command not found: hugo-obsidian`|the troubleshooting page]])! This will allow your terminal to correctly recognize hugo-obsidian as an executable.
Afterwards, start the Hugo server as shown above and your local backlinks and interactive graph should be populated!
## Installing Hugo ## Installing Hugo
Hugo is the static site generator that powers Quartz. [Install Hugo with "extended" Sass/SCSS version](https://gohugo.io/getting-started/installing/) first. Then, Hugo is the static site generator that powers Quartz. [Install Hugo with "extended" Sass/SCSS version](https://gohugo.io/getting-started/installing/) first. Then,
@@ -34,4 +32,10 @@ make serve
# View your site in a browser at http://localhost:1313/ # View your site in a browser at http://localhost:1313/
``` ```
> 🌍 Step 5: [Hosting Quartz online!](notes/hosting.md) > [!INFO] Docker Support
>
> If you have the Docker CLI installed already, you can avoid installing `hugo-obsidian` and `hugo`. Instead, open your terminal, navigate to your folder with Quartz and run `make docker`
Afterwards, start the Hugo server as shown above and your local backlinks and interactive graph should be populated! Now, let's get it hosted online.
> 🌍 Step 5: [Hosting Quartz online!](notes/hosting.md)

View File

@@ -13,38 +13,25 @@ enableSemanticSearch: false
``` ```
## Natural Language ## Natural Language
Natural language search is powered by [Operand](https://operand.ai/). It understands language like a person does and finds results that best match user intent. In this sense, it is closer to how Google Search works. Natural language search is powered by [Operand](https://beta.operand.ai/). It understands language like a person does and finds results that best match user intent. In this sense, it is closer to how Google Search works.
Natural language search tends to produce higher quality results than full-text search. Natural language search tends to produce higher quality results than full-text search.
Here's how to set it up. Here's how to set it up.
1. Create an Operand Account on [their website](https://operand.ai/). 1. Login or Register for a new Operand account. Click the verification link sent to your email, and you'll be redirected to the dashboard. (Note) You do not need to enter a credit card to create an account, or get started with the Operand API. The first $10 of usage each month is free. To learn more, see pricing. If you go over your free quota, we'll (politely) reach out and ask you to configure billing.
2. Go to Dashboard > Settings > Integrations. 2. Create your first index. On the dashboard, under "Indexes", enter the name and description of your index, and click "Create Index". Note down the ID of the index (obtained by clicking on the index name in the list of indexes), as you'll need it in the next step. IDs are unique to each index, and look something like `uqv1duxxbdxu`.
3. Follow the steps to setup the GitHub integration. Operand needs access to GitHub in order to index your digital garden properly! 3. Click into the index you've created. Under "Index Something", select "SITEMAP" from the dropdown and click "Add Source".
4. Head over to Dashboard > Objects and press `(Cmd + K)` to open the omnibar and select 'Create Collection'. 4. For the "Sitemap.xml URL", put your deployed site's base URL followed by `sitemap.xml`. For example, for `quartz.jzhao.xyz`, put `https://quartz.jzhao.xyz/sitemap.xml`. Leave the URL Regex empty.
1. Set the 'Collection Label' to something that will help you remember it. 5. Get your API key. On the dashboard, under "API Keys", you can manage your API keys. If you don't already have an API key, click "Create API Key". You'll need this for the next step.
2. You can leave the 'Parent Collection' field empty. 6. Open `data/config.yaml`. Set `enableSemanticSearch` to `true`, `operandApiKey` to your copied key, and `operandIndexId` to the ID of the index we created from earlier..
5. Click into your newly made Collection.
1. Press the 'share' button that looks like three dots connected by lines.
2. Set the 'Interface Type' to `object-search` and click 'Create'.
3. This will bring you to a new page with a search bar. Ignore this for now.
6. Go back to Dashboard > Settings > API Keys and find your Quartz-specific Operand API key under 'Other keys'.
1. Copy the key (which looks something like `0e733a7f-9b9c-48c6-9691-b54fa1c8b910`).
2. Open `data/config.yaml`. Set `enableSemanticSearch` to `true` and `operandApiKey` to your copied key.
```yaml {title="data/config.yaml"} ```yaml {title="data/config.yaml"}
# the default option # the default option
enableSemanticSearch: true search:
operandApiKey: "0e733a7f-9b9c-48c6-9691-b54fa1c8b910" enableSemanticSearch: true
operandApiKey: "jp9k5hudse2a828z98kxd6z3payi8u90rnjf"
operandIndexId: "s0kf3bd6tldw"
``` ```
7. Make a commit and push your changes to GitHub. See the [[notes/hosting|hosting]] page if you haven't done this already. 7. Push your changes to the site and wait for it to deploy.
1. This step is *required* for Operand to be able to properly index your content. 8. Check the Operand dashboard and wait for your site to index. Enjoy natural language search powered by Operand!
2. Head over to Dashboard > Objects and select the collection that you made earlier
8. Press `(Cmd + K)` to open the omnibar again and select 'Create GitHub Repo'
1. Set the 'Repository Label' to `Quartz`
2. Set the 'Repository Owner' to your GitHub username
3. Set the 'Repository Ref' to `master`
4. Set the 'Repository Name' to the name of your repository (usually just `quartz` if you forked the repository without changing the name)
5. Leave 'Root Path' and 'Root URL' empty
9. Wait for your repository to index and enjoy natural language search in Quartz! Operand refreshes the index every 2h so all you need to do is just push to GitHub to update the contents in the search.

View File

@@ -15,10 +15,14 @@ Navigate to the GitHub repository for the Quartz project:
📁 [Quartz Repository](https://github.com/jackyzha0/quartz) 📁 [Quartz Repository](https://github.com/jackyzha0/quartz)
Then, Fork the repository into your own GitHub account. If you don't have an account, you can make on for free [here](https://github.com/join). More details about forking a repo can be found on [GitHub's documentation](https://docs.github.com/en/get-started/quickstart/fork-a-repo). Then, Fork the repository into your own GitHub account. **Make sure that when you fork, you _uncheck_ the 'Copy the `hugo` branch only' option**.
If you don't have an account, you can make on for free [here](https://github.com/join). More details about forking a repo can be found on [GitHub's documentation](https://docs.github.com/en/get-started/quickstart/fork-a-repo).
![[notes/images/fork.png]]
### Cloning ### Cloning
After you've made a fork of the repository, you need to download the files locally onto your machine. Ensure you have `git`, then type the following command replacing `YOUR-USERNAME` with your GitHub username. After you've made a fork of the repository, you need to download the files locally onto your machine. Ensure you have `git`, then type the following command in your terminal replacing `YOUR-USERNAME` with your GitHub username.
```shell ```shell
git clone https://github.com/YOUR-USERNAME/quartz git clone https://github.com/YOUR-USERNAME/quartz

View File

@@ -9,10 +9,15 @@ Want to see what Quartz can do? Here are some cool community gardens :)
- [Scaling Synthesis - A hypertext research notebook](https://scalingsynthesis.com/) - [Scaling Synthesis - A hypertext research notebook](https://scalingsynthesis.com/)
- [AWAGMI Intern Notes](https://notes.awagmi.xyz/) - [AWAGMI Intern Notes](https://notes.awagmi.xyz/)
- [Shihyu's PKM](https://shihyuho.github.io/pkm/) - [Shihyu's PKM](https://shihyuho.github.io/pkm/)
- [Chloe's Garden](https://garden.chloeabrasada.online/)
- [SlRvb's Site](https://slrvb.github.io/Site/) - [SlRvb's Site](https://slrvb.github.io/Site/)
- [Course notes for Information Technology Advanced Theory](https://a2itnotes.github.io/quartz/) - [Course notes for Information Technology Advanced Theory](https://a2itnotes.github.io/quartz/)
- [Brandon Boswell's Garden](https://brandonkboswell.com) - [Brandon Boswell's Garden](https://brandonkboswell.com)
- [Siyang's Courtyard](https://siyangsun.github.io/courtyard/) - [Siyang's Courtyard](https://siyangsun.github.io/courtyard/)
- [Data Dictionary 🧠](https://glossary.airbyte.com/)
- [sspaeti.com's Second Brain](https://brain.sspaeti.com/)
- [oldwinterの数字花园](https://garden.oldwinter.top/)
- [SethMB Work](https://sethmb.xyz/)
- [Abhijeet's Math Wiki](https://abhmul.github.io/quartz/Math-Wiki/)
- [Mike's AI Garden 🤖🪴](https://mwalton.me/)
If you want to see your own on here, submit a [Pull Request adding yourself to this file](https://github.com/jackyzha0/quartz/blob/hugo/content/notes/showcase.md)! If you want to see your own on here, submit a [Pull Request adding yourself to this file](https://github.com/jackyzha0/quartz/blob/hugo/content/notes/showcase.md)!

View File

@@ -38,12 +38,12 @@ Yes! All built files can be found under `/public` in the `master` branch. More d
Make sure you set your `GOPATH` correctly! This will allow your terminal to correctly recognize `hugo-obsidian` as an executable. Make sure you set your `GOPATH` correctly! This will allow your terminal to correctly recognize `hugo-obsidian` as an executable.
```shell ```shell
# Add the following 2 lines to your ~/.bash_profile # Add the following 2 lines to your ~/.bash_profile (~/.zshrc if you are on Mac)
export GOPATH=/Users/$USER/go export GOPATH=/Users/$USER/go
export PATH=$GOPATH/bin:$PATH export PATH=$GOPATH/bin:$PATH
# In your current terminal, to reload the session # In your current terminal, to reload the session
source ~/.bash_profile source ~/.bash_profile # again, (~/.zshrc if you are on Mac)
``` ```
### How come my notes aren't being rendered? ### How come my notes aren't being rendered?
@@ -52,8 +52,13 @@ You probably forgot to include front matter in your Markdown files. You can eith
### My custom domain isn't working! ### My custom domain isn't working!
Walk through the steps in [the hosting guide](notes/hosting.md) again. Make sure you wait 30 min to 1 hour for changes to take effect. Walk through the steps in [the hosting guide](notes/hosting.md) again. Make sure you wait 30 min to 1 hour for changes to take effect.
### How do I setup Google Analytics? ### How do I setup analytics?
You can edit it in `config.toml` and either use a V3 (UA-) or V4 (G-) tag. Quartz by default uses [Plausible](https://plausible.io/) for analytics.
If you would prefer to use Google Analytics, you can follow this [guide in the Hugo documentation](https://gohugo.io/templates/internal/#google-analytics).
Alternatively, you can also import your Google Analytics data into Plausible by [following this guide](https://plausible.io/docs/google-analytics-import).
### How do I change the content on the home page? ### How do I change the content on the home page?
To edit the main home page, open `/content/_index.md`. To edit the main home page, open `/content/_index.md`.
@@ -78,4 +83,4 @@ Not out of the box. You could probably make it work by editing `/layouts/_defaul
## Still Stuck? ## Still Stuck?
Quartz isn't perfect! If you're still having troubles, file an issue in the GitHub repo with as much information as you can reasonably provide. Alternatively, you can message me on [Twitter](https://twitter.com/_jzhao) and I'll try to get back to you as soon as I can. Quartz isn't perfect! If you're still having troubles, file an issue in the GitHub repo with as much information as you can reasonably provide. Alternatively, you can message me on [Twitter](https://twitter.com/_jzhao) and I'll try to get back to you as soon as I can.
🐛 [Submit an Issue](https://github.com/jackyzha0/quartz/issues) 🐛 [Submit an Issue](https://github.com/jackyzha0/quartz/issues)

View File

@@ -11,16 +11,19 @@ enableFooter: true
enableContextualBacklinks: true enableContextualBacklinks: true
enableRecentNotes: false enableRecentNotes: false
enableGitHubEdit: true enableGitHubEdit: true
enableMermaid: true
GitHubLink: https://github.com/jackyzha0/quartz/tree/hugo/content GitHubLink: https://github.com/jackyzha0/quartz/tree/hugo/content
enableSemanticSearch: false search:
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY" enableSemanticSearch: false
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY"
operandIndexId: "REPLACE-WITH-YOUR-OPERAND-INDEX-ID"
description: description:
Host your second brain and digital garden for free. Quartz features extremely fast full-text search, Host your second brain and digital garden for free. Quartz features extremely fast full-text search,
Wikilink support, backlinks, local graph, tags, and link previews. Wikilink support, backlinks, local graph, tags, and link previews.
page_title: page_title:
"🪴 Quartz 3.2" "🪴 Quartz 3.3"
links: links:
- link_name: Twitter - link_name: Twitter
link: https://twitter.com/_jzhao link: https://twitter.com/_jzhao
- link_name: Github - link_name: GitHub
link: https://github.com/jackyzha0 link: https://github.com/jackyzha0

65
i18n/bn.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "এই পাতাটি নেই (অথবা ব্যক্তিগত)"
[404_back]
other = "↳ হোম পেজে ফিরে যাই"
[all_posts]
other = "সকল {{.Title}}"
[last_updated]
other = "সর্বশেষ পরিবর্তিত"
[notes_count]
other = "সংখ্যক এই ট্যাগের"
[first_10]
other = "প্রথম ১০ টি ফলাফল"
[tag]
other = "ট্যাগ"
[backlinks]
other = "পিছন পাতা"
[no_backlinks]
other = "পিছনে কোন পাতা নেই"
[home]
other = "হোম"
[light_mode]
other = "আলোকিত"
[dark_mode]
other = "অন্ধকার"
[edit_source]
other = "সম্পাদন করুন"
[interactive_graph]
other = "জ্ঞানকোষের গ্রাফ"
[search]
other = "খুঁজুন"
[search_icon]
other = "খোঁজার আইকন"
[icon_search]
other = "জ্ঞানকোষ"
[recent_notes]
other = "সাম্প্রতিক"
[first_3_notes]
other = "প্রথম ৩ {{ .notes }}"
[search_for_something]
other = "খুঁজুন..."
[toc]
other = "সূচিপত্র"
[copyright]
other = "{{ .name }} কর্তৃক <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a> ব্যবহার করে তৈরিকৃত © {{ .year }}"

65
i18n/de.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "Hey! Hast du dich verirrt? Diese Seite existiert leider nicht (oder ist privat)."
[404_back]
other = "↳ Zurück zur Startseite."
[all_posts]
other = "Alle {{.Title}}"
[last_updated]
other = "Zuletzt aktualisiert"
[notes_count]
other = "Beiträge mit diesem Tag"
[first_10]
other = "Zeige die ersten 10 Ergebnisse"
[tag]
other = "Tag"
[backlinks]
other = "Backlinks"
[no_backlinks]
other = "Keine Backlinks gefunden"
[home]
other = "Home"
[light_mode]
other = "Light Mode"
[dark_mode]
other = "Dark Mode"
[edit_source]
other = "Quelldatei bearbeiten"
[interactive_graph]
other = "Interaktiver Graph"
[search]
other = "Suche"
[search_icon]
other = "Suchsymbol"
[icon_search]
other = "Symbol, um die Suche zu öffnen"
[recent_notes]
other = "Neuste Beiträge"
[first_3_notes]
other = "Die ersten 3 {{ .notes }}"
[search_for_something]
other = "Suche nach etwas ..."
[toc]
other = "Inhaltsverzeichnis"
[copyright]
other = "Made by {{ .name }} using <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a>, © {{ .year }}"

65
i18n/es.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "Hey! Te ves un poco perdido. Esta página no existe (o puede que sea privada)."
[404_back]
other = "↳ Vamos a llevarte de regreso a casa."
[all_posts]
other = "Todos {{.Title}}"
[last_updated]
other = "Actualizado por última vez"
[notes_count]
other = "notas con esta etiqueta"
[first_10]
other = "mostrando los primeros 10 resultados"
[tag]
other = "Etiqueta"
[backlinks]
other = "Backlinks"
[no_backlinks]
other = "No se encontraron backlinks"
[home]
other = "Casa"
[light_mode]
other = "Modo Claro"
[dark_mode]
other = "Modo Oscuro"
[edit_source]
other = "Editar Fuente"
[interactive_graph]
other = "Gráfico Interactivo"
[search]
other = "Búsqueda"
[search_icon]
other = "Ícono de Búsqueda"
[icon_search]
other = "Ícono para abrir la búsqueda"
[recent_notes]
other = "Notas Recientes"
[first_3_notes]
other = "primeras 3 {{ .notes }}"
[search_for_something]
other = "Buscar algo..."
[toc]
other = "Tabla de Contenido"
[copyright]
other = "Hecho por {{ .name }} usando <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a>, © {{ .year }}"

65
i18n/fr.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "Hey ! Vous semblez perdu‧e. Cette page n'existe pas (ou est privée)."
[404_back]
other = "↳ Clique ici pour retourner sur la page d'accueil"
[all_posts]
other = "Tout {{.Title}}"
[last_updated]
other = "Dernière modification"
[notes_count]
other = "notes avec ce tag"
[first_10]
other = "les 10 premiers résultats"
[tag]
other = "Tag"
[backlinks]
other = "Backlinks"
[no_backlinks]
other = "Pas de backlinks trouvés"
[home]
other = "Accueil"
[light_mode]
other = "Mode Clair"
[dark_mode]
other = "Mode Sombre"
[edit_source]
other = "Modifier la source"
[interactive_graph]
other = "Graphique interactif"
[search]
other = "Rechercher"
[search_icon]
other = "l'icône de recherche"
[icon_search]
other = "L'icône pour ouvrir la recherche"
[recent_notes]
other = "Notes récentes"
[first_3_notes]
other = "les 3 premières {{ .notes }}"
[search_for_something]
other = "Rechercher quelque-chose..."
[toc]
other = "Table des matières"
[copyright]
other = "Fait par {{ .name }} en utilisant <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a>, © {{ .year }}"

65
i18n/it.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "Hey, ti sei perso? Questa pagina non esiste (o è privata)"
[404_back]
other = "↳ Torna alla home."
[all_posts]
other = "Tutti {{.Title}}"
[last_updated]
other = "Ultima modifica"
[notes_count]
other = "note con questo tag"
[first_10]
other = "mostrando i primi 10 risultati"
[tag]
other = "Tag"
[backlinks]
other = "Backlinks"
[no_backlinks]
other = "Nessun Backlink trovato"
[home]
other = "Home"
[light_mode]
other = "Modalità Chiara"
[dark_mode]
other = "Modalità Scura"
[edit_source]
other = "Modifica Sorgente"
[interactive_graph]
other = "Grafico Interattivo"
[search]
other = "Cerca"
[search_icon]
other = "Icona di ricerca"
[icon_search]
other = "Icona per aprire la ricerca"
[recent_notes]
other = "Note Recenti"
[first_3_notes]
other = "prime 3 {{ .notes }}"
[search_for_something]
other = "Cerca qualcosa..."
[toc]
other = "Indice"
[copyright]
other = "Realizzato da {{ .name }} con <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a>, © {{ .year }}"

65
i18n/no.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "Hei! Ser ut til at du har gått deg vill. Denne siden finnes ikke (eller den kan være privat)."
[404_back]
other = "↳ La oss få deg hjem."
[all_posts]
other = "Alle {{.Title}}"
[last_updated]
other = "Sist oppdatert"
[notes_count]
other = "notater med denne taggen"
[first_10]
other = "viser første 10 resultatene"
[tag]
other = "Tag"
[backlinks]
other = "Tilbakekoblinger"
[no_backlinks]
other = "Ingen tilbakekoblinger funnet"
[home]
other = "Hjem"
[light_mode]
other = "Lys Modus"
[dark_mode]
other = "Mørk Modus"
[edit_source]
other = "Rediger Kilde"
[interactive_graph]
other = "Interaktiv Graf"
[search]
other = "Søk"
[search_icon]
other = "Søkeikon"
[icon_search]
other = "Ikon for å åpne søk"
[recent_notes]
other = "Nylige notater"
[first_3_notes]
other = "første 3 {{ .notes }}"
[search_for_something]
other = "Søk etter noe..."
[toc]
other = "Innholdsfortegnelse"
[copyright]
other = "Opprettet av {{ .name }} ved hjelp av <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a>, © {{ .year }}"

65
i18n/tr.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "Hey! Biraz kaybolmuş görünüyorsun. Bu sayfa mevcut değil (veya özel olabilir)."
[404_back]
other = "↳ Seni eve götürelim."
[all_posts]
other = "Hepsi {{.Title}}"
[last_updated]
other = "Son güncelleme"
[notes_count]
other = "Bu etikete sahip notlar"
[first_10]
other = "İlk 10 sonuç gösteriliyor"
[tag]
other = "Etiket"
[backlinks]
other = "Geri bağlantılar"
[no_backlinks]
other = "Geri bağlantı bulunamadı"
[home]
other = "Ev"
[light_mode]
other = "Aydınlık Modu"
[dark_mode]
other = "Karanlık Modu"
[edit_source]
other = "Kaynağı Düzenle"
[interactive_graph]
other = "Etkileşimli Grafik"
[search]
other = "Ara"
[search_icon]
other = "Arama Simgesi"
[icon_search]
other = "Aramayı açmak için simge tıklayın"
[recent_notes]
other = "Son Notlar"
[first_3_notes]
other = "İlk Üç {{ .notes }}"
[search_for_something]
other = "Bir şey ara..."
[toc]
other = "İçindekiler"
[copyright]
other = "{{ .name }} tarafından <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a> kullanılarak yapılmıştır, © {{ .year }}"

65
i18n/uk.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "Хей! Виглядаєте здивовано. Цієї сторінки не існує (або вона приватна)."
[404_back]
other = "↳ Повернемося додому."
[all_posts]
other = "Всі {{.Title}}"
[last_updated]
other = "Оновлено"
[notes_count]
other = "нонаток з цим тегом"
[first_10]
other = "показано 10 перших результатів"
[tag]
other = "Тег"
[backlinks]
other = "Зворотнє посилання"
[no_backlinks]
other = "Зворотних посилань не знайдено"
[home]
other = "Дім"
[light_mode]
other = "Світлий Режим"
[dark_mode]
other = "Темний Режим"
[edit_source]
other = "Редагувати Джерело"
[interactive_graph]
other = "Інтерактивний граф"
[search]
other = "Пошук"
[search_icon]
other = "Іконка Пошуку"
[icon_search]
other = "Іконка для відкриття пошуку"
[recent_notes]
other = "Нещодавні Нотатки"
[first_3_notes]
other = "перші 3 {{ .notes }}"
[search_for_something]
other = "Знайти щось..."
[toc]
other = "Зміст"
[copyright]
other = "Створено {{ .name }} з використанням <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a>, © {{ .year }}"

65
i18n/zh-cn.toml Normal file
View File

@@ -0,0 +1,65 @@
[404_message]
other = "喔哦...... 你是不是迷路了呀..... (⌯' '⌯ ) 这个页面并不存在(也许它还未被发布)。"
[404_back]
other = "↳ 回到主页"
[all_posts]
other = "所有 {{.Title}}"
[last_updated]
other = "最后更新于"
[notes_count]
other = "带有此标签的笔记"
[first_10]
other = "正在展示前10个结果"
[tag]
other = "标签"
[backlinks]
other = "反向链接"
[no_backlinks]
other = "没有找到反向链接"
[home]
other = "主页"
[light_mode]
other = "明亮模式"
[dark_mode]
other = "黑暗模式"
[edit_source]
other = "编辑源码"
[interactive_graph]
other = "互动图"
[search]
other = "搜索"
[search_icon]
other = "搜索图标"
[icon_search]
other = "打开搜索图标"
[recent_notes]
other = "近期笔记"
[first_3_notes]
other = "前3个 {{ .notes }}"
[search_for_something]
other = "进行搜索......"
[toc]
other = "目录"
[copyright]
other = "由 {{ .name }} 用 <a href=\"https://github.com/jackyzha0/quartz\">Quartz</a> 创造, © {{ .year }}"

View File

@@ -0,0 +1,4 @@
<div class="mermaid">
{{- .Inner | safeHTML }}
</div>
{{ .Page.Store.Set "hasMermaid" true }}

View File

@@ -1,9 +1,9 @@
{{$trimmed := strings.TrimSuffix ".md" (.Destination | safeURL)}} {{$dashedurl := replace .Destination "%20" "-" }}
{{$dashedurl := replace $trimmed "%20" "-" }}
{{$external := strings.HasPrefix $dashedurl "http" }} {{$external := strings.HasPrefix $dashedurl "http" }}
{{- if $external -}} {{- if $external -}}
<a href="{{ $dashedurl }}" rel="noopener">{{ .Text | safeHTML }}</a> <a href="{{ $dashedurl }}" rel="noopener">{{ .Text | safeHTML }}</a>
{{- else -}} {{- else -}}
{{$trimmed := strings.TrimSuffix ".md" (.Destination | safeURL)}}
{{$spacedurl := replace $trimmed "%20" " " }} {{$spacedurl := replace $trimmed "%20" " " }}
{{$fixedUrl := (cond (hasPrefix $spacedurl "/") $spacedurl (print "/" $spacedurl)) | urlize}} {{$fixedUrl := (cond (hasPrefix $spacedurl "/") $spacedurl (print "/" $spacedurl)) | urlize}}
{{$nonexistent := eq (.Page.GetPage $spacedurl).RelPermalink ""}} {{$nonexistent := eq (.Page.GetPage $spacedurl).RelPermalink ""}}

View File

@@ -15,7 +15,14 @@
</p> </p>
<ul class="tags"> <ul class="tags">
{{ range (.GetTerms "tags") }} {{ range (.GetTerms "tags") }}
<li><a href="{{ .Permalink }}">{{ .LinkTitle | humanize }}</a></li> <li><a href="{{ .Permalink }}">
{{if (eq $.Site.Language.Lang "en")}}
{{ .LinkTitle | humanize }}
{{else}}
{{ .LinkTitle }}
{{end}}
</a>
</li>
{{ end }} {{ end }}
</ul> </ul>
{{partial "toc.html" .}} {{partial "toc.html" .}}

View File

@@ -8,6 +8,24 @@
name="description" name="description"
content="{{if .IsHome}}{{$data.description | default $.Site.Data.config.description}}{{else}}{{.Summary}}{{end}}" content="{{if .IsHome}}{{$data.description | default $.Site.Data.config.description}}{{else}}{{.Summary}}{{end}}"
/> />
<meta property="og:title" content="{{ .Title }}">
<meta property="og:description" content="{{if .IsHome}}{{$data.description | default $.Site.Data.config.description}}{{else}}{{.Summary}}{{end}}">
<meta property="og:type" content="website">
<meta property="og:image" content="{{.Site.BaseURL}}icon.png">
<meta property="og:url" content="{{ .Permalink }}">
<meta property="og:width" content="200">
<meta property="og:height" content="200">
<meta name="twitter:card" content="summary" />
<meta name="twitter:title" content="{{ .Title }}" />
<meta name="twitter:description" content="{{if .IsHome}}{{$data.description | default $.Site.Data.config.description}}{{else}}{{.Summary}}{{end}}" />
<meta name="twitter:image" content="{{.Site.BaseURL}}icon.png">
{{ range $data.links }}
{{ if strings.Contains .link "twitter.com" }}
{{ $twitter_handle := index (split .link "/") (sub (len (split .link "/")) 1) }}
<meta name="twitter:site" content="{{ $twitter_handle }}" />
{{ end }}
{{ end }}
<title> <title>
{{ if .Title }}{{ .Title }}{{ else }}{{ $data.page_title | default $.Site.Data.config.page_title }}{{ {{ if .Title }}{{ .Title }}{{ else }}{{ $data.page_title | default $.Site.Data.config.page_title }}{{
end }} end }}
@@ -50,27 +68,29 @@
<script src="{{$s.Permalink}}"></script> <script src="{{$s.Permalink}}"></script>
{{end}} {{end}}
{{partial "katex.html" .}} {{partial "katex.html" .}}
<script src="https://unpkg.com/@floating-ui/core@0.7.3"></script> {{partial "mermaid.html" .}}
<script src="https://unpkg.com/@floating-ui/dom@0.5.4"></script>
<script src="https://cdn.jsdelivr.net/npm/@floating-ui/core@1.2.1"></script>
<script src="https://cdn.jsdelivr.net/npm/@floating-ui/dom@1.2.1"></script>
{{ $popover := resources.Get "js/popover.js" | resources.Fingerprint "md5" | {{ $popover := resources.Get "js/popover.js" | resources.Fingerprint "md5" |
resources.Minify }} resources.Minify }}
<script src="{{$popover.Permalink}}"></script> <script defer src="{{$popover.Permalink}}"></script>
<!-- Optional scripts --> <!-- Optional scripts -->
{{ if $data.enableCodeBlockTitle | default $.Site.Data.config.enableCallouts }} {{ if $data.enableCodeBlockTitle | default $.Site.Data.config.enableCallouts }}
{{ $codeTitle := resources.Get "js/code-title.js" | resources.Fingerprint "md5" | resources.Minify }} {{ $codeTitle := resources.Get "js/code-title.js" | resources.Fingerprint "md5" | resources.Minify }}
<script src="{{$codeTitle.Permalink}}"></script> <script defer src="{{$codeTitle.Permalink}}"></script>
{{end}} {{end}}
{{ if $data.enableCodeBlockCopy | default $.Site.Data.config.enableCodeBlockCopy }} {{ if $data.enableCodeBlockCopy | default $.Site.Data.config.enableCodeBlockCopy }}
{{ $clipboard := resources.Get "js/clipboard.js" | resources.Fingerprint "md5" | resources.Minify }} {{ $clipboard := resources.Get "js/clipboard.js" | resources.Fingerprint "md5" | resources.Minify }}
<script src="{{$clipboard.Permalink}}"></script> <script defer src="{{$clipboard.Permalink}}"></script>
{{ end }} {{ end }}
{{ if $data.enableCallouts | default $.Site.Data.config.enableCallouts }} {{ if $data.enableCallouts | default $.Site.Data.config.enableCallouts }}
{{ $callouts := resources.Get "js/callouts.js" | resources.Fingerprint "md5" | resources.Minify }} {{ $callouts := resources.Get "js/callouts.js" | resources.Fingerprint "md5" | resources.Minify }}
<script src="{{$callouts.Permalink}}"></script> <script defer src="{{$callouts.Permalink}}"></script>
{{ end }} {{ end }}
<!-- Preload page vars --> <!-- Preload page vars -->
@@ -79,6 +99,9 @@
"indices/contentIndex.json" | resources.Fingerprint "md5" | resources.Minify "indices/contentIndex.json" | resources.Fingerprint "md5" | resources.Minify
}} }}
<script> <script>
const SEARCH_ENABLED = {{.Site.Data.config.search.enableSemanticSearch}}
const LATEX_ENABLED = {{.Site.Data.config.enableLatex}}
const PRODUCTION = {{ hugo.IsProduction }}
const BASE_URL = {{.Site.BaseURL}} const BASE_URL = {{.Site.BaseURL}}
const fetchData = Promise.all([ const fetchData = Promise.all([
fetch("{{ $linkIndex.Permalink }}") fetch("{{ $linkIndex.Permalink }}")
@@ -115,12 +138,11 @@
{{if $data.enableCallouts | default $.Site.Data.config.enableCallouts -}} {{if $data.enableCallouts | default $.Site.Data.config.enableCallouts -}}
addCollapsibleCallouts(); addCollapsibleCallouts();
{{ end }} {{ end }}
{{if $data.enableLinkPreview | default $.Site.Data.config.enableLinkPreview}} {{if $data.enableLinkPreview | default $.Site.Data.config.enableLinkPreview}}
initPopover( initPopover(
{{strings.TrimRight "/" .Site.BaseURL }}, {{strings.TrimRight "/" .Site.BaseURL }},
{{$data.enableContextualBacklinks | default $.Site.Data.config.enableContextualBacklinks}}, {{$data.enableContextualBacklinks | default $.Site.Data.config.enableContextualBacklinks}}
{{$data.enableLatex | default $.Site.Data.config.enableLatex}}
) )
{{end}} {{end}}
@@ -143,6 +165,42 @@
} }
{{end}} {{end}}
{{if $data.enableMermaid | default $.Site.Data.config.enableMermaid}}
var els = document.getElementsByClassName("mermaid");
if (els.length > 0) {
import('https://unpkg.com/mermaid@9/dist/mermaid.esm.min.mjs').then(
(obj) => {
// init forces mermaid to render mermaid markdown without waiting
// for DOMContentLoaded event
obj.default.init();
}
)
}
{{end}}
// analytics
function clickHandler(evt) {
const target = evt.target
const classNames = target.className.split(" ")
const broken = classNames.includes("broken")
const internal = classNames.includes("internal-link")
plausible("Link Click", {
props: {
href: target.href,
broken,
internal,
graph: false,
}
})
}
const links = document.querySelectorAll("a")
for (link of links) {
if (link.className.includes("root-title")) {
link.addEventListener('click', clickHandler, {once: true})
}
}
} }
const init = (doc = document) => { const init = (doc = document) => {
@@ -160,6 +218,9 @@
{left: '$$', right: '$$', display: true}, {left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}, {left: '$', right: '$', display: false},
], ],
macros: {
'': "'"
},
throwOnError : false throwOnError : false
}); });
{{end}} {{end}}
@@ -185,5 +246,7 @@
}) })
</script> </script>
{{end}} {{end}}
{{ $trimmedURL := trim (index (split .Site.BaseURL "://") 1) "/" }}
<script defer data-domain="{{$trimmedURL}}" src="https://plausible.io/js/script.js"></script>
<script>window.plausible = window.plausible || function() { (window.plausible.q = window.plausible.q || []).push(arguments) }</script>
</head> </head>
{{ template "_internal/google_analytics.html" . }}

View File

@@ -1,6 +1,6 @@
<header> <header>
{{ $config := cond (eq $.Site.Language.Lang "en") "config" (printf "config.%s" $.Site.Language.Lang) }} {{ $config := cond (eq $.Site.Language.Lang "en") "config" (printf "config.%s" $.Site.Language.Lang) }}
<h1 id="page-title"><a href="{{ "" | absLangURL }}">{{ ( index $.Site.Data $config ).page_title | default $.Site.Data.config.page_title }}</a></h1> <h1 id="page-title"><a class="root-title" href="{{ "" | absLangURL }}">{{ ( index $.Site.Data $config ).page_title | default $.Site.Data.config.page_title }}</a></h1>
<div class="spacer"></div> <div class="spacer"></div>
<div id="search-icon"> <div id="search-icon">
<p>{{ i18n "search" }}</p> <p>{{ i18n "search" }}</p>

View File

@@ -1,5 +1,14 @@
{{if $.Site.Data.config.enableLatex}} {{if $.Site.Data.config.enableLatex}}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css" integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous"> <link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css" as="style"
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js" integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx" crossorigin="anonymous"></script> onload="this.onload=null;this.rel='stylesheet'"
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js" integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR" crossorigin="anonymous"></script> integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
{{end}} <script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.js"
integrity="sha384-z1fJDqw8ZApjGO3/unPWUPsIymfsJmyrDVWC8Tv/a1HeOtGmkwNd/7xUS0Xcnvsx"
crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/contrib/auto-render.min.js"
integrity="sha384-+XBljXPPiv+OzfbB3cVmLHf4hdUFHlWNZN5spNQ7rmHTXpd7WvJum6fIACpNNfIR"
crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.2/dist/contrib/copy-tex.min.js"
integrity="sha384-ww/583aHhxWkz5DEVn6OKtNiIaLi2iBRNZXfJRiY1Ai7tnJ9UXpEsyvOITVpTl4A"
crossorigin="anonymous"></script>
{{end}}

View File

@@ -0,0 +1,8 @@
{{if $.Site.Data.config.enableMermaid}}
{{ if .Page.Store.Get "hasMermaid" }}
<script type="module">
import mermaid from 'https://unpkg.com/mermaid@9/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true });
</script>
{{ end }}
{{ end }}

View File

@@ -6,7 +6,7 @@
is a collection of pages. is a collection of pages.
https://gohugo.io/content-management/related/ https://gohugo.io/content-management/related/
--> -->
{{$notes := .Site.RegularPages}} {{$notes := .Site.RegularPages.ByLastmod.Reverse}}
{{partial "page-list.html" (first 3 $notes)}} {{partial "page-list.html" (first 3 $notes)}}
</div> </div>

View File

@@ -6,9 +6,9 @@
</div> </div>
</div> </div>
</div> </div>
{{if $.Site.Data.config.enableSemanticSearch}} {{if $.Site.Data.config.search.enableSemanticSearch}}
{{ $js := resources.Get "js/semantic-search.js" | resources.ExecuteAsTemplate "js/semantic-search.js" . | resources.Fingerprint "md5" | resources.Minify }} {{ $js := resources.Get "js/semantic-search.js" | resources.ExecuteAsTemplate "js/semantic-search.js" . | resources.Fingerprint "md5" | resources.Minify }}
<script defer src="{{ $js.Permalink }}"></script> <script defer type="module" src="{{ $js.Permalink }}"></script>
{{else}} {{else}}
<script src="https://cdn.jsdelivr.net/npm/flexsearch@0.7.21/dist/flexsearch.bundle.js" <script src="https://cdn.jsdelivr.net/npm/flexsearch@0.7.21/dist/flexsearch.bundle.js"
integrity="sha256-i3A0NZGkhsKjVMzFxv3ksk0DZh3aXqu0l49Bbh0MdjE=" crossorigin="anonymous" defer></script> integrity="sha256-i3A0NZGkhsKjVMzFxv3ksk0DZh3aXqu0l49Bbh0MdjE=" crossorigin="anonymous" defer></script>

View File

@@ -3,9 +3,9 @@
{{ $page := .Page }} {{ $page := .Page }}
{{/* Escape slashes for Latex to fix line breaks */}} {{/* Escape slashes for Latex to fix line breaks */}}
{{$latex := findRE "\\$\\$([^\\$]+)\\$\\$" $content}} {{$latex := findRE "(?:\\${2}([^\\$]+)\\${2})|(?:\\$([^\\$]*)\\$)" $content}}
{{range $latex}} {{range $latex}}
{{$fixed := replaceRE "\\\\(?: +|\\n)" "\\\\" .}} {{$fixed := replaceRE "\\\\(?: +|\\n)" "\\\\ " .}}
{{$content = replace $content . $fixed}} {{$content = replace $content . $fixed}}
{{end}} {{end}}
@@ -14,6 +14,7 @@
{{$codefences := $raw | findRE "\\x60[^\\x60\\n]+\\x60"}} {{$codefences := $raw | findRE "\\x60[^\\x60\\n]+\\x60"}}
{{$codeblocks := $raw | findRE "\\x60{3}[^\\x60]+\\x60{3}"}} {{$codeblocks := $raw | findRE "\\x60{3}[^\\x60]+\\x60{3}"}}
{{$code := union $codefences $codeblocks}} {{$code := union $codefences $codeblocks}}
{{range $wikilinks}} {{range $wikilinks}}
{{$cur := .}} {{$cur := .}}
{{$incode := false}} {{$incode := false}}
@@ -22,33 +23,95 @@
{{$incode = true}} {{$incode = true}}
{{end}} {{end}}
{{end}} {{end}}
{{if not $incode}} {{if not $incode}}
{{if (hasPrefix . "!")}}
{{$inner := . | strings.TrimPrefix "![[" | strings.TrimSuffix "]]" }} <!-- remove link delimiters -->
{{$split := split $inner "|"}} {{$inner := . | strings.TrimPrefix "!" | strings.TrimPrefix "[[" | strings.TrimSuffix "]]" }}
{{$path := index $split 0 | relURL}} <!-- split from alias -->
{{$width := index $split 1}} {{$split := split $inner "|"}}
{{$img := printf "<img src=\"%s\" width=\"%s\" />" $path (default "auto" $width)}} <!-- separate link path -->
{{$content = replace $content . $img}} {{$path := index $split 0}}
{{else}}
{{$inner := . | strings.TrimPrefix "[[" | strings.TrimSuffix "]]" }} {{$reference := split $path "#"}}
{{$split := split $inner "|"}} <!-- path with heading link removed -->
{{$path := index $split 0}} {{$title := index $reference 0}}
{{$reference := split $path "#"}} <!-- $display is hyperlink display text -->
{{$title := index $reference 0}} <!-- use alias, else title -->
{{$display := default $title (index $split 1)}}
<!-- remove subfolder from title -->
{{$display := index (last 1 (split $display "/")) 0}}
<!-- attempt to get title -->
{{$searchtitle := $title }}
{{$curpage := $page.GetPage $searchtitle }}
<!-- attempt to search md file instead -->
{{ if (eq $curpage.String "nopPage") }}
{{$searchtitle = (add $title ".md") }}
{{$curpage = $page.GetPage $searchtitle }}
{{ end }}
<!-- attempt to reverse typographer behaviour -->
{{ if (eq $curpage.String "nopPage") }}
{{$searchtitle = (replace $searchtitle "&amp;" "&") }}
{{$searchtitle = (replace $searchtitle "&quot;" "\"") }}
{{$searchtitle = (replace $searchtitle "&rdquo;" "\"") }}
{{$searchtitle = (replace $searchtitle "&ldquo;" "\"") }}
{{$searchtitle = (replace $searchtitle "&rsquo;" "'") }}
{{$searchtitle = (replace $searchtitle "&lsquo;" "'") }}
{{$curpage = $page.GetPage $searchtitle }}
{{ end }}
{{$relpath := relURL $path}}
<!-- If path to Hugo page -->
{{if not (eq $curpage.String "nopPage") }}
{{$block := default "" (index $reference 1)}} {{$block := default "" (index $reference 1)}}
{{$block = strings.TrimRight "/" (cond (eq $block "") $block (printf "#%s" $block)) | urlize | lower}} {{$block = strings.TrimRight "/" (cond (eq $block "") $block (printf "#%s" $block)) | urlize | lower}}
{{$href := strings.TrimRight "/" ($page.GetPage $title).RelPermalink}} {{$href := strings.TrimRight "/" $curpage.RelPermalink}}
{{$display := default $title (index $split 1)}} {{$link := printf "<a href=\"%s%s\" rel=\"noopener\" class=\"internal-link\" data-src=\"%s\">%s</a>" $href $block $href $display}}
{{if not $href}} {{$content = replace $content . $link}}
{{$link := printf "<a class=\"internal-link broken\">%s</a>" $display}} <!-- If path to existing file -->
{{$content = replace $content . $link}} {{else if fileExists $relpath}}
{{$splitpath := split $relpath "/"}}
{{$dirname := first (sub (len $splitpath) 1) $splitpath | path.Join | urlize}}
{{$basename := index (last 1 $splitpath) 0}}
{{$href := printf "/%s/%s" $dirname $basename}}
<!-- Embedded? -->
{{if (hasPrefix . "!")}}
{{ $embed_ext := lower (path.Ext $href) }}
<!-- Image -->
{{if in ".png .jpg .jpeg .gif .bmp .svg" $embed_ext }}
{{$width := default "auto" (index $split 1) }}
{{$link := printf "<img src=\"%s\" width=\"%s\" />" $href $width}}
{{$content = replace $content . $link}}
<!-- Video -->
{{else if in ".mp4 .webm .ogv .mov .mkv" $embed_ext}}
{{$link := printf "<video src=\"%s\" style=\"width: -webkit-fill-available;\" controls></video>" $href}}
{{$content = replace $content . $link}}
<!-- Audio -->
{{else if in ".mp3 .webm .wav .m4a .ogg .3gp .flac" $embed_ext}}
{{$link := printf "<audio src=\"%s\" controls></audio>" $href}}
{{$content = replace $content . $link}}
<!-- PDF -->
{{else if in ".pdf" $embed_ext }}
{{$src_link := printf "<a href=\"%s\" rel=\"noopener\" class=\"internal-link\">[source]</a>" $href}}
{{$iframe_link := printf "<iframe src=\"%s\" style=\"height: -webkit-fill-available; width: -webkit-fill-available;\"></iframe>" $href}}
{{$link := printf "%s<br>%s" $src_link $iframe_link}}
{{$content = replace $content . $link}}
<!-- other -->
{{else}}
{{$link := printf "<a href=\"%s\" rel=\"noopener\" class=\"internal-link\">%s</a>" $href $href}}
{{$content = replace $content . $link}}
{{end}}
{{else}} {{else}}
{{$fullhref := printf "%s%s" $href $block }} {{$link := printf "<a href=\"%s\" rel=\"noopener\" class=\"internal-link\">%s</a>" $href $display}}
{{$link := printf "<a href=\"%s\" rel=\"noopener\" class=\"internal-link\" data-src=\"%s\">%s</a>" $fullhref $href $display}}
{{$content = replace $content . $link}} {{$content = replace $content . $link}}
{{end}} {{end}}
<!-- Broken path -->
{{else}}
{{$link := printf "<a class=\"internal-link broken\">%s</a>" $display}}
{{$content = replace $content . $link}}
{{end}} {{end}}
{{end}} {{end}}
{{end}} {{end}}
@@ -86,6 +149,14 @@
{{end}} {{end}}
{{ $content = $content | replaceRE `\[![a-zA-Z]+\][-\+]?` "" }} {{ $content = $content | replaceRE `\[![a-zA-Z]+\][-\+]?` "" }}
{{ $content = $content | replaceRE "blockquote class=callout" "blockquote" }} {{ $content = $content | replaceRE "blockquote class=callout" "blockquote" }}
{{ $content = $content | replaceRE `(?s)(<blockquote class="\S+-callout">.*?)<br>(.*?<\/blockquote)` `${1}</p><p>${2}` }}
{{end}}
{{/* Make ==text== into <mark>text</mark> */}}
{{$mark := findRE "==([^=\n]+)==" $content}}
{{range $mark}}
{{$fixed := printf "<mark>%s</mark>" (replace . "==" "")}}
{{$content = replace $content . $fixed}}
{{end}} {{end}}
{{ $content | safeHTML }} {{ $content | safeHTML }}

View File

@@ -1,4 +1,5 @@
{{ if (and $.Site.Data.config.enableToc (ne .Params.enableToc false) (gt .WordCount 250)) }} {{ $hasHeaders := gt (len (findRE "<h\\d.*?>(.|\n)*?</h\\d>" .Content)) 0 }}
{{ if (or (and (not $.Site.Data.config.enableToc) .Params.enableToc) (and $.Site.Data.config.enableToc (ne .Params.enableToc false) $hasHeaders)) }}
<aside class="mainTOC"> <aside class="mainTOC">
<details {{ if $.Site.Data.config.openToc }}open {{ end }}> <details {{ if $.Site.Data.config.openToc }}open {{ end }}>
<summary>{{ i18n "toc" }}</summary> <summary>{{ i18n "toc" }}</summary>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 MiB

After

Width:  |  Height:  |  Size: 1012 KiB