mirror of
https://github.com/qingchencloud/clawpanel.git
synced 2026-05-06 20:02:49 +08:00
feat(markdown): 支持 Markdown 表格渲染
- 在 markdown.js 中添加表格检测和渲染逻辑 - 支持标准格式 (| cell |) 和简化格式 (cell | cell) - 添加 renderTable() 辅助函数处理表格解析 - 在 chat.css 中添加美观的表格样式 - 表头高亮、斑马纹、悬停效果
This commit is contained in:
@@ -89,6 +89,8 @@ export function renderMarkdown(text) {
|
||||
const result = []
|
||||
let inList = false
|
||||
let listType = ''
|
||||
let inTable = false
|
||||
let tableRows = []
|
||||
|
||||
for (let i = 0; i < lines.length; i++) {
|
||||
let line = lines[i]
|
||||
@@ -100,6 +102,38 @@ export function renderMarkdown(text) {
|
||||
continue
|
||||
}
|
||||
|
||||
// 表格检测:表头分隔行 (|---|...|)
|
||||
const isTableSeparator = /^\s*\|[\s\-:|]+\|\s*$/.test(line) ||
|
||||
/^\s*[\-:]+(\s*\|\s*[\-:]+)+\s*$/.test(line)
|
||||
|
||||
// 检测是否可能是表格行
|
||||
const isTableRow = /^\s*\|.*\|\s*$/.test(line) ||
|
||||
/^\s*[^\|]+\s*\|\s*[^\|]+/.test(line)
|
||||
|
||||
// 如果在表格中,继续收集行
|
||||
if (inTable) {
|
||||
if (isTableRow && line.trim() !== '') {
|
||||
tableRows.push(line)
|
||||
continue
|
||||
} else {
|
||||
// 表格结束,渲染表格
|
||||
result.push(renderTable(tableRows))
|
||||
inTable = false
|
||||
tableRows = []
|
||||
}
|
||||
}
|
||||
|
||||
// 检测表格开始:当前行是表格行,且下一行是分隔行
|
||||
if (!inTable && isTableRow && i + 1 < lines.length) {
|
||||
const nextLine = lines[i + 1]
|
||||
if (/^\s*\|[\s\-:|]+\|\s*$/.test(nextLine) ||
|
||||
/^\s*[\-:]+(\s*\|\s*[\-:]+)+\s*$/.test(nextLine)) {
|
||||
inTable = true
|
||||
tableRows.push(line)
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
// 标题
|
||||
const headingMatch = line.match(/^(#{1,3})\s+(.+)$/)
|
||||
if (headingMatch) {
|
||||
@@ -138,9 +172,69 @@ export function renderMarkdown(text) {
|
||||
}
|
||||
|
||||
if (inList) result.push(`</${listType}>`)
|
||||
// 处理剩余的表格
|
||||
if (inTable && tableRows.length > 0) {
|
||||
result.push(renderTable(tableRows))
|
||||
}
|
||||
return result.join('\n')
|
||||
}
|
||||
|
||||
/**
|
||||
* 渲染 Markdown 表格
|
||||
* @param {string[]} rows - 表格行数组
|
||||
* @returns {string} HTML 表格
|
||||
*/
|
||||
function renderTable(rows) {
|
||||
if (!rows || rows.length < 2) return ''
|
||||
|
||||
const table = ['<table>']
|
||||
let isHeaderRow = true
|
||||
let hasSeparator = false
|
||||
|
||||
for (let i = 0; i < rows.length; i++) {
|
||||
let row = rows[i].trim()
|
||||
|
||||
// 跳过空行
|
||||
if (!row) continue
|
||||
// 检测分隔行 (|---|...|)
|
||||
const isSeparator = /^\s*\|[\s\-:|]+\|\s*$/.test(row) ||
|
||||
/^\s*[\-:]+(\s*\|\s*[\-:]+)+\s*$/.test(row)
|
||||
if (isSeparator) {
|
||||
hasSeparator = true
|
||||
continue
|
||||
}
|
||||
|
||||
// 解析单元格
|
||||
let cells = []
|
||||
if (row.startsWith('|') && row.endsWith('|')) {
|
||||
// 标准格式: | cell1 | cell2 |
|
||||
cells = row.slice(1, -1).split('|')
|
||||
} else {
|
||||
// 简化格式: cell1 | cell2
|
||||
cells = row.split('|')
|
||||
}
|
||||
// 清理单元格内容
|
||||
cells = cells.map(cell => inlineFormat(cell.trim()))
|
||||
if (cells.length === 0) continue
|
||||
|
||||
// 渲染行
|
||||
const tag = isHeaderRow && !hasSeparator && i === 0 ? 'th' : 'td'
|
||||
table.push(' <tr>')
|
||||
cells.forEach(cell => {
|
||||
table.push(` <${tag}>${cell}</${tag}>`)
|
||||
})
|
||||
table.push(' </tr>')
|
||||
|
||||
// 第一行后切换到数据行(如果有分隔行)
|
||||
if (hasSeparator && i === 0) {
|
||||
isHeaderRow = false
|
||||
}
|
||||
}
|
||||
|
||||
table.push('</table>')
|
||||
return table.join('\n')
|
||||
}
|
||||
|
||||
function inlineFormat(text) {
|
||||
return text
|
||||
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
|
||||
|
||||
@@ -304,6 +304,34 @@
|
||||
.hl-func { color: #61afef; }
|
||||
.hl-type { color: #e5c07b; }
|
||||
|
||||
/* Markdown 表格 */
|
||||
.msg-ai .msg-bubble table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
margin: 8px 0;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.msg-ai .msg-bubble th,
|
||||
.msg-ai .msg-bubble td {
|
||||
border: 1px solid var(--border);
|
||||
padding: 8px 12px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.msg-ai .msg-bubble th {
|
||||
background: var(--bg-tertiary);
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.msg-ai .msg-bubble tr:nth-child(even) {
|
||||
background: var(--bg-hover);
|
||||
}
|
||||
|
||||
.msg-ai .msg-bubble tr:hover {
|
||||
background: rgba(99, 102, 241, 0.08);
|
||||
}
|
||||
|
||||
/* 行内代码 */
|
||||
.msg-ai .msg-bubble > code {
|
||||
background: var(--bg-hover, rgba(255,255,255,0.08));
|
||||
|
||||
Reference in New Issue
Block a user