0.8.4.0
This commit is contained in:
@@ -695,7 +695,8 @@ export function MemberForm({ initialData, existingMembers = [], onSubmit, onCanc
|
||||
value={formData.birthDate || ""}
|
||||
isLunar={formData.isLunarDate || false}
|
||||
onChange={(value) => handleChange("birthDate", value)}
|
||||
showLunarToggle={false}
|
||||
onLunarChange={(isLunar) => handleChange("isLunarDate", isLunar)}
|
||||
showLunarToggle={true}
|
||||
/>
|
||||
<DateInputWithLunar
|
||||
id="deathDate"
|
||||
@@ -703,7 +704,8 @@ export function MemberForm({ initialData, existingMembers = [], onSubmit, onCanc
|
||||
value={formData.deathDate || ""}
|
||||
isLunar={formData.isLunarDate || false}
|
||||
onChange={(value) => handleChange("deathDate", value)}
|
||||
showLunarToggle={false}
|
||||
onLunarChange={(isLunar) => handleChange("isLunarDate", isLunar)}
|
||||
showLunarToggle={true}
|
||||
/>
|
||||
</div>
|
||||
</ChineseCardContent>
|
||||
|
||||
+51
-23
@@ -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>
|
||||
)}
|
||||
|
||||
@@ -26,6 +26,7 @@ interface FamilyNodeProps {
|
||||
isRoot?: boolean
|
||||
onSelect?: (member: FamilyMember) => void
|
||||
isHighlighted?: boolean
|
||||
highlightedMemberId?: string | null
|
||||
relationMode?: boolean
|
||||
isSelected?: boolean
|
||||
selectedMembers?: string[]
|
||||
@@ -502,6 +503,7 @@ export function FamilyNode({
|
||||
isRoot,
|
||||
onSelect,
|
||||
isHighlighted,
|
||||
highlightedMemberId,
|
||||
relationMode,
|
||||
isSelected,
|
||||
selectedMembers = [],
|
||||
@@ -535,6 +537,11 @@ export function FamilyNode({
|
||||
// 有配偶时,合并到一个卡片中显示(类似D3布局)
|
||||
const isMale = member.gender === 'MALE'
|
||||
const isDead = !!member.deathDate
|
||||
|
||||
// 检查是否有任何配偶被高亮,如果是则整个卡片高亮
|
||||
const isAnySpouseHighlighted = spouseList.some(sp => sp.id === highlightedMemberId)
|
||||
const isCardHighlighted = isHighlighted || isAnySpouseHighlighted
|
||||
|
||||
// 使用 isRoot prop 而不是 isFounder 字段
|
||||
const isFounder = isRoot === true
|
||||
const avatarUrl = member.avatarUrl
|
||||
@@ -552,8 +559,8 @@ export function FamilyNode({
|
||||
"relative rounded-xl overflow-hidden transition-all duration-300",
|
||||
"shadow-[0_4px_20px_rgba(0,0,0,0.08)] hover:shadow-[0_12px_40px_rgba(0,0,0,0.15)]",
|
||||
"hover:scale-[1.02] hover:-translate-y-1",
|
||||
isHighlighted
|
||||
? "bg-gradient-to-br from-yellow-50 via-amber-50 to-yellow-100 ring-2 ring-yellow-400"
|
||||
isCardHighlighted
|
||||
? "bg-gradient-to-br from-yellow-50 via-amber-50 to-yellow-100 ring-2 ring-yellow-400 shadow-[0_8px_30px_rgba(234,179,8,0.4)]"
|
||||
: isFounder || isRoot
|
||||
? "bg-gradient-to-br from-amber-50 via-orange-50 to-yellow-50"
|
||||
: "bg-gradient-to-br from-slate-50 via-gray-50 to-slate-100"
|
||||
@@ -562,7 +569,7 @@ export function FamilyNode({
|
||||
{/* 顶部装饰条 */}
|
||||
<div className={cn(
|
||||
"h-1.5",
|
||||
isHighlighted ? "bg-gradient-to-r from-yellow-400 via-amber-500 to-yellow-400"
|
||||
isCardHighlighted ? "bg-gradient-to-r from-yellow-400 via-amber-500 to-yellow-400"
|
||||
: isFounder || isRoot ? "bg-gradient-to-r from-amber-400 via-orange-500 to-amber-400"
|
||||
: "bg-gradient-to-r from-slate-400 via-gray-500 to-slate-400"
|
||||
)} />
|
||||
@@ -669,8 +676,8 @@ export function FamilyNode({
|
||||
{/* 配偶卡片 */}
|
||||
<div
|
||||
className={cn(
|
||||
"flex flex-col items-center cursor-pointer min-w-[80px] relative",
|
||||
relationMode && "hover:ring-2 hover:ring-primary/50 rounded-lg p-1"
|
||||
"flex flex-col items-center cursor-pointer min-w-[80px] relative p-2 rounded-lg transition-all",
|
||||
relationMode && "hover:ring-2 hover:ring-primary/50"
|
||||
)}
|
||||
data-member-id={sp.id}
|
||||
onClick={() => onSelect?.(sp)}
|
||||
|
||||
@@ -86,6 +86,7 @@ export const TreeNode = memo(function TreeNode({
|
||||
onSelect={handleSelect}
|
||||
isRoot={isRoot}
|
||||
isHighlighted={isHighlighted}
|
||||
highlightedMemberId={highlightedMemberId}
|
||||
relationMode={relationMode}
|
||||
isSelected={isSelected}
|
||||
selectedMembers={selectedMembers}
|
||||
|
||||
Reference in New Issue
Block a user