diff --git a/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.html b/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.html
index 12eaddb..78eff63 100644
--- a/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.html
+++ b/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.html
@@ -1,19 +1,26 @@
Channels
- @for (channel of channels(); track channel.type + channel.name) {
-
-
- @for (segment of parseColoredName(getDisplayName(channel)); track $index) {
- {{ segment.text }}
- }
-
- @if (channel.unreadMessages > 0) {
-
-
+ @for (group of groupedChannels(); track group.type) {
+
+ {{ group.type }} {{ collapsedGroups().has(group.type) ? '▼' : '▲' }}
+
+ @if (!collapsedGroups().has(group.type)) {
+ @for (channel of group.channels; track channel.name) {
+
+
+ @for (segment of parseColoredName(getDisplayName(channel)); track $index) {
+ {{ segment.text }}
+ }
+
+ @if (channel.unreadMessages > 0) {
+
+
+
+ }
}
-
+ }
}
diff --git a/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.scss b/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.scss
index 20094a1..54c9c3a 100644
--- a/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.scss
+++ b/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.scss
@@ -30,4 +30,18 @@
color: #3b82f6;
}
}
+
+ .channel.indented {
+ padding-left: 40px;
+ }
+
+ .channel-group-title {
+ padding: 10px 20px;
+ color: #888;
+ font-size: 0.8rem;
+ font-weight: bold;
+ text-transform: uppercase;
+ cursor: pointer;
+ user-select: none;
+ }
}
diff --git a/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.ts b/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.ts
index 326eb1a..8b965c8 100644
--- a/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.ts
+++ b/frontend/src/app/pages/altitude/chat/components/channel-list/channel-list.component.ts
@@ -1,4 +1,4 @@
-import {Component, effect, inject, input, output} from '@angular/core';
+import {Component, computed, effect, inject, input, output, signal} from '@angular/core';
import {ChatChannel} from '@pages/altitude/chat/objects/chat-channel.object';
import {CircleSvgComponent} from '@pages/altitude/chat/svg/circle.svg';
import {ChatService} from '@pages/altitude/chat/service/chat.service';
@@ -22,6 +22,33 @@ export class ChannelListComponent {
public readonly selectedChannel = input.required
();
public readonly selectedChannelChange = output();
+ protected readonly collapsedGroups = signal>(new Set());
+
+ protected toggleGroup(type: string) {
+ const next = new Set(this.collapsedGroups());
+ if (next.has(type)) {
+ next.delete(type);
+ } else {
+ next.add(type);
+ }
+ this.collapsedGroups.set(next);
+ }
+
+ protected readonly groupedChannels = computed(() => {
+ const channels = this.channels();
+ const groups: { type: ChatChannel['type'], channels: ChatChannel[] }[] = [];
+ const types: ChatChannel['type'][] = ['SERVER', 'DM', 'PARTY', 'GAC'];
+
+ for (const type of types) {
+ const typeChannels = channels.filter(c => c.type === type);
+ if (typeChannels.length > 0) {
+ groups.push({type, channels: typeChannels});
+ }
+ }
+
+ return groups;
+ });
+
constructor() {
effect(() => {
const chatChannels = this.channels();