mirror of
https://github.com/revoltchat/revite.git
synced 2024-11-25 08:30:58 -05:00
feat: add reaction button to overlay
This commit is contained in:
parent
e1d3ad1675
commit
58f294b790
9 changed files with 334 additions and 129 deletions
|
@ -43,6 +43,8 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@floating-ui/react-dom": "^0.7.2",
|
||||||
|
"@floating-ui/react-dom-interactions": "^0.7.0",
|
||||||
"fs-extra": "^10.0.0",
|
"fs-extra": "^10.0.0",
|
||||||
"klaw": "^3.0.0",
|
"klaw": "^3.0.0",
|
||||||
"sirv-cli": "^1.0.14",
|
"sirv-cli": "^1.0.14",
|
||||||
|
|
|
@ -5,7 +5,7 @@ import { useTriggerEvents } from "preact-context-menu";
|
||||||
import { memo } from "preact/compat";
|
import { memo } from "preact/compat";
|
||||||
import { useEffect, useState } from "preact/hooks";
|
import { useEffect, useState } from "preact/hooks";
|
||||||
|
|
||||||
import { Category } from "@revoltchat/ui";
|
import { Category, Button } from "@revoltchat/ui";
|
||||||
|
|
||||||
import { internalEmit } from "../../../lib/eventEmitter";
|
import { internalEmit } from "../../../lib/eventEmitter";
|
||||||
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
|
import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice";
|
||||||
|
@ -88,6 +88,7 @@ const Message = observer(
|
||||||
|
|
||||||
// ! FIXME(?): animate on hover
|
// ! FIXME(?): animate on hover
|
||||||
const [mouseHovering, setAnimate] = useState(false);
|
const [mouseHovering, setAnimate] = useState(false);
|
||||||
|
const [reactionsOpen, setReactionsOpen] = useState(false);
|
||||||
useEffect(() => setAnimate(false), [replacement]);
|
useEffect(() => setAnimate(false), [replacement]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -182,10 +183,12 @@ const Message = observer(
|
||||||
<Embed key={index} embed={embed} />
|
<Embed key={index} embed={embed} />
|
||||||
))}
|
))}
|
||||||
<Reactions message={message} />
|
<Reactions message={message} />
|
||||||
{mouseHovering &&
|
{(mouseHovering || reactionsOpen) &&
|
||||||
!replacement &&
|
!replacement &&
|
||||||
!isTouchscreenDevice && (
|
!isTouchscreenDevice && (
|
||||||
<MessageOverlayBar
|
<MessageOverlayBar
|
||||||
|
reactionsOpen={reactionsOpen}
|
||||||
|
setReactionsOpen={setReactionsOpen}
|
||||||
message={message}
|
message={message}
|
||||||
queued={queued}
|
queued={queued}
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -26,7 +26,10 @@ import { state, useApplicationState } from "../../../mobx/State";
|
||||||
import { Reply } from "../../../mobx/stores/MessageQueue";
|
import { Reply } from "../../../mobx/stores/MessageQueue";
|
||||||
|
|
||||||
import { emojiDictionary } from "../../../assets/emojis";
|
import { emojiDictionary } from "../../../assets/emojis";
|
||||||
import { useClient } from "../../../controllers/client/ClientController";
|
import {
|
||||||
|
clientController,
|
||||||
|
useClient,
|
||||||
|
} from "../../../controllers/client/ClientController";
|
||||||
import { takeError } from "../../../controllers/client/jsx/error";
|
import { takeError } from "../../../controllers/client/jsx/error";
|
||||||
import {
|
import {
|
||||||
FileUploader,
|
FileUploader,
|
||||||
|
@ -143,8 +146,14 @@ const RE_SED = new RegExp("^s/([^])*/([^])*$");
|
||||||
// Tests for code block delimiters (``` at start of line)
|
// Tests for code block delimiters (``` at start of line)
|
||||||
const RE_CODE_DELIMITER = new RegExp("^```", "gm");
|
const RE_CODE_DELIMITER = new RegExp("^```", "gm");
|
||||||
|
|
||||||
const HackAlertThisFileWillBeReplaced = observer(
|
export const HackAlertThisFileWillBeReplaced = observer(
|
||||||
({ channel, onClose }: Props & { onClose: () => void }) => {
|
({
|
||||||
|
onSelect,
|
||||||
|
onClose,
|
||||||
|
}: {
|
||||||
|
onSelect: (emoji: string) => void;
|
||||||
|
onClose: () => void;
|
||||||
|
}) => {
|
||||||
const renderEmoji = useMemo(
|
const renderEmoji = useMemo(
|
||||||
() =>
|
() =>
|
||||||
memo(({ emoji }: { emoji: string }) => (
|
memo(({ emoji }: { emoji: string }) => (
|
||||||
|
@ -162,8 +171,12 @@ const HackAlertThisFileWillBeReplaced = observer(
|
||||||
|
|
||||||
for (const server of state.ordering.orderedServers) {
|
for (const server of state.ordering.orderedServers) {
|
||||||
// ! FIXME: add a separate map on each server for emoji
|
// ! FIXME: add a separate map on each server for emoji
|
||||||
const list = [...channel.client.emojis.values()]
|
const list = [...clientController.getReadyClient()!.emojis.values()]
|
||||||
.filter((emoji) => emoji.parent.id === server._id)
|
.filter(
|
||||||
|
(emoji) =>
|
||||||
|
emoji.parent.type !== "Detached" &&
|
||||||
|
emoji.parent.id === server._id,
|
||||||
|
)
|
||||||
.map(({ _id, name }) => ({ id: _id, name }));
|
.map(({ _id, name }) => ({ id: _id, name }));
|
||||||
|
|
||||||
if (list.length > 0) {
|
if (list.length > 0) {
|
||||||
|
@ -187,13 +200,7 @@ const HackAlertThisFileWillBeReplaced = observer(
|
||||||
emojis={emojis}
|
emojis={emojis}
|
||||||
categories={categories}
|
categories={categories}
|
||||||
renderEmoji={renderEmoji}
|
renderEmoji={renderEmoji}
|
||||||
onSelect={(emoji) => {
|
onSelect={onSelect}
|
||||||
const v = state.draft.get(channel._id);
|
|
||||||
state.draft.set(
|
|
||||||
channel._id,
|
|
||||||
`${v ? `${v} ` : ""}:${emoji}:`,
|
|
||||||
);
|
|
||||||
}}
|
|
||||||
onClose={onClose}
|
onClose={onClose}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -568,7 +575,13 @@ export default observer(({ channel }: Props) => {
|
||||||
<FloatingLayer>
|
<FloatingLayer>
|
||||||
{picker && (
|
{picker && (
|
||||||
<HackAlertThisFileWillBeReplaced
|
<HackAlertThisFileWillBeReplaced
|
||||||
channel={channel}
|
onSelect={(emoji) => {
|
||||||
|
const v = state.draft.get(channel._id);
|
||||||
|
state.draft.set(
|
||||||
|
channel._id,
|
||||||
|
`${v ? `${v} ` : ""}:${emoji}:`,
|
||||||
|
);
|
||||||
|
}}
|
||||||
onClose={closePicker}
|
onClose={closePicker}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -1,11 +1,20 @@
|
||||||
|
import {
|
||||||
|
autoPlacement,
|
||||||
|
offset,
|
||||||
|
shift,
|
||||||
|
useFloating,
|
||||||
|
} from "@floating-ui/react-dom-interactions";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Message } from "revolt.js";
|
import { Message } from "revolt.js";
|
||||||
import styled, { css } from "styled-components";
|
import styled, { css } from "styled-components";
|
||||||
|
|
||||||
import { useCallback } from "preact/hooks";
|
import { createPortal } from "preact/compat";
|
||||||
|
import { useCallback, useRef } from "preact/hooks";
|
||||||
|
|
||||||
|
import { emojiDictionary } from "../../../../assets/emojis";
|
||||||
import { useClient } from "../../../../controllers/client/ClientController";
|
import { useClient } from "../../../../controllers/client/ClientController";
|
||||||
import { RenderEmoji } from "../../../markdown/plugins/emoji";
|
import { RenderEmoji } from "../../../markdown/plugins/emoji";
|
||||||
|
import { HackAlertThisFileWillBeReplaced } from "../MessageBox";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
message: Message;
|
message: Message;
|
||||||
|
@ -131,3 +140,78 @@ export const Reactions = observer(({ message }: Props) => {
|
||||||
</List>
|
</List>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const Base = styled.div`
|
||||||
|
> div {
|
||||||
|
position: unset;
|
||||||
|
}
|
||||||
|
`;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ! FIXME: rewrite
|
||||||
|
*/
|
||||||
|
export const ReactionWrapper: React.FC<{
|
||||||
|
message: Message;
|
||||||
|
open: boolean;
|
||||||
|
setOpen: (v: boolean) => void;
|
||||||
|
}> = ({ open, setOpen, message, children }) => {
|
||||||
|
const { x, y, reference, floating, strategy } = useFloating({
|
||||||
|
open,
|
||||||
|
middleware: [
|
||||||
|
offset(4),
|
||||||
|
shift({ mainAxis: true, crossAxis: true, padding: 4 }),
|
||||||
|
autoPlacement(),
|
||||||
|
],
|
||||||
|
});
|
||||||
|
|
||||||
|
const skip = useRef();
|
||||||
|
const toggle = () => {
|
||||||
|
if (skip.current) {
|
||||||
|
skip.current = null;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
setOpen(!open);
|
||||||
|
|
||||||
|
if (!open) {
|
||||||
|
skip.current = true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<div
|
||||||
|
ref={reference}
|
||||||
|
onClick={toggle}
|
||||||
|
style={{ width: "fit-content" }}>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{createPortal(
|
||||||
|
<div id="reaction">
|
||||||
|
{open && (
|
||||||
|
<Base
|
||||||
|
ref={floating}
|
||||||
|
style={{
|
||||||
|
position: strategy,
|
||||||
|
top: y ?? 0,
|
||||||
|
left: x ?? 0,
|
||||||
|
}}>
|
||||||
|
<HackAlertThisFileWillBeReplaced
|
||||||
|
onSelect={(emoji) =>
|
||||||
|
message.react(
|
||||||
|
emojiDictionary[
|
||||||
|
emoji as keyof typeof emojiDictionary
|
||||||
|
] ?? emoji,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
onClose={toggle}
|
||||||
|
/>
|
||||||
|
</Base>
|
||||||
|
)}
|
||||||
|
</div>,
|
||||||
|
document.body,
|
||||||
|
)}
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
|
@ -5,6 +5,7 @@ import {
|
||||||
Share,
|
Share,
|
||||||
InfoSquare,
|
InfoSquare,
|
||||||
Notification,
|
Notification,
|
||||||
|
HappyBeaming,
|
||||||
} from "@styled-icons/boxicons-solid";
|
} from "@styled-icons/boxicons-solid";
|
||||||
import { observer } from "mobx-react-lite";
|
import { observer } from "mobx-react-lite";
|
||||||
import { Message as MessageObject } from "revolt.js";
|
import { Message as MessageObject } from "revolt.js";
|
||||||
|
@ -17,12 +18,16 @@ import { internalEmit } from "../../../../lib/eventEmitter";
|
||||||
import { shiftKeyPressed } from "../../../../lib/modifiers";
|
import { shiftKeyPressed } from "../../../../lib/modifiers";
|
||||||
import { getRenderer } from "../../../../lib/renderer/Singleton";
|
import { getRenderer } from "../../../../lib/renderer/Singleton";
|
||||||
|
|
||||||
|
import { state } from "../../../../mobx/State";
|
||||||
import { QueuedMessage } from "../../../../mobx/stores/MessageQueue";
|
import { QueuedMessage } from "../../../../mobx/stores/MessageQueue";
|
||||||
|
|
||||||
import { modalController } from "../../../../controllers/modals/ModalController";
|
import { modalController } from "../../../../controllers/modals/ModalController";
|
||||||
import Tooltip from "../../../common/Tooltip";
|
import Tooltip from "../../../common/Tooltip";
|
||||||
|
import { ReactionWrapper } from "../attachments/Reactions";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
|
reactionsOpen: boolean;
|
||||||
|
setReactionsOpen: (v: boolean) => void;
|
||||||
message: MessageObject;
|
message: MessageObject;
|
||||||
queued?: QueuedMessage;
|
queued?: QueuedMessage;
|
||||||
}
|
}
|
||||||
|
@ -81,125 +86,152 @@ const Divider = styled.div`
|
||||||
background: var(--tertiary-background);
|
background: var(--tertiary-background);
|
||||||
`;
|
`;
|
||||||
|
|
||||||
export const MessageOverlayBar = observer(({ message, queued }: Props) => {
|
export const MessageOverlayBar = observer(
|
||||||
const client = message.client;
|
({ reactionsOpen, setReactionsOpen, message, queued }: Props) => {
|
||||||
const isAuthor = message.author_id === client.user!._id;
|
const client = message.client;
|
||||||
|
const isAuthor = message.author_id === client.user!._id;
|
||||||
|
|
||||||
const [copied, setCopied] = useState<"link" | "id">(null!);
|
const [copied, setCopied] = useState<"link" | "id">(null!);
|
||||||
const [extraActions, setExtra] = useState(shiftKeyPressed);
|
const [extraActions, setExtra] = useState(shiftKeyPressed);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const handler = (ev: KeyboardEvent) => setExtra(ev.shiftKey);
|
const handler = (ev: KeyboardEvent) => setExtra(ev.shiftKey);
|
||||||
|
|
||||||
document.addEventListener("keyup", handler);
|
document.addEventListener("keyup", handler);
|
||||||
document.addEventListener("keydown", handler);
|
document.addEventListener("keydown", handler);
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
document.removeEventListener("keyup", handler);
|
document.removeEventListener("keyup", handler);
|
||||||
document.removeEventListener("keydown", handler);
|
document.removeEventListener("keydown", handler);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OverlayBar>
|
<OverlayBar>
|
||||||
<Tooltip content="Reply">
|
{message.channel?.havePermission("SendMessage") && (
|
||||||
<Entry onClick={() => internalEmit("ReplyBar", "add", message)}>
|
<Tooltip content="Reply">
|
||||||
<Share size={18} />
|
<Entry
|
||||||
</Entry>
|
onClick={() =>
|
||||||
</Tooltip>
|
internalEmit("ReplyBar", "add", message)
|
||||||
|
}>
|
||||||
|
<Share size={18} />
|
||||||
|
</Entry>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
|
||||||
{isAuthor && (
|
{message.channel?.havePermission("React") &&
|
||||||
<Tooltip content="Edit">
|
state.experiments.isEnabled("picker") && (
|
||||||
|
<ReactionWrapper
|
||||||
|
open={reactionsOpen}
|
||||||
|
setOpen={setReactionsOpen}
|
||||||
|
message={message}>
|
||||||
|
<Tooltip content="React">
|
||||||
|
<Entry>
|
||||||
|
<HappyBeaming size={18} />
|
||||||
|
</Entry>
|
||||||
|
</Tooltip>
|
||||||
|
</ReactionWrapper>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{isAuthor && (
|
||||||
|
<Tooltip content="Edit">
|
||||||
|
<Entry
|
||||||
|
onClick={() =>
|
||||||
|
internalEmit(
|
||||||
|
"MessageRenderer",
|
||||||
|
"edit_message",
|
||||||
|
message._id,
|
||||||
|
)
|
||||||
|
}>
|
||||||
|
<Pencil size={18} />
|
||||||
|
</Entry>
|
||||||
|
</Tooltip>
|
||||||
|
)}
|
||||||
|
{isAuthor ||
|
||||||
|
(message.channel &&
|
||||||
|
message.channel.havePermission("ManageMessages")) ? (
|
||||||
|
<Tooltip content="Delete">
|
||||||
|
<Entry
|
||||||
|
onClick={(e) =>
|
||||||
|
e.shiftKey
|
||||||
|
? message.delete()
|
||||||
|
: modalController.push({
|
||||||
|
type: "delete_message",
|
||||||
|
target: message,
|
||||||
|
})
|
||||||
|
}>
|
||||||
|
<Trash size={18} color={"var(--error)"} />
|
||||||
|
</Entry>
|
||||||
|
</Tooltip>
|
||||||
|
) : undefined}
|
||||||
|
<Tooltip content="More">
|
||||||
<Entry
|
<Entry
|
||||||
onClick={() =>
|
onClick={() =>
|
||||||
internalEmit(
|
openContextMenu("Menu", {
|
||||||
"MessageRenderer",
|
message,
|
||||||
"edit_message",
|
contextualChannel: message.channel_id,
|
||||||
message._id,
|
queued,
|
||||||
)
|
})
|
||||||
}>
|
}>
|
||||||
<Pencil size={18} />
|
<DotsVerticalRounded size={18} />
|
||||||
</Entry>
|
</Entry>
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
{extraActions && (
|
||||||
{isAuthor ||
|
<>
|
||||||
(message.channel &&
|
<Divider />
|
||||||
message.channel.havePermission("ManageMessages")) ? (
|
<Tooltip content="Mark as Unread">
|
||||||
<Tooltip content="Delete">
|
<Entry
|
||||||
<Entry
|
onClick={() => {
|
||||||
onClick={(e) =>
|
// ! FIXME: deduplicate this code with ctx menu
|
||||||
e.shiftKey
|
const messages = getRenderer(
|
||||||
? message.delete()
|
message.channel!,
|
||||||
: modalController.push({
|
).messages;
|
||||||
type: "delete_message",
|
const index = messages.findIndex(
|
||||||
target: message,
|
(x) => x._id === message._id,
|
||||||
})
|
);
|
||||||
}>
|
|
||||||
<Trash size={18} color={"var(--error)"} />
|
|
||||||
</Entry>
|
|
||||||
</Tooltip>
|
|
||||||
) : undefined}
|
|
||||||
<Tooltip content="More">
|
|
||||||
<Entry
|
|
||||||
onClick={() =>
|
|
||||||
openContextMenu("Menu", {
|
|
||||||
message,
|
|
||||||
contextualChannel: message.channel_id,
|
|
||||||
queued,
|
|
||||||
})
|
|
||||||
}>
|
|
||||||
<DotsVerticalRounded size={18} />
|
|
||||||
</Entry>
|
|
||||||
</Tooltip>
|
|
||||||
{extraActions && (
|
|
||||||
<>
|
|
||||||
<Divider />
|
|
||||||
<Tooltip content="Mark as Unread">
|
|
||||||
<Entry
|
|
||||||
onClick={() => {
|
|
||||||
// ! FIXME: deduplicate this code with ctx menu
|
|
||||||
const messages = getRenderer(
|
|
||||||
message.channel!,
|
|
||||||
).messages;
|
|
||||||
const index = messages.findIndex(
|
|
||||||
(x) => x._id === message._id,
|
|
||||||
);
|
|
||||||
|
|
||||||
let unread_id = message._id;
|
let unread_id = message._id;
|
||||||
if (index > 0) {
|
if (index > 0) {
|
||||||
unread_id = messages[index - 1]._id;
|
unread_id = messages[index - 1]._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
internalEmit("NewMessages", "mark", unread_id);
|
internalEmit(
|
||||||
message.channel?.ack(unread_id, true);
|
"NewMessages",
|
||||||
}}>
|
"mark",
|
||||||
<Notification size={18} />
|
unread_id,
|
||||||
</Entry>
|
);
|
||||||
</Tooltip>
|
message.channel?.ack(unread_id, true);
|
||||||
<Tooltip
|
}}>
|
||||||
content={copied === "link" ? "Copied!" : "Copy Link"}
|
<Notification size={18} />
|
||||||
hideOnClick={false}>
|
</Entry>
|
||||||
<Entry
|
</Tooltip>
|
||||||
onClick={() => {
|
<Tooltip
|
||||||
setCopied("link");
|
content={
|
||||||
modalController.writeText(message.url);
|
copied === "link" ? "Copied!" : "Copy Link"
|
||||||
}}>
|
}
|
||||||
<LinkAlt size={18} />
|
hideOnClick={false}>
|
||||||
</Entry>
|
<Entry
|
||||||
</Tooltip>
|
onClick={() => {
|
||||||
<Tooltip
|
setCopied("link");
|
||||||
content={copied === "id" ? "Copied!" : "Copy ID"}
|
modalController.writeText(message.url);
|
||||||
hideOnClick={false}>
|
}}>
|
||||||
<Entry
|
<LinkAlt size={18} />
|
||||||
onClick={() => {
|
</Entry>
|
||||||
setCopied("id");
|
</Tooltip>
|
||||||
modalController.writeText(message._id);
|
<Tooltip
|
||||||
}}>
|
content={copied === "id" ? "Copied!" : "Copy ID"}
|
||||||
<InfoSquare size={18} />
|
hideOnClick={false}>
|
||||||
</Entry>
|
<Entry
|
||||||
</Tooltip>
|
onClick={() => {
|
||||||
</>
|
setCopied("id");
|
||||||
)}
|
modalController.writeText(message._id);
|
||||||
</OverlayBar>
|
}}>
|
||||||
);
|
<InfoSquare size={18} />
|
||||||
});
|
</Entry>
|
||||||
|
</Tooltip>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</OverlayBar>
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
|
@ -155,7 +155,9 @@ export const ChannelButton = observer((props: ChannelProps) => {
|
||||||
data-alert={alerting}
|
data-alert={alerting}
|
||||||
data-muted={muted}
|
data-muted={muted}
|
||||||
aria-label={channel.name}
|
aria-label={channel.name}
|
||||||
className={classNames(styles.item, { [styles.compact]: compact })}
|
className={classNames(styles.item, {
|
||||||
|
[styles.compact]: compact,
|
||||||
|
})}
|
||||||
{...useTriggerEvents("Menu", {
|
{...useTriggerEvents("Menu", {
|
||||||
channel: channel._id,
|
channel: channel._id,
|
||||||
unread: !!alert,
|
unread: !!alert,
|
||||||
|
@ -175,7 +177,9 @@ export const ChannelButton = observer((props: ChannelProps) => {
|
||||||
<Text
|
<Text
|
||||||
id="quantities.members"
|
id="quantities.members"
|
||||||
plural={channel.recipients!.length}
|
plural={channel.recipients!.length}
|
||||||
fields={{ count: channel.recipients!.length }}
|
fields={{
|
||||||
|
count: channel.recipients!.length,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -45,7 +45,7 @@ export const EXPERIMENTS: {
|
||||||
picker: {
|
picker: {
|
||||||
title: "Custom Emoji",
|
title: "Custom Emoji",
|
||||||
description:
|
description:
|
||||||
"This will enable a work-in-progress emoji picker and custom emoji settings.",
|
"This will enable a work-in-progress emoji picker, custom emoji settings and reaction picker.",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -43,6 +43,7 @@ export default function Developer() {
|
||||||
fields={{ provider: <b>GAMING!</b> }}
|
fields={{ provider: <b>GAMING!</b> }}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ padding: "16px" }}>
|
<div style={{ padding: "16px" }}>
|
||||||
<a onClick={() => setCrash(true)}>click to crash app</a>
|
<a onClick={() => setCrash(true)}>click to crash app</a>
|
||||||
{crash && (window as any).sus.sus()}
|
{crash && (window as any).sus.sus()}
|
||||||
|
|
68
yarn.lock
68
yarn.lock
|
@ -1825,6 +1825,49 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"@floating-ui/core@npm:^0.7.3":
|
||||||
|
version: 0.7.3
|
||||||
|
resolution: "@floating-ui/core@npm:0.7.3"
|
||||||
|
checksum: f48f9fb0d19dcbe7a68c38e8de7fabb11f0c0e6e0ef215ae60b5004900bacb1386e7b89cb377d91a90ff7d147ea1f06c2905136ecf34dea162d9696d8f448d5f
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@floating-ui/dom@npm:^0.5.3":
|
||||||
|
version: 0.5.4
|
||||||
|
resolution: "@floating-ui/dom@npm:0.5.4"
|
||||||
|
dependencies:
|
||||||
|
"@floating-ui/core": ^0.7.3
|
||||||
|
checksum: 9f9d8a51a828c6be5f187204aa6d293c6c9ef70d51dcc5891a4d85683745fceebf79ff8826d0f75ae41b45c3b138367d339756f27f41be87a8770742ebc0de42
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@floating-ui/react-dom-interactions@npm:^0.7.0":
|
||||||
|
version: 0.7.0
|
||||||
|
resolution: "@floating-ui/react-dom-interactions@npm:0.7.0"
|
||||||
|
dependencies:
|
||||||
|
"@floating-ui/react-dom": ^0.7.2
|
||||||
|
aria-hidden: ^1.1.3
|
||||||
|
use-isomorphic-layout-effect: ^1.1.1
|
||||||
|
peerDependencies:
|
||||||
|
react: ">=16.8.0"
|
||||||
|
react-dom: ">=16.8.0"
|
||||||
|
checksum: 7cf0875a65c55c06a0d0cc91e07d725cb0be8cccf61d6c08ab91f24c80c9dce370d6a47e6b7c4d49c3d9456136d840a57ca548b0bc2316f3ff869ac8e1797424
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
|
"@floating-ui/react-dom@npm:^0.7.2":
|
||||||
|
version: 0.7.2
|
||||||
|
resolution: "@floating-ui/react-dom@npm:0.7.2"
|
||||||
|
dependencies:
|
||||||
|
"@floating-ui/dom": ^0.5.3
|
||||||
|
use-isomorphic-layout-effect: ^1.1.1
|
||||||
|
peerDependencies:
|
||||||
|
react: ">=16.8.0"
|
||||||
|
react-dom: ">=16.8.0"
|
||||||
|
checksum: bc3f2b5557f87f6f4bbccfe3e8d097abafad61a41083d3b79f3499f27590e273bcb3dc7136c2444841ee7a8c0d2a70cc1385458c16103fa8b70eade80c24af52
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"@fontsource/atkinson-hyperlegible@npm:^4.4.5":
|
"@fontsource/atkinson-hyperlegible@npm:^4.4.5":
|
||||||
version: 4.5.1
|
version: 4.5.1
|
||||||
resolution: "@fontsource/atkinson-hyperlegible@npm:4.5.1"
|
resolution: "@fontsource/atkinson-hyperlegible@npm:4.5.1"
|
||||||
|
@ -3156,6 +3199,15 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"aria-hidden@npm:^1.1.3":
|
||||||
|
version: 1.1.3
|
||||||
|
resolution: "aria-hidden@npm:1.1.3"
|
||||||
|
dependencies:
|
||||||
|
tslib: ^1.0.0
|
||||||
|
checksum: 2d40a328246baac7ae0b243ebe0cbef53c836c5f78c9212e9c1ff93f3aee185bd9aa51773e161e0025722d691c9d5f125070f6175a7074c4a57778ddc30d9e74
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"array-includes@npm:^3.1.2, array-includes@npm:^3.1.3":
|
"array-includes@npm:^3.1.2, array-includes@npm:^3.1.3":
|
||||||
version: 3.1.3
|
version: 3.1.3
|
||||||
resolution: "array-includes@npm:3.1.3"
|
resolution: "array-includes@npm:3.1.3"
|
||||||
|
@ -3603,6 +3655,8 @@ __metadata:
|
||||||
resolution: "client@workspace:."
|
resolution: "client@workspace:."
|
||||||
dependencies:
|
dependencies:
|
||||||
"@babel/plugin-proposal-decorators": ^7.17.9
|
"@babel/plugin-proposal-decorators": ^7.17.9
|
||||||
|
"@floating-ui/react-dom": ^0.7.2
|
||||||
|
"@floating-ui/react-dom-interactions": ^0.7.0
|
||||||
"@fontsource/atkinson-hyperlegible": ^4.4.5
|
"@fontsource/atkinson-hyperlegible": ^4.4.5
|
||||||
"@fontsource/bitter": ^4.5.7
|
"@fontsource/bitter": ^4.5.7
|
||||||
"@fontsource/comic-neue": ^4.4.5
|
"@fontsource/comic-neue": ^4.4.5
|
||||||
|
@ -8792,7 +8846,7 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"tslib@npm:^1.8.1":
|
"tslib@npm:^1.0.0, tslib@npm:^1.8.1":
|
||||||
version: 1.14.1
|
version: 1.14.1
|
||||||
resolution: "tslib@npm:1.14.1"
|
resolution: "tslib@npm:1.14.1"
|
||||||
checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd
|
checksum: dbe628ef87f66691d5d2959b3e41b9ca0045c3ee3c7c7b906cc1e328b39f199bb1ad9e671c39025bd56122ac57dfbf7385a94843b1cc07c60a4db74795829acd
|
||||||
|
@ -9131,6 +9185,18 @@ __metadata:
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
|
"use-isomorphic-layout-effect@npm:^1.1.1":
|
||||||
|
version: 1.1.2
|
||||||
|
resolution: "use-isomorphic-layout-effect@npm:1.1.2"
|
||||||
|
peerDependencies:
|
||||||
|
react: ^16.8.0 || ^17.0.0 || ^18.0.0
|
||||||
|
peerDependenciesMeta:
|
||||||
|
"@types/react":
|
||||||
|
optional: true
|
||||||
|
checksum: a6532f7fc9ae222c3725ff0308aaf1f1ddbd3c00d685ef9eee6714fd0684de5cb9741b432fbf51e61a784e2955424864f7ea9f99734a02f237b17ad3e18ea5cb
|
||||||
|
languageName: node
|
||||||
|
linkType: hard
|
||||||
|
|
||||||
"use-memo-one@npm:^1.1.1":
|
"use-memo-one@npm:^1.1.1":
|
||||||
version: 1.1.2
|
version: 1.1.2
|
||||||
resolution: "use-memo-one@npm:1.1.2"
|
resolution: "use-memo-one@npm:1.1.2"
|
||||||
|
|
Loading…
Reference in a new issue