From 38cff2d670ecf7fd325aaaf776a4c250a72cc661 Mon Sep 17 00:00:00 2001 From: Jacky Zhao <j.zhao2k19@gmail.com> Date: Tue, 4 Jul 2023 16:48:36 -0700 Subject: [PATCH] more visual polish, adjust colours and spacing --- quartz.config.ts | 10 +- quartz/components/Backlinks.tsx | 2 +- quartz/components/DesktopOnly.tsx | 4 +- quartz/components/Footer.tsx | 14 +- quartz/components/Graph.tsx | 2 +- quartz/components/MobileOnly.tsx | 4 +- quartz/components/ReadingTime.tsx | 2 +- quartz/components/Spacer.tsx | 7 +- quartz/components/TableOfContents.tsx | 2 +- quartz/components/pages/FolderContent.tsx | 1 - quartz/components/pages/TagContent.tsx | 1 - quartz/components/renderPage.tsx | 18 +-- quartz/components/scripts/graph.inline.ts | 13 +- quartz/components/scripts/search.inline.ts | 62 ++++----- quartz/components/styles/darkmode.scss | 2 +- quartz/components/styles/footer.scss | 1 - quartz/components/styles/popover.scss | 4 +- quartz/components/styles/search.scss | 6 +- quartz/components/styles/toc.scss | 2 +- quartz/components/types.ts | 3 + quartz/styles/base.scss | 150 +++++++++++++-------- quartz/styles/variables.scss | 3 +- 22 files changed, 173 insertions(+), 140 deletions(-) diff --git a/quartz.config.ts b/quartz.config.ts index 18f2533..4f17bd9 100644 --- a/quartz.config.ts +++ b/quartz.config.ts @@ -22,6 +22,7 @@ const contentPageLayout: PageLayout = { ], left: [ Component.PageTitle(), + Component.MobileOnly(Component.Spacer()), Component.Search(), Component.Darkmode(), Component.DesktopOnly(Component.TableOfContents()), @@ -38,6 +39,7 @@ const listPageLayout: PageLayout = { ], left: [ Component.PageTitle(), + Component.MobileOnly(Component.Spacer()), Component.Search(), Component.Darkmode() ], @@ -63,8 +65,8 @@ const config: QuartzConfig = { colors: { lightMode: { light: '#faf8f8', - lightgray: '#e8e8e8', - gray: '#dadada', + lightgray: '#e5e5e5', + gray: '#b8b8b8', darkgray: '#4e4e4e', dark: '#141021', secondary: '#284b63', @@ -73,8 +75,8 @@ const config: QuartzConfig = { }, darkMode: { light: '#161618', - lightgray: '#292629', - gray: '#343434', + lightgray: '#393639', + gray: '#646464', darkgray: '#d4d4d4', dark: '#fbfffe', secondary: '#7b97aa', diff --git a/quartz/components/Backlinks.tsx b/quartz/components/Backlinks.tsx index 5096977..0784e9a 100644 --- a/quartz/components/Backlinks.tsx +++ b/quartz/components/Backlinks.tsx @@ -8,7 +8,7 @@ function Backlinks({ fileData, allFiles }: QuartzComponentProps) { const backlinkFiles = allFiles.filter(file => file.links?.includes(slug)) return <div class="backlinks"> <h3>Backlinks</h3> - <ul> + <ul class="overflow"> {backlinkFiles.length > 0 ? backlinkFiles.map(f => <li><a href={stripIndex(relativeToRoot(slug, f.slug!))} class="internal">{f.frontmatter?.title}</a></li>) : <li>No backlinks found</li>} diff --git a/quartz/components/DesktopOnly.tsx b/quartz/components/DesktopOnly.tsx index a1c5dae..a11f23f 100644 --- a/quartz/components/DesktopOnly.tsx +++ b/quartz/components/DesktopOnly.tsx @@ -4,9 +4,7 @@ export default ((component?: QuartzComponent) => { if (component) { const Component = component function DesktopOnly(props: QuartzComponentProps) { - return <div class="desktop-only"> - <Component {...props} /> - </div> + return <Component displayClass="desktop-only" {...props} /> } DesktopOnly.displayName = component.displayName diff --git a/quartz/components/Footer.tsx b/quartz/components/Footer.tsx index 5fc6d64..a4c895b 100644 --- a/quartz/components/Footer.tsx +++ b/quartz/components/Footer.tsx @@ -11,15 +11,13 @@ export default ((opts?: Options) => { const year = new Date().getFullYear() const name = opts?.authorName ?? "someone" const links = opts?.links ?? [] - return <> + return <footer> <hr /> - <footer> - <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> - </footer> - </> + <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> + </footer> } Footer.css = style diff --git a/quartz/components/Graph.tsx b/quartz/components/Graph.tsx index e7f1df2..6d492f2 100644 --- a/quartz/components/Graph.tsx +++ b/quartz/components/Graph.tsx @@ -50,7 +50,7 @@ export default ((opts?: GraphOptions) => { const localGraph = { ...opts?.localGraph, ...defaultOptions.localGraph } const globalGraph = { ...opts?.globalGraph, ...defaultOptions.globalGraph } return <div class="graph"> - <h3>Interactive Graph</h3> + <h3>Site Graph</h3> <div class="graph-outer"> <div id="graph-container" data-cfg={JSON.stringify(localGraph)}></div> <svg version="1.1" id="global-graph-icon" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" x="0px" y="0px" diff --git a/quartz/components/MobileOnly.tsx b/quartz/components/MobileOnly.tsx index b75fd76..5a19095 100644 --- a/quartz/components/MobileOnly.tsx +++ b/quartz/components/MobileOnly.tsx @@ -4,9 +4,7 @@ export default ((component?: QuartzComponent) => { if (component) { const Component = component function MobileOnly(props: QuartzComponentProps) { - return <div class="mobile-only"> - <Component {...props} /> - </div> + return <Component displayClass="mobile-only" {...props} /> } MobileOnly.displayName = component.displayName diff --git a/quartz/components/ReadingTime.tsx b/quartz/components/ReadingTime.tsx index 9c64289..3e3d4d7 100644 --- a/quartz/components/ReadingTime.tsx +++ b/quartz/components/ReadingTime.tsx @@ -14,7 +14,7 @@ function ReadingTime({ fileData }: QuartzComponentProps) { ReadingTime.css = ` .reading-time { margin-top: 0; - opacity: 0.5; + color: var(--gray); } ` diff --git a/quartz/components/Spacer.tsx b/quartz/components/Spacer.tsx index 34ea084..b9d5bb6 100644 --- a/quartz/components/Spacer.tsx +++ b/quartz/components/Spacer.tsx @@ -1,7 +1,8 @@ -import { QuartzComponentConstructor } from "./types" +import { QuartzComponentConstructor, QuartzComponentProps } from "./types" -function Spacer() { - return <div class="spacer"></div> +function Spacer({ displayClass }: QuartzComponentProps) { + const className = displayClass ? `spacer ${displayClass}` : "spacer" + return <div class={className}></div> } export default (() => Spacer) satisfies QuartzComponentConstructor diff --git a/quartz/components/TableOfContents.tsx b/quartz/components/TableOfContents.tsx index a9d7b78..ddd5195 100644 --- a/quartz/components/TableOfContents.tsx +++ b/quartz/components/TableOfContents.tsx @@ -26,7 +26,7 @@ function TableOfContents({ fileData }: QuartzComponentProps) { </svg> </button> <div id="toc-content"> - <ul> + <ul class="overflow"> {fileData.toc.map(tocEntry => <li key={tocEntry.slug} class={`depth-${tocEntry.depth}`}> <a href={`#${tocEntry.slug}`} data-for={tocEntry.slug}>{tocEntry.text}</a> </li>)} diff --git a/quartz/components/pages/FolderContent.tsx b/quartz/components/pages/FolderContent.tsx index 445074c..b00ea94 100644 --- a/quartz/components/pages/FolderContent.tsx +++ b/quartz/components/pages/FolderContent.tsx @@ -27,7 +27,6 @@ function FolderContent(props: QuartzComponentProps) { const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' }) return <div class="popover-hint"> <article>{content}</article> - <hr/> <p>{allPagesInFolder.length} items under this folder.</p> <div> <PageList {...listProps} /> diff --git a/quartz/components/pages/TagContent.tsx b/quartz/components/pages/TagContent.tsx index b84ce29..81e8de2 100644 --- a/quartz/components/pages/TagContent.tsx +++ b/quartz/components/pages/TagContent.tsx @@ -21,7 +21,6 @@ function TagContent(props: QuartzComponentProps) { const content = toJsxRuntime(tree, { Fragment, jsx, jsxs, elementAttributeNameCase: 'html' }) return <div class="popover-hint"> <article>{content}</article> - <hr/> <p>{allPagesWithTag.length} items with this tag.</p> <div> <PageList {...listProps} /> diff --git a/quartz/components/renderPage.tsx b/quartz/components/renderPage.tsx index 4da6370..8de60bf 100644 --- a/quartz/components/renderPage.tsx +++ b/quartz/components/renderPage.tsx @@ -55,22 +55,22 @@ export function renderPage(slug: string, componentData: QuartzComponentProps, co <Head {...componentData} /> <body data-slug={slug}> <div id="quartz-root" class="page"> - <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}> {LeftComponent} <div class="center"> + <div class="page-header"> + <Header {...componentData} > + {header.map(HeaderComponent => <HeaderComponent {...componentData} />)} + </Header> + <div class="popover-hint"> + {beforeBody.map(BodyComponent => <BodyComponent {...componentData} />)} + </div> + </div> <Content {...componentData} /> - <Footer {...componentData} /> </div> {RightComponent} </Body> + <Footer {...componentData} /> </div> </body> {pageResources.js.filter(resource => resource.loadTime === "afterDOMReady").map(res => JSResourceToScriptElement(res))} diff --git a/quartz/components/scripts/graph.inline.ts b/quartz/components/scripts/graph.inline.ts index 194a23b..33e90c7 100644 --- a/quartz/components/scripts/graph.inline.ts +++ b/quartz/components/scripts/graph.inline.ts @@ -225,7 +225,7 @@ async function renderGraph(container: string, slug: string) { const labels = graphNode .append("text") .attr("dx", 0) - .attr("dy", (d) => nodeRadius(d) - 8 + "px") + .attr("dy", (d) => -nodeRadius(d) + "px") .attr("text-anchor", "middle") .text((d) => data[d.id]?.title || (d.id.charAt(1).toUpperCase() + d.id.slice(2)).replace("-", " ")) .style('opacity', (opacityScale - 1) / 3.75) @@ -297,14 +297,3 @@ document.addEventListener("nav", async (e: unknown) => { containerIcon?.addEventListener("click", renderGlobalGraph) }) -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) -}) diff --git a/quartz/components/scripts/search.inline.ts b/quartz/components/scripts/search.inline.ts index f69d77d..054d352 100644 --- a/quartz/components/scripts/search.inline.ts +++ b/quartz/components/scripts/search.inline.ts @@ -58,38 +58,7 @@ const encoder = (str: string) => str.toLowerCase().split(/([^a-z]|[^\x00-\x7F])/ document.addEventListener("nav", async (e: unknown) => { const currentSlug = (e as CustomEventMap["nav"]).detail.url - // setup index if it hasn't been already const data = await fetchData - if (!index) { - index = new Document({ - cache: true, - charset: 'latin:extra', - optimize: true, - encode: encoder, - document: { - id: "slug", - index: [ - { - field: "title", - tokenize: "forward", - }, - { - field: "content", - tokenize: "reverse", - }, - ] - }, - }) - - for (const [slug, fileData] of Object.entries<ContentDetails>(data)) { - await index.addAsync(slug, { - slug, - title: fileData.title, - content: fileData.content - }) - } - } - const container = document.getElementById("search-container") const searchIcon = document.getElementById("search-icon") const searchBar = document.getElementById("search-bar") as HTMLInputElement | null @@ -176,6 +145,37 @@ document.addEventListener("nav", async (e: unknown) => { searchIcon?.addEventListener("click", showSearch) searchBar?.removeEventListener("input", onType) searchBar?.addEventListener("input", onType) + + // setup index if it hasn't been already + if (!index) { + index = new Document({ + cache: true, + charset: 'latin:extra', + optimize: true, + encode: encoder, + document: { + id: "slug", + index: [ + { + field: "title", + tokenize: "forward", + }, + { + field: "content", + tokenize: "reverse", + }, + ] + }, + }) + + for (const [slug, fileData] of Object.entries<ContentDetails>(data)) { + await index.addAsync(slug, { + slug, + title: fileData.title, + content: fileData.content + }) + } + } // register handlers registerEscapeHandler(container, hideSearch) diff --git a/quartz/components/styles/darkmode.scss b/quartz/components/styles/darkmode.scss index 0edfebd..10cbc72 100644 --- a/quartz/components/styles/darkmode.scss +++ b/quartz/components/styles/darkmode.scss @@ -2,7 +2,7 @@ position: relative; width: 20px; height: 20px; - margin: 1rem; + margin: 0 10px; & > .toggle { display: none; diff --git a/quartz/components/styles/footer.scss b/quartz/components/styles/footer.scss index 16df545..565f9e3 100644 --- a/quartz/components/styles/footer.scss +++ b/quartz/components/styles/footer.scss @@ -1,6 +1,5 @@ footer { text-align: left; - opacity: 0.8; margin-bottom: 4rem; & ul { diff --git a/quartz/components/styles/popover.scss b/quartz/components/styles/popover.scss index 05c6dc7..a372299 100644 --- a/quartz/components/styles/popover.scss +++ b/quartz/components/styles/popover.scss @@ -29,11 +29,11 @@ line-height: normal; font-size: initial; font-family: var(--bodyFont); - border: 1px solid var(--gray); + border: 1px solid var(--lightgray); background-color: var(--light); border-radius: 5px; box-shadow: 6px 6px 36px 0 rgba(0,0,0,0.25); - overflow: scroll; + overflow: auto; } h1 { diff --git a/quartz/components/styles/search.scss b/quartz/components/styles/search.scss index 1f0a8b5..fe94ec7 100644 --- a/quartz/components/styles/search.scss +++ b/quartz/components/styles/search.scss @@ -12,6 +12,7 @@ display: flex; align-items: center; cursor: pointer; + white-space: nowrap; & > div { flex-grow: 1; @@ -38,12 +39,13 @@ & > #search-container { position: fixed; + contain: layout; z-index: 999; left: 0; top: 0; width: 100vw; height: 100vh; - overflow: scroll; + overflow-y: auto; display: none; backdrop-filter: blur(4px); @@ -57,7 +59,7 @@ margin-left: auto; margin-right: auto; - @media all and (max-width: $tabletBreakpoint) { + @media all and (max-width: $fullPageWidth) { width: 90%; } diff --git a/quartz/components/styles/toc.scss b/quartz/components/styles/toc.scss index eee3ee8..08e9548 100644 --- a/quartz/components/styles/toc.scss +++ b/quartz/components/styles/toc.scss @@ -29,7 +29,7 @@ button#toc { list-style: none; overflow: hidden; max-height: none; - transition: max-height 0.3s ease; + transition: max-height 0.5s ease; & ul { list-style: none; diff --git a/quartz/components/types.ts b/quartz/components/types.ts index d1c153d..b37ccee 100644 --- a/quartz/components/types.ts +++ b/quartz/components/types.ts @@ -11,6 +11,9 @@ export type QuartzComponentProps = { children: (QuartzComponent | JSX.Element)[] tree: Node<QuartzPluginData> allFiles: QuartzPluginData[] + displayClass?: 'mobile-only' | 'desktop-only' +} & JSX.IntrinsicAttributes & { + [key: string]: any } export type QuartzComponent = ComponentType<QuartzComponentProps> & { diff --git a/quartz/styles/base.scss b/quartz/styles/base.scss index e741755..4d1145d 100644 --- a/quartz/styles/base.scss +++ b/quartz/styles/base.scss @@ -43,71 +43,23 @@ a { } } -.page { - & > .page-header { - max-width: $pageWidth; - margin: $topSpacing auto 0 auto; - } - - & > #quartz-body { - width: 100%; - display: flex; - - & .left, & .right { - flex: 1; - width: calc(calc(100vw - $pageWidth) / 2); - } - - & .left-inner, & .right-inner { - display: flex; - flex-direction: column; - gap: 2rem; - top: 0; - width: $sidePanelWidth; - margin-top: $topSpacing; - box-sizing: border-box; - padding: 0 4rem; - position: fixed; - } - - & .left-inner { - left: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); - } - - & .right-inner { - right: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); - } - - & .center { - width: $pageWidth; - margin: 0 auto; - } - } -} - .desktop-only { display: initial; - @media all and (max-width: ($pageWidth + 2 * $sidePanelWidth)) { + @media all and (max-width: $fullPageWidth) { display: none; } } .mobile-only { display: none; - @media all and (max-width: ($pageWidth + 2 * $sidePanelWidth)) { + @media all and (max-width: $fullPageWidth) { display: initial; } } .page { - @media all and (max-width: $tabletBreakpoint) { - margin: 25px 5vw; - & .left, & .right { - padding: 0; - height: initial; - max-width: none; - position: initial; - } + @media all and (max-width: $fullPageWidth) { + margin: 0 5vw; } & p { @@ -129,6 +81,78 @@ a { padding-left: 0; } } + + & > #quartz-body { + width: 100%; + display: flex; + @media all and (max-width: $fullPageWidth) { + flex-direction: column; + } + + & .left, & .right { + flex: 1; + width: calc(calc(100vw - $pageWidth) / 2); + @media all and (max-width: $fullPageWidth) { + width: initial; + } + } + + & .left-inner, & .right-inner { + display: flex; + flex-direction: column; + gap: 2rem; + top: 0; + width: $sidePanelWidth; + margin-top: $topSpacing; + box-sizing: border-box; + padding: 0 4rem; + position: fixed; + @media all and (max-width: $fullPageWidth) { + position: initial; + flex-direction: row; + padding: 0; + width: initial; + margin-top: 4rem; + } + } + + & .left-inner { + left: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); + @media all and (max-width: $fullPageWidth) { + gap: 1rem; + align-items: center; + } + } + + & .right-inner { + right: calc(calc(100vw - $pageWidth) / 2 - $sidePanelWidth); + & > * { + @media all and (max-width: $fullPageWidth) { + flex: 1; + } + } + } + } + + & .page-header { + width: $pageWidth; + margin: $topSpacing auto 0 auto; + @media all and (max-width: $fullPageWidth) { + width: initial; + margin-top: 2rem; + } + } + + & .center, & footer { + width: $pageWidth; + margin-left: auto; + margin-right: auto; + @media all and (max-width: $fullPageWidth) { + width: initial; + margin-left: 0; + margin-right: 0; + } + } } input[type="checkbox"] { @@ -200,7 +224,7 @@ pre { font-family: var(--codeFont); padding: 0.5rem; border-radius: 5px; - overflow-x: scroll; + overflow-x: auto; border: 1px solid var(--lightgray); & > code { @@ -301,3 +325,23 @@ audio, video { .spacer { flex: 1 1 auto; } + +ul.overflow, ol.overflow { + height: 400px; + overflow-y: scroll; + + & > li:last-of-type { + margin-bottom: 50px; + } + + &:after { + pointer-events: none; + content: ''; + width: 100%; + height: 50px; + position: absolute; + left: 0; + bottom: 0; + background: linear-gradient(transparent 0px, var(--light)); + } +} diff --git a/quartz/styles/variables.scss b/quartz/styles/variables.scss index 792223b..6dd5614 100644 --- a/quartz/styles/variables.scss +++ b/quartz/styles/variables.scss @@ -1,5 +1,6 @@ -$pageWidth: 800px; +$pageWidth: 750px; $mobileBreakpoint: 600px; $tabletBreakpoint: 1200px; $sidePanelWidth: 400px; $topSpacing: 6rem; +$fullPageWidth: $pageWidth + 2 * $sidePanelWidth