diff --git a/src/components/common/messaging/Message.tsx b/src/components/common/messaging/Message.tsx
index 778e932c..68517fd3 100644
--- a/src/components/common/messaging/Message.tsx
+++ b/src/components/common/messaging/Message.tsx
@@ -25,6 +25,7 @@ import MessageBase, {
} from "./MessageBase";
import Attachment from "./attachments/Attachment";
import { MessageReply } from "./attachments/MessageReply";
+import { MessageOverlayBar } from "./bars/MessageOverlayBar";
import Embed from "./embed/Embed";
import InviteList from "./embed/EmbedInvite";
@@ -86,7 +87,7 @@ const Message = observer(
};
// ! FIXME(?): animate on hover
- const [animate, setAnimate] = useState(false);
+ const [mouseHovering, setAnimate] = useState(false);
return (
@@ -135,7 +136,7 @@ const Message = observer(
size={36}
onContextMenu={userContext}
onClick={handleUserClick}
- animate={animate}
+ animate={mouseHovering}
showServerIdentity
/>
) : (
@@ -174,6 +175,12 @@ const Message = observer(
{message.embeds?.map((embed, index) => (
))}
+ {mouseHovering && !replacement && (
+
+ )}
diff --git a/src/components/common/messaging/MessageBase.tsx b/src/components/common/messaging/MessageBase.tsx
index e970a4ab..33a3471e 100644
--- a/src/components/common/messaging/MessageBase.tsx
+++ b/src/components/common/messaging/MessageBase.tsx
@@ -195,6 +195,10 @@ export const MessageInfo = styled.div`
`;
export const MessageContent = styled.div`
+ // Position relatively so we can put
+ // the overlay in the right place.
+ position: relative;
+
min-width: 0;
flex-grow: 1;
display: flex;
diff --git a/src/components/common/messaging/bars/MessageOverlayBar.tsx b/src/components/common/messaging/bars/MessageOverlayBar.tsx
new file mode 100644
index 00000000..848a1bff
--- /dev/null
+++ b/src/components/common/messaging/bars/MessageOverlayBar.tsx
@@ -0,0 +1,117 @@
+import {
+ DotsHorizontalRounded,
+ Edit,
+ Reply,
+ Trash,
+} from "@styled-icons/boxicons-regular";
+import { observer } from "mobx-react-lite";
+import { ChannelPermission } from "revolt.js";
+import { Message as MessageObject } from "revolt.js/dist/maps/Messages";
+import styled from "styled-components";
+
+import { openContextMenu } from "preact-context-menu";
+
+import { internalEmit } from "../../../../lib/eventEmitter";
+
+import { QueuedMessage } from "../../../../mobx/stores/MessageQueue";
+
+import {
+ Screen,
+ useIntermediate,
+} from "../../../../context/intermediate/Intermediate";
+import { useClient } from "../../../../context/revoltjs/RevoltClient";
+
+import IconButton from "../../../ui/IconButton";
+
+interface Props {
+ message: MessageObject;
+ queued?: QueuedMessage;
+}
+
+const OverlayBar = styled.div`
+ display: inline-flex;
+ position: absolute;
+ justify-self: end;
+ align-self: end;
+ align-content: center;
+ justify-content: center;
+
+ right: 0;
+ top: -18px;
+ z-index: 0;
+ overflow: hidden;
+
+ border-radius: 5px;
+ background: var(--primary-header);
+ border: 1px sold var(--background);
+`;
+
+const Entry = styled.div`
+ padding: 4px;
+ flex-shrink: 0;
+ cursor: pointer;
+ transition: 0.2s ease background-color;
+
+ &:hover {
+ background: var(--secondary-header);
+ }
+`;
+
+export const MessageOverlayBar = observer(({ message, queued }: Props) => {
+ const client = useClient();
+ const { openScreen } = useIntermediate();
+ const isAuthor = message.author_id === client.user!._id;
+
+ return (
+
+ internalEmit("ReplyBar", "add", message)}>
+
+
+
+
+ {isAuthor && (
+
+ internalEmit(
+ "MessageRenderer",
+ "edit_message",
+ message._id,
+ )
+ }>
+
+
+
+
+ )}
+ {isAuthor ||
+ (message.channel &&
+ message.channel.permission &
+ ChannelPermission.ManageMessages) ? (
+
+ openScreen({
+ id: "special_prompt",
+ type: "delete_message",
+ target: message,
+ } as unknown as Screen)
+ }>
+
+
+
+
+ ) : undefined}
+
+ openContextMenu("Menu", {
+ message,
+ contextualChannel: message.channel_id,
+ queued,
+ })
+ }>
+
+
+
+
+
+ );
+});