新增 OIDC/SSO、邮件验证码与 Gitea 项目同步,并强化 Feed 与管理后台。
作为 OIDC Provider 对接 Gitea;注册支持邮件验证码/验证码;侧栏同步公开仓库;Feed 分页、文章大纲、标签云与站点品牌设置。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -1,14 +1,17 @@
|
||||
import {
|
||||
Home, Star, LayoutDashboard,
|
||||
Home, Star, LayoutDashboard, FolderGit2, ArrowLeft,
|
||||
} from 'lucide-react';
|
||||
import { useNavigate, useLocation, useSearchParams } from 'react-router-dom';
|
||||
import type { Board } from '../api/types';
|
||||
import type { PostHeading } from '../utils/postHeadings';
|
||||
import { useAuth } from '../hooks/useAuth';
|
||||
import { cn } from '@/lib/utils';
|
||||
import { Skeleton } from '@/components/ui/skeleton';
|
||||
import { buildHomeUrl, parseFeedSort } from './FeedSortBar';
|
||||
import { navigateFeed } from '../utils/feedCache';
|
||||
import BoardIconDisplay from './BoardIconDisplay';
|
||||
import { getBoardThemeIndex } from '../utils/boardTheme';
|
||||
import ArticleOutline from './ArticleOutline';
|
||||
|
||||
// 内容页不参与左侧栏高亮(非 feed 浏览上下文)
|
||||
const NEUTRAL_SIDEBAR_PREFIXES = ['/post/', '/profile'];
|
||||
@@ -20,6 +23,7 @@ export function isNeutralSidebarRoute(pathname: string): boolean {
|
||||
function resolveMenuKey(pathname: string, activeBoard: number): string | null {
|
||||
if (isNeutralSidebarRoute(pathname)) return null;
|
||||
if (pathname.startsWith('/favorites')) return 'favorites';
|
||||
if (pathname.startsWith('/projects')) return 'projects';
|
||||
if (pathname.startsWith('/admin')) return 'admin';
|
||||
return activeBoard === 0 ? 'all' : String(activeBoard);
|
||||
}
|
||||
@@ -28,9 +32,25 @@ interface Props {
|
||||
boards: Board[];
|
||||
activeBoard: number;
|
||||
onSelectBoard: (id: number) => void;
|
||||
/** 板块列表首次拉取中 */
|
||||
boardsLoading?: boolean;
|
||||
/** 帖子详情:左侧切换为文章目录 */
|
||||
outlineMode?: boolean;
|
||||
outlineHeadings?: PostHeading[];
|
||||
outlineScrollRoot?: HTMLElement | null;
|
||||
outlineTitle?: string;
|
||||
}
|
||||
|
||||
export default function Sidebar({ boards, activeBoard, onSelectBoard }: Props) {
|
||||
export default function Sidebar({
|
||||
boards,
|
||||
activeBoard,
|
||||
onSelectBoard,
|
||||
boardsLoading = false,
|
||||
outlineMode = false,
|
||||
outlineHeadings = [],
|
||||
outlineScrollRoot = null,
|
||||
outlineTitle,
|
||||
}: Props) {
|
||||
const nav = useNavigate();
|
||||
const loc = useLocation();
|
||||
const [params] = useSearchParams();
|
||||
@@ -52,15 +72,48 @@ export default function Sidebar({ boards, activeBoard, onSelectBoard }: Props) {
|
||||
</button>
|
||||
);
|
||||
|
||||
if (outlineMode) {
|
||||
return (
|
||||
<aside className="sidebar sidebar--outline">
|
||||
<button
|
||||
type="button"
|
||||
className="sidebar-nav-item sidebar-outline-back"
|
||||
onClick={() => navigateFeed(nav, '/')}
|
||||
>
|
||||
<ArrowLeft aria-hidden />
|
||||
<span className="flex-1 truncate">返回首页</span>
|
||||
</button>
|
||||
<ArticleOutline
|
||||
headings={outlineHeadings}
|
||||
scrollRoot={outlineScrollRoot}
|
||||
title={outlineTitle || '文章目录'}
|
||||
/>
|
||||
</aside>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<aside className="sidebar">
|
||||
<div className="sidebar-section">浏览</div>
|
||||
<nav className="sidebar-nav">
|
||||
{navItem('all', '全部帖子', <Home aria-hidden />, () => { onSelectBoard(0); navigateFeed(nav, buildHomeUrl(0, sort)); })}
|
||||
{user && navItem('favorites', '我的收藏', <Star aria-hidden />, () => nav('/favorites'))}
|
||||
{navItem('projects', '开源码桶', <FolderGit2 aria-hidden />, () => nav('/projects'))}
|
||||
</nav>
|
||||
|
||||
{boards.length > 0 && (
|
||||
{(boardsLoading && boards.length === 0) ? (
|
||||
<>
|
||||
<div className="sidebar-section sidebar-section--boards">板块</div>
|
||||
<nav className="sidebar-nav sidebar-nav--skeleton" aria-busy="true" aria-label="板块加载中">
|
||||
{Array.from({ length: 4 }, (_, i) => (
|
||||
<div key={i} className="sidebar-nav-item sidebar-nav-item--skeleton">
|
||||
<Skeleton className="skeleton--sidebar-icon" />
|
||||
<Skeleton className="skeleton--sidebar-label" style={{ width: `${58 + (i % 3) * 12}%` }} />
|
||||
</div>
|
||||
))}
|
||||
</nav>
|
||||
</>
|
||||
) : boards.length > 0 ? (
|
||||
<>
|
||||
<div className="sidebar-section sidebar-section--boards">板块</div>
|
||||
<nav className="sidebar-nav">
|
||||
@@ -92,7 +145,7 @@ export default function Sidebar({ boards, activeBoard, onSelectBoard }: Props) {
|
||||
})}
|
||||
</nav>
|
||||
</>
|
||||
)}
|
||||
) : null}
|
||||
|
||||
{isAdmin && (
|
||||
<>
|
||||
|
||||
Reference in New Issue
Block a user