Adopt Stackless UI: warm palette, sidebar, project tab bar with Design tab
- Add Google Fonts (Newsreader/Outfit/IBM Plex Mono) + warm beige CSS palette - New VIBNSidebar: Stackless-style 220px sidebar with project list + user footer - New ProjectShell: project header with name/status/progress% + tab bar - Tabs: Atlas → PRD → Design → Build → Deploy → Settings - New /prd page: section-by-section progress view - New /build page: locked until PRD complete - Projects list page: Stackless-style row layout - Simplify overview page to just render AtlasChat Made-with: Cursor
This commit is contained in:
176
app/[workspace]/project/[projectId]/build/page.tsx
Normal file
176
app/[workspace]/project/[projectId]/build/page.tsx
Normal file
@@ -0,0 +1,176 @@
|
||||
"use client";
|
||||
|
||||
import { useEffect, useState } from "react";
|
||||
import { useParams } from "next/navigation";
|
||||
import Link from "next/link";
|
||||
|
||||
interface Project {
|
||||
id: string;
|
||||
status?: string;
|
||||
prd?: string;
|
||||
giteaRepoUrl?: string;
|
||||
}
|
||||
|
||||
const BUILD_FEATURES = [
|
||||
"Authentication system",
|
||||
"Database schema",
|
||||
"API endpoints",
|
||||
"Core UI",
|
||||
"Business logic",
|
||||
"Tests",
|
||||
];
|
||||
|
||||
export default function BuildPage() {
|
||||
const params = useParams();
|
||||
const projectId = params.projectId as string;
|
||||
const workspace = params.workspace as string;
|
||||
const [project, setProject] = useState<Project | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
|
||||
useEffect(() => {
|
||||
fetch(`/api/projects/${projectId}`)
|
||||
.then((r) => r.json())
|
||||
.then((d) => {
|
||||
setProject(d.project);
|
||||
setLoading(false);
|
||||
})
|
||||
.catch(() => setLoading(false));
|
||||
}, [projectId]);
|
||||
|
||||
if (loading) {
|
||||
return (
|
||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "Outfit, sans-serif", color: "#a09a90" }}>
|
||||
Loading…
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const hasRepo = Boolean(project?.giteaRepoUrl);
|
||||
const hasPRD = Boolean(project?.prd);
|
||||
|
||||
if (!hasPRD) {
|
||||
return (
|
||||
<div
|
||||
className="vibn-enter"
|
||||
style={{
|
||||
flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
|
||||
padding: 40, fontFamily: "Outfit, sans-serif",
|
||||
}}
|
||||
>
|
||||
<div style={{ textAlign: "center", maxWidth: 360 }}>
|
||||
<div style={{
|
||||
width: 56, height: 56, borderRadius: 14,
|
||||
background: "#fff", border: "1px solid #e8e4dc",
|
||||
display: "flex", alignItems: "center", justifyContent: "center",
|
||||
fontSize: "1.4rem", margin: "0 auto 18px",
|
||||
boxShadow: "0 2px 8px #1a1a1a08",
|
||||
}}>
|
||||
🔒
|
||||
</div>
|
||||
<h3 style={{
|
||||
fontFamily: "Newsreader, serif", fontSize: "1.3rem",
|
||||
fontWeight: 400, color: "#1a1a1a", marginBottom: 8,
|
||||
}}>
|
||||
Complete your PRD first
|
||||
</h3>
|
||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", lineHeight: 1.6, marginBottom: 20 }}>
|
||||
Finish your discovery with Atlas, then the builder unlocks automatically.
|
||||
</p>
|
||||
<Link
|
||||
href={`/${workspace}/project/${projectId}/overview`}
|
||||
style={{
|
||||
display: "inline-block",
|
||||
padding: "9px 20px", borderRadius: 7,
|
||||
background: "#1a1a1a", color: "#fff",
|
||||
fontSize: "0.78rem", fontWeight: 600,
|
||||
fontFamily: "Outfit, sans-serif",
|
||||
textDecoration: "none",
|
||||
}}
|
||||
>
|
||||
Continue with Atlas →
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!hasRepo) {
|
||||
return (
|
||||
<div
|
||||
className="vibn-enter"
|
||||
style={{
|
||||
flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
|
||||
padding: 40, fontFamily: "Outfit, sans-serif",
|
||||
}}
|
||||
>
|
||||
<div style={{ textAlign: "center", maxWidth: 360 }}>
|
||||
<div style={{
|
||||
width: 56, height: 56, borderRadius: 14,
|
||||
background: "#fff", border: "1px solid #e8e4dc",
|
||||
display: "flex", alignItems: "center", justifyContent: "center",
|
||||
fontSize: "1.4rem", margin: "0 auto 18px",
|
||||
boxShadow: "0 2px 8px #1a1a1a08",
|
||||
}}>
|
||||
⚡
|
||||
</div>
|
||||
<h3 style={{
|
||||
fontFamily: "Newsreader, serif", fontSize: "1.3rem",
|
||||
fontWeight: 400, color: "#1a1a1a", marginBottom: 8,
|
||||
}}>
|
||||
PRD ready — build coming soon
|
||||
</h3>
|
||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", lineHeight: 1.6 }}>
|
||||
The Architect agent will generate your project structure and kick off the build pipeline.
|
||||
This feature is in active development.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className="vibn-enter"
|
||||
style={{
|
||||
flex: 1, display: "flex", alignItems: "center", justifyContent: "center",
|
||||
padding: 40, fontFamily: "Outfit, sans-serif",
|
||||
}}
|
||||
>
|
||||
<div style={{ width: "100%", maxWidth: 500 }}>
|
||||
<h3 style={{
|
||||
fontFamily: "Newsreader, serif", fontSize: "1.2rem",
|
||||
fontWeight: 400, color: "#1a1a1a", marginBottom: 18,
|
||||
}}>
|
||||
Build progress
|
||||
</h3>
|
||||
{BUILD_FEATURES.map((f, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className="vibn-enter"
|
||||
style={{
|
||||
display: "flex", alignItems: "center", gap: 12,
|
||||
padding: "12px 16px", marginBottom: 4, borderRadius: 8,
|
||||
background: "#fff", border: "1px solid #e8e4dc",
|
||||
animationDelay: `${i * 0.05}s`,
|
||||
}}
|
||||
>
|
||||
<span style={{
|
||||
width: 7, height: 7, borderRadius: "50%",
|
||||
background: "#d4a04a", display: "inline-block", flexShrink: 0,
|
||||
}} />
|
||||
<span style={{ flex: 1, fontSize: "0.84rem", color: "#1a1a1a" }}>{f}</span>
|
||||
<div style={{ width: 80, height: 3, borderRadius: 2, background: "#eae6de" }}>
|
||||
<div style={{ height: "100%", width: "0%", borderRadius: 2, background: "#3d5afe" }} />
|
||||
</div>
|
||||
<span style={{
|
||||
fontFamily: "IBM Plex Mono, monospace",
|
||||
fontSize: "0.7rem", color: "#a09a90", minWidth: 28, textAlign: "right",
|
||||
}}>
|
||||
0%
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user