Files
pengzhan.dev/views/pages/post.ejs
T
haopengzhan f52b3fe9e4 feat(migration): complete WordPress migration and UX refinements
- Migrate historical posts, localized assets, and 103 comments
- Colocate media into posts/<slug>/images/ and remove wp-content
- Add native bilingual support for ai-can-change post (English default, /zh variant)
- Support clean taxonomy routing (/category/:category and /tag/:tag)
- Dynamically populate categories and tags in sitemap.xml
- Fix header scroll padding/margin offsets for anchor and reference links
- Constrain image and media widths to prevent content overflow
- Redesign homepage recent posts to 4 compact editorial cards
- Restore valid binary favicon.ico and high-res icon assets
- Remove placeholder content and sample test comments
2026-09-16 23:09:09 -07:00

140 lines
5.5 KiB
Plaintext

<%- include('../partials/head', { pageType: 'post' }) %>
<div class="post-layout-container">
<article class="post-article-main">
<header class="post-header-editorial">
<h1 class="post-title-editorial"><%= post.title %></h1>
<div class="post-meta-editorial">
<time datetime="<%= post.date.toISOString() %>"><%= post.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) %></time>
<span class="meta-sep">&mdash;</span>
<span>by <%= post.author %></span>
<% if (post.category) { %>
<span>in <a href="/category/<%= encodeURIComponent(post.category) %>" class="meta-category-link"><%= post.category %></a></span>
<% } %>
<!-- Inline Bilingual Language Switcher with stable line height -->
<% if (post.availableLanguages && post.availableLanguages.length > 1) { %>
<span class="meta-sep">&bull;</span>
<span class="meta-lang-switcher">
<span style="opacity: 0.7;">🌐</span>
<% post.availableLanguages.forEach(l => {
const isCurrent = (currentLang === l);
const targetUrl = (l === post.defaultLang || (post.isDefault && l === post.lang))
? `/${post.slug}`
: `/${post.slug}/${l}`;
const displayLabel = l === 'zh' ? '中文' : (l === 'en' ? 'English' : l.toUpperCase());
%>
<a href="<%= targetUrl %>" class="lang-text-link <%= isCurrent ? 'lang-active' : '' %>">
<%= displayLabel %>
</a>
<% }) %>
</span>
<% } %>
</div>
</header>
<% if (post.cover) { %>
<img src="<%= post.cover %>" alt="<%= post.title %>" class="post-featured-image">
<% } %>
<!-- Rendered Markdown Body -->
<div class="post-body-content">
<%- post.contentHtml %>
</div>
<!-- Unified Tag Links -->
<% if (post.tags && post.tags.length > 0) { %>
<div class="post-tags-container">
<span class="post-tags-label">Tags:</span>
<% post.tags.forEach(tag => { %>
<a href="/tag/<%= encodeURIComponent(tag.toLowerCase()) %>" class="tag-link">
#<%= tag %>
</a>
<% }) %>
</div>
<% } %>
<!-- Plugin Hook: injectPostEnd -->
<%- pluginHook('injectPostEnd', { post, pageType: 'post' }) %>
<!-- Clean Previous / Next Post Navigation -->
<% if (prevPost || nextPost) { %>
<nav class="post-nav-editorial">
<div class="nav-prev">
<% if (prevPost) { %>
<a href="/<%= prevPost.slug %>" class="editorial-nav-link">
&larr; Previous: <%= prevPost.title %>
</a>
<% } %>
</div>
<div class="nav-next">
<% if (nextPost) { %>
<a href="/<%= nextPost.slug %>" class="editorial-nav-link">
Next: <%= nextPost.title %> &rarr;
</a>
<% } %>
</div>
</nav>
<% } %>
<!-- Modernized Comments Section -->
<%- include('../partials/comments', { post, comments, commentStatus }) %>
</article>
<!-- Ambient Floating Side Rail TOC (Positioned in left margin, Dropbox Paper style) -->
<% if (post.toc && post.toc.length > 0) { %>
<aside class="desktop-side-toc" id="side-toc">
<div class="side-toc-sticky">
<div class="side-toc-header">
<span class="side-toc-title">Contents</span>
<button type="button" class="side-toc-minimize-btn" id="side-toc-minimize" title="Minimize Table of Contents" aria-label="Minimize Table of Contents">&mdash;</button>
</div>
<nav class="side-toc-nav" id="side-toc-nav">
<ul class="side-toc-list">
<% post.toc.forEach(h => { %>
<li class="side-toc-item level-<%= h.level %>">
<a href="#<%= h.id %>" class="side-toc-link" data-id="<%= h.id %>">
<span class="toc-rail-indicator"></span>
<span class="toc-link-text"><%= h.title %></span>
</a>
</li>
<% }) %>
</ul>
</nav>
</div>
</aside>
<!-- Floating Dock Badge (shown when side TOC is minimized, or on compact/mobile screens) -->
<button type="button" class="floating-toc-badge" id="floating-toc-badge" aria-label="Open Table of Contents" title="Table of Contents">
<span class="badge-icon">📑</span>
<span class="badge-label">Contents</span>
<span class="badge-count"><%= post.toc.length %></span>
</button>
<!-- Mobile Slide-Up Drawer Sheet & Dark Backdrop -->
<div class="mobile-toc-overlay" id="mobile-toc-overlay"></div>
<div class="mobile-toc-sheet" id="mobile-toc-sheet">
<div class="mobile-sheet-header">
<div class="mobile-sheet-title">
<span>📑 Table of Contents</span>
<span class="pill" style="font-size: 0.75rem; background: var(--color-surface); border: 1px solid var(--color-border);"><%= post.toc.length %> sections</span>
</div>
<button type="button" class="mobile-sheet-close" id="mobile-sheet-close" aria-label="Close Table of Contents">&times;</button>
</div>
<nav class="mobile-sheet-body">
<ol class="mobile-sheet-list">
<% post.toc.forEach(h => { %>
<li class="mobile-sheet-item level-<%= h.level %>">
<a href="#<%= h.id %>" class="mobile-sheet-link"><%= h.title %></a>
</li>
<% }) %>
</ol>
</nav>
</div>
<% } %>
</div>
<%- include('../partials/foot', { pageType: 'post' }) %>