feat: Enhance user color and banner management
- Updated `useUserColor` hook to support fetching and embedding user color from avatar metadata with authentication. - Introduced `useUserBanner` hook for managing user banners stored in avatar metadata, including fetching and embedding functionality. - Added `fetchAndExtractMetadata` utility to retrieve both color and banner from images. - Implemented `CustomStatusDialog` component for users to set and clear custom status messages. - Modified `SettingsTab` to include custom status functionality and improved user experience. - Enhanced image metadata utilities to support banner extraction and embedding in PNG format. - Updated sidebar settings to handle user profile changes more gracefully.
This commit is contained in:
@@ -1,8 +1,8 @@
|
||||
import React, { MouseEventHandler, useState } from 'react';
|
||||
import { Box, config, Icon, Icons, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
|
||||
import { Box, config, Icon, Icons, Line, Menu, MenuItem, PopOut, RectCords, Text } from 'folds';
|
||||
import FocusTrap from 'focus-trap-react';
|
||||
import { useNavigate } from 'react-router-dom';
|
||||
import { SidebarItem, SidebarItemTooltip, SidebarAvatar } from '../../../components/sidebar';
|
||||
import { SidebarItem, SidebarAvatar } from '../../../components/sidebar';
|
||||
import { UserAvatar } from '../../../components/user-avatar';
|
||||
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
||||
import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix';
|
||||
@@ -13,21 +13,23 @@ import { useUserProfile } from '../../../hooks/useUserProfile';
|
||||
import { Modal500 } from '../../../components/Modal500';
|
||||
import { AccountSwitcher } from '../../../components/account-switcher';
|
||||
import { stopPropagation } from '../../../utils/keyboard';
|
||||
import { getLoginPath, withSearchParam } from '../../pathUtils';
|
||||
import { getLoginPath } from '../../pathUtils';
|
||||
import { logoutClient } from '../../../../client/initMatrix';
|
||||
import { CustomStatusDialog } from '../../../components/custom-status';
|
||||
|
||||
export function SettingsTab() {
|
||||
const mx = useMatrixClient();
|
||||
const useAuthentication = useMediaAuthentication();
|
||||
const userId = mx.getUserId()!;
|
||||
const profile = useUserProfile(userId);
|
||||
const userId = mx.getUserId();
|
||||
const profile = useUserProfile(userId ?? '');
|
||||
const navigate = useNavigate();
|
||||
|
||||
const [settings, setSettings] = useState(false);
|
||||
const [menuAnchor, setMenuAnchor] = useState<RectCords>();
|
||||
const [customStatusOpen, setCustomStatusOpen] = useState(false);
|
||||
|
||||
const displayName = profile.displayName ?? getMxIdLocalPart(userId) ?? userId;
|
||||
const avatarUrl = profile.avatarUrl
|
||||
const displayName = profile.displayName ?? getMxIdLocalPart(userId ?? '') ?? userId ?? '';
|
||||
const avatarUrl = profile.avatarUrl && userId
|
||||
? mxcUrlToHttp(mx, profile.avatarUrl, useAuthentication, 96, 96, 'crop') ?? undefined
|
||||
: undefined;
|
||||
|
||||
@@ -42,22 +44,17 @@ export function SettingsTab() {
|
||||
|
||||
return (
|
||||
<SidebarItem active={settings}>
|
||||
<SidebarItemTooltip tooltip="User Settings">
|
||||
{(triggerRef) => (
|
||||
<SidebarAvatar
|
||||
as="button"
|
||||
ref={triggerRef}
|
||||
onClick={openSettings}
|
||||
onContextMenu={handleContextMenu}
|
||||
>
|
||||
<UserAvatar
|
||||
userId={userId}
|
||||
src={avatarUrl}
|
||||
renderFallback={() => <Text size="H4">{nameInitials(displayName)}</Text>}
|
||||
/>
|
||||
</SidebarAvatar>
|
||||
)}
|
||||
</SidebarItemTooltip>
|
||||
<SidebarAvatar
|
||||
as="button"
|
||||
onClick={openSettings}
|
||||
onContextMenu={handleContextMenu}
|
||||
>
|
||||
<UserAvatar
|
||||
userId={userId ?? ''}
|
||||
src={avatarUrl}
|
||||
renderFallback={() => <Text size="H4">{nameInitials(displayName)}</Text>}
|
||||
/>
|
||||
</SidebarAvatar>
|
||||
|
||||
<PopOut
|
||||
anchor={menuAnchor}
|
||||
@@ -78,18 +75,14 @@ export function SettingsTab() {
|
||||
>
|
||||
<Menu>
|
||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||
<AccountSwitcher currentUserId={userId} />
|
||||
<AccountSwitcher currentUserId={userId ?? ''} />
|
||||
</Box>
|
||||
<Line variant="Surface" size="300" />
|
||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
setMenuAnchor(undefined);
|
||||
const loginPath = getLoginPath() + '?add-account=true';
|
||||
console.log('[SettingsTab] Navigating to add account:', loginPath);
|
||||
localStorage.setItem('debug-add-account-nav', JSON.stringify({
|
||||
timestamp: new Date().toISOString(),
|
||||
loginPath,
|
||||
currentUrl: window.location.href
|
||||
}));
|
||||
navigate(loginPath);
|
||||
navigate(`${getLoginPath()}?add-account=true`);
|
||||
}}
|
||||
size="300"
|
||||
radii="300"
|
||||
@@ -116,11 +109,34 @@ export function SettingsTab() {
|
||||
</Text>
|
||||
</MenuItem>
|
||||
</Box>
|
||||
<Line variant="Surface" size="300" />
|
||||
<Box direction="Column" gap="100" style={{ padding: config.space.S100 }}>
|
||||
<MenuItem
|
||||
onClick={() => {
|
||||
setMenuAnchor(undefined);
|
||||
setCustomStatusOpen(true);
|
||||
}}
|
||||
size="300"
|
||||
radii="300"
|
||||
>
|
||||
<Box gap="200" alignItems="Center">
|
||||
<Icon size="100" src={Icons.Message} />
|
||||
<Text as="span" size="T300" truncate>
|
||||
Set Custom Status
|
||||
</Text>
|
||||
</Box>
|
||||
</MenuItem>
|
||||
</Box>
|
||||
</Menu>
|
||||
</FocusTrap>
|
||||
}
|
||||
/>
|
||||
|
||||
<CustomStatusDialog
|
||||
open={customStatusOpen}
|
||||
onClose={() => setCustomStatusOpen(false)}
|
||||
/>
|
||||
|
||||
{settings && (
|
||||
<Modal500 requestClose={closeSettings}>
|
||||
<Settings requestClose={closeSettings} />
|
||||
|
||||
Reference in New Issue
Block a user