From cb89cce183215f6a8edcb6d166875e2982586002 Mon Sep 17 00:00:00 2001
From: Jacky Zhao <j.zhao2k19@gmail.com>
Date: Sat, 17 Jun 2023 14:36:06 -0700
Subject: [PATCH] basic left,right layout

---
 quartz.config.ts                            | 11 +++++----
 quartz/components/TagList.tsx               |  2 +-
 quartz/components/scripts/callout.inline.ts | 26 +++++++++++----------
 quartz/components/scripts/toc.inline.ts     | 13 +++++++----
 quartz/components/styles/darkmode.scss      |  4 ----
 quartz/plugins/emitters/contentPage.tsx     | 20 ++++++++++++----
 quartz/plugins/transformers/ofm.ts          |  2 --
 quartz/styles/base.scss                     | 23 ++++++++++++++++++
 quartz/styles/callouts.scss                 |  5 +++-
 9 files changed, 73 insertions(+), 33 deletions(-)

diff --git a/quartz.config.ts b/quartz.config.ts
index 0c77c90..e18f8ba 100644
--- a/quartz.config.ts
+++ b/quartz.config.ts
@@ -59,15 +59,16 @@ const config: QuartzConfig = {
       Plugin.ContentPage({
         head: Component.Head(),
         header: [Component.PageTitle(), Component.Spacer(), Component.Darkmode()],
-        body: [
+        beforeBody: [
           Component.ArticleTitle(),
           Component.ReadingTime(),
           Component.TagList(),
-          Component.TableOfContents(),
-          Component.Content()
         ],
-        left: [],
-        right: [],
+        left: [
+          Component.TableOfContents(),
+        ],
+        right: [
+        ],
         footer: []
       }),
       Plugin.ContentIndex(), // you can exclude this if you don't plan on using popovers, graph, or backlinks,
diff --git a/quartz/components/TagList.tsx b/quartz/components/TagList.tsx
index a462e95..65286a5 100644
--- a/quartz/components/TagList.tsx
+++ b/quartz/components/TagList.tsx
@@ -6,7 +6,7 @@ function TagList({ fileData }: QuartzComponentProps) {
   const tags = fileData.frontmatter?.tags
   const slug = fileData.slug!
   const baseDir = resolveToRoot(slug)
-  if (tags) {
+  if (tags && tags.length > 0) {
     return <ul class="tags">{tags.map(tag => {
       const display = `#${tag}`
       const linkDest = baseDir + `/tags/${slugAnchor(tag)}`
diff --git a/quartz/components/scripts/callout.inline.ts b/quartz/components/scripts/callout.inline.ts
index 5f35873..081a5a2 100644
--- a/quartz/components/scripts/callout.inline.ts
+++ b/quartz/components/scripts/callout.inline.ts
@@ -6,19 +6,21 @@ function toggleCallout(this: HTMLElement) {
   outerBlock.style.maxHeight = height + `px`
 }
 
-function setupCallout(div: HTMLElement) {
-  const collapsed = div.classList.contains(`is-collapsed`)
-  const title = div.firstElementChild!
-  const height = collapsed ? title.scrollHeight : div.scrollHeight
-  div.style.maxHeight = height + `px`
-}
-
-document.addEventListener(`nav`, () => {
+function setupCallout() {
   const collapsible = document.getElementsByClassName(`callout is-collapsible`) as HTMLCollectionOf<HTMLElement>
   for (const div of collapsible) {
     const title = div.firstElementChild
-    setupCallout(div)
-    title?.removeEventListener(`click`, toggleCallout)
-    title?.addEventListener(`click`, toggleCallout)
+
+    if (title) {
+      title.removeEventListener(`click`, toggleCallout)
+      title.addEventListener(`click`, toggleCallout)
+
+      const collapsed = div.classList.contains(`is-collapsed`)
+      const height = collapsed ? title.scrollHeight : div.scrollHeight
+      div.style.maxHeight = height + `px`
+    }
   }
-})
+}
+
+document.addEventListener(`nav`, setupCallout)
+window.addEventListener(`resize`, setupCallout)
diff --git a/quartz/components/scripts/toc.inline.ts b/quartz/components/scripts/toc.inline.ts
index 405a21f..105889d 100644
--- a/quartz/components/scripts/toc.inline.ts
+++ b/quartz/components/scripts/toc.inline.ts
@@ -14,19 +14,24 @@ const observer = new IntersectionObserver(entries => {
   }
 })
 
-function toggleCollapsible(this: HTMLElement) {
+function toggleToc(this: HTMLElement) {
   this.classList.toggle("collapsed")
   const content = this.nextElementSibling as HTMLElement
   content.classList.toggle("collapsed")
   content.style.maxHeight = content.style.maxHeight === "0px" ? content.scrollHeight + "px" : "0px"
 }
 
-document.addEventListener("nav", () => {
+function setupToc() {
   const toc = document.getElementById("toc")!
   const content = toc.nextElementSibling as HTMLElement
   content.style.maxHeight = content.scrollHeight + "px"
-  toc.removeEventListener("click", toggleCollapsible)
-  toc.addEventListener("click", toggleCollapsible)
+  toc.removeEventListener("click", toggleToc)
+  toc.addEventListener("click", toggleToc)
+}
+
+window.addEventListener("resize", setupToc)
+document.addEventListener("nav", () => {
+  setupToc()
 
   // update toc entry highlighting
   observer.disconnect()
diff --git a/quartz/components/styles/darkmode.scss b/quartz/components/styles/darkmode.scss
index 561a83c..46291d8 100644
--- a/quartz/components/styles/darkmode.scss
+++ b/quartz/components/styles/darkmode.scss
@@ -4,10 +4,6 @@
   min-width: 30px;
   position: relative;
 
-  @media all and (max-width: 450px) {
-    padding: 1rem;
-  }
-
   & > .toggle {
     display: none;
     box-sizing: border-box;
diff --git a/quartz/plugins/emitters/contentPage.tsx b/quartz/plugins/emitters/contentPage.tsx
index 7afab9d..ea626f5 100644
--- a/quartz/plugins/emitters/contentPage.tsx
+++ b/quartz/plugins/emitters/contentPage.tsx
@@ -6,11 +6,12 @@ import { resolveToRoot } from "../../path"
 import HeaderConstructor from "../../components/Header"
 import { QuartzComponentProps } from "../../components/types"
 import BodyConstructor from "../../components/Body"
+import ContentConstructor from "../../components/Content"
 
 interface Options {
   head: QuartzComponent
   header: QuartzComponent[],
-  body: QuartzComponent[],
+  beforeBody: QuartzComponent[],
   left: QuartzComponent[],
   right: QuartzComponent[],
   footer: QuartzComponent[],
@@ -21,14 +22,15 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
     throw new Error("ContentPage must be initialized with options specifiying the components to use")
   }
 
-  const { head: Head, header, body } = opts
+  const { head: Head, header, beforeBody, left, right, footer } = opts
   const Header = HeaderConstructor()
   const Body = BodyConstructor()
+  const Content = ContentConstructor()
 
   return {
     name: "ContentPage",
     getQuartzComponents() {
-      return [opts.head, Header, Body, ...opts.header, ...opts.body, ...opts.left, ...opts.right, ...opts.footer]
+      return [opts.head, Header, Body, ...opts.header, ...opts.beforeBody, ...opts.left, ...opts.right, ...opts.footer]
     },
     async emit(_contentDir, cfg, content, resources, emit): Promise<string[]> {
       const fps: string[] = []
@@ -59,9 +61,19 @@ export const ContentPage: QuartzEmitterPlugin<Options> = (opts) => {
               <Header {...componentData} >
                 {header.map(HeaderComponent => <HeaderComponent {...componentData} />)}
               </Header>
+              {beforeBody.map(BodyComponent => <BodyComponent {...componentData} />)}
               <Body {...componentData}>
-                {body.map(BodyComponent => <BodyComponent {...componentData} />)}
+                <div class="left">
+                  {left.map(BodyComponent => <BodyComponent {...componentData} />)}
+                </div>
+                <div class="center">
+                  <Content {...componentData} />
+                </div>
+                <div class="right">
+                  {right.map(BodyComponent => <BodyComponent {...componentData} />)}
+                </div>
               </Body>
+
             </div>
           </body>
           {pageResources.js.filter(resource => resource.loadTime === "afterDOMReady").map(res => JSResourceToScriptElement(res))}
diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts
index 4ade476..3742d4b 100644
--- a/quartz/plugins/transformers/ofm.ts
+++ b/quartz/plugins/transformers/ofm.ts
@@ -300,8 +300,6 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
         })
       }
 
-      console.log(js)
-
       return { js }
     }
   }
diff --git a/quartz/styles/base.scss b/quartz/styles/base.scss
index d7a1891..9fc76f9 100644
--- a/quartz/styles/base.scss
+++ b/quartz/styles/base.scss
@@ -51,8 +51,31 @@ a {
   padding: 4rem 30vw;
   margin: 0 auto;
   max-width: 1000px;
+  position: relative;
+
+  & .left, & .right {
+    position: fixed;
+    padding: 0 4rem 0 6rem;
+    max-width: 30vw;
+    box-sizing: border-box;
+    top: 10rem;
+  }
+  
+  & .left {
+    left: 0;
+  }
+
+  & .right {
+    right: 0;
+  }
+
   @media all and (max-width: 1200px) {
     padding: 25px 5vw;
+    & .left, & .right {
+      padding: 0;
+      max-width: none;
+      position: initial;
+    }
   }
 
   & p {
diff --git a/quartz/styles/callouts.scss b/quartz/styles/callouts.scss
index 84d70b4..d33d78b 100644
--- a/quartz/styles/callouts.scss
+++ b/quartz/styles/callouts.scss
@@ -8,6 +8,10 @@
 	overflow-y: hidden;
   transition: max-height 0.3s ease;
 
+  & > *:nth-child(2) {
+    margin-top: 0;
+  }
+
 	&[data-callout="note"] {
 	  --color: #448aff;
 	  --border: #448aff22;
@@ -74,7 +78,6 @@
 	align-items: center;
 	gap: 5px;
 	padding: 1rem 0;
-	margin-bottom: -1rem;
 	color: var(--color);
 
 	& .fold {