From b3480bdc49120010da8d2805df02cbf84ca08bdc Mon Sep 17 00:00:00 2001
From: Jacky Zhao <j.zhao2k19@gmail.com>
Date: Fri, 07 Jul 2023 02:18:18 +0000
Subject: [PATCH] fix styling for bullet points

---
 quartz/plugins/transformers/ofm.ts |   80 +++++++++++++++++++++++++++++-----------
 1 files changed, 58 insertions(+), 22 deletions(-)

diff --git a/quartz/plugins/transformers/ofm.ts b/quartz/plugins/transformers/ofm.ts
index aa83953..0e694d3 100644
--- a/quartz/plugins/transformers/ofm.ts
+++ b/quartz/plugins/transformers/ofm.ts
@@ -3,10 +3,13 @@
 import { Root, HTML, BlockContent, DefinitionContent, Code } from 'mdast'
 import { findAndReplace } from "mdast-util-find-and-replace"
 import { slugify } from "../../path"
+import { slug as slugAnchor } from 'github-slugger'
 import rehypeRaw from "rehype-raw"
 import { visit } from "unist-util-visit"
 import path from "path"
 import { JSResource } from "../../resources"
+// @ts-ignore
+import calloutScript from "../../components/scripts/callout.inline.ts"
 
 export interface Options {
   highlight: boolean
@@ -92,21 +95,43 @@
   return s.substring(0, 1).toUpperCase() + s.substring(1);
 }
 
+// Match wikilinks 
+// !?               -> optional embedding
+// \[\[             -> open brace
+// ([^\[\]\|\#]+)   -> one or more non-special characters ([,],|, or #) (name)
+// (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
+// (|[^\[\]\|\#]+)? -> | then one or more non-special characters (alias)
+const backlinkRegex = new RegExp(/!?\[\[([^\[\]\|\#]+)(#[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/, "g")
+
+// Match highlights 
+const highlightRegex = new RegExp(/==(.+)==/, "g")
+
+// from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts
+const calloutRegex = new RegExp(/^\[\!(\w+)\]([+-]?)/)
+
 export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options> | undefined> = (userOpts) => {
   const opts = { ...defaultOptions, ...userOpts }
   return {
     name: "ObsidianFlavoredMarkdown",
+    textTransform(src) {
+      // pre-transform wikilinks (fix anchors to things that may contain illegal syntax e.g. codeblocks, latex)
+      if (opts.wikilinks) {
+        src = src.toString()
+        return src.replaceAll(backlinkRegex, (value, ...capture) => {
+          const [fp, rawHeader, rawAlias] = capture
+          const anchor = rawHeader?.trim().slice(1)
+          const displayAnchor = anchor ? `#${slugAnchor(anchor)}` : ""
+          const displayAlias = rawAlias ?? ""
+          const embedDisplay = value.startsWith("!") ? "!" : ""
+          return `${embedDisplay}[[${fp}${displayAnchor}${displayAlias}]]`
+        })
+      }
+      return src
+    },
     markdownPlugins() {
       const plugins: PluggableList = []
       if (opts.wikilinks) {
         plugins.push(() => {
-          // Match wikilinks 
-          // !?               -> optional embedding
-          // \[\[             -> open brace
-          // ([^\[\]\|\#]+)   -> one or more non-special characters ([,],|, or #) (name)
-          // (#[^\[\]\|\#]+)? -> # then one or more non-special characters (heading link)
-          // (|[^\[\]\|\#]+)? -> | then one or more non-special characters (alias)
-          const backlinkRegex = new RegExp(/!?\[\[([^\[\]\|\#]+)(#[^\[\]\|\#]+)?(\|[^\[\]\|\#]+)?\]\]/, "g")
           return (tree: Root, _file) => {
             findAndReplace(tree, backlinkRegex, (value: string, ...capture: string[]) => {
               const [fp, rawHeader, rawAlias] = capture
@@ -168,8 +193,6 @@
 
       if (opts.highlight) {
         plugins.push(() => {
-          // Match highlights 
-          const highlightRegex = new RegExp(/==(.+)==/, "g")
           return (tree: Root, _file) => {
             findAndReplace(tree, highlightRegex, (_value: string, ...capture: string[]) => {
               const [inner] = capture
@@ -184,8 +207,6 @@
 
       if (opts.callouts) {
         plugins.push(() => {
-          // from https://github.com/escwxyz/remark-obsidian-callout/blob/main/src/index.ts
-          const calloutRegex = new RegExp(/^\[\!(\w+)\]([+-]?)/)
           return (tree: Root, _file) => {
             visit(tree, "blockquote", (node) => {
               if (node.children.length === 0) {
@@ -199,6 +220,7 @@
               }
 
               const text = firstChild.children[0].value
+              const restChildren = firstChild.children.splice(1)
               const [firstLine, ...remainingLines] = text.split("\n")
               const remainingText = remainingLines.join("\n")
 
@@ -210,6 +232,10 @@
                 const defaultState = collapseChar === "-" ? "collapsed" : "expanded"
                 const title = match.input.slice(calloutDirective.length).trim() || capitalize(calloutType)
 
+                const toggleIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="fold">
+                  <polyline points="6 9 12 15 18 9"></polyline>
+                </svg>`
+
                 const titleNode: HTML = {
                   type: "html",
                   value: `<div 
@@ -217,6 +243,7 @@
                 >
                   <div class="callout-icon">${callouts[canonicalizeCallout(calloutType)]}</div>
                   <div class="callout-title-inner">${title}</div>
+                  ${collapse ? toggleIcon : ""}
                 </div>`
                 }
 
@@ -227,8 +254,7 @@
                     children: [{
                       type: 'text',
                       value: remainingText,
-                    }]
-
+                    }, ...restChildren]
                   })
                 }
 
@@ -236,7 +262,6 @@
                 node.children.splice(0, 1, ...blockquoteContent)
 
                 // add properties to base blockquote
-                // TODO: add the js to actually support collapsing callout
                 node.data = {
                   hProperties: {
                     ...(node.data?.hProperties ?? {}),
@@ -273,18 +298,29 @@
       return [rehypeRaw]
     },
     externalResources() {
-      const mermaidScript: JSResource = {
-        script: `
+      const js: JSResource[] = []
+
+      if (opts.callouts) {
+        js.push({
+          script: calloutScript,
+          loadTime: 'afterDOMReady',
+          contentType: 'inline'
+        })
+      }
+
+      if (opts.mermaid) {
+        js.push({
+          script: `
           import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
           mermaid.initialize({ startOnLoad: true });
           `,
-        loadTime: 'afterDOMReady',
-        moduleType: 'module',
-        contentType: 'inline'
+          loadTime: 'afterDOMReady',
+          moduleType: 'module',
+          contentType: 'inline'
+        })
       }
-      return {
-        js: opts.mermaid ? [mermaidScript] : []
-      }
+
+      return { js }
     }
   }
 }

--
Gitblit v1.10.0