repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
Projectflow
stars
latest
clone command
git clone gitlawb://did:key:z6Mkfh4Y...QBEi/projectflowgit clone gitlawb://did:key:z6Mkfh4Y.../projectflowb3cded1async from playground23h ago| #1 | import { motion } from "framer-motion"; |
| #2 | import { Users, Shield, Crown, User } from "lucide-react"; |
| #3 | import clsx from "clsx"; |
| #4 | import { useStore } from "../store"; |
| #5 | import { Avatar } from "./ui"; |
| #6 | import type { UserRole } from "../types"; |
| #7 | |
| #8 | export function MembersView() { |
| #9 | const { currentWorkspace, users } = useStore(); |
| #10 | |
| #11 | const members = currentWorkspace?.members || []; |
| #12 | |
| #13 | const roleIcons: Record<UserRole, React.ReactNode> = { |
| #14 | owner: <Crown size={12} className="text-amber-400" />, |
| #15 | admin: <Shield size={12} className="text-accent" />, |
| #16 | member: <User size={12} className="text-zinc-500" />, |
| #17 | }; |
| #18 | |
| #19 | const roleLabels: Record<UserRole, string> = { |
| #20 | owner: "Owner", |
| #21 | admin: "Admin", |
| #22 | member: "Member", |
| #23 | }; |
| #24 | |
| #25 | return ( |
| #26 | <div className="p-6 max-w-3xl mx-auto"> |
| #27 | <div className="page-header"> |
| #28 | <h1 className="page-title">Members</h1> |
| #29 | <span className="text-sm text-zinc-500"> |
| #30 | {members.length} members |
| #31 | </span> |
| #32 | </div> |
| #33 | |
| #34 | <div className="card divide-y divide-border"> |
| #35 | {members.map((member) => { |
| #36 | const user = users.find((u) => u.id === member.userId); |
| #37 | if (!user) return null; |
| #38 | |
| #39 | return ( |
| #40 | <motion.div |
| #41 | key={member.userId} |
| #42 | initial={{ opacity: 0 }} |
| #43 | animate={{ opacity: 1 }} |
| #44 | className="flex items-center justify-between py-4 px-1" |
| #45 | > |
| #46 | <div className="flex items-center gap-3"> |
| #47 | <Avatar name={user.name} size="md" /> |
| #48 | <div> |
| #49 | <p className="text-sm font-medium text-zinc-200"> |
| #50 | {user.name} |
| #51 | </p> |
| #52 | <p className="text-2xs text-zinc-500">{user.email}</p> |
| #53 | </div> |
| #54 | </div> |
| #55 | <div className="flex items-center gap-2"> |
| #56 | <span |
| #57 | className={clsx( |
| #58 | "badge flex items-center gap-1.5", |
| #59 | member.role === "owner" |
| #60 | ? "bg-amber-500/10 text-amber-400" |
| #61 | : member.role === "admin" |
| #62 | ? "bg-accent/10 text-accent" |
| #63 | : "bg-zinc-500/10 text-zinc-400" |
| #64 | )} |
| #65 | > |
| #66 | {roleIcons[member.role]} |
| #67 | {roleLabels[member.role]} |
| #68 | </span> |
| #69 | </div> |
| #70 | </motion.div> |
| #71 | ); |
| #72 | })} |
| #73 | </div> |
| #74 | </div> |
| #75 | ); |
| #76 | } |
| #77 |