application [wireframe-renderer-web] view page [pages/index] development
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import { useState, useRef, useEffect } from "react";
|
||||
import { useSearchParams } from "react-router-dom";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
@@ -24,6 +25,7 @@ interface DrawingElement {
|
||||
}
|
||||
|
||||
export default function CanvasPage() {
|
||||
const [searchParams] = useSearchParams();
|
||||
const canvasRef = useRef<HTMLCanvasElement>(null);
|
||||
const [tool, setTool] = useState<Tool>("pen");
|
||||
const [isDrawing, setIsDrawing] = useState(false);
|
||||
@@ -198,6 +200,8 @@ export default function CanvasPage() {
|
||||
const user = await auth.currentUser();
|
||||
if (!user) return;
|
||||
|
||||
const projectIdFromUrl = searchParams.get("projectId");
|
||||
|
||||
// Load projects
|
||||
const { data: userProjects } = await entities
|
||||
.from("nvwa_project")
|
||||
@@ -206,8 +210,14 @@ export default function CanvasPage() {
|
||||
|
||||
if (userProjects && userProjects.length > 0) {
|
||||
setProjects(userProjects);
|
||||
// Use first project or create new one
|
||||
const project = userProjects[0];
|
||||
// Use specified project or first one
|
||||
let project;
|
||||
if (projectIdFromUrl) {
|
||||
project = userProjects.find(p => p.id === parseInt(projectIdFromUrl));
|
||||
}
|
||||
if (!project) {
|
||||
project = userProjects[0];
|
||||
}
|
||||
setCurrentProject(project);
|
||||
|
||||
// Load latest wireframe for this project
|
||||
@@ -230,7 +240,7 @@ export default function CanvasPage() {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Create default project
|
||||
// Create default project if no projects exist
|
||||
const { data: newProject } = await entities
|
||||
.from("nvwa_project")
|
||||
.insert({
|
||||
|
||||
@@ -1,11 +1,150 @@
|
||||
import { useState, useEffect } from "react";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
|
||||
import { Button } from "@/components/ui/button";
|
||||
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogTrigger } from "@/components/ui/dialog";
|
||||
import { Input } from "@/components/ui/input";
|
||||
import { Textarea } from "@/components/ui/textarea";
|
||||
import { Label } from "@/components/ui/label";
|
||||
import { Plus, Folder } from "lucide-react";
|
||||
import { entities, auth } from "@/lib/nvwa";
|
||||
|
||||
export default function HomePage() {
|
||||
const [projects, setProjects] = useState([]);
|
||||
const [isCreateDialogOpen, setIsCreateDialogOpen] = useState(false);
|
||||
const [newProjectName, setNewProjectName] = useState("");
|
||||
const [newProjectDescription, setNewProjectDescription] = useState("");
|
||||
const navigate = useNavigate();
|
||||
|
||||
useEffect(() => {
|
||||
loadProjects();
|
||||
}, []);
|
||||
|
||||
const loadProjects = async () => {
|
||||
try {
|
||||
const user = await auth.currentUser();
|
||||
if (!user) return;
|
||||
|
||||
const { data } = await entities
|
||||
.from("nvwa_project")
|
||||
.select("*")
|
||||
.eq("user_id", user.id)
|
||||
.order("updated_at", { ascending: false });
|
||||
|
||||
setProjects(data || []);
|
||||
} catch (error) {
|
||||
console.error("Failed to load projects:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const createProject = async () => {
|
||||
try {
|
||||
const user = await auth.currentUser();
|
||||
if (!user || !newProjectName.trim()) return;
|
||||
|
||||
const { data } = await entities
|
||||
.from("nvwa_project")
|
||||
.insert({
|
||||
name: newProjectName,
|
||||
description: newProjectDescription,
|
||||
user_id: user.id
|
||||
})
|
||||
.select();
|
||||
|
||||
if (data && data.length > 0) {
|
||||
setProjects(prev => [data[0], ...prev]);
|
||||
setNewProjectName("");
|
||||
setNewProjectDescription("");
|
||||
setIsCreateDialogOpen(false);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Failed to create project:", error);
|
||||
}
|
||||
};
|
||||
|
||||
const openProject = (projectId) => {
|
||||
navigate(`/canvas?projectId=${projectId}`);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex min-h-screen items-center justify-center bg-background p-4">
|
||||
<div className="text-center">
|
||||
<h1 className="text-2xl font-bold mb-4">欢迎</h1>
|
||||
<p className="text-muted-foreground">这是首页</p>
|
||||
<div className="container mx-auto p-4">
|
||||
<div className="flex justify-between items-center mb-6">
|
||||
<h1 className="text-3xl font-bold">项目列表</h1>
|
||||
<Dialog open={isCreateDialogOpen} onOpenChange={setIsCreateDialogOpen}>
|
||||
<DialogTrigger asChild>
|
||||
<Button>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
创建新项目
|
||||
</Button>
|
||||
</DialogTrigger>
|
||||
<DialogContent>
|
||||
<DialogHeader>
|
||||
<DialogTitle>创建新项目</DialogTitle>
|
||||
</DialogHeader>
|
||||
<div className="space-y-4">
|
||||
<div>
|
||||
<Label htmlFor="name">项目名称</Label>
|
||||
<Input
|
||||
id="name"
|
||||
value={newProjectName}
|
||||
onChange={(e) => setNewProjectName(e.target.value)}
|
||||
placeholder="输入项目名称"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<Label htmlFor="desc">描述</Label>
|
||||
<Textarea
|
||||
id="desc"
|
||||
value={newProjectDescription}
|
||||
onChange={(e) => setNewProjectDescription(e.target.value)}
|
||||
placeholder="输入项目描述(可选)"
|
||||
rows={3}
|
||||
/>
|
||||
</div>
|
||||
<Button onClick={createProject} disabled={!newProjectName.trim()}>
|
||||
创建
|
||||
</Button>
|
||||
</div>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
</div>
|
||||
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
|
||||
{projects.map((project) => (
|
||||
<Card
|
||||
key={project.id}
|
||||
className="cursor-pointer hover:shadow-md transition-shadow"
|
||||
onClick={() => openProject(project.id)}
|
||||
>
|
||||
<CardHeader>
|
||||
<CardTitle className="flex items-center">
|
||||
<Folder className="w-5 h-5 mr-2" />
|
||||
{project.name}
|
||||
</CardTitle>
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<p className="text-sm text-muted-foreground mb-2">
|
||||
{project.description || "无描述"}
|
||||
</p>
|
||||
<p className="text-xs text-muted-foreground">
|
||||
创建于 {new Date(project.created_at).toLocaleDateString()}
|
||||
</p>
|
||||
</CardContent>
|
||||
</Card>
|
||||
))}
|
||||
</div>
|
||||
|
||||
{projects.length === 0 && (
|
||||
<div className="text-center py-12">
|
||||
<Folder className="w-12 h-12 mx-auto mb-4 text-muted-foreground" />
|
||||
<h3 className="text-lg font-medium mb-2">还没有项目</h3>
|
||||
<p className="text-muted-foreground mb-4">创建一个新项目开始你的设计之旅</p>
|
||||
<Button onClick={() => setIsCreateDialogOpen(true)}>
|
||||
<Plus className="w-4 h-4 mr-2" />
|
||||
创建第一个项目
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user