revite/src/components/common/messaging/bars/TypingIndicator.tsx

138 lines
3.6 KiB
TypeScript
Raw Normal View History

import { observer } from "mobx-react-lite";
2021-07-05 06:23:23 -04:00
import { User } from "revolt.js";
import styled from "styled-components";
import { Text } from "preact-i18n";
2021-07-05 06:23:23 -04:00
import { useContext } from "preact/hooks";
import { TextReact } from "../../../../lib/i18n";
import { useData } from "../../../../mobx/State";
2021-07-05 06:23:23 -04:00
import { connectState } from "../../../../redux/connector";
import { TypingUser } from "../../../../redux/reducers/typing";
import {
AppContext,
useClient,
} from "../../../../context/revoltjs/RevoltClient";
import { Username } from "../../user/UserShort";
interface Props {
2021-07-05 06:25:20 -04:00
typing?: TypingUser[];
}
const Base = styled.div`
2021-07-05 06:25:20 -04:00
position: relative;
> div {
height: 24px;
margin-top: -24px;
position: absolute;
gap: 8px;
display: flex;
padding: 0 10px;
user-select: none;
align-items: center;
flex-direction: row;
width: calc(100% - 3px);
color: var(--secondary-foreground);
background: var(--secondary-background);
}
.avatars {
display: flex;
img {
width: 16px;
height: 16px;
object-fit: cover;
border-radius: 50%;
&:not(:first-child) {
margin-left: -4px;
}
}
}
.usernames {
min-width: 0;
font-size: 13px;
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
`;
export const TypingIndicator = observer(({ typing }: Props) => {
2021-07-05 06:25:20 -04:00
if (typing && typing.length > 0) {
const client = useClient();
const store = useData();
const users = typing
.map((x) => store.users.get(x.id)!)
.filter((x) => typeof x !== "undefined");
2021-07-05 06:25:20 -04:00
users.sort((a, b) =>
a._id.toUpperCase().localeCompare(b._id.toUpperCase()),
);
let text;
if (users.length >= 5) {
text = <Text id="app.main.channel.typing.several" />;
} else if (users.length > 1) {
2021-07-28 09:04:27 -04:00
const userlist = [...users].map((x) => <Username user={x} />);
const user = userlist.pop();
for (let i = 0; i < userlist.length - 1; i++) {
userlist.splice(i * 2 + 1, 0, <>, </>);
}
2021-07-05 06:25:20 -04:00
text = (
<TextReact
2021-07-05 06:25:20 -04:00
id="app.main.channel.typing.multiple"
fields={{
2021-07-28 09:04:27 -04:00
user,
userlist,
2021-07-05 06:25:20 -04:00
}}
/>
);
} else {
text = (
<TextReact
2021-07-05 06:25:20 -04:00
id="app.main.channel.typing.single"
fields={{ user: <Username user={users[0]} /> }}
2021-07-05 06:25:20 -04:00
/>
);
}
return (
<Base>
<div>
<div className="avatars">
{users.map((user) => (
<img
loading="eager"
2021-07-05 06:25:20 -04:00
src={client.users.getAvatarURL(
user._id,
{ max_side: 256 },
true,
)}
/>
))}
</div>
<div className="usernames">{text}</div>
</div>
</Base>
);
}
return null;
});
export default connectState<{ id: string }>(TypingIndicator, (state, props) => {
2021-07-05 06:25:20 -04:00
return {
typing: state.typing && state.typing[props.id],
};
});