mirror of
https://github.com/fromchat-messenger/web.git
synced 2026-09-22 19:15:08 +03:00
Implement formatting
This commit is contained in:
@@ -205,8 +205,16 @@
|
|||||||
|
|
||||||
.message-content {
|
.message-content {
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
margin-bottom: 0.3rem;
|
margin-bottom: 10px;
|
||||||
white-space: pre-wrap;
|
white-space: pre-wrap;
|
||||||
|
|
||||||
|
> p:first-child {
|
||||||
|
margin-block-start: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
> p:last-child {
|
||||||
|
margin-block-end: 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.quote.reply-preview {
|
.quote.reply-preview {
|
||||||
|
|||||||
@@ -2,6 +2,9 @@ import { formatTime } from "../../../utils/utils";
|
|||||||
import type { Message as MessageType } from "../../../core/types";
|
import type { Message as MessageType } from "../../../core/types";
|
||||||
import defaultAvatar from "../../../resources/images/default-avatar.png";
|
import defaultAvatar from "../../../resources/images/default-avatar.png";
|
||||||
import Quote from "../core/Quote";
|
import Quote from "../core/Quote";
|
||||||
|
import { parse } from "marked";
|
||||||
|
import DOMPurify from "dompurify";
|
||||||
|
import { useEffect, useState } from "react";
|
||||||
|
|
||||||
interface MessageProps {
|
interface MessageProps {
|
||||||
message: MessageType;
|
message: MessageType;
|
||||||
@@ -13,11 +16,23 @@ interface MessageProps {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function Message({ message, isAuthor, onProfileClick, onContextMenu, isLoadingProfile = false, isDm = false }: MessageProps) {
|
export function Message({ message, isAuthor, onProfileClick, onContextMenu, isLoadingProfile = false, isDm = false }: MessageProps) {
|
||||||
const handleContextMenu = (e: React.MouseEvent) => {
|
const [formattedMessage, setFormattedMessage] = useState({ __html: DOMPurify.sanitize(message.content).trim() });
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
(async () => {
|
||||||
|
setFormattedMessage({
|
||||||
|
__html: DOMPurify.sanitize(
|
||||||
|
await parse(message.content)
|
||||||
|
).trim()
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
}, [message]);
|
||||||
|
|
||||||
|
function handleContextMenu(e: React.MouseEvent) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
onContextMenu(e, message);
|
onContextMenu(e, message);
|
||||||
};
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -47,7 +62,7 @@ export function Message({ message, isAuthor, onProfileClick, onContextMenu, isLo
|
|||||||
<div
|
<div
|
||||||
className={`message-username ${isLoadingProfile ? "loading" : ""}`}
|
className={`message-username ${isLoadingProfile ? "loading" : ""}`}
|
||||||
onClick={() => !isLoadingProfile && onProfileClick(message.username)}
|
onClick={() => !isLoadingProfile && onProfileClick(message.username)}
|
||||||
style={{ cursor: isLoadingProfile ? "default" : "pointer" }}> {/* TODO extract to SCSS */}
|
style={{ cursor: isLoadingProfile ? "default" : "pointer" }}>
|
||||||
{message.username}
|
{message.username}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
@@ -60,17 +75,15 @@ export function Message({ message, isAuthor, onProfileClick, onContextMenu, isLo
|
|||||||
</Quote>
|
</Quote>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="message-content">
|
<div className="message-content" dangerouslySetInnerHTML={formattedMessage} />
|
||||||
{message.content}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="message-time">
|
<div className="message-time">
|
||||||
{formatTime(message.timestamp)}
|
{formatTime(message.timestamp)}
|
||||||
{message.is_edited ? " (edited)" : undefined}
|
{message.is_edited ? " (edited)" : undefined}
|
||||||
|
|
||||||
{isAuthor && message.is_read ? (
|
{isAuthor && message.is_read && (
|
||||||
<span className="material-symbols outlined"></span>
|
<span className="material-symbols outlined"></span>
|
||||||
) : undefined}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -61,6 +61,7 @@
|
|||||||
"vite-plugin-html": "^3.2.2"
|
"vite-plugin-html": "^3.2.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"dompurify": "^3.2.7",
|
||||||
"electron-squirrel-startup": "^1.0.1",
|
"electron-squirrel-startup": "^1.0.1",
|
||||||
"marked": "^16.3.0",
|
"marked": "^16.3.0",
|
||||||
"mdui": "^2.1.4",
|
"mdui": "^2.1.4",
|
||||||
|
|||||||
Reference in New Issue
Block a user