({ workspace, filePath, fileName, onClose }: EditorModalProps)
| 100 | } |
| 101 | |
| 102 | function EditorModal({ workspace, filePath, fileName, onClose }: EditorModalProps) { |
| 103 | const [content, setContent] = useState<string>(""); |
| 104 | const [loading, setLoading] = useState(true); |
| 105 | const [saving, setSaving] = useState(false); |
| 106 | const [saved, setSaved] = useState(false); |
| 107 | const [error, setError] = useState<string | null>(null); |
| 108 | const [viewMode, setViewMode] = useState<"edit" | "preview">("edit"); |
| 109 | |
| 110 | useEffect(() => { |
| 111 | setLoading(true); |
| 112 | fetch(`/api/browse?workspace=${encodeURIComponent(workspace)}&path=${encodeURIComponent(filePath)}&content=true`) |
| 113 | .then((r) => r.json()) |
| 114 | .then((data) => { |
| 115 | setContent(data.content || ""); |
| 116 | setLoading(false); |
| 117 | }) |
| 118 | .catch(() => { |
| 119 | setError("Failed to load file"); |
| 120 | setLoading(false); |
| 121 | }); |
| 122 | }, [workspace, filePath]); |
| 123 | |
| 124 | const handleSave = async () => { |
| 125 | setSaving(true); |
| 126 | setError(null); |
| 127 | try { |
| 128 | const res = await fetch("/api/files/write", { |
| 129 | method: "POST", |
| 130 | headers: { "Content-Type": "application/json" }, |
| 131 | body: JSON.stringify({ workspace, path: filePath, content }), |
| 132 | }); |
| 133 | if (!res.ok) throw new Error("Save failed"); |
| 134 | setSaved(true); |
| 135 | setTimeout(() => setSaved(false), 2000); |
| 136 | } catch { |
| 137 | setError("Failed to save file"); |
| 138 | } finally { |
| 139 | setSaving(false); |
| 140 | } |
| 141 | }; |
| 142 | |
| 143 | // Keyboard shortcut: Ctrl/Cmd+S to save |
| 144 | useEffect(() => { |
| 145 | const handler = (e: KeyboardEvent) => { |
| 146 | if ((e.ctrlKey || e.metaKey) && e.key === "s") { |
| 147 | e.preventDefault(); |
| 148 | handleSave(); |
| 149 | } |
| 150 | if (e.key === "Escape") onClose(); |
| 151 | }; |
| 152 | window.addEventListener("keydown", handler); |
| 153 | return () => window.removeEventListener("keydown", handler); |
| 154 | }, [content]); |
| 155 | |
| 156 | return ( |
| 157 | <div style={{ |
| 158 | position: "fixed", inset: 0, zIndex: 1000, |
| 159 | backgroundColor: "rgba(0,0,0,0.8)", |
nothing calls this directly
no test coverage detected