Files
fuz-site/src/islands/Markdown.jsx
2025-12-18 07:12:27 +01:00

84 lines
1.6 KiB
JavaScript

import { marked } from "marked";
marked.setOptions({
gfm: true,
breaks: true,
headerIds: false,
mangle: false,
sanitize: false,
smartLists: true,
smartypants: false,
});
function applyShortcodes(md, ctx = {}) {
md = md.replace(/{{\s*channels\s*}}/g, () => {
if (!ctx.kanaly) return "";
const html = ctx.kanaly
.map(
(k) => `
<div class="flex items-center justify-center p-1">
<img
src="${k.logo}"
alt="${k.name}"
title="${k.name}"
class="channel-logo w-20 h-auto object-contain rounded"
/>
</div>
`
)
.join("");
return `
<div class="grid grid-cols-3 sm:grid-cols-4 md:grid-cols-6 lg:grid-cols-10 gap-2 my-4">
${html}
</div>
`;
});
return md;
}
export default function FuzMarkdown({ text, ctx = {} }) {
if (!text) return null;
let processed = applyShortcodes(text, ctx);
processed = processed.replace(
/\[([^\]]+)\]\(#([^) "]+)(?:\s+"([^"]+)")?\)/g,
(match, label, modalId, title) => {
return `<a href="#" class="modal-link" data-modal="${modalId}"${title ? ` title="${title}"` : ""
}>${label}</a>`;
}
);
processed = processed.replace(
/\[([^\]]+)\]\("([^"]+)"(?:\s+"([^"]+)")?\s+btn\)/g,
(match, label, href, title) => {
return `
<div class="">
<a
href="${href}"
class="btn btn-primary"
target="_blank"
rel="noopener noreferrer"${title ? ` title="${title}"` : ""}
>
${label}
</a>
</div>`;
}
);
const html = marked(processed);
return (
<div
class="fuz-markdown max-w-none"
dangerouslySetInnerHTML={{ __html: html }}
/>
);
}