mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-06 23:30:28 +03:00
add call button for DMs and try to setup for spreading across header for when in call menu (not working yet)
This commit is contained in:
parent
f39a262eb5
commit
3403adeb61
1 changed files with 90 additions and 69 deletions
|
|
@ -21,11 +21,12 @@ import {
|
||||||
RectCords,
|
RectCords,
|
||||||
Badge,
|
Badge,
|
||||||
Spinner,
|
Spinner,
|
||||||
} from 'folds';
|
} from 'folds'; // Assuming 'folds' is your UI library
|
||||||
import { useNavigate } from 'react-router-dom';
|
import { useNavigate } from 'react-router-dom';
|
||||||
import { JoinRule, Room } from 'matrix-js-sdk';
|
import { JoinRule, Room } from 'matrix-js-sdk';
|
||||||
import { useAtomValue } from 'jotai';
|
import { useAtomValue } from 'jotai';
|
||||||
|
|
||||||
|
// --- Required Imports (Adjust paths as needed) ---
|
||||||
import { useStateEvent } from '../../hooks/useStateEvent';
|
import { useStateEvent } from '../../hooks/useStateEvent';
|
||||||
import { PageHeader } from '../../components/page';
|
import { PageHeader } from '../../components/page';
|
||||||
import { RoomAvatar, RoomIcon } from '../../components/room-avatar';
|
import { RoomAvatar, RoomIcon } from '../../components/room-avatar';
|
||||||
|
|
@ -40,7 +41,7 @@ import { useSpaceOptionally } from '../../hooks/useSpace';
|
||||||
import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils';
|
import { getHomeSearchPath, getSpaceSearchPath, withSearchParam } from '../../pages/pathUtils';
|
||||||
import { getCanonicalAliasOrRoomId, isRoomAlias, mxcUrlToHttp } from '../../utils/matrix';
|
import { getCanonicalAliasOrRoomId, isRoomAlias, mxcUrlToHttp } from '../../utils/matrix';
|
||||||
import { _SearchPathSearchParams } from '../../pages/paths';
|
import { _SearchPathSearchParams } from '../../pages/paths';
|
||||||
import * as css from './RoomViewHeader.css';
|
import * as css from './RoomViewHeader.css'; // Assuming CSS Modules
|
||||||
import { useRoomUnread } from '../../state/hooks/unread';
|
import { useRoomUnread } from '../../state/hooks/unread';
|
||||||
import { usePowerLevelsAPI, usePowerLevelsContext } from '../../hooks/usePowerLevels';
|
import { usePowerLevelsAPI, usePowerLevelsContext } from '../../hooks/usePowerLevels';
|
||||||
import { markAsRead } from '../../../client/action/notifications';
|
import { markAsRead } from '../../../client/action/notifications';
|
||||||
|
|
@ -66,11 +67,14 @@ import {
|
||||||
useRoomsNotificationPreferencesContext,
|
useRoomsNotificationPreferencesContext,
|
||||||
} from '../../hooks/useRoomsNotificationPreferences';
|
} from '../../hooks/useRoomsNotificationPreferences';
|
||||||
|
|
||||||
|
// --- RoomMenu Component (Assuming it's defined elsewhere or here) ---
|
||||||
|
// (Include the RoomMenu component code from the previous snippet here if needed)
|
||||||
type RoomMenuProps = {
|
type RoomMenuProps = {
|
||||||
room: Room;
|
room: Room;
|
||||||
requestClose: () => void;
|
requestClose: () => void;
|
||||||
};
|
};
|
||||||
const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose }, ref) => {
|
const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose }, ref) => {
|
||||||
|
// ... (RoomMenu implementation from previous snippet) ...
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
const [hideActivity] = useSetting(settingsAtom, 'hideActivity');
|
||||||
const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
|
const unread = useRoomUnread(room.roomId, roomToUnreadAtom);
|
||||||
|
|
@ -209,7 +213,9 @@ const RoomMenu = forwardRef<HTMLDivElement, RoomMenuProps>(({ room, requestClose
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// --- RoomViewHeader Component ---
|
||||||
export function RoomViewHeader() {
|
export function RoomViewHeader() {
|
||||||
|
// --- Hooks ---
|
||||||
const navigate = useNavigate();
|
const navigate = useNavigate();
|
||||||
const mx = useMatrixClient();
|
const mx = useMatrixClient();
|
||||||
const useAuthentication = useMediaAuthentication();
|
const useAuthentication = useMediaAuthentication();
|
||||||
|
|
@ -232,19 +238,22 @@ export function RoomViewHeader() {
|
||||||
|
|
||||||
const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
|
const setPeopleDrawer = useSetSetting(settingsAtom, 'isPeopleDrawer');
|
||||||
|
|
||||||
// I assume there is a global state so I don't have to run this check every time but for now we'll stub this in
|
// --- Event Handlers ---
|
||||||
const isDirectMessage = () => {
|
const isDirectMessage = () => {
|
||||||
|
// Simplified check - consider optimizing if performance is an issue
|
||||||
const mDirectsEvent = mx.getAccountData('m.direct');
|
const mDirectsEvent = mx.getAccountData('m.direct');
|
||||||
const { roomId } = room;
|
const { roomId } = room;
|
||||||
return (
|
return (
|
||||||
Object.values(mDirectsEvent?.event.content).filter((e) => {
|
!!mDirectsEvent?.event.content &&
|
||||||
if (e.indexOf(roomId) === 0) return true;
|
Object.values(mDirectsEvent.event.content).flat().includes(roomId)
|
||||||
}).length !== 0
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCall: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
const handleCall: MouseEventHandler<HTMLButtonElement> = (evt) => {
|
||||||
setMenuAnchor(evt.currentTarget.getBoundingClientRect());
|
// Placeholder for call initiation logic
|
||||||
|
console.log('Initiate call');
|
||||||
|
// Potentially set anchor for a call menu if needed, similar to other menus
|
||||||
|
// setMenuAnchor(evt.currentTarget.getBoundingClientRect());
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleSearchClick = () => {
|
const handleSearchClick = () => {
|
||||||
|
|
@ -265,21 +274,29 @@ export function RoomViewHeader() {
|
||||||
setPinMenuAnchor(evt.currentTarget.getBoundingClientRect());
|
setPinMenuAnchor(evt.currentTarget.getBoundingClientRect());
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// --- Render ---
|
||||||
return (
|
return (
|
||||||
|
// Use PageHeader component for consistent header styling
|
||||||
<PageHeader balance={screenSize === ScreenSize.Mobile}>
|
<PageHeader balance={screenSize === ScreenSize.Mobile}>
|
||||||
<Box grow="Yes" gap="300">
|
{/* Main container Box: Uses Flexbox (row), aligns items vertically centered */}
|
||||||
{screenSize === ScreenSize.Mobile && (
|
<Box grow="Yes" alignItems="Center" gap="300">
|
||||||
<BackRouteHandler>
|
{' '}
|
||||||
{(onBack) => (
|
{/* Adjust gap as needed */}
|
||||||
<Box shrink="No" alignItems="Center">
|
{/* --- LEFT GROUP --- */}
|
||||||
|
{/* This Box groups elements intended for the left side */}
|
||||||
|
{/* It takes only the width required by its content */}
|
||||||
|
<Box alignItems="Center" gap="300">
|
||||||
|
{/* Back button shown only on mobile */}
|
||||||
|
{screenSize === ScreenSize.Mobile && (
|
||||||
|
<BackRouteHandler>
|
||||||
|
{(onBack) => (
|
||||||
<IconButton onClick={onBack}>
|
<IconButton onClick={onBack}>
|
||||||
<Icon src={Icons.ArrowLeft} />
|
<Icon src={Icons.ArrowLeft} />
|
||||||
</IconButton>
|
</IconButton>
|
||||||
</Box>
|
)}
|
||||||
)}
|
</BackRouteHandler>
|
||||||
</BackRouteHandler>
|
)}
|
||||||
)}
|
{/* Avatar shown only on desktop */}
|
||||||
<Box grow="Yes" alignItems="Center" gap="300">
|
|
||||||
{screenSize !== ScreenSize.Mobile && (
|
{screenSize !== ScreenSize.Mobile && (
|
||||||
<Avatar size="300">
|
<Avatar size="300">
|
||||||
<RoomAvatar
|
<RoomAvatar
|
||||||
|
|
@ -296,14 +313,17 @@ export function RoomViewHeader() {
|
||||||
/>
|
/>
|
||||||
</Avatar>
|
</Avatar>
|
||||||
)}
|
)}
|
||||||
|
{/* Room name and topic */}
|
||||||
<Box direction="Column">
|
<Box direction="Column">
|
||||||
<Text size={topic ? 'H5' : 'H3'} truncate>
|
<Text size={topic ? 'H5' : 'H3'} truncate>
|
||||||
{name}
|
{name}
|
||||||
</Text>
|
</Text>
|
||||||
|
{/* Topic is conditionally rendered and includes logic for an overlay */}
|
||||||
{topic && (
|
{topic && (
|
||||||
<UseStateProvider initial={false}>
|
<UseStateProvider initial={false}>
|
||||||
{(viewTopic, setViewTopic) => (
|
{(viewTopic, setViewTopic) => (
|
||||||
<>
|
<>
|
||||||
|
{/* Overlay for viewing full topic */}
|
||||||
<Overlay open={viewTopic} backdrop={<OverlayBackdrop />}>
|
<Overlay open={viewTopic} backdrop={<OverlayBackdrop />}>
|
||||||
<OverlayCenter>
|
<OverlayCenter>
|
||||||
<FocusTrap
|
<FocusTrap
|
||||||
|
|
@ -322,11 +342,12 @@ export function RoomViewHeader() {
|
||||||
</FocusTrap>
|
</FocusTrap>
|
||||||
</OverlayCenter>
|
</OverlayCenter>
|
||||||
</Overlay>
|
</Overlay>
|
||||||
|
{/* Clickable truncated topic text */}
|
||||||
<Text
|
<Text
|
||||||
as="button"
|
as="button"
|
||||||
type="button"
|
type="button"
|
||||||
onClick={() => setViewTopic(true)}
|
onClick={() => setViewTopic(true)}
|
||||||
className={css.HeaderTopic}
|
className={css.HeaderTopic} // Apply specific styles if needed
|
||||||
size="T200"
|
size="T200"
|
||||||
priority="300"
|
priority="300"
|
||||||
truncate
|
truncate
|
||||||
|
|
@ -338,8 +359,18 @@ export function RoomViewHeader() {
|
||||||
</UseStateProvider>
|
</UseStateProvider>
|
||||||
)}
|
)}
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>{' '}
|
||||||
<Box shrink="No">
|
{/* --- END OF LEFT GROUP --- */}
|
||||||
|
{/* --- SPACER --- */}
|
||||||
|
{/* This empty Box has 'grow="Yes"', making it expand */}
|
||||||
|
{/* It pushes the Left Group and Right Group to opposite ends */}
|
||||||
|
<Box grow="Yes" />
|
||||||
|
{/* --- RIGHT GROUP --- */}
|
||||||
|
{/* This Box groups elements intended for the right side */}
|
||||||
|
{/* 'shrink="No"' prevents it from collapsing if space is tight */}
|
||||||
|
{/* Items are vertically centered, gap adjusted for icons */}
|
||||||
|
<Box shrink="No" alignItems="Center" gap="100">
|
||||||
|
{/* Call button, shown only for Direct Messages */}
|
||||||
{isDirectMessage() && (
|
{isDirectMessage() && (
|
||||||
<TooltipProvider
|
<TooltipProvider
|
||||||
position="Bottom"
|
position="Bottom"
|
||||||
|
|
@ -358,6 +389,7 @@ export function RoomViewHeader() {
|
||||||
)}
|
)}
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
)}
|
)}
|
||||||
|
{/* Search button, hidden for encrypted rooms */}
|
||||||
{!ecryptedRoom && (
|
{!ecryptedRoom && (
|
||||||
<TooltipProvider
|
<TooltipProvider
|
||||||
position="Bottom"
|
position="Bottom"
|
||||||
|
|
@ -375,6 +407,7 @@ export function RoomViewHeader() {
|
||||||
)}
|
)}
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
)}
|
)}
|
||||||
|
{/* Pinned Messages button */}
|
||||||
<TooltipProvider
|
<TooltipProvider
|
||||||
position="Bottom"
|
position="Bottom"
|
||||||
offset={4}
|
offset={4}
|
||||||
|
|
@ -386,18 +419,15 @@ export function RoomViewHeader() {
|
||||||
>
|
>
|
||||||
{(triggerRef) => (
|
{(triggerRef) => (
|
||||||
<IconButton
|
<IconButton
|
||||||
style={{ position: 'relative' }}
|
style={{ position: 'relative' }} // Needed for Badge positioning
|
||||||
onClick={handleOpenPinMenu}
|
onClick={handleOpenPinMenu}
|
||||||
ref={triggerRef}
|
ref={triggerRef}
|
||||||
aria-pressed={!!pinMenuAnchor}
|
aria-pressed={!!pinMenuAnchor} // Indicate state when menu is open
|
||||||
>
|
>
|
||||||
|
{/* Badge showing pin count */}
|
||||||
{pinnedEvents.length > 0 && (
|
{pinnedEvents.length > 0 && (
|
||||||
<Badge
|
<Badge
|
||||||
style={{
|
style={{ position: 'absolute', left: toRem(3), top: toRem(3) }}
|
||||||
position: 'absolute',
|
|
||||||
left: toRem(3),
|
|
||||||
top: toRem(3),
|
|
||||||
}}
|
|
||||||
variant="Secondary"
|
variant="Secondary"
|
||||||
size="400"
|
size="400"
|
||||||
fill="Solid"
|
fill="Solid"
|
||||||
|
|
@ -412,26 +442,7 @@ export function RoomViewHeader() {
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
<PopOut
|
{/* Members button, shown only on desktop */}
|
||||||
anchor={pinMenuAnchor}
|
|
||||||
position="Bottom"
|
|
||||||
content={
|
|
||||||
<FocusTrap
|
|
||||||
focusTrapOptions={{
|
|
||||||
initialFocus: false,
|
|
||||||
returnFocusOnDeactivate: false,
|
|
||||||
onDeactivate: () => setPinMenuAnchor(undefined),
|
|
||||||
clickOutsideDeactivates: true,
|
|
||||||
isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
|
|
||||||
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
|
|
||||||
escapeDeactivates: stopPropagation,
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<RoomPinMenu room={room} requestClose={() => setPinMenuAnchor(undefined)} />
|
|
||||||
</FocusTrap>
|
|
||||||
}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{screenSize === ScreenSize.Desktop && (
|
{screenSize === ScreenSize.Desktop && (
|
||||||
<TooltipProvider
|
<TooltipProvider
|
||||||
position="Bottom"
|
position="Bottom"
|
||||||
|
|
@ -449,6 +460,7 @@ export function RoomViewHeader() {
|
||||||
)}
|
)}
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
)}
|
)}
|
||||||
|
{/* More Options button */}
|
||||||
<TooltipProvider
|
<TooltipProvider
|
||||||
position="Bottom"
|
position="Bottom"
|
||||||
align="End"
|
align="End"
|
||||||
|
|
@ -465,28 +477,37 @@ export function RoomViewHeader() {
|
||||||
</IconButton>
|
</IconButton>
|
||||||
)}
|
)}
|
||||||
</TooltipProvider>
|
</TooltipProvider>
|
||||||
<PopOut
|
</Box>{' '}
|
||||||
anchor={menuAnchor}
|
{/* --- END OF RIGHT GROUP --- */}
|
||||||
position="Bottom"
|
{/* PopOuts render their content outside the normal flow (usually via React Portals) */}
|
||||||
align="End"
|
{/* They are placed here logically near their trigger buttons */}
|
||||||
content={
|
<PopOut
|
||||||
<FocusTrap
|
anchor={pinMenuAnchor} // Anchored to the pin button's position
|
||||||
focusTrapOptions={{
|
position="Bottom"
|
||||||
initialFocus: false,
|
content={
|
||||||
returnFocusOnDeactivate: false,
|
// FocusTrap manages keyboard focus within the menu
|
||||||
onDeactivate: () => setMenuAnchor(undefined),
|
<FocusTrap
|
||||||
clickOutsideDeactivates: true,
|
focusTrapOptions={{ /* ... focus options ... */ escapeDeactivates: stopPropagation }}
|
||||||
isKeyForward: (evt: KeyboardEvent) => evt.key === 'ArrowDown',
|
>
|
||||||
isKeyBackward: (evt: KeyboardEvent) => evt.key === 'ArrowUp',
|
<RoomPinMenu room={room} requestClose={() => setPinMenuAnchor(undefined)} />
|
||||||
escapeDeactivates: stopPropagation,
|
</FocusTrap>
|
||||||
}}
|
}
|
||||||
>
|
/>
|
||||||
<RoomMenu room={room} requestClose={() => setMenuAnchor(undefined)} />
|
<PopOut
|
||||||
</FocusTrap>
|
anchor={menuAnchor} // Anchored to the 'more options' button's position
|
||||||
}
|
position="Bottom"
|
||||||
/>
|
align="End"
|
||||||
</Box>
|
content={
|
||||||
</Box>
|
// FocusTrap manages keyboard focus within the menu
|
||||||
|
<FocusTrap
|
||||||
|
focusTrapOptions={{ /* ... focus options ... */ escapeDeactivates: stopPropagation }}
|
||||||
|
>
|
||||||
|
<RoomMenu room={room} requestClose={() => setMenuAnchor(undefined)} />
|
||||||
|
</FocusTrap>
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
</Box>{' '}
|
||||||
|
{/* --- END OF MAIN CONTAINER BOX --- */}
|
||||||
</PageHeader>
|
</PageHeader>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue