Add tables and lists to highlight
This commit is contained in:
parent
f3d916982f
commit
5121a8047e
|
|
@ -43,3 +43,32 @@
|
|||
.header3 {
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.table {
|
||||
border-collapse: collapse;
|
||||
width: 100%;
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
||||
.table th,
|
||||
.table td {
|
||||
border: 1px solid var(--tableBorder, #555);
|
||||
padding: 0.3em 0.6em;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.table th {
|
||||
background: var(--tableHeaderBg, #3a3a3a);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.list {
|
||||
margin: 0.4em 0;
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
|
||||
.hr {
|
||||
border: none;
|
||||
border-top: 1px solid var(--hrColor, #555);
|
||||
margin: 0.5em 0;
|
||||
}
|
||||
|
|
@ -1,6 +1,44 @@
|
|||
import clsx from 'clsx';
|
||||
import styles from './assets/highlight.module.css';
|
||||
|
||||
const parseTableRow = (line: string): string[] =>
|
||||
line.split('|').slice(1, -1).map(cell => cell.trim());
|
||||
|
||||
const isSeparatorRow = (line: string): boolean =>
|
||||
/^\|[\s|:\-]+\|$/.test(line.trim());
|
||||
|
||||
export const parseList = (block: string, ordered: boolean): string => {
|
||||
const marker = ordered ? /^\d+\. / : /^[-+] /;
|
||||
const items = block.trim().split('\n')
|
||||
.map(l => `<li>${l.trim().replace(marker, '')}</li>`)
|
||||
.join('');
|
||||
const tag = ordered ? 'ol' : 'ul';
|
||||
return `<${tag} class="${styles.list}">${items}</${tag}>`;
|
||||
};
|
||||
|
||||
export const parseTable = (table: string): string => {
|
||||
const lines = table.trim().split('\n').map(l => l.trim()).filter(l => l.startsWith('|'));
|
||||
if (lines.length < 2) return table;
|
||||
|
||||
const sepIndex = lines.findIndex(isSeparatorRow);
|
||||
if (sepIndex === -1) return table;
|
||||
|
||||
const headerLines = lines.slice(0, sepIndex);
|
||||
const bodyLines = lines.slice(sepIndex + 1);
|
||||
|
||||
const renderCells = (cells: string[], tag: 'th' | 'td') =>
|
||||
cells.map(cell => `<${tag}>${cell}</${tag}>`).join('');
|
||||
|
||||
const headers = headerLines
|
||||
.map(l => `<tr>${renderCells(parseTableRow(l), 'th')}</tr>`)
|
||||
.join('');
|
||||
const rows = bodyLines
|
||||
.map(l => `<tr>${renderCells(parseTableRow(l), 'td')}</tr>`)
|
||||
.join('');
|
||||
|
||||
return `<table class="${styles.table}"><thead>${headers}</thead><tbody>${rows}</tbody></table>`;
|
||||
};
|
||||
|
||||
export const highlight = (message: string, keepMarkup = true): string => {
|
||||
let resultHTML = '';
|
||||
const tokenRegex = /(\*\*?|"|```|`|(?:^|\n)#{1,3} |\n)/g;
|
||||
|
|
@ -90,5 +128,12 @@ export const highlight = (message: string, keepMarkup = true): string => {
|
|||
if (inHeader) resultHTML += '</span>';
|
||||
resultHTML += '</span>'.repeat(stack.length);
|
||||
|
||||
if (!keepMarkup) {
|
||||
resultHTML = resultHTML.replace(/((?:(?:^|\n)\|.+)+)/g, match => parseTable(match));
|
||||
resultHTML = resultHTML.replace(/(^|\n)---(\n|$)/g, (_, pre, post) => `${pre}<hr class="${styles.hr}">${post}`);
|
||||
resultHTML = resultHTML.replace(/((?:(?:^|\n)[-+] .+)+)/g, match => parseList(match, false));
|
||||
resultHTML = resultHTML.replace(/((?:(?:^|\n)\d+\. .+)+)/g, match => parseList(match, true));
|
||||
}
|
||||
|
||||
return resultHTML;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -394,6 +394,9 @@ export namespace Tools {
|
|||
{ name: `character:${c.name}`, content: c.name },
|
||||
{ name: `character:${c.name}`, content: c.shortDescription },
|
||||
{ name: `character:${c.name}`, content: c.description || '' },
|
||||
...c.relations.map(rel => (
|
||||
{ name: `character:${c.name}`, content: `relation: ${rel.name} (${rel.relation})` }
|
||||
)),
|
||||
]),
|
||||
...appState.currentStory.locations.flatMap(l => [
|
||||
{ name: `location:${l.name}`, content: l.name },
|
||||
|
|
|
|||
Loading…
Reference in New Issue