fix: Mobile style fixes and other small ui fixes

This commit is contained in:
2026-05-18 23:14:16 +02:00
parent afb64520ed
commit 94428ed170
32 changed files with 808 additions and 239 deletions

View File

@@ -1,21 +1,19 @@
<nav class="relative flex h-full w-full flex-col items-center gap-2 border-r border-border bg-secondary/35 px-2 py-3">
<nav class="relative flex h-full min-w-14 flex-col items-center gap-2 border-r border-border bg-secondary/35 px-0 py-3 md:min-w-0 md:w-full">
<!-- Create button -->
<button
appThemeNode="serversRailCreateButton"
type="button"
class="flex h-10 w-10 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90"
class="flex h-11 w-11 items-center justify-center rounded-md bg-primary text-primary-foreground transition-colors hover:bg-primary/90 md:h-10 md:w-10"
title="Create Server"
(click)="createServer()"
>
<ng-icon
name="lucidePlus"
class="w-5 h-5"
class="h-[22px] w-[22px] md:h-5 md:w-5"
/>
</button>
@if (dmRailComponent()) {
<ng-container *ngComponentOutlet="dmRailComponent()" />
}
<app-dm-rail />
@for (call of directCalls.visibleActiveSessions(); track call.callId + ':' + $index) {
<div class="group/call relative flex w-full justify-center">
@@ -27,7 +25,7 @@
<button
type="button"
class="relative z-10 grid h-10 w-10 place-items-center overflow-hidden rounded-xl transition-colors hover:rounded-lg"
class="relative z-10 grid h-11 w-11 place-items-center overflow-hidden rounded-xl transition-colors hover:rounded-lg md:h-10 md:w-10"
[ngClass]="
callAvatarUrls(call).length > 0
? 'bg-emerald-950 text-white shadow-sm hover:bg-emerald-900'
@@ -61,7 +59,7 @@
<ng-icon
name="lucidePhone"
class="relative z-10 h-5 w-5 drop-shadow"
class="relative z-10 h-[22px] w-[22px] drop-shadow md:h-5 md:w-5"
/>
</button>
</div>
@@ -83,7 +81,7 @@
<button
appThemeNode="serversRailItem"
type="button"
class="relative z-10 flex h-10 w-10 cursor-pointer flex-shrink-0 items-center justify-center border border-transparent transition-[border-radius,box-shadow,background-color] duration-100 hover:rounded-lg hover:bg-card"
class="relative z-10 flex h-11 w-11 cursor-pointer flex-shrink-0 items-center justify-center border border-transparent transition-[border-radius,box-shadow,background-color] duration-100 hover:rounded-lg hover:bg-card md:h-10 md:w-10"
[ngClass]="isSelectedRoom(room) ? 'rounded-lg ring-2 ring-primary/40 bg-primary/10' : 'rounded-xl bg-card'"
[title]="room.name"
[attr.aria-current]="isSelectedRoom(room) ? 'page' : null"

View File

@@ -2,7 +2,6 @@
import {
Component,
DestroyRef,
Type,
computed,
effect,
inject,
@@ -36,6 +35,7 @@ import { RoomsActions } from '../../../store/rooms/rooms.actions';
import { DatabaseService } from '../../../infrastructure/persistence';
import { NotificationsFacade } from '../../../domains/notifications';
import { DirectCallService, DirectCallSession } from '../../../domains/direct-call';
import { DmRailComponent } from '../../../domains/direct-message/feature/dm-rail/dm-rail.component';
import { type ServerInfo, ServerDirectoryFacade } from '../../../domains/server-directory';
import { ThemeNodeDirective } from '../../../domains/theme';
import { hasRoomBanForUser } from '../../../domains/access-control';
@@ -54,6 +54,7 @@ import {
NgIcon,
ConfirmDialogComponent,
ContextMenuComponent,
DmRailComponent,
LeaveServerDialogComponent,
ThemeNodeDirective,
UserBarComponent
@@ -71,12 +72,12 @@ export class ServersRailComponent {
private serverDirectory = inject(ServerDirectoryFacade);
private destroyRef = inject(DestroyRef);
private banLookupRequestVersion = 0;
private visibleSavedRoomCache: Room[] = [];
private savedRoomJoinRequests = new Subject<{ room: Room; password?: string }>();
savedRooms = this.store.selectSignal(selectSavedRooms);
currentRoom = this.store.selectSignal(selectCurrentRoom);
showMenu = signal(false);
dmRailComponent = signal<Type<unknown> | null>(null);
menuX = signal(72);
menuY = signal(100);
contextRoom = signal<Room | null>(null);
@@ -95,9 +96,9 @@ export class ServersRailComponent {
isOnDirectMessage = toSignal(
this.router.events.pipe(
filter((navigationEvent): navigationEvent is NavigationEnd => navigationEvent instanceof NavigationEnd),
map((navigationEvent) => navigationEvent.urlAfterRedirects.startsWith('/dm/') || navigationEvent.urlAfterRedirects.startsWith('/pm/'))
map((navigationEvent) => this.isDirectMessageUrl(navigationEvent.urlAfterRedirects))
),
{ initialValue: this.router.url.startsWith('/dm/') || this.router.url.startsWith('/pm/') }
{ initialValue: this.isDirectMessageUrl(this.router.url) }
);
isOnCall = toSignal(
this.router.events.pipe(
@@ -139,7 +140,7 @@ export class ServersRailComponent {
passwordPromptRoom = signal<Room | null>(null);
joinPassword = signal('');
joinPasswordError = signal<string | null>(null);
visibleSavedRooms = computed(() => this.savedRooms().filter((room) => !this.isRoomMarkedBanned(room)));
visibleSavedRooms = computed(() => this.stabilizeVisibleSavedRooms(this.savedRooms().filter((room) => !this.isRoomMarkedBanned(room))));
voicePresenceByRoom = computed(() => {
const presence: Record<string, number> = {};
const seenByRoom = new Map<string, Set<string>>();
@@ -182,10 +183,6 @@ export class ServersRailComponent {
});
constructor() {
void import('../../../domains/direct-message/feature/dm-rail/dm-rail.component').then((module) => {
this.dmRailComponent.set(module.DmRailComponent);
});
effect(() => {
const rooms = this.savedRooms();
const currentUser = this.currentUser();
@@ -237,6 +234,7 @@ export class ServersRailComponent {
}
joinSavedRoom(room: Room): void {
const targetRoom = this.savedRooms().find((savedRoom) => savedRoom.id === room.id) ?? room;
const currentUserId = localStorage.getItem('metoyou_currentUserId');
if (!currentUserId) {
@@ -244,20 +242,20 @@ export class ServersRailComponent {
return;
}
if (this.isRoomMarkedBanned(room)) {
this.bannedServerName.set(room.name);
if (this.isRoomMarkedBanned(targetRoom)) {
this.bannedServerName.set(targetRoom.name);
this.showBannedDialog.set(true);
return;
}
this.optimisticSelectedRoomId.set(room.id);
this.activateSavedRoom(room);
this.savedRoomJoinRequests.next({ room });
this.optimisticSelectedRoomId.set(targetRoom.id);
this.activateSavedRoom(targetRoom);
this.savedRoomJoinRequests.next({ room: targetRoom });
}
openCall(callId: string): void {
this.optimisticSelectedRoomId.set(null);
void this.router.navigate(['/call', callId]);
void this.directCalls.openCallView(callId);
}
isSelectedCall(callIndex: number): boolean {
@@ -392,17 +390,46 @@ export class ServersRailComponent {
}
isSelectedRoom(room: Room): boolean {
if (this.isOnDirectMessage() || this.isOnCall()) {
return false;
}
const optimisticRoomId = this.optimisticSelectedRoomId();
if (optimisticRoomId) {
return optimisticRoomId === room.id;
}
if (this.isOnDirectMessage() || this.isOnCall()) {
return false;
return this.currentRoom()?.id === room.id;
}
private stabilizeVisibleSavedRooms(nextRooms: Room[]): Room[] {
const previousById = new Map(this.visibleSavedRoomCache.map((room) => [room.id, room]));
const stabilizedRooms = nextRooms.map((room) => {
const previousRoom = previousById.get(room.id);
return previousRoom && this.hasSameRailRoomView(previousRoom, room) ? previousRoom : room;
});
if (
stabilizedRooms.length === this.visibleSavedRoomCache.length
&& stabilizedRooms.every((room, index) => room === this.visibleSavedRoomCache[index])
) {
return this.visibleSavedRoomCache;
}
return this.currentRoom()?.id === room.id;
this.visibleSavedRoomCache = stabilizedRooms;
return stabilizedRooms;
}
private hasSameRailRoomView(previousRoom: Room, nextRoom: Room): boolean {
return previousRoom.id === nextRoom.id && previousRoom.name === nextRoom.name && previousRoom.icon === nextRoom.icon;
}
private isDirectMessageUrl(url: string): boolean {
const path = url.split(/[?#]/, 1)[0];
return path === '/dm' || path.startsWith('/dm/') || path === '/pm' || path.startsWith('/pm/');
}
private async refreshBannedLookup(rooms: Room[], currentUser: User | null): Promise<void> {