147 lines
4.2 KiB
TypeScript
147 lines
4.2 KiB
TypeScript
"use client";
|
|
|
|
import { useReviewStore } from "@/hooks/use-review-player";
|
|
import { Button } from "@/components/ui/button";
|
|
import { cn } from "@/lib/utils";
|
|
import type { AnnotationTool } from "@/types";
|
|
import {
|
|
Pencil,
|
|
ArrowUpRight,
|
|
Square,
|
|
Circle,
|
|
Minus,
|
|
Plus,
|
|
} from "lucide-react";
|
|
import {
|
|
Tooltip,
|
|
TooltipContent,
|
|
TooltipTrigger,
|
|
} from "@/components/ui/tooltip";
|
|
|
|
const TOOLS: { tool: AnnotationTool; icon: React.ElementType; label: string }[] = [
|
|
{ tool: "freehand", icon: Pencil, label: "Freehand" },
|
|
{ tool: "arrow", icon: ArrowUpRight, label: "Arrow" },
|
|
{ tool: "rectangle", icon: Square, label: "Rectangle" },
|
|
{ tool: "circle", icon: Circle, label: "Circle" },
|
|
];
|
|
|
|
const COLORS = [
|
|
{ value: "#ef4444", label: "Red" },
|
|
{ value: "#f59e0b", label: "Amber" },
|
|
{ value: "#22c55e", label: "Green" },
|
|
{ value: "#3b82f6", label: "Blue" },
|
|
{ value: "#a855f7", label: "Purple" },
|
|
{ value: "#ffffff", label: "White" },
|
|
{ value: "#000000", label: "Black" },
|
|
];
|
|
|
|
export function AnnotationTools() {
|
|
const {
|
|
isAnnotating,
|
|
selectedTool,
|
|
selectedColor,
|
|
strokeWidth,
|
|
setSelectedTool,
|
|
setSelectedColor,
|
|
setStrokeWidth,
|
|
setAnnotating,
|
|
} = useReviewStore();
|
|
|
|
if (!isAnnotating) return null;
|
|
|
|
return (
|
|
<div className="flex items-center gap-3 px-3 py-2 bg-zinc-900/95 border-b border-white/5">
|
|
{/* Tool selector */}
|
|
<div className="flex items-center gap-1">
|
|
{TOOLS.map(({ tool, icon: Icon, label }) => (
|
|
<Tooltip key={tool}>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon-sm"
|
|
className={cn(
|
|
"text-zinc-400 hover:text-white",
|
|
selectedTool === tool &&
|
|
"bg-primary/20 text-primary hover:bg-primary/30"
|
|
)}
|
|
onClick={() => setSelectedTool(tool)}
|
|
>
|
|
<Icon className="h-4 w-4" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>{label}</TooltipContent>
|
|
</Tooltip>
|
|
))}
|
|
</div>
|
|
|
|
<div className="h-5 w-px bg-white/10" />
|
|
|
|
{/* Color picker */}
|
|
<div className="flex items-center gap-1.5">
|
|
{COLORS.map((c) => (
|
|
<Tooltip key={c.value}>
|
|
<TooltipTrigger asChild>
|
|
<button
|
|
className={cn(
|
|
"h-5 w-5 rounded-full border-2 transition-transform hover:scale-110",
|
|
selectedColor === c.value
|
|
? "border-white scale-110"
|
|
: "border-transparent"
|
|
)}
|
|
style={{ backgroundColor: c.value }}
|
|
onClick={() => setSelectedColor(c.value)}
|
|
title={c.label}
|
|
/>
|
|
</TooltipTrigger>
|
|
<TooltipContent>{c.label}</TooltipContent>
|
|
</Tooltip>
|
|
))}
|
|
</div>
|
|
|
|
<div className="h-5 w-px bg-white/10" />
|
|
|
|
{/* Stroke width */}
|
|
<div className="flex items-center gap-1.5">
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon-sm"
|
|
className="text-zinc-400 hover:text-white h-6 w-6"
|
|
onClick={() => setStrokeWidth(Math.max(1, strokeWidth - 1))}
|
|
>
|
|
<Minus className="h-3 w-3" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>Thinner</TooltipContent>
|
|
</Tooltip>
|
|
|
|
<div
|
|
className="rounded-full bg-current"
|
|
style={{
|
|
width: Math.min(16, strokeWidth * 3),
|
|
height: Math.min(16, strokeWidth * 3),
|
|
backgroundColor: selectedColor,
|
|
}}
|
|
/>
|
|
|
|
<Tooltip>
|
|
<TooltipTrigger asChild>
|
|
<Button
|
|
variant="ghost"
|
|
size="icon-sm"
|
|
className="text-zinc-400 hover:text-white h-6 w-6"
|
|
onClick={() => setStrokeWidth(Math.min(8, strokeWidth + 1))}
|
|
>
|
|
<Plus className="h-3 w-3" />
|
|
</Button>
|
|
</TooltipTrigger>
|
|
<TooltipContent>Thicker</TooltipContent>
|
|
</Tooltip>
|
|
|
|
<span className="text-xs text-zinc-500 font-mono w-4">{strokeWidth}</span>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|