feat: wire web app infrastructure

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
tao.chen
2026-07-02 17:23:48 +08:00
co-authored by Claude
parent 27503781fa
commit 593d2aee5e
9 changed files with 230 additions and 6 deletions
+28
View File
@@ -0,0 +1,28 @@
import { findFileByPath, mockWorkspaceFiles } from "@/pages/workspace/mock-data";
import { useWorkspaceUiStore } from "@/lib/store/workspace-ui-store";
export function WorkspacePage() {
const activeFilePath = useWorkspaceUiStore((s) => s.activeFilePath);
const activeFile = findFileByPath(mockWorkspaceFiles, activeFilePath);
return (
<div className="flex h-full flex-col bg-background text-foreground">
<header className="border-b border-border px-4 py-2">
<h1 className="text-sm font-semibold">Codespace Workspace</h1>
</header>
<div className="flex-1 overflow-auto p-4">
<p className="text-sm text-muted-foreground">
Active file: <code className="text-foreground">{activeFilePath}</code>
</p>
<p className="mt-2 text-sm text-muted-foreground">
Mock file match:{" "}
<code className="text-foreground">
{activeFile
? `${activeFile.name} (${activeFile.language ?? activeFile.kind})`
: "not found"}
</code>
</p>
</div>
</div>
);
}
+80
View File
@@ -0,0 +1,80 @@
export type MockFileNode = {
name: string;
path: string;
kind: "file" | "dir";
language?: string;
content?: string;
children?: MockFileNode[];
};
const file = (
name: string,
path: string,
language: string,
content: string,
): MockFileNode => ({ name, path, kind: "file", language, content });
const dir = (
name: string,
path: string,
children: MockFileNode[],
): MockFileNode => ({ name, path, kind: "dir", children });
export const mockWorkspaceFiles: MockFileNode[] = [
file("package.json", "package.json", "json", `{
"name": "codespace",
"version": "0.0.0"
}
`),
file("README.md", "README.md", "markdown", `# Codespace
A self-hosted development environment.
`),
dir("src", "src", [
file(
"main.tsx",
"src/main.tsx",
"typescript",
`import { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import { App } from "@/app/App";
import "@/styles/index.css";
createRoot(document.getElementById("root")!).render(
<StrictMode>
<App />
</StrictMode>,
);
`,
),
]),
dir("internal", "internal", [
dir("api", "internal/api", [
file(
"router.go",
"internal/api/router.go",
"go",
`package api
// Router is reserved for future backend routes.
type Router struct{}
`,
),
]),
]),
];
/** Depth-first search for a node with the given slash-delimited path. */
export function findFileByPath(
files: MockFileNode[],
path: string,
): MockFileNode | undefined {
for (const node of files) {
if (node.path === path) return node;
if (node.children) {
const found = findFileByPath(node.children, path);
if (found) return found;
}
}
return undefined;
}