|
|
|
|
@@ -79,15 +79,39 @@
|
|
|
|
|
: [],
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const filteredRooms = $derived(
|
|
|
|
|
// All non-space rooms (exclude Space entries themselves from the list)
|
|
|
|
|
const allRooms = $derived(
|
|
|
|
|
$roomSummaries.filter((r) => !r.isSpace),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Org rooms: rooms that belong to any Space
|
|
|
|
|
const orgRooms = $derived(
|
|
|
|
|
allRooms.filter((r) => r.parentSpaceId && !r.isDirect),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// DMs: direct messages (not tied to org)
|
|
|
|
|
const dmRooms = $derived(
|
|
|
|
|
allRooms.filter((r) => r.isDirect),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Other rooms: not in a space and not a DM
|
|
|
|
|
const otherRooms = $derived(
|
|
|
|
|
allRooms.filter((r) => !r.parentSpaceId && !r.isDirect),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
// Apply search filter across all sections
|
|
|
|
|
const filterBySearch = (rooms: typeof allRooms) =>
|
|
|
|
|
roomSearchQuery.trim()
|
|
|
|
|
? $roomSummaries.filter(
|
|
|
|
|
? rooms.filter(
|
|
|
|
|
(room) =>
|
|
|
|
|
room.name.toLowerCase().includes(roomSearchQuery.toLowerCase()) ||
|
|
|
|
|
room.topic?.toLowerCase().includes(roomSearchQuery.toLowerCase()),
|
|
|
|
|
)
|
|
|
|
|
: $roomSummaries,
|
|
|
|
|
);
|
|
|
|
|
: rooms;
|
|
|
|
|
|
|
|
|
|
const filteredOrgRooms = $derived(filterBySearch(orgRooms));
|
|
|
|
|
const filteredDmRooms = $derived(filterBySearch(dmRooms));
|
|
|
|
|
const filteredOtherRooms = $derived(filterBySearch(otherRooms));
|
|
|
|
|
|
|
|
|
|
const currentMembers = $derived(
|
|
|
|
|
$selectedRoomId ? getRoomMembers($selectedRoomId) : [],
|
|
|
|
|
@@ -438,50 +462,132 @@
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Room actions -->
|
|
|
|
|
<div class="flex items-center justify-between px-3 py-1">
|
|
|
|
|
<span class="text-xs font-semibold text-light/40 uppercase tracking-wider">
|
|
|
|
|
Rooms {roomSearchQuery ? `(${filteredRooms.length})` : ""}
|
|
|
|
|
</span>
|
|
|
|
|
<div class="flex gap-1">
|
|
|
|
|
<button
|
|
|
|
|
class="w-6 h-6 flex items-center justify-center text-light/40 hover:text-light hover:bg-light/10 rounded transition-colors"
|
|
|
|
|
onclick={() => (showCreateRoomModal = true)}
|
|
|
|
|
title="Create room"
|
|
|
|
|
>
|
|
|
|
|
<span class="material-symbols-rounded" style="font-size: 16px;">add_circle</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<!-- Room list -->
|
|
|
|
|
<!-- Room list (sectioned) -->
|
|
|
|
|
<nav class="flex-1 overflow-y-auto px-2 pb-2">
|
|
|
|
|
{#if filteredRooms.length === 0}
|
|
|
|
|
{#if allRooms.length === 0}
|
|
|
|
|
<p class="text-light/40 text-sm text-center py-8">
|
|
|
|
|
{roomSearchQuery ? "No matching rooms" : "No rooms yet"}
|
|
|
|
|
</p>
|
|
|
|
|
{:else}
|
|
|
|
|
<ul class="flex flex-col gap-1">
|
|
|
|
|
{#each filteredRooms as room (room.roomId)}
|
|
|
|
|
<li>
|
|
|
|
|
<!-- Org / Space Rooms -->
|
|
|
|
|
{#if filteredOrgRooms.length > 0}
|
|
|
|
|
<div class="mb-2">
|
|
|
|
|
<div class="flex items-center justify-between px-2 py-1">
|
|
|
|
|
<span class="text-xs font-semibold text-light/40 uppercase tracking-wider">
|
|
|
|
|
<span class="material-symbols-rounded align-middle" style="font-size: 14px;">workspaces</span>
|
|
|
|
|
Organization
|
|
|
|
|
</span>
|
|
|
|
|
<button
|
|
|
|
|
class="w-full flex items-center gap-2 pl-1 pr-2 py-1 rounded-[50px] transition-colors text-left
|
|
|
|
|
{$selectedRoomId === room.roomId ? 'bg-primary/20' : 'hover:bg-light/5'}"
|
|
|
|
|
onclick={() => handleRoomSelect(room.roomId)}
|
|
|
|
|
class="w-5 h-5 flex items-center justify-center text-light/40 hover:text-light hover:bg-light/10 rounded transition-colors"
|
|
|
|
|
onclick={() => (showCreateRoomModal = true)}
|
|
|
|
|
title="Create room"
|
|
|
|
|
>
|
|
|
|
|
<Avatar src={room.avatarUrl} name={room.name} size="xs" />
|
|
|
|
|
<div class="flex-1 min-w-0">
|
|
|
|
|
<span class="font-bold text-sm text-light truncate block">{room.name}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{#if room.unreadCount > 0}
|
|
|
|
|
<span class="bg-primary text-white text-xs px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
|
|
|
|
|
{room.unreadCount > 99 ? "99+" : room.unreadCount}
|
|
|
|
|
</span>
|
|
|
|
|
{/if}
|
|
|
|
|
<span class="material-symbols-rounded" style="font-size: 14px;">add</span>
|
|
|
|
|
</button>
|
|
|
|
|
</li>
|
|
|
|
|
{/each}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
<ul class="flex flex-col gap-0.5">
|
|
|
|
|
{#each filteredOrgRooms as room (room.roomId)}
|
|
|
|
|
<li>
|
|
|
|
|
<button
|
|
|
|
|
class="w-full flex items-center gap-2 pl-1 pr-2 py-1 rounded-[50px] transition-colors text-left
|
|
|
|
|
{$selectedRoomId === room.roomId ? 'bg-primary/20' : 'hover:bg-light/5'}"
|
|
|
|
|
onclick={() => handleRoomSelect(room.roomId)}
|
|
|
|
|
>
|
|
|
|
|
<Avatar src={room.avatarUrl} name={room.name} size="xs" />
|
|
|
|
|
<div class="flex-1 min-w-0">
|
|
|
|
|
<span class="font-bold text-sm text-light truncate block">{room.name}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{#if room.unreadCount > 0}
|
|
|
|
|
<span class="bg-primary text-white text-xs px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
|
|
|
|
|
{room.unreadCount > 99 ? "99+" : room.unreadCount}
|
|
|
|
|
</span>
|
|
|
|
|
{/if}
|
|
|
|
|
</button>
|
|
|
|
|
</li>
|
|
|
|
|
{/each}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<!-- Direct Messages -->
|
|
|
|
|
{#if filteredDmRooms.length > 0}
|
|
|
|
|
<div class="mb-2">
|
|
|
|
|
<div class="flex items-center justify-between px-2 py-1">
|
|
|
|
|
<span class="text-xs font-semibold text-light/40 uppercase tracking-wider">
|
|
|
|
|
<span class="material-symbols-rounded align-middle" style="font-size: 14px;">chat_bubble</span>
|
|
|
|
|
Direct Messages
|
|
|
|
|
</span>
|
|
|
|
|
<button
|
|
|
|
|
class="w-5 h-5 flex items-center justify-center text-light/40 hover:text-light hover:bg-light/10 rounded transition-colors"
|
|
|
|
|
onclick={() => (showStartDMModal = true)}
|
|
|
|
|
title="New DM"
|
|
|
|
|
>
|
|
|
|
|
<span class="material-symbols-rounded" style="font-size: 14px;">add</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<ul class="flex flex-col gap-0.5">
|
|
|
|
|
{#each filteredDmRooms as room (room.roomId)}
|
|
|
|
|
<li>
|
|
|
|
|
<button
|
|
|
|
|
class="w-full flex items-center gap-2 pl-1 pr-2 py-1 rounded-[50px] transition-colors text-left
|
|
|
|
|
{$selectedRoomId === room.roomId ? 'bg-primary/20' : 'hover:bg-light/5'}"
|
|
|
|
|
onclick={() => handleRoomSelect(room.roomId)}
|
|
|
|
|
>
|
|
|
|
|
<Avatar src={room.avatarUrl} name={room.name} size="xs" />
|
|
|
|
|
<div class="flex-1 min-w-0">
|
|
|
|
|
<span class="font-bold text-sm text-light truncate block">{room.name}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{#if room.unreadCount > 0}
|
|
|
|
|
<span class="bg-primary text-white text-xs px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
|
|
|
|
|
{room.unreadCount > 99 ? "99+" : room.unreadCount}
|
|
|
|
|
</span>
|
|
|
|
|
{/if}
|
|
|
|
|
</button>
|
|
|
|
|
</li>
|
|
|
|
|
{/each}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
|
|
|
|
|
<!-- Other Rooms (not in a space, not DMs) -->
|
|
|
|
|
{#if filteredOtherRooms.length > 0}
|
|
|
|
|
<div class="mb-2">
|
|
|
|
|
<div class="flex items-center justify-between px-2 py-1">
|
|
|
|
|
<span class="text-xs font-semibold text-light/40 uppercase tracking-wider">
|
|
|
|
|
<span class="material-symbols-rounded align-middle" style="font-size: 14px;">tag</span>
|
|
|
|
|
Rooms
|
|
|
|
|
</span>
|
|
|
|
|
<button
|
|
|
|
|
class="w-5 h-5 flex items-center justify-center text-light/40 hover:text-light hover:bg-light/10 rounded transition-colors"
|
|
|
|
|
onclick={() => (showCreateRoomModal = true)}
|
|
|
|
|
title="Create room"
|
|
|
|
|
>
|
|
|
|
|
<span class="material-symbols-rounded" style="font-size: 14px;">add</span>
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<ul class="flex flex-col gap-0.5">
|
|
|
|
|
{#each filteredOtherRooms as room (room.roomId)}
|
|
|
|
|
<li>
|
|
|
|
|
<button
|
|
|
|
|
class="w-full flex items-center gap-2 pl-1 pr-2 py-1 rounded-[50px] transition-colors text-left
|
|
|
|
|
{$selectedRoomId === room.roomId ? 'bg-primary/20' : 'hover:bg-light/5'}"
|
|
|
|
|
onclick={() => handleRoomSelect(room.roomId)}
|
|
|
|
|
>
|
|
|
|
|
<Avatar src={room.avatarUrl} name={room.name} size="xs" />
|
|
|
|
|
<div class="flex-1 min-w-0">
|
|
|
|
|
<span class="font-bold text-sm text-light truncate block">{room.name}</span>
|
|
|
|
|
</div>
|
|
|
|
|
{#if room.unreadCount > 0}
|
|
|
|
|
<span class="bg-primary text-white text-xs px-1.5 py-0.5 rounded-full min-w-[18px] text-center">
|
|
|
|
|
{room.unreadCount > 99 ? "99+" : room.unreadCount}
|
|
|
|
|
</span>
|
|
|
|
|
{/if}
|
|
|
|
|
</button>
|
|
|
|
|
</li>
|
|
|
|
|
{/each}
|
|
|
|
|
</ul>
|
|
|
|
|
</div>
|
|
|
|
|
{/if}
|
|
|
|
|
{/if}
|
|
|
|
|
</nav>
|
|
|
|
|
|
|
|
|
|
|