feat: Add renderer for Markdown alerts

This commit is contained in:
Shaun Gallagher 2025-03-14 15:22:27 -04:00
parent b03fc97e28
commit 8bc797fe6a

View File

@ -0,0 +1,116 @@
<script lang="ts" context="module">
import { marked, type Token } from 'marked';
type AlertType = "NOTE" | "TIP" | "IMPORTANT" | "WARNING" | "CAUTION";
interface AlertTheme {
border: string;
text: string;
icon: ComponentType;
}
export interface AlertData {
type: AlertType;
text: string;
tokens: Token[];
}
const alertStyles: Record<AlertType, AlertTheme> = {
"NOTE": {
border: "border-sky-500",
text: "text-sky-500",
icon: Info
},
"TIP": {
border: "border-emerald-500",
text: "text-emerald-500",
icon: LightBlub
},
"IMPORTANT": {
border: "border-purple-500",
text: "text-purple-500",
icon: Star
},
"WARNING": {
border: "border-yellow-500",
text: "text-yellow-500",
icon: ArrowRightCircle
},
"CAUTION": {
border: "border-rose-500",
text: "text-rose-500",
icon: Bolt
}
};
export function alertComponent(token: Token): AlertData | false {
const regExpStr = `^(?:\\[!(NOTE|TIP|IMPORTANT|WARNING|CAUTION)\\])\\s*?\n*`;
const regExp = new RegExp(regExpStr);
const matches = token.text?.match(regExp);
if (matches && matches.length) {
const alertType = matches[1] as AlertType;
const newText = token.text.replace(regExp, '');
const newTokens = marked.lexer(newText);
return {
type: alertType,
text: newText,
tokens: newTokens
};
}
return false;
}
</script>
<script lang="ts">
import Info from '$lib/components/icons/Info.svelte';
import Star from '$lib/components/icons/Star.svelte';
import LightBlub from '$lib/components/icons/LightBlub.svelte';
import Bolt from '$lib/components/icons/Bolt.svelte';
import ArrowRightCircle from '$lib/components/icons/ArrowRightCircle.svelte';
import MarkdownTokens from './MarkdownTokens.svelte';
import type { ComponentType } from 'svelte';
export let token: Token;
export let alert: AlertData;
export let id = '';
export let tokenIdx = 0;
export let onTaskClick: ((event: MouseEvent) => void) | undefined = undefined;
export let onSourceClick: ((event: MouseEvent) => void) | undefined = undefined;
</script>
<!--
Renders the following Markdown as alerts:
> [!NOTE]
> Example note
> [!TIP]
> Example tip
> [!IMPORTANT]
> Example important
> [!CAUTION]
> Example caution
> [!WARNING]
> Example warning
-->
<div class={`border-l-2 pl-2 ${alertStyles[alert.type].border}`}>
<p class={alertStyles[alert.type].text}>
<svelte:component
this={alertStyles[alert.type].icon}
className="inline-block size-4"
/>
<b>{alert.type}</b>
</p>
<MarkdownTokens
id={`${id}-${tokenIdx}`}
tokens={alert.tokens}
{onTaskClick}
{onSourceClick}
/>
</div>