支持 app.ini 配置与系统服务安装,并优化前端布局与无障碍体验。

引入类 Gitea 的 app.ini、Windows Service/systemd 控制;前端增加侧栏抽屉、回到顶部、标签输入与浮层 a11y。

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-07-29 14:09:58 +08:00
parent 962bb15298
commit 9487c8ab02
37 changed files with 2025 additions and 403 deletions

View File

@@ -1,23 +1,19 @@
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { ArrowLeft } from 'lucide-react';
import { ArrowLeft, Star } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Spinner } from '@/components/ui/spinner';
import { notify } from '@/lib/notify';
import { api } from '../api/client';
import type { PostItem } from '../api/types';
import { useAuth } from '../hooks/useAuth';
import { formatTime } from '../utils/content';
import PostListItem from '../components/PostListItem';
interface FavItem {
id: number;
post_id: number;
created_at: string;
post?: {
id: number;
title: string;
board?: { name: string };
user?: { nickname: string };
};
post?: PostItem;
}
export default function FavoritesPage() {
@@ -30,7 +26,7 @@ export default function FavoritesPage() {
if (authLoading) return;
if (!user) { nav('/login'); return; }
api.favorites()
.then(d => setList(Array.isArray(d.favorites) ? d.favorites : []))
.then(d => setList(Array.isArray(d.favorites) ? d.favorites as FavItem[] : []))
.catch(e => notify.error(e.message))
.finally(() => setLoading(false));
}, [user, authLoading, nav]);
@@ -51,26 +47,31 @@ export default function FavoritesPage() {
{list.length === 0 ? (
<div className="empty-state">
<Star className="empty-state-icon" aria-hidden size={36} strokeWidth={1.5} />
<p></p>
<Button onClick={() => nav('/')}></Button>
</div>
) : (
<div className="content-surface">
{list.map(fav => (
<div
key={fav.id}
className="post-row"
onClick={() => nav(`/post/${fav.post_id}`)}
>
<div className="post-body">
<div className="post-title">{fav.post?.title || '帖子已删除'}</div>
<div className="post-meta">
{fav.post?.board?.name && <span>{fav.post.board.name}</span>}
{fav.post?.user?.nickname && <span>{fav.post.user.nickname}</span>}
<span> {formatTime(fav.created_at)}</span>
fav.post ? (
<PostListItem
key={fav.id}
post={fav.post}
onClick={() => nav(`/post/${fav.post_id}`)}
/>
) : (
<button
key={fav.id}
type="button"
className="post-row"
onClick={() => nav(`/post/${fav.post_id}`)}
>
<div className="post-body">
<div className="post-title"></div>
</div>
</div>
</div>
</button>
)
))}
</div>
)}