mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Improve animation
This commit is contained in:
@@ -420,6 +420,14 @@
|
|||||||
min-width: 160px;
|
min-width: 160px;
|
||||||
z-index: 1000;
|
z-index: 1000;
|
||||||
|
|
||||||
|
&.entering {
|
||||||
|
animation: fadeInDown 0.2s ease forwards;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.closing {
|
||||||
|
animation: fadeOutUp 0.2s ease forwards;
|
||||||
|
}
|
||||||
|
|
||||||
.context-menu-item {
|
.context-menu-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -6,12 +6,10 @@ import type { UserProfile } from "../../../core/types";
|
|||||||
import { UserProfileDialog } from "./UserProfileDialog";
|
import { UserProfileDialog } from "./UserProfileDialog";
|
||||||
import { MessageContextMenu, type ContextMenuState } from "./MessageContextMenu";
|
import { MessageContextMenu, type ContextMenuState } from "./MessageContextMenu";
|
||||||
import { fetchUserProfile } from "../../api/profileApi";
|
import { fetchUserProfile } from "../../api/profileApi";
|
||||||
import { useState } from "react";
|
import { useState, useEffect } from "react";
|
||||||
import { delay } from "../../../utils/utils";
|
import { delay } from "../../../utils/utils";
|
||||||
import { request } from "../../../websocket";
|
import { request } from "../../../websocket";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
export function ChatMessages() {
|
export function ChatMessages() {
|
||||||
const { messages } = useChat();
|
const { messages } = useChat();
|
||||||
const { user } = useAppState();
|
const { user } = useAppState();
|
||||||
@@ -26,6 +24,44 @@ export function ChatMessages() {
|
|||||||
position: { x: 0, y: 0 }
|
position: { x: 0, y: 0 }
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Effect to handle clicks outside the context menu
|
||||||
|
useEffect(() => {
|
||||||
|
const handleClickOutside = (event: MouseEvent) => {
|
||||||
|
if (contextMenu.isOpen) {
|
||||||
|
// Check if the click is on a context menu element
|
||||||
|
const target = event.target as Element;
|
||||||
|
if (!target.closest('.context-menu')) {
|
||||||
|
handleContextMenuClose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleKeyDown = (event: KeyboardEvent) => {
|
||||||
|
if (event.key === 'Escape' && contextMenu.isOpen) {
|
||||||
|
handleContextMenuClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleWindowBlur = () => {
|
||||||
|
// Close context menu when browser window loses focus
|
||||||
|
if (contextMenu.isOpen) {
|
||||||
|
handleContextMenuClose();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add event listeners
|
||||||
|
document.addEventListener('mousedown', handleClickOutside);
|
||||||
|
document.addEventListener('keydown', handleKeyDown);
|
||||||
|
window.addEventListener('blur', handleWindowBlur);
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('mousedown', handleClickOutside);
|
||||||
|
document.removeEventListener('keydown', handleKeyDown);
|
||||||
|
window.removeEventListener('blur', handleWindowBlur);
|
||||||
|
};
|
||||||
|
}, [contextMenu.isOpen]);
|
||||||
|
|
||||||
const handleProfileClick = async (username: string) => {
|
const handleProfileClick = async (username: string) => {
|
||||||
if (!user.authToken) return;
|
if (!user.authToken) return;
|
||||||
|
|
||||||
@@ -120,19 +156,9 @@ export function ChatMessages() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Close context menu when clicking outside
|
|
||||||
const handleClickOutside = (e: React.MouseEvent) => {
|
|
||||||
if (contextMenu.isOpen) {
|
|
||||||
// Only close if clicking on the chat messages container, not on the context menu itself
|
|
||||||
if (e.target === e.currentTarget) {
|
|
||||||
handleContextMenuClose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="chat-messages" id="chat-messages" onClick={handleClickOutside}>
|
<div className="chat-messages" id="chat-messages">
|
||||||
{messages.map((message) => (
|
{messages.map((message) => (
|
||||||
<Message
|
<Message
|
||||||
key={message.id}
|
key={message.id}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ export function MessageContextMenu({
|
|||||||
// Internal state for dialogs
|
// Internal state for dialogs
|
||||||
const [editDialogOpen, setEditDialogOpen] = useState(false);
|
const [editDialogOpen, setEditDialogOpen] = useState(false);
|
||||||
const [replyDialogOpen, setReplyDialogOpen] = useState(false);
|
const [replyDialogOpen, setReplyDialogOpen] = useState(false);
|
||||||
|
const [isClosing, setIsClosing] = useState(false);
|
||||||
|
|
||||||
const handleAction = (action: string) => {
|
const handleAction = (action: string) => {
|
||||||
console.log("Context menu action triggered:", action);
|
console.log("Context menu action triggered:", action);
|
||||||
@@ -48,12 +49,20 @@ export function MessageContextMenu({
|
|||||||
case "delete":
|
case "delete":
|
||||||
if (isAuthor) {
|
if (isAuthor) {
|
||||||
onDelete(message);
|
onDelete(message);
|
||||||
onClose();
|
handleClose();
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleClose = () => {
|
||||||
|
setIsClosing(true);
|
||||||
|
// Wait for animation to complete before calling onClose
|
||||||
|
setTimeout(() => {
|
||||||
|
onClose();
|
||||||
|
}, 200); // Match the animation duration from _animations.scss
|
||||||
|
};
|
||||||
|
|
||||||
const handleEditSave = (messageId: number, newContent: string) => {
|
const handleEditSave = (messageId: number, newContent: string) => {
|
||||||
// Create a temporary message object with the updated content
|
// Create a temporary message object with the updated content
|
||||||
const updatedMessage = { ...message, content: newContent };
|
const updatedMessage = { ...message, content: newContent };
|
||||||
@@ -71,7 +80,7 @@ export function MessageContextMenu({
|
|||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div
|
<div
|
||||||
className="context-menu"
|
className={`context-menu ${isClosing ? 'closing' : 'entering'}`}
|
||||||
style={{
|
style={{
|
||||||
position: "fixed",
|
position: "fixed",
|
||||||
display: "block",
|
display: "block",
|
||||||
|
|||||||
Reference in New Issue
Block a user