Add tables and lists to highlight
This commit is contained in:
parent
f3d916982f
commit
5121a8047e
|
|
@ -42,4 +42,33 @@
|
||||||
|
|
||||||
.header3 {
|
.header3 {
|
||||||
font-size: 1em;
|
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 clsx from 'clsx';
|
||||||
import styles from './assets/highlight.module.css';
|
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 => {
|
export const highlight = (message: string, keepMarkup = true): string => {
|
||||||
let resultHTML = '';
|
let resultHTML = '';
|
||||||
const tokenRegex = /(\*\*?|"|```|`|(?:^|\n)#{1,3} |\n)/g;
|
const tokenRegex = /(\*\*?|"|```|`|(?:^|\n)#{1,3} |\n)/g;
|
||||||
|
|
@ -90,5 +128,12 @@ export const highlight = (message: string, keepMarkup = true): string => {
|
||||||
if (inHeader) resultHTML += '</span>';
|
if (inHeader) resultHTML += '</span>';
|
||||||
resultHTML += '</span>'.repeat(stack.length);
|
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;
|
return resultHTML;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -394,6 +394,9 @@ export namespace Tools {
|
||||||
{ name: `character:${c.name}`, content: c.name },
|
{ name: `character:${c.name}`, content: c.name },
|
||||||
{ name: `character:${c.name}`, content: c.shortDescription },
|
{ name: `character:${c.name}`, content: c.shortDescription },
|
||||||
{ name: `character:${c.name}`, content: c.description || '' },
|
{ 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 => [
|
...appState.currentStory.locations.flatMap(l => [
|
||||||
{ name: `location:${l.name}`, content: l.name },
|
{ name: `location:${l.name}`, content: l.name },
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue