mirror of
https://github.com/revoltchat/revite.git
synced 2024-12-24 06:32:08 -05:00
feat: add corresponding UI for interactions
reactions
This commit is contained in:
parent
084c90613f
commit
dedc1e0666
1 changed files with 78 additions and 16 deletions
|
@ -2,6 +2,8 @@ import { observer } from "mobx-react-lite";
|
|||
import { Message } from "revolt.js";
|
||||
import styled, { css } from "styled-components";
|
||||
|
||||
import { useCallback } from "preact/hooks";
|
||||
|
||||
import { useClient } from "../../../../controllers/client/ClientController";
|
||||
import { RenderEmoji } from "../../../markdown/plugins/emoji";
|
||||
|
||||
|
@ -9,18 +11,35 @@ interface Props {
|
|||
message: Message;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reaction list element
|
||||
*/
|
||||
const List = styled.div`
|
||||
gap: 0.4em;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-top: 0.2em;
|
||||
align-items: center;
|
||||
`;
|
||||
|
||||
/**
|
||||
* List divider
|
||||
*/
|
||||
const Divider = styled.div`
|
||||
width: 1px;
|
||||
height: 14px;
|
||||
background: var(--tertiary-foreground);
|
||||
`;
|
||||
|
||||
/**
|
||||
* Reaction styling
|
||||
*/
|
||||
const Reaction = styled.div<{ active: boolean }>`
|
||||
padding: 0.4em;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
vertical-align: middle;
|
||||
border: 1px solid transparent;
|
||||
color: var(--secondary-foreground);
|
||||
border-radius: var(--border-radius);
|
||||
background: var(--secondary-background);
|
||||
|
@ -42,30 +61,73 @@ const Reaction = styled.div<{ active: boolean }>`
|
|||
${(props) =>
|
||||
props.active &&
|
||||
css`
|
||||
border: 1px solid var(--accent);
|
||||
border-color: var(--accent);
|
||||
`}
|
||||
`;
|
||||
|
||||
/**
|
||||
* Render reactions on a message
|
||||
*/
|
||||
export const Reactions = observer(({ message }: Props) => {
|
||||
const client = useClient();
|
||||
if (message.reactions.size === 0) return null;
|
||||
|
||||
/**
|
||||
* Render individual reaction entries
|
||||
*/
|
||||
const Entry = useCallback(
|
||||
observer(({ id, user_ids }: { id: string; user_ids?: Set<string> }) => {
|
||||
const active = user_ids?.has(client.user!._id) || false;
|
||||
|
||||
return (
|
||||
<Reaction
|
||||
active={active}
|
||||
onClick={() =>
|
||||
active ? message.unreact(id) : message.react(id)
|
||||
}>
|
||||
<RenderEmoji match={id} /> {user_ids?.size || 0}
|
||||
</Reaction>
|
||||
);
|
||||
}),
|
||||
[],
|
||||
);
|
||||
|
||||
/**
|
||||
* Determine two lists of 'required' and 'optional' reactions
|
||||
*/
|
||||
const { required, optional } = (() => {
|
||||
const required = new Set<string>();
|
||||
const optional = new Set<string>();
|
||||
|
||||
if (message.interactions?.reactions) {
|
||||
for (const reaction of message.interactions.reactions) {
|
||||
required.add(reaction);
|
||||
}
|
||||
}
|
||||
|
||||
for (const key of message.reactions.keys()) {
|
||||
if (!required.has(key)) {
|
||||
optional.add(key);
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
required,
|
||||
optional,
|
||||
};
|
||||
})();
|
||||
|
||||
// Don't render list if nothing is going to show anyways
|
||||
if (required.size === 0 && optional.size === 0) return null;
|
||||
|
||||
return (
|
||||
<List>
|
||||
{Array.from(message.reactions, ([key, user_ids]) => {
|
||||
const active = user_ids.has(client.user!._id);
|
||||
|
||||
return (
|
||||
<Reaction
|
||||
key={key}
|
||||
active={active}
|
||||
onClick={() =>
|
||||
active ? message.unreact(key) : message.react(key)
|
||||
}>
|
||||
<RenderEmoji match={key} /> {user_ids.size}
|
||||
</Reaction>
|
||||
);
|
||||
})}
|
||||
{Array.from(required, (id) => (
|
||||
<Entry key={id} id={id} user_ids={message.reactions.get(id)} />
|
||||
))}
|
||||
{required.size !== 0 && optional.size !== 0 && <Divider />}
|
||||
{Array.from(optional, (id) => (
|
||||
<Entry key={id} id={id} user_ids={message.reactions.get(id)} />
|
||||
))}
|
||||
</List>
|
||||
);
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue