From 2966e779177cd423c0bda567560277115efffb44 Mon Sep 17 00:00:00 2001 From: brecert Date: Tue, 7 Sep 2021 08:14:22 -0400 Subject: [PATCH 1/5] Add `shift+click` to mention a user in the textarea --- src/components/common/messaging/Message.tsx | 44 ++++++++++++------- src/components/common/user/UserShort.tsx | 30 ++++++++++--- .../navigation/right/MemberList.tsx | 22 +++++++--- 3 files changed, 68 insertions(+), 28 deletions(-) diff --git a/src/components/common/messaging/Message.tsx b/src/components/common/messaging/Message.tsx index 8b740c8d..21f6f4c2 100644 --- a/src/components/common/messaging/Message.tsx +++ b/src/components/common/messaging/Message.tsx @@ -25,6 +25,7 @@ import Attachment from "./attachments/Attachment"; import { MessageReply } from "./attachments/MessageReply"; import Embed from "./embed/Embed"; import InviteList from "./embed/EmbedInvite"; +import { internalEmit } from "../../../lib/eventEmitter"; interface Props { attachContext?: boolean; @@ -61,15 +62,28 @@ const Message = observer( // bree: Fatal please... const userContext = attachContext ? (attachContextMenu("Menu", { - user: message.author_id, - contextualChannel: message.channel_id, - // eslint-disable-next-line - }) as any) + user: message.author_id, + contextualChannel: message.channel_id, + // eslint-disable-next-line + }) as any) : undefined; const openProfile = () => openScreen({ id: "profile", user_id: message.author_id }); + const handleUserClick = (e: MouseEvent) => { + if (e.shiftKey && user?._id) { + internalEmit( + "MessageBox", + "append", + `<@${user._id}>`, + "mention", + ); + } else { + openProfile() + } + } + // ! FIXME(?): animate on hover const [animate, setAnimate] = useState(false); @@ -91,11 +105,11 @@ const Message = observer( hideReply ? false : (head && - !( - message.reply_ids && - message.reply_ids.length > 0 - )) ?? - false + !( + message.reply_ids && + message.reply_ids.length > 0 + )) ?? + false } contrast={contrast} sending={typeof queued !== "undefined"} @@ -104,10 +118,10 @@ const Message = observer( onContextMenu={ attachContext ? attachContextMenu("Menu", { - message, - contextualChannel: message.channel_id, - queued, - }) + message, + contextualChannel: message.channel_id, + queued, + }) : undefined } onMouseEnter={() => setAnimate(true)} @@ -118,7 +132,7 @@ const Message = observer( target={user} size={36} onContextMenu={userContext} - onClick={openProfile} + onClick={handleUserClick} animate={animate} showServerIdentity /> @@ -133,7 +147,7 @@ const Message = observer( className="author" user={user} onContextMenu={userContext} - onClick={openProfile} + onClick={handleUserClick} showServerIdentity /> & { + user?: User; + prefixAt?: boolean; + showServerIdentity?: boolean; +} export const Username = observer( ({ user, prefixAt, showServerIdentity, ...otherProps - }: { - user?: User; - prefixAt?: boolean; - showServerIdentity?: boolean; - } & JSX.HTMLAttributes) => { + }: UsernameProps) => { let username = user?.username; let color; @@ -108,18 +110,32 @@ export default function UserShort({ const openProfile = () => user && openScreen({ id: "profile", user_id: user._id }); + const handleUserClick = (e: MouseEvent) => { + if (e.shiftKey && user?._id) { + e.preventDefault() + internalEmit( + "MessageBox", + "append", + `<@${user?._id}>`, + "mention", + ); + } else { + openProfile() + } + } + return ( <> diff --git a/src/components/navigation/right/MemberList.tsx b/src/components/navigation/right/MemberList.tsx index 3b8c1b63..6840ee22 100644 --- a/src/components/navigation/right/MemberList.tsx +++ b/src/components/navigation/right/MemberList.tsx @@ -12,6 +12,7 @@ import { } from "../../../context/intermediate/Intermediate"; import { UserButton } from "../items/ButtonItem"; +import { internalEmit } from "../../../lib/eventEmitter"; export type MemberListGroup = { type: "online" | "offline" | "role"; @@ -53,12 +54,21 @@ const ItemContent = memo( user={item} margin context={context} - onClick={() => - openScreen({ - id: "profile", - user_id: item._id, - }) - } + onClick={e => { + if (e.shiftKey) { + internalEmit( + "MessageBox", + "append", + `<@${item._id}>`, + "mention", + ); + } else[ + openScreen({ + id: "profile", + user_id: item._id, + }) + ] + }} /> ), ); From dd9b486dabde729f15ce8e5d89321c210cacf564 Mon Sep 17 00:00:00 2001 From: brecert Date: Tue, 7 Sep 2021 08:34:40 -0400 Subject: [PATCH 2/5] Add `shift+click` to link to a channel in the textarea --- src/components/navigation/left/ServerSidebar.tsx | 12 ++++++++++++ src/lib/ConditionalLink.tsx | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/components/navigation/left/ServerSidebar.tsx b/src/components/navigation/left/ServerSidebar.tsx index 61fca6b3..83adce2a 100644 --- a/src/components/navigation/left/ServerSidebar.tsx +++ b/src/components/navigation/left/ServerSidebar.tsx @@ -22,6 +22,7 @@ import { mapChannelWithUnread, useUnreads } from "./common"; import { ChannelButton } from "../items/ButtonItem"; import ConnectionStatus from "../items/ConnectionStatus"; +import { internalEmit } from "../../../lib/eventEmitter"; interface Props { unreads: Unreads; @@ -86,6 +87,17 @@ const ServerSidebar = observer((props: Props) => { return ( { + if (e.shiftKey) { + internalEmit( + "MessageBox", + "append", + `<#${entry._id}>`, + "mention", + ); + e.preventDefault() + } + }} key={entry._id} active={active} to={`/server/${server!._id}/channel/${entry._id}`}> diff --git a/src/lib/ConditionalLink.tsx b/src/lib/ConditionalLink.tsx index b2057c4d..fbe4fdd9 100644 --- a/src/lib/ConditionalLink.tsx +++ b/src/lib/ConditionalLink.tsx @@ -9,7 +9,7 @@ export default function ConditionalLink(props: Props) { const { active, ...linkProps } = props; if (active) { - return {props.children}; + return {props.children}; } return ; } From b166b063215263cca901523de9b4c73e5dcb0537 Mon Sep 17 00:00:00 2001 From: brecert Date: Tue, 7 Sep 2021 08:58:39 -0400 Subject: [PATCH 3/5] Change mention to channel mention --- src/components/navigation/left/ServerSidebar.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/navigation/left/ServerSidebar.tsx b/src/components/navigation/left/ServerSidebar.tsx index 83adce2a..0c760782 100644 --- a/src/components/navigation/left/ServerSidebar.tsx +++ b/src/components/navigation/left/ServerSidebar.tsx @@ -93,7 +93,7 @@ const ServerSidebar = observer((props: Props) => { "MessageBox", "append", `<#${entry._id}>`, - "mention", + "channel_mention", ); e.preventDefault() } From a308e6ecb85ab2fc1d2fc17f3c9b638e9d3720e3 Mon Sep 17 00:00:00 2001 From: brecert Date: Tue, 7 Sep 2021 09:09:12 -0400 Subject: [PATCH 4/5] Add `shift+click` to mention mentions --- src/components/markdown/Renderer.tsx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/markdown/Renderer.tsx b/src/components/markdown/Renderer.tsx index d484cc2d..01a850e2 100644 --- a/src/components/markdown/Renderer.tsx +++ b/src/components/markdown/Renderer.tsx @@ -44,7 +44,7 @@ if (typeof window !== "undefined") { if (code) { navigator.clipboard.writeText(code.textContent?.trim() ?? ""); } - } catch (e) {} + } catch (e) { } }; } @@ -140,7 +140,18 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { (ev: MouseEvent) => { if (ev.currentTarget) { const element = ev.currentTarget as HTMLAnchorElement; - if (openLink(element.href)) ev.preventDefault(); + if (element.dataset.type === 'mention' && ev.shiftKey) { + internalEmit( + "MessageBox", + "append", + `<@${element.dataset.mentionId}>`, + "mention", + ); + + ev.preventDefault() + } else if (openLink(element.href)) { + ev.preventDefault(); + } } }, [openLink], @@ -162,6 +173,7 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { element.removeEventListener("click", handleLink); element.addEventListener("click", handleLink); element.removeAttribute("data-type"); + element.removeAttribute("data-mention-id"); element.removeAttribute("target"); const link = determineLink(element.href); @@ -171,6 +183,10 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { "data-type", "mention", ); + element.setAttribute( + "data-mention-id", + link.id + ) break; } case "external": { From f35ebeab6799b2e3a224cc499e36aea8380b84e0 Mon Sep 17 00:00:00 2001 From: brecert Date: Tue, 7 Sep 2021 09:26:12 -0400 Subject: [PATCH 5/5] Add `shift+click` to channel links --- src/components/markdown/Renderer.tsx | 49 +++++++++++++++++++++++----- src/lib/links.ts | 9 ++++- 2 files changed, 48 insertions(+), 10 deletions(-) diff --git a/src/components/markdown/Renderer.tsx b/src/components/markdown/Renderer.tsx index 01a850e2..c845390c 100644 --- a/src/components/markdown/Renderer.tsx +++ b/src/components/markdown/Renderer.tsx @@ -140,16 +140,33 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { (ev: MouseEvent) => { if (ev.currentTarget) { const element = ev.currentTarget as HTMLAnchorElement; - if (element.dataset.type === 'mention' && ev.shiftKey) { - internalEmit( - "MessageBox", - "append", - `<@${element.dataset.mentionId}>`, - "mention", - ); - ev.preventDefault() - } else if (openLink(element.href)) { + if (ev.shiftKey) { + switch (element.dataset.type) { + case "mention": { + internalEmit( + "MessageBox", + "append", + `<@${element.dataset.mentionId}>`, + "mention", + ); + ev.preventDefault() + return + } + case "channel_mention": { + internalEmit( + "MessageBox", + "append", + `<#${element.dataset.mentionId}>`, + "channel_mention", + ); + ev.preventDefault() + return + } + } + } + + if (openLink(element.href)) { ev.preventDefault(); } } @@ -177,6 +194,7 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { element.removeAttribute("target"); const link = determineLink(element.href); + console.log(link) switch (link.type) { case "profile": { element.setAttribute( @@ -189,6 +207,19 @@ export default function Renderer({ content, disallowBigEmoji }: MarkdownProps) { ) break; } + case "navigate": { + if (link.navigation_type === 'channel') { + element.setAttribute( + "data-type", + "channel_mention", + ); + element.setAttribute( + "data-mention-id", + link.channel_id + ) + } + break; + } case "external": { element.setAttribute("target", "_blank"); break; diff --git a/src/lib/links.ts b/src/lib/links.ts index d915a43c..c41b5bf5 100644 --- a/src/lib/links.ts +++ b/src/lib/links.ts @@ -1,6 +1,7 @@ type LinkType = | { type: "profile"; id: string } - | { type: "navigate"; path: string } + | { type: "navigate"; path: string; navigation_type?: null } + | { type: "navigate"; path: string; navigation_type: 'channel'; channel_id: string } | { type: "external"; href: string; url: URL } | { type: "none" }; @@ -11,6 +12,8 @@ const ALLOWED_ORIGINS = [ "local.revolt.chat", ]; +const CHANNEL_PATH_RE = /^\/server\/[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}\/channel\/[0123456789ABCDEFGHJKMNPQRSTVWXYZ]{26}$/ + export function determineLink(href?: string): LinkType { let internal, url: URL | null = null; @@ -27,6 +30,10 @@ export function determineLink(href?: string): LinkType { return { type: "profile", id }; } } else { + console.log(path) + if(CHANNEL_PATH_RE.test(path)) { + return { type: 'navigate', path, navigation_type: 'channel', channel_id: path.slice(43) } + } return { type: "navigate", path }; }