import React, { useEffect, useState } from 'react'; import { useAtom } from 'jotai'; 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, SettingsPages } from '../../../features/settings'; import { settingsRequestAtom } from '../../../state/settingsRequest'; 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); // [Gitea #159] Programmatic "open settings at page X" requests. const [settingsRequest, setSettingsRequest] = useAtom(settingsRequestAtom); const [initialPage, setInitialPage] = useState(); useEffect(() => { if (!settingsRequest) return; const page = { general: SettingsPages.GeneralPage, account: SettingsPages.AccountPage, notifications: SettingsPages.NotificationPage, devices: SettingsPages.DevicesPage, }[settingsRequest]; setInitialPage(page); setSettingsOpen(true); setSettingsRequest(null); }, [settingsRequest, setSettingsRequest]); 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)} label="Settings"> setSettingsOpen(false)} /> )} ); }