chore: checkpoint ai search comments and i18n foundation
This commit is contained in:
@@ -4,8 +4,8 @@ import TerminalWindow from '../../components/ui/TerminalWindow.astro';
|
||||
import CommandPrompt from '../../components/ui/CommandPrompt.astro';
|
||||
import FilterPill from '../../components/ui/FilterPill.astro';
|
||||
import PostCard from '../../components/PostCard.astro';
|
||||
import { terminalConfig } from '../../lib/config/terminal';
|
||||
import { api } from '../../lib/api/client';
|
||||
import { getI18n } from '../../lib/i18n';
|
||||
import type { Category, Post, Tag } from '../../lib/types';
|
||||
|
||||
export const prerender = false;
|
||||
@@ -15,6 +15,7 @@ let allTags: Tag[] = [];
|
||||
let allCategories: Category[] = [];
|
||||
const url = new URL(Astro.request.url);
|
||||
const selectedSearch = url.searchParams.get('search') || '';
|
||||
const { t } = getI18n(Astro);
|
||||
|
||||
try {
|
||||
allPosts = selectedSearch ? await api.searchPosts(selectedSearch) : await api.getPosts();
|
||||
@@ -54,9 +55,9 @@ const startIndex = (currentPage - 1) * postsPerPage;
|
||||
const paginatedPosts = filteredPosts.slice(startIndex, startIndex + postsPerPage);
|
||||
|
||||
const postTypeFilters = [
|
||||
{ id: 'all', name: '全部', icon: 'fa-stream' },
|
||||
{ id: 'article', name: terminalConfig.postTypes.article.label, icon: 'fa-file-alt' },
|
||||
{ id: 'tweet', name: terminalConfig.postTypes.tweet.label, icon: 'fa-comment-dots' }
|
||||
{ id: 'all', name: t('common.all'), icon: 'fa-stream' },
|
||||
{ id: 'article', name: t('common.article'), icon: 'fa-file-alt' },
|
||||
{ id: 'tweet', name: t('common.tweet'), icon: 'fa-comment-dots' }
|
||||
];
|
||||
|
||||
const typePromptCommand = `./filter --type ${selectedType || 'all'}`;
|
||||
@@ -89,21 +90,21 @@ const buildArticlesUrl = ({
|
||||
};
|
||||
---
|
||||
|
||||
<BaseLayout title="文章列表 - Termi">
|
||||
<BaseLayout title={`${t('articlesPage.title')} - Termi`}>
|
||||
<div class="max-w-5xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
|
||||
<TerminalWindow title="~/articles/index" class="w-full">
|
||||
<div class="px-4 pb-2">
|
||||
<CommandPrompt command="fd . ./content/posts --full-path" />
|
||||
|
||||
<div class="ml-4 mt-4 space-y-3">
|
||||
<h1 class="text-3xl font-bold tracking-tight text-[var(--title-color)]">文章索引</h1>
|
||||
<h1 class="text-3xl font-bold tracking-tight text-[var(--title-color)]">{t('articlesPage.title')}</h1>
|
||||
<p class="max-w-2xl text-sm leading-7 text-[var(--text-secondary)]">
|
||||
按类型、分类和标签筛选内容。这里保留更轻的 prompt 标题结构,下方筛选拆成独立区域。
|
||||
{t('articlesPage.description')}
|
||||
</p>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
<span class="terminal-stat-pill">
|
||||
<i class="fas fa-file-lines text-[var(--primary)]"></i>
|
||||
共 {filteredPosts.length} 篇
|
||||
{t('articlesPage.totalPosts', { count: filteredPosts.length })}
|
||||
</span>
|
||||
{selectedSearch && (
|
||||
<span class="terminal-stat-pill">
|
||||
@@ -154,7 +155,7 @@ const buildArticlesUrl = ({
|
||||
active={!selectedCategory}
|
||||
>
|
||||
<i class="fas fa-folder-tree"></i>
|
||||
<span class="font-medium">全部分类</span>
|
||||
<span class="font-medium">{t('articlesPage.allCategories')}</span>
|
||||
</FilterPill>
|
||||
{allCategories.map(category => (
|
||||
<FilterPill
|
||||
@@ -181,7 +182,7 @@ const buildArticlesUrl = ({
|
||||
active={!selectedTag}
|
||||
>
|
||||
<i class="fas fa-hashtag"></i>
|
||||
<span class="font-medium">全部标签</span>
|
||||
<span class="font-medium">{t('articlesPage.allTags')}</span>
|
||||
</FilterPill>
|
||||
{allTags.map(tag => (
|
||||
<FilterPill
|
||||
@@ -211,13 +212,13 @@ const buildArticlesUrl = ({
|
||||
<span class="terminal-section-icon">
|
||||
<i class="fas fa-folder-open"></i>
|
||||
</span>
|
||||
<h2 class="text-xl font-semibold text-[var(--title-color)]">没有匹配结果</h2>
|
||||
<h2 class="text-xl font-semibold text-[var(--title-color)]">{t('articlesPage.emptyTitle')}</h2>
|
||||
<p class="text-sm leading-7 text-[var(--text-secondary)]">
|
||||
当前筛选条件下没有找到文章。可以清空标签或关键字,重新浏览整个内容目录。
|
||||
{t('articlesPage.emptyDescription')}
|
||||
</p>
|
||||
<a href="/articles" class="terminal-action-button terminal-action-button-primary">
|
||||
<i class="fas fa-rotate-left"></i>
|
||||
<span>reset filters</span>
|
||||
<span>{t('common.resetFilters')}</span>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -228,7 +229,7 @@ const buildArticlesUrl = ({
|
||||
<div class="px-4 py-6">
|
||||
<div class="terminal-panel-muted ml-4 mt-4 flex flex-col gap-4 sm:flex-row sm:items-center sm:justify-between">
|
||||
<span class="text-sm text-[var(--text-secondary)]">
|
||||
page {currentPage}/{totalPages} · {totalPosts} results
|
||||
{t('articlesPage.pageSummary', { current: currentPage, total: totalPages, count: totalPosts })}
|
||||
</span>
|
||||
<div class="flex flex-wrap gap-2">
|
||||
{currentPage > 1 && (
|
||||
@@ -237,7 +238,7 @@ const buildArticlesUrl = ({
|
||||
class="terminal-action-button"
|
||||
>
|
||||
<i class="fas fa-chevron-left"></i>
|
||||
<span>prev</span>
|
||||
<span>{t('articlesPage.previous')}</span>
|
||||
</a>
|
||||
)}
|
||||
{currentPage < totalPages && (
|
||||
@@ -245,7 +246,7 @@ const buildArticlesUrl = ({
|
||||
href={buildArticlesUrl({ page: currentPage + 1 })}
|
||||
class="terminal-action-button terminal-action-button-primary"
|
||||
>
|
||||
<span>next</span>
|
||||
<span>{t('articlesPage.next')}</span>
|
||||
<i class="fas fa-chevron-right"></i>
|
||||
</a>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user