collapsible callout

This commit is contained in:
Jacky Zhao 2023-06-17 13:08:06 -07:00
parent 6d5491fdcb
commit b587782450
4 changed files with 68 additions and 12 deletions

View 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)
}
})

View file

@ -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)
} }

View file

@ -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,18 +278,31 @@ export const ObsidianFlavoredMarkdown: QuartzTransformerPlugin<Partial<Options>
return [rehypeRaw] return [rehypeRaw]
}, },
externalResources() { externalResources() {
const mermaidScript: JSResource = { const js: JSResource[] = []
script: `
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'; import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
mermaid.initialize({ startOnLoad: true }); mermaid.initialize({ startOnLoad: true });
`, `,
loadTime: 'afterDOMReady', loadTime: 'afterDOMReady',
moduleType: 'module', moduleType: 'module',
contentType: 'inline' contentType: 'inline'
} })
return {
js: opts.mermaid ? [mermaidScript] : []
} }
console.log(js)
return { js }
} }
} }
} }

View file

@ -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 {