80 lines
2.0 KiB
Vue
80 lines
2.0 KiB
Vue
<template>
|
|
<div ref="element"></div>
|
|
</template>
|
|
|
|
<script setup lang="ts">
|
|
import { heading } from 'hast-util-heading';
|
|
import { headingRank } from 'hast-util-heading-rank';
|
|
import { parseId } from '~/shared/general.util';
|
|
import type { Root } from 'hast';
|
|
import { renderMarkdown } from '~/shared/markdown.util';
|
|
import { tag, a, blockquote, h1, h2, h3, h4, h5, hr, li, small, table, td, th, type Prose } from '~/shared/proses';
|
|
import { callout } from '../shared/proses';
|
|
|
|
const { content, proses, filter } = defineProps<{
|
|
content: string
|
|
proses?: Record<string, Prose>
|
|
filter?: string
|
|
}>();
|
|
const element = useTemplateRef('element');
|
|
|
|
const parser = useMarkdown(), data = ref<Root>();
|
|
const node = computed(() => content ? parser.parseSync(content) : undefined);
|
|
watch([node], () => {
|
|
if(!node.value)
|
|
{
|
|
data.value = undefined;
|
|
return;
|
|
}
|
|
else if(!filter)
|
|
{
|
|
data.value = node.value;
|
|
}
|
|
else
|
|
{
|
|
const start = node.value?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1;
|
|
|
|
if(start === -1)
|
|
data.value = node.value;
|
|
else
|
|
{
|
|
let end = start;
|
|
const rank = headingRank(node.value.children[start])!;
|
|
while(end < node.value.children.length)
|
|
{
|
|
end++;
|
|
if(heading(node.value.children[end]) && headingRank(node.value.children[end])! <= rank)
|
|
break;
|
|
}
|
|
data.value = { ...node.value, children: node.value.children.slice(start, end) };
|
|
}
|
|
}
|
|
|
|
mount();
|
|
}, { immediate: true, });
|
|
|
|
onMounted(() => {
|
|
mount();
|
|
})
|
|
|
|
function mount()
|
|
{
|
|
if(!element.value || !data.value)
|
|
return;
|
|
|
|
const el = element.value!;
|
|
|
|
for(let i = el.childElementCount - 1; i >= 0; i--)
|
|
{
|
|
el.removeChild(el.children[i]);
|
|
}
|
|
|
|
el.appendChild(renderMarkdown(data.value, { tag, a, blockquote, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th, ...proses }));
|
|
|
|
const hash = useRouter().currentRoute.value.hash;
|
|
if(hash.length > 0)
|
|
{
|
|
document.getElementById(parseId(hash.substring(1))!)?.scrollIntoView({ behavior: 'instant' })
|
|
}
|
|
}
|
|
</script> |