This commit is contained in:
freedakgmail
2025-12-22 00:38:20 +08:00
parent 5a604e89f9
commit c2b890994d
9 changed files with 507 additions and 240 deletions
+51 -23
View File
@@ -1,7 +1,7 @@
"use client"
import Link from "next/link"
import { BookOpen, Search, Settings, LogOut, User, ChevronDown, Plus, Trash2, Network, LayoutGrid, Calculator, HelpCircle, Calendar, Menu, X, Home, Users as UsersIcon, Clock, TreePine } from "lucide-react"
import { BookOpen, Search, Settings, LogOut, User, ChevronDown, Plus, Trash2, Network, LayoutGrid, Calculator, HelpCircle, Calendar, Menu, X, Home, Users as UsersIcon, Clock, TreePine, MapPin } from "lucide-react"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Avatar, AvatarFallback, AvatarImage } from "@/components/ui/avatar"
@@ -34,7 +34,7 @@ interface FamilyTree {
}
export function SiteHeader() {
const { searchMembers, searchResults, currentTree: familyCurrentTree } = useFamily()
const { searchMembers, searchResults, currentTree: familyCurrentTree, setHighlightedMemberId } = useFamily()
const { data: session, status } = useSession()
const { showAlert, showConfirm, showPrompt } = useDialog()
const pathname = usePathname()
@@ -241,6 +241,21 @@ export function SiteHeader() {
setShowResults(false)
}
// 在族谱图中定位成员
const handleLocateMember = (memberId: string) => {
setHighlightedMemberId(memberId)
// 如果不在族谱页面,跳转到族谱页面
if (pathname !== '/tree') {
const params = new URLSearchParams()
if (currentTree?.id) {
params.set('treeId', currentTree.id)
}
router.push(`/tree?${params.toString()}`)
}
setSearchQuery("")
setShowResults(false)
}
// 导航菜单项配置
const navItems = [
{ href: "/", label: "总览", icon: Home },
@@ -474,31 +489,44 @@ export function SiteHeader() {
{showResults && searchResults.length > 0 && (
<div className="absolute top-full mt-2 w-full bg-background border border-border rounded-lg shadow-lg max-h-96 overflow-y-auto z-50">
{searchResults.map((member) => (
<button
<div
key={member.id}
onClick={() => handleSelectMember(member.id)}
className="w-full px-4 py-3 text-left hover:bg-muted transition-colors border-b border-border last:border-0"
className="w-full px-4 py-3 hover:bg-muted transition-colors border-b border-border last:border-0 flex items-center gap-2"
>
<div className="flex items-center gap-3">
<div className="flex-1">
<div className="flex items-center gap-2">
<MemberNameWithStatus
name={member.fullName}
isDead={!!member.deathDate}
className="font-medium"
/>
<span className={`text-xs px-1.5 py-0.5 rounded ${member.gender === "MALE" ? "bg-blue-100 text-blue-700" : "bg-pink-100 text-pink-700"}`}>
{member.gender === "MALE" ? "男" : "女"}
</span>
<span className="text-xs text-muted-foreground">{member.generation}</span>
<button
onClick={() => handleSelectMember(member.id)}
className="flex-1 text-left"
>
<div className="flex items-center gap-3">
<div className="flex-1">
<div className="flex items-center gap-2">
<MemberNameWithStatus
name={member.fullName}
isDead={!!member.deathDate}
className="font-medium"
/>
<span className={`text-xs px-1.5 py-0.5 rounded ${member.gender === "MALE" ? "bg-blue-100 text-blue-700" : "bg-pink-100 text-pink-700"}`}>
{member.gender === "MALE" ? "男" : "女"}
</span>
<span className="text-xs text-muted-foreground">{member.generation}</span>
</div>
<p className="text-xs text-muted-foreground mt-1">
{member.birthDate && `生于 ${member.birthDate}`}
{member.birthPlace && ` · ${member.birthPlace}`}
</p>
</div>
<p className="text-xs text-muted-foreground mt-1">
{member.birthDate && `生于 ${member.birthDate}`}
{member.birthPlace && ` · ${member.birthPlace}`}
</p>
</div>
</div>
</button>
</button>
<Button
variant="ghost"
size="icon"
className="h-8 w-8 flex-shrink-0 text-muted-foreground hover:text-primary"
onClick={() => handleLocateMember(member.id)}
title="在族谱图中定位"
>
<MapPin className="h-4 w-4" />
</Button>
</div>
))}
</div>
)}