move project tabs to sidebar, remove top tab bar

Made-with: Cursor
This commit is contained in:
2026-03-08 13:00:54 -07:00
parent fc59333383
commit 231aeb4402
2 changed files with 82 additions and 65 deletions

View File

@@ -5,8 +5,16 @@ import Link from "next/link";
import { usePathname } from "next/navigation";
import { signOut, useSession } from "next-auth/react";
interface TabItem {
id: string;
label: string;
path: string;
}
interface VIBNSidebarProps {
workspace: string;
tabs?: TabItem[];
activeTab?: string;
}
interface ProjectData {
@@ -23,7 +31,7 @@ const COLLAPSED_KEY = "vibn_sidebar_collapsed";
const COLLAPSED_W = 52;
const EXPANDED_W = 216;
export function VIBNSidebar({ workspace }: VIBNSidebarProps) {
export function VIBNSidebar({ workspace, tabs, activeTab }: VIBNSidebarProps) {
const pathname = usePathname();
const { data: session } = useSession();
@@ -179,34 +187,85 @@ export function VIBNSidebar({ workspace }: VIBNSidebarProps) {
<div style={{ flex: 1, overflow: "auto", paddingBottom: 8 }}>
{activeProjectId && project ? (
/* ── PROJECT VIEW: name + status only ── */
/* ── PROJECT VIEW: name + status + section tabs ── */
<>
{!collapsed && (
<div style={{ padding: "6px 12px 8px" }}>
<div style={{ fontSize: "0.82rem", fontWeight: 700, color: "#1a1a1a", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{project.productName || project.name || "Project"}
<>
<div style={{ padding: "6px 12px 8px" }}>
<div style={{ fontSize: "0.82rem", fontWeight: 700, color: "#1a1a1a", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{project.productName || project.name || "Project"}
</div>
<div style={{ display: "flex", alignItems: "center", gap: 5, marginTop: 3 }}>
<span style={{
width: 6, height: 6, borderRadius: "50%", flexShrink: 0, display: "inline-block",
background: project.status === "live" ? "#2e7d32"
: project.status === "building" ? "#3d5afe"
: "#d4a04a",
}} />
<span style={{ fontSize: "0.68rem", color: "#8a8478" }}>
{project.status === "live" ? "Live" : project.status === "building" ? "Building" : "Defining"}
</span>
</div>
</div>
<div style={{ display: "flex", alignItems: "center", gap: 5, marginTop: 3 }}>
<span style={{
width: 6, height: 6, borderRadius: "50%", flexShrink: 0, display: "inline-block",
background: project.status === "live" ? "#2e7d32"
: project.status === "building" ? "#3d5afe"
: "#d4a04a",
}} />
<span style={{ fontSize: "0.68rem", color: "#8a8478" }}>
{project.status === "live" ? "Live" : project.status === "building" ? "Building" : "Defining"}
</span>
</div>
</div>
{tabs && tabs.length > 0 && (
<div style={{ padding: "2px 8px" }}>
{tabs.map(t => {
const isActive = activeTab === t.id;
return (
<Link
key={t.id}
href={`/${workspace}/project/${activeProjectId}/${t.path}`}
style={{
width: "100%", display: "flex", alignItems: "center",
padding: "7px 10px", borderRadius: 6,
background: isActive ? "#f6f4f0" : "transparent",
color: isActive ? "#1a1a1a" : "#6b6560",
fontSize: "0.8rem", fontWeight: isActive ? 600 : 500,
transition: "background 0.12s", textDecoration: "none",
}}
onMouseEnter={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "#f6f4f0"; }}
onMouseLeave={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "transparent"; }}
>
{t.label}
</Link>
);
})}
</div>
)}
</>
)}
{collapsed && (
<div style={{ display: "flex", justifyContent: "center", paddingTop: 8 }}>
<div style={{ display: "flex", flexDirection: "column", alignItems: "center", paddingTop: 8, gap: 6 }}>
<span style={{
width: 7, height: 7, borderRadius: "50%", display: "inline-block",
background: project.status === "live" ? "#2e7d32"
: project.status === "building" ? "#3d5afe"
: "#d4a04a",
}} title={project.productName || project.name} />
{tabs && tabs.map(t => {
const isActive = activeTab === t.id;
return (
<Link
key={t.id}
href={`/${workspace}/project/${activeProjectId}/${t.path}`}
title={t.label}
style={{
width: 28, height: 28, borderRadius: 6, display: "flex",
alignItems: "center", justifyContent: "center",
background: isActive ? "#f6f4f0" : "transparent",
color: isActive ? "#1a1a1a" : "#a09a90",
fontSize: "0.6rem", fontWeight: 700, textDecoration: "none",
textTransform: "uppercase", letterSpacing: "0.02em",
transition: "background 0.12s",
}}
onMouseEnter={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "#f6f4f0"; }}
onMouseLeave={e => { if (!isActive) (e.currentTarget as HTMLElement).style.background = "transparent"; }}
>
{t.label.slice(0, 2)}
</Link>
);
})}
</div>
)}
</>