feat(messaging): quick action bar (#493)

Co-authored-by: Kuhn Chris <kuhnchris+github@kuhnchris.eu>
Co-authored-by: Paul Makles <paulmakles@gmail.com>
This commit is contained in:
KuhnChris 2022-01-14 22:03:52 +01:00 committed by GitHub
parent fe382f9532
commit f509acbe80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 130 additions and 2 deletions

View file

@ -25,6 +25,7 @@ import MessageBase, {
} from "./MessageBase"; } from "./MessageBase";
import Attachment from "./attachments/Attachment"; import Attachment from "./attachments/Attachment";
import { MessageReply } from "./attachments/MessageReply"; import { MessageReply } from "./attachments/MessageReply";
import { MessageOverlayBar } from "./bars/MessageOverlayBar";
import Embed from "./embed/Embed"; import Embed from "./embed/Embed";
import InviteList from "./embed/EmbedInvite"; import InviteList from "./embed/EmbedInvite";
@ -86,7 +87,7 @@ const Message = observer(
}; };
// ! FIXME(?): animate on hover // ! FIXME(?): animate on hover
const [animate, setAnimate] = useState(false); const [mouseHovering, setAnimate] = useState(false);
return ( return (
<div id={message._id}> <div id={message._id}>
@ -135,7 +136,7 @@ const Message = observer(
size={36} size={36}
onContextMenu={userContext} onContextMenu={userContext}
onClick={handleUserClick} onClick={handleUserClick}
animate={animate} animate={mouseHovering}
showServerIdentity showServerIdentity
/> />
) : ( ) : (
@ -174,6 +175,12 @@ const Message = observer(
{message.embeds?.map((embed, index) => ( {message.embeds?.map((embed, index) => (
<Embed key={index} embed={embed} /> <Embed key={index} embed={embed} />
))} ))}
{mouseHovering && !replacement && (
<MessageOverlayBar
message={message}
queued={queued}
/>
)}
</MessageContent> </MessageContent>
</MessageBase> </MessageBase>
</div> </div>

View file

@ -195,6 +195,10 @@ export const MessageInfo = styled.div`
`; `;
export const MessageContent = styled.div` export const MessageContent = styled.div`
// Position relatively so we can put
// the overlay in the right place.
position: relative;
min-width: 0; min-width: 0;
flex-grow: 1; flex-grow: 1;
display: flex; display: flex;

View file

@ -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 (
<OverlayBar>
<Entry onClick={() => internalEmit("ReplyBar", "add", message)}>
<IconButton>
<Reply size={24} />
</IconButton>
</Entry>
{isAuthor && (
<Entry
onClick={() =>
internalEmit(
"MessageRenderer",
"edit_message",
message._id,
)
}>
<IconButton>
<Edit size={24} />
</IconButton>
</Entry>
)}
{isAuthor ||
(message.channel &&
message.channel.permission &
ChannelPermission.ManageMessages) ? (
<Entry
onClick={() =>
openScreen({
id: "special_prompt",
type: "delete_message",
target: message,
} as unknown as Screen)
}>
<IconButton>
<Trash size={24} />
</IconButton>
</Entry>
) : undefined}
<Entry
onClick={() =>
openContextMenu("Menu", {
message,
contextualChannel: message.channel_id,
queued,
})
}>
<IconButton>
<DotsHorizontalRounded size={24} />
</IconButton>
</Entry>
</OverlayBar>
);
});