91 lines
3.0 KiB
TypeScript
91 lines
3.0 KiB
TypeScript
"use client"
|
|
|
|
import type React from "react"
|
|
|
|
import { SiteHeader } from "@/components/site-header"
|
|
import { TreeLayout } from "@/components/tree/tree-layout"
|
|
import { useFamily } from "@/context/family-context"
|
|
import { Button } from "@/components/ui/button"
|
|
import { ZoomIn, ZoomOut, Move, Filter } from "lucide-react"
|
|
import { useState, useRef } from "react"
|
|
|
|
export default function TreePage() {
|
|
const { treeData } = useFamily()
|
|
const [scale, setScale] = useState(1)
|
|
const [position, setPosition] = useState({ x: 0, y: 0 })
|
|
const [isDragging, setIsDragging] = useState(false)
|
|
const [startPos, setStartPos] = useState({ x: 0, y: 0 })
|
|
const containerRef = useRef<HTMLDivElement>(null)
|
|
|
|
const handleMouseDown = (e: React.MouseEvent) => {
|
|
setIsDragging(true)
|
|
setStartPos({ x: e.clientX - position.x, y: e.clientY - position.y })
|
|
}
|
|
|
|
const handleMouseMove = (e: React.MouseEvent) => {
|
|
if (!isDragging) return
|
|
setPosition({
|
|
x: e.clientX - startPos.x,
|
|
y: e.clientY - startPos.y,
|
|
})
|
|
}
|
|
|
|
const handleMouseUp = () => {
|
|
setIsDragging(false)
|
|
}
|
|
|
|
// Handle root not found
|
|
if (!treeData.rootId) {
|
|
return (
|
|
<div className="min-h-screen bg-background flex flex-col">
|
|
<SiteHeader />
|
|
<div className="flex-1 flex items-center justify-center text-muted-foreground">No family tree data found.</div>
|
|
</div>
|
|
)
|
|
}
|
|
|
|
return (
|
|
<div className="h-screen flex flex-col bg-muted/30 overflow-hidden">
|
|
<SiteHeader />
|
|
|
|
{/* Toolbar */}
|
|
<div className="absolute top-20 left-4 z-20 flex flex-col gap-2 bg-background/80 backdrop-blur p-2 rounded-lg border shadow-sm">
|
|
<Button variant="outline" size="icon" onClick={() => setScale((s) => Math.min(s + 0.1, 2))}>
|
|
<ZoomIn className="h-4 w-4" />
|
|
</Button>
|
|
<Button variant="outline" size="icon" onClick={() => setScale((s) => Math.max(s - 0.1, 0.1))}>
|
|
<ZoomOut className="h-4 w-4" />
|
|
</Button>
|
|
<Button variant="outline" size="icon" onClick={() => setPosition({ x: 0, y: 0 })}>
|
|
<Move className="h-4 w-4" />
|
|
</Button>
|
|
<div className="h-px bg-border my-1" />
|
|
<Button variant="outline" size="icon">
|
|
<Filter className="h-4 w-4" />
|
|
</Button>
|
|
</div>
|
|
|
|
{/* Tree Canvas */}
|
|
<div
|
|
ref={containerRef}
|
|
className="flex-1 overflow-hidden cursor-move relative touch-none bg-[url('https://www.transparenttextures.com/patterns/rice-paper.png')] bg-repeat"
|
|
onMouseDown={handleMouseDown}
|
|
onMouseMove={handleMouseMove}
|
|
onMouseUp={handleMouseUp}
|
|
onMouseLeave={handleMouseUp}
|
|
>
|
|
<div
|
|
style={{
|
|
transform: `translate(${position.x}px, ${position.y}px) scale(${scale})`,
|
|
transformOrigin: "top center",
|
|
transition: isDragging ? "none" : "transform 0.1s ease-out",
|
|
}}
|
|
className="absolute min-w-full min-h-full flex justify-center pt-20 pb-20"
|
|
>
|
|
<TreeLayout rootId={treeData.rootId} />
|
|
</div>
|
|
</div>
|
|
</div>
|
|
)
|
|
}
|