// ============================================================
// vibn-ai-templates/shells.jsx
// ------------------------------------------------------------
// Layout shells — both in-product navs (Sidebar / Rail /
// Topbar) and auth scaffolds (CenteredCard / SplitHero / Glass).
//
// These are containers. Wrap your page in any shell and the
// shell handles brand, search, nav, footer. Compose with the
// components from components.jsx.
// ============================================================
// ── SidebarShell ─────────────────────────────────────────────
// Props:
// brand: { name, mark? }
// sections: [{ title?, items: [{ id, label, icon, count, active }] }]
// user: { name, email, color? }
// children: main pane
const SidebarShell = ({ brand = { name: "Vibn" }, sections = [], user, search = "Search…", children, width = 248 }) => {
return (
);
};
// ── TopbarShell ──────────────────────────────────────────────
// Dark top with breadcrumb + ⌘K + avatar; tabs strip below.
const TopbarShell = ({ brand = { name: "Vibn" }, breadcrumb, tabs = [], activeTab,
onTabChange = () => {}, user, children, search = "Find or jump to anything…" }) => {
return (
);
};
// ── RailShell ────────────────────────────────────────────────
// Icon rail + secondary panel + content.
const RailShell = ({ brand, items = [], activeRail, onRailChange = () => {},
secondary, secondaryTitle, user, children }) => {
return (
{/* Rail */}
{brand?.mark || }
{items.map(it => {
const sel = (it.id || it.label) === activeRail;
return (
onRailChange(it.id || it.label)}
aria-label={it.label}
style={{
width: 40, height: 40, borderRadius: "var(--radius)",
background: sel ? "var(--accent)" : "transparent",
color: sel ? "var(--text-on-accent)" : "var(--text-2)",
border: "none", cursor: "pointer", position: "relative",
}}>
{typeof it.icon === "string" ? : it.icon}
{it.badge && {it.badge} }
);
})}
{user &&
}
{/* Secondary */}
{secondaryTitle && (
{secondaryTitle}
}
trailingIcon={
⌘K }
style={{ padding: "6px 10px" }}
/>
)}
{secondary}
{children}
);
};
// ── AuthCenteredShell ────────────────────────────────────────
// A single centered Card on a soft background, with brand top
// and small footer links. Good for sign-in / sign-up.
const AuthCenteredShell = ({ brand = { name: "Vibn" }, footerLinks = ["Privacy", "Terms", "Security"], cardWidth = 420, children }) => (
);
// ── AuthSplitShell ───────────────────────────────────────────
// Left storytelling panel, right form. Big SaaS / Vercel feel.
const AuthSplitShell = ({ brand = { name: "Vibn" }, hero = {}, children }) => (
{/* Decorative wash, picks up theme accent */}
{brand.mark || }
{brand.name}
{hero.badge && (
{hero.badge}
)}
{hero.headline &&
{hero.headline} }
{hero.sub &&
{hero.sub}
}
{hero.quote && (
"{hero.quote.body}"
{hero.quote.author}
{hero.quote.role}
)}
Need help? support
Privacy Terms Security v4.2.1
);
// ── AuthGlassShell ───────────────────────────────────────────
// Aurora background + frosted card. Marketing-leaning.
const AuthGlassShell = ({ brand = { name: "Vibn" }, eyebrow, cardWidth = 460, children }) => (
{/* Top bar (a thin frosted pill — works in any theme thanks to surface vars) */}
{eyebrow && {eyebrow} }
{children}
);
// ─── Exports ─────────────────────────────────────────────────
Object.assign(window, {
SidebarShell, TopbarShell, RailShell,
AuthCenteredShell, AuthSplitShell, AuthGlassShell,
});