Fix ordered list bullets and implement footnotes

- CSS: global reset `ul, ol { list-style: none }` was killing all bullets
  and numbers. Add list-style: disc/decimal back on .lt-markdown ul/ol.
  Remove duplicate ol rules.
- Footnotes: implement [^label] / [^label]: syntax. Uses placeholder
  approach (like code blocks) so <sup> tags aren't HTML-escaped. Renders
  inline superscript refs + numbered footnote block at bottom with
  back-links.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-07 00:28:02 -04:00
parent ddf1d236eb
commit 74d1770cd6
2 changed files with 41 additions and 3 deletions
+7 -3
View File
@@ -5151,6 +5151,8 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
.lt-markdown h4, .lt-markdown h5, .lt-markdown h6 { font-size: 0.8rem; color: var(--text-muted); margin: 0.5rem 0 0.25rem; }
.lt-markdown p { font-size: 0.82rem; line-height: 1.7; color: var(--text-secondary); margin: 0.5rem 0; }
.lt-markdown ul, .lt-markdown ol { padding-left: 1.25rem; margin: 0.5rem 0; }
.lt-markdown ul { list-style: disc; }
.lt-markdown ol { list-style: decimal; }
.lt-markdown li { font-size: 0.8rem; color: var(--text-secondary); line-height: 1.6; margin-bottom: 0.2rem; }
.lt-markdown ul li::marker { color: var(--accent-cyan); }
.lt-markdown ol li::marker { color: var(--accent-orange); }
@@ -5167,12 +5169,14 @@ body.lt-is-offline .lt-main { margin-top: 2rem; transition: margin-top 0.25s eas
.lt-markdown del { color: var(--text-muted); text-decoration: line-through; }
.lt-markdown sub, .lt-markdown sup { font-size: 0.7em; line-height: 0; }
.lt-markdown .task-item { list-style: none; margin-left: -1.2em; }
.lt-markdown .fn-ref a { color: var(--accent-cyan); font-size: 0.7em; text-decoration: none; }
.lt-markdown .fn-hr { margin: 1rem 0 0.5rem; }
.lt-markdown .fn-list { font-size: 0.75rem; color: var(--text-muted); list-style: decimal; padding-left: 1.25rem; margin: 0; }
.lt-markdown .fn-item { margin-bottom: 0.2rem; }
.lt-markdown .fn-back { color: var(--accent-cyan); text-decoration: none; font-size: 0.85em; }
.lt-markdown .task-cb { margin-right: 0.35em; font-size: 1em; }
.lt-markdown .task-done { color: var(--text-muted); text-decoration: line-through; }
.lt-markdown .task-todo { color: var(--text-secondary); }
.lt-markdown ol { padding-left: 1.5em; margin: 0.5rem 0; }
.lt-markdown ol li { color: var(--text-secondary); }
.lt-markdown ol li::marker { color: var(--accent-orange); }
.lt-markdown table { width: 100%; border-collapse: collapse; font-size: 0.78rem; margin: 0.75rem 0; }
.lt-markdown th { background: var(--bg-secondary); color: var(--accent-cyan); padding: 0.4rem 0.6rem; border: 1px solid var(--border-dim); text-align: left; font-size: 0.7rem; text-transform: uppercase; letter-spacing: 0.08em; }
.lt-markdown td { padding: 0.35rem 0.6rem; border: 1px solid var(--border-dim); color: var(--text-secondary); }
+34
View File
@@ -6,6 +6,23 @@
function parseMarkdown(markdown) {
if (!markdown) return '';
// Footnotes — collect definitions and mark references with placeholders
// (must happen before HTML escaping so <sup> tags don't get escaped)
const footnotes = {};
const footnoteOrder = [];
const fnRefs = [];
markdown = markdown.replace(/^\[\^([^\]]+)\]:\s+(.+)$/gm, function(_, label, text) {
footnotes[label] = text;
return '';
});
markdown = markdown.replace(/\[\^([^\]]+)\]/g, function(_, label) {
if (!footnotes[label]) return '[^' + label + ']';
if (!footnoteOrder.includes(label)) footnoteOrder.push(label);
const n = footnoteOrder.indexOf(label) + 1;
fnRefs.push({ label, n });
return '%%FNREF' + (fnRefs.length - 1) + '%%';
});
let html = markdown;
// Escape HTML first to prevent XSS
@@ -122,11 +139,28 @@ function parseMarkdown(markdown) {
html = html.replace('%%INLINECODE' + i + '%%', code);
});
// Restore footnote reference placeholders
fnRefs.forEach(function(ref, i) {
html = html.replace('%%FNREF' + i + '%%',
'<sup class="fn-ref"><a href="#fn-' + ref.label + '" id="fnref-' + ref.label + '">[' + ref.n + ']</a></sup>');
});
// Wrap in paragraph if not already wrapped
if (!html.startsWith('<')) {
html = '<p>' + html + '</p>';
}
// Append footnote definitions block
if (footnoteOrder.length) {
html += '<hr class="fn-hr"><ol class="fn-list">';
footnoteOrder.forEach(function(label, i) {
html += '<li id="fn-' + label + '" class="fn-item">' +
parseMarkdown(footnotes[label]).replace(/<\/?p>/g, '') +
' <a href="#fnref-' + label + '" class="fn-back">&#x21A9;</a></li>';
});
html += '</ol>';
}
return html;
}