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
116 lines
3.5 KiB
TypeScript
116 lines
3.5 KiB
TypeScript
"use client";
|
|
|
|
import Link from "next/link";
|
|
import { useCallback, useEffect, useState } from "react";
|
|
|
|
/** Nav from justine/01_homepage.html — classes defined in app/styles/justine/01-homepage.css */
|
|
export function JustineNav() {
|
|
const [open, setOpen] = useState(false);
|
|
|
|
const close = useCallback(() => {
|
|
setOpen(false);
|
|
document.body.style.overflow = "";
|
|
}, []);
|
|
|
|
const toggle = useCallback(() => {
|
|
setOpen((o) => {
|
|
const next = !o;
|
|
document.body.style.overflow = next ? "hidden" : "";
|
|
return next;
|
|
});
|
|
}, []);
|
|
|
|
useEffect(() => () => {
|
|
document.body.style.overflow = "";
|
|
}, []);
|
|
|
|
return (
|
|
<>
|
|
<nav>
|
|
<Link href="/" style={{ display: "flex", alignItems: "center", gap: 10, textDecoration: "none" }}>
|
|
<div
|
|
className="logo-box"
|
|
style={{
|
|
width: 30,
|
|
height: 30,
|
|
background: "linear-gradient(135deg,#2E2A5E,#4338CA)",
|
|
borderRadius: 7,
|
|
display: "flex",
|
|
alignItems: "center",
|
|
justifyContent: "center",
|
|
}}
|
|
>
|
|
<span className="f" style={{ fontSize: 15, fontWeight: 700, color: "#FFFFFF" }}>
|
|
V
|
|
</span>
|
|
</div>
|
|
<span className="f" style={{ fontSize: 19, fontWeight: 700, color: "var(--ink)", letterSpacing: "-0.02em" }}>
|
|
vibn
|
|
</span>
|
|
</Link>
|
|
|
|
<div className="nav-links">
|
|
<Link href="/#how-it-works" style={{ fontSize: 14, color: "var(--muted)", textDecoration: "none" }}>
|
|
How it works
|
|
</Link>
|
|
<Link href="/pricing" style={{ fontSize: 14, color: "var(--muted)", textDecoration: "none" }}>
|
|
Pricing
|
|
</Link>
|
|
<Link href="/stories" style={{ fontSize: 14, color: "var(--muted)", textDecoration: "none" }}>
|
|
Stories
|
|
</Link>
|
|
<span style={{ fontSize: 14, color: "var(--muted)" }}>Blog</span>
|
|
</div>
|
|
|
|
<div className="nav-right-btns" style={{ display: "flex", alignItems: "center", gap: 12 }}>
|
|
<Link href="/auth" style={{ fontSize: 14, color: "#6366F1", fontWeight: 600, textDecoration: "none" }}>
|
|
Log in
|
|
</Link>
|
|
<Link href="/auth">
|
|
<button type="button" className="btn-ink">
|
|
Get started free
|
|
</button>
|
|
</Link>
|
|
</div>
|
|
|
|
<button
|
|
type="button"
|
|
className={`hamburger ${open ? "open" : ""}`}
|
|
aria-label={open ? "Close menu" : "Open menu"}
|
|
aria-expanded={open}
|
|
onClick={toggle}
|
|
>
|
|
<span />
|
|
<span />
|
|
<span />
|
|
</button>
|
|
</nav>
|
|
|
|
<div className={`mobile-menu ${open ? "open" : ""}`}>
|
|
<Link href="/#how-it-works" onClick={close}>
|
|
How it works
|
|
</Link>
|
|
<Link href="/pricing" onClick={close}>
|
|
Pricing
|
|
</Link>
|
|
<Link href="/stories" onClick={close}>
|
|
Stories
|
|
</Link>
|
|
<Link href="#" onClick={(e) => { e.preventDefault(); close(); }}>
|
|
Blog
|
|
</Link>
|
|
<Link href="/auth" style={{ color: "#6366F1", fontWeight: 600 }} onClick={close}>
|
|
Log in
|
|
</Link>
|
|
<div className="mobile-menu-cta">
|
|
<Link href="/auth" onClick={close} style={{ display: "block", width: "100%" }}>
|
|
<button type="button" className="btn-ink-lg" style={{ width: "100%" }}>
|
|
Get started free
|
|
</button>
|
|
</Link>
|
|
</div>
|
|
</div>
|
|
</>
|
|
);
|
|
}
|