Room input improvements (#1502)

* prevent context menu when editing message

* send sticker body (#1479)

* update emojiboard search text reaction input label

* stop generating upload image thumbnail (#1475)

* maintain upload order

* Fix message options spinner variant

* add markdown toggle in editor toolbar

* fix heading toggle icon update with cursor move

* add hotkeys for heading

* change editor markdown btn style

* use Ctrl + Enter to send message (#1470)

* fix reaction tooltip word-break

* add shift in editor hokeys with number

* stop parsing markdown in link
This commit is contained in:
Ajay Bura 2023-10-25 16:50:38 +11:00 committed by GitHub
parent c7e5c1fce8
commit 2957a45c4b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 162 additions and 71 deletions

View file

@ -29,7 +29,6 @@ import {
config,
toRem,
} from 'folds';
import to from 'await-to-js';
import { useMatrixClient } from '../../hooks/useMatrixClient';
import {
@ -216,30 +215,24 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
};
const handleSendUpload = async (uploads: UploadSuccess[]) => {
const sendPromises = uploads.map(async (upload) => {
const contentsPromises = uploads.map(async (upload) => {
const fileItem = selectedFiles.find((f) => f.file === upload.file);
if (fileItem && fileItem.file.type.startsWith('image')) {
const [imgError, imgContent] = await to(getImageMsgContent(mx, fileItem, upload.mxc));
if (imgError) console.warn(imgError);
if (imgContent) mx.sendMessage(roomId, imgContent);
return;
if (!fileItem) throw new Error('Broken upload');
if (fileItem.file.type.startsWith('image')) {
return getImageMsgContent(mx, fileItem, upload.mxc);
}
if (fileItem && fileItem.file.type.startsWith('video')) {
const [videoError, videoContent] = await to(getVideoMsgContent(mx, fileItem, upload.mxc));
if (videoError) console.warn(videoError);
if (videoContent) mx.sendMessage(roomId, videoContent);
return;
if (fileItem.file.type.startsWith('video')) {
return getVideoMsgContent(mx, fileItem, upload.mxc);
}
if (fileItem && fileItem.file.type.startsWith('audio')) {
mx.sendMessage(roomId, getAudioMsgContent(fileItem, upload.mxc));
return;
}
if (fileItem) {
mx.sendMessage(roomId, getFileMsgContent(fileItem, upload.mxc));
if (fileItem.file.type.startsWith('audio')) {
return getAudioMsgContent(fileItem, upload.mxc);
}
return getFileMsgContent(fileItem, upload.mxc);
});
handleCancelUpload(uploads);
await Promise.allSettled(sendPromises);
const contents = fulfilledPromiseSettledResult(await Promise.allSettled(contentsPromises));
contents.forEach((content) => mx.sendMessage(roomId, content));
};
const submit = useCallback(() => {
@ -319,7 +312,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
const handleKeyDown: KeyboardEventHandler = useCallback(
(evt) => {
if (enterForNewline ? isKeyHotkey('shift+enter', evt) : isKeyHotkey('enter', evt)) {
if (isKeyHotkey('mod+enter', evt) || (!enterForNewline && isKeyHotkey('enter', evt))) {
evt.preventDefault();
submit();
}
@ -359,7 +352,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
moveCursor(editor);
};
const handleStickerSelect = async (mxc: string, shortcode: string) => {
const handleStickerSelect = async (mxc: string, shortcode: string, label: string) => {
const stickerUrl = mx.mxcUrlToHttp(mxc);
if (!stickerUrl) return;
@ -369,7 +362,7 @@ export const RoomInput = forwardRef<HTMLDivElement, RoomInputProps>(
);
mx.sendEvent(roomId, EventType.Sticker, {
body: shortcode,
body: label,
url: mxc,
info,
});

View file

@ -392,7 +392,7 @@ export const MessageDeleteItem = as<
variant="Critical"
before={
deleteState.status === AsyncStatus.Loading ? (
<Spinner fill="Soft" variant="Critical" size="200" />
<Spinner fill="Solid" variant="Critical" size="200" />
) : undefined
}
aria-disabled={deleteState.status === AsyncStatus.Loading}
@ -522,7 +522,7 @@ export const MessageReportItem = as<
variant="Critical"
before={
reportState.status === AsyncStatus.Loading ? (
<Spinner fill="Soft" variant="Critical" size="200" />
<Spinner fill="Solid" variant="Critical" size="200" />
) : undefined
}
aria-disabled={
@ -702,7 +702,7 @@ export const Message = as<'div', MessageProps>(
);
const handleContextMenu: MouseEventHandler<HTMLDivElement> = (evt) => {
if (evt.altKey || !window.getSelection()?.isCollapsed) return;
if (evt.altKey || !window.getSelection()?.isCollapsed || edit) return;
const tag = (evt.target as any).tagName;
if (typeof tag === 'string' && tag.toLowerCase() === 'a') return;
evt.preventDefault();

View file

@ -129,7 +129,7 @@ export const MessageEditor = as<'div', MessageEditorProps>(
const handleKeyDown: KeyboardEventHandler = useCallback(
(evt) => {
if (enterForNewline ? isKeyHotkey('shift+enter', evt) : isKeyHotkey('enter', evt)) {
if (isKeyHotkey('mod+enter', evt) || (!enterForNewline && isKeyHotkey('enter', evt))) {
evt.preventDefault();
handleSave();
}

View file

@ -68,7 +68,7 @@ export const Reactions = as<'div', ReactionsProps>(
position="Top"
tooltip={
<Tooltip style={{ maxWidth: toRem(200) }}>
<Text size="T300">
<Text className={css.ReactionsTooltipText} size="T300">
<ReactionTooltipMsg room={room} reaction={key} events={rEvents} />
</Text>
</Tooltip>

View file

@ -79,3 +79,7 @@ export const ReactionsContainer = style({
},
},
});
export const ReactionsTooltipText = style({
wordBreak: 'break-all',
});

View file

@ -54,23 +54,10 @@ export const getImageMsgContent = async (
};
if (imgEl) {
const blurHash = encodeBlurHash(imgEl, 512, scaleYDimension(imgEl.width, 512, imgEl.height));
const [thumbError, thumbContent] = await to(
generateThumbnailContent(
mx,
imgEl,
getThumbnailDimensions(imgEl.width, imgEl.height),
!!encInfo
)
);
if (thumbContent && thumbContent.thumbnail_info) {
thumbContent.thumbnail_info[MATRIX_BLUR_HASH_PROPERTY_NAME] = blurHash;
}
if (thumbError) console.warn(thumbError);
content.info = {
...getImageInfo(imgEl, file),
[MATRIX_BLUR_HASH_PROPERTY_NAME]: blurHash,
...thumbContent,
};
}
if (encInfo) {

View file

@ -45,6 +45,8 @@ import CinnySVG from '../../../../public/res/svg/cinny.svg';
import { confirmDialog } from '../../molecules/confirm-dialog/ConfirmDialog';
import { useSetting } from '../../state/hooks/settings';
import { settingsAtom } from '../../state/settings';
import { isMacOS } from '../../utils/user-agent';
import { KeySymbol } from '../../utils/key-symbol';
function AppearanceSection() {
const [, updateState] = useState({});
@ -147,7 +149,7 @@ function AppearanceSection() {
onToggle={() => setEnterForNewline(!enterForNewline) }
/>
)}
content={<Text variant="b3">Use SHIFT + ENTER to send message and ENTER for newline.</Text>}
content={<Text variant="b3">{`Use ${isMacOS() ? KeySymbol.Command : 'Ctrl'} + ENTER to send message and ENTER for newline.`}</Text>}
/>
<SettingTile
title="Inline Markdown formatting"