various polish

This commit is contained in:
Jacky Zhao
2023-07-02 13:08:29 -07:00
parent bcebc20808
commit 20b2d88a06
30 changed files with 339 additions and 190 deletions

View File

@ -2,9 +2,8 @@ import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
function ArticleTitle({ fileData }: QuartzComponentProps) {
const title = fileData.frontmatter?.title
const displayTitle = fileData.slug === "index" ? undefined : title
if (displayTitle) {
return <h1 class="article-title">{displayTitle}</h1>
if (title) {
return <h1 class="article-title">{title}</h1>
} else {
return null
}

View File

@ -14,7 +14,7 @@ export default ((opts?: Options) => {
return <>
<hr />
<footer>
<p>Made by {name} using <a>Quartz</a>, © {year}</p>
<p>Made by {name} using <a href="https://quartz.jzhao.xyz/">Quartz</a>, © {year}</p>
<ul>{Object.entries(links).map(([text, link]) => <li>
<a href={link}>{text}</a>
</li>)}</ul>

View File

@ -2,15 +2,7 @@ import { resolveToRoot } from "../path"
import { JSResourceToScriptElement } from "../resources"
import { QuartzComponentConstructor, QuartzComponentProps } from "./types"
interface Options {
prefetchContentIndex: boolean
}
const defaultOptions: Options = {
prefetchContentIndex: true
}
export default ((opts?: Options) => {
export default (() => {
function Head({ fileData, externalResources }: QuartzComponentProps) {
const slug = fileData.slug!
const title = fileData.frontmatter?.title ?? "Untitled"
@ -20,10 +12,6 @@ export default ((opts?: Options) => {
const iconPath = baseDir + "/static/icon.png"
const ogImagePath = baseDir + "/static/og-image.png"
const prefetchContentIndex = opts?.prefetchContentIndex ?? defaultOptions.prefetchContentIndex
const contentIndexPath = baseDir + "/static/contentIndex.json"
const contentIndexScript = `const fetchData = fetch(\`${contentIndexPath}\`).then(data => data.json())`
return <head>
<title>{title}</title>
<meta charSet="utf-8" />
@ -36,9 +24,8 @@ export default ((opts?: Options) => {
<link rel="icon" href={iconPath} />
<meta name="description" content={description} />
<meta name="generator" content="Quartz" />
<link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" />
{prefetchContentIndex && <script spa-preserve>{contentIndexScript}</script>}
<link rel="preconnect" href="https://fonts.googleapis.com"/>
<link rel="preconnect" href="https://fonts.gstatic.com"/>
{css.map(href => <link key={href} href={href} rel="stylesheet" type="text/css" spa-preserve />)}
{js.filter(resource => resource.loadTime === "beforeDOMReady").map(res => JSResourceToScriptElement(res, true))}
</head>

View File

@ -12,6 +12,7 @@ header {
flex-direction: row;
align-items: center;
margin: 2em 0;
gap: 1.5rem;
}
header h1 {

View File

@ -23,7 +23,7 @@ function byDateAndAlphabetical(f1: QuartzPluginData, f2: QuartzPluginData): numb
export function PageList({ fileData, allFiles }: QuartzComponentProps) {
const slug = fileData.slug!
return <ul class="section-ul">
return <ul class="section-ul popover-hint">
{allFiles.sort(byDateAndAlphabetical).map(page => {
const title = page.frontmatter?.title
const pageSlug = page.slug!
@ -36,9 +36,8 @@ export function PageList({ fileData, allFiles }: QuartzComponentProps) {
<div class="desc">
<h3><a href={stripIndex(relativeToRoot(slug, pageSlug))} class="internal">{title}</a></h3>
</div>
<div class="spacer"></div>
<ul class="tags">
{tags.map(tag => <li><a href={relativeToRoot(slug, `tags/${tag}`)}>#{tag}</a></li>)}
{tags.map(tag => <li><a class="internal" href={relativeToRoot(slug, `tags/${tag}`)}>#{tag}</a></li>)}
</ul>
</div>
</li>

View File

@ -11,7 +11,7 @@ function TagList({ fileData }: QuartzComponentProps) {
const display = `#${tag}`
const linkDest = baseDir + `/tags/${slugAnchor(tag)}`
return <li>
<a href={linkDest}>{display}</a>
<a href={linkDest} class="internal">{display}</a>
</li>
})}</ul>
} else {
@ -25,17 +25,18 @@ TagList.css = `
display: flex;
padding-left: 0;
gap: 0.4rem;
}
.tags > li {
display: inline-block;
margin: 0;
overflow-wrap: normal;
}
& > li {
display: inline-block;
margin: 0;
& > a {
border-radius: 8px;
border: var(--lightgray) 1px solid;
padding: 0.2rem 0.5rem;
}
}
.tags > li > a {
border-radius: 8px;
background-color: var(--highlight);
padding: 0.2rem 0.5rem;
}
`

View File

@ -5,7 +5,7 @@ import { toJsxRuntime } from "hast-util-to-jsx-runtime"
function Content({ tree }: QuartzComponentProps) {
// @ts-ignore (preact makes it angry)
const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' })
return <article>{content}</article>
return <article class="popover-hint">{content}</article>
}
export default (() => Content) satisfies QuartzComponentConstructor
export default (() => Content) satisfies QuartzComponentConstructor

View File

@ -17,10 +17,15 @@ interface RenderComponents {
export function pageResources(slug: string, staticResources: StaticResources): StaticResources {
const baseDir = resolveToRoot(slug)
const contentIndexPath = baseDir + "/static/contentIndex.json"
const contentIndexScript = `const fetchData = fetch(\`${contentIndexPath}\`).then(data => data.json())`
return {
css: [baseDir + "/index.css", ...staticResources.css],
js: [
{ src: baseDir + "/prescript.js", loadTime: "beforeDOMReady", contentType: "external" },
{ loadTime: "afterDOMReady", contentType: "inline", spaPreserve: true, script: contentIndexScript },
...staticResources.js,
{ src: baseDir + "/postscript.js", loadTime: "afterDOMReady", moduleType: 'module', contentType: "external" }
]
@ -32,28 +37,40 @@ export function renderPage(slug: string, componentData: QuartzComponentProps, co
const Header = HeaderConstructor()
const Body = BodyConstructor()
const LeftComponent =
<div class="left">
<div class="left-inner">
{left.map(BodyComponent => <BodyComponent {...componentData} />)}
</div>
</div>
const RightComponent =
<div class="right">
<div class="right-inner">
{right.map(BodyComponent => <BodyComponent {...componentData} />)}
</div>
</div>
const doc = <html>
<Head {...componentData} />
<body data-slug={slug}>
<div id="quartz-root" class="page">
<Header {...componentData} >
{header.map(HeaderComponent => <HeaderComponent {...componentData} />)}
</Header>
<div class="popover-hint">
{beforeBody.map(BodyComponent => <BodyComponent {...componentData} />)}
<div class="page-header">
<Header {...componentData} >
{header.map(HeaderComponent => <HeaderComponent {...componentData} />)}
</Header>
<div class="popover-hint">
{beforeBody.map(BodyComponent => <BodyComponent {...componentData} />)}
</div>
</div>
<Body {...componentData}>
<div class="left">
{left.map(BodyComponent => <BodyComponent {...componentData} />)}
</div>
<div class="center popover-hint">
{LeftComponent}
<div class="center">
<Content {...componentData} />
<Footer {...componentData} />
</div>
<div class="right">
{right.map(BodyComponent => <BodyComponent {...componentData} />)}
</div>
{RightComponent}
</Body>
<Footer {...componentData} />
</div>
</body>
{pageResources.js.filter(resource => resource.loadTime === "afterDOMReady").map(res => JSResourceToScriptElement(res))}

View File

@ -2,7 +2,7 @@ const userPref = window.matchMedia('(prefers-color-scheme: light)').matches ? 'l
const currentTheme = localStorage.getItem('theme') ?? userPref
document.documentElement.setAttribute('saved-theme', currentTheme)
window.addEventListener('DOMContentLoaded', () => {
document.addEventListener("nav", () => {
const switchTheme = (e: any) => {
if (e.target.checked) {
document.documentElement.setAttribute('saved-theme', 'dark')
@ -16,7 +16,8 @@ window.addEventListener('DOMContentLoaded', () => {
// Darkmode toggle
const toggleSwitch = document.querySelector('#darkmode-toggle') as HTMLInputElement
toggleSwitch.addEventListener('change', switchTheme, false)
toggleSwitch.removeEventListener('change', switchTheme)
toggleSwitch.addEventListener('change', switchTheme)
if (currentTheme === 'dark') {
toggleSwitch.checked = true
}

View File

@ -266,9 +266,9 @@ async function renderGraph(container: string, slug: string) {
})
}
function renderGlobalGraph() {
async function renderGlobalGraph() {
const slug = document.body.dataset["slug"]!
renderGraph("global-graph-container", slug)
await renderGraph("global-graph-container", slug)
const container = document.getElementById("global-graph-outer")
container?.classList.add("active")
@ -293,7 +293,14 @@ document.addEventListener("nav", async (e: unknown) => {
containerIcon?.addEventListener("click", renderGlobalGraph)
})
window.addEventListener('resize', async () => {
const slug = document.body.dataset["slug"]!
await renderGraph("graph-container", slug)
let resizeEventDebounce: number | undefined = undefined
window.addEventListener('resize', () => {
if (resizeEventDebounce) {
clearTimeout(resizeEventDebounce)
}
resizeEventDebounce = window.setTimeout(async () => {
const slug = document.body.dataset["slug"]!
await renderGraph("graph-container", slug)
}, 50)
})

View File

@ -0,0 +1,3 @@
import Plausible from 'plausible-tracker'
const { trackPageview } = Plausible()
document.addEventListener("nav", () => trackPageview())

View File

@ -1,5 +1,24 @@
import { computePosition, flip, inline, shift } from "@floating-ui/dom"
// from micromorph/src/utils.ts
// https://github.com/natemoo-re/micromorph/blob/main/src/utils.ts#L5
export function normalizeRelativeURLs(
el: Element | Document,
base: string | URL
) {
const update = (el: Element, attr: string, base: string | URL) => {
el.setAttribute(attr, new URL(el.getAttribute(attr)!, base).pathname)
}
el.querySelectorAll('[href^="./"], [href^="../"]').forEach((item) =>
update(item, 'href', base)
)
el.querySelectorAll('[src^="./"], [src^="../"]').forEach((item) =>
update(item, 'src', base)
)
}
document.addEventListener("nav", () => {
const links = [...document.getElementsByClassName("internal")] as HTMLLinkElement[]
const p = new DOMParser()
@ -41,6 +60,7 @@ document.addEventListener("nav", () => {
if (!contents) return
const html = p.parseFromString(contents, "text/html")
normalizeRelativeURLs(html, targetUrl)
const elts = [...html.getElementsByClassName("popover-hint")]
if (elts.length === 0) return
@ -54,11 +74,13 @@ document.addEventListener("nav", () => {
setPosition(popoverElement)
link.appendChild(popoverElement)
link.dataset.fetchedPopover = "true"
const heading = popoverInner.querySelector(hash) as HTMLElement | null
if (heading) {
// leave ~12px of buffer when scrolling to a heading
popoverInner.scroll({ top: heading.offsetTop - 12, behavior: 'instant' })
if (hash !== "") {
const heading = popoverInner.querySelector(hash) as HTMLElement | null
if (heading) {
// leave ~12px of buffer when scrolling to a heading
popoverInner.scroll({ top: heading.offsetTop - 12, behavior: 'instant' })
}
}
})
}

View File

@ -7,13 +7,9 @@
& > ul {
list-style: none;
padding: 0;
margin: 0;
margin: 0.5rem 0;
& > li {
margin: 0.5rem 0;
padding: 0.25rem 1rem;
border: var(--lightgray) 1px solid;
border-radius: 5px;
& > a {
background-color: transparent;
}

View File

@ -1,6 +1,8 @@
footer {
text-align: left;
opacity: 0.8;
margin-bottom: 4rem;
& ul {
list-style: none;
margin: 0;

View File

@ -11,6 +11,7 @@
height: 250px;
margin: 0.5em 0;
position: relative;
overflow: hidden;
& > #global-graph-icon {
color: var(--dark);
@ -30,10 +31,6 @@
background-color: var(--lightgray);
}
}
& > #graph-container > svg {
margin-bottom: -5px;
}
}
& > #global-graph-outer {

View File

@ -8,29 +8,36 @@ li.section-li {
margin-bottom: 1em;
& > .section {
display: flex;
align-items: center;
display: grid;
grid-template-columns: 6em 3fr 1fr;
@media all and (max-width: 600px) {
& .tags {
& > .tags {
display: none;
}
}
& h3 > a {
font-weight: 700;
margin: 0;
background-color: transparent;
& > .tags {
justify-self: end;
margin-left: 1rem;
}
& p {
& > .desc a {
background-color: transparent;
}
& > .meta {
margin: 0;
padding-right: 1em;
flex-basis: 6em;
opacity: 0.6;
}
}
& .meta {
opacity: 0.6;
}
}
// modifications in popover context
.popover .section {
grid-template-columns: 6em 1fr !important;
& > .tags {
display: none;
}
}

View File

@ -24,7 +24,7 @@
height: 20rem;
padding: 0 1rem 1rem 1rem;
font-weight: initial;
line-height: initial;
line-height: normal;
font-size: initial;
font-family: var(--bodyFont);
border: 1px solid var(--gray);

View File

@ -1,8 +1,7 @@
.search {
min-width: 5rem;
max-width: 12rem;
max-width: 14rem;
flex-grow: 0.3;
margin: 0 1.5rem;
& > #search-icon {
background-color: var(--lightgray);

View File

@ -8,7 +8,7 @@ export type QuartzComponentProps = {
externalResources: StaticResources
fileData: QuartzPluginData
cfg: GlobalConfiguration
children: QuartzComponent[] | JSX.Element[]
children: (QuartzComponent | JSX.Element)[]
tree: Node<QuartzPluginData>
allFiles: QuartzPluginData[]
}