feat: remove image preview panel and make manual labeling form full-width
This commit is contained in:
1 parent
5a097c457f
commit
ab21d1ca5d
1 file changed
+4
-110
@@ -38,12 +38,6 @@ export default function ManualLabelPage() {
|
||||
items: [{ kodeBarang: "", namaBarang: "", banyak: "", jumlah: "" }]
|
||||
});
|
||||
|
||||
// Transform states
|
||||
const [scale, setScale] = useState<number>(1.0);
|
||||
const [rotation, setRotation] = useState<number>(0);
|
||||
const [isDragging, setIsDragging] = useState<boolean>(false);
|
||||
const dragStart = useRef({ x: 0, y: 0, scrollLeft: 0, scrollTop: 0 });
|
||||
const viewportRef = useRef<HTMLDivElement>(null);
|
||||
|
||||
// Status indicators
|
||||
const [toast, setToast] = useState<{ message: string; show: boolean; isError: boolean }>({
|
||||
@@ -109,9 +103,6 @@ export default function ManualLabelPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// Reset view
|
||||
setScale(1.0);
|
||||
setRotation(0);
|
||||
fetchLabel();
|
||||
}, [currentIndex, files]);
|
||||
|
||||
@@ -217,39 +208,6 @@ export default function ManualLabelPage() {
|
||||
}
|
||||
};
|
||||
|
||||
// Panning functionality
|
||||
const handleMouseDown = (e: React.MouseEvent) => {
|
||||
if (e.target instanceof HTMLImageElement || e.target === viewportRef.current) {
|
||||
setIsDragging(true);
|
||||
const vp = viewportRef.current;
|
||||
if (vp) {
|
||||
dragStart.current = {
|
||||
x: e.pageX - vp.offsetLeft,
|
||||
y: e.pageY - vp.offsetTop,
|
||||
scrollLeft: vp.scrollLeft,
|
||||
scrollTop: vp.scrollTop
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseMove = (e: React.MouseEvent) => {
|
||||
if (!isDragging) return;
|
||||
e.preventDefault();
|
||||
const vp = viewportRef.current;
|
||||
if (vp) {
|
||||
const x = e.pageX - vp.offsetLeft;
|
||||
const y = e.pageY - vp.offsetTop;
|
||||
const walkX = (x - dragStart.current.x) * 1.5;
|
||||
const walkY = (y - dragStart.current.y) * 1.5;
|
||||
vp.scrollLeft = dragStart.current.scrollLeft - walkX;
|
||||
vp.scrollTop = dragStart.current.scrollTop - walkY;
|
||||
}
|
||||
};
|
||||
|
||||
const handleMouseUpOrLeave = () => {
|
||||
setIsDragging(false);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="h-screen w-screen flex flex-col bg-slate-950 text-slate-100 overflow-hidden font-sans">
|
||||
@@ -317,11 +275,11 @@ export default function ManualLabelPage() {
|
||||
</div>
|
||||
</header>
|
||||
|
||||
{/* Main Split Layout */}
|
||||
<div className="flex-1 flex overflow-hidden w-full">
|
||||
{/* Centered Form Layout */}
|
||||
<div className="flex-1 flex overflow-hidden w-full justify-center bg-slate-950">
|
||||
|
||||
{/* Left Form Viewport */}
|
||||
<div className="w-[45%] border-r border-slate-800 overflow-y-auto p-6 space-y-6 flex flex-col bg-slate-950">
|
||||
{/* Form Viewport */}
|
||||
<div className="w-full max-w-4xl border-x border-slate-800/60 overflow-y-auto p-8 space-y-6 flex flex-col bg-slate-900/10">
|
||||
|
||||
{/* Metadata Card */}
|
||||
<div className="rounded-xl border border-slate-800 bg-slate-900/40 p-5 space-y-5">
|
||||
@@ -518,70 +476,6 @@ export default function ManualLabelPage() {
|
||||
|
||||
</div>
|
||||
|
||||
{/* Right Image Panning Viewport */}
|
||||
<div className="w-[55%] bg-slate-950 flex flex-col relative select-none">
|
||||
<div
|
||||
ref={viewportRef}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseMove={handleMouseMove}
|
||||
onMouseUp={handleMouseUpOrLeave}
|
||||
onMouseLeave={handleMouseUpOrLeave}
|
||||
className="flex-1 overflow-auto flex items-center justify-center cursor-grab active:cursor-grabbing p-6"
|
||||
>
|
||||
{files[currentIndex] ? (
|
||||
<img
|
||||
src={`/test-images/${files[currentIndex]}`}
|
||||
alt={files[currentIndex]}
|
||||
style={{
|
||||
transform: `scale(${scale}) rotate(${rotation}deg)`,
|
||||
transformOrigin: "center center",
|
||||
transition: isDragging ? "none" : "transform 0.1s ease-out"
|
||||
}}
|
||||
draggable={false}
|
||||
className="max-w-[90%] max-h-[90%] object-contain rounded shadow-2xl shadow-black/80 border border-slate-900"
|
||||
/>
|
||||
) : (
|
||||
<div className="text-slate-500 text-sm font-medium">Select an image to load</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Interactive controls */}
|
||||
<div className="absolute bottom-6 right-6 flex items-center gap-2 px-3 py-1.5 bg-slate-900/90 backdrop-blur-md border border-slate-800 rounded-full shadow-lg shadow-black/40">
|
||||
<button
|
||||
onClick={() => setScale(s => Math.min(4.0, s + 0.15))}
|
||||
title="Zoom In"
|
||||
className="w-8 h-8 rounded-full flex items-center justify-center text-sm hover:bg-slate-800 active:scale-95 text-slate-100"
|
||||
>
|
||||
➕
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setScale(s => Math.max(0.2, s - 0.15))}
|
||||
title="Zoom Out"
|
||||
className="w-8 h-8 rounded-full flex items-center justify-center text-sm hover:bg-slate-800 active:scale-95 text-slate-100"
|
||||
>
|
||||
➖
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
setScale(1.0);
|
||||
setRotation(0);
|
||||
}}
|
||||
title="Reset View"
|
||||
className="w-8 h-8 rounded-full flex items-center justify-center text-sm hover:bg-slate-800 active:scale-95 text-slate-100"
|
||||
>
|
||||
🔄
|
||||
</button>
|
||||
<button
|
||||
onClick={() => setRotation(r => (r + 90) % 360)}
|
||||
title="Rotate Clockwise"
|
||||
className="w-8 h-8 rounded-full flex items-center justify-center text-sm hover:bg-slate-800 active:scale-95 text-slate-100"
|
||||
>
|
||||
↪️
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
{/* Alert toast notifications */}
|
||||
|
||||
Reference in new issue
Block a user