import { useState, useEffect, useRef, useCallback } from "react"; import { open } from "@tauri-apps/plugin-dialog"; import { useProjects } from "../../hooks/useProjects"; interface Props { onClose: () => void; } export default function AddProjectDialog({ onClose }: Props) { const { add } = useProjects(); const [name, setName] = useState(""); const [path, setPath] = useState(""); const [error, setError] = useState(null); const [loading, setLoading] = useState(false); const nameInputRef = useRef(null); const overlayRef = useRef(null); // Auto-focus the first input when the dialog opens useEffect(() => { nameInputRef.current?.focus(); }, []); // Close on Escape key useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === "Escape") { onClose(); } }; document.addEventListener("keydown", handleKeyDown); return () => document.removeEventListener("keydown", handleKeyDown); }, [onClose]); // Close on click outside (click on overlay backdrop) const handleOverlayClick = useCallback( (e: React.MouseEvent) => { if (e.target === overlayRef.current) { onClose(); } }, [onClose], ); const handleBrowse = async () => { const selected = await open({ directory: true, multiple: false }); if (typeof selected === "string") { setPath(selected); if (!name) { const parts = selected.replace(/[/\\]$/, "").split(/[/\\]/); setName(parts[parts.length - 1]); } } }; const handleSubmit = async (e?: React.FormEvent) => { if (e) e.preventDefault(); if (!name.trim() || !path.trim()) { setError("Name and path are required"); return; } setLoading(true); setError(null); try { await add(name.trim(), path.trim()); onClose(); } catch (err) { setError(String(err)); } finally { setLoading(false); } }; return (

Add Project

setName(e.target.value)} placeholder="my-project" className="w-full px-3 py-2 mb-3 bg-[var(--bg-primary)] border border-[var(--border-color)] rounded text-sm text-[var(--text-primary)] focus:outline-none focus:border-[var(--accent)]" />
setPath(e.target.value)} placeholder="/path/to/project" className="flex-1 px-3 py-2 bg-[var(--bg-primary)] border border-[var(--border-color)] rounded text-sm text-[var(--text-primary)] focus:outline-none focus:border-[var(--accent)]" />
{error && (
{error}
)}
); }