From 898b7469bb07ed6d7d53600fbd3b1c85a17ab723 Mon Sep 17 00:00:00 2001 From: byGalax Date: Sat, 16 May 2026 17:01:38 +0200 Subject: [PATCH] feat(desktop): set-nickname dialog + right-click trigger in friends list --- .../desktop/src/components/NicknameDialog.tsx | 81 +++++++++++++++++++ apps/desktop/src/pages/FriendsPage.tsx | 45 ++++++++++- 2 files changed, 123 insertions(+), 3 deletions(-) create mode 100644 apps/desktop/src/components/NicknameDialog.tsx diff --git a/apps/desktop/src/components/NicknameDialog.tsx b/apps/desktop/src/components/NicknameDialog.tsx new file mode 100644 index 0000000..fa7027a --- /dev/null +++ b/apps/desktop/src/components/NicknameDialog.tsx @@ -0,0 +1,81 @@ +import { useEffect, useRef, useState } from 'react'; + +import { getNickname, setNickname } from '../lib/friendNicknames'; + +interface Props { + open: boolean; + userId: string; + displayName: string; + onClose: () => void; +} + +export function NicknameDialog({ open, userId, displayName, onClose }: Props) { + const [value, setValue] = useState(''); + const inputRef = useRef(null); + + useEffect(() => { + if (!open) return; + setValue(getNickname(userId) ?? ''); + setTimeout(() => inputRef.current?.focus(), 0); + }, [open, userId]); + + useEffect(() => { + if (!open) return; + const onKey = (e: KeyboardEvent) => { if (e.key === 'Escape') onClose(); }; + window.addEventListener('keydown', onKey); + return () => window.removeEventListener('keydown', onKey); + }, [open, onClose]); + + if (!open) return null; + + const submit = (): void => { + setNickname(userId, value); + onClose(); + }; + + return ( +
+
e.stopPropagation()} + className="w-full max-w-sm rounded-2xl border border-line bg-surface-2 p-5 shadow-xl" + > +

Spitzname für {displayName}

+

+ Nur du siehst diesen Namen. Leer lassen = den richtigen Namen verwenden. +

+ setValue(e.target.value)} + onKeyDown={(e) => { if (e.key === 'Enter') submit(); }} + maxLength={32} + placeholder={displayName} + className="mt-4 w-full rounded-lg border border-line bg-surface-3 px-3 py-2 text-sm text-fg placeholder-fg-muted focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent/30" + /> +
+ + +
+
+
+ ); +} diff --git a/apps/desktop/src/pages/FriendsPage.tsx b/apps/desktop/src/pages/FriendsPage.tsx index 1e247e2..e0fc4da 100644 --- a/apps/desktop/src/pages/FriendsPage.tsx +++ b/apps/desktop/src/pages/FriendsPage.tsx @@ -14,6 +14,7 @@ import { useNavigate } from 'react-router-dom'; import { Avatar } from '../components/Avatar'; import { EmptyState } from '../components/EmptyState'; +import { NicknameDialog } from '../components/NicknameDialog'; import { AddUserIcon, AlertIcon, @@ -41,6 +42,7 @@ export function FriendsPage() { const [searchError, setSearchError] = useState(null); const [pendingId, setPendingId] = useState(null); const [actionError, setActionError] = useState(null); + const [nicknameDialog, setNicknameDialog] = useState<{ userId: string; displayName: string } | null>(null); const searchInputRef = useRef(null); const focusSearch = useCallback(() => { @@ -184,6 +186,12 @@ export function FriendsPage() { + setNicknameDialog({ + userId: f.peer.userId, + displayName: f.peer.displayName ?? f.peer.username ?? 'Freund', + }) + } renderActions={(f) => ( )} + setNicknameDialog(null)} + /> ); } @@ -275,10 +289,12 @@ function FriendList({ items, emptyKey, renderActions, + onRowContextMenu, }: { items: Friendship[]; emptyKey: string; renderActions: (f: Friendship) => React.ReactNode; + onRowContextMenu?: (f: Friendship) => void; }) { const { t } = useTranslation(['app']); if (items.length === 0) { @@ -296,16 +312,39 @@ function FriendList({
    {items.map((f) => (
  • - {renderActions(f)} + ) => { + e.preventDefault(); + onRowContextMenu(f); + }, + } + : {})} + > + {renderActions(f)} +
  • ))}
); } -function FriendRow({ profile, children }: { profile: ProfileBrief; children: React.ReactNode }) { +function FriendRow({ + profile, + children, + onContextMenu, +}: { + profile: ProfileBrief; + children: React.ReactNode; + onContextMenu?: (e: React.MouseEvent) => void; +}) { return ( -
+