Compare commits
67 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
66dd6bcf2d | ||
|
|
bb3877998a | ||
|
|
9450278680 | ||
|
|
7b1da7a845 | ||
|
|
e482fa1097 | ||
|
|
ba7a968881 | ||
|
|
db27557aa3 | ||
|
|
b7c305e002 | ||
|
|
74fe4d6813 | ||
|
|
d6c31595b3 | ||
|
|
aa5ab03d4a | ||
|
|
ecba6071b8 | ||
|
|
983efab94c | ||
|
|
10e41743e5 | ||
|
|
bde44fadf2 | ||
|
|
6885651f7b | ||
|
|
7df2bb6f5e | ||
|
|
11959de11c | ||
|
|
a73aca8ed9 | ||
|
|
93610e232b | ||
|
|
712dab5c8c | ||
|
|
77b3907b23 | ||
|
|
8fc63586c4 | ||
|
|
24c9777a52 | ||
|
|
7a8811a184 | ||
|
|
eb2f6aeca8 | ||
|
|
b78008532f | ||
|
|
c5b103c85f | ||
|
|
614a6222a1 | ||
|
|
dc43737896 | ||
|
|
ea37486309 | ||
|
|
c1b0eafce6 | ||
|
|
ce5df837f5 | ||
|
|
4cd6f7efdf | ||
|
|
5a7936e23a | ||
|
|
5fd707714f | ||
|
|
717a13a580 | ||
|
|
5f3d430699 | ||
|
|
66f3e249fe | ||
|
|
e374e3abd4 | ||
|
|
f08a76a738 | ||
|
|
d80f6946c8 | ||
|
|
120d104230 | ||
|
|
e9aa6ae9e7 | ||
|
|
c12af32a5a | ||
|
|
de2b6b9a1b | ||
|
|
7f9f58860d | ||
|
|
151b9851d6 | ||
|
|
d56a58044d | ||
|
|
689201bfbd | ||
|
|
9b72edcd9c | ||
|
|
8704edcca2 | ||
|
|
0a602eda1b | ||
|
|
72571a7588 | ||
|
|
3409a49f15 | ||
|
|
666ffebe90 | ||
|
|
8ea1525df4 | ||
|
|
dd11d56dd9 | ||
|
|
cd7e2088d5 | ||
|
|
169ef442b9 | ||
|
|
8e3042df49 | ||
|
|
2145e92b00 | ||
|
|
e6c7a4e1e2 | ||
|
|
ca84da5b31 | ||
|
|
0d1670adba | ||
|
|
5c770f965a | ||
|
|
ce55eca73b |
6
.github/workflows/deploy.yaml
vendored
@@ -7,14 +7,14 @@ on:
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
runs-on: ubuntu-18.04
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
with:
|
||||
fetch-depth: 0 # Fetch all history for .GitInfo and .Lastmod
|
||||
|
||||
- name: Build Link Index
|
||||
uses: jackyzha0/hugo-obsidian@v2.18
|
||||
uses: jackyzha0/hugo-obsidian@v2.20
|
||||
with:
|
||||
index: true
|
||||
input: content
|
||||
@@ -36,4 +36,4 @@ jobs:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./public
|
||||
publish_branch: master # deploying branch
|
||||
cname: quartz.jzhao.xyz
|
||||
cname: three.quartz.jzhao.xyz
|
||||
|
||||
42
.github/workflows/docker-publish.yaml
vendored
Normal 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
@@ -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"]
|
||||
6
Makefile
@@ -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
|
||||
|
||||
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
|
||||
|
||||
12
README.md
@@ -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
|
||||
|
||||
1. Extremely fast full-text search by pressing `Ctrl` + `k`
|
||||
1. Extremely fast natural-language search
|
||||
2. Customizable and hackable design based on Hugo
|
||||
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
|
||||
|
||||
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
|
||||
|
||||
🔗 Get Started: https://quartz.jzhao.xyz/
|
||||
🔗 Get Started: https://three.quartz.jzhao.xyz/
|
||||
|
||||
*Quartz Example Screenshot*
|
||||
|
||||
|
||||
@@ -8,6 +8,7 @@ const addCopyButtons = () => {
|
||||
let els = document.getElementsByClassName("highlight");
|
||||
// for each highlight
|
||||
for (let i = 0; i < els.length; i++) {
|
||||
try {
|
||||
if (els[i].getElementsByClassName("clipboard-button").length) continue;
|
||||
|
||||
// find pre > code inside els[i]
|
||||
@@ -19,6 +20,7 @@ const addCopyButtons = () => {
|
||||
button.className = "clipboard-button";
|
||||
button.type = "button";
|
||||
button.innerHTML = svgCopy;
|
||||
button.ariaLabel = "opy the shown code";
|
||||
// remove every second newline from lastCodeBlock.innerText
|
||||
button.addEventListener("click", () => {
|
||||
navigator.clipboard.writeText(lastCodeBlock.innerText.replace(/\n\n/g, "\n")).then(
|
||||
@@ -36,5 +38,8 @@ const addCopyButtons = () => {
|
||||
// find chroma inside els[i]
|
||||
let chroma = els[i].getElementsByClassName("chroma")[0];
|
||||
els[i].insertBefore(button, chroma);
|
||||
} catch(error) {
|
||||
console.debug(error);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
|
||||
function addTitleToCodeBlocks() {
|
||||
var els = document.getElementsByClassName("highlight");
|
||||
for (var i = 0; i < els.length; i++) {
|
||||
const els = document.getElementsByClassName("highlight");
|
||||
for (let i = 0; i < els.length; i++) {
|
||||
try {
|
||||
if (els[i].title.length) {
|
||||
let div = document.createElement("div");
|
||||
if (els[i].getElementsByClassName("code-title").length) continue;
|
||||
div.textContent=els[i].title;
|
||||
div.textContent = els[i].title;
|
||||
div.classList.add("code-title")
|
||||
els[i].insertBefore(div, els[i].firstChild);
|
||||
}
|
||||
} catch (error) {
|
||||
console.debug(error);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,7 +35,7 @@
|
||||
})
|
||||
|
||||
registerHandlers((e) => {
|
||||
term = e.target.value
|
||||
const term = e.target.value
|
||||
const searchResults = contentIndex.search(term, [
|
||||
{
|
||||
field: "content",
|
||||
@@ -56,6 +56,6 @@
|
||||
}
|
||||
const allIds = new Set([...getByField("title"), ...getByField("content")])
|
||||
const finalResults = [...allIds].map(formatForDisplay)
|
||||
displayResults(finalResults, true)
|
||||
displayResults(term, finalResults, true)
|
||||
})
|
||||
})()
|
||||
|
||||
@@ -8,7 +8,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
|
||||
opacityScale,
|
||||
scale,
|
||||
repelForce,
|
||||
fontSize} = graphConfig;
|
||||
fontSize } = graphConfig;
|
||||
|
||||
const container = document.getElementById("graph-container")
|
||||
const { index, links, content } = await fetchData
|
||||
@@ -85,7 +85,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
|
||||
d.fy = null
|
||||
}
|
||||
|
||||
const noop = () => {}
|
||||
const noop = () => { }
|
||||
return d3
|
||||
.drag()
|
||||
.on("start", enableDrag ? dragstarted : noop)
|
||||
@@ -113,7 +113,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
|
||||
.append("svg")
|
||||
.attr("width", width)
|
||||
.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) {
|
||||
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")
|
||||
.on("click", (_, d) => {
|
||||
// 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)")
|
||||
|
||||
const neighbours = parseIdsFromLinks([
|
||||
@@ -190,7 +199,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
|
||||
// highlight links
|
||||
linkNodes.transition().duration(200).attr("stroke", "var(--g-link-active)")
|
||||
|
||||
const bigFont = fontSize*1.5
|
||||
const bigFont = fontSize * 1.5
|
||||
|
||||
// show text for self
|
||||
d3.select(this.parentNode)
|
||||
@@ -200,10 +209,10 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
|
||||
.duration(200)
|
||||
.attr('opacityOld', d3.select(this.parentNode).select('text').style("opacity"))
|
||||
.style('opacity', 1)
|
||||
.style('font-size', bigFont+'em')
|
||||
.style('font-size', bigFont + 'em')
|
||||
.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)
|
||||
|
||||
const currentId = d.id
|
||||
@@ -218,7 +227,7 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
|
||||
.transition()
|
||||
.duration(200)
|
||||
.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
|
||||
})
|
||||
.call(drag(simulation))
|
||||
@@ -229,10 +238,10 @@ async function drawGraph(baseUrl, isHome, pathColors, graphConfig) {
|
||||
.attr("dx", 0)
|
||||
.attr("dy", (d) => nodeRadius(d) + 8 + "px")
|
||||
.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("pointer-events", "none")
|
||||
.style('font-size', fontSize+'em')
|
||||
.style('font-size', fontSize + 'em')
|
||||
.raise()
|
||||
.call(drag(simulation))
|
||||
|
||||
|
||||
@@ -5,14 +5,14 @@ function htmlToElement(html) {
|
||||
return template.content.firstChild
|
||||
}
|
||||
|
||||
function initPopover(baseURL, useContextualBacklinks, renderLatex) {
|
||||
function initPopover(baseURL, useContextualBacklinks) {
|
||||
const basePath = baseURL.replace(window.location.origin, "")
|
||||
fetchData.then(({ content }) => {
|
||||
const links = [...document.getElementsByClassName("internal-link")]
|
||||
links
|
||||
.filter(li => li.dataset.src || (li.dataset.idx && useContextualBacklinks))
|
||||
.forEach(li => {
|
||||
var el
|
||||
let el
|
||||
if (li.dataset.ctx) {
|
||||
const linkDest = content[li.dataset.src]
|
||||
const popoverElement = `<div class="popover">
|
||||
@@ -27,7 +27,7 @@ function initPopover(baseURL, useContextualBacklinks, renderLatex) {
|
||||
let splitLink = li.href.split("#")
|
||||
let cleanedContent = removeMarkdown(linkDest.content)
|
||||
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>")
|
||||
cleanedContent = cleanedContent.substring(headingIndex, cleanedContent.length)
|
||||
}
|
||||
@@ -42,13 +42,11 @@ function initPopover(baseURL, useContextualBacklinks, renderLatex) {
|
||||
|
||||
if (el) {
|
||||
li.appendChild(el)
|
||||
if (renderLatex) {
|
||||
if (LATEX_ENABLED) {
|
||||
renderMathInElement(el, {
|
||||
delimiters: [
|
||||
{ left: '$$', right: '$$', display: false },
|
||||
{ left: '$', right: '$', display: false },
|
||||
{ left: '\\(', right: '\\)', display: false },
|
||||
{ left: '\\[', right: '\\]', display: false }
|
||||
],
|
||||
throwOnError: false
|
||||
})
|
||||
@@ -66,6 +64,11 @@ function initPopover(baseURL, useContextualBacklinks, renderLatex) {
|
||||
})
|
||||
|
||||
el.classList.add("visible")
|
||||
plausible("Popover Hover", {
|
||||
props: {
|
||||
href: li.dataset.src
|
||||
}
|
||||
})
|
||||
})
|
||||
li.addEventListener("mouseout", () => {
|
||||
el.classList.remove("visible")
|
||||
|
||||
@@ -15,7 +15,6 @@ export const attachSPARouting = (init, rerender) => {
|
||||
}
|
||||
|
||||
const render = () => requestAnimationFrame(rerender)
|
||||
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
apply((doc) => init(doc))
|
||||
init()
|
||||
|
||||
@@ -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) {
|
||||
const response = await fetch('https://prod.operand.ai/v3/search/objects', {
|
||||
method: 'POST',
|
||||
const result = await fetch("https://api.operand.ai/operand.v1.ObjectService/SearchWithin", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
Authorization: apiKey,
|
||||
"Content-Type": "application/json",
|
||||
Authorization: `${apiKey}`,
|
||||
"Operand-Index-ID": `${indexId}`,
|
||||
},
|
||||
body: JSON.stringify({
|
||||
query,
|
||||
max: 10
|
||||
query: query,
|
||||
limit: 10,
|
||||
}),
|
||||
});
|
||||
return (await response.json());
|
||||
})
|
||||
if (result.ok) {
|
||||
return parseSearchResults(await result.json())
|
||||
} else {
|
||||
console.error(result)
|
||||
}
|
||||
}
|
||||
|
||||
function debounce(func, timeout = 200) {
|
||||
let timer;
|
||||
let timer
|
||||
return (...args) => {
|
||||
clearTimeout(timer)
|
||||
timer = setTimeout(() => { func.apply(this, args); }, timeout)
|
||||
};
|
||||
timer = setTimeout(() => {
|
||||
func.apply(this, args)
|
||||
}, timeout)
|
||||
}
|
||||
}
|
||||
|
||||
registerHandlers(debounce((e) => {
|
||||
term = e.target.value
|
||||
registerHandlers(
|
||||
debounce((e) => {
|
||||
let term = e.target.value
|
||||
if (term !== "") {
|
||||
searchContents(term)
|
||||
.then((res) => res.results.map(entry => ({
|
||||
url: entry.object.properties.url,
|
||||
content: entry.snippet,
|
||||
title: entry.object.metadata.title
|
||||
})
|
||||
))
|
||||
.then(results => displayResults(results))
|
||||
searchContents(term).then((results) => displayResults(term, results))
|
||||
}
|
||||
}))
|
||||
}),
|
||||
)
|
||||
|
||||
@@ -40,8 +40,8 @@ const removeMarkdown = (
|
||||
.replace(/^\s{0,3}>\s?/g, "")
|
||||
.replace(/(^|\n)\s{0,3}>\s?/g, "\n\n")
|
||||
.replace(/^\s{1,2}\[(.*?)\]: (\S+)( ".*?")?\s*$/g, "")
|
||||
.replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, "$2")
|
||||
.replace(/([\*_]{1,3})(\S.*?\S{0,1})\1/g, "$2")
|
||||
.replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2")
|
||||
.replace(/([\*_]{1,3})(\S.*?\S?)\1/g, "$2")
|
||||
.replace(/(`{3,})(.*?)\1/gm, "$2")
|
||||
.replace(/`(.+?)`/g, "$1")
|
||||
.replace(/\n{2,}/g, "\n\n")
|
||||
@@ -65,7 +65,7 @@ const highlight = (content, term) => {
|
||||
.split(" ")
|
||||
.slice(0, h)
|
||||
return (
|
||||
(before.length == h ? `...${before.join(" ")}` : before.join(" ")) +
|
||||
(before.length === h ? `...${before.join(" ")}` : before.join(" ")) +
|
||||
`<span class="search-highlight">${term}</span>` +
|
||||
after.join(" ")
|
||||
)
|
||||
@@ -115,12 +115,19 @@ const resultToHTML = ({ url, title, content }) => {
|
||||
}
|
||||
|
||||
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(
|
||||
new URL(`${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/`),
|
||||
new URL(urlString),
|
||||
".singlePage",
|
||||
)
|
||||
closeSearch()
|
||||
plausible("Search", {
|
||||
props: {
|
||||
term
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
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")
|
||||
if (finalResults.length === 0) {
|
||||
results.innerHTML = `<button class="result-card">
|
||||
@@ -201,6 +208,16 @@ const displayResults = (finalResults, extractHighlight = false) => {
|
||||
}
|
||||
)
|
||||
.join("\n")
|
||||
if (LATEX_ENABLED) {
|
||||
renderMathInElement(results, {
|
||||
delimiters: [
|
||||
{ left: '$$', right: '$$', display: false },
|
||||
{ left: '$', right: '$', display: false },
|
||||
],
|
||||
throwOnError: false
|
||||
})
|
||||
}
|
||||
|
||||
const anchors = [...document.getElementsByClassName("result-card")]
|
||||
anchors.forEach((anchor) => {
|
||||
anchor.onclick = () => redir(anchor.id, term)
|
||||
|
||||
@@ -114,6 +114,10 @@ blockquote[class*="-callout"] > p:first-child {
|
||||
}
|
||||
}
|
||||
|
||||
blockquote[class*="-callout"] > p:empty {
|
||||
padding: 1.2em 35px;
|
||||
}
|
||||
|
||||
$summary: summary, abstract, tldr;
|
||||
$bug: bug;
|
||||
$danger: danger, error;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
// 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');
|
||||
:root {
|
||||
--font-body: "Source Sans Pro";
|
||||
--font-header: "Inter";
|
||||
--font-mono: "Fira Code"
|
||||
--font-body: "Source Sans Pro", sans-serif;
|
||||
--font-header: "Inter", sans-serif;
|
||||
--font-mono: "Fira Code", monospace;
|
||||
}
|
||||
|
||||
// typography
|
||||
@@ -22,6 +22,8 @@ html {
|
||||
|
||||
.singlePage {
|
||||
padding: 4em 30vw;
|
||||
margin: 0 auto;
|
||||
max-width: 1000px;
|
||||
@media all and (max-width: 1200px) {
|
||||
padding: 25px 5vw;
|
||||
}
|
||||
@@ -89,7 +91,7 @@ tbody, li, p {
|
||||
|
||||
#TableOfContents > ol {
|
||||
counter-reset: section;
|
||||
margin-left: 0em;
|
||||
margin-left: 0;
|
||||
padding-left: 1.5em;
|
||||
& > li {
|
||||
counter-increment: section;
|
||||
@@ -142,7 +144,7 @@ sup {
|
||||
}
|
||||
|
||||
blockquote {
|
||||
margin-left: 0em;
|
||||
margin-left: 0;
|
||||
border-left: 3px solid var(--secondary);
|
||||
padding-left: 1em;
|
||||
transition: border-color 0.2s ease;
|
||||
@@ -299,13 +301,11 @@ footer {
|
||||
}
|
||||
|
||||
hr {
|
||||
width: 25%;
|
||||
margin: 4em auto;
|
||||
height: 2px;
|
||||
border-radius: 1px;
|
||||
border-width: 0;
|
||||
color: var(--dark);
|
||||
background-color: var(--dark);
|
||||
width: 100%;
|
||||
margin: 2em auto;
|
||||
height: 1px;
|
||||
border: none;
|
||||
background-color: var(--outlinegray);
|
||||
}
|
||||
|
||||
.page-end {
|
||||
@@ -532,7 +532,7 @@ header {
|
||||
& h3 {
|
||||
opacity: 1;
|
||||
font-weight: 700;
|
||||
margin: 0em;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
& .meta {
|
||||
@@ -570,7 +570,7 @@ header {
|
||||
transition: opacity 0.2s ease, transform 0.2s ease;
|
||||
user-select: none;
|
||||
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) {
|
||||
display: none !important;
|
||||
@@ -588,7 +588,7 @@ header {
|
||||
margin: 0.25rem 0;
|
||||
}
|
||||
|
||||
& > .meta {
|
||||
& .meta {
|
||||
margin-top: 0.25rem;
|
||||
opacity: 0.5;
|
||||
font-family: var(--font-mono);
|
||||
@@ -619,3 +619,7 @@ header {
|
||||
}
|
||||
}
|
||||
|
||||
mark {
|
||||
background-color: var(--highlighted);
|
||||
color: var(--gray);
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
--lightgray: #f0f0f0;
|
||||
--outlinegray: #dadada;
|
||||
--million-progress-bar-color: var(--secondary);
|
||||
--highlighted: #f5dfaf88;
|
||||
}
|
||||
|
||||
[saved-theme="dark"] {
|
||||
@@ -23,6 +24,7 @@
|
||||
--gray: #d4d4d4 !important;
|
||||
--lightgray: #292633 !important;
|
||||
--outlinegray: #343434 !important;
|
||||
--highlighted: #574010;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -60,3 +60,7 @@
|
||||
pre.chroma {
|
||||
-moz-tab-size:4;-o-tab-size:4;tab-size:4;
|
||||
}
|
||||
|
||||
.katex {
|
||||
font-size: 1.1em !important;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
baseURL = "https://quartz.jzhao.xyz/"
|
||||
baseURL = "https://three.quartz.jzhao.xyz/"
|
||||
languageCode = "en-us"
|
||||
googleAnalytics = "G-XYFD95KB4J"
|
||||
relativeURLs = false
|
||||
disablePathToLower = true
|
||||
ignoreFiles = [
|
||||
|
||||
@@ -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
|
||||
|
||||
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/)
|
||||
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]]
|
||||
|
||||
@@ -17,7 +17,7 @@ $$f(x) = \int_{-\infty}^\infty
|
||||
f\hat(\xi),e^{2 \pi i \xi x}
|
||||
\,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:
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ This includes
|
||||
- 12 Distinct callout types (each with several aliases)
|
||||
- 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
|
||||
|
||||
|
||||
@@ -57,11 +57,16 @@ enableRecentNotes: false
|
||||
enableGitHubEdit: true
|
||||
GitHubLink: https://github.com/jackyzha0/quartz/tree/hugo/content
|
||||
|
||||
# whether to render mermaid diagrams
|
||||
enableMermaid: true
|
||||
|
||||
# whether to use Operand to power semantic search
|
||||
# IMPORTANT: replace this API key with your own if you plan on using
|
||||
# Operand search!
|
||||
enableSemanticSearch: false
|
||||
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY"
|
||||
search:
|
||||
enableSemanticSearch: false
|
||||
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY"
|
||||
operandIndexId: "REPLACE-WITH-YOUR-OPERAND-INDEX-ID"
|
||||
|
||||
# page description used for SEO
|
||||
description:
|
||||
@@ -70,7 +75,7 @@ description:
|
||||
|
||||
# title of the home page (also for SEO)
|
||||
page_title:
|
||||
"🪴 Quartz 3.2"
|
||||
"🪴 Quartz 3.3"
|
||||
|
||||
# links to show in the footer
|
||||
links:
|
||||
|
||||
57
content/notes/docker.md
Normal 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!
|
||||
@@ -15,24 +15,10 @@ Here's a rough overview of what's what.
|
||||
|
||||
**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)
|
||||

|
||||
```
|
||||
|
||||
You can also use wikilinks if that is what you are more comfortable with!
|
||||
|
||||
### 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
|
||||
---
|
||||
|
||||
@@ -10,10 +10,13 @@ aliases:
|
||||
## 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.
|
||||
|
||||
### Enable GitHub Actions
|
||||
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!
|
||||
### Enable GitHub Actions Permissions
|
||||
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*
|
||||
Head to `Settings > Action > General > Workflow Permissions` and choose `Read and Write Permissions`
|
||||
|
||||
![[notes/images/github-actions.png]]
|
||||
*Enable GitHub Actions*
|
||||
|
||||
### 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)
|
||||
|
||||
## 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*!
|
||||
|
||||
BIN
content/notes/images/fork.png
Normal file
|
After Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 116 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 44 KiB |
@@ -17,15 +17,20 @@ The easiest way to use an existing Vault is to copy all of your files (directory
|
||||
## Settings
|
||||
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.
|
||||
2. Go to Settings > Files & Links > Turn "on" automatically update internal links.
|
||||
Open Settings > Files & Links and look for these two items:
|
||||
|
||||
*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
|
||||
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!
|
||||
|
||||
|
||||
@@ -5,9 +5,9 @@ tags:
|
||||
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`
|
||||
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
|
||||
```
|
||||
|
||||
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.
|
||||
|
||||
Afterwards, start the Hugo server as shown above and your local backlinks and interactive graph should be populated!
|
||||
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.
|
||||
|
||||
## 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,
|
||||
@@ -34,4 +32,10 @@ make serve
|
||||
# View your site in a browser at http://localhost:1313/
|
||||
```
|
||||
|
||||
> [!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)
|
||||
@@ -13,38 +13,25 @@ enableSemanticSearch: false
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
Here's how to set it up.
|
||||
|
||||
1. Create an Operand Account on [their website](https://operand.ai/).
|
||||
2. Go to Dashboard > Settings > Integrations.
|
||||
3. Follow the steps to setup the GitHub integration. Operand needs access to GitHub in order to index your digital garden properly!
|
||||
4. Head over to Dashboard > Objects and press `(Cmd + K)` to open the omnibar and select 'Create Collection'.
|
||||
1. Set the 'Collection Label' to something that will help you remember it.
|
||||
2. You can leave the 'Parent Collection' field empty.
|
||||
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.
|
||||
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. 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. Click into the index you've created. Under "Index Something", select "SITEMAP" from the dropdown and click "Add Source".
|
||||
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.
|
||||
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.
|
||||
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..
|
||||
|
||||
```yaml {title="data/config.yaml"}
|
||||
# the default option
|
||||
enableSemanticSearch: true
|
||||
operandApiKey: "0e733a7f-9b9c-48c6-9691-b54fa1c8b910"
|
||||
search:
|
||||
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.
|
||||
1. This step is *required* for Operand to be able to properly index your content.
|
||||
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.
|
||||
7. Push your changes to the site and wait for it to deploy.
|
||||
8. Check the Operand dashboard and wait for your site to index. Enjoy natural language search powered by Operand!
|
||||
|
||||
@@ -15,10 +15,14 @@ Navigate to the GitHub repository for the Quartz project:
|
||||
|
||||
📁 [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
|
||||
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
|
||||
git clone https://github.com/YOUR-USERNAME/quartz
|
||||
|
||||
@@ -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/)
|
||||
- [AWAGMI Intern Notes](https://notes.awagmi.xyz/)
|
||||
- [Shihyu's PKM](https://shihyuho.github.io/pkm/)
|
||||
- [Chloe's Garden](https://garden.chloeabrasada.online/)
|
||||
- [SlRvb's Site](https://slrvb.github.io/Site/)
|
||||
- [Course notes for Information Technology Advanced Theory](https://a2itnotes.github.io/quartz/)
|
||||
- [Brandon Boswell's Garden](https://brandonkboswell.com)
|
||||
- [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)!
|
||||
|
||||
@@ -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.
|
||||
|
||||
```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 PATH=$GOPATH/bin:$PATH
|
||||
|
||||
# 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?
|
||||
@@ -52,8 +52,13 @@ You probably forgot to include front matter in your Markdown files. You can eith
|
||||
### 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.
|
||||
|
||||
### How do I setup Google Analytics?
|
||||
You can edit it in `config.toml` and either use a V3 (UA-) or V4 (G-) tag.
|
||||
### How do I setup analytics?
|
||||
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?
|
||||
To edit the main home page, open `/content/_index.md`.
|
||||
|
||||
@@ -11,16 +11,19 @@ enableFooter: true
|
||||
enableContextualBacklinks: true
|
||||
enableRecentNotes: false
|
||||
enableGitHubEdit: true
|
||||
enableMermaid: true
|
||||
GitHubLink: https://github.com/jackyzha0/quartz/tree/hugo/content
|
||||
enableSemanticSearch: false
|
||||
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY"
|
||||
search:
|
||||
enableSemanticSearch: false
|
||||
operandApiKey: "REPLACE-WITH-YOUR-OPERAND-API-KEY"
|
||||
operandIndexId: "REPLACE-WITH-YOUR-OPERAND-INDEX-ID"
|
||||
description:
|
||||
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.
|
||||
page_title:
|
||||
"🪴 Quartz 3.2"
|
||||
"🪴 Quartz 3.3"
|
||||
links:
|
||||
- link_name: Twitter
|
||||
link: https://twitter.com/_jzhao
|
||||
- link_name: Github
|
||||
- link_name: GitHub
|
||||
link: https://github.com/jackyzha0
|
||||
|
||||
65
i18n/bn.toml
Normal 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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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 }}"
|
||||
4
layouts/_default/_markup/render-codeblock-mermaid.html
Normal file
@@ -0,0 +1,4 @@
|
||||
<div class="mermaid">
|
||||
{{- .Inner | safeHTML }}
|
||||
</div>
|
||||
{{ .Page.Store.Set "hasMermaid" true }}
|
||||
@@ -1,9 +1,9 @@
|
||||
{{$trimmed := strings.TrimSuffix ".md" (.Destination | safeURL)}}
|
||||
{{$dashedurl := replace $trimmed "%20" "-" }}
|
||||
{{$dashedurl := replace .Destination "%20" "-" }}
|
||||
{{$external := strings.HasPrefix $dashedurl "http" }}
|
||||
{{- if $external -}}
|
||||
<a href="{{ $dashedurl }}" rel="noopener">{{ .Text | safeHTML }}</a>
|
||||
{{- else -}}
|
||||
{{$trimmed := strings.TrimSuffix ".md" (.Destination | safeURL)}}
|
||||
{{$spacedurl := replace $trimmed "%20" " " }}
|
||||
{{$fixedUrl := (cond (hasPrefix $spacedurl "/") $spacedurl (print "/" $spacedurl)) | urlize}}
|
||||
{{$nonexistent := eq (.Page.GetPage $spacedurl).RelPermalink ""}}
|
||||
|
||||
@@ -15,7 +15,14 @@
|
||||
</p>
|
||||
<ul class="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 }}
|
||||
</ul>
|
||||
{{partial "toc.html" .}}
|
||||
|
||||
@@ -8,6 +8,24 @@
|
||||
name="description"
|
||||
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>
|
||||
{{ if .Title }}{{ .Title }}{{ else }}{{ $data.page_title | default $.Site.Data.config.page_title }}{{
|
||||
end }}
|
||||
@@ -51,26 +69,28 @@
|
||||
{{end}}
|
||||
{{partial "katex.html" .}}
|
||||
|
||||
<script src="https://unpkg.com/@floating-ui/core@0.7.3"></script>
|
||||
<script src="https://unpkg.com/@floating-ui/dom@0.5.4"></script>
|
||||
{{partial "mermaid.html" .}}
|
||||
|
||||
<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" |
|
||||
resources.Minify }}
|
||||
<script src="{{$popover.Permalink}}"></script>
|
||||
<script defer src="{{$popover.Permalink}}"></script>
|
||||
|
||||
<!-- Optional scripts -->
|
||||
{{ if $data.enableCodeBlockTitle | default $.Site.Data.config.enableCallouts }}
|
||||
{{ $codeTitle := resources.Get "js/code-title.js" | resources.Fingerprint "md5" | resources.Minify }}
|
||||
<script src="{{$codeTitle.Permalink}}"></script>
|
||||
<script defer src="{{$codeTitle.Permalink}}"></script>
|
||||
{{end}}
|
||||
|
||||
{{ if $data.enableCodeBlockCopy | default $.Site.Data.config.enableCodeBlockCopy }}
|
||||
{{ $clipboard := resources.Get "js/clipboard.js" | resources.Fingerprint "md5" | resources.Minify }}
|
||||
<script src="{{$clipboard.Permalink}}"></script>
|
||||
<script defer src="{{$clipboard.Permalink}}"></script>
|
||||
{{ end }}
|
||||
|
||||
{{ if $data.enableCallouts | default $.Site.Data.config.enableCallouts }}
|
||||
{{ $callouts := resources.Get "js/callouts.js" | resources.Fingerprint "md5" | resources.Minify }}
|
||||
<script src="{{$callouts.Permalink}}"></script>
|
||||
<script defer src="{{$callouts.Permalink}}"></script>
|
||||
{{ end }}
|
||||
|
||||
<!-- Preload page vars -->
|
||||
@@ -79,6 +99,9 @@
|
||||
"indices/contentIndex.json" | resources.Fingerprint "md5" | resources.Minify
|
||||
}}
|
||||
<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 fetchData = Promise.all([
|
||||
fetch("{{ $linkIndex.Permalink }}")
|
||||
@@ -119,8 +142,7 @@
|
||||
{{if $data.enableLinkPreview | default $.Site.Data.config.enableLinkPreview}}
|
||||
initPopover(
|
||||
{{strings.TrimRight "/" .Site.BaseURL }},
|
||||
{{$data.enableContextualBacklinks | default $.Site.Data.config.enableContextualBacklinks}},
|
||||
{{$data.enableLatex | default $.Site.Data.config.enableLatex}}
|
||||
{{$data.enableContextualBacklinks | default $.Site.Data.config.enableContextualBacklinks}}
|
||||
)
|
||||
{{end}}
|
||||
|
||||
@@ -143,6 +165,42 @@
|
||||
|
||||
}
|
||||
{{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) => {
|
||||
@@ -160,6 +218,9 @@
|
||||
{left: '$$', right: '$$', display: true},
|
||||
{left: '$', right: '$', display: false},
|
||||
],
|
||||
macros: {
|
||||
'’': "'"
|
||||
},
|
||||
throwOnError : false
|
||||
});
|
||||
{{end}}
|
||||
@@ -185,5 +246,7 @@
|
||||
})
|
||||
</script>
|
||||
{{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>
|
||||
{{ template "_internal/google_analytics.html" . }}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<header>
|
||||
{{ $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 id="search-icon">
|
||||
<p>{{ i18n "search" }}</p>
|
||||
|
||||
@@ -1,5 +1,14 @@
|
||||
{{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">
|
||||
<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>
|
||||
<link rel="preload" href="https://cdn.jsdelivr.net/npm/katex@0.15.1/dist/katex.min.css" as="style"
|
||||
onload="this.onload=null;this.rel='stylesheet'"
|
||||
integrity="sha384-R4558gYOUz8mP9YWpZJjofhk+zx0AS11p36HnD2ZKj/6JR5z27gSSULCNHIRReVs" crossorigin="anonymous">
|
||||
<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}}
|
||||
8
layouts/partials/mermaid.html
Normal 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 }}
|
||||
@@ -6,7 +6,7 @@
|
||||
is a collection of pages.
|
||||
https://gohugo.io/content-management/related/
|
||||
-->
|
||||
{{$notes := .Site.RegularPages}}
|
||||
{{$notes := .Site.RegularPages.ByLastmod.Reverse}}
|
||||
{{partial "page-list.html" (first 3 $notes)}}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -6,9 +6,9 @@
|
||||
</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 }}
|
||||
<script defer src="{{ $js.Permalink }}"></script>
|
||||
<script defer type="module" src="{{ $js.Permalink }}"></script>
|
||||
{{else}}
|
||||
<script src="https://cdn.jsdelivr.net/npm/flexsearch@0.7.21/dist/flexsearch.bundle.js"
|
||||
integrity="sha256-i3A0NZGkhsKjVMzFxv3ksk0DZh3aXqu0l49Bbh0MdjE=" crossorigin="anonymous" defer></script>
|
||||
|
||||
@@ -3,9 +3,9 @@
|
||||
{{ $page := .Page }}
|
||||
|
||||
{{/* Escape slashes for Latex to fix line breaks */}}
|
||||
{{$latex := findRE "\\$\\$([^\\$]+)\\$\\$" $content}}
|
||||
{{$latex := findRE "(?:\\${2}([^\\$]+)\\${2})|(?:\\$([^\\$]*)\\$)" $content}}
|
||||
{{range $latex}}
|
||||
{{$fixed := replaceRE "\\\\(?: +|\\n)" "\\\\" .}}
|
||||
{{$fixed := replaceRE "\\\\(?: +|\\n)" "\\\\ " .}}
|
||||
{{$content = replace $content . $fixed}}
|
||||
{{end}}
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
{{$codefences := $raw | findRE "\\x60[^\\x60\\n]+\\x60"}}
|
||||
{{$codeblocks := $raw | findRE "\\x60{3}[^\\x60]+\\x60{3}"}}
|
||||
{{$code := union $codefences $codeblocks}}
|
||||
|
||||
{{range $wikilinks}}
|
||||
{{$cur := .}}
|
||||
{{$incode := false}}
|
||||
@@ -22,33 +23,95 @@
|
||||
{{$incode = true}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{if not $incode}}
|
||||
{{if (hasPrefix . "!")}}
|
||||
{{$inner := . | strings.TrimPrefix "![[" | strings.TrimSuffix "]]" }}
|
||||
{{$split := split $inner "|"}}
|
||||
{{$path := index $split 0 | relURL}}
|
||||
{{$width := index $split 1}}
|
||||
{{$img := printf "<img src=\"%s\" width=\"%s\" />" $path (default "auto" $width)}}
|
||||
{{$content = replace $content . $img}}
|
||||
{{else}}
|
||||
{{$inner := . | strings.TrimPrefix "[[" | strings.TrimSuffix "]]" }}
|
||||
|
||||
<!-- remove link delimiters -->
|
||||
{{$inner := . | strings.TrimPrefix "!" | strings.TrimPrefix "[[" | strings.TrimSuffix "]]" }}
|
||||
<!-- split from alias -->
|
||||
{{$split := split $inner "|"}}
|
||||
<!-- separate link path -->
|
||||
{{$path := index $split 0}}
|
||||
|
||||
{{$reference := split $path "#"}}
|
||||
<!-- path with heading link removed -->
|
||||
{{$title := index $reference 0}}
|
||||
<!-- $display is hyperlink display text -->
|
||||
<!-- 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 "&" "&") }}
|
||||
{{$searchtitle = (replace $searchtitle """ "\"") }}
|
||||
{{$searchtitle = (replace $searchtitle "”" "\"") }}
|
||||
{{$searchtitle = (replace $searchtitle "“" "\"") }}
|
||||
{{$searchtitle = (replace $searchtitle "’" "'") }}
|
||||
{{$searchtitle = (replace $searchtitle "‘" "'") }}
|
||||
{{$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 = strings.TrimRight "/" (cond (eq $block "") $block (printf "#%s" $block)) | urlize | lower}}
|
||||
{{$href := strings.TrimRight "/" ($page.GetPage $title).RelPermalink}}
|
||||
{{$display := default $title (index $split 1)}}
|
||||
{{if not $href}}
|
||||
{{$href := strings.TrimRight "/" $curpage.RelPermalink}}
|
||||
{{$link := printf "<a href=\"%s%s\" rel=\"noopener\" class=\"internal-link\" data-src=\"%s\">%s</a>" $href $block $href $display}}
|
||||
{{$content = replace $content . $link}}
|
||||
<!-- If path to existing file -->
|
||||
{{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}}
|
||||
{{$link := printf "<a href=\"%s\" rel=\"noopener\" class=\"internal-link\">%s</a>" $href $display}}
|
||||
{{$content = replace $content . $link}}
|
||||
{{end}}
|
||||
<!-- Broken path -->
|
||||
{{else}}
|
||||
{{$link := printf "<a class=\"internal-link broken\">%s</a>" $display}}
|
||||
{{$content = replace $content . $link}}
|
||||
{{else}}
|
||||
{{$fullhref := printf "%s%s" $href $block }}
|
||||
{{$link := printf "<a href=\"%s\" rel=\"noopener\" class=\"internal-link\" data-src=\"%s\">%s</a>" $fullhref $href $display}}
|
||||
{{$content = replace $content . $link}}
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
{{end}}
|
||||
{{end}}
|
||||
|
||||
@@ -86,6 +149,14 @@
|
||||
{{end}}
|
||||
{{ $content = $content | replaceRE `\[![a-zA-Z]+\][-\+]?` "" }}
|
||||
{{ $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}}
|
||||
|
||||
{{ $content | safeHTML }}
|
||||
|
||||
@@ -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">
|
||||
<details {{ if $.Site.Data.config.openToc }}open {{ end }}>
|
||||
<summary>{{ i18n "toc" }}</summary>
|
||||
|
||||
BIN
screenshot.png
|
Before Width: | Height: | Size: 1.1 MiB After Width: | Height: | Size: 1012 KiB |