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
@@ -0,0 +1,109 @@
"use client";
import { useRouter } from "next/navigation";
import { useSdk } from "@lynkd/messaging-inbox-sdk";
import { useUi } from "@/lib/ui-state";
import { Avatar, Chip } from "@/components/ui/primitives";
import { X, MessageSquare, Phone, Clock, Mail, AtSign, Smile, Pencil } from "lucide-react";
export function ProfileDrawer() {
const { profileUserId, closeProfile, startHuddle, toast, openModal } = useUi();
const { userById, me, channels, client, refresh } = useSdk();
const router = useRouter();
if (!profileUserId) return null;
const user = userById(profileUserId);
if (!user) return null;
const isMe = user.id === me?.id;
async function openDm() {
if (!user) return;
const existing = channels.find((c) => c.kind === "dm" && c.memberIds.includes(user.id));
closeProfile();
if (existing) { router.push(`/c/${existing.id}`); return; }
const { channel } = await client.createChannel({ name: user.name, kind: "dm", memberIds: [user.id] });
refresh();
router.push(`/c/${channel.id}`);
}
async function huddle() {
if (!user) return;
const existing = channels.find((c) => c.kind === "dm" && c.memberIds.includes(user.id));
closeProfile();
if (existing) startHuddle(existing.id);
else toast(`Starting a huddle with ${user.name}`, "success");
}
return (
<div className="fixed inset-0 z-40 flex justify-end bg-black/40 animate-fade-in" onClick={closeProfile}>
<div role="dialog" aria-modal="true" aria-label="Profile" className="flex h-full w-[min(380px,100vw)] flex-col border-l border-border bg-surface shadow-pop" onClick={(e) => e.stopPropagation()}>
<div className="flex items-center justify-between border-b border-border px-4 py-3">
<span className="text-[15px] font-bold">Profile</span>
<button onClick={closeProfile} className="text-muted hover:text-ink"><X size={18} /></button>
</div>
<div className="min-h-0 flex-1 overflow-y-auto p-5">
<div className="flex flex-col items-center text-center">
<Avatar user={user} size={96} showPresence={false} rounded="24px" />
<h2 className="mt-3 text-[20px] font-black">{user.name}</h2>
<div className="text-[13px] text-muted">{user.title}</div>
{user.statusText && <div className="mt-2 rounded-pill bg-hover px-3 py-1 text-[12.5px]">{user.statusEmoji} {user.statusText}</div>}
<div className="mt-2"><Chip tone={user.presence === "active" ? "success" : user.presence === "dnd" ? "danger" : "neutral"}>{user.presence}</Chip></div>
</div>
{!isMe && (
<div className="mt-5 grid grid-cols-2 gap-2">
<button onClick={openDm} className="focus-ring flex items-center justify-center gap-2 rounded-control bg-accent px-3 py-2 text-[13px] font-semibold text-accent-fg"><MessageSquare size={15} /> Message</button>
<button onClick={huddle} className="focus-ring flex items-center justify-center gap-2 rounded-control border border-border bg-panel px-3 py-2 text-[13px] font-semibold hover:bg-hover"><Phone size={15} /> Huddle</button>
</div>
)}
{isMe && (
<>
<div className="mt-5">
<div className="mb-1.5 text-[11px] font-bold uppercase tracking-wide text-dim">Availability</div>
<div className="grid grid-cols-3 gap-2">
{([
{ p: "active", label: "Active", dot: "bg-success" },
{ p: "away", label: "Away", dot: "bg-warning" },
{ p: "dnd", label: "Do not disturb", dot: "bg-danger" },
] as const).map((o) => (
<button
key={o.p}
onClick={async () => { await client.updateMe({ presence: o.p }); refresh(); }}
className={`focus-ring flex items-center justify-center gap-1.5 rounded-control border px-2 py-2 text-[12px] font-semibold ${user.presence === o.p ? "border-accent bg-accent-soft text-accent" : "border-border hover:bg-hover"}`}
>
<span className={`h-2 w-2 rounded-full ${o.dot}`} /> {o.label}
</button>
))}
</div>
</div>
<div className="mt-3 grid grid-cols-2 gap-2">
<button onClick={() => { closeProfile(); openModal("set-status"); }} className="focus-ring flex items-center justify-center gap-2 rounded-control border border-border bg-panel px-3 py-2 text-[13px] font-semibold hover:bg-hover">
<Smile size={15} /> {user.statusText ? "Status" : "Set status"}
</button>
<button onClick={() => { closeProfile(); openModal("edit-profile"); }} className="focus-ring flex items-center justify-center gap-2 rounded-control border border-border bg-panel px-3 py-2 text-[13px] font-semibold hover:bg-hover">
<Pencil size={15} /> Edit profile
</button>
</div>
</>
)}
<div className="mt-6 space-y-3 text-[13px]">
<Field icon={AtSign} label="Handle" value={`@${user.handle}`} />
{user.email && <Field icon={Mail} label="Email" value={user.email} />}
{user.timezone && <Field icon={Clock} label="Local time" value={`${user.localTime ?? ""} · ${user.timezone}`} />}
{user.pronouns && <Field icon={AtSign} label="Pronouns" value={user.pronouns} />}
</div>
</div>
</div>
</div>
);
}
function Field({ icon: Icon, label, value }: { icon: typeof Mail; label: string; value: string }) {
return (
<div className="flex items-center gap-3 rounded-control border border-border bg-panel px-3 py-2.5">
<Icon size={16} className="text-muted" />
<div><div className="text-[11px] uppercase tracking-wide text-dim">{label}</div><div className="text-ink">{value}</div></div>
</div>
);
}