mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Clean up
This commit is contained in:
@@ -68,4 +68,4 @@ export function optimizeCssModules(options?: OptimizeCssModuleOptions): Plugin {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
};
|
};
|
||||||
};
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
import type { Dialog as MduiDialog } from "mdui/components/dialog";
|
|
||||||
import { useEffect, type Ref } from "react"
|
|
||||||
import { createPortal } from "react-dom";
|
|
||||||
import { id } from "@/utils/utils";
|
|
||||||
import useCombinedRefs from "@/core/hooks/useCombinedRefs";
|
|
||||||
|
|
||||||
export interface BaseDialogProps {
|
|
||||||
onOpenChange: (value: boolean) => void;
|
|
||||||
ref?: Ref<MduiDialog & HTMLElement>
|
|
||||||
}
|
|
||||||
|
|
||||||
export type FullDialogProps = React.ComponentPropsWithoutRef<"mdui-dialog"> & BaseDialogProps;
|
|
||||||
|
|
||||||
export function MaterialDialog(props: FullDialogProps) {
|
|
||||||
const [setDialogRef, dialogRef] = useCombinedRefs(props.ref);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const dialog = dialogRef.current;
|
|
||||||
if (!dialog) return;
|
|
||||||
|
|
||||||
const observer = new MutationObserver((mutations) => {
|
|
||||||
mutations.forEach((mutation) => {
|
|
||||||
if (mutation.type === "attributes" && mutation.attributeName === "open") {
|
|
||||||
const isOpen = dialog.hasAttribute("open");
|
|
||||||
if (isOpen !== props.open) {
|
|
||||||
props.onOpenChange(isOpen);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
// Start observing the dialog element for attribute changes
|
|
||||||
observer.observe(dialog, {
|
|
||||||
attributes: true,
|
|
||||||
attributeFilter: ["open"]
|
|
||||||
});
|
|
||||||
|
|
||||||
// Cleanup observer
|
|
||||||
return () => {
|
|
||||||
observer.disconnect();
|
|
||||||
};
|
|
||||||
}, [dialogRef.current, props.open, props.onOpenChange]);
|
|
||||||
|
|
||||||
return createPortal(<mdui-dialog {...props} ref={setDialogRef} />, id("root"));
|
|
||||||
}
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
@keyframes fadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.fade-in {
|
|
||||||
animation: fadeIn 0.3s ease forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeOutUp {
|
|
||||||
from {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInDown {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInLeft {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeInUpLeft {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate(10px, 10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translate(0, 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeOutRight {
|
|
||||||
from {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(10px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeOutDown {
|
|
||||||
from {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(10px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes fadeOutDownRight {
|
|
||||||
from {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translate(0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translate(10px, 10px);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-switch-out {
|
|
||||||
animation: fadeOutUp 0.2s ease forwards;
|
|
||||||
}
|
|
||||||
|
|
||||||
.chat-switch-in {
|
|
||||||
animation: fadeInDown 0.2s ease forwards;
|
|
||||||
}
|
|
||||||
@@ -169,12 +169,6 @@ button, input {
|
|||||||
justify-content: center;
|
justify-content: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
.search-result-headline {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
gap: 6px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.dm-list-headline {
|
.dm-list-headline {
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
@use "animations";
|
|
||||||
@use "components";
|
@use "components";
|
||||||
@use "colors" as *;
|
@use "colors" as *;
|
||||||
@use "material" as *;
|
@use "material" as *;
|
||||||
@@ -32,16 +31,6 @@ body, #root {
|
|||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
}
|
}
|
||||||
|
|
||||||
mdui-dialog {
|
|
||||||
> *:first-child {
|
|
||||||
margin-block-start: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
> *:last-child {
|
|
||||||
margin-block-end: 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
mdui-icon {
|
mdui-icon {
|
||||||
user-select: none;
|
user-select: none;
|
||||||
}
|
}
|
||||||
@@ -1,184 +0,0 @@
|
|||||||
@use "../../../css/colors" as *;
|
|
||||||
@use "../../../css/material" as *;
|
|
||||||
@use "sass:color";
|
|
||||||
|
|
||||||
// Animation for reactions appearing/disappearing
|
|
||||||
@keyframes messageReactionsFadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-10px);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionFadeIn {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionFadeOut {
|
|
||||||
from {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Context menu wrapper animations
|
|
||||||
@keyframes contextMenuEnter {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes contextMenuEnterLeft {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0) scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes contextMenuEnterUp {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0) scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes contextMenuEnterUpLeft {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0) translateY(0) scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes contextMenuClose {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scale(0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes contextMenuCloseLeft {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(-20px) scale(0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes contextMenuCloseUp {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(20px) scale(0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes contextMenuCloseUpLeft {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(-20px) translateY(20px) scale(0.8);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes emojiMenuEnter {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes emojiMenuEnterDown {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scaleY(0);
|
|
||||||
transform-origin: top;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scaleY(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes emojiMenuEnterUp {
|
|
||||||
from {
|
|
||||||
opacity: 0;
|
|
||||||
transform: scaleY(0);
|
|
||||||
transform-origin: bottom;
|
|
||||||
}
|
|
||||||
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: scaleY(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reaction bar animations
|
|
||||||
@keyframes reactionBarEnter {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0) scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionBarEnterLeft {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0) translateY(0) scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionBarEnterUp {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateY(0) scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionBarEnterRight {
|
|
||||||
to {
|
|
||||||
opacity: 1;
|
|
||||||
transform: translateX(0) scale(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionBarClose {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(-20px) scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionBarCloseLeft {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateX(-20px) translateY(-20px) scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@keyframes reactionBarCloseUp {
|
|
||||||
to {
|
|
||||||
opacity: 0;
|
|
||||||
transform: translateY(20px) scale(0.9);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -73,6 +73,13 @@
|
|||||||
&.dragging {
|
&.dragging {
|
||||||
cursor: grabbing;
|
cursor: grabbing;
|
||||||
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7);
|
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.7);
|
||||||
|
transition: width 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
height 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
background-color 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
backdrop-filter 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
border 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
border-radius 0.4s cubic-bezier(0.4, 0, 0.2, 1),
|
||||||
|
box-shadow 0.4s cubic-bezier(0.4, 0, 0.2, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
.callHeader {
|
.callHeader {
|
||||||
|
|||||||
@@ -1,13 +1,13 @@
|
|||||||
import { useState, useEffect, useRef } from "react";
|
import { useState, useEffect, useRef } from "react";
|
||||||
import { motion, AnimatePresence } from "motion/react";
|
import { motion, AnimatePresence } from "motion/react";
|
||||||
import { MaterialDialog } from "@/core/components/Dialog";
|
|
||||||
import { RichTextArea } from "@/core/components/RichTextArea";
|
import { RichTextArea } from "@/core/components/RichTextArea";
|
||||||
import type { Message } from "@/core/types";
|
import type { Message } from "@/core/types";
|
||||||
import Quote from "@/core/components/Quote";
|
import Quote from "@/core/components/Quote";
|
||||||
import { useImmer } from "use-immer";
|
import { useImmer } from "use-immer";
|
||||||
import { EmojiMenu } from "./EmojiMenu";
|
import { EmojiMenu } from "./EmojiMenu";
|
||||||
import { MaterialButton, MaterialIcon, MaterialIconButton } from "@/utils/material";
|
import { MaterialIcon, MaterialIconButton } from "@/utils/material";
|
||||||
import styles from "@/pages/chat/css/ChatInput.module.scss";
|
import styles from "@/pages/chat/css/ChatInput.module.scss";
|
||||||
|
import { alert } from "mdui/functions/alert";
|
||||||
|
|
||||||
interface ChatInputWrapperProps {
|
interface ChatInputWrapperProps {
|
||||||
onSendMessage: (message: string, files: File[]) => void;
|
onSendMessage: (message: string, files: File[]) => void;
|
||||||
@@ -47,7 +47,6 @@ export function ChatInputWrapper(
|
|||||||
const [message, setMessage] = useState("");
|
const [message, setMessage] = useState("");
|
||||||
const [selectedFiles, setSelectedFiles] = useImmer<File[]>([]);
|
const [selectedFiles, setSelectedFiles] = useImmer<File[]>([]);
|
||||||
const [attachmentsVisible, setAttachmentsVisible] = useState(false);
|
const [attachmentsVisible, setAttachmentsVisible] = useState(false);
|
||||||
const [errorOpen, setErrorOpen] = useState(false);
|
|
||||||
const [emojiMenuOpen, setEmojiMenuOpen] = useState(false);
|
const [emojiMenuOpen, setEmojiMenuOpen] = useState(false);
|
||||||
const [emojiMenuPosition, setEmojiMenuPosition] = useState({ x: 0, y: 0 });
|
const [emojiMenuPosition, setEmojiMenuPosition] = useState({ x: 0, y: 0 });
|
||||||
const chatInputWrapperRef = useRef<HTMLDivElement>(null);
|
const chatInputWrapperRef = useRef<HTMLDivElement>(null);
|
||||||
@@ -116,9 +115,13 @@ export function ChatInputWrapper(
|
|||||||
const totalSize = selectedFiles.reduce((acc, f) => acc + f.size, 0);
|
const totalSize = selectedFiles.reduce((acc, f) => acc + f.size, 0);
|
||||||
const limit = 4 * 1024 * 1024 * 1024; // 4GB
|
const limit = 4 * 1024 * 1024 * 1024; // 4GB
|
||||||
if (totalSize > limit) {
|
if (totalSize > limit) {
|
||||||
setErrorOpen(true);
|
alert({
|
||||||
|
headline: "Ошибка",
|
||||||
|
description: "Общий размер вложений превышает 4 ГБ."
|
||||||
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (editingMessage && onSaveEdit) {
|
if (editingMessage && onSaveEdit) {
|
||||||
onSaveEdit(message);
|
onSaveEdit(message);
|
||||||
setMessage("");
|
setMessage("");
|
||||||
@@ -249,11 +252,6 @@ export function ChatInputWrapper(
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<MaterialDialog open={errorOpen} onOpenChange={setErrorOpen} close-on-overlay-click close-on-esc>
|
|
||||||
<div slot="headline">Ошибка</div>
|
|
||||||
<div>Общий размер вложений превышает 4 ГБ.</div>
|
|
||||||
<MaterialButton slot="action" onClick={() => setErrorOpen(false)}>Закрыть</MaterialButton>
|
|
||||||
</MaterialDialog>
|
|
||||||
|
|
||||||
<EmojiMenu
|
<EmojiMenu
|
||||||
isOpen={emojiMenuOpen}
|
isOpen={emojiMenuOpen}
|
||||||
|
|||||||
@@ -132,13 +132,13 @@ export function CallWindow() {
|
|||||||
style={isMinimized ? {
|
style={isMinimized ? {
|
||||||
left: pipPosition.x,
|
left: pipPosition.x,
|
||||||
top: pipPosition.y
|
top: pipPosition.y
|
||||||
} : undefined}
|
} : {}}
|
||||||
initial={false}
|
initial={false}
|
||||||
exit={isMinimized ?
|
exit={isMinimized ?
|
||||||
{ opacity: 0, scale: 0.7 } :
|
{ opacity: 0, scale: 0.7 } :
|
||||||
{ opacity: 0, y: -100 }
|
{ opacity: 0, y: -100 }
|
||||||
}
|
}
|
||||||
transition={{
|
transition={isDragging ? { duration: 0 } : {
|
||||||
opacity: { duration: 0.4 },
|
opacity: { duration: 0.4 },
|
||||||
scale: { duration: 0.4 },
|
scale: { duration: 0.4 },
|
||||||
y: { duration: 0.4 }
|
y: { duration: 0.4 }
|
||||||
|
|||||||
Reference in New Issue
Block a user