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: "" }]
|
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
|
// Status indicators
|
||||||
const [toast, setToast] = useState<{ message: string; show: boolean; isError: boolean }>({
|
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();
|
fetchLabel();
|
||||||
}, [currentIndex, files]);
|
}, [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 (
|
return (
|
||||||
<div className="h-screen w-screen flex flex-col bg-slate-950 text-slate-100 overflow-hidden font-sans">
|
<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>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
{/* Main Split Layout */}
|
{/* Centered Form Layout */}
|
||||||
<div className="flex-1 flex overflow-hidden w-full">
|
<div className="flex-1 flex overflow-hidden w-full justify-center bg-slate-950">
|
||||||
|
|
||||||
{/* Left Form Viewport */}
|
{/* 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">
|
<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 */}
|
{/* Metadata Card */}
|
||||||
<div className="rounded-xl border border-slate-800 bg-slate-900/40 p-5 space-y-5">
|
<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>
|
</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>
|
</div>
|
||||||
|
|
||||||
{/* Alert toast notifications */}
|
{/* Alert toast notifications */}
|
||||||
|
|||||||
Reference in new issue
Block a user