Files
storkit/frontend/src/App.tsx

132 lines
3.9 KiB
TypeScript
Raw Normal View History

import * as React from "react";
import { api } from "./api/client";
import { Chat } from "./components/Chat";
import "./App.css";
function App() {
2026-02-16 18:57:39 +00:00
const [projectPath, setProjectPath] = React.useState<string | null>(null);
const [errorMsg, setErrorMsg] = React.useState<string | null>(null);
const [pathInput, setPathInput] = React.useState("");
const [isOpening, setIsOpening] = React.useState(false);
const [knownProjects, setKnownProjects] = React.useState<string[]>([]);
2026-02-16 18:57:39 +00:00
React.useEffect(() => {
api
.getKnownProjects()
.then((projects) => setKnownProjects(projects))
.catch((error) => console.error(error));
}, []);
2026-02-16 18:57:39 +00:00
async function openProject(path: string) {
if (!path.trim()) {
setErrorMsg("Please enter a project path.");
return;
}
2026-02-16 18:57:39 +00:00
try {
setErrorMsg(null);
setIsOpening(true);
const confirmedPath = await api.openProject(path.trim());
setProjectPath(confirmedPath);
} catch (e) {
console.error(e);
const message =
e instanceof Error
? e.message
: typeof e === "string"
? e
: "An error occurred opening the project.";
setErrorMsg(message);
} finally {
setIsOpening(false);
}
}
2026-02-16 18:57:39 +00:00
function handleOpen() {
void openProject(pathInput);
}
2026-02-16 18:57:39 +00:00
async function closeProject() {
try {
await api.closeProject();
setProjectPath(null);
} catch (e) {
console.error(e);
}
}
2026-02-16 18:57:39 +00:00
return (
<main
className="container"
style={{ height: "100vh", padding: 0, maxWidth: "100%" }}
>
{!projectPath ? (
<div
className="selection-screen"
style={{ padding: "2rem", maxWidth: "800px", margin: "0 auto" }}
>
<h1>AI Code Assistant</h1>
<p>Paste a project path to start the Story-Driven Spec Workflow.</p>
{knownProjects.length > 0 && (
<div style={{ marginTop: "12px" }}>
<div style={{ fontSize: "0.9em", color: "#666" }}>
Recent projects
</div>
<ul style={{ listStyle: "none", padding: 0, margin: "8px 0 0" }}>
{knownProjects.map((project) => (
<li key={project} style={{ marginBottom: "6px" }}>
<button
type="button"
onClick={() => void openProject(project)}
style={{
width: "100%",
textAlign: "left",
padding: "8px 10px",
borderRadius: "6px",
border: "1px solid #ddd",
background: "#f7f7f7",
cursor: "pointer",
fontFamily: "monospace",
fontSize: "0.9em",
}}
>
{project}
</button>
</li>
))}
</ul>
</div>
)}
<input
type="text"
value={pathInput}
placeholder="/path/to/project"
onChange={(event) => setPathInput(event.target.value)}
onKeyDown={(event) => {
if (event.key === "Enter") {
handleOpen();
}
}}
style={{ width: "100%", padding: "10px", marginTop: "12px" }}
/>
<button type="button" onClick={handleOpen} disabled={isOpening}>
{isOpening ? "Opening..." : "Open Project"}
</button>
</div>
) : (
<div className="workspace" style={{ height: "100%" }}>
<Chat projectPath={projectPath} onCloseProject={closeProject} />
</div>
)}
{errorMsg && (
<div className="error-message" style={{ marginTop: "20px" }}>
<p style={{ color: "red" }}>Error: {errorMsg}</p>
</div>
)}
</main>
);
}
export default App;