From 5db0854b42edc37c9bce770831224206d57b1fdd Mon Sep 17 00:00:00 2001 From: Paul Date: Tue, 22 Jun 2021 10:28:13 +0100 Subject: [PATCH] Add global event pipeline. Add message editor back. --- src/components/ui/DateDivider.tsx | 2 +- src/lib/ContextMenus.tsx | 3 +- src/lib/eventEmitter.ts | 18 ++++ .../channels/messaging/MessageEditor.tsx | 84 +++++++++++++++++++ .../channels/messaging/MessageRenderer.tsx | 34 ++++---- 5 files changed, 121 insertions(+), 20 deletions(-) create mode 100644 src/lib/eventEmitter.ts create mode 100644 src/pages/channels/messaging/MessageEditor.tsx diff --git a/src/components/ui/DateDivider.tsx b/src/components/ui/DateDivider.tsx index f310753d..5f6e1a0a 100644 --- a/src/components/ui/DateDivider.tsx +++ b/src/components/ui/DateDivider.tsx @@ -4,9 +4,9 @@ import styled, { css } from "styled-components"; const Base = styled.div<{ unread?: boolean }>` height: 0; display: flex; - margin: 14px 10px; user-select: none; align-items: center; + margin: 17px 12px 5px; border-top: thin solid var(--tertiary-foreground); time { diff --git a/src/lib/ContextMenus.tsx b/src/lib/ContextMenus.tsx index c1d35ba0..e0e3a375 100644 --- a/src/lib/ContextMenus.tsx +++ b/src/lib/ContextMenus.tsx @@ -17,6 +17,7 @@ import { useChannel, useChannelPermission, useForceUpdate, useServer, useServerP import { Children } from "../types/Preact"; import LineDivider from "../components/ui/LineDivider"; import { connectState } from "../redux/connector"; +import { internalEmit } from "./eventEmitter"; interface ContextMenuData { user?: string; @@ -162,7 +163,7 @@ function ContextMenus(props: WithDispatcher) { case "edit_message": { - // InternalEventEmitter.emit("edit_message", data.id); + internalEmit("MessageRenderer", "edit_message", data.id); } break; diff --git a/src/lib/eventEmitter.ts b/src/lib/eventEmitter.ts new file mode 100644 index 00000000..5eaf08d1 --- /dev/null +++ b/src/lib/eventEmitter.ts @@ -0,0 +1,18 @@ +import EventEmitter from "eventemitter3"; +export const InternalEvent = new EventEmitter(); + +export function internalSubscribe(ns: string, event: string, fn: (...args: any[]) => void) { + InternalEvent.addListener(ns + '/' + event, fn); + return () => InternalEvent.removeListener(ns + '/' + event, fn); +} + +export function internalEmit(ns: string, event: string, ...args: any[]) { + InternalEvent.emit(ns + '/' + event, ...args); +} + +// Event structure: namespace/event + +/// Event List +// - MessageRenderer/edit_last +// - MessageRenderer/edit_message +// - MessageBox/focus diff --git a/src/pages/channels/messaging/MessageEditor.tsx b/src/pages/channels/messaging/MessageEditor.tsx new file mode 100644 index 00000000..065eb4cd --- /dev/null +++ b/src/pages/channels/messaging/MessageEditor.tsx @@ -0,0 +1,84 @@ +import styled from "styled-components"; +import { useContext, useState } from "preact/hooks"; +import TextAreaAutoSize from "../../../lib/TextAreaAutoSize"; +import { MessageObject } from "../../../context/revoltjs/util"; +import { AppContext } from "../../../context/revoltjs/RevoltClient"; +import { isTouchscreenDevice } from "../../../lib/isTouchscreenDevice"; + +const EditorBase = styled.div` + display: flex; + flex-direction: column; + + textarea { + resize: none; + padding: 12px; + border-radius: 3px; + white-space: pre-wrap; + background: var(--secondary-header); + } + + .caption { + padding: 2px; + font-size: 11px; + color: var(--tertiary-foreground); + + a { + cursor: pointer; + &:hover { + text-decoration: underline; + } + } + } +`; + +interface Props { + message: MessageObject + finish: () => void +} + +export default function MessageEditor({ message, finish }: Props) { + const [ content, setContent ] = useState(message.content as string ?? ''); + const client = useContext(AppContext); + + async function save() { + finish(); + + if (content.length === 0) { + // @ts-expect-error + openScreen({ id: 'special_prompt', type: 'delete_message', target: message }); + } else if (content !== message.content) { + await client.channels.editMessage( + message.channel, + message._id, + { content } + ); + } + } + + return ( + + setContent(ev.currentTarget.value)} + onKeyDown={e => { + if ( + !e.shiftKey && + e.key === "Enter" && + !isTouchscreenDevice + ) { + e.preventDefault(); + save(); + } + }} + // forceFocus + /> + + escape to cancel · + enter to save + + + ) +} diff --git a/src/pages/channels/messaging/MessageRenderer.tsx b/src/pages/channels/messaging/MessageRenderer.tsx index b1b54936..4f30cd98 100644 --- a/src/pages/channels/messaging/MessageRenderer.tsx +++ b/src/pages/channels/messaging/MessageRenderer.tsx @@ -1,4 +1,6 @@ import { decodeTime } from "ulid"; +import MessageEditor from "./MessageEditor"; +import { Children } from "../../../types/Preact"; import { useEffect, useState } from "preact/hooks"; import ConversationStart from "./ConversationStart"; import { connectState } from "../../../redux/connector"; @@ -7,11 +9,11 @@ import { RenderState } from "../../../lib/renderer/types"; import DateDivider from "../../../components/ui/DateDivider"; import { QueuedMessage } from "../../../redux/reducers/queue"; import { MessageObject } from "../../../context/revoltjs/util"; +import Message from "../../../components/common/messaging/Message"; import RequiresOnline from "../../../context/revoltjs/RequiresOnline"; import { useForceUpdate, useUsers } from "../../../context/revoltjs/hooks"; -import { Children } from "../../../types/Preact"; +import { internalSubscribe, internalEmit } from "../../../lib/eventEmitter"; import { SystemMessage } from "../../../components/common/messaging/SystemMessage"; -import Message from "../../../components/common/messaging/Message"; interface Props { id: string; @@ -32,8 +34,9 @@ function MessageRenderer({ id, state, queue }: Props) { const [editing, setEditing] = useState(undefined); const stopEditing = () => { setEditing(undefined); - // InternalEventEmitter.emit("focus_textarea", "message"); + internalEmit("MessageBox", "focus"); }; + useEffect(() => { function editLast() { if (state.type !== 'RENDER') return; @@ -45,13 +48,12 @@ function MessageRenderer({ id, state, queue }: Props) { } } - // InternalEventEmitter.addListener("edit_last", editLast); - // InternalEventEmitter.addListener("edit_message", setEditing); + const subs = [ + internalSubscribe("MessageRenderer", "edit_last", editLast), + internalSubscribe("MessageRenderer", "edit_message", setEditing) + ] - return () => { - // InternalEventEmitter.removeListener("edit_last", editLast); - // InternalEventEmitter.removeListener("edit_message", setEditing); - }; + return () => subs.forEach(unsub => unsub()); }, [state.messages]); let render: Children[] = [], @@ -107,17 +109,13 @@ function MessageRenderer({ id, state, queue }: Props) { + : undefined + } attachContext /> ); - /*render.push( - x?._id === message.author)} - message={message} - key={message._id} - head={head} - /> - );*/ } previous = message;