Add article + graph support

This commit is contained in:
Raven Scott
2026-01-05 16:11:50 -05:00
parent afb59c82a7
commit 0503d2f470
6 changed files with 3174 additions and 5 deletions
View File
+113 -4
View File
@@ -11,10 +11,119 @@ const axios = require('axios'); // Add axios for reCAPTCHA verification
const app = express();
// Set options for marked to use highlight.js for syntax highlighting
marked.setOptions({
// Configure custom renderer for code blocks to handle mermaid
marked.use({
renderer: {
code(code, language) {
// In marked v4+, code is an object with properties: text, lang, raw, etc.
// Extract the actual code text and language
let codeStr = '';
let lang = '';
if (typeof code === 'object' && code !== null) {
// Marked v4+ format: code is an object
codeStr = code.text || code.raw || String(code);
lang = code.lang || language || '';
} else if (typeof code === 'string') {
// Fallback for string format (older marked versions)
codeStr = code;
lang = language || '';
} else {
codeStr = String(code);
lang = language || '';
}
// Normalize language
if (lang && typeof lang === 'string') {
lang = lang.trim();
} else {
lang = '';
}
// If language is mermaid, wrap in a div with class "mermaid"
if (lang === 'mermaid') {
// Ensure mermaid code is properly formatted (trim and preserve newlines)
const mermaidCode = codeStr.trim();
return `<div class="mermaid">${mermaidCode}</div>\n`;
}
// Determine valid language for highlighting - default to plaintext
let validLanguage = 'plaintext';
if (lang && lang.length > 0) {
try {
// Only check if language is valid if lang is a non-empty string
const langInfo = hljs.getLanguage(lang);
if (langInfo) {
validLanguage = lang;
}
} catch (e) {
// If getLanguage throws, use plaintext
validLanguage = 'plaintext';
}
}
// Ensure validLanguage is always a valid string before highlighting
if (!validLanguage || typeof validLanguage !== 'string') {
validLanguage = 'plaintext';
}
// Highlight the code
try {
// Use new highlight.js API (v11+)
const highlighted = hljs.highlight(codeStr, { language: validLanguage }).value;
return `<pre><code class="hljs language-${validLanguage}">${highlighted}</code></pre>\n`;
} catch (e) {
// Fallback if highlighting fails - escape HTML and return plain code
const escapedCode = codeStr.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
return `<pre><code class="hljs language-plaintext">${escapedCode}</code></pre>\n`;
}
}
},
highlight: function (code, language) {
const validLanguage = hljs.getLanguage(language) ? language : 'plaintext';
return hljs.highlight(validLanguage, code).value;
// In marked v4+, code might be an object with a text property
let codeStr = '';
if (typeof code === 'object' && code !== null) {
codeStr = code.text || code.raw || String(code);
} else if (typeof code === 'string') {
codeStr = code;
} else {
codeStr = String(code);
}
// Handle undefined/null/empty language - ensure it's always a string
let lang = '';
if (language && typeof language === 'string') {
lang = language.trim();
}
// Determine valid language for highlighting - default to plaintext
let validLanguage = 'plaintext';
if (lang && lang.length > 0) {
try {
// Only check if language is valid if lang is a non-empty string
const langInfo = hljs.getLanguage(lang);
if (langInfo) {
validLanguage = lang;
}
} catch (e) {
// If getLanguage throws, use plaintext
validLanguage = 'plaintext';
}
}
// Ensure validLanguage is always a valid string before highlighting
if (!validLanguage || typeof validLanguage !== 'string') {
validLanguage = 'plaintext';
}
// Highlight the code
try {
// Use new highlight.js API (v11+)
return hljs.highlight(codeStr, { language: validLanguage }).value;
} catch (e) {
// Fallback if highlighting fails - return code as-is (will be escaped by marked)
return codeStr;
}
}
});
@@ -357,7 +466,7 @@ app.use((req, res) => {
});
// Server Listening
const PORT = process.env.PORT || 8899;
const PORT = process.env.PORT || 8888;
app.listen(PORT, () => {
console.log(`Server running on http://localhost:${PORT}`);
});
File diff suppressed because it is too large Load Diff
+15
View File
@@ -55,6 +55,21 @@
<!-- Bootstrap JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- Mermaid.js Script -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
// Initialize Mermaid first (before DOMContentLoaded)
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// Render Mermaid after DOM is ready
document.addEventListener('DOMContentLoaded', (event) => {
mermaid.run();
});
</script>
</body>
+15
View File
@@ -70,6 +70,21 @@
<!-- Bootstrap JS Bundle -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- Mermaid.js Script -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
// Initialize Mermaid first (before DOMContentLoaded)
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// Render Mermaid after DOM is ready
document.addEventListener('DOMContentLoaded', (event) => {
mermaid.run();
});
</script>
</body>
+14 -1
View File
@@ -71,12 +71,25 @@
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js"></script>
<!-- Highlight.js Script -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/highlight.min.js"></script>
<!-- Mermaid.js Script -->
<script src="https://cdn.jsdelivr.net/npm/mermaid@10/dist/mermaid.min.js"></script>
<script>
// Initialize Highlight.js
// Initialize Mermaid first (before DOMContentLoaded)
mermaid.initialize({
startOnLoad: false,
theme: 'default',
securityLevel: 'loose'
});
// Initialize Highlight.js and render Mermaid after DOM is ready
document.addEventListener('DOMContentLoaded', (event) => {
// Initialize Highlight.js
document.querySelectorAll('pre code').forEach((block) => {
hljs.highlightElement(block);
});
// Manually run mermaid to render all diagrams
mermaid.run();
});
</script>
</body>