feat(ui): apply Justine ink & parchment design system
- Map Justine tokens to shadcn CSS variables (--vibn-* aliases) - Switch fonts to Inter + Lora via next/font (IBM Plex Mono for code) - Base typography: body Inter, h1–h3 Lora; marketing hero + wordmark serif - Project shell and global chrome use semantic colors - Replace Outfit/Newsreader references across TSX inline styles Made-with: Cursor
This commit is contained in:
@@ -38,7 +38,7 @@ export default function MarketingLayout({
|
|||||||
alt="Vib'n"
|
alt="Vib'n"
|
||||||
className="h-8 w-8"
|
className="h-8 w-8"
|
||||||
/>
|
/>
|
||||||
<span className="text-xl font-bold">Vib'n</span>
|
<span className="font-serif text-xl font-bold tracking-tight">Vib'n</span>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex flex-1 items-center justify-between space-x-2 md:justify-end">
|
<div className="flex flex-1 items-center justify-between space-x-2 md:justify-end">
|
||||||
|
|||||||
@@ -58,10 +58,10 @@ export default function ActivityPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="vibn-enter"
|
className="vibn-enter"
|
||||||
style={{ padding: "44px 52px", maxWidth: 720, fontFamily: "Outfit, sans-serif" }}
|
style={{ padding: "44px 52px", maxWidth: 720, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}
|
||||||
>
|
>
|
||||||
<h1 style={{
|
<h1 style={{
|
||||||
fontFamily: "Newsreader, serif", fontSize: "1.9rem",
|
fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.9rem",
|
||||||
fontWeight: 400, color: "#1a1a1a", letterSpacing: "-0.03em", marginBottom: 4,
|
fontWeight: 400, color: "#1a1a1a", letterSpacing: "-0.03em", marginBottom: 4,
|
||||||
}}>
|
}}>
|
||||||
Activity
|
Activity
|
||||||
@@ -81,7 +81,7 @@ export default function ActivityPage() {
|
|||||||
background: filter === f.id ? "#1a1a1a" : "#fff",
|
background: filter === f.id ? "#1a1a1a" : "#fff",
|
||||||
color: filter === f.id ? "#fff" : "#6b6560",
|
color: filter === f.id ? "#fff" : "#6b6560",
|
||||||
fontSize: "0.75rem", fontWeight: 600, transition: "all 0.12s",
|
fontSize: "0.75rem", fontWeight: 600, transition: "all 0.12s",
|
||||||
cursor: "pointer", fontFamily: "Outfit, sans-serif",
|
cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{f.label}
|
{f.label}
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type SectionId = typeof SECTIONS[number]["id"];
|
|||||||
const NAV_GROUP: React.CSSProperties = {
|
const NAV_GROUP: React.CSSProperties = {
|
||||||
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
||||||
letterSpacing: "0.09em", textTransform: "uppercase",
|
letterSpacing: "0.09em", textTransform: "uppercase",
|
||||||
padding: "14px 12px 6px", fontFamily: "Outfit, sans-serif",
|
padding: "14px 12px 6px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
};
|
};
|
||||||
|
|
||||||
function AnalyticsInner() {
|
function AnalyticsInner() {
|
||||||
@@ -60,7 +60,7 @@ function AnalyticsInner() {
|
|||||||
router.push(`/${workspace}/project/${projectId}/analytics?section=${id}`, { scroll: false });
|
router.push(`/${workspace}/project/${projectId}/analytics?section=${id}`, { scroll: false });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", height: "100%", fontFamily: "Outfit, sans-serif", overflow: "hidden" }}>
|
<div style={{ display: "flex", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", overflow: "hidden" }}>
|
||||||
|
|
||||||
{/* Left nav */}
|
{/* Left nav */}
|
||||||
<div style={{ width: 200, flexShrink: 0, borderRight: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", flexDirection: "column", overflow: "auto" }}>
|
<div style={{ width: 200, flexShrink: 0, borderRight: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", flexDirection: "column", overflow: "auto" }}>
|
||||||
@@ -126,7 +126,7 @@ function AnalyticsInner() {
|
|||||||
|
|
||||||
export default function AnalyticsPage() {
|
export default function AnalyticsPage() {
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "Outfit, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
||||||
<AnalyticsInner />
|
<AnalyticsInner />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type SectionId = typeof SECTIONS[number]["id"];
|
|||||||
const NAV_GROUP: React.CSSProperties = {
|
const NAV_GROUP: React.CSSProperties = {
|
||||||
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
||||||
letterSpacing: "0.09em", textTransform: "uppercase",
|
letterSpacing: "0.09em", textTransform: "uppercase",
|
||||||
padding: "14px 12px 6px", fontFamily: "Outfit, sans-serif",
|
padding: "14px 12px 6px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
};
|
};
|
||||||
|
|
||||||
function AssistInner() {
|
function AssistInner() {
|
||||||
@@ -60,7 +60,7 @@ function AssistInner() {
|
|||||||
router.push(`/${workspace}/project/${projectId}/assist?section=${id}`, { scroll: false });
|
router.push(`/${workspace}/project/${projectId}/assist?section=${id}`, { scroll: false });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", height: "100%", fontFamily: "Outfit, sans-serif", overflow: "hidden" }}>
|
<div style={{ display: "flex", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", overflow: "hidden" }}>
|
||||||
|
|
||||||
{/* Left nav */}
|
{/* Left nav */}
|
||||||
<div style={{ width: 200, flexShrink: 0, borderRight: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", flexDirection: "column", overflow: "auto" }}>
|
<div style={{ width: 200, flexShrink: 0, borderRight: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", flexDirection: "column", overflow: "auto" }}>
|
||||||
@@ -126,7 +126,7 @@ function AssistInner() {
|
|||||||
|
|
||||||
export default function AssistPage() {
|
export default function AssistPage() {
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "Outfit, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
||||||
<AssistInner />
|
<AssistInner />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ function TreeRow({ node, depth, selectedPath, onSelect, onToggle }: {
|
|||||||
const NAV_GROUP_LABEL: React.CSSProperties = {
|
const NAV_GROUP_LABEL: React.CSSProperties = {
|
||||||
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
||||||
letterSpacing: "0.09em", textTransform: "uppercase",
|
letterSpacing: "0.09em", textTransform: "uppercase",
|
||||||
padding: "12px 12px 5px", fontFamily: "Outfit, sans-serif",
|
padding: "12px 12px 5px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
};
|
};
|
||||||
|
|
||||||
function NavItem({ label, active, onClick, indent = false }: { label: string; active: boolean; onClick: () => void; indent?: boolean }) {
|
function NavItem({ label, active, onClick, indent = false }: { label: string; active: boolean; onClick: () => void; indent?: boolean }) {
|
||||||
@@ -115,7 +115,7 @@ function NavItem({ label, active, onClick, indent = false }: { label: string; ac
|
|||||||
background: active ? "#f0ece4" : "transparent", border: "none", cursor: "pointer",
|
background: active ? "#f0ece4" : "transparent", border: "none", cursor: "pointer",
|
||||||
padding: `5px 12px 5px ${indent ? 22 : 12}px`, borderRadius: 5,
|
padding: `5px 12px 5px ${indent ? 22 : 12}px`, borderRadius: 5,
|
||||||
fontSize: "0.78rem", fontWeight: active ? 600 : 440,
|
fontSize: "0.78rem", fontWeight: active ? 600 : 440,
|
||||||
color: active ? "#1a1a1a" : "#5a5550", fontFamily: "Outfit, sans-serif",
|
color: active ? "#1a1a1a" : "#5a5550", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => { if (!active) (e.currentTarget as HTMLElement).style.background = "#f6f4f0"; }}
|
onMouseEnter={e => { if (!active) (e.currentTarget as HTMLElement).style.background = "#f6f4f0"; }}
|
||||||
onMouseLeave={e => { if (!active) (e.currentTarget as HTMLElement).style.background = "transparent"; }}
|
onMouseLeave={e => { if (!active) (e.currentTarget as HTMLElement).style.background = "transparent"; }}
|
||||||
@@ -156,8 +156,8 @@ function InfraContent({ tab, projectId, workspace }: { tab: string; projectId: s
|
|||||||
return (
|
return (
|
||||||
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column" }}>
|
||||||
<div style={{ padding: "20px 28px 0", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
<div style={{ padding: "20px 28px 0", display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
||||||
<div style={{ fontSize: "0.68rem", fontWeight: 700, color: "#a09a90", letterSpacing: "0.08em", textTransform: "uppercase", fontFamily: "Outfit, sans-serif" }}>{tab}</div>
|
<div style={{ fontSize: "0.68rem", fontWeight: 700, color: "#a09a90", letterSpacing: "0.08em", textTransform: "uppercase", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>{tab}</div>
|
||||||
<Link href={`${base}?tab=${tab}`} style={{ fontSize: "0.72rem", color: "#a09a90", textDecoration: "none", fontFamily: "Outfit, sans-serif" }}>Open full view →</Link>
|
<Link href={`${base}?tab=${tab}`} style={{ fontSize: "0.72rem", color: "#a09a90", textDecoration: "none", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Open full view →</Link>
|
||||||
</div>
|
</div>
|
||||||
{d && <Placeholder icon={d.icon} title={d.title} desc={d.desc} />}
|
{d && <Placeholder icon={d.icon} title={d.title} desc={d.desc} />}
|
||||||
</div>
|
</div>
|
||||||
@@ -179,8 +179,8 @@ function LayoutsContent({ surfaces, projectId, workspace, activeSurfaceId, onSel
|
|||||||
return (
|
return (
|
||||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", padding: "24px 28px", gap: 20 }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column", padding: "24px 28px", gap: 20 }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between" }}>
|
||||||
<div style={{ fontSize: "0.68rem", fontWeight: 700, color: "#a09a90", letterSpacing: "0.08em", textTransform: "uppercase", fontFamily: "Outfit, sans-serif" }}>Layouts</div>
|
<div style={{ fontSize: "0.68rem", fontWeight: 700, color: "#a09a90", letterSpacing: "0.08em", textTransform: "uppercase", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Layouts</div>
|
||||||
<Link href={`/${workspace}/project/${projectId}/design?surface=${active?.id ?? ""}`} style={{ fontSize: "0.72rem", color: "#a09a90", textDecoration: "none", fontFamily: "Outfit, sans-serif" }}>Edit in Design →</Link>
|
<Link href={`/${workspace}/project/${projectId}/design?surface=${active?.id ?? ""}`} style={{ fontSize: "0.72rem", color: "#a09a90", textDecoration: "none", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Edit in Design →</Link>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
|
<div style={{ display: "flex", gap: 14, flexWrap: "wrap" }}>
|
||||||
{surfaces.map(s => (
|
{surfaces.map(s => (
|
||||||
@@ -191,18 +191,18 @@ function LayoutsContent({ surfaces, projectId, workspace, activeSurfaceId, onSel
|
|||||||
minWidth: 180, flex: "1 1 180px", maxWidth: 240,
|
minWidth: 180, flex: "1 1 180px", maxWidth: 240,
|
||||||
transition: "border-color 0.1s",
|
transition: "border-color 0.1s",
|
||||||
}}>
|
}}>
|
||||||
<div style={{ fontSize: "0.85rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "Outfit, sans-serif", marginBottom: 4 }}>
|
<div style={{ fontSize: "0.85rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", marginBottom: 4 }}>
|
||||||
{SURFACE_LABELS[s.id] ?? s.id}
|
{SURFACE_LABELS[s.id] ?? s.id}
|
||||||
</div>
|
</div>
|
||||||
{s.lockedTheme ? (
|
{s.lockedTheme ? (
|
||||||
<div style={{ fontSize: "0.72rem", color: "#6b6560", fontFamily: "Outfit, sans-serif" }}>Theme: {s.lockedTheme}</div>
|
<div style={{ fontSize: "0.72rem", color: "#6b6560", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Theme: {s.lockedTheme}</div>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif", fontStyle: "italic" }}>Not configured</div>
|
<div style={{ fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontStyle: "italic" }}>Not configured</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.75rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.75rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Click a surface to select it, then open the Design editor to configure themes, fonts, and components.
|
Click a surface to select it, then open the Design editor to configure themes, fonts, and components.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -507,8 +507,8 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
if (!appName) {
|
if (!appName) {
|
||||||
return (
|
return (
|
||||||
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 10, padding: 40, textAlign: "center" }}>
|
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 10, padding: 40, textAlign: "center" }}>
|
||||||
<div style={{ fontSize: "0.88rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "Outfit, sans-serif" }}>Select an app first</div>
|
<div style={{ fontSize: "0.88rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Select an app first</div>
|
||||||
<div style={{ fontSize: "0.78rem", color: "#a09a90", fontFamily: "Outfit, sans-serif" }}>Choose an app from the left nav to run agent tasks against it.</div>
|
<div style={{ fontSize: "0.78rem", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Choose an app from the left nav to run agent tasks against it.</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -517,11 +517,11 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden" }}>
|
||||||
{/* Horizontal sessions strip */}
|
{/* Horizontal sessions strip */}
|
||||||
<div style={{ flexShrink: 0, height: 38, borderBottom: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", alignItems: "center", gap: 8, padding: "0 16px", overflowX: "auto" }}>
|
<div style={{ flexShrink: 0, height: 38, borderBottom: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", alignItems: "center", gap: 8, padding: "0 16px", overflowX: "auto" }}>
|
||||||
<span style={{ fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6", letterSpacing: "0.09em", textTransform: "uppercase", whiteSpace: "nowrap", fontFamily: "Outfit, sans-serif" }}>Sessions</span>
|
<span style={{ fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6", letterSpacing: "0.09em", textTransform: "uppercase", whiteSpace: "nowrap", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Sessions</span>
|
||||||
<span style={{ width: 1, height: 14, background: "#e0dcd5", flexShrink: 0 }} />
|
<span style={{ width: 1, height: 14, background: "#e0dcd5", flexShrink: 0 }} />
|
||||||
{loadingSessions && <span style={{ fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>Loading…</span>}
|
{loadingSessions && <span style={{ fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Loading…</span>}
|
||||||
{!loadingSessions && sessions.length === 0 && (
|
{!loadingSessions && sessions.length === 0 && (
|
||||||
<span style={{ fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>No sessions yet — run your first task below</span>
|
<span style={{ fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>No sessions yet — run your first task below</span>
|
||||||
)}
|
)}
|
||||||
{sessions.map(s => (
|
{sessions.map(s => (
|
||||||
<button key={s.id} onClick={() => { setActiveSessionId(s.id); setActiveSession(s); }} style={{
|
<button key={s.id} onClick={() => { setActiveSessionId(s.id); setActiveSession(s); }} style={{
|
||||||
@@ -530,7 +530,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
color: activeSessionId === s.id ? "#fff" : "#5a5550",
|
color: activeSessionId === s.id ? "#fff" : "#5a5550",
|
||||||
fontSize: "0.68rem", cursor: "pointer", whiteSpace: "nowrap",
|
fontSize: "0.68rem", cursor: "pointer", whiteSpace: "nowrap",
|
||||||
display: "flex", alignItems: "center", gap: 5,
|
display: "flex", alignItems: "center", gap: 5,
|
||||||
fontFamily: "Outfit, sans-serif", flexShrink: 0,
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flexShrink: 0,
|
||||||
}}>
|
}}>
|
||||||
<span style={{ width: 5, height: 5, borderRadius: "50%", background: activeSessionId === s.id ? "#fff" : (STATUS_COLORS[s.status] ?? "#a09a90"), display: "inline-block", flexShrink: 0 }} />
|
<span style={{ width: 5, height: 5, borderRadius: "50%", background: activeSessionId === s.id ? "#fff" : (STATUS_COLORS[s.status] ?? "#a09a90"), display: "inline-block", flexShrink: 0 }} />
|
||||||
{s.task.length > 30 ? s.task.slice(0, 30) + "…" : s.task}
|
{s.task.length > 30 ? s.task.slice(0, 30) + "…" : s.task}
|
||||||
@@ -540,7 +540,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
<button onClick={() => { setActiveSession(null); setActiveSessionId(null); setTask(""); }} style={{
|
<button onClick={() => { setActiveSession(null); setActiveSessionId(null); setTask(""); }} style={{
|
||||||
marginLeft: "auto", padding: "3px 10px", border: "1px solid #e0dcd5", borderRadius: 20,
|
marginLeft: "auto", padding: "3px 10px", border: "1px solid #e0dcd5", borderRadius: 20,
|
||||||
background: "transparent", color: "#a09a90", fontSize: "0.68rem", cursor: "pointer",
|
background: "transparent", color: "#a09a90", fontSize: "0.68rem", cursor: "pointer",
|
||||||
fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap", flexShrink: 0,
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap", flexShrink: 0,
|
||||||
}}>+ New</button>
|
}}>+ New</button>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
@@ -553,14 +553,14 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
{/* Session header */}
|
{/* Session header */}
|
||||||
<div style={{ padding: "12px 20px", borderBottom: "1px solid #e8e4dc", background: "#fff", display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }}>
|
<div style={{ padding: "12px 20px", borderBottom: "1px solid #e8e4dc", background: "#fff", display: "flex", alignItems: "center", gap: 12, flexShrink: 0 }}>
|
||||||
<span style={{ width: 8, height: 8, borderRadius: "50%", background: STATUS_COLORS[activeSession.status], flexShrink: 0, display: "inline-block" }} />
|
<span style={{ width: 8, height: 8, borderRadius: "50%", background: STATUS_COLORS[activeSession.status], flexShrink: 0, display: "inline-block" }} />
|
||||||
<span style={{ fontSize: "0.8rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "Outfit, sans-serif", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{activeSession.task}</span>
|
<span style={{ fontSize: "0.8rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flex: 1, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{activeSession.task}</span>
|
||||||
{activeSession.started_at && (
|
{activeSession.started_at && (
|
||||||
<span style={{ fontSize: "0.7rem", color: "#a09a90", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
<span style={{ fontSize: "0.7rem", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
{["running", "pending"].includes(activeSession.status) ? `${elapsed(activeSession.started_at)} elapsed` : elapsed(activeSession.started_at)}
|
{["running", "pending"].includes(activeSession.status) ? `${elapsed(activeSession.started_at)} elapsed` : elapsed(activeSession.started_at)}
|
||||||
</span>
|
</span>
|
||||||
)}
|
)}
|
||||||
{["running", "pending"].includes(activeSession.status) && (
|
{["running", "pending"].includes(activeSession.status) && (
|
||||||
<button onClick={handleStop} style={{ padding: "4px 12px", background: "#fee2e2", color: "#c62828", border: "1px solid #fca5a5", borderRadius: 5, fontSize: "0.72rem", cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
<button onClick={handleStop} style={{ padding: "4px 12px", background: "#fee2e2", color: "#c62828", border: "1px solid #fca5a5", borderRadius: 5, fontSize: "0.72rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
Stop
|
Stop
|
||||||
</button>
|
</button>
|
||||||
)}
|
)}
|
||||||
@@ -596,7 +596,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 20px", flexShrink: 0 }}>
|
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 20px", flexShrink: 0 }}>
|
||||||
{showFollowUp ? (
|
{showFollowUp ? (
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||||
<div style={{ fontSize: "0.72rem", color: "#6b6560", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.72rem", color: "#6b6560", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Add a follow-up instruction (optional) then retry:
|
Add a follow-up instruction (optional) then retry:
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "flex-end" }}>
|
<div style={{ display: "flex", gap: 8, alignItems: "flex-end" }}>
|
||||||
@@ -607,34 +607,34 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
onKeyDown={e => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) handleRetry(followUp); if (e.key === "Escape") setShowFollowUp(false); }}
|
onKeyDown={e => { if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) handleRetry(followUp); if (e.key === "Escape") setShowFollowUp(false); }}
|
||||||
placeholder="e.g. Also update the TypeScript types, or just leave blank to retry as-is…"
|
placeholder="e.g. Also update the TypeScript types, or just leave blank to retry as-is…"
|
||||||
rows={2}
|
rows={2}
|
||||||
style={{ flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 7, padding: "8px 11px", fontSize: "0.78rem", fontFamily: "Outfit, sans-serif", outline: "none", background: "#faf8f5" }}
|
style={{ flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 7, padding: "8px 11px", fontSize: "0.78rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", outline: "none", background: "#faf8f5" }}
|
||||||
/>
|
/>
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
||||||
<button onClick={() => handleRetry(followUp)} disabled={retrying}
|
<button onClick={() => handleRetry(followUp)} disabled={retrying}
|
||||||
style={{ padding: "8px 14px", background: "#1a1a1a", color: "#fff", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "8px 14px", background: "#1a1a1a", color: "#fff", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
{retrying ? "Retrying…" : "Retry"}
|
{retrying ? "Retrying…" : "Retry"}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => setShowFollowUp(false)}
|
<button onClick={() => setShowFollowUp(false)}
|
||||||
style={{ padding: "6px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.73rem", cursor: "pointer", fontFamily: "Outfit, sans-serif" }}>
|
style={{ padding: "6px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.73rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.63rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.63rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
⌘↵ to retry · Esc to cancel · Same session, fresh run
|
⌘↵ to retry · Esc to cancel · Same session, fresh run
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
||||||
<div style={{ fontSize: "0.75rem", color: activeSession.status === "failed" ? "#c62828" : "#a09a90", fontFamily: "Outfit, sans-serif", flex: 1 }}>
|
<div style={{ fontSize: "0.75rem", color: activeSession.status === "failed" ? "#c62828" : "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flex: 1 }}>
|
||||||
{activeSession.status === "failed" ? "Session failed — retry without losing context" : "Session stopped"}
|
{activeSession.status === "failed" ? "Session failed — retry without losing context" : "Session stopped"}
|
||||||
</div>
|
</div>
|
||||||
<button onClick={() => handleRetry()} disabled={retrying}
|
<button onClick={() => handleRetry()} disabled={retrying}
|
||||||
style={{ padding: "7px 14px", background: "#fef9f0", color: "#92400e", border: "1px solid #fde68a", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "7px 14px", background: "#fef9f0", color: "#92400e", border: "1px solid #fde68a", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
{retrying ? "Retrying…" : "↺ Retry"}
|
{retrying ? "Retrying…" : "↺ Retry"}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => setShowFollowUp(true)}
|
<button onClick={() => setShowFollowUp(true)}
|
||||||
style={{ padding: "7px 14px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "7px 14px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
Follow up…
|
Follow up…
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -645,7 +645,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
{/* Changed files */}
|
{/* Changed files */}
|
||||||
{activeSession.changed_files.length > 0 && (
|
{activeSession.changed_files.length > 0 && (
|
||||||
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 20px", flexShrink: 0 }}>
|
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 20px", flexShrink: 0 }}>
|
||||||
<div style={{ fontSize: "0.65rem", fontWeight: 700, color: "#a09a90", letterSpacing: "0.08em", textTransform: "uppercase", fontFamily: "Outfit, sans-serif", marginBottom: 8 }}>Changed Files</div>
|
<div style={{ fontSize: "0.65rem", fontWeight: 700, color: "#a09a90", letterSpacing: "0.08em", textTransform: "uppercase", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", marginBottom: 8 }}>Changed Files</div>
|
||||||
<div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
|
<div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
|
||||||
{activeSession.changed_files.map((f, i) => (
|
{activeSession.changed_files.map((f, i) => (
|
||||||
<div key={i} style={{ display: "flex", alignItems: "center", gap: 5, background: "#faf8f5", border: "1px solid #e8e4dc", borderRadius: 5, padding: "3px 8px" }}>
|
<div key={i} style={{ display: "flex", alignItems: "center", gap: 5, background: "#faf8f5", border: "1px solid #e8e4dc", borderRadius: 5, padding: "3px 8px" }}>
|
||||||
@@ -655,7 +655,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{activeSession.status === "approved" && (
|
{activeSession.status === "approved" && (
|
||||||
<div style={{ marginTop: 8, fontSize: "0.73rem", color: "#1b5e20", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ marginTop: 8, fontSize: "0.73rem", color: "#1b5e20", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
✓ Auto-committed — these changes are live.
|
✓ Auto-committed — these changes are live.
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -664,7 +664,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
{approveResult && (
|
{approveResult && (
|
||||||
<div style={{
|
<div style={{
|
||||||
marginBottom: 10, padding: "8px 12px", borderRadius: 6, fontSize: "0.74rem",
|
marginBottom: 10, padding: "8px 12px", borderRadius: 6, fontSize: "0.74rem",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
background: approveResult.startsWith("✓") ? "#f0fdf4" : "#fef2f2",
|
background: approveResult.startsWith("✓") ? "#f0fdf4" : "#fef2f2",
|
||||||
color: approveResult.startsWith("✓") ? "#166534" : "#991b1b",
|
color: approveResult.startsWith("✓") ? "#166534" : "#991b1b",
|
||||||
border: `1px solid ${approveResult.startsWith("✓") ? "#bbf7d0" : "#fecaca"}`,
|
border: `1px solid ${approveResult.startsWith("✓") ? "#bbf7d0" : "#fecaca"}`,
|
||||||
@@ -682,7 +682,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
placeholder="Commit message…"
|
placeholder="Commit message…"
|
||||||
style={{
|
style={{
|
||||||
width: "100%", padding: "8px 11px", border: "1px solid #e8e4dc",
|
width: "100%", padding: "8px 11px", border: "1px solid #e8e4dc",
|
||||||
borderRadius: 6, fontSize: "0.78rem", fontFamily: "Outfit, sans-serif",
|
borderRadius: 6, fontSize: "0.78rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
outline: "none", background: "#faf8f5", boxSizing: "border-box",
|
outline: "none", background: "#faf8f5", boxSizing: "border-box",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -694,16 +694,16 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
padding: "7px 16px", background: approveMsg.trim() ? "#1a1a1a" : "#e8e4dc",
|
padding: "7px 16px", background: approveMsg.trim() ? "#1a1a1a" : "#e8e4dc",
|
||||||
color: approveMsg.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 7,
|
color: approveMsg.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 7,
|
||||||
fontSize: "0.75rem", fontWeight: 600, cursor: approveMsg.trim() ? "pointer" : "default",
|
fontSize: "0.75rem", fontWeight: 600, cursor: approveMsg.trim() ? "pointer" : "default",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{approving ? "Committing…" : "Commit & push"}
|
{approving ? "Committing…" : "Commit & push"}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => setShowApproveInput(false)} style={{ padding: "7px 12px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "Outfit, sans-serif" }}>
|
<button onClick={() => setShowApproveInput(false)} style={{ padding: "7px 12px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.65rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.65rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Enter to commit · Esc to cancel · Coolify will auto-deploy after push
|
Enter to commit · Esc to cancel · Coolify will auto-deploy after push
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -711,14 +711,14 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
<div style={{ display: "flex", gap: 8 }}>
|
<div style={{ display: "flex", gap: 8 }}>
|
||||||
<button
|
<button
|
||||||
onClick={() => { setShowApproveInput(true); setApproveMsg(`agent: ${activeSession.task.slice(0, 60)}`); }}
|
onClick={() => { setShowApproveInput(true); setApproveMsg(`agent: ${activeSession.task.slice(0, 60)}`); }}
|
||||||
style={{ padding: "7px 16px", background: "#1a1a1a", color: "#fff", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "Outfit, sans-serif" }}
|
style={{ padding: "7px 16px", background: "#1a1a1a", color: "#fff", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}
|
||||||
>
|
>
|
||||||
Approve & commit
|
Approve & commit
|
||||||
</button>
|
</button>
|
||||||
<a
|
<a
|
||||||
href="https://theia.vibnai.com"
|
href="https://theia.vibnai.com"
|
||||||
target="_blank" rel="noreferrer"
|
target="_blank" rel="noreferrer"
|
||||||
style={{ padding: "7px 16px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "Outfit, sans-serif", textDecoration: "none", display: "inline-flex", alignItems: "center" }}
|
style={{ padding: "7px 16px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", textDecoration: "none", display: "inline-flex", alignItems: "center" }}
|
||||||
>
|
>
|
||||||
Open in Theia →
|
Open in Theia →
|
||||||
</a>
|
</a>
|
||||||
@@ -730,7 +730,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "#b5b0a6", fontSize: "0.8rem", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "#b5b0a6", fontSize: "0.8rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Select a session or run a new task
|
Select a session or run a new task
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -745,7 +745,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 16px", flexShrink: 0 }}>
|
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 16px", flexShrink: 0 }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
<div style={{ display: "flex", alignItems: "center", gap: 10 }}>
|
||||||
<span style={{ width: 7, height: 7, borderRadius: "50%", background: "#3d5afe", flexShrink: 0, display: "inline-block" }} />
|
<span style={{ width: 7, height: 7, borderRadius: "50%", background: "#3d5afe", flexShrink: 0, display: "inline-block" }} />
|
||||||
<span style={{ fontSize: "0.78rem", color: "#6b6560", fontFamily: "Outfit, sans-serif", flex: 1 }}>
|
<span style={{ fontSize: "0.78rem", color: "#6b6560", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flex: 1 }}>
|
||||||
Agent is working — wait for it to finish, or stop it above.
|
Agent is working — wait for it to finish, or stop it above.
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
@@ -758,15 +758,15 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
return (
|
return (
|
||||||
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 16px", flexShrink: 0 }}>
|
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 16px", flexShrink: 0 }}>
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.75rem", color: "#1b5e20", fontFamily: "Outfit, sans-serif", flex: 1 }}>
|
<span style={{ fontSize: "0.75rem", color: "#1b5e20", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flex: 1 }}>
|
||||||
✓ Shipped — changes committed and deployment triggered automatically.
|
✓ Shipped — changes committed and deployment triggered automatically.
|
||||||
</span>
|
</span>
|
||||||
<button onClick={() => setShowFollowUp(true)}
|
<button onClick={() => setShowFollowUp(true)}
|
||||||
style={{ padding: "7px 14px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "7px 14px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
+ Follow up
|
+ Follow up
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => { setActiveSession(null); setActiveSessionId(null); setTask(""); }}
|
<button onClick={() => { setActiveSession(null); setActiveSessionId(null); setTask(""); }}
|
||||||
style={{ padding: "7px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "7px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
New task
|
New task
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -782,10 +782,10 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
}}
|
}}
|
||||||
placeholder="What should the agent build next?"
|
placeholder="What should the agent build next?"
|
||||||
rows={2}
|
rows={2}
|
||||||
style={{ flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 7, padding: "8px 11px", fontSize: "0.78rem", fontFamily: "Outfit, sans-serif", outline: "none", background: "#faf8f5" }}
|
style={{ flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 7, padding: "8px 11px", fontSize: "0.78rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", outline: "none", background: "#faf8f5" }}
|
||||||
/>
|
/>
|
||||||
<button onClick={() => { handleRun(); setShowFollowUp(false); }} disabled={submitting || !task.trim()}
|
<button onClick={() => { handleRun(); setShowFollowUp(false); }} disabled={submitting || !task.trim()}
|
||||||
style={{ padding: "9px 14px", background: task.trim() ? "#1a1a1a" : "#e8e4dc", color: task.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: task.trim() ? "pointer" : "default", fontFamily: "Outfit, sans-serif" }}>
|
style={{ padding: "9px 14px", background: task.trim() ? "#1a1a1a" : "#e8e4dc", color: task.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: task.trim() ? "pointer" : "default", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
{submitting ? "Starting…" : "Run"}
|
{submitting ? "Starting…" : "Run"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -800,7 +800,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 16px", flexShrink: 0 }}>
|
<div style={{ borderTop: "1px solid #e8e4dc", background: "#fff", padding: "12px 16px", flexShrink: 0 }}>
|
||||||
{showFollowUp ? (
|
{showFollowUp ? (
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||||
<div style={{ fontSize: "0.72rem", color: "#6b6560", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.72rem", color: "#6b6560", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Describe the next thing to build (continues from this session's context):
|
Describe the next thing to build (continues from this session's context):
|
||||||
</div>
|
</div>
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "flex-end" }}>
|
<div style={{ display: "flex", gap: 8, alignItems: "flex-end" }}>
|
||||||
@@ -816,36 +816,36 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
rows={2}
|
rows={2}
|
||||||
style={{
|
style={{
|
||||||
flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 7,
|
flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 7,
|
||||||
padding: "8px 11px", fontSize: "0.78rem", fontFamily: "Outfit, sans-serif",
|
padding: "8px 11px", fontSize: "0.78rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
outline: "none", background: "#faf8f5",
|
outline: "none", background: "#faf8f5",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
||||||
<button onClick={() => { handleRun(); setShowFollowUp(false); }} disabled={submitting || !task.trim()}
|
<button onClick={() => { handleRun(); setShowFollowUp(false); }} disabled={submitting || !task.trim()}
|
||||||
style={{ padding: "8px 14px", background: task.trim() ? "#1a1a1a" : "#e8e4dc", color: task.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: task.trim() ? "pointer" : "default", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "8px 14px", background: task.trim() ? "#1a1a1a" : "#e8e4dc", color: task.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: task.trim() ? "pointer" : "default", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
{submitting ? "Starting…" : "Run"}
|
{submitting ? "Starting…" : "Run"}
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => { setShowFollowUp(false); setTask(""); }}
|
<button onClick={() => { setShowFollowUp(false); setTask(""); }}
|
||||||
style={{ padding: "6px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.73rem", cursor: "pointer", fontFamily: "Outfit, sans-serif" }}>
|
style={{ padding: "6px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.73rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Cancel
|
Cancel
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.63rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.63rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
⌘↵ to run · Esc to cancel · Starts a new session for this task
|
⌘↵ to run · Esc to cancel · Starts a new session for this task
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
) : (
|
) : (
|
||||||
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
<div style={{ display: "flex", gap: 8, alignItems: "center" }}>
|
||||||
<span style={{ fontSize: "0.75rem", color: "#2e7d32", fontFamily: "Outfit, sans-serif", flex: 1 }}>
|
<span style={{ fontSize: "0.75rem", color: "#2e7d32", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flex: 1 }}>
|
||||||
✓ Done — approve the changes above, or continue building.
|
✓ Done — approve the changes above, or continue building.
|
||||||
</span>
|
</span>
|
||||||
<button onClick={() => setShowFollowUp(true)}
|
<button onClick={() => setShowFollowUp(true)}
|
||||||
style={{ padding: "7px 14px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "7px 14px", background: "#f0ece4", color: "#1a1a1a", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", fontWeight: 600, cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
+ Follow up
|
+ Follow up
|
||||||
</button>
|
</button>
|
||||||
<button onClick={() => { setActiveSession(null); setActiveSessionId(null); setTask(""); }}
|
<button onClick={() => { setActiveSession(null); setActiveSessionId(null); setTask(""); }}
|
||||||
style={{ padding: "7px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
style={{ padding: "7px 14px", background: "transparent", color: "#a09a90", border: "1px solid #e8e4dc", borderRadius: 7, fontSize: "0.75rem", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
New task
|
New task
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
@@ -867,7 +867,7 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
rows={2}
|
rows={2}
|
||||||
style={{
|
style={{
|
||||||
flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 8,
|
flex: 1, resize: "none", border: "1px solid #e8e4dc", borderRadius: 8,
|
||||||
padding: "9px 12px", fontSize: "0.8rem", fontFamily: "Outfit, sans-serif",
|
padding: "9px 12px", fontSize: "0.8rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
color: "#1a1a1a", outline: "none", background: "#faf8f5",
|
color: "#1a1a1a", outline: "none", background: "#faf8f5",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -878,13 +878,13 @@ function AgentMode({ projectId, appName, appPath }: { projectId: string; appName
|
|||||||
padding: "10px 18px", background: task.trim() ? "#1a1a1a" : "#e8e4dc",
|
padding: "10px 18px", background: task.trim() ? "#1a1a1a" : "#e8e4dc",
|
||||||
color: task.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 8,
|
color: task.trim() ? "#fff" : "#a09a90", border: "none", borderRadius: 8,
|
||||||
fontSize: "0.78rem", fontWeight: 600, cursor: task.trim() ? "pointer" : "default",
|
fontSize: "0.78rem", fontWeight: 600, cursor: task.trim() ? "pointer" : "default",
|
||||||
fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{submitting ? "Starting…" : "Run"}
|
{submitting ? "Starting…" : "Run"}
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.65rem", color: "#b5b0a6", marginTop: 5, fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.65rem", color: "#b5b0a6", marginTop: 5, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
⌘↵ to start · The agent works autonomously until done · You approve before anything is committed
|
⌘↵ to start · The agent works autonomously until done · You approve before anything is committed
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -916,15 +916,15 @@ function TerminalPanel({ appName }: { appName: string }) {
|
|||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: "0.58rem", color: "#555", transform: open ? "rotate(180deg)" : "none", transition: "transform 0.2s", display: "inline-block" }}>▲</span>
|
<span style={{ fontSize: "0.58rem", color: "#555", transform: open ? "rotate(180deg)" : "none", transition: "transform 0.2s", display: "inline-block" }}>▲</span>
|
||||||
<span style={{ fontSize: "0.68rem", fontWeight: 600, color: "#6b6560", letterSpacing: "0.07em", textTransform: "uppercase", fontFamily: "Outfit, sans-serif" }}>Terminal</span>
|
<span style={{ fontSize: "0.68rem", fontWeight: 600, color: "#6b6560", letterSpacing: "0.07em", textTransform: "uppercase", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Terminal</span>
|
||||||
{appName && <span style={{ fontSize: "0.65rem", color: "#3a3a3a", fontFamily: "IBM Plex Mono, monospace" }}>{appName}</span>}
|
{appName && <span style={{ fontSize: "0.65rem", color: "#3a3a3a", fontFamily: "IBM Plex Mono, monospace" }}>{appName}</span>}
|
||||||
<span style={{ marginLeft: "auto", fontSize: "0.6rem", color: "#3a3a3a", fontFamily: "Outfit, sans-serif" }}>Phase 4</span>
|
<span style={{ marginLeft: "auto", fontSize: "0.6rem", color: "#3a3a3a", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Phase 4</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
{/* Body */}
|
{/* Body */}
|
||||||
{open && (
|
{open && (
|
||||||
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 10, padding: "16px 24px", textAlign: "center" }}>
|
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", flexDirection: "column", gap: 10, padding: "16px 24px", textAlign: "center" }}>
|
||||||
<div style={{ fontSize: "0.78rem", color: "#6b6560", lineHeight: 1.6, fontFamily: "Outfit, sans-serif", maxWidth: 340 }}>
|
<div style={{ fontSize: "0.78rem", color: "#6b6560", lineHeight: 1.6, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", maxWidth: 340 }}>
|
||||||
{appName
|
{appName
|
||||||
? `Live shell into the ${appName} container via xterm.js + Theia PTY — coming in Phase 4.`
|
? `Live shell into the ${appName} container via xterm.js + Theia PTY — coming in Phase 4.`
|
||||||
: "Select an app from the left, then open a live shell into its container."}
|
: "Select an app from the left, then open a live shell into its container."}
|
||||||
@@ -979,8 +979,8 @@ function FileTree({ projectId, rootPath, selectedPath, onSelectFile }: {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ flex: 1, overflow: "auto", padding: "4px" }}>
|
<div style={{ flex: 1, overflow: "auto", padding: "4px" }}>
|
||||||
{treeLoading && <div style={{ padding: "12px", fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>Loading…</div>}
|
{treeLoading && <div style={{ padding: "12px", fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Loading…</div>}
|
||||||
{!treeLoading && tree.length === 0 && <div style={{ padding: "12px", fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>Empty.</div>}
|
{!treeLoading && tree.length === 0 && <div style={{ padding: "12px", fontSize: "0.72rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Empty.</div>}
|
||||||
{tree.map(n => <TreeRow key={n.path} node={n} depth={0} selectedPath={selectedPath} onSelect={onSelectFile} onToggle={handleToggle} />)}
|
{tree.map(n => <TreeRow key={n.path} node={n} depth={0} selectedPath={selectedPath} onSelect={onSelectFile} onToggle={handleToggle} />)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -1081,7 +1081,7 @@ function PrdContent({ projectId }: { projectId: string }) {
|
|||||||
}, [projectId]);
|
}, [projectId]);
|
||||||
|
|
||||||
if (loading) return (
|
if (loading) return (
|
||||||
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "#a09a90", fontSize: "0.82rem", fontFamily: "Outfit, sans-serif" }}>Loading…</div>
|
<div style={{ flex: 1, display: "flex", alignItems: "center", justifyContent: "center", color: "#a09a90", fontSize: "0.82rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Loading…</div>
|
||||||
);
|
);
|
||||||
|
|
||||||
const phaseMap = new Map(savedPhases.map(p => [p.phase, p]));
|
const phaseMap = new Map(savedPhases.map(p => [p.phase, p]));
|
||||||
@@ -1095,11 +1095,11 @@ function PrdContent({ projectId }: { projectId: string }) {
|
|||||||
const totalPct = Math.round((doneCount / sections.length) * 100);
|
const totalPct = Math.round((doneCount / sections.length) * 100);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ flex: 1, overflow: "auto", padding: "24px 28px", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ flex: 1, overflow: "auto", padding: "24px 28px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
{prd ? (
|
{prd ? (
|
||||||
<div style={{ maxWidth: 720 }}>
|
<div style={{ maxWidth: 720 }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 20 }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 20 }}>
|
||||||
<h3 style={{ fontFamily: "Newsreader, serif", fontSize: "1.15rem", fontWeight: 400, color: "#1a1a1a", margin: 0 }}>Product Requirements</h3>
|
<h3 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.15rem", fontWeight: 400, color: "#1a1a1a", margin: 0 }}>Product Requirements</h3>
|
||||||
<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: "0.68rem", color: "#2e7d32", background: "#2e7d3210", padding: "3px 9px", borderRadius: 5 }}>PRD complete</span>
|
<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: "0.68rem", color: "#2e7d32", background: "#2e7d3210", padding: "3px 9px", borderRadius: 5 }}>PRD complete</span>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ background: "#fff", borderRadius: 10, border: "1px solid #e8e4dc", padding: "24px 28px", lineHeight: 1.8, fontSize: "0.86rem", color: "#2a2824", whiteSpace: "pre-wrap" }}>
|
<div style={{ background: "#fff", borderRadius: 10, border: "1px solid #e8e4dc", padding: "24px 28px", lineHeight: 1.8, fontSize: "0.86rem", color: "#2a2824", whiteSpace: "pre-wrap" }}>
|
||||||
@@ -1190,8 +1190,8 @@ function PreviewContent({ projectId, apps, activePreviewApp, onSelectApp }: {
|
|||||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 16, padding: 60, textAlign: "center", background: "#faf8f5" }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "center", gap: 16, padding: 60, textAlign: "center", background: "#faf8f5" }}>
|
||||||
<div style={{ width: 52, height: 52, borderRadius: 13, background: "#f0ece4", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "1.5rem" }}>🖥</div>
|
<div style={{ width: 52, height: 52, borderRadius: 13, background: "#f0ece4", display: "flex", alignItems: "center", justifyContent: "center", fontSize: "1.5rem" }}>🖥</div>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ fontSize: "0.92rem", fontWeight: 600, color: "#1a1a1a", marginBottom: 6, fontFamily: "Outfit, sans-serif" }}>No deployment URL yet</div>
|
<div style={{ fontSize: "0.92rem", fontWeight: 600, color: "#1a1a1a", marginBottom: 6, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>No deployment URL yet</div>
|
||||||
<div style={{ fontSize: "0.8rem", color: "#a09a90", maxWidth: 320, lineHeight: 1.6, fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.8rem", color: "#a09a90", maxWidth: 320, lineHeight: 1.6, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Deploy an app via Coolify to see a live preview here. Once deployed, the URL will appear automatically.
|
Deploy an app via Coolify to see a live preview here. Once deployed, the URL will appear automatically.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -1337,7 +1337,7 @@ function BuildHubInner() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", height: "100%", fontFamily: "Outfit, sans-serif", overflow: "hidden" }}>
|
<div style={{ display: "flex", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", overflow: "hidden" }}>
|
||||||
|
|
||||||
{/* ── Build content ── */}
|
{/* ── Build content ── */}
|
||||||
<div style={{ flex: 1, display: "flex", overflow: "hidden", minWidth: 0 }}>
|
<div style={{ flex: 1, display: "flex", overflow: "hidden", minWidth: 0 }}>
|
||||||
@@ -1356,13 +1356,13 @@ function BuildHubInner() {
|
|||||||
onClick={() => navigate({ section: "code", app: app.name, root: app.path })}
|
onClick={() => navigate({ section: "code", app: app.name, root: app.path })}
|
||||||
/>
|
/>
|
||||||
)) : (
|
)) : (
|
||||||
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>No apps yet</div>
|
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>No apps yet</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
{activeApp && activeRoot && (
|
{activeApp && activeRoot && (
|
||||||
<div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden", borderTop: "1px solid #e8e4dc", marginTop: 6 }}>
|
<div style={{ flex: 1, display: "flex", flexDirection: "column", overflow: "hidden", borderTop: "1px solid #e8e4dc", marginTop: 6 }}>
|
||||||
<div style={{ padding: "7px 12px 4px", flexShrink: 0, display: "flex", alignItems: "center", gap: 6 }}>
|
<div style={{ padding: "7px 12px 4px", flexShrink: 0, display: "flex", alignItems: "center", gap: 6 }}>
|
||||||
<span style={{ fontSize: "0.57rem", fontWeight: 700, color: "#b5b0a6", letterSpacing: "0.1em", textTransform: "uppercase", fontFamily: "Outfit, sans-serif" }}>Files</span>
|
<span style={{ fontSize: "0.57rem", fontWeight: 700, color: "#b5b0a6", letterSpacing: "0.1em", textTransform: "uppercase", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Files</span>
|
||||||
<span style={{ fontSize: "0.62rem", color: "#a09a90", fontFamily: "IBM Plex Mono, monospace", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{activeApp}</span>
|
<span style={{ fontSize: "0.62rem", color: "#a09a90", fontFamily: "IBM Plex Mono, monospace", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{activeApp}</span>
|
||||||
</div>
|
</div>
|
||||||
<FileTree projectId={projectId} rootPath={activeRoot} selectedPath={selectedFilePath} onSelectFile={handleSelectFile} />
|
<FileTree projectId={projectId} rootPath={activeRoot} selectedPath={selectedFilePath} onSelectFile={handleSelectFile} />
|
||||||
@@ -1381,7 +1381,7 @@ function BuildHubInner() {
|
|||||||
onClick={() => { setActiveSurfaceId(s.id); navigate({ section: "layouts", surface: s.id }); }}
|
onClick={() => { setActiveSurfaceId(s.id); navigate({ section: "layouts", surface: s.id }); }}
|
||||||
/>
|
/>
|
||||||
)) : (
|
)) : (
|
||||||
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>Not configured</div>
|
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Not configured</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1409,7 +1409,7 @@ function BuildHubInner() {
|
|||||||
return (
|
return (
|
||||||
<button key={item.id} onClick={() => navigate({ section: "tasks", tab: item.id })} style={{
|
<button key={item.id} onClick={() => navigate({ section: "tasks", tab: item.id })} style={{
|
||||||
flex: 1, padding: "5px 0", border: "none", borderRadius: 6, cursor: "pointer",
|
flex: 1, padding: "5px 0", border: "none", borderRadius: 6, cursor: "pointer",
|
||||||
fontSize: "0.72rem", fontWeight: 600, fontFamily: "Outfit, sans-serif",
|
fontSize: "0.72rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
background: isActive ? "#1a1a1a" : "transparent",
|
background: isActive ? "#1a1a1a" : "transparent",
|
||||||
color: isActive ? "#fff" : "#a09a90",
|
color: isActive ? "#fff" : "#a09a90",
|
||||||
transition: "all 0.12s",
|
transition: "all 0.12s",
|
||||||
@@ -1429,7 +1429,7 @@ function BuildHubInner() {
|
|||||||
onClick={() => navigate({ section: "tasks", tab: "tasks", app: app.name, root: app.path })}
|
onClick={() => navigate({ section: "tasks", tab: "tasks", app: app.name, root: app.path })}
|
||||||
/>
|
/>
|
||||||
)) : (
|
)) : (
|
||||||
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>No apps yet</div>
|
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>No apps yet</div>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
@@ -1446,7 +1446,7 @@ function BuildHubInner() {
|
|||||||
onClick={() => setActivePreviewApp(app)}
|
onClick={() => setActivePreviewApp(app)}
|
||||||
/>
|
/>
|
||||||
)) : (
|
)) : (
|
||||||
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif" }}>No deployments yet</div>
|
<div style={{ padding: "8px 22px", fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>No deployments yet</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -1492,7 +1492,7 @@ function BuildHubInner() {
|
|||||||
|
|
||||||
export default function BuildPage() {
|
export default function BuildPage() {
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "Outfit, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
||||||
<BuildHubInner />
|
<BuildHubInner />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ export default function DeploymentPage() {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "Outfit, sans-serif", color: "#a09a90" }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#a09a90" }}>
|
||||||
Loading…
|
Loading…
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -77,11 +77,11 @@ export default function DeploymentPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="vibn-enter"
|
className="vibn-enter"
|
||||||
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "Outfit, sans-serif" }}
|
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}
|
||||||
>
|
>
|
||||||
<div style={{ maxWidth: 560 }}>
|
<div style={{ maxWidth: 560 }}>
|
||||||
<h3 style={{
|
<h3 style={{
|
||||||
fontFamily: "Newsreader, serif", fontSize: "1.2rem",
|
fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem",
|
||||||
fontWeight: 400, color: "#1a1a1a", marginBottom: 4,
|
fontWeight: 400, color: "#1a1a1a", marginBottom: 4,
|
||||||
}}>
|
}}>
|
||||||
Deployment
|
Deployment
|
||||||
@@ -103,7 +103,7 @@ export default function DeploymentPage() {
|
|||||||
<div style={{ fontSize: "0.84rem", fontFamily: "IBM Plex Mono, monospace", color: "#3d5afe", fontWeight: 500 }}>{project.coolifyDeployUrl}</div>
|
<div style={{ fontSize: "0.84rem", fontFamily: "IBM Plex Mono, monospace", color: "#3d5afe", fontWeight: 500 }}>{project.coolifyDeployUrl}</div>
|
||||||
</div>
|
</div>
|
||||||
<a href={project.coolifyDeployUrl} target="_blank" rel="noopener noreferrer"
|
<a href={project.coolifyDeployUrl} target="_blank" rel="noopener noreferrer"
|
||||||
style={{ padding: "5px 12px", borderRadius: 7, border: "1px solid #e0dcd4", background: "#fff", color: "#1a1a1a", fontSize: "0.7rem", fontWeight: 600, textDecoration: "none", fontFamily: "Outfit, sans-serif" }}>
|
style={{ padding: "5px 12px", borderRadius: 7, border: "1px solid #e0dcd4", background: "#fff", color: "#1a1a1a", fontSize: "0.7rem", fontWeight: 600, textDecoration: "none", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Open ↗
|
Open ↗
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -117,7 +117,7 @@ export default function DeploymentPage() {
|
|||||||
</div>
|
</div>
|
||||||
<span style={{ display: "inline-flex", alignItems: "center", padding: "3px 9px", borderRadius: 4, fontSize: "0.68rem", fontWeight: 600, color: "#2e7d32", background: "#2e7d3210" }}>SSL Active</span>
|
<span style={{ display: "inline-flex", alignItems: "center", padding: "3px 9px", borderRadius: 4, fontSize: "0.68rem", fontWeight: 600, color: "#2e7d32", background: "#2e7d3210" }}>SSL Active</span>
|
||||||
<a href={`https://${project.customDomain}`} target="_blank" rel="noopener noreferrer"
|
<a href={`https://${project.customDomain}`} target="_blank" rel="noopener noreferrer"
|
||||||
style={{ padding: "5px 12px", borderRadius: 7, border: "1px solid #e0dcd4", background: "#fff", color: "#1a1a1a", fontSize: "0.7rem", fontWeight: 600, textDecoration: "none", fontFamily: "Outfit, sans-serif" }}>
|
style={{ padding: "5px 12px", borderRadius: 7, border: "1px solid #e0dcd4", background: "#fff", color: "#1a1a1a", fontSize: "0.7rem", fontWeight: 600, textDecoration: "none", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Open ↗
|
Open ↗
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -130,7 +130,7 @@ export default function DeploymentPage() {
|
|||||||
<div style={{ fontSize: "0.84rem", fontFamily: "IBM Plex Mono, monospace", color: "#6b6560", fontWeight: 500 }}>{project.giteaRepo}</div>
|
<div style={{ fontSize: "0.84rem", fontFamily: "IBM Plex Mono, monospace", color: "#6b6560", fontWeight: 500 }}>{project.giteaRepo}</div>
|
||||||
</div>
|
</div>
|
||||||
<a href={project.giteaRepoUrl} target="_blank" rel="noopener noreferrer"
|
<a href={project.giteaRepoUrl} target="_blank" rel="noopener noreferrer"
|
||||||
style={{ padding: "5px 12px", borderRadius: 7, border: "1px solid #e0dcd4", background: "#fff", color: "#1a1a1a", fontSize: "0.7rem", fontWeight: 600, textDecoration: "none", fontFamily: "Outfit, sans-serif" }}>
|
style={{ padding: "5px 12px", borderRadius: 7, border: "1px solid #e0dcd4", background: "#fff", color: "#1a1a1a", fontSize: "0.7rem", fontWeight: 600, textDecoration: "none", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
View ↗
|
View ↗
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -166,7 +166,7 @@ export default function DeploymentPage() {
|
|||||||
<button
|
<button
|
||||||
onClick={handleConnectDomain}
|
onClick={handleConnectDomain}
|
||||||
disabled={connecting}
|
disabled={connecting}
|
||||||
style={{ padding: "9px 18px", borderRadius: 7, border: "none", background: "#1a1a1a", color: "#fff", fontSize: "0.78rem", fontWeight: 600, cursor: "pointer", fontFamily: "Outfit, sans-serif", opacity: connecting ? 0.6 : 1 }}
|
style={{ padding: "9px 18px", borderRadius: 7, border: "none", background: "#1a1a1a", color: "#fff", fontSize: "0.78rem", fontWeight: 600, cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", opacity: connecting ? 0.6 : 1 }}
|
||||||
>
|
>
|
||||||
{connecting ? "Connecting…" : "Connect"}
|
{connecting ? "Connecting…" : "Connect"}
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -361,7 +361,7 @@ const LIBRARY_STYLE_OPTIONS: Record<string, LibraryStyleOptions> = {
|
|||||||
function ConfigRow({ label, children }: { label: string; children: React.ReactNode }) {
|
function ConfigRow({ label, children }: { label: string; children: React.ReactNode }) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 7, paddingBottom: 12, borderBottom: "1px solid #f0ece4" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 7, paddingBottom: 12, borderBottom: "1px solid #f0ece4" }}>
|
||||||
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "Outfit" }}>{label}</span>
|
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>{label}</span>
|
||||||
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
|
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@@ -383,7 +383,7 @@ function OptionChip({
|
|||||||
display: "flex", alignItems: "center", gap: 5,
|
display: "flex", alignItems: "center", gap: 5,
|
||||||
padding: multi ? "4px 9px" : "4px 11px",
|
padding: multi ? "4px 9px" : "4px 11px",
|
||||||
borderRadius: 5, border: "1px solid",
|
borderRadius: 5, border: "1px solid",
|
||||||
fontSize: "0.72rem", fontFamily: "Outfit", cursor: "pointer",
|
fontSize: "0.72rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
transition: "all 0.1s",
|
transition: "all 0.1s",
|
||||||
borderColor: active ? "#1a1a1a" : "#e0dcd4",
|
borderColor: active ? "#1a1a1a" : "#e0dcd4",
|
||||||
background: active ? "#1a1a1a" : "#fff",
|
background: active ? "#1a1a1a" : "#fff",
|
||||||
@@ -411,7 +411,7 @@ function ModeToggle({ value, onChange }: { value: string; onChange: (v: "dark" |
|
|||||||
key={m}
|
key={m}
|
||||||
onClick={() => onChange(id)}
|
onClick={() => onChange(id)}
|
||||||
style={{
|
style={{
|
||||||
padding: "4px 14px", border: "none", fontSize: "0.72rem", fontFamily: "Outfit",
|
padding: "4px 14px", border: "none", fontSize: "0.72rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: "pointer", fontWeight: active ? 600 : 400,
|
cursor: "pointer", fontWeight: active ? 600 : 400,
|
||||||
background: active ? "#1a1a1a" : "transparent",
|
background: active ? "#1a1a1a" : "transparent",
|
||||||
color: active ? "#fff" : "#8a8478",
|
color: active ? "#fff" : "#8a8478",
|
||||||
@@ -622,7 +622,7 @@ function SurfaceSection({
|
|||||||
{ScaffoldComponent
|
{ScaffoldComponent
|
||||||
? <ScaffoldComponent themeColor={activeColorTheme ?? undefined} config={designConfig} />
|
? <ScaffoldComponent themeColor={activeColorTheme ?? undefined} config={designConfig} />
|
||||||
: (
|
: (
|
||||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "#b5b0a6", fontSize: "0.82rem", fontFamily: "Outfit" }}>
|
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", color: "#b5b0a6", fontSize: "0.82rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Select a library below to preview
|
Select a library below to preview
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@@ -647,7 +647,7 @@ function SurfaceSection({
|
|||||||
style={{
|
style={{
|
||||||
flex: 1, padding: "7px 14px", borderRadius: 7, border: "1px solid #e0dcd4",
|
flex: 1, padding: "7px 14px", borderRadius: 7, border: "1px solid #e0dcd4",
|
||||||
background: "#fff", color: "#1a1a1a", fontSize: "0.76rem", fontWeight: 600,
|
background: "#fff", color: "#1a1a1a", fontSize: "0.76rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit", cursor: "pointer", transition: "opacity 0.15s",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer", transition: "opacity 0.15s",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => (e.currentTarget.style.opacity = "0.7")}
|
onMouseEnter={e => (e.currentTarget.style.opacity = "0.7")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
||||||
@@ -660,7 +660,7 @@ function SurfaceSection({
|
|||||||
flex: 1, padding: "7px 14px", borderRadius: 7, border: `1px solid ${previewId && !saving ? "#1a1a1a" : "#e0dcd4"}`,
|
flex: 1, padding: "7px 14px", borderRadius: 7, border: `1px solid ${previewId && !saving ? "#1a1a1a" : "#e0dcd4"}`,
|
||||||
background: previewId && !saving ? "#1a1a1a" : "#e0dcd4",
|
background: previewId && !saving ? "#1a1a1a" : "#e0dcd4",
|
||||||
color: previewId && !saving ? "#fff" : "#b5b0a6",
|
color: previewId && !saving ? "#fff" : "#b5b0a6",
|
||||||
fontSize: "0.76rem", fontWeight: 600, fontFamily: "Outfit",
|
fontSize: "0.76rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: !previewId || saving ? "not-allowed" : "pointer",
|
cursor: !previewId || saving ? "not-allowed" : "pointer",
|
||||||
transition: "opacity 0.15s",
|
transition: "opacity 0.15s",
|
||||||
}}
|
}}
|
||||||
@@ -670,7 +670,7 @@ function SurfaceSection({
|
|||||||
)}
|
)}
|
||||||
{activeTheme && (
|
{activeTheme && (
|
||||||
<a href={activeTheme.url} target="_blank" rel="noopener noreferrer"
|
<a href={activeTheme.url} target="_blank" rel="noopener noreferrer"
|
||||||
style={{ fontSize: "0.72rem", color: "#b5b0a6", textDecoration: "none", fontFamily: "Outfit", flexShrink: 0 }}
|
style={{ fontSize: "0.72rem", color: "#b5b0a6", textDecoration: "none", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flexShrink: 0 }}
|
||||||
onMouseEnter={e => (e.currentTarget.style.color = "#1a1a1a")}
|
onMouseEnter={e => (e.currentTarget.style.color = "#1a1a1a")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.color = "#b5b0a6")}
|
onMouseLeave={e => (e.currentTarget.style.color = "#b5b0a6")}
|
||||||
>Docs ↗</a>
|
>Docs ↗</a>
|
||||||
@@ -679,7 +679,7 @@ function SurfaceSection({
|
|||||||
|
|
||||||
{/* 2. Library */}
|
{/* 2. Library */}
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 7, paddingBottom: 12, borderBottom: "1px solid #f0ece4" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 7, paddingBottom: 12, borderBottom: "1px solid #f0ece4" }}>
|
||||||
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "Outfit" }}>Library</span>
|
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Library</span>
|
||||||
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
|
<div style={{ display: "flex", gap: 6, flexWrap: "wrap" }}>
|
||||||
{surface.themes.map(theme => {
|
{surface.themes.map(theme => {
|
||||||
const isActive = theme.id === previewId;
|
const isActive = theme.id === previewId;
|
||||||
@@ -693,7 +693,7 @@ function SurfaceSection({
|
|||||||
style={{
|
style={{
|
||||||
display: "flex", alignItems: "center", gap: 4,
|
display: "flex", alignItems: "center", gap: 4,
|
||||||
padding: "4px 11px", borderRadius: 5, border: "1px solid",
|
padding: "4px 11px", borderRadius: 5, border: "1px solid",
|
||||||
fontSize: "0.72rem", fontFamily: "Outfit", cursor: dimmed ? "not-allowed" : "pointer",
|
fontSize: "0.72rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: dimmed ? "not-allowed" : "pointer",
|
||||||
transition: "all 0.1s", opacity: dimmed ? 0.35 : 1,
|
transition: "all 0.1s", opacity: dimmed ? 0.35 : 1,
|
||||||
borderColor: isActive ? "#1a1a1a" : "#e0dcd4",
|
borderColor: isActive ? "#1a1a1a" : "#e0dcd4",
|
||||||
background: isActive ? "#1a1a1a" : "#fff",
|
background: isActive ? "#1a1a1a" : "#fff",
|
||||||
@@ -720,7 +720,7 @@ function SurfaceSection({
|
|||||||
{/* 4. Colour */}
|
{/* 4. Colour */}
|
||||||
{availableColorThemes.length > 0 && (
|
{availableColorThemes.length > 0 && (
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 7, paddingBottom: 12, borderBottom: "1px solid #f0ece4" }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 7, paddingBottom: 12, borderBottom: "1px solid #f0ece4" }}>
|
||||||
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "Outfit" }}>Colour</span>
|
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Colour</span>
|
||||||
<div style={{ display: "flex", gap: 7, flexWrap: "wrap", alignItems: "center" }}>
|
<div style={{ display: "flex", gap: 7, flexWrap: "wrap", alignItems: "center" }}>
|
||||||
{availableColorThemes.map(ct => (
|
{availableColorThemes.map(ct => (
|
||||||
<button
|
<button
|
||||||
@@ -740,7 +740,7 @@ function SurfaceSection({
|
|||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
{activeColorTheme && (
|
{activeColorTheme && (
|
||||||
<span style={{ fontSize: "0.72rem", color: "#a09a90", fontFamily: "Outfit" }}>{activeColorTheme.label}</span>
|
<span style={{ fontSize: "0.72rem", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>{activeColorTheme.label}</span>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -801,7 +801,7 @@ function SurfaceSection({
|
|||||||
{/* Colour swatches when locked (read-only) */}
|
{/* Colour swatches when locked (read-only) */}
|
||||||
{isLocked && availableColorThemes.length > 0 && (
|
{isLocked && availableColorThemes.length > 0 && (
|
||||||
<div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
|
<div style={{ display: "flex", flexDirection: "column", gap: 7 }}>
|
||||||
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "Outfit" }}>Colour</span>
|
<span style={{ fontSize: "0.62rem", fontWeight: 700, color: "#a09a90", textTransform: "uppercase", letterSpacing: "0.1em", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>Colour</span>
|
||||||
<div style={{ display: "flex", gap: 7, flexWrap: "wrap" }}>
|
<div style={{ display: "flex", gap: 7, flexWrap: "wrap" }}>
|
||||||
{availableColorThemes.map(ct => (
|
{availableColorThemes.map(ct => (
|
||||||
<button key={ct.id} title={ct.label} disabled
|
<button key={ct.id} title={ct.label} disabled
|
||||||
@@ -863,8 +863,8 @@ function SurfacePicker({
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: "28px 32px", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ padding: "28px 32px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<h3 style={{ fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
<h3 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
||||||
Design surfaces
|
Design surfaces
|
||||||
</h3>
|
</h3>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: aiSuggested.length > 0 ? 10 : 24 }}>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: aiSuggested.length > 0 ? 10 : 24 }}>
|
||||||
@@ -898,7 +898,7 @@ function SurfacePicker({
|
|||||||
border: `1px solid ${isSelected ? "#1a1a1a" : "#e8e4dc"}`,
|
border: `1px solid ${isSelected ? "#1a1a1a" : "#e8e4dc"}`,
|
||||||
background: isSelected ? "#1a1a1a08" : "#fff",
|
background: isSelected ? "#1a1a1a08" : "#fff",
|
||||||
boxShadow: isSelected ? "0 0 0 1px #1a1a1a" : "0 1px 2px #1a1a1a05",
|
boxShadow: isSelected ? "0 0 0 1px #1a1a1a" : "0 1px 2px #1a1a1a05",
|
||||||
cursor: "pointer", transition: "all 0.12s", fontFamily: "Outfit",
|
cursor: "pointer", transition: "all 0.12s", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => { if (!isSelected) (e.currentTarget.style.borderColor = "#d0ccc4"); }}
|
onMouseEnter={e => { if (!isSelected) (e.currentTarget.style.borderColor = "#d0ccc4"); }}
|
||||||
@@ -937,7 +937,7 @@ function SurfacePicker({
|
|||||||
padding: "9px 20px", borderRadius: 7, border: "none",
|
padding: "9px 20px", borderRadius: 7, border: "none",
|
||||||
background: selected.size === 0 || saving ? "#e0dcd4" : "#1a1a1a",
|
background: selected.size === 0 || saving ? "#e0dcd4" : "#1a1a1a",
|
||||||
color: selected.size === 0 || saving ? "#b5b0a6" : "#fff",
|
color: selected.size === 0 || saving ? "#b5b0a6" : "#fff",
|
||||||
fontSize: "0.82rem", fontWeight: 600, fontFamily: "Outfit",
|
fontSize: "0.82rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: selected.size === 0 || saving ? "not-allowed" : "pointer",
|
cursor: selected.size === 0 || saving ? "not-allowed" : "pointer",
|
||||||
transition: "opacity 0.15s",
|
transition: "opacity 0.15s",
|
||||||
}}
|
}}
|
||||||
@@ -947,7 +947,7 @@ function SurfacePicker({
|
|||||||
{saving ? "Saving…" : `Confirm surfaces (${selected.size})`} →
|
{saving ? "Saving…" : `Confirm surfaces (${selected.size})`} →
|
||||||
</button>
|
</button>
|
||||||
{selected.size === 0 && (
|
{selected.size === 0 && (
|
||||||
<p style={{ display: "inline-block", marginLeft: 12, fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "Outfit" }}>
|
<p style={{ display: "inline-block", marginLeft: 12, fontSize: "0.74rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
Select at least one surface to continue
|
Select at least one surface to continue
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -1056,7 +1056,7 @@ function DesignPageInner({ projectId }: { projectId: string }) {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "Outfit" }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ width: 18, height: 18, borderRadius: "50%", border: "2px solid #e8e4dc", borderTopColor: "#1a1a1a", animation: "spin 0.8s linear infinite" }} />
|
<div style={{ width: 18, height: 18, borderRadius: "50%", border: "2px solid #e8e4dc", borderTopColor: "#1a1a1a", animation: "spin 0.8s linear infinite" }} />
|
||||||
<style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
|
<style>{`@keyframes spin { to { transform: rotate(360deg); } }`}</style>
|
||||||
</div>
|
</div>
|
||||||
@@ -1072,7 +1072,7 @@ function DesignPageInner({ projectId }: { projectId: string }) {
|
|||||||
const lockedCount = Object.keys(surfaceThemes).length;
|
const lockedCount = Object.keys(surfaceThemes).length;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", height: "100%", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ display: "flex", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
|
|
||||||
{/* Left nav */}
|
{/* Left nav */}
|
||||||
<div style={{ width: 180, flexShrink: 0, borderRight: "1px solid #e8e4dc", display: "flex", flexDirection: "column", background: "#fff" }}>
|
<div style={{ width: 180, flexShrink: 0, borderRight: "1px solid #e8e4dc", display: "flex", flexDirection: "column", background: "#fff" }}>
|
||||||
@@ -1095,7 +1095,7 @@ function DesignPageInner({ projectId }: { projectId: string }) {
|
|||||||
color: isActive ? "#1a1a1a" : "#6b6560",
|
color: isActive ? "#1a1a1a" : "#6b6560",
|
||||||
fontSize: "0.8rem", fontWeight: isActive ? 600 : 450,
|
fontSize: "0.8rem", fontWeight: isActive ? 600 : 450,
|
||||||
cursor: "pointer", transition: "all 0.12s", position: "relative",
|
cursor: "pointer", transition: "all 0.12s", position: "relative",
|
||||||
fontFamily: "Outfit",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => { if (!isActive) (e.currentTarget.style.background = "#f6f4f0"); }}
|
onMouseEnter={e => { if (!isActive) (e.currentTarget.style.background = "#f6f4f0"); }}
|
||||||
onMouseLeave={e => { if (!isActive) (e.currentTarget.style.background = "transparent"); }}
|
onMouseLeave={e => { if (!isActive) (e.currentTarget.style.background = "transparent"); }}
|
||||||
@@ -1113,11 +1113,11 @@ function DesignPageInner({ projectId }: { projectId: string }) {
|
|||||||
|
|
||||||
<div style={{ padding: "12px 18px", borderTop: "1px solid #f0ece4" }}>
|
<div style={{ padding: "12px 18px", borderTop: "1px solid #f0ece4" }}>
|
||||||
{lockedCount === activeSurfaces.length && lockedCount > 0 && (
|
{lockedCount === activeSurfaces.length && lockedCount > 0 && (
|
||||||
<p style={{ fontSize: "0.68rem", color: "#2e7d32", fontFamily: "Outfit", marginBottom: 6 }}>✓ All locked</p>
|
<p style={{ fontSize: "0.68rem", color: "#2e7d32", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", marginBottom: 6 }}>✓ All locked</p>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
onClick={() => setSurfaces([])}
|
onClick={() => setSurfaces([])}
|
||||||
style={{ fontSize: "0.72rem", color: "#a09a90", background: "none", border: "none", cursor: "pointer", fontFamily: "Outfit", padding: 0 }}
|
style={{ fontSize: "0.72rem", color: "#a09a90", background: "none", border: "none", cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", padding: 0 }}
|
||||||
onMouseEnter={e => (e.currentTarget.style.color = "#1a1a1a")}
|
onMouseEnter={e => (e.currentTarget.style.color = "#1a1a1a")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.color = "#a09a90")}
|
onMouseLeave={e => (e.currentTarget.style.color = "#a09a90")}
|
||||||
>
|
>
|
||||||
@@ -1147,7 +1147,7 @@ function DesignPageInner({ projectId }: { projectId: string }) {
|
|||||||
export default function DesignPage({ params }: { params: Promise<{ workspace: string; projectId: string }> }) {
|
export default function DesignPage({ params }: { params: Promise<{ workspace: string; projectId: string }> }) {
|
||||||
const { projectId } = use(params);
|
const { projectId } = use(params);
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "Outfit, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
||||||
<DesignPageInner projectId={projectId} />
|
<DesignPageInner projectId={projectId} />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ export default function GrowPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="vibn-enter"
|
className="vibn-enter"
|
||||||
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "Outfit, sans-serif" }}
|
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}
|
||||||
>
|
>
|
||||||
<div style={{ maxWidth: 560 }}>
|
<div style={{ maxWidth: 560 }}>
|
||||||
<h3 style={{ fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
<h3 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
||||||
Grow
|
Grow
|
||||||
</h3>
|
</h3>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: 28 }}>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: 28 }}>
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ type SectionId = typeof SECTIONS[number]["id"];
|
|||||||
const NAV_GROUP: React.CSSProperties = {
|
const NAV_GROUP: React.CSSProperties = {
|
||||||
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
fontSize: "0.6rem", fontWeight: 700, color: "#b5b0a6",
|
||||||
letterSpacing: "0.09em", textTransform: "uppercase",
|
letterSpacing: "0.09em", textTransform: "uppercase",
|
||||||
padding: "14px 12px 6px", fontFamily: "Outfit, sans-serif",
|
padding: "14px 12px 6px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
};
|
};
|
||||||
|
|
||||||
function GrowthInner() {
|
function GrowthInner() {
|
||||||
@@ -60,7 +60,7 @@ function GrowthInner() {
|
|||||||
router.push(`/${workspace}/project/${projectId}/growth?section=${id}`, { scroll: false });
|
router.push(`/${workspace}/project/${projectId}/growth?section=${id}`, { scroll: false });
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", height: "100%", fontFamily: "Outfit, sans-serif", overflow: "hidden" }}>
|
<div style={{ display: "flex", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", overflow: "hidden" }}>
|
||||||
|
|
||||||
{/* Left nav */}
|
{/* Left nav */}
|
||||||
<div style={{ width: 200, flexShrink: 0, borderRight: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", flexDirection: "column", overflow: "auto" }}>
|
<div style={{ width: 200, flexShrink: 0, borderRight: "1px solid #e8e4dc", background: "#faf8f5", display: "flex", flexDirection: "column", overflow: "auto" }}>
|
||||||
@@ -137,7 +137,7 @@ function GrowthInner() {
|
|||||||
|
|
||||||
export default function GrowthPage() {
|
export default function GrowthPage() {
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "Outfit, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
||||||
<GrowthInner />
|
<GrowthInner />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -285,7 +285,7 @@ function InfrastructurePageInner() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", height: "100%", fontFamily: "Outfit, sans-serif", overflow: "hidden" }}>
|
<div style={{ display: "flex", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", overflow: "hidden" }}>
|
||||||
|
|
||||||
{/* ── Left sub-nav ── */}
|
{/* ── Left sub-nav ── */}
|
||||||
<div style={{
|
<div style={{
|
||||||
@@ -346,7 +346,7 @@ function InfrastructurePageInner() {
|
|||||||
|
|
||||||
export default function InfrastructurePage() {
|
export default function InfrastructurePage() {
|
||||||
return (
|
return (
|
||||||
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "Outfit, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
<Suspense fallback={<div style={{ display: "flex", height: "100%", alignItems: "center", justifyContent: "center", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem" }}>Loading…</div>}>
|
||||||
<InfrastructurePageInner />
|
<InfrastructurePageInner />
|
||||||
</Suspense>
|
</Suspense>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -11,10 +11,10 @@ export default function InsightsPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="vibn-enter"
|
className="vibn-enter"
|
||||||
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "Outfit, sans-serif" }}
|
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}
|
||||||
>
|
>
|
||||||
<div style={{ maxWidth: 560 }}>
|
<div style={{ maxWidth: 560 }}>
|
||||||
<h3 style={{ fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
<h3 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
||||||
Insights
|
Insights
|
||||||
</h3>
|
</h3>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: 28 }}>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: 28 }}>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export default function ProjectOverviewPage() {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<Loader2 style={{ width: 24, height: 24, color: "#a09a90" }} className="animate-spin" />
|
<Loader2 style={{ width: 24, height: 24, color: "#a09a90" }} className="animate-spin" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -56,7 +56,7 @@ export default function ProjectOverviewPage() {
|
|||||||
|
|
||||||
if (!project) {
|
if (!project) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "Outfit, sans-serif", color: "#a09a90", fontSize: "0.88rem" }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#a09a90", fontSize: "0.88rem" }}>
|
||||||
Project not found.
|
Project not found.
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ function PhaseDataCard({ phase }: { phase: SavedPhase }) {
|
|||||||
width: "100%", textAlign: "left", padding: "10px 14px",
|
width: "100%", textAlign: "left", padding: "10px 14px",
|
||||||
background: "none", border: "none", cursor: "pointer",
|
background: "none", border: "none", cursor: "pointer",
|
||||||
display: "flex", alignItems: "center", justifyContent: "space-between",
|
display: "flex", alignItems: "center", justifyContent: "space-between",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: "0.78rem", color: "#4a4640", lineHeight: 1.45 }}>
|
<span style={{ fontSize: "0.78rem", color: "#4a4640", lineHeight: 1.45 }}>
|
||||||
@@ -237,7 +237,7 @@ export default function PRDPage() {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "Outfit, sans-serif", color: "#a09a90" }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#a09a90" }}>
|
||||||
Loading…
|
Loading…
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -249,7 +249,7 @@ export default function PRDPage() {
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ padding: "28px 32px", flex: 1, overflow: "auto", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ padding: "28px 32px", flex: 1, overflow: "auto", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
|
|
||||||
{/* Tab bar — only when at least one doc exists */}
|
{/* Tab bar — only when at least one doc exists */}
|
||||||
{(prd || architecture) && (
|
{(prd || architecture) && (
|
||||||
@@ -266,7 +266,7 @@ export default function PRDPage() {
|
|||||||
background: isActive ? "#1a1a1a" : "transparent",
|
background: isActive ? "#1a1a1a" : "transparent",
|
||||||
color: isActive ? "#fff" : t.available ? "#6b6560" : "#c5c0b8",
|
color: isActive ? "#fff" : t.available ? "#6b6560" : "#c5c0b8",
|
||||||
fontSize: "0.8rem", fontWeight: isActive ? 600 : 400,
|
fontSize: "0.8rem", fontWeight: isActive ? 600 : 400,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
transition: "all 0.1s",
|
transition: "all 0.1s",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -305,7 +305,7 @@ export default function PRDPage() {
|
|||||||
background: archGenerating ? "#4a4640" : "#fff",
|
background: archGenerating ? "#4a4640" : "#fff",
|
||||||
color: archGenerating ? "#a09a90" : "#1a1a1a",
|
color: archGenerating ? "#a09a90" : "#1a1a1a",
|
||||||
fontSize: "0.82rem", fontWeight: 700,
|
fontSize: "0.82rem", fontWeight: 700,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: archGenerating ? "default" : "pointer",
|
cursor: archGenerating ? "default" : "pointer",
|
||||||
flexShrink: 0, display: "flex", alignItems: "center", gap: 8,
|
flexShrink: 0, display: "flex", alignItems: "center", gap: 8,
|
||||||
transition: "opacity 0.15s",
|
transition: "opacity 0.15s",
|
||||||
@@ -332,7 +332,7 @@ export default function PRDPage() {
|
|||||||
{activeTab === "prd" && prd && (
|
{activeTab === "prd" && prd && (
|
||||||
<div style={{ maxWidth: 760 }}>
|
<div style={{ maxWidth: 760 }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 20 }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 20 }}>
|
||||||
<h3 style={{ fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", margin: 0 }}>
|
<h3 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", margin: 0 }}>
|
||||||
Product Requirements
|
Product Requirements
|
||||||
</h3>
|
</h3>
|
||||||
<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: "0.72rem", color: "#6b6560", background: "#f0ece4", padding: "4px 10px", borderRadius: 5 }}>
|
<span style={{ fontFamily: "IBM Plex Mono, monospace", fontSize: "0.72rem", color: "#6b6560", background: "#f0ece4", padding: "4px 10px", borderRadius: 5 }}>
|
||||||
@@ -343,7 +343,7 @@ export default function PRDPage() {
|
|||||||
background: "#fff", borderRadius: 10, border: "1px solid #e8e4dc",
|
background: "#fff", borderRadius: 10, border: "1px solid #e8e4dc",
|
||||||
padding: "28px 32px", lineHeight: 1.8,
|
padding: "28px 32px", lineHeight: 1.8,
|
||||||
fontSize: "0.88rem", color: "#2a2824",
|
fontSize: "0.88rem", color: "#2a2824",
|
||||||
whiteSpace: "pre-wrap", fontFamily: "Outfit, sans-serif",
|
whiteSpace: "pre-wrap", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}>
|
}}>
|
||||||
{prd}
|
{prd}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -122,7 +122,7 @@ export default function ProjectSettingsPage() {
|
|||||||
|
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100%", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<Loader2 style={{ width: 24, height: 24, color: "#a09a90" }} className="animate-spin" />
|
<Loader2 style={{ width: 24, height: 24, color: "#a09a90" }} className="animate-spin" />
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -131,10 +131,10 @@ export default function ProjectSettingsPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="vibn-enter"
|
className="vibn-enter"
|
||||||
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "Outfit, sans-serif" }}
|
style={{ padding: "28px 32px", overflow: "auto", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}
|
||||||
>
|
>
|
||||||
<div style={{ maxWidth: 480 }}>
|
<div style={{ maxWidth: 480 }}>
|
||||||
<h3 style={{ fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
<h3 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 4 }}>
|
||||||
Project Settings
|
Project Settings
|
||||||
</h3>
|
</h3>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: 24 }}>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", marginBottom: 24 }}>
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ function StatusTag({ status }: { status?: string }) {
|
|||||||
display: "inline-flex", alignItems: "center", gap: 5,
|
display: "inline-flex", alignItems: "center", gap: 5,
|
||||||
padding: "3px 9px", borderRadius: 4,
|
padding: "3px 9px", borderRadius: 4,
|
||||||
fontSize: "0.68rem", fontWeight: 600, letterSpacing: "0.02em",
|
fontSize: "0.68rem", fontWeight: 600, letterSpacing: "0.02em",
|
||||||
color, background: bg, fontFamily: "Outfit, sans-serif",
|
color, background: bg, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}>
|
}}>
|
||||||
<StatusDot status={status} /> {label}
|
<StatusDot status={status} /> {label}
|
||||||
</span>
|
</span>
|
||||||
@@ -135,13 +135,13 @@ export default function ProjectsPage() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className="vibn-enter"
|
className="vibn-enter"
|
||||||
style={{ padding: "44px 52px", maxWidth: 900, fontFamily: "Outfit, sans-serif" }}
|
style={{ padding: "44px 52px", maxWidth: 900, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}
|
||||||
>
|
>
|
||||||
{/* Header */}
|
{/* Header */}
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 36 }}>
|
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-end", marginBottom: 36 }}>
|
||||||
<div>
|
<div>
|
||||||
<h1 style={{
|
<h1 style={{
|
||||||
fontFamily: "Newsreader, serif", fontSize: "1.9rem",
|
fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.9rem",
|
||||||
fontWeight: 400, color: "#1a1a1a", letterSpacing: "-0.03em",
|
fontWeight: 400, color: "#1a1a1a", letterSpacing: "-0.03em",
|
||||||
lineHeight: 1.15, marginBottom: 4,
|
lineHeight: 1.15, marginBottom: 4,
|
||||||
}}>
|
}}>
|
||||||
@@ -159,7 +159,7 @@ export default function ProjectsPage() {
|
|||||||
background: "#1a1a1a", color: "#fff",
|
background: "#1a1a1a", color: "#fff",
|
||||||
border: "1px solid #1a1a1a",
|
border: "1px solid #1a1a1a",
|
||||||
fontSize: "0.78rem", fontWeight: 600,
|
fontSize: "0.78rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<span style={{ fontSize: "1rem", lineHeight: 1, fontWeight: 300 }}>+</span>
|
<span style={{ fontSize: "1rem", lineHeight: 1, fontWeight: 300 }}>+</span>
|
||||||
@@ -189,7 +189,7 @@ export default function ProjectsPage() {
|
|||||||
width: "100%", display: "flex", alignItems: "center",
|
width: "100%", display: "flex", alignItems: "center",
|
||||||
padding: "18px 22px", borderRadius: 10,
|
padding: "18px 22px", borderRadius: 10,
|
||||||
background: "#fff", border: "1px solid #e8e4dc",
|
background: "#fff", border: "1px solid #e8e4dc",
|
||||||
cursor: "pointer", fontFamily: "Outfit, sans-serif",
|
cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
textDecoration: "none", boxShadow: "0 1px 2px #1a1a1a05",
|
textDecoration: "none", boxShadow: "0 1px 2px #1a1a1a05",
|
||||||
transition: "all 0.15s",
|
transition: "all 0.15s",
|
||||||
}}
|
}}
|
||||||
@@ -212,7 +212,7 @@ export default function ProjectsPage() {
|
|||||||
flexShrink: 0,
|
flexShrink: 0,
|
||||||
}}>
|
}}>
|
||||||
<span style={{
|
<span style={{
|
||||||
fontFamily: "Newsreader, serif",
|
fontFamily: "var(--font-lora), ui-serif, serif",
|
||||||
fontSize: "1.05rem", fontWeight: 500, color: "#1a1a1a",
|
fontSize: "1.05rem", fontWeight: 500, color: "#1a1a1a",
|
||||||
}}>
|
}}>
|
||||||
{p.productName[0]?.toUpperCase() ?? "P"}
|
{p.productName[0]?.toUpperCase() ?? "P"}
|
||||||
@@ -259,7 +259,7 @@ export default function ProjectsPage() {
|
|||||||
color: "#c0bab2", cursor: "pointer",
|
color: "#c0bab2", cursor: "pointer",
|
||||||
opacity: hoveredId === p.id ? 1 : 0,
|
opacity: hoveredId === p.id ? 1 : 0,
|
||||||
transition: "opacity 0.15s, color 0.15s",
|
transition: "opacity 0.15s, color 0.15s",
|
||||||
fontFamily: "Outfit, sans-serif", flexShrink: 0,
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
onMouseEnter={(e) => { e.currentTarget.style.color = "#d32f2f"; }}
|
onMouseEnter={(e) => { e.currentTarget.style.color = "#d32f2f"; }}
|
||||||
onMouseLeave={(e) => { e.currentTarget.style.color = "#c0bab2"; }}
|
onMouseLeave={(e) => { e.currentTarget.style.color = "#c0bab2"; }}
|
||||||
@@ -278,7 +278,7 @@ export default function ProjectsPage() {
|
|||||||
width: "100%", display: "flex", alignItems: "center", justifyContent: "center",
|
width: "100%", display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
padding: "22px", borderRadius: 10,
|
padding: "22px", borderRadius: 10,
|
||||||
background: "transparent", border: "1px dashed #d0ccc4",
|
background: "transparent", border: "1px dashed #d0ccc4",
|
||||||
cursor: "pointer", fontFamily: "Outfit, sans-serif",
|
cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
color: "#b5b0a6", fontSize: "0.84rem", fontWeight: 500,
|
color: "#b5b0a6", fontSize: "0.84rem", fontWeight: 500,
|
||||||
transition: "all 0.15s",
|
transition: "all 0.15s",
|
||||||
animationDelay: `${projects.length * 0.05}s`,
|
animationDelay: `${projects.length * 0.05}s`,
|
||||||
@@ -295,7 +295,7 @@ export default function ProjectsPage() {
|
|||||||
{/* Empty state */}
|
{/* Empty state */}
|
||||||
{!loading && projects.length === 0 && (
|
{!loading && projects.length === 0 && (
|
||||||
<div style={{ textAlign: "center", paddingTop: 64 }}>
|
<div style={{ textAlign: "center", paddingTop: 64 }}>
|
||||||
<h3 style={{ fontFamily: "Newsreader, serif", fontSize: "1.3rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 8 }}>
|
<h3 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.3rem", fontWeight: 400, color: "#1a1a1a", marginBottom: 8 }}>
|
||||||
No projects yet
|
No projects yet
|
||||||
</h3>
|
</h3>
|
||||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", lineHeight: 1.6, marginBottom: 24 }}>
|
<p style={{ fontSize: "0.82rem", color: "#a09a90", lineHeight: 1.6, marginBottom: 24 }}>
|
||||||
@@ -307,7 +307,7 @@ export default function ProjectsPage() {
|
|||||||
padding: "10px 22px", borderRadius: 7,
|
padding: "10px 22px", borderRadius: 7,
|
||||||
background: "#1a1a1a", color: "#fff",
|
background: "#1a1a1a", color: "#fff",
|
||||||
border: "none", fontSize: "0.84rem", fontWeight: 600,
|
border: "none", fontSize: "0.84rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Create your first project
|
Create your first project
|
||||||
|
|||||||
@@ -11,8 +11,8 @@
|
|||||||
@theme inline {
|
@theme inline {
|
||||||
--color-background: var(--background);
|
--color-background: var(--background);
|
||||||
--color-foreground: var(--foreground);
|
--color-foreground: var(--foreground);
|
||||||
--font-sans: var(--font-outfit);
|
--font-sans: var(--font-inter);
|
||||||
--font-serif: var(--font-newsreader);
|
--font-serif: var(--font-lora);
|
||||||
--font-mono: var(--font-ibm-plex-mono);
|
--font-mono: var(--font-ibm-plex-mono);
|
||||||
--color-sidebar-ring: var(--sidebar-ring);
|
--color-sidebar-ring: var(--sidebar-ring);
|
||||||
--color-sidebar-border: var(--sidebar-border);
|
--color-sidebar-border: var(--sidebar-border);
|
||||||
@@ -51,38 +51,50 @@
|
|||||||
|
|
||||||
:root {
|
:root {
|
||||||
--radius: 0.5rem;
|
--radius: 0.5rem;
|
||||||
/* Stackless warm beige palette */
|
/* Justine UX pack — ink & parchment (aligned with master-ai/justine/00_design-tokens.css) */
|
||||||
--background: #f6f4f0;
|
--vibn-ink: #1a1510;
|
||||||
--foreground: #1a1a1a;
|
--vibn-ink2: #2c2c2a;
|
||||||
--card: #ffffff;
|
--vibn-ink3: #444441;
|
||||||
--card-foreground: #1a1a1a;
|
--vibn-mid: #5f5e5a;
|
||||||
--popover: #ffffff;
|
--vibn-muted: #888780;
|
||||||
--popover-foreground: #1a1a1a;
|
--vibn-stone: #b4b2a9;
|
||||||
--primary: #1a1a1a;
|
--vibn-parch: #d3d1c7;
|
||||||
--primary-foreground: #ffffff;
|
--vibn-cream: #f1efe8;
|
||||||
--secondary: #f0ece4;
|
--vibn-paper: #f7f4ee;
|
||||||
--secondary-foreground: #1a1a1a;
|
--vibn-white: #fdfcfa;
|
||||||
--muted: #f0ece4;
|
--vibn-border: #e8e2d9;
|
||||||
--muted-foreground: #a09a90;
|
|
||||||
--accent: #eae6de;
|
--background: var(--vibn-paper);
|
||||||
--accent-foreground: #1a1a1a;
|
--foreground: var(--vibn-ink);
|
||||||
--destructive: #d32f2f;
|
--card: var(--vibn-white);
|
||||||
--border: #e8e4dc;
|
--card-foreground: var(--vibn-ink);
|
||||||
--input: #e0dcd4;
|
--popover: var(--vibn-white);
|
||||||
--ring: #d0ccc4;
|
--popover-foreground: var(--vibn-ink);
|
||||||
|
--primary: var(--vibn-ink);
|
||||||
|
--primary-foreground: var(--vibn-paper);
|
||||||
|
--secondary: var(--vibn-cream);
|
||||||
|
--secondary-foreground: var(--vibn-ink);
|
||||||
|
--muted: var(--vibn-cream);
|
||||||
|
--muted-foreground: var(--vibn-muted);
|
||||||
|
--accent: var(--vibn-cream);
|
||||||
|
--accent-foreground: var(--vibn-ink);
|
||||||
|
--destructive: #b42318;
|
||||||
|
--border: var(--vibn-border);
|
||||||
|
--input: var(--vibn-border);
|
||||||
|
--ring: var(--vibn-stone);
|
||||||
--chart-1: oklch(0.70 0.15 60);
|
--chart-1: oklch(0.70 0.15 60);
|
||||||
--chart-2: oklch(0.70 0.12 210);
|
--chart-2: oklch(0.70 0.12 210);
|
||||||
--chart-3: oklch(0.55 0.10 220);
|
--chart-3: oklch(0.55 0.10 220);
|
||||||
--chart-4: oklch(0.40 0.08 230);
|
--chart-4: oklch(0.40 0.08 230);
|
||||||
--chart-5: oklch(0.75 0.15 70);
|
--chart-5: oklch(0.75 0.15 70);
|
||||||
--sidebar: #ffffff;
|
--sidebar: var(--vibn-white);
|
||||||
--sidebar-foreground: #1a1a1a;
|
--sidebar-foreground: var(--vibn-ink);
|
||||||
--sidebar-primary: #1a1a1a;
|
--sidebar-primary: var(--vibn-ink);
|
||||||
--sidebar-primary-foreground: #ffffff;
|
--sidebar-primary-foreground: var(--vibn-paper);
|
||||||
--sidebar-accent: #f6f4f0;
|
--sidebar-accent: var(--vibn-paper);
|
||||||
--sidebar-accent-foreground: #1a1a1a;
|
--sidebar-accent-foreground: var(--vibn-ink);
|
||||||
--sidebar-border: #e8e4dc;
|
--sidebar-border: var(--vibn-border);
|
||||||
--sidebar-ring: #d0ccc4;
|
--sidebar-ring: var(--vibn-stone);
|
||||||
}
|
}
|
||||||
|
|
||||||
.dark {
|
.dark {
|
||||||
@@ -111,8 +123,8 @@
|
|||||||
--chart-5: oklch(0.645 0.246 16.439);
|
--chart-5: oklch(0.645 0.246 16.439);
|
||||||
--sidebar: oklch(0.205 0 0);
|
--sidebar: oklch(0.205 0 0);
|
||||||
--sidebar-foreground: oklch(0.985 0 0);
|
--sidebar-foreground: oklch(0.985 0 0);
|
||||||
--sidebar-primary: oklch(0.488 0.243 264.376);
|
--sidebar-primary: oklch(0.85 0.02 85);
|
||||||
--sidebar-primary-foreground: oklch(0.985 0 0);
|
--sidebar-primary-foreground: oklch(0.18 0.02 60);
|
||||||
--sidebar-accent: oklch(0.269 0 0);
|
--sidebar-accent: oklch(0.269 0 0);
|
||||||
--sidebar-accent-foreground: oklch(0.985 0 0);
|
--sidebar-accent-foreground: oklch(0.985 0 0);
|
||||||
--sidebar-border: oklch(1 0 0 / 10%);
|
--sidebar-border: oklch(1 0 0 / 10%);
|
||||||
@@ -125,21 +137,24 @@
|
|||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
@apply bg-background text-foreground;
|
@apply bg-background text-foreground;
|
||||||
font-family: var(--font-outfit), 'Outfit', sans-serif;
|
font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
|
||||||
|
}
|
||||||
|
h1, h2, h3 {
|
||||||
|
font-family: var(--font-lora), ui-serif, Georgia, serif;
|
||||||
}
|
}
|
||||||
button {
|
button {
|
||||||
font-family: var(--font-outfit), 'Outfit', sans-serif;
|
font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
input, textarea, select {
|
input, textarea, select {
|
||||||
font-family: var(--font-outfit), 'Outfit', sans-serif;
|
font-family: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
|
||||||
}
|
}
|
||||||
input::placeholder {
|
input::placeholder {
|
||||||
color: #b5b0a6;
|
color: var(--muted-foreground);
|
||||||
}
|
}
|
||||||
::selection {
|
::selection {
|
||||||
background: #1a1a1a;
|
background: var(--foreground);
|
||||||
color: #fff;
|
color: var(--background);
|
||||||
}
|
}
|
||||||
::-webkit-scrollbar {
|
::-webkit-scrollbar {
|
||||||
width: 4px;
|
width: 4px;
|
||||||
@@ -149,7 +164,7 @@
|
|||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
::-webkit-scrollbar-thumb {
|
::-webkit-scrollbar-thumb {
|
||||||
background: #d0ccc4;
|
background: var(--vibn-stone);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,19 @@
|
|||||||
import type { Metadata } from "next";
|
import type { Metadata } from "next";
|
||||||
import { Outfit, Newsreader, IBM_Plex_Mono } from "next/font/google";
|
import { Inter, Lora, IBM_Plex_Mono } from "next/font/google";
|
||||||
import "./globals.css";
|
import "./globals.css";
|
||||||
import { Toaster } from "@/components/ui/sonner";
|
import { Toaster } from "@/components/ui/sonner";
|
||||||
import { Providers } from "@/app/components/Providers";
|
import { Providers } from "@/app/components/Providers";
|
||||||
|
|
||||||
const outfit = Outfit({
|
const inter = Inter({
|
||||||
variable: "--font-outfit",
|
variable: "--font-inter",
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
weight: ["300", "400", "500", "600", "700"],
|
weight: ["400", "500", "600", "700"],
|
||||||
});
|
});
|
||||||
|
|
||||||
const newsreader = Newsreader({
|
const lora = Lora({
|
||||||
variable: "--font-newsreader",
|
variable: "--font-lora",
|
||||||
subsets: ["latin"],
|
subsets: ["latin"],
|
||||||
weight: ["400", "500"],
|
weight: ["400", "500", "600", "700"],
|
||||||
style: ["normal", "italic"],
|
style: ["normal", "italic"],
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ export const metadata: Metadata = {
|
|||||||
},
|
},
|
||||||
other: {
|
other: {
|
||||||
"mobile-web-app-capable": "yes",
|
"mobile-web-app-capable": "yes",
|
||||||
"msapplication-TileColor": "#1a1a1a",
|
"msapplication-TileColor": "#1a1510",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -47,12 +47,12 @@ export default function RootLayout({
|
|||||||
<html lang="en" suppressHydrationWarning>
|
<html lang="en" suppressHydrationWarning>
|
||||||
<head>
|
<head>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover" />
|
||||||
<meta name="theme-color" content="#1a1a1a" />
|
<meta name="theme-color" content="#1a1510" />
|
||||||
<link rel="apple-touch-icon" href="/vibn-logo-circle.png" />
|
<link rel="apple-touch-icon" href="/vibn-logo-circle.png" />
|
||||||
<link rel="manifest" href="/manifest.json" />
|
<link rel="manifest" href="/manifest.json" />
|
||||||
</head>
|
</head>
|
||||||
<body
|
<body
|
||||||
className={`${outfit.variable} ${newsreader.variable} ${ibmPlexMono.variable} antialiased`}
|
className={`${inter.variable} ${lora.variable} ${ibmPlexMono.variable} antialiased`}
|
||||||
>
|
>
|
||||||
<Providers>
|
<Providers>
|
||||||
{children}
|
{children}
|
||||||
@@ -69,4 +69,3 @@ export default function RootLayout({
|
|||||||
</html>
|
</html>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -140,7 +140,7 @@ function MessageRow({
|
|||||||
display: "flex", alignItems: "center", justifyContent: "center",
|
display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
fontSize: "0.68rem", fontWeight: 700,
|
fontSize: "0.68rem", fontWeight: 700,
|
||||||
color: isAtlas ? "#fff" : "#8a8478",
|
color: isAtlas ? "#fff" : "#8a8478",
|
||||||
fontFamily: isAtlas ? "Newsreader, serif" : "Outfit, sans-serif",
|
fontFamily: isAtlas ? "var(--font-lora), ui-serif, serif" : "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}>
|
}}>
|
||||||
{isAtlas ? "A" : userInitial}
|
{isAtlas ? "A" : userInitial}
|
||||||
</div>
|
</div>
|
||||||
@@ -149,14 +149,14 @@ function MessageRow({
|
|||||||
<div style={{
|
<div style={{
|
||||||
fontSize: "0.68rem", fontWeight: 600, color: "#a09a90",
|
fontSize: "0.68rem", fontWeight: 600, color: "#a09a90",
|
||||||
marginBottom: 5, textTransform: "uppercase", letterSpacing: "0.04em",
|
marginBottom: 5, textTransform: "uppercase", letterSpacing: "0.04em",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}>
|
}}>
|
||||||
{isAtlas ? "Vibn" : "You"}
|
{isAtlas ? "Vibn" : "You"}
|
||||||
</div>
|
</div>
|
||||||
{/* Content */}
|
{/* Content */}
|
||||||
<div style={{
|
<div style={{
|
||||||
fontSize: "0.88rem", color: "#2a2824", lineHeight: 1.72,
|
fontSize: "0.88rem", color: "#2a2824", lineHeight: 1.72,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
whiteSpace: isAtlas ? "normal" : "pre-wrap",
|
whiteSpace: isAtlas ? "normal" : "pre-wrap",
|
||||||
}}>
|
}}>
|
||||||
{renderContent(clean)}
|
{renderContent(clean)}
|
||||||
@@ -175,7 +175,7 @@ function MessageRow({
|
|||||||
color: saved ? "#2e7d32" : "#fff",
|
color: saved ? "#2e7d32" : "#fff",
|
||||||
border: saved ? "1px solid #a5d6a7" : "none",
|
border: saved ? "1px solid #a5d6a7" : "none",
|
||||||
fontSize: "0.78rem", fontWeight: 600,
|
fontSize: "0.78rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: saved || saving ? "default" : "pointer",
|
cursor: saved || saving ? "default" : "pointer",
|
||||||
transition: "all 0.15s",
|
transition: "all 0.15s",
|
||||||
opacity: saving ? 0.7 : 1,
|
opacity: saving ? 0.7 : 1,
|
||||||
@@ -186,7 +186,7 @@ function MessageRow({
|
|||||||
{!saved && (
|
{!saved && (
|
||||||
<div style={{
|
<div style={{
|
||||||
marginTop: 6, fontSize: "0.72rem", color: "#a09a90",
|
marginTop: 6, fontSize: "0.72rem", color: "#a09a90",
|
||||||
fontFamily: "Outfit, sans-serif", lineHeight: 1.4,
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", lineHeight: 1.4,
|
||||||
}}>
|
}}>
|
||||||
{phase.summary}
|
{phase.summary}
|
||||||
</div>
|
</div>
|
||||||
@@ -218,7 +218,7 @@ function MessageRow({
|
|||||||
display: "inline-block", padding: "8px 16px", borderRadius: 7,
|
display: "inline-block", padding: "8px 16px", borderRadius: 7,
|
||||||
background: "#1a1a1a", color: "#fff",
|
background: "#1a1a1a", color: "#fff",
|
||||||
fontSize: "0.76rem", fontWeight: 600,
|
fontSize: "0.76rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif", textDecoration: "none",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", textDecoration: "none",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Review architecture →
|
Review architecture →
|
||||||
@@ -234,7 +234,7 @@ function MessageRow({
|
|||||||
style={{
|
style={{
|
||||||
padding: "7px 14px", borderRadius: 6, border: "1px solid #e0dcd4",
|
padding: "7px 14px", borderRadius: 6, border: "1px solid #e0dcd4",
|
||||||
background: "none", fontSize: "0.74rem", color: "#6b6560",
|
background: "none", fontSize: "0.74rem", color: "#6b6560",
|
||||||
fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Try again
|
Try again
|
||||||
@@ -256,7 +256,7 @@ function MessageRow({
|
|||||||
padding: "9px 18px", borderRadius: 8, border: "none",
|
padding: "9px 18px", borderRadius: 8, border: "none",
|
||||||
background: archState === "loading" ? "#8a8478" : "#1a1a1a",
|
background: archState === "loading" ? "#8a8478" : "#1a1a1a",
|
||||||
color: "#fff", fontSize: "0.78rem", fontWeight: 600,
|
color: "#fff", fontSize: "0.78rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: archState === "loading" ? "default" : "pointer",
|
cursor: archState === "loading" ? "default" : "pointer",
|
||||||
transition: "background 0.15s",
|
transition: "background 0.15s",
|
||||||
}}
|
}}
|
||||||
@@ -288,7 +288,7 @@ function TypingIndicator() {
|
|||||||
<div style={{
|
<div style={{
|
||||||
width: 28, height: 28, borderRadius: 7, flexShrink: 0, marginTop: 2,
|
width: 28, height: 28, borderRadius: 7, flexShrink: 0, marginTop: 2,
|
||||||
background: "#1a1a1a", display: "flex", alignItems: "center", justifyContent: "center",
|
background: "#1a1a1a", display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
fontSize: "0.68rem", fontWeight: 700, color: "#fff", fontFamily: "Newsreader, serif",
|
fontSize: "0.68rem", fontWeight: 700, color: "#fff", fontFamily: "var(--font-lora), ui-serif, serif",
|
||||||
}}>A</div>
|
}}>A</div>
|
||||||
<div style={{ display: "flex", gap: 5, paddingTop: 10 }}>
|
<div style={{ display: "flex", gap: 5, paddingTop: 10 }}>
|
||||||
{[0, 1, 2].map(d => (
|
{[0, 1, 2].map(d => (
|
||||||
@@ -425,7 +425,7 @@ export function AtlasChat({ projectId }: AtlasChatProps) {
|
|||||||
return (
|
return (
|
||||||
<div style={{
|
<div style={{
|
||||||
display: "flex", flexDirection: "column", height: "100%",
|
display: "flex", flexDirection: "column", height: "100%",
|
||||||
background: "#f6f4f0", fontFamily: "Outfit, sans-serif",
|
background: "#f6f4f0", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}>
|
}}>
|
||||||
<style>{`
|
<style>{`
|
||||||
@keyframes blink { 0%,100%{opacity:.2} 50%{opacity:.8} }
|
@keyframes blink { 0%,100%{opacity:.2} 50%{opacity:.8} }
|
||||||
@@ -443,7 +443,7 @@ export function AtlasChat({ projectId }: AtlasChatProps) {
|
|||||||
<div style={{
|
<div style={{
|
||||||
width: 44, height: 44, borderRadius: 11, background: "#1a1a1a",
|
width: 44, height: 44, borderRadius: 11, background: "#1a1a1a",
|
||||||
display: "flex", alignItems: "center", justifyContent: "center",
|
display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 500, color: "#fff",
|
fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 500, color: "#fff",
|
||||||
animation: "breathe 2.5s ease infinite",
|
animation: "breathe 2.5s ease infinite",
|
||||||
}}>A</div>
|
}}>A</div>
|
||||||
<style>{`@keyframes breathe { 0%,100%{transform:scale(1)} 50%{transform:scale(1.08)} }`}</style>
|
<style>{`@keyframes breathe { 0%,100%{transform:scale(1)} 50%{transform:scale(1.08)} }`}</style>
|
||||||
@@ -466,7 +466,7 @@ export function AtlasChat({ projectId }: AtlasChatProps) {
|
|||||||
style={{
|
style={{
|
||||||
position: "absolute", top: 12, right: 16,
|
position: "absolute", top: 12, right: 16,
|
||||||
background: "none", border: "none", cursor: "pointer",
|
background: "none", border: "none", cursor: "pointer",
|
||||||
fontSize: "0.68rem", color: "#d0ccc4", fontFamily: "Outfit, sans-serif",
|
fontSize: "0.68rem", color: "#d0ccc4", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
padding: "3px 7px", borderRadius: 4, transition: "color 0.12s",
|
padding: "3px 7px", borderRadius: 4, transition: "color 0.12s",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => (e.currentTarget.style.color = "#8a8478")}
|
onMouseEnter={e => (e.currentTarget.style.color = "#8a8478")}
|
||||||
@@ -504,7 +504,7 @@ export function AtlasChat({ projectId }: AtlasChatProps) {
|
|||||||
padding: "5px 12px", borderRadius: 20,
|
padding: "5px 12px", borderRadius: 20,
|
||||||
border: "1px solid #e0dcd4",
|
border: "1px solid #e0dcd4",
|
||||||
background: "#fff", color: "#6b6560",
|
background: "#fff", color: "#6b6560",
|
||||||
fontSize: "0.73rem", fontFamily: "Outfit, sans-serif",
|
fontSize: "0.73rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: "pointer", transition: "all 0.1s",
|
cursor: "pointer", transition: "all 0.1s",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
}}
|
}}
|
||||||
@@ -541,7 +541,7 @@ export function AtlasChat({ projectId }: AtlasChatProps) {
|
|||||||
disabled={isStreaming}
|
disabled={isStreaming}
|
||||||
style={{
|
style={{
|
||||||
flex: 1, border: "none", background: "none",
|
flex: 1, border: "none", background: "none",
|
||||||
fontSize: "0.86rem", fontFamily: "Outfit, sans-serif",
|
fontSize: "0.86rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
color: "#1a1a1a", padding: "8px 0",
|
color: "#1a1a1a", padding: "8px 0",
|
||||||
resize: "none", outline: "none",
|
resize: "none", outline: "none",
|
||||||
minHeight: 24, maxHeight: 120,
|
minHeight: 24, maxHeight: 120,
|
||||||
@@ -553,7 +553,7 @@ export function AtlasChat({ projectId }: AtlasChatProps) {
|
|||||||
style={{
|
style={{
|
||||||
padding: "9px 16px", borderRadius: 7, border: "none",
|
padding: "9px 16px", borderRadius: 7, border: "none",
|
||||||
background: "#eae6de", color: "#8a8478",
|
background: "#eae6de", color: "#8a8478",
|
||||||
fontSize: "0.78rem", fontWeight: 600, fontFamily: "Outfit, sans-serif",
|
fontSize: "0.78rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: "pointer", flexShrink: 0,
|
cursor: "pointer", flexShrink: 0,
|
||||||
display: "flex", alignItems: "center", gap: 6,
|
display: "flex", alignItems: "center", gap: 6,
|
||||||
}}
|
}}
|
||||||
@@ -569,7 +569,7 @@ export function AtlasChat({ projectId }: AtlasChatProps) {
|
|||||||
padding: "9px 16px", borderRadius: 7, border: "none",
|
padding: "9px 16px", borderRadius: 7, border: "none",
|
||||||
background: input.trim() ? "#1a1a1a" : "#eae6de",
|
background: input.trim() ? "#1a1a1a" : "#eae6de",
|
||||||
color: input.trim() ? "#fff" : "#b5b0a6",
|
color: input.trim() ? "#fff" : "#b5b0a6",
|
||||||
fontSize: "0.78rem", fontWeight: 600, fontFamily: "Outfit, sans-serif",
|
fontSize: "0.78rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: input.trim() ? "pointer" : "default",
|
cursor: input.trim() ? "pointer" : "default",
|
||||||
flexShrink: 0, transition: "all 0.15s",
|
flexShrink: 0, transition: "all 0.15s",
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -162,7 +162,7 @@ export function CooChat({ projectId }: { projectId: string }) {
|
|||||||
margin: "8px 0 4px", opacity: 0.5,
|
margin: "8px 0 4px", opacity: 0.5,
|
||||||
}}>
|
}}>
|
||||||
<div style={{ flex: 1, height: 1, background: "#e8e4dc" }} />
|
<div style={{ flex: 1, height: 1, background: "#e8e4dc" }} />
|
||||||
<span style={{ fontSize: "0.58rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif", whiteSpace: "nowrap" }}>
|
<span style={{ fontSize: "0.58rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", whiteSpace: "nowrap" }}>
|
||||||
Discovery · COO
|
Discovery · COO
|
||||||
</span>
|
</span>
|
||||||
<div style={{ flex: 1, height: 1, background: "#e8e4dc" }} />
|
<div style={{ flex: 1, height: 1, background: "#e8e4dc" }} />
|
||||||
@@ -183,7 +183,7 @@ export function CooChat({ projectId }: { projectId: string }) {
|
|||||||
display: "flex", alignItems: "center", justifyContent: "center",
|
display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
fontSize: isAtlas ? "0.48rem" : "0.48rem",
|
fontSize: isAtlas ? "0.48rem" : "0.48rem",
|
||||||
color: "#fff", flexShrink: 0,
|
color: "#fff", flexShrink: 0,
|
||||||
fontFamily: isAtlas ? "Newsreader, serif" : "inherit",
|
fontFamily: isAtlas ? "var(--font-lora), ui-serif, serif" : "inherit",
|
||||||
fontWeight: isAtlas ? 700 : 400,
|
fontWeight: isAtlas ? 700 : 400,
|
||||||
}}>
|
}}>
|
||||||
{isAtlas ? "A" : "◈"}
|
{isAtlas ? "A" : "◈"}
|
||||||
@@ -197,7 +197,7 @@ export function CooChat({ projectId }: { projectId: string }) {
|
|||||||
borderRadius: isUser ? 10 : 0,
|
borderRadius: isUser ? 10 : 0,
|
||||||
fontSize: isAtlas ? "0.75rem" : "0.79rem",
|
fontSize: isAtlas ? "0.75rem" : "0.79rem",
|
||||||
color: isAtlas ? "#4a4540" : "#1a1a1a",
|
color: isAtlas ? "#4a4540" : "#1a1a1a",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
lineHeight: 1.6,
|
lineHeight: 1.6,
|
||||||
whiteSpace: "pre-wrap",
|
whiteSpace: "pre-wrap",
|
||||||
wordBreak: "break-word",
|
wordBreak: "break-word",
|
||||||
@@ -248,7 +248,7 @@ export function CooChat({ projectId }: { projectId: string }) {
|
|||||||
flex: 1, resize: "none",
|
flex: 1, resize: "none",
|
||||||
border: "1px solid #e8e4dc", borderRadius: 10,
|
border: "1px solid #e8e4dc", borderRadius: 10,
|
||||||
padding: "8px 10px", fontSize: "0.79rem",
|
padding: "8px 10px", fontSize: "0.79rem",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
color: "#1a1a1a", outline: "none",
|
color: "#1a1a1a", outline: "none",
|
||||||
background: "#faf8f5", lineHeight: 1.5,
|
background: "#faf8f5", lineHeight: 1.5,
|
||||||
}}
|
}}
|
||||||
@@ -267,7 +267,7 @@ export function CooChat({ projectId }: { projectId: string }) {
|
|||||||
}}
|
}}
|
||||||
>↑</button>
|
>↑</button>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.6rem", color: "#c5c0b8", marginTop: 5, fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.6rem", color: "#c5c0b8", marginTop: 5, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
↵ send · Shift+↵ newline
|
↵ send · Shift+↵ newline
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -59,15 +59,15 @@ function ProjectShellInner({
|
|||||||
<div style={{
|
<div style={{
|
||||||
display: "flex", flexDirection: "column",
|
display: "flex", flexDirection: "column",
|
||||||
height: "100dvh", overflow: "hidden",
|
height: "100dvh", overflow: "hidden",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
background: "#f6f4f0",
|
background: "var(--background)",
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
{/* ── Top bar ── */}
|
{/* ── Top bar ── */}
|
||||||
<header style={{
|
<header style={{
|
||||||
height: 48, flexShrink: 0,
|
height: 48, flexShrink: 0,
|
||||||
display: "flex", alignItems: "stretch",
|
display: "flex", alignItems: "stretch",
|
||||||
background: "#fff", borderBottom: "1px solid #e8e4dc",
|
background: "var(--card)", borderBottom: "1px solid var(--border)",
|
||||||
zIndex: 10,
|
zIndex: 10,
|
||||||
}}>
|
}}>
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@ function ProjectShellInner({
|
|||||||
<div style={{
|
<div style={{
|
||||||
display: "flex", alignItems: "center",
|
display: "flex", alignItems: "center",
|
||||||
padding: "0 16px", gap: 9, flexShrink: 0,
|
padding: "0 16px", gap: 9, flexShrink: 0,
|
||||||
borderRight: "1px solid #e8e4dc",
|
borderRight: "1px solid var(--border)",
|
||||||
}}>
|
}}>
|
||||||
<Link
|
<Link
|
||||||
href={`/${workspace}/projects`}
|
href={`/${workspace}/projects`}
|
||||||
@@ -86,7 +86,7 @@ function ProjectShellInner({
|
|||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<span style={{
|
<span style={{
|
||||||
fontSize: "0.82rem", fontWeight: 600, color: "#1a1a1a",
|
fontSize: "0.82rem", fontWeight: 600, color: "var(--foreground)",
|
||||||
maxWidth: 160, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
|
maxWidth: 160, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
|
||||||
}}>
|
}}>
|
||||||
{projectName}
|
{projectName}
|
||||||
@@ -105,13 +105,13 @@ function ProjectShellInner({
|
|||||||
padding: "5px 12px", borderRadius: 8,
|
padding: "5px 12px", borderRadius: 8,
|
||||||
fontSize: "0.8rem",
|
fontSize: "0.8rem",
|
||||||
fontWeight: isActive ? 600 : 440,
|
fontWeight: isActive ? 600 : 440,
|
||||||
color: isActive ? "#1a1a1a" : "#8a8478",
|
color: isActive ? "var(--foreground)" : "var(--muted-foreground)",
|
||||||
background: isActive ? "#f0ece4" : "transparent",
|
background: isActive ? "var(--secondary)" : "transparent",
|
||||||
textDecoration: "none",
|
textDecoration: "none",
|
||||||
transition: "background 0.1s, color 0.1s",
|
transition: "background 0.1s, color 0.1s",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "#f6f4f0"; }}
|
onMouseEnter={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "var(--muted)"; }}
|
||||||
onMouseLeave={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "transparent"; }}
|
onMouseLeave={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "transparent"; }}
|
||||||
>
|
>
|
||||||
{s.label}
|
{s.label}
|
||||||
@@ -128,9 +128,9 @@ function ProjectShellInner({
|
|||||||
title={`${session?.user?.name ?? session?.user?.email ?? "Account"} — Sign out`}
|
title={`${session?.user?.name ?? session?.user?.email ?? "Account"} — Sign out`}
|
||||||
style={{
|
style={{
|
||||||
width: 28, height: 28, borderRadius: "50%",
|
width: 28, height: 28, borderRadius: "50%",
|
||||||
background: "#f0ece4", border: "none", cursor: "pointer",
|
background: "var(--secondary)", border: "none", cursor: "pointer",
|
||||||
display: "flex", alignItems: "center", justifyContent: "center",
|
display: "flex", alignItems: "center", justifyContent: "center",
|
||||||
fontSize: "0.65rem", fontWeight: 700, color: "#6b6560", flexShrink: 0,
|
fontSize: "0.65rem", fontWeight: 700, color: "var(--muted-foreground)", flexShrink: 0,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{userInitial}
|
{userInitial}
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export function VIBNSidebar({ workspace, tabs, activeTab }: VIBNSidebarProps) {
|
|||||||
width: w, height: "100vh",
|
width: w, height: "100vh",
|
||||||
background: "#fff", borderRight: "1px solid #e8e4dc",
|
background: "#fff", borderRight: "1px solid #e8e4dc",
|
||||||
display: "flex", flexDirection: "column",
|
display: "flex", flexDirection: "column",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
flexShrink: 0, overflow: "hidden",
|
flexShrink: 0, overflow: "hidden",
|
||||||
transition, position: "relative",
|
transition, position: "relative",
|
||||||
}}>
|
}}>
|
||||||
@@ -136,7 +136,7 @@ export function VIBNSidebar({ workspace, tabs, activeTab }: VIBNSidebarProps) {
|
|||||||
<div style={{ width: 26, height: 26, borderRadius: 7, overflow: "hidden", flexShrink: 0 }}>
|
<div style={{ width: 26, height: 26, borderRadius: 7, overflow: "hidden", flexShrink: 0 }}>
|
||||||
<img src="/vibn-black-circle-logo.png" alt="VIBN" style={{ width: "100%", height: "100%", objectFit: "cover" }} />
|
<img src="/vibn-black-circle-logo.png" alt="VIBN" style={{ width: "100%", height: "100%", objectFit: "cover" }} />
|
||||||
</div>
|
</div>
|
||||||
<span style={{ fontSize: "0.92rem", fontWeight: 600, color: "#1a1a1a", letterSpacing: "-0.03em", fontFamily: "Newsreader, serif", whiteSpace: "nowrap" }}>
|
<span style={{ fontSize: "0.92rem", fontWeight: 600, color: "#1a1a1a", letterSpacing: "-0.03em", fontFamily: "var(--font-lora), ui-serif, serif", whiteSpace: "nowrap" }}>
|
||||||
vibn
|
vibn
|
||||||
</span>
|
</span>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -334,7 +334,7 @@ export function VIBNSidebar({ workspace, tabs, activeTab }: VIBNSidebarProps) {
|
|||||||
<button onClick={() => signOut({ callbackUrl: "/auth" })} style={{
|
<button onClick={() => signOut({ callbackUrl: "/auth" })} style={{
|
||||||
background: "none", border: "none", padding: 0,
|
background: "none", border: "none", padding: 0,
|
||||||
fontSize: "0.62rem", color: "#a09a90", cursor: "pointer",
|
fontSize: "0.62rem", color: "#a09a90", cursor: "pointer",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
}}>
|
}}>
|
||||||
Sign out
|
Sign out
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export function ChatImportSetup({ workspace, onClose, onBack }: SetupProps) {
|
|||||||
width: "100%", padding: "12px 14px", marginBottom: 20,
|
width: "100%", padding: "12px 14px", marginBottom: 20,
|
||||||
borderRadius: 8, border: "1px solid #e0dcd4",
|
borderRadius: 8, border: "1px solid #e0dcd4",
|
||||||
background: "#faf8f5", fontSize: "0.85rem", lineHeight: 1.55,
|
background: "#faf8f5", fontSize: "0.85rem", lineHeight: 1.55,
|
||||||
fontFamily: "Outfit, sans-serif", color: "#1a1a1a",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a",
|
||||||
outline: "none", resize: "vertical", boxSizing: "border-box",
|
outline: "none", resize: "vertical", boxSizing: "border-box",
|
||||||
}}
|
}}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export function CodeImportSetup({ workspace, onClose, onBack }: SetupProps) {
|
|||||||
width: "100%", padding: "11px 14px", marginBottom: 20,
|
width: "100%", padding: "11px 14px", marginBottom: 20,
|
||||||
borderRadius: 8, border: "1px solid #e0dcd4",
|
borderRadius: 8, border: "1px solid #e0dcd4",
|
||||||
background: "#faf8f5", fontSize: "0.9rem",
|
background: "#faf8f5", fontSize: "0.9rem",
|
||||||
fontFamily: "Outfit, sans-serif", color: "#1a1a1a",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a",
|
||||||
outline: "none", boxSizing: "border-box",
|
outline: "none", boxSizing: "border-box",
|
||||||
}}
|
}}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export function CreateProjectFlow({ open, onOpenChange, workspace }: CreateProje
|
|||||||
boxShadow: "0 12px 48px rgba(26,26,26,0.16)",
|
boxShadow: "0 12px 48px rgba(26,26,26,0.16)",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
maxWidth: 520,
|
maxWidth: 520,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
pointerEvents: "all",
|
pointerEvents: "all",
|
||||||
animation: "vibn-slideUp 0.18s cubic-bezier(0.4,0,0.2,1)",
|
animation: "vibn-slideUp 0.18s cubic-bezier(0.4,0,0.2,1)",
|
||||||
transition: "max-width 0.2s ease",
|
transition: "max-width 0.2s ease",
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ export function FreshIdeaSetup({ workspace, onClose }: SetupProps) {
|
|||||||
return (
|
return (
|
||||||
<div style={{ padding: "32px 36px 36px" }}>
|
<div style={{ padding: "32px 36px 36px" }}>
|
||||||
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 28 }}>
|
<div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", marginBottom: 28 }}>
|
||||||
<div style={{ fontSize: "1.15rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "Newsreader, serif" }}>
|
<div style={{ fontSize: "1.15rem", fontWeight: 600, color: "#1a1a1a", fontFamily: "var(--font-lora), ui-serif, serif" }}>
|
||||||
New project
|
New project
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
|
|||||||
@@ -114,7 +114,7 @@ export function MigrateSetup({ workspace, onClose, onBack }: SetupProps) {
|
|||||||
width: "100%", padding: "11px 14px", marginBottom: 16,
|
width: "100%", padding: "11px 14px", marginBottom: 16,
|
||||||
borderRadius: 8, border: "1px solid #e0dcd4",
|
borderRadius: 8, border: "1px solid #e0dcd4",
|
||||||
background: "#faf8f5", fontSize: "0.88rem",
|
background: "#faf8f5", fontSize: "0.88rem",
|
||||||
fontFamily: "Outfit, sans-serif", color: hosting ? "#1a1a1a" : "#a09a90",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: hosting ? "#1a1a1a" : "#a09a90",
|
||||||
outline: "none", boxSizing: "border-box", appearance: "none",
|
outline: "none", boxSizing: "border-box", appearance: "none",
|
||||||
backgroundImage: `url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23a09a90' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round'/%3E%3C/svg%3E")`,
|
backgroundImage: `url("data:image/svg+xml,%3Csvg width='10' height='6' viewBox='0 0 10 6' fill='none' xmlns='http://www.w3.org/2000/svg'%3E%3Cpath d='M1 1l4 4 4-4' stroke='%23a09a90' strokeWidth='1.5' strokeLinecap='round' strokeLinejoin='round'/%3E%3C/svg%3E")`,
|
||||||
backgroundRepeat: "no-repeat", backgroundPosition: "right 12px center",
|
backgroundRepeat: "no-repeat", backgroundPosition: "right 12px center",
|
||||||
@@ -138,7 +138,7 @@ export function MigrateSetup({ workspace, onClose, onBack }: SetupProps) {
|
|||||||
width: "100%", padding: "11px 14px", marginBottom: 16,
|
width: "100%", padding: "11px 14px", marginBottom: 16,
|
||||||
borderRadius: 8, border: "1px solid #e0dcd4",
|
borderRadius: 8, border: "1px solid #e0dcd4",
|
||||||
background: "#faf8f5", fontSize: "0.9rem",
|
background: "#faf8f5", fontSize: "0.9rem",
|
||||||
fontFamily: "Outfit, sans-serif", color: "#1a1a1a",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a",
|
||||||
outline: "none", boxSizing: "border-box",
|
outline: "none", boxSizing: "border-box",
|
||||||
}}
|
}}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ export function TypeSelector({ onSelect, onClose }: TypeSelectorProps) {
|
|||||||
<div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 28 }}>
|
<div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", marginBottom: 28 }}>
|
||||||
<div>
|
<div>
|
||||||
<h2 style={{
|
<h2 style={{
|
||||||
fontFamily: "Newsreader, serif", fontSize: "1.4rem", fontWeight: 400,
|
fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.4rem", fontWeight: 400,
|
||||||
color: "#1a1a1a", margin: 0, marginBottom: 4,
|
color: "#1a1a1a", margin: 0, marginBottom: 4,
|
||||||
}}>
|
}}>
|
||||||
Start a new project
|
Start a new project
|
||||||
@@ -97,7 +97,7 @@ export function TypeSelector({ onSelect, onClose }: TypeSelectorProps) {
|
|||||||
background: "#faf8f5",
|
background: "#faf8f5",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
transition: "all 0.14s",
|
transition: "all 0.14s",
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ export function SetupHeader({
|
|||||||
</button>
|
</button>
|
||||||
<div>
|
<div>
|
||||||
<h2 style={{
|
<h2 style={{
|
||||||
fontFamily: "Newsreader, serif", fontSize: "1.3rem", fontWeight: 400,
|
fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.3rem", fontWeight: 400,
|
||||||
color: "#1a1a1a", margin: 0, marginBottom: 3,
|
color: "#1a1a1a", margin: 0, marginBottom: 3,
|
||||||
}}>
|
}}>
|
||||||
{label}
|
{label}
|
||||||
@@ -94,7 +94,7 @@ export function TextInput({
|
|||||||
width: "100%", padding: "11px 14px", marginBottom: 16,
|
width: "100%", padding: "11px 14px", marginBottom: 16,
|
||||||
borderRadius: 8, border: "1px solid #e0dcd4",
|
borderRadius: 8, border: "1px solid #e0dcd4",
|
||||||
background: "#faf8f5", fontSize: "0.9rem",
|
background: "#faf8f5", fontSize: "0.9rem",
|
||||||
fontFamily: "Outfit, sans-serif", color: "#1a1a1a",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a",
|
||||||
outline: "none", boxSizing: "border-box",
|
outline: "none", boxSizing: "border-box",
|
||||||
};
|
};
|
||||||
return (
|
return (
|
||||||
@@ -135,7 +135,7 @@ export function PrimaryButton({
|
|||||||
background: active ? "#1a1a1a" : "#e0dcd4",
|
background: active ? "#1a1a1a" : "#e0dcd4",
|
||||||
color: active ? "#fff" : "#b5b0a6",
|
color: active ? "#fff" : "#b5b0a6",
|
||||||
fontSize: "0.88rem", fontWeight: 600,
|
fontSize: "0.88rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: active ? "pointer" : "not-allowed",
|
cursor: active ? "pointer" : "not-allowed",
|
||||||
display: "flex", alignItems: "center", justifyContent: "center", gap: 8,
|
display: "flex", alignItems: "center", justifyContent: "center", gap: 8,
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ function EditableList({
|
|||||||
{label}
|
{label}
|
||||||
</div>
|
</div>
|
||||||
{items.length === 0 && (
|
{items.length === 0 && (
|
||||||
<p style={{ fontSize: "0.75rem", color: "#b5b0a6", fontFamily: "Outfit, sans-serif", margin: "0 0 6px" }}>
|
<p style={{ fontSize: "0.75rem", color: "#b5b0a6", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", margin: "0 0 6px" }}>
|
||||||
Nothing captured.
|
Nothing captured.
|
||||||
</p>
|
</p>
|
||||||
)}
|
)}
|
||||||
@@ -62,7 +62,7 @@ function EditableList({
|
|||||||
style={{
|
style={{
|
||||||
flex: 1, padding: "7px 10px", borderRadius: 6,
|
flex: 1, padding: "7px 10px", borderRadius: 6,
|
||||||
border: "1px solid #e0dcd4", background: "#faf8f5",
|
border: "1px solid #e0dcd4", background: "#faf8f5",
|
||||||
fontSize: "0.81rem", fontFamily: "Outfit, sans-serif",
|
fontSize: "0.81rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
color: "#1a1a1a", outline: "none",
|
color: "#1a1a1a", outline: "none",
|
||||||
}}
|
}}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
@@ -83,7 +83,7 @@ function EditableList({
|
|||||||
style={{
|
style={{
|
||||||
background: "none", border: "1px dashed #e0dcd4", cursor: "pointer",
|
background: "none", border: "1px dashed #e0dcd4", cursor: "pointer",
|
||||||
borderRadius: 6, padding: "5px 10px", fontSize: "0.72rem", color: "#a09a90",
|
borderRadius: 6, padding: "5px 10px", fontSize: "0.72rem", color: "#a09a90",
|
||||||
fontFamily: "Outfit, sans-serif", width: "100%",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", width: "100%",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => (e.currentTarget.style.borderColor = "#b5b0a6")}
|
onMouseEnter={e => (e.currentTarget.style.borderColor = "#b5b0a6")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.borderColor = "#e0dcd4")}
|
onMouseLeave={e => (e.currentTarget.style.borderColor = "#e0dcd4")}
|
||||||
@@ -147,9 +147,9 @@ export function ChatImportMain({
|
|||||||
if (stage === "intake") {
|
if (stage === "intake") {
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
||||||
<div style={{ width: "100%", maxWidth: 640, fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ width: "100%", maxWidth: 640, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ marginBottom: 28 }}>
|
<div style={{ marginBottom: 28 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||||
Paste your chat history
|
Paste your chat history
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
||||||
@@ -172,7 +172,7 @@ export function ChatImportMain({
|
|||||||
width: "100%", padding: "14px 16px", marginBottom: 16,
|
width: "100%", padding: "14px 16px", marginBottom: 16,
|
||||||
borderRadius: 10, border: "1px solid #e0dcd4",
|
borderRadius: 10, border: "1px solid #e0dcd4",
|
||||||
background: "#faf8f5", fontSize: "0.85rem", lineHeight: 1.6,
|
background: "#faf8f5", fontSize: "0.85rem", lineHeight: 1.6,
|
||||||
fontFamily: "Outfit, sans-serif", color: "#1a1a1a",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a",
|
||||||
outline: "none", resize: "vertical", boxSizing: "border-box",
|
outline: "none", resize: "vertical", boxSizing: "border-box",
|
||||||
}}
|
}}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
@@ -192,7 +192,7 @@ export function ChatImportMain({
|
|||||||
background: chatText.trim().length > 20 ? "#1a1a1a" : "#e0dcd4",
|
background: chatText.trim().length > 20 ? "#1a1a1a" : "#e0dcd4",
|
||||||
color: chatText.trim().length > 20 ? "#fff" : "#b5b0a6",
|
color: chatText.trim().length > 20 ? "#fff" : "#b5b0a6",
|
||||||
fontSize: "0.9rem", fontWeight: 600,
|
fontSize: "0.9rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: chatText.trim().length > 20 ? "pointer" : "not-allowed",
|
cursor: chatText.trim().length > 20 ? "pointer" : "not-allowed",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -206,7 +206,7 @@ export function ChatImportMain({
|
|||||||
// ── Stage: extracting ─────────────────────────────────────────────────────
|
// ── Stage: extracting ─────────────────────────────────────────────────────
|
||||||
if (stage === "extracting") {
|
if (stage === "extracting") {
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
width: 48, height: 48, borderRadius: "50%",
|
width: 48, height: 48, borderRadius: "50%",
|
||||||
@@ -228,10 +228,10 @@ export function ChatImportMain({
|
|||||||
|
|
||||||
// ── Stage: review ─────────────────────────────────────────────────────────
|
// ── Stage: review ─────────────────────────────────────────────────────────
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
||||||
<div style={{ marginBottom: 28 }}>
|
<div style={{ marginBottom: 28 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||||
What Atlas found
|
What Atlas found
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>
|
||||||
@@ -303,7 +303,7 @@ export function ChatImportMain({
|
|||||||
style={{
|
style={{
|
||||||
padding: "11px 22px", borderRadius: 8, border: "none",
|
padding: "11px 22px", borderRadius: 8, border: "none",
|
||||||
background: "#fff", color: "#1a1a1a",
|
background: "#fff", color: "#1a1a1a",
|
||||||
fontSize: "0.85rem", fontWeight: 700, fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontSize: "0.85rem", fontWeight: 700, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
||||||
@@ -315,7 +315,7 @@ export function ChatImportMain({
|
|||||||
style={{
|
style={{
|
||||||
padding: "11px 22px", borderRadius: 8,
|
padding: "11px 22px", borderRadius: 8,
|
||||||
border: "1px solid rgba(255,255,255,0.2)", background: "transparent", color: "#fff",
|
border: "1px solid rgba(255,255,255,0.2)", background: "transparent", color: "#fff",
|
||||||
fontSize: "0.85rem", fontWeight: 600, fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontSize: "0.85rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => (e.currentTarget.style.background = "rgba(255,255,255,0.08)")}
|
onMouseEnter={e => (e.currentTarget.style.background = "rgba(255,255,255,0.08)")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.background = "transparent")}
|
onMouseLeave={e => (e.currentTarget.style.background = "transparent")}
|
||||||
|
|||||||
@@ -135,9 +135,9 @@ export function CodeImportMain({
|
|||||||
const isValid = repoUrl.trim().startsWith("http");
|
const isValid = repoUrl.trim().startsWith("http");
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
||||||
<div style={{ width: "100%", maxWidth: 540, fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ width: "100%", maxWidth: 540, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ marginBottom: 28 }}>
|
<div style={{ marginBottom: 28 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||||
Import your repository
|
Import your repository
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
||||||
@@ -161,7 +161,7 @@ export function CodeImportMain({
|
|||||||
width: "100%", padding: "12px 14px", marginBottom: 16,
|
width: "100%", padding: "12px 14px", marginBottom: 16,
|
||||||
borderRadius: 8, border: "1px solid #e0dcd4",
|
borderRadius: 8, border: "1px solid #e0dcd4",
|
||||||
background: "#faf8f5", fontSize: "0.9rem",
|
background: "#faf8f5", fontSize: "0.9rem",
|
||||||
fontFamily: "Outfit, sans-serif", color: "#1a1a1a",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a",
|
||||||
outline: "none", boxSizing: "border-box",
|
outline: "none", boxSizing: "border-box",
|
||||||
}}
|
}}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
@@ -179,7 +179,7 @@ export function CodeImportMain({
|
|||||||
width: "100%", padding: "13px", borderRadius: 8, border: "none",
|
width: "100%", padding: "13px", borderRadius: 8, border: "none",
|
||||||
background: isValid ? "#1a1a1a" : "#e0dcd4",
|
background: isValid ? "#1a1a1a" : "#e0dcd4",
|
||||||
color: isValid ? "#fff" : "#b5b0a6",
|
color: isValid ? "#fff" : "#b5b0a6",
|
||||||
fontSize: "0.9rem", fontWeight: 600, fontFamily: "Outfit, sans-serif",
|
fontSize: "0.9rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: isValid ? "pointer" : "not-allowed",
|
cursor: isValid ? "pointer" : "not-allowed",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -194,7 +194,7 @@ export function CodeImportMain({
|
|||||||
if (stage === "cloning") {
|
if (stage === "cloning") {
|
||||||
const currentIdx = PROGRESS_STEPS.findIndex(s => s.key === progressStep);
|
const currentIdx = PROGRESS_STEPS.findIndex(s => s.key === progressStep);
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ textAlign: "center", maxWidth: 400 }}>
|
<div style={{ textAlign: "center", maxWidth: 400 }}>
|
||||||
<div style={{
|
<div style={{
|
||||||
width: 52, height: 52, borderRadius: "50%",
|
width: 52, height: 52, borderRadius: "50%",
|
||||||
@@ -250,10 +250,10 @@ export function CodeImportMain({
|
|||||||
];
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ maxWidth: 800, margin: "0 auto" }}>
|
<div style={{ maxWidth: 800, margin: "0 auto" }}>
|
||||||
<div style={{ marginBottom: 24 }}>
|
<div style={{ marginBottom: 24 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||||
Architecture map
|
Architecture map
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: "0 0 4px" }}>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: "0 0 4px" }}>
|
||||||
@@ -289,7 +289,7 @@ export function CodeImportMain({
|
|||||||
style={{
|
style={{
|
||||||
width: "100%", padding: "13px", borderRadius: 8, border: "none",
|
width: "100%", padding: "13px", borderRadius: 8, border: "none",
|
||||||
background: "#1a1a1a", color: "#fff",
|
background: "#1a1a1a", color: "#fff",
|
||||||
fontSize: "0.9rem", fontWeight: 600, fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontSize: "0.9rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
||||||
@@ -311,9 +311,9 @@ export function CodeImportMain({
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
||||||
<div style={{ width: "100%", maxWidth: 540, fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ width: "100%", maxWidth: 540, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ marginBottom: 28 }}>
|
<div style={{ marginBottom: 28 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||||
What should Atlas build?
|
What should Atlas build?
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
||||||
@@ -331,7 +331,7 @@ export function CodeImportMain({
|
|||||||
padding: "18px", borderRadius: 10, textAlign: "left",
|
padding: "18px", borderRadius: 10, textAlign: "left",
|
||||||
border: `2px solid ${selected ? "#1a1a1a" : "#e8e4dc"}`,
|
border: `2px solid ${selected ? "#1a1a1a" : "#e8e4dc"}`,
|
||||||
background: selected ? "#1a1a1a08" : "#fff",
|
background: selected ? "#1a1a1a08" : "#fff",
|
||||||
cursor: "pointer", fontFamily: "Outfit, sans-serif",
|
cursor: "pointer", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
transition: "all 0.12s",
|
transition: "all 0.12s",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => { if (!selected) e.currentTarget.style.borderColor = "#d0ccc4"; }}
|
onMouseEnter={e => { if (!selected) e.currentTarget.style.borderColor = "#d0ccc4"; }}
|
||||||
@@ -351,7 +351,7 @@ export function CodeImportMain({
|
|||||||
width: "100%", padding: "13px", borderRadius: 8, border: "none",
|
width: "100%", padding: "13px", borderRadius: 8, border: "none",
|
||||||
background: confirmedSurfaces.length > 0 ? "#1a1a1a" : "#e0dcd4",
|
background: confirmedSurfaces.length > 0 ? "#1a1a1a" : "#e0dcd4",
|
||||||
color: confirmedSurfaces.length > 0 ? "#fff" : "#b5b0a6",
|
color: confirmedSurfaces.length > 0 ? "#fff" : "#b5b0a6",
|
||||||
fontSize: "0.9rem", fontWeight: 600, fontFamily: "Outfit, sans-serif",
|
fontSize: "0.9rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif",
|
||||||
cursor: confirmedSurfaces.length > 0 ? "pointer" : "not-allowed",
|
cursor: confirmedSurfaces.length > 0 ? "pointer" : "not-allowed",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -103,7 +103,7 @@ export function FreshIdeaMain({ projectId, projectName }: FreshIdeaMainProps) {
|
|||||||
display: "flex", alignItems: "center", justifyContent: "space-between",
|
display: "flex", alignItems: "center", justifyContent: "space-between",
|
||||||
gap: 16, flexShrink: 0, borderBottom: "1px solid #333",
|
gap: 16, flexShrink: 0, borderBottom: "1px solid #333",
|
||||||
}}>
|
}}>
|
||||||
<div style={{ fontSize: "0.8rem", color: "#e8e4dc", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.8rem", color: "#e8e4dc", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
✦ PRD saved — you can keep refining here or view the full document.
|
✦ PRD saved — you can keep refining here or view the full document.
|
||||||
</div>
|
</div>
|
||||||
<Link
|
<Link
|
||||||
@@ -130,10 +130,10 @@ export function FreshIdeaMain({ projectId, projectName }: FreshIdeaMainProps) {
|
|||||||
borderBottom: "1px solid #333",
|
borderBottom: "1px solid #333",
|
||||||
}}>
|
}}>
|
||||||
<div>
|
<div>
|
||||||
<div style={{ fontSize: "0.84rem", fontWeight: 700, color: "#fff", fontFamily: "Outfit, sans-serif", marginBottom: 2 }}>
|
<div style={{ fontSize: "0.84rem", fontWeight: 700, color: "#fff", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", marginBottom: 2 }}>
|
||||||
✦ Discovery complete — what's next?
|
✦ Discovery complete — what's next?
|
||||||
</div>
|
</div>
|
||||||
<div style={{ fontSize: "0.72rem", color: "#a09a90", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ fontSize: "0.72rem", color: "#a09a90", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
All 6 phases captured. Generate your PRD or jump into Build.
|
All 6 phases captured. Generate your PRD or jump into Build.
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -145,7 +145,7 @@ export function FreshIdeaMain({ projectId, projectName }: FreshIdeaMainProps) {
|
|||||||
padding: "8px 16px", borderRadius: 7, border: "none",
|
padding: "8px 16px", borderRadius: 7, border: "none",
|
||||||
background: "#fff", color: "#1a1a1a",
|
background: "#fff", color: "#1a1a1a",
|
||||||
fontSize: "0.8rem", fontWeight: 700,
|
fontSize: "0.8rem", fontWeight: 700,
|
||||||
fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
transition: "opacity 0.12s",
|
transition: "opacity 0.12s",
|
||||||
}}
|
}}
|
||||||
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
||||||
@@ -160,7 +160,7 @@ export function FreshIdeaMain({ projectId, projectName }: FreshIdeaMainProps) {
|
|||||||
border: "1px solid rgba(255,255,255,0.2)",
|
border: "1px solid rgba(255,255,255,0.2)",
|
||||||
background: "transparent", color: "#fff",
|
background: "transparent", color: "#fff",
|
||||||
fontSize: "0.8rem", fontWeight: 600,
|
fontSize: "0.8rem", fontWeight: 600,
|
||||||
fontFamily: "Outfit, sans-serif", cursor: "pointer",
|
fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer",
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
Plan MVP →
|
Plan MVP →
|
||||||
|
|||||||
@@ -32,11 +32,11 @@ const HOSTING_OPTIONS = [
|
|||||||
function MarkdownRenderer({ md }: { md: string }) {
|
function MarkdownRenderer({ md }: { md: string }) {
|
||||||
const lines = md.split('\n');
|
const lines = md.split('\n');
|
||||||
return (
|
return (
|
||||||
<div style={{ fontFamily: "Outfit, sans-serif", fontSize: "0.85rem", color: "#1a1a1a", lineHeight: 1.7 }}>
|
<div style={{ fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", fontSize: "0.85rem", color: "#1a1a1a", lineHeight: 1.7 }}>
|
||||||
{lines.map((line, i) => {
|
{lines.map((line, i) => {
|
||||||
if (line.startsWith('## ')) return <h2 key={i} style={{ fontFamily: "Newsreader, serif", fontSize: "1.2rem", fontWeight: 500, margin: "24px 0 10px", color: "#1a1a1a" }}>{line.slice(3)}</h2>;
|
if (line.startsWith('## ')) return <h2 key={i} style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.2rem", fontWeight: 500, margin: "24px 0 10px", color: "#1a1a1a" }}>{line.slice(3)}</h2>;
|
||||||
if (line.startsWith('### ')) return <h3 key={i} style={{ fontSize: "0.88rem", fontWeight: 700, margin: "18px 0 6px", color: "#1a1a1a" }}>{line.slice(4)}</h3>;
|
if (line.startsWith('### ')) return <h3 key={i} style={{ fontSize: "0.88rem", fontWeight: 700, margin: "18px 0 6px", color: "#1a1a1a" }}>{line.slice(4)}</h3>;
|
||||||
if (line.startsWith('# ')) return <h1 key={i} style={{ fontFamily: "Newsreader, serif", fontSize: "1.5rem", fontWeight: 400, margin: "0 0 16px", color: "#1a1a1a" }}>{line.slice(2)}</h1>;
|
if (line.startsWith('# ')) return <h1 key={i} style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.5rem", fontWeight: 400, margin: "0 0 16px", color: "#1a1a1a" }}>{line.slice(2)}</h1>;
|
||||||
if (line.match(/^- \[ \] /)) return (
|
if (line.match(/^- \[ \] /)) return (
|
||||||
<div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 8, marginBottom: 5 }}>
|
<div key={i} style={{ display: "flex", alignItems: "flex-start", gap: 8, marginBottom: 5 }}>
|
||||||
<input type="checkbox" style={{ marginTop: 3, accentColor: "#1a1a1a" }} />
|
<input type="checkbox" style={{ marginTop: 3, accentColor: "#1a1a1a" }} />
|
||||||
@@ -157,9 +157,9 @@ export function MigrateMain({
|
|||||||
const canProceed = repoUrl.trim().startsWith("http") || liveUrl.trim().startsWith("http");
|
const canProceed = repoUrl.trim().startsWith("http") || liveUrl.trim().startsWith("http");
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
<div style={{ height: "100%", overflow: "auto", display: "flex", alignItems: "center", justifyContent: "center", padding: 32 }}>
|
||||||
<div style={{ width: "100%", maxWidth: 540, fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ width: "100%", maxWidth: 540, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ marginBottom: 28 }}>
|
<div style={{ marginBottom: 28 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>
|
||||||
Tell us about your product
|
Tell us about your product
|
||||||
</h2>
|
</h2>
|
||||||
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
<p style={{ fontSize: "0.82rem", color: "#a09a90", margin: 0 }}>
|
||||||
@@ -176,7 +176,7 @@ export function MigrateMain({
|
|||||||
</label>
|
</label>
|
||||||
<input type="text" value={repoUrl} onChange={e => setRepoUrl(e.target.value)}
|
<input type="text" value={repoUrl} onChange={e => setRepoUrl(e.target.value)}
|
||||||
placeholder="https://github.com/yourorg/your-repo"
|
placeholder="https://github.com/yourorg/your-repo"
|
||||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "Outfit, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
onBlur={e => (e.currentTarget.style.borderColor = "#e0dcd4")} autoFocus
|
onBlur={e => (e.currentTarget.style.borderColor = "#e0dcd4")} autoFocus
|
||||||
/>
|
/>
|
||||||
@@ -185,7 +185,7 @@ export function MigrateMain({
|
|||||||
</label>
|
</label>
|
||||||
<input type="text" value={liveUrl} onChange={e => setLiveUrl(e.target.value)}
|
<input type="text" value={liveUrl} onChange={e => setLiveUrl(e.target.value)}
|
||||||
placeholder="https://yourproduct.com"
|
placeholder="https://yourproduct.com"
|
||||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "Outfit, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
style={{ width: "100%", padding: "11px 14px", marginBottom: 16, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.9rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: "#1a1a1a", outline: "none", boxSizing: "border-box" }}
|
||||||
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
onFocus={e => (e.currentTarget.style.borderColor = "#1a1a1a")}
|
||||||
onBlur={e => (e.currentTarget.style.borderColor = "#e0dcd4")}
|
onBlur={e => (e.currentTarget.style.borderColor = "#e0dcd4")}
|
||||||
/>
|
/>
|
||||||
@@ -193,7 +193,7 @@ export function MigrateMain({
|
|||||||
Current hosting provider
|
Current hosting provider
|
||||||
</label>
|
</label>
|
||||||
<select value={hosting} onChange={e => setHosting(e.target.value)}
|
<select value={hosting} onChange={e => setHosting(e.target.value)}
|
||||||
style={{ width: "100%", padding: "11px 14px", marginBottom: 20, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.88rem", fontFamily: "Outfit, sans-serif", color: hosting ? "#1a1a1a" : "#a09a90", outline: "none", boxSizing: "border-box", appearance: "none" }}
|
style={{ width: "100%", padding: "11px 14px", marginBottom: 20, borderRadius: 8, border: "1px solid #e0dcd4", background: "#faf8f5", fontSize: "0.88rem", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", color: hosting ? "#1a1a1a" : "#a09a90", outline: "none", boxSizing: "border-box", appearance: "none" }}
|
||||||
>
|
>
|
||||||
{HOSTING_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
|
{HOSTING_OPTIONS.map(o => <option key={o.value} value={o.value}>{o.label}</option>)}
|
||||||
</select>
|
</select>
|
||||||
@@ -201,7 +201,7 @@ export function MigrateMain({
|
|||||||
<strong style={{ color: "#4a2a5a" }}>Non-destructive.</strong> Your existing product stays live throughout. Atlas duplicates, never deletes.
|
<strong style={{ color: "#4a2a5a" }}>Non-destructive.</strong> Your existing product stays live throughout. Atlas duplicates, never deletes.
|
||||||
</div>
|
</div>
|
||||||
<button onClick={startAudit} disabled={!canProceed}
|
<button onClick={startAudit} disabled={!canProceed}
|
||||||
style={{ width: "100%", padding: "13px", borderRadius: 8, border: "none", background: canProceed ? "#1a1a1a" : "#e0dcd4", color: canProceed ? "#fff" : "#b5b0a6", fontSize: "0.9rem", fontWeight: 600, fontFamily: "Outfit, sans-serif", cursor: canProceed ? "pointer" : "not-allowed" }}
|
style={{ width: "100%", padding: "13px", borderRadius: 8, border: "none", background: canProceed ? "#1a1a1a" : "#e0dcd4", color: canProceed ? "#fff" : "#b5b0a6", fontSize: "0.9rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: canProceed ? "pointer" : "not-allowed" }}
|
||||||
>
|
>
|
||||||
Start audit →
|
Start audit →
|
||||||
</button>
|
</button>
|
||||||
@@ -220,7 +220,7 @@ export function MigrateMain({
|
|||||||
];
|
];
|
||||||
const currentIdx = steps.findIndex(s => s.key === progressStep);
|
const currentIdx = steps.findIndex(s => s.key === progressStep);
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ textAlign: "center", maxWidth: 400 }}>
|
<div style={{ textAlign: "center", maxWidth: 400 }}>
|
||||||
<div style={{ width: 52, height: 52, borderRadius: "50%", border: "3px solid #e0dcd4", borderTopColor: "#4a2a5a", animation: "vibn-mig-spin 0.85s linear infinite", margin: "0 auto 24px" }} />
|
<div style={{ width: 52, height: 52, borderRadius: "50%", border: "3px solid #e0dcd4", borderTopColor: "#4a2a5a", animation: "vibn-mig-spin 0.85s linear infinite", margin: "0 auto 24px" }} />
|
||||||
<style>{`@keyframes vibn-mig-spin { to { transform:rotate(360deg); } }`}</style>
|
<style>{`@keyframes vibn-mig-spin { to { transform:rotate(360deg); } }`}</style>
|
||||||
@@ -250,10 +250,10 @@ export function MigrateMain({
|
|||||||
const rows = (analysisResult?.rows as Array<{ category: string; item: string; status: string; detail?: string }>) ?? [];
|
const rows = (analysisResult?.rows as Array<{ category: string; item: string; status: string; detail?: string }>) ?? [];
|
||||||
const summary = (analysisResult?.summary as string) ?? '';
|
const summary = (analysisResult?.summary as string) ?? '';
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", overflow: "auto", padding: "32px 40px", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
||||||
<div style={{ marginBottom: 24 }}>
|
<div style={{ marginBottom: 24 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Audit complete</h2>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Audit complete</h2>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>{summary || `${projectName} — review your current infrastructure below.`}</p>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>{summary || `${projectName} — review your current infrastructure below.`}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -286,7 +286,7 @@ export function MigrateMain({
|
|||||||
<div style={{ fontSize: "0.75rem", color: "#8a8478" }}>Atlas will generate a phased migration doc with Mirror, Validate, Cutover, and Decommission phases.</div>
|
<div style={{ fontSize: "0.75rem", color: "#8a8478" }}>Atlas will generate a phased migration doc with Mirror, Validate, Cutover, and Decommission phases.</div>
|
||||||
</div>
|
</div>
|
||||||
<button onClick={startPlanning}
|
<button onClick={startPlanning}
|
||||||
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#fff", color: "#1a1a1a", fontSize: "0.85rem", fontWeight: 700, fontFamily: "Outfit, sans-serif", cursor: "pointer", flexShrink: 0 }}
|
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#fff", color: "#1a1a1a", fontSize: "0.85rem", fontWeight: 700, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer", flexShrink: 0 }}
|
||||||
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
onMouseEnter={e => (e.currentTarget.style.opacity = "0.88")}
|
||||||
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
onMouseLeave={e => (e.currentTarget.style.opacity = "1")}
|
||||||
>
|
>
|
||||||
@@ -301,7 +301,7 @@ export function MigrateMain({
|
|||||||
// ── Stage: planning ───────────────────────────────────────────────────────
|
// ── Stage: planning ───────────────────────────────────────────────────────
|
||||||
if (stage === "planning") {
|
if (stage === "planning") {
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", display: "flex", alignItems: "center", justifyContent: "center", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
<div style={{ textAlign: "center" }}>
|
<div style={{ textAlign: "center" }}>
|
||||||
<div style={{ width: 52, height: 52, borderRadius: "50%", border: "3px solid #e0dcd4", borderTopColor: "#4a2a5a", animation: "vibn-mig-spin 0.85s linear infinite", margin: "0 auto 20px" }} />
|
<div style={{ width: 52, height: 52, borderRadius: "50%", border: "3px solid #e0dcd4", borderTopColor: "#4a2a5a", animation: "vibn-mig-spin 0.85s linear infinite", margin: "0 auto 20px" }} />
|
||||||
<h3 style={{ fontSize: "1.05rem", fontWeight: 600, color: "#1a1a1a", margin: "0 0 6px" }}>Generating migration plan…</h3>
|
<h3 style={{ fontSize: "1.05rem", fontWeight: 600, color: "#1a1a1a", margin: "0 0 6px" }}>Generating migration plan…</h3>
|
||||||
@@ -313,7 +313,7 @@ export function MigrateMain({
|
|||||||
|
|
||||||
// ── Stage: plan ───────────────────────────────────────────────────────────
|
// ── Stage: plan ───────────────────────────────────────────────────────────
|
||||||
return (
|
return (
|
||||||
<div style={{ height: "100%", overflow: "auto", fontFamily: "Outfit, sans-serif" }}>
|
<div style={{ height: "100%", overflow: "auto", fontFamily: "var(--font-inter), ui-sans-serif, sans-serif" }}>
|
||||||
{/* Non-destructive banner */}
|
{/* Non-destructive banner */}
|
||||||
<div style={{ background: "#4a2a5a12", borderBottom: "1px solid #4a2a5a30", padding: "12px 32px", display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
|
<div style={{ background: "#4a2a5a12", borderBottom: "1px solid #4a2a5a30", padding: "12px 32px", display: "flex", alignItems: "center", gap: 10, flexShrink: 0 }}>
|
||||||
<span style={{ fontSize: "1rem" }}>🛡️</span>
|
<span style={{ fontSize: "1rem" }}>🛡️</span>
|
||||||
@@ -326,7 +326,7 @@ export function MigrateMain({
|
|||||||
<div style={{ padding: "32px 40px" }}>
|
<div style={{ padding: "32px 40px" }}>
|
||||||
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
<div style={{ maxWidth: 760, margin: "0 auto" }}>
|
||||||
<div style={{ marginBottom: 28 }}>
|
<div style={{ marginBottom: 28 }}>
|
||||||
<h2 style={{ fontFamily: "Newsreader, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Migration Plan</h2>
|
<h2 style={{ fontFamily: "var(--font-lora), ui-serif, serif", fontSize: "1.7rem", fontWeight: 400, color: "#1a1a1a", margin: 0, marginBottom: 6 }}>Migration Plan</h2>
|
||||||
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>{projectName} — four phased migration with rollback plan</p>
|
<p style={{ fontSize: "0.8rem", color: "#a09a90", margin: 0 }}>{projectName} — four phased migration with rollback plan</p>
|
||||||
</div>
|
</div>
|
||||||
<div style={{ background: "#fff", borderRadius: 12, border: "1px solid #e8e4dc", padding: "28px 32px" }}>
|
<div style={{ background: "#fff", borderRadius: 12, border: "1px solid #e8e4dc", padding: "28px 32px" }}>
|
||||||
@@ -335,13 +335,13 @@ export function MigrateMain({
|
|||||||
<div style={{ marginTop: 20, display: "flex", gap: 10 }}>
|
<div style={{ marginTop: 20, display: "flex", gap: 10 }}>
|
||||||
<button
|
<button
|
||||||
onClick={() => router.push(`/${workspace}/project/${projectId}/design`)}
|
onClick={() => router.push(`/${workspace}/project/${projectId}/design`)}
|
||||||
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#1a1a1a", color: "#fff", fontSize: "0.85rem", fontWeight: 600, fontFamily: "Outfit, sans-serif", cursor: "pointer" }}
|
style={{ padding: "11px 22px", borderRadius: 8, border: "none", background: "#1a1a1a", color: "#fff", fontSize: "0.85rem", fontWeight: 600, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer" }}
|
||||||
>
|
>
|
||||||
Go to Design →
|
Go to Design →
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
onClick={() => window.print()}
|
onClick={() => window.print()}
|
||||||
style={{ padding: "11px 22px", borderRadius: 8, border: "1px solid #e0dcd4", background: "#fff", color: "#6b6560", fontSize: "0.85rem", fontWeight: 500, fontFamily: "Outfit, sans-serif", cursor: "pointer" }}
|
style={{ padding: "11px 22px", borderRadius: 8, border: "1px solid #e0dcd4", background: "#fff", color: "#6b6560", fontSize: "0.85rem", fontWeight: 500, fontFamily: "var(--font-inter), ui-sans-serif, sans-serif", cursor: "pointer" }}
|
||||||
>
|
>
|
||||||
Print / Export
|
Print / Export
|
||||||
</button>
|
</button>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export function Hero() {
|
|||||||
<div className="flex flex-col items-center gap-6 pb-16 pt-16 md:py-24 lg:py-32">
|
<div className="flex flex-col items-center gap-6 pb-16 pt-16 md:py-24 lg:py-32">
|
||||||
<div className="flex max-w-[980px] flex-col items-center gap-6 text-center">
|
<div className="flex max-w-[980px] flex-col items-center gap-6 text-center">
|
||||||
{/* Main title */}
|
{/* Main title */}
|
||||||
<h1 className="text-3xl font-extrabold leading-tight tracking-tighter md:text-5xl lg:text-6xl lg:leading-[1.1]">
|
<h1 className="font-serif text-3xl font-bold leading-tight tracking-tight md:text-5xl md:font-semibold lg:text-6xl lg:leading-[1.1]">
|
||||||
{homepage.hero.title}
|
{homepage.hero.title}
|
||||||
</h1>
|
</h1>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user