- 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
59 lines
2.4 KiB
Plaintext
59 lines
2.4 KiB
Plaintext
<%- 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' }) %>
|