Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion apps/desktop/src/pages/Library.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ export default function Library() {
<div className="space-y-8">
{/* Header */}
<div className="flex flex-col sm:flex-row sm:items-center justify-between gap-4">
<div>
<div className="hidden md:block">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
我的书库
</h1>
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/pages/MemberBenefits.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -282,7 +282,7 @@ export default function MemberBenefits() {
<div className="inline-flex items-center justify-center w-16 h-16 bg-gradient-to-br from-amber-400 to-orange-500 rounded-2xl shadow-xl mb-4">
<Crown className="w-8 h-8 text-white" />
</div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
<h1 className="hidden md:block text-3xl font-bold text-gray-900 dark:text-white">
会员特权
</h1>
<p className="text-gray-500 dark:text-gray-400 mt-2">
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/pages/MemberDetail.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ export default function MemberDetail() {
<div className={`inline-flex items-center justify-center w-20 h-20 bg-gradient-to-br ${levelColor} rounded-2xl shadow-xl mb-4`}>
<Crown className="w-10 h-10 text-white" />
</div>
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">我的会员</h1>
<h1 className="hidden md:block text-3xl font-bold text-gray-900 dark:text-white">我的会员</h1>
<p className="text-gray-500 dark:text-gray-400 mt-1">感谢您对 BookDock 的支持</p>
</div>

Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/pages/Notes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ export default function Notes() {
>
<ArrowLeft className="w-5 h-5" />
</button>
<h1 className="text-2xl font-bold text-gray-900 dark:text-white">
<h1 className="hidden md:block text-2xl font-bold text-gray-900 dark:text-white">
{headerTitle}
</h1>
</div>
Expand Down
89 changes: 82 additions & 7 deletions apps/desktop/src/pages/Profile.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// @ts-nocheck
import { useState, useEffect, useCallback, useMemo, useRef } from "react";
import { useNavigate } from "react-router-dom";
import { useNavigate, Link } from "react-router-dom";
import { getApiClient, Book, Collection } from "@bookdock/api-client";
import { useAuthStore } from "../stores/authStore";
import { getCoverImageUrl } from "../utils/network";
Expand All @@ -17,6 +17,11 @@ import {
Search,
Clock,
User,
Settings,
Crown,
RefreshCw,
Shield,
LogOut,
} from "lucide-react";

function formatDate(dateStr: string): string {
Expand Down Expand Up @@ -53,7 +58,7 @@ type TabKey = "collections" | "reading" | "favorites" | "downloads" | "notes";

export default function Profile() {
const navigate = useNavigate();
const { user } = useAuthStore();
const { user, logout } = useAuthStore();
const [activeTab, setActiveTab] = useState<TabKey>("collections");
const [collections, setCollections] = useState<Collection[]>([]);
const [favorites, setFavorites] = useState<Book[]>([]);
Expand All @@ -67,6 +72,21 @@ export default function Profile() {
const noteLimit = 20;
const [showCreateModal, setShowCreateModal] = useState(false);
const [newCollectionName, setNewCollectionName] = useState("");
const [showDropdown, setShowDropdown] = useState(false);
const dropdownRef = useRef<HTMLDivElement>(null);

// Close dropdown on click outside
useEffect(() => {
const handleClickOutside = (event: MouseEvent) => {
if (dropdownRef.current && !dropdownRef.current.contains(event.target as Node)) {
setShowDropdown(false);
}
};
if (showDropdown) {
document.addEventListener("mousedown", handleClickOutside);
}
return () => document.removeEventListener("mousedown", handleClickOutside);
}, [showDropdown]);

const fetchData = useCallback(async () => {
setIsLoading(true);
Expand Down Expand Up @@ -442,14 +462,69 @@ export default function Profile() {
<div className="space-y-6">
{/* Header */}
<div className="flex items-center justify-between">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">我的</h1>
<div className="flex items-center gap-2">
<div className="relative md:hidden" ref={dropdownRef}>
<button
onClick={() => setShowDropdown(!showDropdown)}
className="p-2 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
>
<Plus className="w-5 h-5" />
</button>
{showDropdown && (
<div className="absolute left-0 top-full mt-1 w-48 bg-white dark:bg-gray-800 rounded-xl shadow-lg border border-gray-200 dark:border-gray-700 z-50 py-1">
<button
onClick={() => { setShowCreateModal(true); setShowDropdown(false); }}
className="w-full flex items-center gap-2 px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<Plus className="w-4 h-4" />
<span>新建书单</span>
</button>
<Link
to="/membership"
onClick={() => setShowDropdown(false)}
className="flex items-center gap-2 px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<Crown className="w-4 h-4" />
<span>会员中心</span>
</Link>
<Link
to="/notes"
onClick={() => setShowDropdown(false)}
className="flex items-center gap-2 px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<StickyNote className="w-4 h-4" />
<span>笔记</span>
</Link>
{user?.role === "admin" && (
<Link
to="/admin"
onClick={() => setShowDropdown(false)}
className="flex items-center gap-2 px-4 py-2.5 text-sm text-gray-700 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 transition-colors"
>
<Shield className="w-4 h-4" />
<span>后台管理</span>
</Link>
)}
<div className="mx-3 my-1 border-t border-gray-100 dark:border-gray-700" />
<button
onClick={() => { logout(); setShowDropdown(false); }}
className="w-full flex items-center gap-2 px-4 py-2.5 text-sm text-red-600 dark:text-red-400 hover:bg-red-50 dark:hover:bg-red-900/20 transition-colors"
>
<LogOut className="w-4 h-4" />
<span>退出登录</span>
</button>
</div>
)}
</div>
<h1 className="hidden md:block text-3xl font-bold text-gray-900 dark:text-white">我的</h1>
</div>
<div className="flex items-center gap-2">
<button
onClick={() => setShowCreateModal(true)}
className="flex items-center gap-1 px-3 py-2 bg-blue-500 text-white rounded-lg text-sm hover:bg-blue-600 transition-colors"
onClick={() => navigate("/settings")}
className="md:hidden p-2 text-gray-500 dark:text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 hover:bg-gray-100 dark:hover:bg-gray-700 rounded-lg transition-colors"
title="设置"
>
<Plus className="w-4 h-4" />
新建书单
<Settings className="w-5 h-5" />
</button>
</div>
</div>
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/pages/Recommend.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ export default function Recommend() {
return (
<div className="space-y-10">
{/* Header */}
<div className="flex items-center gap-3">
<div className="hidden md:flex items-center gap-3">
<Sparkles className="w-6 h-6 text-amber-500" />
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">
推荐
Expand Down
2 changes: 1 addition & 1 deletion apps/desktop/src/pages/Settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ export default function Settings() {

return (
<div className="max-w-3xl mx-auto space-y-6">
<h1 className="text-3xl font-bold text-gray-900 dark:text-white">设置</h1>
<h1 className="hidden md:block text-3xl font-bold text-gray-900 dark:text-white">设置</h1>

{/* Profile Section */}
<Card>
Expand Down
Loading