refactor: strip sidebar down to project name + status only

Removed all product layer sections (Build, Layouts, Infrastructure,
Growth, Monetize, Support, Analytics) from the left sidebar — these
are now handled by the in-page left nav inside each tab.

Sidebar now shows: logo, Projects/Activity/Settings global nav,
project name + colored status dot when inside a project, and the
user avatar/sign out at the bottom. Nothing else.

Cleaned up all dead code: SectionHeading, SectionRow, SectionDivider,
SURFACE_LABELS, SURFACE_ICONS, AppEntry interface, apps state,
apps fetch, surfaces/infraApps variables.

Made-with: Cursor
This commit is contained in:
2026-03-06 17:36:31 -08:00
parent 3cd477c295
commit 93a2b4a0ac

View File

@@ -14,104 +14,8 @@ interface ProjectData {
productName?: string; productName?: string;
name?: string; name?: string;
status?: string; status?: string;
giteaRepo?: string;
giteaRepoUrl?: string;
surfaces?: string[];
surfaceThemes?: Record<string, string>;
apps?: Array<{ name: string; path: string; coolifyServiceUuid?: string | null; domain?: string | null }>;
} }
interface AppEntry {
name: string;
path: string;
}
// ── Section helpers ─────────────────────────────────────────────────────────
function SectionHeading({ label, collapsed }: { label: string; collapsed: boolean }) {
if (collapsed) return null;
return (
<div style={{
fontSize: "0.58rem", fontWeight: 700, color: "#b5b0a6",
letterSpacing: "0.1em", textTransform: "uppercase",
padding: "14px 12px 5px",
}}>
{label}
</div>
);
}
function SectionRow({
icon, label, href, dim, collapsed,
}: {
icon: string;
label: string;
href?: string;
dim?: boolean;
collapsed: boolean;
}) {
const style: React.CSSProperties = {
display: "flex", alignItems: "center",
justifyContent: collapsed ? "center" : "flex-start",
gap: 8, padding: collapsed ? "7px 0" : "5px 12px",
borderRadius: 5, textDecoration: "none",
color: dim ? "#c5c0b8" : "#4a4640",
fontSize: "0.78rem", fontWeight: 450,
transition: "background 0.1s",
width: "100%", boxSizing: "border-box" as const,
};
const inner = (
<>
<span style={{ fontSize: "0.72rem", opacity: 0.6, flexShrink: 0, width: collapsed ? "auto" : 14, textAlign: "center" }}>
{icon}
</span>
{!collapsed && (
<span style={{
overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap",
fontStyle: dim ? "italic" : "normal",
}}>
{label}
</span>
)}
</>
);
if (href) {
return (
<Link href={href} title={collapsed ? label : undefined} style={style}
onMouseEnter={e => { if (!dim) (e.currentTarget as HTMLElement).style.background = "#f6f4f0"; }}
onMouseLeave={e => { (e.currentTarget as HTMLElement).style.background = "transparent"; }}
>
{inner}
</Link>
);
}
return (
<div title={collapsed ? label : undefined} style={{ ...style, cursor: "default" }}>
{inner}
</div>
);
}
function SectionDivider() {
return <div style={{ height: 1, background: "#eae6de", margin: "8px 12px" }} />;
}
// ── Surface label map ────────────────────────────────────────────────────────
const SURFACE_LABELS: Record<string, string> = {
"marketing": "Marketing site",
"web-app": "Web app",
"admin": "Admin panel",
"api": "API layer",
};
const SURFACE_ICONS: Record<string, string> = {
"marketing": "◎",
"web-app": "⬡",
"admin": "◫",
"api": "⌁",
};
// ── Main sidebar ───────────────────────────────────────────────────────────── // ── Main sidebar ─────────────────────────────────────────────────────────────
@@ -128,13 +32,11 @@ export function VIBNSidebar({ workspace }: VIBNSidebarProps) {
// Project-specific data // Project-specific data
const [project, setProject] = useState<ProjectData | null>(null); const [project, setProject] = useState<ProjectData | null>(null);
const [apps, setApps] = useState<AppEntry[]>([]);
// Global projects list (used when NOT inside a project) // Global projects list (used when NOT inside a project)
const [projects, setProjects] = useState<Array<{ id: string; productName: string; status?: string }>>([]); const [projects, setProjects] = useState<Array<{ id: string; productName: string; status?: string }>>([]);
const activeProjectId = pathname?.match(/\/project\/([^/]+)/)?.[1] ?? null; const activeProjectId = pathname?.match(/\/project\/([^/]+)/)?.[1] ?? null;
const activeTab = pathname?.match(/\/project\/[^/]+\/([^/]+)/)?.[1] ?? null;
// Restore collapse state // Restore collapse state
useEffect(() => { useEffect(() => {
@@ -161,17 +63,12 @@ export function VIBNSidebar({ workspace }: VIBNSidebarProps) {
// Fetch project-specific data when inside a project // Fetch project-specific data when inside a project
useEffect(() => { useEffect(() => {
if (!activeProjectId) { setProject(null); setApps([]); return; } if (!activeProjectId) { setProject(null); return; }
fetch(`/api/projects/${activeProjectId}`) fetch(`/api/projects/${activeProjectId}`)
.then(r => r.json()) .then(r => r.json())
.then(d => setProject(d.project ?? null)) .then(d => setProject(d.project ?? null))
.catch(() => {}); .catch(() => {});
fetch(`/api/projects/${activeProjectId}/apps`)
.then(r => r.json())
.then(d => setApps(d.apps ?? []))
.catch(() => {});
}, [activeProjectId]); }, [activeProjectId]);
const isProjects = !activeProjectId && (pathname?.includes("/projects") || pathname?.includes("/project")); const isProjects = !activeProjectId && (pathname?.includes("/projects") || pathname?.includes("/project"));
@@ -193,11 +90,6 @@ export function VIBNSidebar({ workspace }: VIBNSidebarProps) {
const base = `/${workspace}/project/${activeProjectId}`; const base = `/${workspace}/project/${activeProjectId}`;
// Surfaces locked in on design page
const surfaces = project?.surfaces ?? [];
// Coolify/monorepo apps
const infraApps = project?.apps ?? [];
return ( return (
<nav style={{ <nav style={{
width: w, height: "100vh", width: w, height: "100vh",
@@ -287,135 +179,36 @@ export function VIBNSidebar({ workspace }: VIBNSidebarProps) {
<div style={{ flex: 1, overflow: "auto", paddingBottom: 8 }}> <div style={{ flex: 1, overflow: "auto", paddingBottom: 8 }}>
{activeProjectId && project ? ( {activeProjectId && project ? (
/* ── PROJECT VIEW: 7 product layer sections ── */ /* ── PROJECT VIEW: name + status only ── */
<> <>
{/* Project name */}
{!collapsed && ( {!collapsed && (
<div style={{ padding: "4px 12px 10px" }}> <div style={{ padding: "6px 12px 8px" }}>
<div style={{ fontSize: "0.82rem", fontWeight: 700, color: "#1a1a1a", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}> <div style={{ fontSize: "0.82rem", fontWeight: 700, color: "#1a1a1a", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{project.productName || project.name || "Project"} {project.productName || project.name || "Project"}
</div> </div>
<div style={{ display: "flex", alignItems: "center", gap: 5, marginTop: 3 }}> <div style={{ display: "flex", alignItems: "center", gap: 5, marginTop: 3 }}>
<span style={{ <span style={{
width: 6, height: 6, borderRadius: "50%", flexShrink: 0, width: 6, height: 6, borderRadius: "50%", flexShrink: 0, display: "inline-block",
background: project.status === "live" ? "#2e7d32" background: project.status === "live" ? "#2e7d32"
: project.status === "building" ? "#3d5afe" : project.status === "building" ? "#3d5afe"
: "#d4a04a", : "#d4a04a",
display: "inline-block",
}} /> }} />
<span style={{ fontSize: "0.68rem", color: "#8a8478" }}> <span style={{ fontSize: "0.68rem", color: "#8a8478" }}>
{project.status === "live" ? "Live" {project.status === "live" ? "Live" : project.status === "building" ? "Building" : "Defining"}
: project.status === "building" ? "Building"
: "Defining"}
</span> </span>
</div> </div>
</div> </div>
)} )}
{collapsed && (
{/* ── Build ── */} <div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}>
<SectionHeading label="Build" collapsed={collapsed} /> <span style={{
{apps.length > 0 ? ( width: 7, height: 7, borderRadius: "50%", display: "inline-block",
apps.map(app => ( background: project.status === "live" ? "#2e7d32"
<SectionRow : project.status === "building" ? "#3d5afe"
key={app.name} : "#d4a04a",
icon="▢" }} title={project.productName || project.name} />
label={app.name} </div>
href={`${base}/build?app=${encodeURIComponent(app.name)}&root=${encodeURIComponent(app.path)}`}
collapsed={collapsed}
/>
))
) : (
<SectionRow icon="▢" label="No apps yet" dim href={`${base}/build`} collapsed={collapsed} />
)} )}
<SectionDivider />
{/* ── Layouts ── */}
<SectionHeading label="Layouts" collapsed={collapsed} />
{surfaces.length > 0 ? (
surfaces.map(s => (
<SectionRow
key={s}
icon={SURFACE_ICONS[s] ?? "◌"}
label={SURFACE_LABELS[s] ?? s}
href={`${base}/design?surface=${encodeURIComponent(s)}`}
collapsed={collapsed}
/>
))
) : (
<SectionRow icon="◌" label="Not configured" dim href={`${base}/design`} collapsed={collapsed} />
)}
<SectionDivider />
{/* ── Infrastructure ── */}
<SectionHeading label="Infrastructure" collapsed={collapsed} />
<SectionRow
icon="⬡"
label="Builds"
href={`${base}/infrastructure?tab=builds`}
dim={infraApps.length === 0}
collapsed={collapsed}
/>
<SectionRow
icon="◫"
label="Databases"
href={`${base}/infrastructure?tab=databases`}
dim
collapsed={collapsed}
/>
<SectionRow
icon="◎"
label="Services"
href={`${base}/infrastructure?tab=services`}
dim
collapsed={collapsed}
/>
<SectionRow
icon="≡"
label="Environment"
href={`${base}/infrastructure?tab=environment`}
dim
collapsed={collapsed}
/>
<SectionRow
icon="◬"
label="Domains"
href={`${base}/infrastructure?tab=domains`}
dim={!infraApps.some(a => a.domain)}
collapsed={collapsed}
/>
<SectionRow
icon="≈"
label="Logs"
href={`${base}/infrastructure?tab=logs`}
dim={infraApps.length === 0}
collapsed={collapsed}
/>
<SectionDivider />
{/* ── Growth ── */}
<SectionHeading label="Growth" collapsed={collapsed} />
<SectionRow icon="↗" label="Not set up" dim href={`${base}/grow`} collapsed={collapsed} />
<SectionDivider />
{/* ── Monetize ── */}
<SectionHeading label="Monetize" collapsed={collapsed} />
<SectionRow icon="◉" label="Not set up" dim collapsed={collapsed} />
<SectionDivider />
{/* ── Support ── */}
<SectionHeading label="Support" collapsed={collapsed} />
<SectionRow icon="?" label="Not set up" dim collapsed={collapsed} />
<SectionDivider />
{/* ── Analytics ── */}
<SectionHeading label="Analytics" collapsed={collapsed} />
<SectionRow icon="∿" label="Not set up" dim href={`${base}/insights`} collapsed={collapsed} />
</> </>
) : ( ) : (
/* ── GLOBAL VIEW: projects list ── */ /* ── GLOBAL VIEW: projects list ── */