embed readme

This commit is contained in:
2026-05-29 14:09:05 +08:00
parent 1ee22b7155
commit a2d80d2660
8 changed files with 248 additions and 81 deletions

View File

@@ -50,6 +50,14 @@ function getHtml(content: string): string {
font-size: 15px;
line-height: 1.3;
}
h3 {
margin: 14px 0 6px;
font-size: 13px;
line-height: 1.3;
}
strong {
font-weight: 600;
}
ul {
margin: 6px 0 12px;
padding-left: 20px;
@@ -62,6 +70,30 @@ function getHtml(content: string): string {
margin: 8px 0;
line-height: 1.5;
}
code {
font-family: var(--vscode-editor-font-family, monospace);
font-size: 0.95em;
background: var(--vscode-textCodeBlock-background);
padding: 1px 4px;
border-radius: 3px;
}
.changelog-block {
margin: 8px 0 18px;
padding: 10px 12px;
border: 1px solid var(--vscode-panel-border);
border-radius: 4px;
background: var(--vscode-textCodeBlock-background);
}
.change-section {
margin: 8px 0 4px;
font-weight: 600;
}
.changelog-block ul {
margin: 4px 0 10px;
}
.changelog-block li.nested {
margin-left: 18px;
}
</style>
</head>
<body>
@@ -74,6 +106,73 @@ function renderMarkdown(markdown: string): string {
const lines = markdown.replace(/\r\n/g, '\n').split('\n');
const html: string[] = [];
let inList = false;
let inCodeBlock = false;
let codeLines: string[] = [];
const closeList = () => {
if (inList) {
html.push('</ul>');
inList = false;
}
};
for (const rawLine of lines) {
if (rawLine.trim() === '```') {
closeList();
if (inCodeBlock) {
html.push(renderChangelogBlock(codeLines));
codeLines = [];
inCodeBlock = false;
} else {
inCodeBlock = true;
}
continue;
}
if (inCodeBlock) {
codeLines.push(rawLine);
continue;
}
const line = rawLine.trim();
if (!line) {
closeList();
continue;
}
const heading = line.match(/^(#{1,3})\s+(.+)$/);
if (heading) {
closeList();
const level = Math.min(heading[1].length, 2);
html.push(`<h${level}>${renderInlineMarkdown(heading[2])}</h${level}>`);
continue;
}
const boldHeading = line.match(/^\*\*(.+)\*\*$/);
if (boldHeading) {
closeList();
html.push(`<h2>${escapeHtml(boldHeading[1])}</h2>`);
continue;
}
const listItem = line.match(/^-\s+(.+)$/);
if (listItem) {
if (!inList) {
html.push('<ul>');
inList = true;
}
html.push(`<li>${renderInlineMarkdown(listItem[1])}</li>`);
continue;
}
closeList();
html.push(`<p>${renderInlineMarkdown(line)}</p>`);
}
if (inCodeBlock) {
html.push(renderChangelogBlock(codeLines));
}
closeList();
return html.join('\n');
}
function renderChangelogBlock(lines: string[]): string {
const html: string[] = ['<div class="changelog-block">'];
let inList = false;
const closeList = () => {
if (inList) {
@@ -88,29 +187,30 @@ function renderMarkdown(markdown: string): string {
closeList();
continue;
}
const heading = line.match(/^(#{1,3})\s+(.+)$/);
if (heading) {
closeList();
const level = Math.min(heading[1].length, 2);
html.push(`<h${level}>${escapeHtml(heading[2])}</h${level}>`);
continue;
}
const listItem = line.match(/^-\s+(.+)$/);
if (listItem) {
if (!inList) {
html.push('<ul>');
inList = true;
}
html.push(`<li>${escapeHtml(listItem[1])}</li>`);
const nested = rawLine.match(/^\s{8,}-\s+/) ? ' class="nested"' : '';
html.push(`<li${nested}>${renderInlineMarkdown(listItem[1])}</li>`);
continue;
}
closeList();
html.push(`<p>${escapeHtml(line)}</p>`);
html.push(`<div class="change-section">${renderInlineMarkdown(line)}</div>`);
}
closeList();
html.push('</div>');
return html.join('\n');
}
function renderInlineMarkdown(value: string): string {
return escapeHtml(value)
.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
.replace(/`([^`]+)`/g, '<code>$1</code>');
}
function escapeHtml(value: string): string {
return value.replace(/[&<>"']/g, ch => ({
'&': '&amp;',