Files
vibn-frontend/components/project-main/MvpSetupLayoutClient.tsx
Mark Henderson 651ddf1e11 Rip out Theia, ship P5.1 attach E2E + Justine UI work-in-progress
Theia rip-out:
- Delete app/api/theia-auth/route.ts (Traefik ForwardAuth shim)
- Delete app/api/projects/[projectId]/workspace/route.ts and
  app/api/projects/prewarm/route.ts (Cloud Run Theia provisioning)
- Delete lib/cloud-run-workspace.ts and lib/coolify-workspace.ts
- Strip provisionTheiaWorkspace + theiaWorkspaceUrl/theiaAppUuid/
  theiaError from app/api/projects/create/route.ts response
- Remove Theia callbackUrl branch in app/auth/page.tsx
- Drop "Open in Theia" button + xterm/Theia PTY copy in build/page.tsx
- Drop theiaWorkspaceUrl from deployment/page.tsx Project type
- Strip Theia IDE line + theia-code-os from advisor + agent-chat
  context strings
- Scrub Theia mention from lib/auth/workspace-auth.ts comment

P5.1 (custom apex domains + DNS):
- lib/coolify.ts + lib/opensrs.ts: nameserver normalization, OpenSRS
  XML auth, Cloud DNS plumbing
- scripts/smoke-attach-e2e.ts: full prod GCP + sandbox OpenSRS +
  prod Coolify smoke covering register/zone/A/NS/PATCH/cleanup

In-progress (Justine onboarding/build, MVP setup, agent telemetry):
- New (justine)/stories, project (home) layouts, mvp-setup, run, tasks
  routes + supporting components
- Project shell + sidebar + nav refactor for the Stackless palette
- Agent session API hardening (sessions, events, stream, approve,
  retry, stop) + atlas-chat, advisor, design-surfaces refresh
- New scripts/sync-db-url-from-coolify.mjs +
  scripts/prisma-db-push.mjs + docker-compose.local-db.yml for
  local Prisma workflows
- lib/dev-bypass.ts, lib/chat-context-refs.ts, lib/prd-sections.ts
- Misc: stories CSS, debug/prisma route, modal-theme, BuildLivePlanPanel

Made-with: Cursor
2026-04-22 18:05:01 -07:00

175 lines
5.6 KiB
TypeScript

"use client";
import type { ReactNode } from "react";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { JM } from "@/components/project-creation/modal-theme";
const BUILD_LEFT_BG = "#faf8f5";
const BUILD_LEFT_BORDER = "#e8e4dc";
export function MvpSetupLayoutClient({
workspace,
projectId,
children,
}: {
workspace: string;
projectId: string;
children: ReactNode;
}) {
const pathname = usePathname() ?? "";
const base = `/${workspace}/project/${projectId}/mvp-setup`;
const steps = [
{ href: `${base}/describe`, label: "Describe", sub: "Your idea", suffix: "/describe" },
{ href: `${base}/architect`, label: "Architect", sub: "Discovery", suffix: "/architect" },
{ href: `${base}/design`, label: "Design", sub: "Look & feel", suffix: "/design" },
{ href: `${base}/website`, label: "Website", sub: "Grow", suffix: "/website" },
{ href: `${base}/launch`, label: "Build MVP", sub: "Review & launch", suffix: "/launch" },
] as const;
return (
<div
style={{
display: "flex",
height: "100%",
overflow: "hidden",
fontFamily: JM.fontSans,
background: "linear-gradient(180deg, #FAFAFA 0%, #F5F3FF 100%)",
}}
>
<div
style={{
width: 200,
flexShrink: 0,
borderRight: `1px solid ${BUILD_LEFT_BORDER}`,
background: "#fff",
display: "flex",
flexDirection: "column",
padding: "18px 12px",
overflow: "hidden",
}}
>
<div style={{ padding: "0 6px", marginBottom: 20 }}>
<div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 4 }}>
<div
style={{
width: 26,
height: 26,
background: JM.primaryGradient,
borderRadius: 6,
display: "flex",
alignItems: "center",
justifyContent: "center",
}}
>
<span style={{ fontSize: 13, fontWeight: 700, color: "#fff" }}>V</span>
</div>
<span style={{ fontSize: 16, fontWeight: 700, color: JM.ink, letterSpacing: "-0.02em" }}>MVP setup</span>
</div>
<div style={{ fontSize: 11, color: JM.muted, paddingLeft: 34 }}>New product flow</div>
</div>
<div
style={{
fontSize: 9.5,
fontWeight: 700,
letterSpacing: "0.08em",
textTransform: "uppercase",
color: JM.muted,
padding: "0 6px",
marginBottom: 8,
}}
>
Steps
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 2, flex: 1, minHeight: 0, overflowY: "auto" }}>
{steps.map(step => {
const active = pathname.includes(`${base}${step.suffix}`);
return (
<Link
key={step.suffix}
href={step.href}
scroll={false}
style={{
display: "flex",
alignItems: "center",
gap: 9,
padding: "9px 10px",
borderRadius: 8,
textDecoration: "none",
background: active ? "#fafaff" : "transparent",
border: active ? `1px solid rgba(99,102,241,0.2)` : "1px solid transparent",
transition: "background 0.15s",
}}
>
<div
style={{
width: 20,
height: 20,
borderRadius: "50%",
background: active ? JM.primaryGradient : "#e5e7eb",
color: active ? "#fff" : JM.muted,
display: "flex",
alignItems: "center",
justifyContent: "center",
flexShrink: 0,
fontSize: 9,
fontWeight: 700,
}}
>
{active ? "▲" : "○"}
</div>
<div>
<div style={{ fontSize: 12.5, fontWeight: active ? 600 : 500, color: JM.ink }}>{step.label}</div>
<div style={{ fontSize: 10, color: JM.muted }}>{step.sub}</div>
</div>
</Link>
);
})}
</div>
<div style={{ borderTop: `1px solid ${BUILD_LEFT_BORDER}`, marginTop: 14, paddingTop: 12, flexShrink: 0 }}>
<Link
href={`/${workspace}/projects`}
style={{
display: "flex",
alignItems: "center",
justifyContent: "center",
width: "100%",
background: "#eef2ff",
border: "1px solid #e0e7ff",
borderRadius: 8,
padding: "9px 10px",
fontSize: 12,
fontWeight: 600,
color: JM.indigo,
textDecoration: "none",
}}
>
Save & go to dashboard
</Link>
<Link
href={`/${workspace}/project/${projectId}/build`}
style={{
display: "block",
marginTop: 10,
textAlign: "center",
fontSize: 11,
fontWeight: 600,
color: JM.muted,
textDecoration: "none",
}}
>
Open Build workspace
</Link>
</div>
</div>
<div style={{ flex: 1, minWidth: 0, minHeight: 0, overflow: "hidden", display: "flex", flexDirection: "column" }}>
{children}
</div>
</div>
);
}