@switch (activePage()) {
@case ('general') {
diff --git a/toju-app/src/app/features/settings/settings-modal/settings-modal.component.ts b/toju-app/src/app/features/settings/settings-modal/settings-modal.component.ts
index d752498..e42c03b 100644
--- a/toju-app/src/app/features/settings/settings-modal/settings-modal.component.ts
+++ b/toju-app/src/app/features/settings/settings-modal/settings-modal.component.ts
@@ -45,7 +45,11 @@ import { PermissionsSettingsComponent } from './permissions-settings/permissions
import { DebuggingSettingsComponent } from './debugging-settings/debugging-settings.component';
import { UpdatesSettingsComponent } from './updates-settings/updates-settings.component';
import { THIRD_PARTY_LICENSES, type ThirdPartyLicense } from './third-party-licenses';
-import { ThemeLibraryService, ThemeService } from '../../../domains/theme';
+import {
+ ThemeLibraryService,
+ ThemeNodeDirective,
+ ThemeService
+} from '../../../domains/theme';
@Component({
selector: 'app-settings-modal',
@@ -63,7 +67,8 @@ import { ThemeLibraryService, ThemeService } from '../../../domains/theme';
ServerSettingsComponent,
MembersSettingsComponent,
BansSettingsComponent,
- PermissionsSettingsComponent
+ PermissionsSettingsComponent,
+ ThemeNodeDirective
],
viewProviders: [
provideIcons({
@@ -109,41 +114,19 @@ export class SettingsModalComponent {
selectedSavedTheme = this.themeLibrary.selectedEntry;
readonly globalPages: { id: SettingsPage; label: string; icon: string }[] = [
- { id: 'general',
- label: 'General',
- icon: 'lucideSettings' },
- { id: 'theme',
- label: 'Theme Studio',
- icon: 'lucidePalette' },
- { id: 'network',
- label: 'Network',
- icon: 'lucideGlobe' },
- { id: 'notifications',
- label: 'Notifications',
- icon: 'lucideBell' },
- { id: 'voice',
- label: 'Voice & Audio',
- icon: 'lucideAudioLines' },
- { id: 'updates',
- label: 'Updates',
- icon: 'lucideDownload' },
- { id: 'debugging',
- label: 'Debugging',
- icon: 'lucideBug' }
+ { id: 'general', label: 'General', icon: 'lucideSettings' },
+ { id: 'theme', label: 'Theme Studio', icon: 'lucidePalette' },
+ { id: 'network', label: 'Network', icon: 'lucideGlobe' },
+ { id: 'notifications', label: 'Notifications', icon: 'lucideBell' },
+ { id: 'voice', label: 'Voice & Audio', icon: 'lucideAudioLines' },
+ { id: 'updates', label: 'Updates', icon: 'lucideDownload' },
+ { id: 'debugging', label: 'Debugging', icon: 'lucideBug' }
];
readonly serverPages: { id: SettingsPage; label: string; icon: string }[] = [
- { id: 'server',
- label: 'Server',
- icon: 'lucideSettings' },
- { id: 'members',
- label: 'Members',
- icon: 'lucideUsers' },
- { id: 'bans',
- label: 'Bans',
- icon: 'lucideBan' },
- { id: 'permissions',
- label: 'Permissions',
- icon: 'lucideShield' }
+ { id: 'server', label: 'Server', icon: 'lucideSettings' },
+ { id: 'members', label: 'Members', icon: 'lucideUsers' },
+ { id: 'bans', label: 'Bans', icon: 'lucideBan' },
+ { id: 'permissions', label: 'Permissions', icon: 'lucideShield' }
];
manageableRooms = computed
(() => {
@@ -153,16 +136,18 @@ export class SettingsModalComponent {
return [];
return this.savedRooms().filter((room) => {
- const viewedRoom = this.currentRoom()?.id === room.id ? this.currentRoom() ?? room : room;
+ const viewedRoom = this.currentRoom()?.id === room.id ? (this.currentRoom() ?? room) : room;
const role = resolveLegacyRole(viewedRoom, user);
- return role === 'host'
- || resolveRoomPermission(viewedRoom, user, 'manageServer')
- || resolveRoomPermission(viewedRoom, user, 'manageRoles')
- || resolveRoomPermission(viewedRoom, user, 'manageChannels')
- || resolveRoomPermission(viewedRoom, user, 'manageBans')
- || resolveRoomPermission(viewedRoom, user, 'kickMembers')
- || resolveRoomPermission(viewedRoom, user, 'banMembers');
+ return (
+ role === 'host' ||
+ resolveRoomPermission(viewedRoom, user, 'manageServer') ||
+ resolveRoomPermission(viewedRoom, user, 'manageRoles') ||
+ resolveRoomPermission(viewedRoom, user, 'manageChannels') ||
+ resolveRoomPermission(viewedRoom, user, 'manageBans') ||
+ resolveRoomPermission(viewedRoom, user, 'kickMembers') ||
+ resolveRoomPermission(viewedRoom, user, 'banMembers')
+ );
});
});
@@ -187,21 +172,23 @@ export class SettingsModalComponent {
if (!server || !user)
return null;
- return resolveLegacyRole(this.currentRoom()?.id === server.id ? this.currentRoom() ?? server : server, user);
+ return resolveLegacyRole(this.currentRoom()?.id === server.id ? (this.currentRoom() ?? server) : server, user);
});
canAccessSelectedServer = computed(() => {
const server = this.selectedServer();
const user = this.currentUser();
- return !!server && !!user && (
- resolveLegacyRole(server, user) === 'host'
- || resolveRoomPermission(server, user, 'manageServer')
- || resolveRoomPermission(server, user, 'manageRoles')
- || resolveRoomPermission(server, user, 'manageChannels')
- || resolveRoomPermission(server, user, 'manageBans')
- || resolveRoomPermission(server, user, 'kickMembers')
- || resolveRoomPermission(server, user, 'banMembers')
+ return (
+ !!server &&
+ !!user &&
+ (resolveLegacyRole(server, user) === 'host' ||
+ resolveRoomPermission(server, user, 'manageServer') ||
+ resolveRoomPermission(server, user, 'manageRoles') ||
+ resolveRoomPermission(server, user, 'manageChannels') ||
+ resolveRoomPermission(server, user, 'manageBans') ||
+ resolveRoomPermission(server, user, 'kickMembers') ||
+ resolveRoomPermission(server, user, 'banMembers'))
);
});
@@ -209,11 +196,13 @@ export class SettingsModalComponent {
const server = this.selectedServer();
const user = this.currentUser();
- return !!server && !!user && (
- resolveLegacyRole(server, user) === 'host'
- || resolveRoomPermission(server, user, 'manageRoles')
- || resolveRoomPermission(server, user, 'kickMembers')
- || resolveRoomPermission(server, user, 'banMembers')
+ return (
+ !!server &&
+ !!user &&
+ (resolveLegacyRole(server, user) === 'host' ||
+ resolveRoomPermission(server, user, 'manageRoles') ||
+ resolveRoomPermission(server, user, 'kickMembers') ||
+ resolveRoomPermission(server, user, 'banMembers'))
);
});
@@ -221,20 +210,19 @@ export class SettingsModalComponent {
const server = this.selectedServer();
const user = this.currentUser();
- return !!server && !!user && (
- resolveLegacyRole(server, user) === 'host'
- || resolveRoomPermission(server, user, 'manageBans')
- );
+ return !!server && !!user && (resolveLegacyRole(server, user) === 'host' || resolveRoomPermission(server, user, 'manageBans'));
});
canManageSelectedPermissions = computed(() => {
const server = this.selectedServer();
const user = this.currentUser();
- return !!server && !!user && (
- resolveLegacyRole(server, user) === 'host'
- || resolveRoomPermission(server, user, 'manageRoles')
- || resolveRoomPermission(server, user, 'manageServer')
+ return (
+ !!server &&
+ !!user &&
+ (resolveLegacyRole(server, user) === 'host' ||
+ resolveRoomPermission(server, user, 'manageRoles') ||
+ resolveRoomPermission(server, user, 'manageServer'))
);
});
@@ -259,9 +247,8 @@ export class SettingsModalComponent {
const hasSelected = !!selectedId && rooms.some((room) => room.id === selectedId);
if (!hasSelected) {
- const fallbackId = [targetId, currentRoomId].find((candidateId) =>
- !!candidateId && rooms.some((room) => room.id === candidateId)
- ) ?? rooms[0]?.id ?? null;
+ const fallbackId =
+ [targetId, currentRoomId].find((candidateId) => !!candidateId && rooms.some((room) => room.id === candidateId)) ?? rooms[0]?.id ?? null;
this.selectedServerId.set(fallbackId);
}
diff --git a/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.html b/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.html
index b753b8b..06cc4ce 100644
--- a/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.html
+++ b/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.html
@@ -11,6 +11,7 @@
diff --git a/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts b/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts
index c288311..2dd4c8b 100644
--- a/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts
+++ b/toju-app/src/app/shared/components/confirm-dialog/confirm-dialog.component.ts
@@ -4,10 +4,12 @@ import {
output,
HostListener
} from '@angular/core';
+import { ThemeNodeDirective } from '../../../domains/theme';
@Component({
selector: 'app-confirm-dialog',
standalone: true,
+ imports: [ThemeNodeDirective],
templateUrl: './confirm-dialog.component.html',
host: {
style: 'display: contents;'
diff --git a/toju-app/src/app/shared/components/context-menu/context-menu.component.html b/toju-app/src/app/shared/components/context-menu/context-menu.component.html
index f352ab0..35db0ab 100644
--- a/toju-app/src/app/shared/components/context-menu/context-menu.component.html
+++ b/toju-app/src/app/shared/components/context-menu/context-menu.component.html
@@ -12,6 +12,7 @@
@@ -8,7 +9,10 @@
@let statusColor = currentStatusColor();
@let statusLabel = currentStatusLabel();
-
+
-
+
@if (isEditable) {
diff --git a/toju-app/src/app/shared/components/profile-card/profile-card.component.ts b/toju-app/src/app/shared/components/profile-card/profile-card.component.ts
index f27b4dd..e80e2cb 100644
--- a/toju-app/src/app/shared/components/profile-card/profile-card.component.ts
+++ b/toju-app/src/app/shared/components/profile-card/profile-card.component.ts
@@ -21,6 +21,7 @@ import {
} from '../../../domains/profile-avatar';
import { UsersActions } from '../../../store/users/users.actions';
import { selectUsersEntities } from '../../../store/users/users.selectors';
+import { ThemeNodeDirective } from '../../../domains/theme';
@Component({
selector: 'app-profile-card',
@@ -28,15 +29,14 @@ import { selectUsersEntities } from '../../../store/users/users.selectors';
imports: [
CommonModule,
NgIcon,
- UserAvatarComponent
+ UserAvatarComponent,
+ ThemeNodeDirective
],
viewProviders: [provideIcons({ lucideCheck, lucideChevronDown })],
templateUrl: './profile-card.component.html'
})
export class ProfileCardComponent {
readonly user = signal
({ id: '', oderId: '', username: '', displayName: '', status: 'offline', role: 'member', joinedAt: 0 });
- private readonly store = inject(Store);
- private readonly users = this.store.selectSignal(selectUsersEntities);
readonly displayedUser = computed(() => {
const snapshot = this.user();
const entities = this.users();
@@ -60,42 +60,58 @@ export class ProfileCardComponent {
{ value: 'offline', label: 'Invisible', color: 'bg-gray-500' }
];
+ private readonly store = inject(Store);
+ private readonly users = this.store.selectSignal(selectUsersEntities);
private readonly userStatus = inject(UserStatusService);
private readonly profileAvatar = inject(ProfileAvatarFacade);
private readonly profileAvatarEditor = inject(ProfileAvatarEditorService);
- private readonly syncProfileDrafts = effect(() => {
- const user = this.displayedUser();
- const editingField = this.editingField();
+ private readonly syncProfileDrafts = effect(
+ () => {
+ const user = this.displayedUser();
+ const editingField = this.editingField();
- if (editingField !== 'displayName') {
- this.displayNameDraft.set(user.displayName || '');
- }
+ if (editingField !== 'displayName') {
+ this.displayNameDraft.set(user.displayName || '');
+ }
- if (editingField !== 'description') {
- this.descriptionDraft.set(user.description || '');
- }
-
- }, { allowSignalWrites: true });
+ if (editingField !== 'description') {
+ this.descriptionDraft.set(user.description || '');
+ }
+ },
+ { allowSignalWrites: true }
+ );
currentStatusColor(): string {
switch (this.displayedUser().status) {
- case 'online': return 'bg-green-500';
- case 'away': return 'bg-yellow-500';
- case 'busy': return 'bg-red-500';
- case 'offline': return 'bg-gray-500';
- case 'disconnected': return 'bg-gray-500';
- default: return 'bg-green-500';
+ case 'online':
+ return 'bg-green-500';
+ case 'away':
+ return 'bg-yellow-500';
+ case 'busy':
+ return 'bg-red-500';
+ case 'offline':
+ return 'bg-gray-500';
+ case 'disconnected':
+ return 'bg-gray-500';
+ default:
+ return 'bg-green-500';
}
}
currentStatusLabel(): string {
switch (this.displayedUser().status) {
- case 'online': return 'Online';
- case 'away': return 'Away';
- case 'busy': return 'Do Not Disturb';
- case 'offline': return 'Invisible';
- case 'disconnected': return 'Offline';
- default: return 'Online';
+ case 'online':
+ return 'Online';
+ case 'away':
+ return 'Away';
+ case 'busy':
+ return 'Do Not Disturb';
+ case 'offline':
+ return 'Invisible';
+ case 'disconnected':
+ return 'Offline';
+ default:
+ return 'Online';
}
}
@@ -111,9 +127,7 @@ export class ProfileCardComponent {
isStatusOptionSelected(status: UserStatus | null): boolean {
const currentStatus = this.displayedUser().status;
- return status === null
- ? currentStatus === 'online'
- : currentStatus === status;
+ return status === null ? currentStatus === 'online' : currentStatus === status;
}
onDisplayNameInput(event: Event): void {
@@ -223,10 +237,7 @@ export class ProfileCardComponent {
const user = this.displayedUser();
const description = this.normalizeDescription(this.descriptionDraft());
- if (
- displayName === this.normalizeDisplayName(user.displayName)
- && description === this.normalizeDescription(user.description)
- ) {
+ if (displayName === this.normalizeDisplayName(user.displayName) && description === this.normalizeDescription(user.description)) {
return;
}
diff --git a/toju-app/src/app/shared/components/screen-share-source-picker/screen-share-source-picker.component.html b/toju-app/src/app/shared/components/screen-share-source-picker/screen-share-source-picker.component.html
index e61c1ae..c8c6bde 100644
--- a/toju-app/src/app/shared/components/screen-share-source-picker/screen-share-source-picker.component.html
+++ b/toju-app/src/app/shared/components/screen-share-source-picker/screen-share-source-picker.component.html
@@ -11,6 +11,7 @@
this.sources().filter((source) => source.kind === 'screen'));
readonly windowSources = computed(() => this.sources().filter((source) => source.kind === 'window'));
readonly filteredSources = computed(() => {
- return this.activeTab() === 'screen'
- ? this.screenSources()
- : this.windowSources();
+ return this.activeTab() === 'screen' ? this.screenSources() : this.windowSources();
});
readonly hasOpenRequest = computed(() => !!this.request());
readonly activeTab = signal('screen');
@@ -46,9 +49,7 @@ export class ScreenShareSourcePickerComponent {
constructor() {
effect(() => {
const request = this.request();
- const defaultTab: ScreenShareSourceKind = request?.sources.some((source) => source.kind === 'screen')
- ? 'screen'
- : 'window';
+ const defaultTab: ScreenShareSourceKind = request?.sources.some((source) => source.kind === 'screen') ? 'screen' : 'window';
this.activeTab.set(defaultTab);
this.includeSystemAudio.set(request?.includeSystemAudio ?? false);
@@ -68,9 +69,8 @@ export class ScreenShareSourcePickerComponent {
window.requestAnimationFrame(() => {
const activeSourceId = this.selectedSourceId();
- const targetButton = this.sourceButtons().find(
- (button) => button.nativeElement.dataset['sourceId'] === activeSourceId
- ) ?? this.sourceButtons()[0];
+ const targetButton =
+ this.sourceButtons().find((button) => button.nativeElement.dataset['sourceId'] === activeSourceId) ?? this.sourceButtons()[0];
targetButton?.nativeElement.focus();
});
@@ -125,8 +125,6 @@ export class ScreenShareSourcePickerComponent {
}
private getTabSources(tab: ScreenShareSourceKind): ScreenShareSourceOption[] {
- return tab === 'screen'
- ? this.screenSources()
- : this.windowSources();
+ return tab === 'screen' ? this.screenSources() : this.windowSources();
}
}