75 lines
2.4 KiB
TypeScript
75 lines
2.4 KiB
TypeScript
import type { Root, RootContent } from "hast";
|
|
import { dom, styling, text, type Class, type Node } from "./dom.util";
|
|
import prose, { a, blockquote, tag, h1, h2, h3, h4, h5, hr, li, small, table, td, th, callout, type Prose } from "./proses";
|
|
import { heading } from "hast-util-heading";
|
|
import { headingRank } from "hast-util-heading-rank";
|
|
import { parseId } from "./general.util";
|
|
import { loading } from "#shared/proses";
|
|
|
|
export function renderMarkdown(markdown: Root, proses: Record<string, Prose>): HTMLDivElement
|
|
{
|
|
return dom('div', {}, markdown.children.map(e => renderContent(e, proses)));
|
|
}
|
|
|
|
function renderContent(node: RootContent, proses: Record<string, Prose>): Node
|
|
{
|
|
if(node.type === 'text' && node.value.length > 0 && node.value !== '\n')
|
|
{
|
|
return text(node.value);
|
|
}
|
|
else if(node.type === 'comment' && node.value.length > 0 && node.value !== '\n')
|
|
{
|
|
return undefined;
|
|
}
|
|
else if(node.type === 'element')
|
|
{
|
|
const children = node.children.map(e => renderContent(e, proses)), properties = { ...node.properties, class: node.properties.className as string | string[] };
|
|
if(node.tagName in proses)
|
|
return prose(node.tagName, proses[node.tagName], children, properties);
|
|
else
|
|
return dom(node.tagName as keyof HTMLElementTagNameMap, properties, children);
|
|
}
|
|
|
|
return undefined;
|
|
}
|
|
|
|
export interface MDProperties
|
|
{
|
|
class?: Class;
|
|
style?: string | Record<string, string>;
|
|
tags?: Record<string, Prose>;
|
|
}
|
|
export default function(content: string, filter?: string, properties?: MDProperties): HTMLElement
|
|
{
|
|
const load = loading('normal');
|
|
|
|
queueMicrotask(() => {
|
|
useMarkdown().parse(content).then(data => {
|
|
if(filter)
|
|
{
|
|
const start = data?.children.findIndex(e => heading(e) && parseId(e.properties.id as string | undefined) === filter) ?? -1;
|
|
|
|
if(start !== -1)
|
|
{
|
|
let end = start;
|
|
const rank = headingRank(data.children[start])!;
|
|
while(end < data.children.length)
|
|
{
|
|
end++;
|
|
if(heading(data.children[end]) && headingRank(data.children[end])! <= rank)
|
|
break;
|
|
}
|
|
data = { ...data, children: data.children.slice(start, end) };
|
|
}
|
|
}
|
|
|
|
const el = renderMarkdown(data, { a, blockquote, tag, callout, h1, h2, h3, h4, h5, hr, li, small, table, td, th, ...properties?.tags });
|
|
|
|
if(properties) styling(el, properties);
|
|
|
|
load.parentElement?.replaceChild(el, load);
|
|
});
|
|
})
|
|
|
|
return load;
|
|
} |