mirror of
https://github.com/thiloho/archtika.git
synced 2025-11-22 10:51:36 +01:00
Use marked for markdown parsing
This commit is contained in:
@@ -33,7 +33,7 @@
|
||||
<h1>{title}</h1>
|
||||
|
||||
<nav class="operations__nav">
|
||||
<ul>
|
||||
<ul class="unpadded">
|
||||
<li>
|
||||
<a href="/website/{id}">Settings</a>
|
||||
</li>
|
||||
@@ -56,7 +56,11 @@
|
||||
{#if fullPreview}
|
||||
<iframe src={previewContent} title="Preview"></iframe>
|
||||
{:else}
|
||||
{@html md.render(previewContent)}
|
||||
{#await md(previewContent)}
|
||||
<p>Loading preview...</p>
|
||||
{:then content}
|
||||
{@html content}
|
||||
{/await}
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
<section class="articles">
|
||||
<h2>Articles</h2>
|
||||
|
||||
<ul>
|
||||
<ul class="unpadded">
|
||||
{#each articles as article}
|
||||
{@const articleFileName = article.title.toLowerCase().split(" ").join("-")}
|
||||
<li>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import markdownit from "markdown-it";
|
||||
import { Marked } from "marked";
|
||||
import hljs from "highlight.js";
|
||||
import type { StateCore } from "markdown-it/index.js";
|
||||
import { markedHighlight } from "marked-highlight";
|
||||
|
||||
export const sortOptions = [
|
||||
{ value: "creation-time", text: "Creation time" },
|
||||
@@ -11,106 +11,33 @@ export const sortOptions = [
|
||||
|
||||
export const ALLOWED_MIME_TYPES = ["image/jpeg", "image/png", "image/svg+xml", "image/webp"];
|
||||
|
||||
export const md = markdownit({
|
||||
linkify: true,
|
||||
typographer: true,
|
||||
highlight: (str: string, lang: string) => {
|
||||
if (lang && hljs.getLanguage(lang)) {
|
||||
try {
|
||||
return hljs.highlight(str, { language: lang }).value;
|
||||
} catch (_) {}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
}).use((md) => {
|
||||
const addSections = (state: StateCore) => {
|
||||
const tokens = [];
|
||||
const Token = state.Token;
|
||||
const sections: { header: number; nesting: number }[] = [];
|
||||
let nestedLevel = 0;
|
||||
|
||||
const slugify = (text: string) => {
|
||||
return text
|
||||
.toLowerCase()
|
||||
.replace(/\s+/g, "-")
|
||||
.replace(/[^\w-]+/g, "")
|
||||
.replace(/--+/g, "-")
|
||||
.replace(/^-+/, "")
|
||||
.replace(/-+$/, "");
|
||||
};
|
||||
|
||||
const openSection = (attrs: [string, string][] | null, headingText: string) => {
|
||||
const t = new Token("section_open", "section", 1);
|
||||
t.block = true;
|
||||
t.attrs = attrs ? attrs.map((attr) => [attr[0], attr[1]]) : [];
|
||||
t.attrs.push(["id", slugify(headingText)]);
|
||||
return t;
|
||||
};
|
||||
|
||||
const closeSection = () => {
|
||||
const t = new Token("section_close", "section", -1);
|
||||
t.block = true;
|
||||
return t;
|
||||
};
|
||||
|
||||
const closeSections = (section: { header: number; nesting: number }) => {
|
||||
while (sections.length && section.header <= sections[sections.length - 1].header) {
|
||||
sections.pop();
|
||||
tokens.push(closeSection());
|
||||
const createMarkdownParser = () => {
|
||||
const marked = new Marked(
|
||||
markedHighlight({
|
||||
langPrefix: "hljs language-",
|
||||
highlight(code, lang) {
|
||||
const language = hljs.getLanguage(lang) ? lang : "plaintext";
|
||||
return hljs.highlight(code, { language }).value;
|
||||
}
|
||||
};
|
||||
})
|
||||
);
|
||||
|
||||
const closeSectionsToCurrentNesting = (nesting: number) => {
|
||||
while (sections.length && nesting < sections[sections.length - 1].nesting) {
|
||||
sections.pop();
|
||||
tokens.push(closeSection());
|
||||
}
|
||||
};
|
||||
marked.use({
|
||||
async: true,
|
||||
pedantic: false,
|
||||
gfm: true
|
||||
});
|
||||
|
||||
const closeAllSections = () => {
|
||||
while (sections.pop()) {
|
||||
tokens.push(closeSection());
|
||||
}
|
||||
};
|
||||
return marked;
|
||||
};
|
||||
|
||||
for (let i = 0; i < state.tokens.length; i++) {
|
||||
const token = state.tokens[i];
|
||||
if (token.type.search("heading") !== 0) {
|
||||
nestedLevel += token.nesting;
|
||||
}
|
||||
if (sections.length && nestedLevel < sections[sections.length - 1].nesting) {
|
||||
closeSectionsToCurrentNesting(nestedLevel);
|
||||
}
|
||||
const marked = createMarkdownParser();
|
||||
|
||||
if (token.type === "heading_open") {
|
||||
const section: { header: number; nesting: number } = {
|
||||
header: parseInt(token.tag.charAt(1)),
|
||||
nesting: nestedLevel
|
||||
};
|
||||
if (sections.length && section.header <= sections[sections.length - 1].header) {
|
||||
closeSections(section);
|
||||
}
|
||||
export const md = async (markdownContent: string) => {
|
||||
const html = await marked.parse(markdownContent);
|
||||
|
||||
const headingTextToken = state.tokens[i + 1];
|
||||
const headingText = headingTextToken.content;
|
||||
|
||||
tokens.push(openSection(token.attrs, headingText));
|
||||
const idIndex = token.attrIndex("id");
|
||||
if (idIndex !== -1) {
|
||||
token.attrs?.splice(idIndex, 1);
|
||||
}
|
||||
sections.push(section);
|
||||
}
|
||||
|
||||
tokens.push(token);
|
||||
}
|
||||
closeAllSections();
|
||||
|
||||
state.tokens = tokens;
|
||||
};
|
||||
|
||||
md.core.ruler.push("header_sections", addSections);
|
||||
});
|
||||
return html;
|
||||
};
|
||||
|
||||
export const handleImagePaste = async (event: ClipboardEvent, API_BASE_PREFIX: string) => {
|
||||
const clipboardItems = Array.from(event.clipboardData?.items || []);
|
||||
|
||||
Reference in New Issue
Block a user