- Add VisionMenu component with Camera (QRCode) and Barcode (Keyence) submenus - Remove old CameraPanel component and replace with dropdown menu structure - Add ProcessedDataPanel to display processed data in bottom dock (5 rows visible) - Create SystemStatusPanel component with horizontal button layout (START/STOP/RESET) - Create EventLogPanel component for better code organization - Add device initialization feature with 7-axis progress tracking - Add GetProcessedData and GetInitializeStatus backend methods - Update Header menu layout to vertical (icon on top, text below) for more space - Update HomePage layout with bottom-docked ProcessedDataPanel - Refactor HomePage to use new modular components 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
157 lines
7.5 KiB
TypeScript
157 lines
7.5 KiB
TypeScript
import React, { useState, useRef, useEffect } from 'react';
|
|
import { Camera, ChevronRight, X } from 'lucide-react';
|
|
|
|
interface VisionMenuProps {
|
|
isOpen: boolean;
|
|
onClose: () => void;
|
|
}
|
|
|
|
export const VisionMenu: React.FC<VisionMenuProps> = ({ isOpen, onClose }) => {
|
|
const [activeSubmenu, setActiveSubmenu] = useState<string | null>(null);
|
|
const menuRef = useRef<HTMLDivElement>(null);
|
|
|
|
useEffect(() => {
|
|
const handleClickOutside = (event: MouseEvent) => {
|
|
if (menuRef.current && !menuRef.current.contains(event.target as Node)) {
|
|
onClose();
|
|
}
|
|
};
|
|
|
|
if (isOpen) {
|
|
document.addEventListener('mousedown', handleClickOutside);
|
|
}
|
|
|
|
return () => {
|
|
document.removeEventListener('mousedown', handleClickOutside);
|
|
};
|
|
}, [isOpen, onClose]);
|
|
|
|
if (!isOpen) return null;
|
|
|
|
const handleQRCodeCamera = () => {
|
|
console.log('[VisionMenu] Camera (QRCode) clicked');
|
|
// TODO: Implement QR Code camera functionality
|
|
};
|
|
|
|
const handleKeyenceBarcode = () => {
|
|
console.log('[VisionMenu] Barcode (Keyence) clicked');
|
|
// TODO: Implement Keyence barcode functionality
|
|
};
|
|
|
|
return (
|
|
<div
|
|
ref={menuRef}
|
|
className="absolute top-20 left-1/2 -translate-x-1/2 z-50 bg-black/95 backdrop-blur-md border border-neon-blue/50 rounded-lg shadow-glow-blue min-w-[300px]"
|
|
>
|
|
{/* Header */}
|
|
<div className="flex items-center justify-between p-4 border-b border-white/10">
|
|
<div className="flex items-center gap-3">
|
|
<Camera className="w-5 h-5 text-neon-blue" />
|
|
<h3 className="font-tech font-bold text-lg text-white">VISION</h3>
|
|
</div>
|
|
<button
|
|
onClick={onClose}
|
|
className="text-slate-400 hover:text-white transition-colors"
|
|
>
|
|
<X className="w-5 h-5" />
|
|
</button>
|
|
</div>
|
|
|
|
{/* Menu Items */}
|
|
<div className="p-2">
|
|
{/* Camera (QRCode) */}
|
|
<div className="relative">
|
|
<button
|
|
onMouseEnter={() => setActiveSubmenu('qrcode')}
|
|
onClick={handleQRCodeCamera}
|
|
className="w-full flex items-center justify-between px-4 py-3 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors font-tech"
|
|
>
|
|
<span>Camera (QRCode)</span>
|
|
<ChevronRight className="w-4 h-4" />
|
|
</button>
|
|
|
|
{/* QRCode Submenu */}
|
|
{activeSubmenu === 'qrcode' && (
|
|
<div
|
|
className="absolute left-full top-0 ml-1 bg-black/95 backdrop-blur-md border border-neon-blue/50 rounded-lg shadow-glow-blue min-w-[200px] p-2"
|
|
onMouseLeave={() => setActiveSubmenu(null)}
|
|
>
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] QRCode - Connect')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Connect
|
|
</button>
|
|
<div className="h-px bg-white/10 my-1" />
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] QRCode - Get Image')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Get Image
|
|
</button>
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] QRCode - Live View')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Live View
|
|
</button>
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] QRCode - Read Test')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Read Test
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
|
|
{/* Barcode (Keyence) */}
|
|
<div className="relative">
|
|
<button
|
|
onMouseEnter={() => setActiveSubmenu('keyence')}
|
|
onClick={handleKeyenceBarcode}
|
|
className="w-full flex items-center justify-between px-4 py-3 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors font-tech"
|
|
>
|
|
<span>Barcode (Keyence)</span>
|
|
<ChevronRight className="w-4 h-4" />
|
|
</button>
|
|
|
|
{/* Keyence Submenu */}
|
|
{activeSubmenu === 'keyence' && (
|
|
<div
|
|
className="absolute left-full top-0 ml-1 bg-black/95 backdrop-blur-md border border-neon-blue/50 rounded-lg shadow-glow-blue min-w-[200px] p-2"
|
|
onMouseLeave={() => setActiveSubmenu(null)}
|
|
>
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] Keyence - Get Image')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Get Image
|
|
</button>
|
|
<div className="h-px bg-white/10 my-1" />
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] Keyence - Trigger On')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Trigger On
|
|
</button>
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] Keyence - Trigger Off')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Trigger Off
|
|
</button>
|
|
<button
|
|
onClick={() => console.log('[VisionMenu] Keyence - Save Image')}
|
|
className="w-full px-4 py-2 text-left text-slate-300 hover:bg-neon-blue/10 hover:text-neon-blue rounded transition-colors text-sm"
|
|
>
|
|
Save Image
|
|
</button>
|
|
</div>
|
|
)}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
};
|