Files
haopengzhan 95a7dcb93b feat(admin): add ephemeral staging DB, read-only posts overview, and dynamic search
- Implement ephemeral staging mode (APP_ENV=staging) to isolate test/dev DB writes in /tmp
- Add read-only posts management dashboard under /guanli/posts with live links and comment counters
- Add hot re-indexing endpoint (/guanli/reindex) to refresh Markdown without restarting server
- Replace static recommended search config with dynamic frequency-based trending searches
- Remove early scaffold mockup file (dropbox/zh.md) and clean legacy mock test queries
- Add native Makefile with dev, dev-persistent, test, lint, and docker targets
- Update test suite and documentation for development workflows
2026-09-16 23:09:14 -07:00

91 lines
4.4 KiB
Plaintext

<%- include('../partials/head', { pageType: 'search' }) %>
<div class="content-container">
<div class="search-hero" style="margin-bottom: 2rem;">
<h1 style="font-size: 2.5rem; margin-bottom: 1.5rem; font-family: var(--font-serif);">Search</h1>
<form action="/search" method="GET" class="search-form-minimal" id="search-form">
<div class="search-input-wrapper">
<svg class="search-icon-svg" viewBox="0 0 24 24"><path d="M23.809 21.646l-6.205-6.205c1.167-1.605 1.857-3.579 1.857-5.711 0-5.365-4.365-9.73-9.731-9.73-5.365 0-9.73 4.365-9.73 9.73 0 5.366 4.365 9.73 9.73 9.73 2.034 0 3.923-.627 5.487-1.698l6.238 6.238 2.354-2.354zm-20.955-11.916c0-3.792 3.085-6.877 6.877-6.877s6.877 3.085 6.877 6.877-3.085 6.877-6.877 6.877c-3.793 0-6.877-3.085-6.877-6.877z"/></svg>
<input
type="search"
id="search-input"
name="q"
value="<%= query %>"
class="search-input-sleek"
placeholder="Search..."
autocomplete="off"
autofocus
>
</div>
</form>
<!-- Sleek Discovery & Recommended Searches -->
<div class="search-discovery-pills" style="margin-top: 1.5rem;">
<% if (recommended.customPills && recommended.customPills.length > 0) { %>
<div style="font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); margin-bottom: 0.6rem; font-weight: 600;">🔥 Trending Searches</div>
<div class="search-pills-grid" style="margin-bottom: 1.25rem;">
<% recommended.customPills.forEach(pill => { %>
<button type="button" class="pill search-pill-btn" data-query="<%= pill.query %>">
<%= pill.label %>
</button>
<% }) %>
</div>
<% } %>
<div style="font-size: 0.8rem; text-transform: uppercase; letter-spacing: 0.05em; color: var(--color-text-muted); margin-bottom: 0.6rem; font-weight: 600;">🏷️ Browse Topics</div>
<div class="search-pills-grid">
<% (recommended.dynamicPills || []).forEach(pill => { %>
<button type="button" class="pill search-pill-btn" data-query="<%= pill.query %>">
<%= pill.label %>
</button>
<% }) %>
</div>
</div>
</div>
<!-- Search Results -->
<% if (query) { %>
<div class="search-results-section" style="margin-top: 2.5rem; border-top: 1px solid var(--color-border); padding-top: 2rem;">
<div style="font-family: var(--font-sans); font-size: 0.95rem; color: var(--color-text-muted); margin-bottom: 1.5rem;">
<%= searchData.total %> result<%= searchData.total === 1 ? '' : 's' %> for "<%= query %>"
</div>
<% if (searchData.results.length > 0) { %>
<div class="search-results-list">
<% searchData.results.forEach(res => { %>
<article class="search-result-item" style="margin-bottom: 2rem; padding-bottom: 1.5rem; border-bottom: 1px solid var(--color-surface-soft);">
<h2 style="font-size: 1.45rem; margin-bottom: 0.35rem; font-family: var(--font-serif);">
<a href="/<%= res.post.slug %><%= res.post.lang && res.post.lang !== 'en' && !res.post.isDefault ? `/${res.post.lang}` : '' %>" style="color: var(--color-text-main); text-decoration: none;">
<%= res.post.title %>
</a>
</h2>
<div class="post-card-meta" style="margin-bottom: 0.5rem; font-size: 0.82rem; color: var(--color-text-muted);">
<time><%= res.post.date.toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' }) %></time>
<span class="meta-sep">&mdash;</span>
<span>by <%= res.post.author %></span>
<% if (res.post.category) { %>
<span>in <%= res.post.category %></span>
<% } %>
</div>
<% if (res.snippet) { %>
<p class="search-snippet" style="font-size: 0.95rem; color: var(--color-text-secondary); line-height: 1.6;">
<%- res.snippet %>
</p>
<% } %>
</article>
<% }) %>
</div>
<% } else { %>
<p style="color: var(--color-text-muted); padding: 2rem 0; font-size: 1.05rem;">
No articles found matching your query.
</p>
<% } %>
</div>
<% } %>
</div>
<%- include('../partials/foot', { pageType: 'search' }) %>