From 20bc87cd0debd893fec5842bf92ee0e7dfd09a3c Mon Sep 17 00:00:00 2001 From: Jet Hughes Date: Fri, 10 Jun 2022 18:28:33 +1200 Subject: [PATCH] Update --- .github/workflows/deploy.yaml | 76 +++++----- assets/js/graph.js | 221 ++++++++++++++---------------- assets/js/router.js | 34 +++-- assets/js/search.js | 173 +++++++++++------------ assets/styles/base.scss | 60 ++++---- config.toml | 63 +++++---- data/config.yaml | 26 ++-- data/graphConfig.yaml | 42 +++++- layouts/index.html | 5 +- layouts/partials/footer.html | 5 + layouts/partials/footerIndex.html | 24 ++++ layouts/partials/head.html | 67 +++++---- layouts/partials/page-list.html | 6 + layouts/partials/recent.html | 12 ++ 14 files changed, 459 insertions(+), 355 deletions(-) create mode 100644 layouts/partials/footerIndex.html create mode 100644 layouts/partials/recent.html diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index daebdef14..8334ea2ee 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -1,37 +1,39 @@ -name: Deploy to GitHub Pages - -on: - push: - branches: - - hugo - -jobs: - deploy: - runs-on: ubuntu-18.04 - steps: - - uses: actions/checkout@v2 - - - name: Build Link Index - uses: jackyzha0/hugo-obsidian@v2.12 - with: - index: true - input: content - output: assets/indices - root: . - - - name: Setup Hugo - uses: peaceiris/actions-hugo@v2 - with: - hugo-version: '0.96.0' - extended: true - - - name: Build - run: hugo --minify - - - name: Deploy - uses: peaceiris/actions-gh-pages@v3 - with: - github_token: ${{ secrets.GITHUB_TOKEN }} - publish_dir: ./public - publish_branch: master # deploying branch - cname: jethughes.github.io +name: Deploy to GitHub Pages + +on: + push: + branches: + - hugo + +jobs: + deploy: + runs-on: ubuntu-18.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.13 + with: + index: true + input: content + output: assets/indices + root: . + + - name: Setup Hugo + uses: peaceiris/actions-hugo@v2 + with: + hugo-version: '0.96.0' + extended: true + + - name: Build + run: hugo --minify + + - name: Deploy + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./public + publish_branch: master # deploying branch + cname: quartz.jzhao.xyz diff --git a/assets/js/graph.js b/assets/js/graph.js index f71e44d37..174d4946d 100644 --- a/assets/js/graph.js +++ b/assets/js/graph.js @@ -1,12 +1,16 @@ -async function drawGraph( - baseUrl, - pathColors, +async function drawGraph(baseUrl, isHome, pathColors, graphConfig) { + + let { depth, enableDrag, enableLegend, - enableZoom -) { - const container = document.getElementById('graph-container') + enableZoom, + opacityScale, + scale, + repelForce, + fontSize} = graphConfig; + + const container = document.getElementById("graph-container") const { index, links, content } = await fetchData // Use .pathname to remove hashes / searchParams / text fragments @@ -23,22 +27,19 @@ async function drawGraph( const copyLinks = JSON.parse(JSON.stringify(links)) const neighbours = new Set() - const wl = [curPage || '/', '__SENTINEL'] + const wl = [curPage || "/", "__SENTINEL"] if (depth >= 0) { while (depth >= 0 && wl.length > 0) { // compute neighbours const cur = wl.shift() - if (cur === '__SENTINEL') { + if (cur === "__SENTINEL") { depth-- - wl.push('__SENTINEL') + wl.push("__SENTINEL") } else { neighbours.add(cur) const outgoing = index.links[cur] || [] const incoming = index.backlinks[cur] || [] - wl.push( - ...outgoing.map((l) => l.target), - ...incoming.map((l) => l.source) - ) + wl.push(...outgoing.map((l) => l.target), ...incoming.map((l) => l.source)) } } } else { @@ -47,14 +48,12 @@ async function drawGraph( const data = { nodes: [...neighbours].map((id) => ({ id })), - links: copyLinks.filter( - (l) => neighbours.has(l.source) && neighbours.has(l.target) - ), + links: copyLinks.filter((l) => neighbours.has(l.source) && neighbours.has(l.target)), } const color = (d) => { - if (d.id === curPage || (d.id === '/' && curPage === '')) { - return 'var(--g-node-active)' + if (d.id === curPage || (d.id === "/" && curPage === "")) { + return "var(--g-node-active)" } for (const pathColor of pathColors) { @@ -65,7 +64,7 @@ async function drawGraph( } } - return 'var(--g-node)' + return "var(--g-node)" } const drag = (simulation) => { @@ -86,80 +85,71 @@ async function drawGraph( d.fy = null } - const noop = () => { } + const noop = () => {} return d3 .drag() - .on('start', enableDrag ? dragstarted : noop) - .on('drag', enableDrag ? dragged : noop) - .on('end', enableDrag ? dragended : noop) + .on("start", enableDrag ? dragstarted : noop) + .on("drag", enableDrag ? dragged : noop) + .on("end", enableDrag ? dragended : noop) } - const height = Math.max(container.offsetHeight, 250) + const height = Math.max(container.offsetHeight, isHome ? 500 : 250) const width = container.offsetWidth const simulation = d3 .forceSimulation(data.nodes) - .force('charge', d3.forceManyBody().strength(-30)) + .force("charge", d3.forceManyBody().strength(-100 * repelForce)) .force( - 'link', + "link", d3 .forceLink(data.links) .id((d) => d.id) - .distance(40) + .distance(40), ) - .force('center', d3.forceCenter()) + .force("center", d3.forceCenter()) const svg = d3 - .select('#graph-container') - .append('svg') - .attr('width', width) - .attr('height', height) - .attr('viewBox', [-width / 2, -height / 2, width, height]) + .select("#graph-container") + .append("svg") + .attr("width", width) + .attr("height", height) + .attr('viewBox', [-width / 2 * 1 / scale, -height / 2 * 1 / scale, width * 1 / scale, height * 1 / scale]) 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] legend.forEach((legendEntry, i) => { const key = Object.keys(legendEntry)[0] const colour = legendEntry[key] svg - .append('circle') - .attr('cx', -width / 2 + 20) - .attr('cy', height / 2 - 30 * (i + 1)) - .attr('r', 6) - .style('fill', colour) + .append("circle") + .attr("cx", -width / 2 + 20) + .attr("cy", height / 2 - 30 * (i + 1)) + .attr("r", 6) + .style("fill", colour) svg - .append('text') - .attr('x', -width / 2 + 40) - .attr('y', height / 2 - 30 * (i + 1)) + .append("text") + .attr("x", -width / 2 + 40) + .attr("y", height / 2 - 30 * (i + 1)) .text(key) - .style('font-size', '15px') - .attr('alignment-baseline', 'middle') + .style("font-size", "15px") + .attr("alignment-baseline", "middle") }) } // draw links between nodes const link = svg - .append('g') - .selectAll('line') + .append("g") + .selectAll("line") .data(data.links) - .join('line') - .attr('class', 'link') - .attr('stroke', 'var(--g-link)') - .attr('stroke-width', 2) - .attr('data-source', (d) => d.source.id) - .attr('data-target', (d) => d.target.id) + .join("line") + .attr("class", "link") + .attr("stroke", "var(--g-link)") + .attr("stroke-width", 2) + .attr("data-source", (d) => d.source.id) + .attr("data-target", (d) => d.target.id) // svg groups - const graphNode = svg - .append('g') - .selectAll('g') - .data(data.nodes) - .enter() - .append('g') + const graphNode = svg.append("g").selectAll("g").data(data.nodes).enter().append("g") // calculate radius const nodeRadius = (d) => { @@ -170,82 +160,79 @@ async function drawGraph( // draw individual nodes const node = graphNode - .append('circle') - .attr('class', 'node') - .attr('id', (d) => d.id) - .attr('r', nodeRadius) - .attr('fill', color) - .style('cursor', 'pointer') - .on('click', (_, d) => { + .append("circle") + .attr("class", "node") + .attr("id", (d) => d.id) + .attr("r", nodeRadius) + .attr("fill", color) + .style("cursor", "pointer") + .on("click", (_, d) => { // SPA navigation - window.navigate( - new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, '-')}/`), - '.singlePage' - ) + window.Million.navigate(new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`), ".singlePage") }) - .on('mouseover', function(_, d) { - d3.selectAll('.node') - .transition() - .duration(100) - .attr('fill', 'var(--g-node-inactive)') + .on("mouseover", function (_, d) { + d3.selectAll(".node").transition().duration(100).attr("fill", "var(--g-node-inactive)") const neighbours = parseIdsFromLinks([ ...(index.links[d.id] || []), ...(index.backlinks[d.id] || []), ]) - const neighbourNodes = d3 - .selectAll('.node') - .filter((d) => neighbours.includes(d.id)) + const neighbourNodes = d3.selectAll(".node").filter((d) => neighbours.includes(d.id)) const currentId = d.id + window.Million.prefetch(new URL(`${baseUrl}${decodeURI(d.id).replace(/\s+/g, "-")}/`)) const linkNodes = d3 - .selectAll('.link') + .selectAll(".link") .filter((d) => d.source.id === currentId || d.target.id === currentId) // highlight neighbour nodes - neighbourNodes.transition().duration(200).attr('fill', color) + neighbourNodes.transition().duration(200).attr("fill", color) // 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 // show text for self d3.select(this.parentNode) .raise() - .select('text') + .select("text") .transition() .duration(200) + .attr('opacityOld', d3.select(this.parentNode).select('text').style("opacity")) .style('opacity', 1) + .style('font-size', bigFont+'em') + .attr('dy', d => nodeRadius(d) + 20 + 'px') // radius is in px }) - .on('mouseleave', function(_, d) { - d3.selectAll('.node').transition().duration(200).attr('fill', color) + .on("mouseleave", function (_, d) { + d3.selectAll(".node").transition().duration(200).attr("fill", color) const currentId = d.id const linkNodes = d3 - .selectAll('.link') + .selectAll(".link") .filter((d) => d.source.id === currentId || d.target.id === currentId) - linkNodes.transition().duration(200).attr('stroke', 'var(--g-link)') + linkNodes.transition().duration(200).attr("stroke", "var(--g-link)") d3.select(this.parentNode) - .select('text') - .transition() - .duration(200) - .style('opacity', 0) + .select("text") + .transition() + .duration(200) + .style('opacity', d3.select(this.parentNode).select('text').attr("opacityOld")) + .style('font-size', fontSize+'em') + .attr('dy', d => nodeRadius(d) + 8 + 'px') // radius is in px }) .call(drag(simulation)) // draw labels const labels = graphNode - .append('text') - .attr('dx', 0) - .attr('dy', (d) => nodeRadius(d) + 8 + 'px') - .attr('text-anchor', 'middle') - .text((d) => content[d.id]?.title || d.id.replace('-', ' ')) - .style('opacity', 0) - .style('pointer-events', 'none') - .style('font-size', '0.4em') + .append("text") + .attr("dx", 0) + .attr("dy", (d) => nodeRadius(d) + 8 + "px") + .attr("text-anchor", "middle") + .text((d) => content[d.id]?.title || d.id.replace("-", " ")) + .style('opacity', (opacityScale - 1) / 3.75) + .style("pointer-events", "none") + .style('font-size', fontSize+'em') .raise() .call(drag(simulation)) @@ -260,24 +247,24 @@ async function drawGraph( [width, height], ]) .scaleExtent([0.25, 4]) - .on('zoom', ({ transform }) => { - link.attr('transform', transform) - node.attr('transform', transform) - const scale = transform.k + .on("zoom", ({ transform }) => { + link.attr("transform", transform) + node.attr("transform", transform) + const scale = transform.k * opacityScale; const scaledOpacity = Math.max((scale - 1) / 3.75, 0) - labels.attr('transform', transform).style('opacity', scaledOpacity) - }) + labels.attr("transform", transform).style("opacity", scaledOpacity) + }), ) } // progress the simulation - simulation.on('tick', () => { + simulation.on("tick", () => { link - .attr('x1', (d) => d.source.x) - .attr('y1', (d) => d.source.y) - .attr('x2', (d) => d.target.x) - .attr('y2', (d) => d.target.y) - node.attr('cx', (d) => d.x).attr('cy', (d) => d.y) - labels.attr('x', (d) => d.x).attr('y', (d) => d.y) + .attr("x1", (d) => d.source.x) + .attr("y1", (d) => d.source.y) + .attr("x2", (d) => d.target.x) + .attr("y2", (d) => d.target.y) + node.attr("cx", (d) => d.x).attr("cy", (d) => d.y) + labels.attr("x", (d) => d.x).attr("y", (d) => d.y) }) } diff --git a/assets/js/router.js b/assets/js/router.js index 81c25ac1c..3bdc81023 100644 --- a/assets/js/router.js +++ b/assets/js/router.js @@ -1,12 +1,26 @@ -import { router, navigate } from "https://unpkg.com/million@1.8.9-0/dist/router.mjs" +import { + apply, + navigate, + prefetch, + router, +} from "https://unpkg.com/million@1.9.8-0/dist/router.mjs" -export const attachSPARouting = (draw) => { - // SPA navigation for access later - window.navigate = navigate - // We only mutate document.title and content within .singlePage element - router(".singlePage") - // We need on initial load, then subsequent redirs - // requestAnimationFrame() delays graph draw until SPA routing is finished - window.addEventListener("million:navigate", () => requestAnimationFrame(draw)) - window.addEventListener("DOMContentLoaded", () => requestAnimationFrame(draw)) +export const attachSPARouting = (init, rerender) => { + // Attach SPA functions to the global Million namespace + window.Million = { + apply, + navigate, + prefetch, + router, + } + + const render = () => requestAnimationFrame(rerender) + + window.addEventListener("DOMContentLoaded", () => { + apply((doc) => init(doc)) + init() + router(".singlePage") + render() + }) + window.addEventListener("million:navigate", render) } diff --git a/assets/js/search.js b/assets/js/search.js index bb94cd30b..5896061ba 100644 --- a/assets/js/search.js +++ b/assets/js/search.js @@ -7,47 +7,44 @@ const removeMarkdown = ( gfm: true, useImgAltText: false, preserveLinks: false, - } + }, ) => { - let output = markdown || '' - output = output.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, '') + let output = markdown || "" + output = output.replace(/^(-\s*?|\*\s*?|_\s*?){3,}\s*$/gm, "") try { if (options.stripListLeaders) { if (options.listUnicodeChar) - output = output.replace( - /^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, - options.listUnicodeChar + ' $1' - ) - else output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, '$1') + output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, options.listUnicodeChar + " $1") + else output = output.replace(/^([\s\t]*)([\*\-\+]|\d+\.)\s+/gm, "$1") } if (options.gfm) { output = output - .replace(/\n={2,}/g, '\n') - .replace(/~{3}.*\n/g, '') - .replace(/~~/g, '') - .replace(/`{3}.*\n/g, '') + .replace(/\n={2,}/g, "\n") + .replace(/~{3}.*\n/g, "") + .replace(/~~/g, "") + .replace(/`{3}.*\n/g, "") } if (options.preserveLinks) { - output = output.replace(/\[(.*?)\][\[\(](.*?)[\]\)]/g, '$1 ($2)') + output = output.replace(/\[(.*?)\][\[\(](.*?)[\]\)]/g, "$1 ($2)") } output = output - .replace(/<[^>]*>/g, '') - .replace(/^[=\-]{2,}\s*$/g, '') - .replace(/\[\^.+?\](\: .*?$)?/g, '') - .replace(/(#{1,6})\s+(.+)\1?/g, '$2') - .replace(/\s{0,2}\[.*?\]: .*?$/g, '') - .replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? '$1' : '') - .replace(/\[(.*?)\][\[\(].*?[\]\)]/g, '$1') - .replace(/!?\[\[\S[^\[\]\|]*(?:\|([^\[\]]*))?\S\]\]/g, '$1') - .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(/(`{3,})(.*?)\1/gm, '$2') - .replace(/`(.+?)`/g, '$1') - .replace(/\n{2,}/g, '\n\n') + .replace(/<[^>]*>/g, "") + .replace(/^[=\-]{2,}\s*$/g, "") + .replace(/\[\^.+?\](\: .*?$)?/g, "") + .replace(/(#{1,6})\s+(.+)\1?/g, "$2") + .replace(/\s{0,2}\[.*?\]: .*?$/g, "") + .replace(/\!\[(.*?)\][\[\(].*?[\]\)]/g, options.useImgAltText ? "$1" : "") + .replace(/\[(.*?)\][\[\(].*?[\]\)]/g, "$1") + .replace(/!?\[\[\S[^\[\]\|]*(?:\|([^\[\]]*))?\S\]\]/g, "$1") + .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(/(`{3,})(.*?)\1/gm, "$2") + .replace(/`(.+?)`/g, "$1") + .replace(/\n{2,}/g, "\n\n") } catch (e) { console.error(e) return markdown @@ -64,27 +61,28 @@ const highlight = (content, term) => { if (directMatchIdx !== -1) { const h = highlightWindow / 2 const before = content.substring(0, directMatchIdx).split(" ").slice(-h) - const after = content.substring(directMatchIdx + term.length, content.length - 1).split(" ").slice(0, h) - return (before.length == h ? `...${before.join(" ")}` : before.join(" ")) + `${term}` + after.join(" ") + const after = content + .substring(directMatchIdx + term.length, content.length - 1) + .split(" ") + .slice(0, h) + return ( + (before.length == h ? `...${before.join(" ")}` : before.join(" ")) + + `${term}` + + after.join(" ") + ) } - const tokenizedTerm = term.split(/\s+/).filter((t) => t !== '') - const splitText = content.split(/\s+/).filter((t) => t !== '') + const tokenizedTerm = term.split(/\s+/).filter((t) => t !== "") + const splitText = content.split(/\s+/).filter((t) => t !== "") const includesCheck = (token) => - tokenizedTerm.some((term) => - token.toLowerCase().startsWith(term.toLowerCase()) - ) + tokenizedTerm.some((term) => token.toLowerCase().startsWith(term.toLowerCase())) const occurrencesIndices = splitText.map(includesCheck) // calculate best index let bestSum = 0 let bestIndex = 0 - for ( - let i = 0; - i < Math.max(occurrencesIndices.length - highlightWindow, 0); - i++ - ) { + for (let i = 0; i < Math.max(occurrencesIndices.length - highlightWindow, 0); i++) { const window = occurrencesIndices.slice(i, i + highlightWindow) const windowSum = window.reduce((total, cur) => total + cur, 0) if (windowSum >= bestSum) { @@ -94,10 +92,7 @@ const highlight = (content, term) => { } const startIndex = Math.max(bestIndex - highlightWindow, 0) - const endIndex = Math.min( - startIndex + 2 * highlightWindow, - splitText.length - ) + const endIndex = Math.min(startIndex + 2 * highlightWindow, splitText.length) const mappedText = splitText .slice(startIndex, endIndex) .map((token) => { @@ -106,27 +101,28 @@ const highlight = (content, term) => { } return token }) - .join(' ') - .replaceAll(' ', ' ') - return `${startIndex === 0 ? '' : '...'}${mappedText}${endIndex === splitText.length ? '' : '...' - }` -}; + .join(" ") + .replaceAll(' ', " ") + return `${startIndex === 0 ? "" : "..."}${mappedText}${ + endIndex === splitText.length ? "" : "..." + }` +} -(async function() { +;(async function () { const encoder = (str) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])+/) const contentIndex = new FlexSearch.Document({ cache: true, - charset: 'latin:extra', + charset: "latin:extra", optimize: true, index: [ { - field: 'content', - tokenize: 'reverse', + field: "content", + tokenize: "reverse", encode: encoder, }, { - field: 'title', - tokenize: 'forward', + field: "title", + tokenize: "forward", encode: encoder, }, ], @@ -153,11 +149,9 @@ const highlight = (content, term) => { const redir = (id, term) => { // SPA navigation - window.navigate( - new URL( - `${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/` - ), - '.singlePage' + window.Million.navigate( + new URL(`${BASE_URL.replace(/\/$/g, "")}${id}#:~:text=${encodeURIComponent(term)}/`), + ".singlePage", ) closeSearch() } @@ -169,24 +163,24 @@ const highlight = (content, term) => { content: content[id].content, }) - const source = document.getElementById('search-bar') - const results = document.getElementById('results-container') + const source = document.getElementById("search-bar") + const results = document.getElementById("results-container") let term - source.addEventListener('keyup', (e) => { - if (e.key === 'Enter') { - const anchor = document.getElementsByClassName('result-card')[0] + source.addEventListener("keyup", (e) => { + if (e.key === "Enter") { + const anchor = document.getElementsByClassName("result-card")[0] redir(anchor.id, term) } }) - source.addEventListener('input', (e) => { + source.addEventListener("input", (e) => { term = e.target.value const searchResults = contentIndex.search(term, [ { - field: 'content', + field: "content", limit: 10, }, { - field: 'title', + field: "title", limit: 5, }, ]) @@ -198,7 +192,7 @@ const highlight = (content, term) => { return [...results[0].result] } } - const allIds = new Set([...getByField('title'), ...getByField('content')]) + const allIds = new Set([...getByField("title"), ...getByField("content")]) const finalResults = [...allIds].map(formatForDisplay) // display @@ -213,58 +207,55 @@ const highlight = (content, term) => { resultToHTML({ ...result, term, - }) + }), ) - .join('\n') - const anchors = [...document.getElementsByClassName('result-card')] + .join("\n") + const anchors = [...document.getElementsByClassName("result-card")] anchors.forEach((anchor) => { anchor.onclick = () => redir(anchor.id, term) }) } }) - const searchContainer = document.getElementById('search-container') + const searchContainer = document.getElementById("search-container") function openSearch() { - if ( - searchContainer.style.display === 'none' || - searchContainer.style.display === '' - ) { - source.value = '' - results.innerHTML = '' - searchContainer.style.display = 'block' + if (searchContainer.style.display === "none" || searchContainer.style.display === "") { + source.value = "" + results.innerHTML = "" + searchContainer.style.display = "block" source.focus() } else { - searchContainer.style.display = 'none' + searchContainer.style.display = "none" } } function closeSearch() { - searchContainer.style.display = 'none' + searchContainer.style.display = "none" } - document.addEventListener('keydown', (event) => { - if (event.key === 'k' && (event.ctrlKey || event.metaKey)) { + document.addEventListener("keydown", (event) => { + if (event.key === "k" && (event.ctrlKey || event.metaKey)) { event.preventDefault() openSearch() } - if (event.key === 'Escape') { + if (event.key === "Escape") { event.preventDefault() closeSearch() } }) - const searchButton = document.getElementById('search-icon') - searchButton.addEventListener('click', (evt) => { + const searchButton = document.getElementById("search-icon") + searchButton.addEventListener("click", (evt) => { openSearch() }) - searchButton.addEventListener('keydown', (evt) => { + searchButton.addEventListener("keydown", (evt) => { openSearch() }) - searchContainer.addEventListener('click', (evt) => { + searchContainer.addEventListener("click", (evt) => { closeSearch() }) - document.getElementById('search-space').addEventListener('click', (evt) => { + document.getElementById("search-space").addEventListener("click", (evt) => { evt.stopPropagation() }) })() diff --git a/assets/styles/base.scss b/assets/styles/base.scss index 1b9b936e3..1c353f338 100644 --- a/assets/styles/base.scss +++ b/assets/styles/base.scss @@ -171,34 +171,6 @@ article { opacity: 0.7; } - & > .tags { - list-style: none; - padding-left: 0; - - & .meta { - & > h1 { - margin: 0; - } - & > p { - margin: 0; - } - } - - & > li { - display: inline-block; - } - & > li > a { - border-radius: 8px; - border: var(--outlinegray) 1px solid; - padding: 0.2em 0.5em; - &::before { - content: "#"; - margin-right: 0.3em; - color: var(--outlinegray); - } - } - } - & a { font-family: Source Sans Pro; font-weight: 600; @@ -222,6 +194,36 @@ article { } } +.tags { + list-style: none; + padding-left: 0; + + & .meta { + & > h1 { + margin: 0; + } + & > p { + margin: 0; + } + } + + & > li { + display: inline-block; + margin: 0.4em 0; + } + + & > li > a { + border-radius: 8px; + border: var(--outlinegray) 1px solid; + padding: 0.2em 0.5em; + &::before { + content: "#"; + margin-right: 0.3em; + color: var(--outlinegray); + } + } +} + .backlinks a { font-weight: 600; font-size: 0.9rem; @@ -589,3 +591,5 @@ header { padding: 0 1em; } } + + diff --git a/config.toml b/config.toml index e5efd107b..3411b371a 100644 --- a/config.toml +++ b/config.toml @@ -1,30 +1,33 @@ -baseURL = "https://jethughes.github.io/notes/" -languageCode = "en-us" -googleAnalytics = "G-XYFD95KB4J" -pygmentsUseClasses = true -relativeURLs = false -disablePathToLower = true -ignoreFiles = [ - "/content/templates/*", - "/content/private/*", -] -summaryLength = 20 -paginate = 10 -enableGitInfo = true - -[markup] - [markup.tableOfContents] - endLevel = 3 - ordered = true - startLevel = 2 - [markup.highlight] - anchorLineNos = false - codeFences = true - guessSyntax = true - hl_Lines = "" - lineAnchors = "" - lineNoStart = 1 - lineNos = true - lineNumbersInTable = true - style = "dracula" - tabWidth = 4 +baseURL = "https://jethughes.github.io/notes/" +languageCode = "en-us" +googleAnalytics = "G-XYFD95KB4J" +pygmentsUseClasses = true +relativeURLs = false +disablePathToLower = true +ignoreFiles = [ + "/content/templates/*", + "/content/private/*", +] +summaryLength = 20 +paginate = 10 +enableGitInfo = true + +[markup] + [markup.tableOfContents] + endLevel = 3 + ordered = true + startLevel = 2 + [markup.highlight] + anchorLineNos = false + codeFences = true + guessSyntax = true + hl_Lines = "" + lineAnchors = "" + lineNoStart = 1 + lineNos = true + lineNumbersInTable = true + style = "dracula" + tabWidth = 4 + [frontmatter] + lastmod = ["lastmod", ":git", "date", "publishDate"] + publishDate = ["publishDate", "date"] diff --git a/data/config.yaml b/data/config.yaml index db8678f2c..22c66d9d3 100644 --- a/data/config.yaml +++ b/data/config.yaml @@ -1,10 +1,16 @@ -name: Jet Hughes -enableToc: true -openToc: false -enableLinkPreview: true -enableLatex: true -description: "My Notes" -page_title: "Jet Hughes" -links: - - link_name: Github - - link: https://github.com/jethughes +name: Jet Hughes +enableToc: true +openToc: false +enableLinkPreview: true +enableLatex: true +enableSPA: true +enableFooter: true +enableContextualBacklinks: true +enableRecentNotes: false +description: + My notes +page_title: + "Jet's Notes" +links: + - link_name: Github + link: https://github.com/jethughes diff --git a/data/graphConfig.yaml b/data/graphConfig.yaml index 540a1dca2..a6f916acb 100644 --- a/data/graphConfig.yaml +++ b/data/graphConfig.yaml @@ -1,5 +1,37 @@ -enableLegend: false -enableDrag: true -enableZoom: true -depth: -1 # set to -1 to show full graph -paths: \ No newline at end of file +# if true, a Global Graph will be shown on home page with full width, no backlink. +# A different set of Local Graphs will be shown on sub pages. +# if false, Local Graph will be default on every page as usual +enableGlobalGraph: false + +### Local Graph ### + +localGraph: + enableLegend: false + enableDrag: true + enableZoom: true + depth: 1 # set to -1 to show full graph + scale: 1.2 + repelForce: 2 + centerForce: 1 + linkDistance: 1 + fontSize: 0.6 + opacityScale: 3 + +### Global Graph ### + +globalGraph: + enableLegend: false + enableDrag: true + enableZoom: true + depth: -1 # set to -1 to show full graph + scale: 1.4 + repelForce: 1 + centerForce: 1 + linkDistance: 1 + fontSize: 0.5 + opacityScale: 3 + +### For all graphs ### + +paths: + - /moc: "#4388cc" diff --git a/layouts/index.html b/layouts/index.html index 224c99784..505361420 100644 --- a/layouts/index.html +++ b/layouts/index.html @@ -15,8 +15,11 @@
{{partial "toc.html" .}} {{partial "textprocessing.html" . }} + {{if $.Site.Data.config.enableRecentNotes}} + {{partial "recent.html" . }} + {{end}}
- {{partial "footer.html" .}} + {{partial "footerIndex.html" .}} diff --git a/layouts/partials/footer.html b/layouts/partials/footer.html index 6d4ef17b9..ddefe75cf 100644 --- a/layouts/partials/footer.html +++ b/layouts/partials/footer.html @@ -1,4 +1,8 @@ + +
+ +{{if $.Site.Data.config.enableFooter}}
+{{end}} {{partial "contact.html" .}} \ No newline at end of file diff --git a/layouts/partials/footerIndex.html b/layouts/partials/footerIndex.html new file mode 100644 index 000000000..5f190446a --- /dev/null +++ b/layouts/partials/footerIndex.html @@ -0,0 +1,24 @@ +{{if $.Site.Data.config.enableFooter}} + {{if $.Site.Data.graphConfig.enableGlobalGraph}} +
+ +
+ {{partial "graph.html" .}} +
+ +
+ {{else}} +
+
+ +
+ {{partial "graph.html" .}} +
+ +
+ {{end}} +{{end}} + +{{partial "contact.html" .}} diff --git a/layouts/partials/head.html b/layouts/partials/head.html index a5f23da30..b3ad28d8c 100644 --- a/layouts/partials/head.html +++ b/layouts/partials/head.html @@ -10,11 +10,7 @@ end }} - + - {{ $darkMode := resources.Get "js/darkmode.js" | resources.Fingerprint "md5" | - resources.Minify }} + {{ $darkMode := resources.Get "js/darkmode.js" | resources.Fingerprint "md5" | resources.Minify }} {{partial "katex.html" .}} @@ -61,28 +56,31 @@ links, content, })) - - {{if $.Site.Data.config.enableSPA}} - {{ $router := resources.Get "js/router.js" | resources.Fingerprint "md5" | - resources.Minify }} - + {{if $.Site.Data.config.enableSPA}} + {{ $router := resources.Get "js/router.js" | resources.Fingerprint "md5" | + resources.Minify }} + {{else}} - + {{end}} {{ template "_internal/google_analytics.html" . }} diff --git a/layouts/partials/page-list.html b/layouts/partials/page-list.html index 6c2249baf..e51c5ddab 100644 --- a/layouts/partials/page-list.html +++ b/layouts/partials/page-list.html @@ -4,11 +4,17 @@

{{- .Title -}}

+

{{- .Summary -}}{{if .Truncated}}...{{end}}

{{ .ReadingTime }} minute read. Last updated {{if ne .Date .Lastmod}}{{ .Lastmod.Format "January 2, 2006" }}{{else}}Unknown{{end}}

+
{{- end -}} diff --git a/layouts/partials/recent.html b/layouts/partials/recent.html new file mode 100644 index 000000000..e3926c243 --- /dev/null +++ b/layouts/partials/recent.html @@ -0,0 +1,12 @@ +
+

Recent Notes

+ + {{$notes := .Site.RegularPages}} + {{partial "page-list.html" (first 3 $notes)}} +
+