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
This commit is contained in:
2026-09-16 23:09:09 -07:00
parent 8c0b04db0e
commit f52b3fe9e4
87 changed files with 3417 additions and 190 deletions
+7 -3
View File
@@ -28,10 +28,14 @@
<% }) %>
</div>
<% if (totalPages > 1) { %>
<% if (totalPages > 1) {
const filterBaseUrl = activeFilter
? (activeFilter.type === 'category' ? `/category/${encodeURIComponent(activeFilter.value)}` : `/tag/${encodeURIComponent(activeFilter.value)}`)
: '/blogs';
%>
<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">
<a href="<%= filterBaseUrl %>?page=<%= currentPage - 1 %>" class="editorial-nav-link">
&larr; Previous Page
</a>
<% } %>
@@ -41,7 +45,7 @@
</span>
<% if (currentPage < totalPages) { %>
<a href="/blogs?page=<%= currentPage + 1 %><%= activeFilter ? `&${activeFilter.type}=${encodeURIComponent(activeFilter.value)}` : '' %>" class="editorial-nav-link">
<a href="<%= filterBaseUrl %>?page=<%= currentPage + 1 %>" class="editorial-nav-link">
Next Page &rarr;
</a>
<% } %>
+8 -44
View File
@@ -7,56 +7,20 @@
</div>
<% } %>
<% if (recentPosts && recentPosts.length> 0) { %>
<% if (recentPosts && recentPosts.length > 0) { %>
<section class="home-recent-posts"
style="margin-top: 5rem; padding-top: 3rem; border-top: 1px solid var(--color-border);">
<div style="display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 2rem;">
<h2 style="font-size: 2rem; margin: 0; font-family: var(--font-serif); font-weight: 400;">Recent Posts
</h2>
<div style="display: flex; justify-content: space-between; align-items: baseline; margin-bottom: 2.5rem;">
<h2 style="font-size: 2rem; margin: 0; font-family: var(--font-serif); font-weight: 400;">Recent Posts</h2>
<a href="/blogs" class="nav-link" style="font-size: 0.95rem; font-weight: 500;">View all blogs &rarr;</a>
</div>
<div class="home-posts-compact-list">
<% recentPosts.forEach(post=> { %>
<a href="/<%= post.slug %>" class="home-post-compact-item">
<% if (post.cover) { %>
<img src="<%= post.cover %>" alt="<%= post.title %>" class="home-post-thumb" loading="lazy">
<% } else { %>
<div class="home-post-thumb-placeholder">
<span>
<%= post.title.slice(0, 1) %>
</span>
</div>
<% } %>
<div class="home-post-compact-body">
<h3 class="home-post-compact-title">
<%= post.title %>
</h3>
<div class="home-post-compact-meta">
<time datetime="<%= post.date.toISOString() %>">
<%= post.date.toLocaleDateString('en-US', { month: 'short' , day: 'numeric' ,
year: 'numeric' }) %>
</time>
<% if (post.category) { %>
<span class="meta-sep">&bull;</span>
<span>
<%= post.category %>
</span>
<% } %>
<% if (post.availableLanguages && post.availableLanguages.length> 1) { %>
<span class="meta-sep">&bull;</span>
<span class="meta-lang-tag">[<%= post.availableLanguages.map(l=>
l.toUpperCase()).join('|') %>]</span>
<% } %>
</div>
<p class="home-post-compact-excerpt">
<%= post.excerpt %>
</p>
</div>
</a>
<% }) %>
<div class="home-posts-grid-4">
<% recentPosts.forEach(post => { %>
<%- include('../partials/post-card', { post }) %>
<% }) %>
</div>
</section>
<% } %>
<% } %>
</div>
<%- include('../partials/foot', { pageType: 'home' }) %>
+3 -3
View File
@@ -10,7 +10,7 @@
<span class="meta-sep">&mdash;</span>
<span>by <%= post.author %></span>
<% if (post.category) { %>
<span>in <a href="/blogs?category=<%= encodeURIComponent(post.category) %>" class="meta-category-link"><%= post.category %></a></span>
<span>in <a href="/category/<%= encodeURIComponent(post.category) %>" class="meta-category-link"><%= post.category %></a></span>
<% } %>
<!-- Inline Bilingual Language Switcher with stable line height -->
@@ -20,7 +20,7 @@
<span style="opacity: 0.7;">🌐</span>
<% post.availableLanguages.forEach(l => {
const isCurrent = (currentLang === l);
const targetUrl = (l === post.defaultLang || (l === 'en' && post.isDefault))
const targetUrl = (l === post.defaultLang || (post.isDefault && l === post.lang))
? `/${post.slug}`
: `/${post.slug}/${l}`;
const displayLabel = l === 'zh' ? '中文' : (l === 'en' ? 'English' : l.toUpperCase());
@@ -48,7 +48,7 @@
<div class="post-tags-container">
<span class="post-tags-label">Tags:</span>
<% post.tags.forEach(tag => { %>
<a href="/blogs?tag=<%= encodeURIComponent(tag.toLowerCase()) %>" class="tag-link">
<a href="/tag/<%= encodeURIComponent(tag.toLowerCase()) %>" class="tag-link">
#<%= tag %>
</a>
<% }) %>
+8
View File
@@ -33,6 +33,14 @@
</script>
<% } %>
<!-- Site Icons & Favicons -->
<link rel="icon" href="/favicon.ico" sizes="any">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="192x192" href="/android-chrome-192x192.png">
<link rel="icon" type="image/png" href="/favicon.png">
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
<link rel="shortcut icon" href="/favicon.ico">
<!-- RSS Link -->
<link rel="alternate" type="application/rss+xml" title="<%= site.title %> RSS Feed" href="/feed">
-3
View File
@@ -2,9 +2,6 @@
<div class="container header-inner">
<a href="/" class="brand">
<span class="brand-title"><%= site.title %></span>
<% if (site.tagline) { %>
<span class="brand-tagline"><%= site.tagline %></span>
<% } %>
</a>
<!-- Desktop Navigation -->