Files
haopengzhan 8c0b04db0e feat: initial release of pengzhan.dev personal editorial blog platform
- Editorial web platform built with Node.js, Express, EJS, and Vanilla CSS
- Markdown content engine with YAML frontmatter, bilingual variants, and hot-reload watcher
- Unified SQLite with FTS5 search indexing, query logging, and schema filters
- Centered editorial post layout with margin-docked left TOC and mobile bottom sheet
- WordPress-grade comment system with moderation dashboard and bulk operations under /guanli
- Complete SEO suite (JSON-LD structured data, RSS/Atom feeds, XML sitemap, robots.txt)
- CI/CD workflows for linting, security audits (Gitleaks), automated tests, and Docker releases
2026-09-16 23:08:53 -07:00

28 lines
1.0 KiB
Plaintext

<a href="/<%= post.slug %>" class="post-card">
<% if (post.cover) { %>
<img src="<%= post.cover %>" alt="<%= post.title %>" class="post-card-cover" loading="lazy">
<% } else { %>
<div class="post-card-cover-placeholder">
<span><%= post.title.slice(0, 1) %></span>
</div>
<% } %>
<div class="post-card-body">
<h2 class="post-card-title"><%= post.title %></h2>
<div class="post-card-meta">
<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 <%= post.category %></span>
<% } %>
<% if (post.availableLanguages && post.availableLanguages.length > 1) { %>
<span class="meta-lang-tag">[<%= post.availableLanguages.map(l => l.toUpperCase()).join('|') %>]</span>
<% } %>
</div>
<p class="post-card-excerpt"><%= post.excerpt %></p>
</div>
</a>