mirror of
https://github.com/cinnyapp/cinny.git
synced 2025-11-17 20:50:29 +03:00
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:
parent
c7e5c1fce8
commit
2957a45c4b
13 changed files with 162 additions and 71 deletions
|
|
@ -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,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -79,3 +79,7 @@ export const ReactionsContainer = style({
|
|||
},
|
||||
},
|
||||
});
|
||||
|
||||
export const ReactionsTooltipText = style({
|
||||
wordBreak: 'break-all',
|
||||
});
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue