137 lines
5.3 KiB
TypeScript
137 lines
5.3 KiB
TypeScript
import React from 'react';
|
|
import { useTranslation } from 'react-i18next';
|
|
import { useNavigate } from 'react-router-dom';
|
|
import { Avatar, Box, Icon, Icons, Text, color, config, toRem } from 'folds';
|
|
import { NavButton, NavItem, NavItemContent } from '../../../components/nav';
|
|
import { UserAvatar } from '../../../components/user-avatar';
|
|
import { useMatrixClient } from '../../../hooks/useMatrixClient';
|
|
import { useUserProfile } from '../../../hooks/useUserProfile';
|
|
import { useMediaAuthentication } from '../../../hooks/useMediaAuthentication';
|
|
import { getMxIdLocalPart, mxcUrlToHttp } from '../../../utils/matrix';
|
|
import { nameInitials } from '../../../utils/common';
|
|
import { ScreenSize, useScreenSizeContext } from '../../../hooks/useScreenSize';
|
|
import { useOpenSettingsSheet } from '../../../state/hooks/settingsSheet';
|
|
import { SETTINGS_SHEET_DRAG_ORIGIN_ATTR } from '../../../features/settings/MobileSettingsHorseshoe';
|
|
import { SETTINGS_FROM_IN_APP_STATE } from '../../../features/settings/SettingsScreen';
|
|
import { getSettingsPath } from '../../pathUtils';
|
|
|
|
const MONO_FONT = '"JetBrains Mono Variable", ui-monospace, monospace';
|
|
const ROW_MIN_HEIGHT = toRem(68);
|
|
|
|
export function DirectSelfRow() {
|
|
const { t } = useTranslation();
|
|
const mx = useMatrixClient();
|
|
const useAuthentication = useMediaAuthentication();
|
|
const navigate = useNavigate();
|
|
const screenSize = useScreenSizeContext();
|
|
const openSheet = useOpenSettingsSheet();
|
|
const userId = mx.getSafeUserId();
|
|
const profile = useUserProfile(userId);
|
|
|
|
// Mobile: open the atom-driven bottom-up sheet so the DM list stays
|
|
// visible above with a void gap (the )|( horseshoe). The
|
|
// MobileSettingsHorseshoe wrapper owns the drag/animation; the tap
|
|
// just commits to fully-open.
|
|
//
|
|
// Desktop: navigate to `/settings` — the route renders Settings in
|
|
// the right pane of the nested horseshoe (DM list still on the left).
|
|
const handleOpen = () => {
|
|
if (screenSize === ScreenSize.Mobile) {
|
|
openSheet();
|
|
} else {
|
|
navigate(getSettingsPath(), { state: SETTINGS_FROM_IN_APP_STATE });
|
|
}
|
|
};
|
|
|
|
const displayName = profile.displayName ?? getMxIdLocalPart(userId) ?? userId;
|
|
const avatarUrl = profile.avatarUrl
|
|
? mxcUrlToHttp(mx, profile.avatarUrl, useAuthentication, 96, 96, 'crop') ?? undefined
|
|
: undefined;
|
|
|
|
// `data-settings-drag-origin` is the marker the mobile horseshoe
|
|
// wrapper uses to detect drag-up gestures starting on this row.
|
|
// Document-level touch/pointer listeners in `MobileSettingsHorseshoe`
|
|
// check `target.closest('[data-settings-drag-origin]')` so any
|
|
// touch landing inside this Box (anywhere on the row) starts the
|
|
// open-drag while still leaving the row's own onClick handler
|
|
// free to fire when there's no movement (tap → openSheet).
|
|
return (
|
|
<Box
|
|
shrink="No"
|
|
{...{ [SETTINGS_SHEET_DRAG_ORIGIN_ATTR]: true }}
|
|
style={{
|
|
padding: `${toRem(6)} ${config.space.S100}`,
|
|
borderTop: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`,
|
|
}}
|
|
>
|
|
<NavItem variant="Background" radii="400" style={{ minHeight: ROW_MIN_HEIGHT }}>
|
|
<NavButton onClick={handleOpen} aria-label={t('Direct.self_row_preview')}>
|
|
<NavItemContent>
|
|
<Box
|
|
as="span"
|
|
grow="Yes"
|
|
alignItems="Center"
|
|
gap="300"
|
|
style={{
|
|
minHeight: ROW_MIN_HEIGHT,
|
|
boxSizing: 'border-box',
|
|
padding: `${toRem(8)} 0`,
|
|
}}
|
|
>
|
|
<Avatar size="300" radii="400">
|
|
<UserAvatar
|
|
userId={userId}
|
|
src={avatarUrl}
|
|
renderFallback={() => (
|
|
<Text as="span" size="H6">
|
|
{nameInitials(displayName)}
|
|
</Text>
|
|
)}
|
|
/>
|
|
</Avatar>
|
|
<Box
|
|
as="span"
|
|
direction="Column"
|
|
grow="Yes"
|
|
gap="100"
|
|
style={{ minWidth: 0, overflow: 'hidden' }}
|
|
>
|
|
<Box as="span" alignItems="Baseline" gap="100" style={{ minWidth: 0 }}>
|
|
<Text as="span" size="T300" truncate style={{ fontWeight: 600, flexShrink: 1 }}>
|
|
{t('Direct.self_row_label')}
|
|
</Text>
|
|
<span
|
|
style={{
|
|
fontFamily: MONO_FONT,
|
|
fontSize: toRem(11),
|
|
color: color.Surface.OnContainer,
|
|
opacity: 0.65,
|
|
whiteSpace: 'nowrap',
|
|
overflow: 'hidden',
|
|
textOverflow: 'ellipsis',
|
|
flexShrink: 1,
|
|
minWidth: 0,
|
|
}}
|
|
>
|
|
{userId}
|
|
</span>
|
|
</Box>
|
|
<Text as="span" size="T200" truncate style={{ opacity: 0.6 }}>
|
|
{t('Direct.self_row_preview')}
|
|
</Text>
|
|
</Box>
|
|
<Icon
|
|
src={Icons.Setting}
|
|
size="100"
|
|
style={{
|
|
opacity: 0.55,
|
|
flexShrink: 0,
|
|
}}
|
|
/>
|
|
</Box>
|
|
</NavItemContent>
|
|
</NavButton>
|
|
</NavItem>
|
|
</Box>
|
|
);
|
|
}
|