collapsible callout
This commit is contained in:
		
							parent
							
								
									6d5491fdcb
								
							
						
					
					
						commit
						b587782450
					
				
					 4 changed files with 68 additions and 12 deletions
				
			
		
							
								
								
									
										24
									
								
								quartz/components/scripts/callout.inline.ts
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								quartz/components/scripts/callout.inline.ts
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					function toggleCallout(this: HTMLElement) {
 | 
				
			||||||
 | 
					  const outerBlock = this.parentElement!
 | 
				
			||||||
 | 
					  this.classList.toggle(`is-collapsed`)
 | 
				
			||||||
 | 
					  const collapsed = this.classList.contains(`is-collapsed`)
 | 
				
			||||||
 | 
					  const height = collapsed ? this.scrollHeight : outerBlock.scrollHeight
 | 
				
			||||||
 | 
					  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`, () => {
 | 
				
			||||||
 | 
					  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)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					})
 | 
				
			||||||
| 
						 | 
					@ -83,7 +83,7 @@ export function getStaticResourcesFromPlugins(plugins: PluginTypes) {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  for (const transformer of plugins.transformers) {
 | 
					  for (const transformer of plugins.transformers) {
 | 
				
			||||||
    const res = transformer.externalResources
 | 
					    const res = transformer.externalResources ? transformer.externalResources() : {}
 | 
				
			||||||
    if (res?.js) {
 | 
					    if (res?.js) {
 | 
				
			||||||
      staticResources.js = staticResources.js.concat(res.js)
 | 
					      staticResources.js = staticResources.js.concat(res.js)
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -7,6 +7,8 @@ import rehypeRaw from "rehype-raw"
 | 
				
			||||||
import { visit } from "unist-util-visit"
 | 
					import { visit } from "unist-util-visit"
 | 
				
			||||||
import path from "path"
 | 
					import path from "path"
 | 
				
			||||||
import { JSResource } from "../../resources"
 | 
					import { JSResource } from "../../resources"
 | 
				
			||||||
 | 
					// @ts-ignore
 | 
				
			||||||
 | 
					import calloutScript from "../../components/scripts/callout.inline.ts"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface Options {
 | 
					export interface Options {
 | 
				
			||||||
  highlight: boolean
 | 
					  highlight: boolean
 | 
				
			||||||
| 
						 | 
					@ -210,6 +212,10 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
 | 
				
			||||||
                const defaultState = collapseChar === "-" ? "collapsed" : "expanded"
 | 
					                const defaultState = collapseChar === "-" ? "collapsed" : "expanded"
 | 
				
			||||||
                const title = match.input.slice(calloutDirective.length).trim() || capitalize(calloutType)
 | 
					                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 = {
 | 
					                const titleNode: HTML = {
 | 
				
			||||||
                  type: "html",
 | 
					                  type: "html",
 | 
				
			||||||
                  value: `<div 
 | 
					                  value: `<div 
 | 
				
			||||||
| 
						 | 
					@ -217,6 +223,7 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
 | 
				
			||||||
                >
 | 
					                >
 | 
				
			||||||
                  <div class="callout-icon">${callouts[canonicalizeCallout(calloutType)]}</div>
 | 
					                  <div class="callout-icon">${callouts[canonicalizeCallout(calloutType)]}</div>
 | 
				
			||||||
                  <div class="callout-title-inner">${title}</div>
 | 
					                  <div class="callout-title-inner">${title}</div>
 | 
				
			||||||
 | 
					                  ${collapse ? toggleIcon : ""}
 | 
				
			||||||
                </div>`
 | 
					                </div>`
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -228,7 +235,6 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
 | 
				
			||||||
                      type: 'text',
 | 
					                      type: 'text',
 | 
				
			||||||
                      value: remainingText,
 | 
					                      value: remainingText,
 | 
				
			||||||
                    }]
 | 
					                    }]
 | 
				
			||||||
 | 
					 | 
				
			||||||
                  })
 | 
					                  })
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -236,7 +242,6 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
 | 
				
			||||||
                node.children.splice(0, 1, ...blockquoteContent)
 | 
					                node.children.splice(0, 1, ...blockquoteContent)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // add properties to base blockquote
 | 
					                // add properties to base blockquote
 | 
				
			||||||
                // TODO: add the js to actually support collapsing callout
 | 
					 | 
				
			||||||
                node.data = {
 | 
					                node.data = {
 | 
				
			||||||
                  hProperties: {
 | 
					                  hProperties: {
 | 
				
			||||||
                    ...(node.data?.hProperties ?? {}),
 | 
					                    ...(node.data?.hProperties ?? {}),
 | 
				
			||||||
| 
						 | 
					@ -273,7 +278,18 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
 | 
				
			||||||
      return [rehypeRaw]
 | 
					      return [rehypeRaw]
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    externalResources() {
 | 
					    externalResources() {
 | 
				
			||||||
      const mermaidScript: JSResource = {
 | 
					      const js: JSResource[] = []
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (opts.callouts) {
 | 
				
			||||||
 | 
					        js.push({
 | 
				
			||||||
 | 
					          script: calloutScript,
 | 
				
			||||||
 | 
					          loadTime: 'afterDOMReady',
 | 
				
			||||||
 | 
					          contentType: 'inline'
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (opts.mermaid) {
 | 
				
			||||||
 | 
					        js.push({
 | 
				
			||||||
          script: `
 | 
					          script: `
 | 
				
			||||||
          import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
 | 
					          import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
 | 
				
			||||||
          mermaid.initialize({ startOnLoad: true });
 | 
					          mermaid.initialize({ startOnLoad: true });
 | 
				
			||||||
| 
						 | 
					@ -281,10 +297,12 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
 | 
				
			||||||
          loadTime: 'afterDOMReady',
 | 
					          loadTime: 'afterDOMReady',
 | 
				
			||||||
          moduleType: 'module',
 | 
					          moduleType: 'module',
 | 
				
			||||||
          contentType: 'inline'
 | 
					          contentType: 'inline'
 | 
				
			||||||
 | 
					        })
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return {
 | 
					
 | 
				
			||||||
        js: opts.mermaid ? [mermaidScript] : []
 | 
					      console.log(js)
 | 
				
			||||||
      }
 | 
					
 | 
				
			||||||
 | 
					      return { js }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,6 +5,8 @@
 | 
				
			||||||
	background-color: var(--bg);
 | 
						background-color: var(--bg);
 | 
				
			||||||
	border-radius: 5px;
 | 
						border-radius: 5px;
 | 
				
			||||||
	padding: 0 1rem;
 | 
						padding: 0 1rem;
 | 
				
			||||||
 | 
						overflow-y: hidden;
 | 
				
			||||||
 | 
					  transition: max-height 0.3s ease;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	&[data-callout="note"] {
 | 
						&[data-callout="note"] {
 | 
				
			||||||
	  --color: #448aff;
 | 
						  --color: #448aff;
 | 
				
			||||||
| 
						 | 
					@ -71,8 +73,20 @@
 | 
				
			||||||
	display: flex;
 | 
						display: flex;
 | 
				
			||||||
	align-items: center;
 | 
						align-items: center;
 | 
				
			||||||
	gap: 5px;
 | 
						gap: 5px;
 | 
				
			||||||
	margin: 1rem 0;
 | 
						padding: 1rem 0;
 | 
				
			||||||
 | 
						margin-bottom: -1rem;
 | 
				
			||||||
	color: var(--color);
 | 
						color: var(--color);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						& .fold {
 | 
				
			||||||
 | 
					    margin-left: 0.5rem; 
 | 
				
			||||||
 | 
					    transition: transform 0.3s ease;
 | 
				
			||||||
 | 
					    opacity: 0.8;
 | 
				
			||||||
 | 
					    cursor: pointer;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  &.is-collapsed .fold {
 | 
				
			||||||
 | 
					    transform: rotateZ(-90deg)
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
.callout-icon {
 | 
					.callout-icon {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue