first commit

This commit is contained in:
2026-07-17 21:48:37 +05:30
commit f85599dac5
124 changed files with 10775 additions and 0 deletions
+92
View File
@@ -0,0 +1,92 @@
"use client";
import { useState } from "react";
import { usePathname, useRouter } from "next/navigation";
import { useSdk, useFeatureFlags } from "@lynkd/messaging-inbox-sdk";
import { useUi } from "@/lib/ui-state";
import { IconButton } from "@/components/ui/primitives";
import { Home, MessageSquare, Inbox as InboxIcon, Bell, LifeBuoy, MoreHorizontal, Plus } from "lucide-react";
import clsx from "clsx";
/** Slack-style far-left rail: workspace switcher + primary destinations. */
export function WorkspaceRail() {
const { bootstrap, brandName } = useSdk();
const flags = useFeatureFlags();
const router = useRouter();
const pathname = usePathname();
const { setNotifOpen, openModal, toast } = useUi();
const workspaces = bootstrap?.workspaces ?? [];
const [activeWs, setActiveWs] = useState<string | undefined>(bootstrap?.workspace?.id);
const nav = [
{ icon: Home, label: "Home", href: "/", match: (p: string) => p === "/" || p.startsWith("/c/") },
flags.messaging && { icon: MessageSquare, label: "DMs", href: "/dms", match: (p: string) => p.startsWith("/dms") },
flags.inbox && { icon: InboxIcon, label: "Inbox", href: "/inbox", match: (p: string) => p.startsWith("/inbox") },
flags.support && { icon: LifeBuoy, label: "Support", href: "/support", match: (p: string) => p.startsWith("/support") },
].filter(Boolean) as { icon: typeof Home; label: string; href: string; match: (p: string) => boolean }[];
const active = activeWs ?? bootstrap?.workspace?.id;
return (
<nav className="hidden w-[68px] shrink-0 flex-col items-center gap-1 border-r border-border bg-bg py-3 md:flex">
{flags.workspaceSwitcher && (
<div className="flex flex-col items-center gap-2 pb-2">
{workspaces.map((w) => (
<button
key={w.id}
title={w.name}
onClick={() => {
setActiveWs(w.id);
if (w.id !== bootstrap?.workspace?.id) toast(`Switched to ${w.name} (demo)`, "success");
}}
className={clsx(
"focus-ring grid h-11 w-11 place-items-center rounded-[14px] text-sm font-bold transition-all",
w.id === active ? "text-white ring-2 ring-accent" : "text-ink/80 hover:rounded-[12px]",
)}
style={{ background: w.id === active ? "var(--brand-gradient)" : "var(--c-elevated)" }}
>
{w.initials}
</button>
))}
<IconButton label="Add workspace" onClick={() => openModal("create-workspace")}>
<Plus size={18} />
</IconButton>
<div className="my-1 h-px w-8 bg-border" />
</div>
)}
<div className="flex min-h-0 flex-1 flex-col items-center gap-1 overflow-y-auto no-scrollbar">
{nav.map((n) => {
const isActive = n.match(pathname);
return (
<button
key={n.href}
title={n.label}
onClick={() => router.push(n.href)}
className={clsx(
"focus-ring flex h-12 w-12 flex-col items-center justify-center gap-0.5 rounded-control text-[10px] font-medium transition-colors",
isActive ? "bg-accent-soft text-accent" : "text-muted hover:bg-hover hover:text-ink",
)}
>
<n.icon size={20} />
<span>{n.label}</span>
</button>
);
})}
</div>
<div className="flex flex-col items-center gap-1">
{flags.notifications && (
<IconButton label="Notifications" onClick={() => setNotifOpen(true)}>
<Bell size={20} />
</IconButton>
)}
<IconButton label="Help & more" onClick={() => toast("Help center — coming soon", "default")}>
<MoreHorizontal size={20} />
</IconButton>
</div>
<span className="sr-only">{brandName}</span>
</nav>
);
}