added features and fixes
This commit is contained in:
@@ -8,6 +8,7 @@ import { MemberContextMenu } from "./MemberContextMenu.tsx";
|
||||
import { useConversationStore } from "../stores/conversation.ts";
|
||||
import { useLayoutStore } from "../stores/layout.ts";
|
||||
import { useNavigate } from "react-router-dom";
|
||||
import { UserProfileModal } from "./UserProfileModal.tsx";
|
||||
|
||||
function statusIcon(status: UserStatus): string {
|
||||
switch (status) {
|
||||
@@ -48,7 +49,12 @@ function usernameColor(status: UserStatus): string {
|
||||
}
|
||||
}
|
||||
|
||||
function MemberRow({ member }: { member: Member }) {
|
||||
interface MemberRowProps {
|
||||
member: Member;
|
||||
onProfileClick: (userId: string) => void;
|
||||
}
|
||||
|
||||
function MemberRow({ member, onProfileClick }: MemberRowProps) {
|
||||
const presence = usePresenceStore((s) => s.presences[member.id]);
|
||||
const status = presence?.status ?? member.status;
|
||||
const [menuOpen, setMenuOpen] = useState(false);
|
||||
@@ -67,16 +73,27 @@ function MemberRow({ member }: { member: Member }) {
|
||||
|
||||
return (
|
||||
<div className="relative">
|
||||
<button
|
||||
onClick={() => setMenuOpen((v) => !v)}
|
||||
className="w-full flex items-center gap-2 px-2 py-1 text-left hover:bg-gb-bg-t"
|
||||
<div
|
||||
onClick={() => onProfileClick(member.id)}
|
||||
className="w-full flex items-center gap-2 px-2 py-1 text-left hover:bg-gb-bg-t cursor-pointer group"
|
||||
>
|
||||
<span className={statusColor(status)}>{statusIcon(status)}</span>
|
||||
<span className={`truncate ${usernameColor(status)}`}>
|
||||
{member.display_name || member.username}
|
||||
<span className={`truncate ${usernameColor(status)} flex-1`}>
|
||||
{member.nickname || member.display_name || member.username}
|
||||
</span>
|
||||
<span className="ml-auto text-gb-fg-f text-xs">[...]</span>
|
||||
</button>
|
||||
{!isSelf && (
|
||||
<button
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
setMenuOpen((v) => !v);
|
||||
}}
|
||||
className="text-gb-fg-f hover:text-gb-orange font-mono text-xs px-1 hover:bg-gb-bg-s rounded shrink-0 opacity-0 group-hover:opacity-100 transition-opacity"
|
||||
title="Member options"
|
||||
>
|
||||
[...]
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
{menuOpen && !isSelf && activeServerId && (
|
||||
<MemberContextMenu
|
||||
memberId={member.id}
|
||||
@@ -128,6 +145,8 @@ export function MemberList() {
|
||||
const fetchMembers = useMemberStore((s) => s.fetchMembers);
|
||||
const presences = usePresenceStore((s) => s.presences);
|
||||
|
||||
const [profileUserId, setProfileUserId] = useState<string | null>(null);
|
||||
|
||||
const members = activeServerId
|
||||
? membersByServer[activeServerId] || []
|
||||
: [];
|
||||
@@ -164,7 +183,7 @@ export function MemberList() {
|
||||
<div className="text-gb-fg-t text-xs uppercase mb-1">ONLINE</div>
|
||||
<div className="text-gb-fg-f text-xs mb-1">---</div>
|
||||
{online.map((m) => (
|
||||
<MemberRow key={m.id} member={m} />
|
||||
<MemberRow key={m.id} member={m} onProfileClick={setProfileUserId} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
@@ -173,11 +192,14 @@ export function MemberList() {
|
||||
<div className="text-gb-fg-t text-xs uppercase mb-1">OFFLINE</div>
|
||||
<div className="text-gb-fg-f text-xs mb-1">---</div>
|
||||
{offline.map((m) => (
|
||||
<MemberRow key={m.id} member={m} />
|
||||
<MemberRow key={m.id} member={m} onProfileClick={setProfileUserId} />
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
{profileUserId && (
|
||||
<UserProfileModal userId={profileUserId} onClose={() => setProfileUserId(null)} />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user