diff options
Diffstat (limited to 'index.html')
| -rw-r--r-- | index.html | 68 |
1 files changed, 65 insertions, 3 deletions
@@ -30,6 +30,7 @@ </script> <div id="themeButton" style="display: none"> <button id="themeToggle">🌙</button> + <a href="#table-of-contents"><button id="goBackUp">⤴</button></a> </div> <script> @@ -180,10 +181,15 @@ } class TempoParser { - constructor(rawText) { + constructor(rawText, symbols = {}) { this.lines = rawText.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n') this.tokens = [] this.defs = new Set() + this.symbols = symbols + this.reverseSymbols = {} + for (const [name, sym] of Object.entries(symbols)) { + this.reverseSymbols[sym] = name + } } tokenize() { @@ -279,9 +285,53 @@ render() { let html = '' + + let tocItems = [] + for (const token of this.tokens) { + if (token.type === 'definition') { + let line = token.header.substring(4).trim() + let name = '' + const firstTick = line.indexOf('`') + const lastTick = line.lastIndexOf('`') + if (firstTick !== -1 && lastTick !== -1 && lastTick > firstTick) { + name = line.substring(0, firstTick).trim() + } else { + name = line + } + + const actualName = token.description.split('\n')[0].replace(/:/g, '') + + if (this.reverseSymbols[name]) { + tocItems.push({ + symbol: name, + name: actualName, + id: `def-${this.reverseSymbols[name].replace(/\s+/g, '-')}` + }) + } + } + } + + let tocHtml = '' + tocItems = tocItems.sort((a, b) => a.name.localeCompare(b.name)) + if (tocItems.length > 0) { + tocHtml = `<div id="table-of-contents" style="display: grid; grid-template-columns: repeat(16, auto); gap: 0.5rem; width: fit-content; margin-bottom: 2rem; border: 1px solid var(--border); padding: 10px; border-radius: 5px;">` + const tocItemNames = tocItems.map(e => e.id) + for (const itemName of [...new Set(tocItemNames)]) { + const item = tocItems.find(e => e.id === itemName) + tocHtml += `<a class="table-item" href="#${item.id}" title="${item.name}">${item.symbol}</a>` + } + tocHtml += `</div>` + } + let tocInserted = false let i = 0 for (const token of this.tokens) { + // Inject TOC before the first H2 + if (!tocInserted && tocHtml && token.type === 'header' && token.level === 2) { + html += tocHtml + tocInserted = true + } + if (token.type === 'header') { html += `<h${token.level}>${parseInline(token.text)}</h${token.level}>` } @@ -306,6 +356,12 @@ i++ } + + // If no h2 found, prepend it (or append to whatever was rendered) + if (!tocInserted && tocHtml) { + html = tocHtml + html + } + return html } @@ -339,10 +395,16 @@ name = line } + // Determine ID for TOC linking + let idAttr = '' + if (this.reverseSymbols[name]) { + idAttr = ` id="def-${this.reverseSymbols[name].replace(/\s+/g, '-')}"` + } + const descHtml = parseInline(token.description).replace(/\n/g, '<br>').replace(/ /g, ' ') const deftext = escapeHTML(code) - return `<block> + return `<block${idAttr}> <header> <div class='header-left'> <span>def</span> @@ -417,7 +479,7 @@ text = text.replace(/((^|\n)<!> *)/g, (e) => e.replace(/<!> */g, '')) text = applySymbols(text, symbols) - const parser = new TempoParser(text) + const parser = new TempoParser(text, symbols) // Passed symbols here parser.tokenize() const html = parser.render().replace(/{{dict_size}}/g, `<b>${parser.defs.size - 1}</b>`) |
