feat: dynamic ish terminal preview

This commit is contained in:
venus
2026-10-06 17:06:08 -05:00
parent 569152a7be
commit 98e46644c0
11 changed files with 220 additions and 21 deletions
+3
View File
@@ -5,3 +5,6 @@ _site/
*.log
.env
docker-compose.yml
# Local browser fixtures for document-based development
src/posts/*.md
+3 -1
View File
@@ -5,6 +5,9 @@ import { filters } from "./src/_filters/index.js";
import { postComparator, isPostPublic } from "./src/_utils/sort-posts.js";
export default function (eleventyConfig) {
// Build ignored local post fixtures without making them Git-tracked.
eleventyConfig.setUseGitIgnore(false);
// 1. Static Asset Passthrough Copy
eleventyConfig.addPassthroughCopy({ "src/assets": "assets" });
@@ -66,7 +69,6 @@ export default function (eleventyConfig) {
return [...tagSet].sort();
});
// 6. Dev Server Options (dynamic port binding)
eleventyConfig.setServerOptions({
port: parseInt(process.env.PORT || "8080", 10)
+32 -1
View File
@@ -62,13 +62,44 @@ export const extractHeadings = (htmlContent) => {
return headings;
};
const leadingTerminalPreviewHeading = /^\s*<h1\b[^>]*\bid=(["'])terminal-preview\1[^>]*>[\s\S]*?<\/h1>/i;
const terminalPreviewBounds = (htmlContent) => {
if (!htmlContent || typeof htmlContent !== "string") return null;
const heading = htmlContent.match(leadingTerminalPreviewHeading);
if (!heading) return null;
const contentAfterHeading = htmlContent.slice(heading[0].length);
const nextArticleHeading = contentAfterHeading.search(/<h[1-6]\b/i);
if (nextArticleHeading === -1) return null;
const leadingArticleWhitespace = contentAfterHeading
.slice(0, nextArticleHeading)
.match(/\s*$/)?.[0] || "";
return {
preview: contentAfterHeading.slice(0, nextArticleHeading),
article: leadingArticleWhitespace + contentAfterHeading.slice(nextArticleHeading)
};
};
export const extractTerminalPreview = (htmlContent) => terminalPreviewBounds(htmlContent)?.preview || "";
export const removeTerminalPreview = (htmlContent) => {
if (!htmlContent || typeof htmlContent !== "string") return "";
return terminalPreviewBounds(htmlContent)?.article || htmlContent;
};
export const filters = {
postDate,
isoDate,
limit,
filterTagList,
readingTime,
extractHeadings
extractHeadings,
extractTerminalPreview,
removeTerminalPreview
};
export default filters;
+4 -4
View File
@@ -11,7 +11,7 @@
<!-- Left Sticky Sidebar: Document Outline & Telemetry -->
<aside class="article-sidebar" aria-label="Article Sidebar">
<!-- Dynamic Table of Contents -->
{% set headings = content | extractHeadings %}
{% set headings = (content | removeTerminalPreview) | extractHeadings %}
{% if headings.length > 0 %}
<div class="sidebar-tile">
<div class="sidebar-heading">
@@ -45,7 +45,7 @@
<div class="stat-row">
<span>DURATION:</span>
<span class="stat-val">{{ content | readingTime(readingTime) }}</span>
<span class="stat-val">{{ (content | removeTerminalPreview) | readingTime(readingTime) }}</span>
</div>
{% if difficulty %}
<div class="stat-row">
@@ -90,7 +90,7 @@
<time datetime="{{ date | isoDate }}">{{ date | postDate }}</time>
</span>
<span>&bull;</span>
<span class="meta-item">{{ content | readingTime(readingTime) }}</span>
<span class="meta-item">{{ (content | removeTerminalPreview) | readingTime(readingTime) }}</span>
{% if difficulty %}
<span>&bull;</span>
<span class="meta-item" style="color: var(--accent-amber);">DIFFICULTY: {{ difficulty }}</span>
@@ -99,7 +99,7 @@
</header>
<div class="markdown-prose">
{{ content | safe }}
{{ content | removeTerminalPreview | safe }}
</div>
</article>
</div>
+17 -15
View File
@@ -32,21 +32,23 @@
{{ featured.data.excerpt }}
</p>
<!-- Terminal Code Preview Snippet -->
<div class="terminal-code-box">
<div class="code-titlebar">
<span class="code-title">
<span style="color: var(--accent-cyan);">&gt;</span>
<span>init_cluster.sh</span>
</span>
<span>POSIX sh</span>
</div>
<div class="code-content">
<pre><code class="language-bash"># System initialization and node health check
./cluster.sh --verify-nodes
curl -s https://api.local/healthz | jq .status</code></pre>
</div>
</div>
{% if featured.data.terminal == true %}
{% set terminalPreview = featured.templateContent | extractTerminalPreview %}
{% if terminalPreview %}
<div class="terminal-code-box terminal-preview-box">
<div class="code-titlebar">
<span class="code-title">
<span style="color: var(--accent-cyan);">&gt;</span>
<span>TERMINAL PREVIEW</span>
</span>
<span>MARKDOWN</span>
</div>
<div class="terminal-preview-content">
{{ terminalPreview | safe }}
</div>
</div>
{% endif %}
{% endif %}
<div class="featured-cta-row">
<div class="tag-cluster">
+29
View File
@@ -65,6 +65,35 @@
font-family: var(--font-code);
}
.terminal-preview-box {
margin: 0;
}
.terminal-preview-content {
padding: 14px 16px;
color: var(--text-primary);
font-size: 0.82rem;
line-height: 1.55;
}
.terminal-preview-content > :first-child {
margin-top: 0;
}
.terminal-preview-content > :last-child {
margin-bottom: 0;
}
.terminal-preview-content pre {
margin: 10px 0;
padding: 10px 12px;
overflow-x: auto;
background-color: var(--bg-surface);
border: var(--border-width) solid var(--border-color);
border-radius: var(--border-radius-sm);
font-family: var(--font-code);
}
/* Syntax Highlighting Tokens (Prism / 11ty Syntax Highlight) */
.token.comment,
.token.prolog,
+60
View File
@@ -0,0 +1,60 @@
import test from "node:test";
import assert from "node:assert/strict";
import nunjucks from "nunjucks";
import path from "node:path";
import {
extractTerminalPreview,
filterTagList,
isoDate,
postDate,
readingTime
} from "../src/_filters/index.js";
const includesDir = path.resolve("src/_includes");
function renderFeaturedCard(terminal) {
const env = new nunjucks.Environment(new nunjucks.FileSystemLoader(includesDir), { autoescape: false });
env.addFilter("extractTerminalPreview", extractTerminalPreview);
env.addFilter("filterTagList", filterTagList);
env.addFilter("isoDate", isoDate);
env.addFilter("postDate", postDate);
env.addFilter("readingTime", readingTime);
const featured = {
url: "/dispatches/example/",
date: "2026-10-06",
data: {
featured: true,
terminal,
tags: ["systems"],
title: "Example dispatch",
excerpt: "An example featured dispatch used to verify the terminal preview."
},
templateContent: `
<h1 id="terminal-preview">Terminal preview</h1>
<p>Inspect the first five lines:</p>
<pre><code class="language-bash">cat /dispatches/example | head -n 5</code></pre>
<h1 id="investigation">Investigation</h1>
<p>The public article begins here.</p>
`
};
return env.render("partials/featured-card.njk", {
collections: { posts: [featured] }
});
}
test("Featured terminal preview: renders Markdown output only when terminal frontmatter is true", () => {
const output = renderFeaturedCard(true);
assert.match(output, /class="[^"]*terminal-code-box[^"]*"/);
assert.match(output, /Inspect the first five lines:/);
assert.match(output, /cat \/dispatches\/example \| head -n 5/);
assert.doesNotMatch(output, /Terminal preview/);
assert.doesNotMatch(output, /init_cluster\.sh/);
});
test("Featured terminal preview: does not render when terminal frontmatter is false or absent", () => {
assert.doesNotMatch(renderFeaturedCard(false), /terminal-code-box/);
assert.doesNotMatch(renderFeaturedCard(undefined), /terminal-code-box/);
});
+10
View File
@@ -0,0 +1,10 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
const config = fs.readFileSync(path.resolve("eleventy.config.js"), "utf-8");
test("Eleventy config: builds local ignored post fixtures", () => {
assert.match(config, /setUseGitIgnore\(false\)/);
});
+10
View File
@@ -0,0 +1,10 @@
import test from "node:test";
import assert from "node:assert/strict";
import fs from "node:fs";
import path from "node:path";
const postLayout = fs.readFileSync(path.resolve("src/_includes/layouts/post.njk"), "utf-8");
test("Post layout: omits the leading terminal preview from the public article body", () => {
assert.match(postLayout, /content\s*\|\s*removeTerminalPreview\s*\|\s*safe/);
});
+15
View File
@@ -0,0 +1,15 @@
import test from "node:test";
import assert from "node:assert/strict";
import { extractTerminalPreview, removeTerminalPreview } from "../src/_filters/index.js";
test("Terminal previews: stop before the first subsequent Markdown heading at any level", () => {
const renderedPost = `
<h1 id="terminal-preview">Terminal preview</h1>
<p>Plain Markdown preview text is supported.</p>
<h2 id="findings">Findings</h2>
<p>The article begins here.</p>
`;
assert.match(extractTerminalPreview(renderedPost), /Plain Markdown preview text/);
assert.match(removeTerminalPreview(renderedPost), /^\n <h2 id="findings">/);
});
+37
View File
@@ -0,0 +1,37 @@
import test from "node:test";
import assert from "node:assert/strict";
import {
extractTerminalPreview,
removeTerminalPreview
} from "../src/_filters/index.js";
test("Terminal previews: extracts rendered Markdown between the leading preview and article headings", () => {
const renderedPost = `
<h1 id="terminal-preview">Terminal preview</h1>
<p>Use the following command:</p>
<pre class="language-bash"><code class="language-bash">cat /dispatches/example | head -n 5</code></pre>
<h1 id="investigation">Investigation</h1>
<p>The public article starts here.</p>
`;
assert.equal(
extractTerminalPreview(renderedPost),
`\n <p>Use the following command:</p>\n <pre class="language-bash"><code class="language-bash">cat /dispatches/example | head -n 5</code></pre>\n `
);
assert.equal(
removeTerminalPreview(renderedPost),
`\n <h1 id="investigation">Investigation</h1>\n <p>The public article starts here.</p>\n `
);
});
test("Terminal previews: ignores missing, misplaced, and malformed preview headings", () => {
const regularPost = "<h1 id=\"article\">Article</h1><p>Visible text.</p>";
const misplacedPreview = "<h1 id=\"article\">Article</h1><h1 id=\"terminal-preview\">Terminal preview</h1><p>Do not extract.</p>";
assert.equal(extractTerminalPreview(regularPost), "");
assert.equal(removeTerminalPreview(regularPost), regularPost);
assert.equal(extractTerminalPreview(misplacedPreview), "");
assert.equal(removeTerminalPreview(misplacedPreview), misplacedPreview);
assert.equal(extractTerminalPreview(null), "");
assert.equal(removeTerminalPreview(null), "");
});