import React, { useState } from 'react'; import { Badge, Box, Icon, Icons, Menu, MenuItem, PopOut, RectCords, Text, Tooltip, TooltipProvider, color, config, toRem, } from 'folds'; import FocusTrap from 'focus-trap-react'; import { SidebarItem, SidebarItemTooltip, SidebarAvatar } from '../../../components/sidebar'; import { stopPropagation } from '../../../utils/keyboard'; import { UserAvatar } from '../../../components/user-avatar'; import { useMatrixClient } from '../../../hooks/useMatrixClient'; import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix'; import { nameInitials } from '../../../utils/common'; import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication'; import { Settings } from '../../../features/settings'; import { useUserProfile } from '../../../hooks/useUserProfile'; import { Modal500 } from '../../../components/Modal500'; import { useSetting } from '../../../state/hooks/settings'; import { settingsAtom } from '../../../state/settings'; type PresenceOption = { id: 'auto' | 'online' | 'idle' | 'dnd' | 'invisible'; label: string; dotColor: string; soft?: boolean; }; const PRESENCE_OPTIONS: PresenceOption[] = [ { id: 'online', label: 'Online', dotColor: color.Success.Main }, { id: 'idle', label: 'Idle', dotColor: color.Warning.Main }, { id: 'dnd', label: 'Do Not Disturb', dotColor: color.Critical.Main }, { id: 'invisible', label: 'Invisible', dotColor: color.Secondary.Main, soft: true }, { id: 'auto', label: 'Auto (activity-based)', dotColor: color.Primary.Main }, ]; function PresenceDot({ option, size = 10 }: { option: PresenceOption; size?: number }) { return (
); } function presenceVariant(status: string): 'Success' | 'Warning' | 'Critical' | 'Secondary' { if (status === 'online') return 'Success'; if (status === 'idle') return 'Warning'; if (status === 'dnd') return 'Critical'; return 'Secondary'; } function PresencePicker() { const [presenceStatus, setPresenceStatus] = useSetting(settingsAtom, 'presenceStatus'); const [menuAnchor, setMenuAnchor] = useState(); const currentOption = PRESENCE_OPTIONS.find((o) => o.id === presenceStatus) ?? PRESENCE_OPTIONS[4]; const closeMenu = () => setMenuAnchor(undefined); return ( evt.key === 'ArrowDown' || evt.key === 'ArrowRight', isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp' || evt.key === 'ArrowLeft', }} > Set Status {PRESENCE_OPTIONS.map((option) => ( } after={ option.id === presenceStatus ? : undefined } onClick={() => { setPresenceStatus(option.id); closeMenu(); }} > {option.label} ))} } > {/* Presence dot sits in the bottom-right corner of SidebarItem (which is position:relative) */} {`Status: ${currentOption.label}`} } > {(triggerRef) => ( )} ); } export function SettingsTab() { const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const userId = mx.getUserId()!; const profile = useUserProfile(userId); const [settingsOpen, setSettingsOpen] = useState(false); const displayName = profile.displayName ?? getMxIdLocalPart(userId) ?? userId; const avatarUrl = profile.avatarUrl ? (mxcUrlToHttp(mx, profile.avatarUrl, useAuthentication, 96, 96, 'crop') ?? undefined) : undefined; return ( // SidebarItem already has position:relative in its CSS — the PresencePicker // button is absolutely positioned inside it, below the avatar. {(triggerRef) => ( setSettingsOpen(true)}> {nameInitials(displayName)}} /> )} {settingsOpen && ( setSettingsOpen(false)}> setSettingsOpen(false)} /> )} ); }