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
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
<%- include('../partials/head', { pageType: 'blogs' }) %>
|
||||
|
||||
<div class="blogs-container">
|
||||
<div class="blogs-header" style="margin-bottom: 2.5rem;">
|
||||
<h1 style="font-size: 2.8rem; margin-bottom: 0.5rem; font-family: var(--font-serif);">
|
||||
<%= activeFilter ? (activeFilter.type === 'category' ? `${activeFilter.value} Posts` : `Posts tagged #${activeFilter.value}`) : 'Blogs' %>
|
||||
</h1>
|
||||
|
||||
<% if (activeFilter) { %>
|
||||
<div style="margin-top: 1rem; display: flex; align-items: center; gap: 0.75rem;">
|
||||
<span style="font-family: var(--font-sans); font-size: 0.9rem; color: var(--color-text-muted);">
|
||||
Filtering by <%= activeFilter.type %>:
|
||||
</span>
|
||||
<span class="pill" style="background: var(--color-text-main); color: white;">
|
||||
<%= activeFilter.value %>
|
||||
</span>
|
||||
<a href="/blogs" class="pill" style="color: var(--color-text-muted); font-size: 0.8rem;">
|
||||
× Clear filter
|
||||
</a>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<% if (posts && posts.length > 0) { %>
|
||||
<div class="posts-grid-original">
|
||||
<% posts.forEach(post => { %>
|
||||
<%- include('../partials/post-card', { post }) %>
|
||||
<% }) %>
|
||||
</div>
|
||||
|
||||
<% if (totalPages > 1) { %>
|
||||
<nav class="pagination-editorial" aria-label="Blog pagination">
|
||||
<% if (currentPage > 1) { %>
|
||||
<a href="/blogs?page=<%= currentPage - 1 %><%= activeFilter ? `&${activeFilter.type}=${encodeURIComponent(activeFilter.value)}` : '' %>" class="editorial-nav-link">
|
||||
← Previous Page
|
||||
</a>
|
||||
<% } %>
|
||||
|
||||
<span style="font-family: var(--font-sans); font-size: 0.9rem; color: var(--color-text-muted);">
|
||||
Page <%= currentPage %> of <%= totalPages %>
|
||||
</span>
|
||||
|
||||
<% if (currentPage < totalPages) { %>
|
||||
<a href="/blogs?page=<%= currentPage + 1 %><%= activeFilter ? `&${activeFilter.type}=${encodeURIComponent(activeFilter.value)}` : '' %>" class="editorial-nav-link">
|
||||
Next Page →
|
||||
</a>
|
||||
<% } %>
|
||||
</nav>
|
||||
<% } %>
|
||||
<% } else { %>
|
||||
<div style="text-align: center; padding: 4rem 1rem;">
|
||||
<p style="font-size: 1.15rem; color: var(--color-text-muted);">No blog posts found matching your criteria.</p>
|
||||
<a href="/blogs" class="btn btn-primary" style="margin-top: 1rem; text-decoration: none;">View All Posts</a>
|
||||
</div>
|
||||
<% } %>
|
||||
</div>
|
||||
|
||||
<%- include('../partials/foot', { pageType: 'blogs' }) %>
|
||||
Reference in New Issue
Block a user