mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-22 23:20:58 -05:00
feat: list custom emojis in autocomplete
This commit is contained in:
parent
9f3e47d327
commit
35fb6b4381
1 changed files with 75 additions and 14 deletions
|
@ -1,4 +1,7 @@
|
||||||
|
/* eslint-disable @typescript-eslint/ban-ts-comment */
|
||||||
|
import { Link } from "react-router-dom";
|
||||||
import { Channel, User } from "revolt.js";
|
import { Channel, User } from "revolt.js";
|
||||||
|
import { Emoji as CustomEmoji } from "revolt.js/esm/maps/Emojis";
|
||||||
import styled, { css } from "styled-components/macro";
|
import styled, { css } from "styled-components/macro";
|
||||||
|
|
||||||
import { StateUpdater, useState } from "preact/hooks";
|
import { StateUpdater, useState } from "preact/hooks";
|
||||||
|
@ -7,6 +10,8 @@ import { emojiDictionary } from "../../assets/emojis";
|
||||||
import { useClient } from "../../controllers/client/ClientController";
|
import { useClient } from "../../controllers/client/ClientController";
|
||||||
import ChannelIcon from "./ChannelIcon";
|
import ChannelIcon from "./ChannelIcon";
|
||||||
import Emoji from "./Emoji";
|
import Emoji from "./Emoji";
|
||||||
|
import ServerIcon from "./ServerIcon";
|
||||||
|
import Tooltip from "./Tooltip";
|
||||||
import UserIcon from "./user/UserIcon";
|
import UserIcon from "./user/UserIcon";
|
||||||
|
|
||||||
export type AutoCompleteState =
|
export type AutoCompleteState =
|
||||||
|
@ -14,7 +19,7 @@ export type AutoCompleteState =
|
||||||
| ({ selected: number; within: boolean } & (
|
| ({ selected: number; within: boolean } & (
|
||||||
| {
|
| {
|
||||||
type: "emoji";
|
type: "emoji";
|
||||||
matches: string[];
|
matches: (string | CustomEmoji)[];
|
||||||
}
|
}
|
||||||
| {
|
| {
|
||||||
type: "user";
|
type: "user";
|
||||||
|
@ -104,16 +109,23 @@ export function useAutoComplete(
|
||||||
|
|
||||||
if (type === "emoji") {
|
if (type === "emoji") {
|
||||||
// ! TODO: we should convert it to a Binary Search Tree and use that
|
// ! TODO: we should convert it to a Binary Search Tree and use that
|
||||||
const matches = Object.keys(emojiDictionary)
|
const matches = [
|
||||||
.filter((emoji: string) => emoji.match(regex))
|
...Object.keys(emojiDictionary).filter((emoji: string) =>
|
||||||
.splice(0, 5);
|
emoji.match(regex),
|
||||||
|
),
|
||||||
|
...Array.from(client.emojis.values()).filter((emoji) =>
|
||||||
|
emoji.name.match(regex),
|
||||||
|
),
|
||||||
|
].splice(0, 5);
|
||||||
|
|
||||||
if (matches.length > 0) {
|
if (matches.length > 0) {
|
||||||
const currentPosition =
|
const currentPosition =
|
||||||
state.type !== "none" ? state.selected : 0;
|
state.type !== "none" ? state.selected : 0;
|
||||||
|
|
||||||
setState({
|
setState({
|
||||||
|
// @ts-ignore-next-line are you high
|
||||||
type: "emoji",
|
type: "emoji",
|
||||||
|
// @ts-ignore-next-line
|
||||||
matches,
|
matches,
|
||||||
selected: Math.min(currentPosition, matches.length - 1),
|
selected: Math.min(currentPosition, matches.length - 1),
|
||||||
within: false,
|
within: false,
|
||||||
|
@ -233,10 +245,13 @@ export function useAutoComplete(
|
||||||
|
|
||||||
const content = el.value.split("");
|
const content = el.value.split("");
|
||||||
if (state.type === "emoji") {
|
if (state.type === "emoji") {
|
||||||
|
const selected = state.matches[state.selected];
|
||||||
content.splice(
|
content.splice(
|
||||||
index,
|
index,
|
||||||
search.length,
|
search.length,
|
||||||
state.matches[state.selected],
|
selected instanceof CustomEmoji
|
||||||
|
? selected._id
|
||||||
|
: selected,
|
||||||
": ",
|
": ",
|
||||||
);
|
);
|
||||||
} else if (state.type === "user") {
|
} else if (state.type === "user") {
|
||||||
|
@ -388,12 +403,17 @@ export default function AutoComplete({
|
||||||
setState,
|
setState,
|
||||||
onClick,
|
onClick,
|
||||||
}: Pick<AutoCompleteProps, "detached" | "state" | "setState" | "onClick">) {
|
}: Pick<AutoCompleteProps, "detached" | "state" | "setState" | "onClick">) {
|
||||||
|
const client = useClient();
|
||||||
return (
|
return (
|
||||||
<Base detached={detached}>
|
<Base detached={detached}>
|
||||||
<div>
|
<div>
|
||||||
{state.type === "emoji" &&
|
{state.type === "emoji" &&
|
||||||
state.matches.map((match, i) => (
|
state.matches.map((match, i) => (
|
||||||
<button
|
<button
|
||||||
|
style={{
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
}}
|
||||||
key={match}
|
key={match}
|
||||||
className={i === state.selected ? "active" : ""}
|
className={i === state.selected ? "active" : ""}
|
||||||
onMouseEnter={() =>
|
onMouseEnter={() =>
|
||||||
|
@ -412,15 +432,56 @@ export default function AutoComplete({
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
onClick={onClick}>
|
onClick={onClick}>
|
||||||
<Emoji
|
<div>
|
||||||
emoji={
|
{match instanceof CustomEmoji ? (
|
||||||
(emojiDictionary as Record<string, string>)[
|
<img
|
||||||
match
|
loading="lazy"
|
||||||
]
|
src={match.imageURL}
|
||||||
}
|
style={{
|
||||||
size={20}
|
width: `20px`,
|
||||||
/>
|
height: `20px`,
|
||||||
:{match}:
|
}}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<Emoji
|
||||||
|
emoji={
|
||||||
|
(
|
||||||
|
emojiDictionary as Record<
|
||||||
|
string,
|
||||||
|
string
|
||||||
|
>
|
||||||
|
)[match]
|
||||||
|
}
|
||||||
|
size={20}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
{`:${
|
||||||
|
match instanceof CustomEmoji
|
||||||
|
? match.name
|
||||||
|
: match
|
||||||
|
}:`}
|
||||||
|
</div>
|
||||||
|
{match instanceof CustomEmoji &&
|
||||||
|
match.parent.type == "Server" && (
|
||||||
|
<>
|
||||||
|
<Tooltip
|
||||||
|
content={
|
||||||
|
client.servers.get(
|
||||||
|
match.parent.id,
|
||||||
|
)?.name
|
||||||
|
}>
|
||||||
|
<Link
|
||||||
|
to={`/server/${match.parent.id}`}>
|
||||||
|
<ServerIcon
|
||||||
|
target={client.servers.get(
|
||||||
|
match.parent.id,
|
||||||
|
)}
|
||||||
|
size={20}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
{state.type === "user" &&
|
{state.type === "user" &&
|
||||||
|
|
Loading…
Reference in a new issue