diff options
| -rw-r--r-- | index.html | 68 | ||||
| -rw-r--r-- | styles.css | 40 |
2 files changed, 104 insertions, 4 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>`) @@ -111,10 +111,31 @@ body.dark-mode { background-color: var(--code-bg-faint); } +#goBackUp { + position: fixed; + top: 70px; + right: 20px; + padding: 8px 16px; + background-color: var(--code-bg); + border: 1px solid var(--border); + cursor: pointer; + font-family: 'Roboto Mono', monospace; + font-size: 1.2rem; + border-radius: 4px; + z-index: 1000; + transition: 0.5s background-color; + color: var(--text); + font-weight: bold; +} + +#goBackUp:hover { + background-color: var(--code-bg-faint); +} + a { /* text-decoration: none; */ color: var(--link); - transition: 0.5s color; + transition: 0.5s background-color, 0.5s color !important; } a:hover { @@ -173,6 +194,23 @@ b { text-shadow: 0 0 2px var(--text); } +.table-item { + border-radius: 6px; + background-color: var(--code-bg); + transition: 0.5s background-color; + + text-decoration: none; + font-size: 1.5em; + padding: 5px 8px; + text-align: center; + color: inherit; + display: block; +} + +.table-item:hover { + background-color: var(--code-bg-faint); +} + pre code { background-color: transparent; padding: 0; |
