This commit is contained in:
2025-11-02 20:48:00 +03:00
Unverified
parent 2b316de17e
commit 852ab15bd8
9 changed files with 17 additions and 377 deletions
+1 -1
View File
@@ -68,4 +68,4 @@ export function optimizeCssModules(options?: OptimizeCssModuleOptions): Plugin {
} }
}) })
}; };
}; }
-45
View File
@@ -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"));
}
-119
View File
@@ -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;
}
-6
View File
@@ -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;
-11
View File
@@ -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 }