Files
MineGeo/components/ReleaseNotes.tsx
pavel444-byte 690fe12c2c
All checks were successful
Deploy MineGeo to Dokploy / deploy (push) Successful in 5m17s
Fix restricted map controls and release verification
2026-10-20 16:46:36 +05:00

64 lines
1.8 KiB
TypeScript

import { Fragment } from "react";
// Render a small, safe subset of Discord Markdown; React escapes raw HTML.
function inline(text: string) {
return text
.split(/(\*\*[^*]+\*\*|`[^`]+`|\[[^\]]+\]\(https?:\/\/[^\s)]+\))/g)
.map((part, i) => {
if (part.startsWith("**") && part.endsWith("**"))
return <strong key={i}>{part.slice(2, -2)}</strong>;
if (part.startsWith("`") && part.endsWith("`"))
return <code key={i}>{part.slice(1, -1)}</code>;
const link = /^\[([^\]]+)\]\((https?:\/\/[^\s)]+)\)$/.exec(part);
if (link)
return (
<a key={i} href={link[2]} target="_blank" rel="noopener noreferrer">
{link[1]}
</a>
);
return <Fragment key={i}>{part}</Fragment>;
});
}
export function ReleaseNotes({ body }: { body: string }) {
const blocks: { list: boolean; lines: string[] }[] = [];
let current: (typeof blocks)[number] | undefined;
for (const line of body.split(/\r?\n/)) {
if (!line.trim()) {
current = undefined;
continue;
}
const bullet = /^\s*[-*]\s+(.+)$/.exec(line);
if (!bullet && current?.list && /^\s{2,}\S/.test(line)) {
current.lines[current.lines.length - 1] += ` ${line.trim()}`;
continue;
}
const list = !!bullet;
if (!current || current.list !== list) {
current = { list, lines: [] };
blocks.push(current);
}
current.lines.push(bullet ? bullet[1] : line);
}
return blocks.map(({ list, lines }, i) => {
if (list)
return (
<ul key={i}>
{lines.map((line, j) => (
<li key={j}>{inline(line)}</li>
))}
</ul>
);
return (
<p key={i}>
{lines.map((line, j) => (
<Fragment key={j}>
{j > 0 && <br />}
{inline(line)}
</Fragment>
))}
</p>
);
});
}