Remove goto cmds from msg input also fix #81
Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
parent
fbeecc0479
commit
88a988d876
6 changed files with 145 additions and 331 deletions
59
src/app/molecules/following-members/FollowingMembers.jsx
Normal file
59
src/app/molecules/following-members/FollowingMembers.jsx
Normal file
|
@ -0,0 +1,59 @@
|
||||||
|
/* eslint-disable react/prop-types */
|
||||||
|
import React, { useState, useEffect } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import './FollowingMembers.scss';
|
||||||
|
|
||||||
|
import initMatrix from '../../../client/initMatrix';
|
||||||
|
import cons from '../../../client/state/cons';
|
||||||
|
import { openReadReceipts } from '../../../client/action/navigation';
|
||||||
|
|
||||||
|
import Text from '../../atoms/text/Text';
|
||||||
|
import RawIcon from '../../atoms/system-icons/RawIcon';
|
||||||
|
import TickMarkIC from '../../../../public/res/ic/outlined/tick-mark.svg';
|
||||||
|
|
||||||
|
import { getUsersActionJsx } from '../../organisms/room/common';
|
||||||
|
|
||||||
|
function FollowingMembers({ roomTimeline }) {
|
||||||
|
const [followingMembers, setFollowingMembers] = useState([]);
|
||||||
|
const { roomId } = roomTimeline;
|
||||||
|
const mx = initMatrix.matrixClient;
|
||||||
|
const { roomsInput } = initMatrix;
|
||||||
|
const myUserId = mx.getUserId();
|
||||||
|
|
||||||
|
const handleOnMessageSent = () => setFollowingMembers([]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const updateFollowingMembers = () => {
|
||||||
|
setFollowingMembers(roomTimeline.getLiveReaders());
|
||||||
|
};
|
||||||
|
updateFollowingMembers();
|
||||||
|
roomTimeline.on(cons.events.roomTimeline.LIVE_RECEIPT, updateFollowingMembers);
|
||||||
|
roomsInput.on(cons.events.roomsInput.MESSAGE_SENT, handleOnMessageSent);
|
||||||
|
return () => {
|
||||||
|
roomTimeline.removeListener(cons.events.roomTimeline.LIVE_RECEIPT, updateFollowingMembers);
|
||||||
|
roomsInput.removeListener(cons.events.roomsInput.MESSAGE_SENT, handleOnMessageSent);
|
||||||
|
};
|
||||||
|
}, [roomTimeline]);
|
||||||
|
|
||||||
|
const filteredM = followingMembers.filter((userId) => userId !== myUserId);
|
||||||
|
|
||||||
|
return filteredM.length !== 0 && (
|
||||||
|
<button
|
||||||
|
className="following-members"
|
||||||
|
onClick={() => openReadReceipts(roomId, followingMembers)}
|
||||||
|
type="button"
|
||||||
|
>
|
||||||
|
<RawIcon
|
||||||
|
size="extra-small"
|
||||||
|
src={TickMarkIC}
|
||||||
|
/>
|
||||||
|
<Text variant="b2">{getUsersActionJsx(roomId, filteredM, 'following the conversation.')}</Text>
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
FollowingMembers.propTypes = {
|
||||||
|
roomTimeline: PropTypes.shape({}).isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
export default FollowingMembers;
|
32
src/app/molecules/following-members/FollowingMembers.scss
Normal file
32
src/app/molecules/following-members/FollowingMembers.scss
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
.following-members {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 var(--sp-normal);
|
||||||
|
display: flex;
|
||||||
|
justify-content: flex-end;
|
||||||
|
align-items: center;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
& .ic-raw {
|
||||||
|
min-width: var(--ic-extra-small);
|
||||||
|
opacity: 0.4;
|
||||||
|
margin: 0 var(--sp-extra-tight);
|
||||||
|
}
|
||||||
|
& .text {
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
color: var(--tc-surface-low);
|
||||||
|
b {
|
||||||
|
color: var(--tc-surface-normal);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&:hover,
|
||||||
|
&:focus {
|
||||||
|
background-color: var(--bg-surface-hover);
|
||||||
|
}
|
||||||
|
&:active {
|
||||||
|
background-color: var(--bg-surface-active);
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,7 +10,6 @@ import LeaveArraowIC from '../../../../public/res/ic/outlined/leave-arrow.svg';
|
||||||
import InviteArraowIC from '../../../../public/res/ic/outlined/invite-arrow.svg';
|
import InviteArraowIC from '../../../../public/res/ic/outlined/invite-arrow.svg';
|
||||||
import InviteCancelArraowIC from '../../../../public/res/ic/outlined/invite-cancel-arrow.svg';
|
import InviteCancelArraowIC from '../../../../public/res/ic/outlined/invite-cancel-arrow.svg';
|
||||||
import UserIC from '../../../../public/res/ic/outlined/user.svg';
|
import UserIC from '../../../../public/res/ic/outlined/user.svg';
|
||||||
import TickMarkIC from '../../../../public/res/ic/outlined/tick-mark.svg';
|
|
||||||
|
|
||||||
function TimelineChange({
|
function TimelineChange({
|
||||||
variant, content, time, onClick,
|
variant, content, time, onClick,
|
||||||
|
@ -33,9 +32,6 @@ function TimelineChange({
|
||||||
case 'avatar':
|
case 'avatar':
|
||||||
iconSrc = UserIC;
|
iconSrc = UserIC;
|
||||||
break;
|
break;
|
||||||
case 'follow':
|
|
||||||
iconSrc = TickMarkIC;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
iconSrc = JoinArraowIC;
|
iconSrc = JoinArraowIC;
|
||||||
break;
|
break;
|
||||||
|
@ -67,7 +63,6 @@ TimelineChange.propTypes = {
|
||||||
variant: PropTypes.oneOf([
|
variant: PropTypes.oneOf([
|
||||||
'join', 'leave', 'invite',
|
'join', 'leave', 'invite',
|
||||||
'invite-cancel', 'avatar', 'other',
|
'invite-cancel', 'avatar', 'other',
|
||||||
'follow',
|
|
||||||
]),
|
]),
|
||||||
content: PropTypes.oneOfType([
|
content: PropTypes.oneOfType([
|
||||||
PropTypes.string,
|
PropTypes.string,
|
||||||
|
|
|
@ -6,31 +6,19 @@ import parse from 'html-react-parser';
|
||||||
import twemoji from 'twemoji';
|
import twemoji from 'twemoji';
|
||||||
|
|
||||||
import initMatrix from '../../../client/initMatrix';
|
import initMatrix from '../../../client/initMatrix';
|
||||||
import cons from '../../../client/state/cons';
|
|
||||||
import { toggleMarkdown } from '../../../client/action/settings';
|
import { toggleMarkdown } from '../../../client/action/settings';
|
||||||
import * as roomActions from '../../../client/action/room';
|
import * as roomActions from '../../../client/action/room';
|
||||||
import {
|
import {
|
||||||
selectTab,
|
|
||||||
selectRoom,
|
|
||||||
openCreateRoom,
|
openCreateRoom,
|
||||||
openPublicRooms,
|
openPublicRooms,
|
||||||
openInviteUser,
|
openInviteUser,
|
||||||
openReadReceipts,
|
|
||||||
} from '../../../client/action/navigation';
|
} from '../../../client/action/navigation';
|
||||||
import { emojis } from '../emoji-board/emoji';
|
import { emojis } from '../emoji-board/emoji';
|
||||||
import AsyncSearch from '../../../util/AsyncSearch';
|
import AsyncSearch from '../../../util/AsyncSearch';
|
||||||
|
|
||||||
import Text from '../../atoms/text/Text';
|
import Text from '../../atoms/text/Text';
|
||||||
import Button from '../../atoms/button/Button';
|
|
||||||
import IconButton from '../../atoms/button/IconButton';
|
|
||||||
import ContextMenu, { MenuHeader } from '../../atoms/context-menu/ContextMenu';
|
|
||||||
import ScrollView from '../../atoms/scroll/ScrollView';
|
import ScrollView from '../../atoms/scroll/ScrollView';
|
||||||
import SettingTile from '../../molecules/setting-tile/SettingTile';
|
import FollowingMembers from '../../molecules/following-members/FollowingMembers';
|
||||||
import TimelineChange from '../../molecules/message/TimelineChange';
|
|
||||||
|
|
||||||
import CmdIC from '../../../../public/res/ic/outlined/cmd.svg';
|
|
||||||
|
|
||||||
import { getUsersActionJsx } from './common';
|
|
||||||
|
|
||||||
const commands = [{
|
const commands = [{
|
||||||
name: 'markdown',
|
name: 'markdown',
|
||||||
|
@ -61,121 +49,6 @@ const commands = [{
|
||||||
exe: (roomId, searchTerm) => openInviteUser(roomId, searchTerm),
|
exe: (roomId, searchTerm) => openInviteUser(roomId, searchTerm),
|
||||||
}];
|
}];
|
||||||
|
|
||||||
function CmdHelp() {
|
|
||||||
return (
|
|
||||||
<ContextMenu
|
|
||||||
placement="top"
|
|
||||||
content={(
|
|
||||||
<>
|
|
||||||
<MenuHeader>General command</MenuHeader>
|
|
||||||
<Text variant="b2">/command_name</Text>
|
|
||||||
<MenuHeader>Go-to commands</MenuHeader>
|
|
||||||
<Text variant="b2">{'>*space_name'}</Text>
|
|
||||||
<Text variant="b2">{'>#room_name'}</Text>
|
|
||||||
<Text variant="b2">{'>@people_name'}</Text>
|
|
||||||
<MenuHeader>Autofill commands</MenuHeader>
|
|
||||||
<Text variant="b2">:emoji_name</Text>
|
|
||||||
<Text variant="b2">@name</Text>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
render={(toggleMenu) => (
|
|
||||||
<IconButton
|
|
||||||
src={CmdIC}
|
|
||||||
size="extra-small"
|
|
||||||
onClick={toggleMenu}
|
|
||||||
tooltip="Commands"
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function ViewCmd() {
|
|
||||||
function renderAllCmds() {
|
|
||||||
return commands.map((command) => (
|
|
||||||
<SettingTile
|
|
||||||
key={command.name}
|
|
||||||
title={command.name}
|
|
||||||
content={(<Text variant="b3">{command.description}</Text>)}
|
|
||||||
/>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
return (
|
|
||||||
<ContextMenu
|
|
||||||
maxWidth={250}
|
|
||||||
placement="top"
|
|
||||||
content={(
|
|
||||||
<>
|
|
||||||
<MenuHeader>General commands</MenuHeader>
|
|
||||||
{renderAllCmds()}
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
render={(toggleMenu) => (
|
|
||||||
<span>
|
|
||||||
<Button onClick={toggleMenu}><span className="text text-b3">View all</span></Button>
|
|
||||||
</span>
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function FollowingMembers({ roomId, roomTimeline, viewEvent }) {
|
|
||||||
const [followingMembers, setFollowingMembers] = useState([]);
|
|
||||||
const mx = initMatrix.matrixClient;
|
|
||||||
const myUserId = mx.getUserId();
|
|
||||||
|
|
||||||
const handleOnMessageSent = () => setFollowingMembers([]);
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const updateFollowingMembers = () => {
|
|
||||||
setFollowingMembers(roomTimeline.getLiveReaders());
|
|
||||||
};
|
|
||||||
updateFollowingMembers();
|
|
||||||
roomTimeline.on(cons.events.roomTimeline.LIVE_RECEIPT, updateFollowingMembers);
|
|
||||||
viewEvent.on('message_sent', handleOnMessageSent);
|
|
||||||
return () => {
|
|
||||||
roomTimeline.removeListener(cons.events.roomTimeline.LIVE_RECEIPT, updateFollowingMembers);
|
|
||||||
viewEvent.removeListener('message_sent', handleOnMessageSent);
|
|
||||||
};
|
|
||||||
}, [roomTimeline]);
|
|
||||||
|
|
||||||
const filteredM = followingMembers.filter((userId) => userId !== myUserId);
|
|
||||||
return filteredM.length !== 0 && (
|
|
||||||
<TimelineChange
|
|
||||||
variant="follow"
|
|
||||||
content={getUsersActionJsx(roomId, filteredM, 'following the conversation.')}
|
|
||||||
time=""
|
|
||||||
onClick={() => openReadReceipts(roomId, followingMembers)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
FollowingMembers.propTypes = {
|
|
||||||
roomId: PropTypes.string.isRequired,
|
|
||||||
roomTimeline: PropTypes.shape({}).isRequired,
|
|
||||||
viewEvent: PropTypes.shape({}).isRequired,
|
|
||||||
};
|
|
||||||
|
|
||||||
function getCmdActivationMessage(prefix) {
|
|
||||||
function genMessage(prime, secondary) {
|
|
||||||
return (
|
|
||||||
<>
|
|
||||||
<span>{prime}</span>
|
|
||||||
<span>{secondary}</span>
|
|
||||||
</>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const cmd = {
|
|
||||||
'/': () => genMessage('General command mode activated. ', 'Type command name for suggestions.'),
|
|
||||||
'>*': () => genMessage('Go-to command mode activated. ', 'Type space name for suggestions.'),
|
|
||||||
'>#': () => genMessage('Go-to command mode activated. ', 'Type room name for suggestions.'),
|
|
||||||
'>@': () => genMessage('Go-to command mode activated. ', 'Type people name for suggestions.'),
|
|
||||||
':': () => genMessage('Emoji autofill command mode activated. ', 'Type emoji shortcut for suggestions.'),
|
|
||||||
'@': () => genMessage('Name autofill command mode activated. ', 'Type name for suggestions.'),
|
|
||||||
};
|
|
||||||
return cmd[prefix]?.();
|
|
||||||
}
|
|
||||||
|
|
||||||
function CmdItem({ onClick, children }) {
|
function CmdItem({ onClick, children }) {
|
||||||
return (
|
return (
|
||||||
<button className="cmd-item" onClick={onClick} type="button">
|
<button className="cmd-item" onClick={onClick} type="button">
|
||||||
|
@ -188,8 +61,8 @@ CmdItem.propTypes = {
|
||||||
children: PropTypes.node.isRequired,
|
children: PropTypes.node.isRequired,
|
||||||
};
|
};
|
||||||
|
|
||||||
function getCmdSuggestions({ prefix, option, suggestions }, fireCmd) {
|
function renderSuggestions({ prefix, option, suggestions }, fireCmd) {
|
||||||
function getGenCmdSuggestions(cmdPrefix, cmds) {
|
function renderCmdSuggestions(cmdPrefix, cmds) {
|
||||||
const cmdOptString = (typeof option === 'string') ? `/${option}` : '/?';
|
const cmdOptString = (typeof option === 'string') ? `/${option}` : '/?';
|
||||||
return cmds.map((cmd) => (
|
return cmds.map((cmd) => (
|
||||||
<CmdItem
|
<CmdItem
|
||||||
|
@ -207,23 +80,7 @@ function getCmdSuggestions({ prefix, option, suggestions }, fireCmd) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRoomsSuggestion(cmdPrefix, rooms) {
|
function renderEmojiSuggestion(emPrefix, emos) {
|
||||||
return rooms.map((room) => (
|
|
||||||
<CmdItem
|
|
||||||
key={room.roomId}
|
|
||||||
onClick={() => {
|
|
||||||
fireCmd({
|
|
||||||
prefix: cmdPrefix,
|
|
||||||
result: room,
|
|
||||||
});
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<Text variant="b2">{room.name}</Text>
|
|
||||||
</CmdItem>
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
function getEmojiSuggestion(emPrefix, emos) {
|
|
||||||
return emos.map((emoji) => (
|
return emos.map((emoji) => (
|
||||||
<CmdItem
|
<CmdItem
|
||||||
key={emoji.hexcode}
|
key={emoji.hexcode}
|
||||||
|
@ -248,7 +105,7 @@ function getCmdSuggestions({ prefix, option, suggestions }, fireCmd) {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNameSuggestion(namePrefix, members) {
|
function renderNameSuggestion(namePrefix, members) {
|
||||||
return members.map((member) => (
|
return members.map((member) => (
|
||||||
<CmdItem
|
<CmdItem
|
||||||
key={member.userId}
|
key={member.userId}
|
||||||
|
@ -265,12 +122,9 @@ function getCmdSuggestions({ prefix, option, suggestions }, fireCmd) {
|
||||||
}
|
}
|
||||||
|
|
||||||
const cmd = {
|
const cmd = {
|
||||||
'/': (cmds) => getGenCmdSuggestions(prefix, cmds),
|
'/': (cmds) => renderCmdSuggestions(prefix, cmds),
|
||||||
'>*': (spaces) => getRoomsSuggestion(prefix, spaces),
|
':': (emos) => renderEmojiSuggestion(prefix, emos),
|
||||||
'>#': (rooms) => getRoomsSuggestion(prefix, rooms),
|
'@': (members) => renderNameSuggestion(prefix, members),
|
||||||
'>@': (peoples) => getRoomsSuggestion(prefix, peoples),
|
|
||||||
':': (emos) => getEmojiSuggestion(prefix, emos),
|
|
||||||
'@': (members) => getNameSuggestion(prefix, members),
|
|
||||||
};
|
};
|
||||||
return cmd[prefix]?.(suggestions);
|
return cmd[prefix]?.(suggestions);
|
||||||
}
|
}
|
||||||
|
@ -319,29 +173,28 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
|
||||||
asyncSearch.search(searchTerm);
|
asyncSearch.search(searchTerm);
|
||||||
}
|
}
|
||||||
function activateCmd(prefix) {
|
function activateCmd(prefix) {
|
||||||
setCmd({ prefix });
|
|
||||||
cmdPrefix = prefix;
|
cmdPrefix = prefix;
|
||||||
|
cmdPrefix = undefined;
|
||||||
|
|
||||||
const { roomList, matrixClient } = initMatrix;
|
const mx = initMatrix.matrixClient;
|
||||||
function getRooms(roomIds) {
|
|
||||||
return roomIds.map((rId) => {
|
|
||||||
const room = matrixClient.getRoom(rId);
|
|
||||||
return {
|
|
||||||
name: room.name,
|
|
||||||
roomId: room.roomId,
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
const setupSearch = {
|
const setupSearch = {
|
||||||
'/': () => asyncSearch.setup(commands, { keys: ['name'], isContain: true }),
|
'/': () => {
|
||||||
'>*': () => asyncSearch.setup(getRooms([...roomList.spaces]), { keys: ['name'], limit: 20 }),
|
asyncSearch.setup(commands, { keys: ['name'], isContain: true });
|
||||||
'>#': () => asyncSearch.setup(getRooms([...roomList.rooms]), { keys: ['name'], limit: 20 }),
|
setCmd({ prefix, suggestions: commands });
|
||||||
'>@': () => asyncSearch.setup(getRooms([...roomList.directs]), { keys: ['name'], limit: 20 }),
|
},
|
||||||
':': () => asyncSearch.setup(emojis, { keys: ['shortcode'], isContain: true, limit: 20 }),
|
':': () => {
|
||||||
'@': () => asyncSearch.setup(matrixClient.getRoom(roomId).getJoinedMembers().map((member) => ({
|
asyncSearch.setup(emojis, { keys: ['shortcode'], isContain: true, limit: 20 });
|
||||||
name: member.name,
|
setCmd({ prefix, suggestions: emojis.slice(26, 46) });
|
||||||
userId: member.userId.slice(1),
|
},
|
||||||
})), { keys: ['name', 'userId'], limit: 20 }),
|
'@': () => {
|
||||||
|
const members = mx.getRoom(roomId).getJoinedMembers().map((member) => ({
|
||||||
|
name: member.name,
|
||||||
|
userId: member.userId.slice(1),
|
||||||
|
}));
|
||||||
|
asyncSearch.setup(members, { keys: ['name', 'userId'], limit: 20 });
|
||||||
|
const endIndex = members.length > 20 ? 20 : members.length;
|
||||||
|
setCmd({ prefix, suggestions: members.slice(0, endIndex) });
|
||||||
|
},
|
||||||
};
|
};
|
||||||
setupSearch[prefix]?.();
|
setupSearch[prefix]?.();
|
||||||
}
|
}
|
||||||
|
@ -351,11 +204,6 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
|
||||||
cmdPrefix = undefined;
|
cmdPrefix = undefined;
|
||||||
}
|
}
|
||||||
function fireCmd(myCmd) {
|
function fireCmd(myCmd) {
|
||||||
if (myCmd.prefix.match(/^>[*#@]$/)) {
|
|
||||||
if (cmd.prefix === '>*') selectTab(myCmd.result.roomId);
|
|
||||||
else selectRoom(myCmd.result.roomId);
|
|
||||||
viewEvent.emit('cmd_fired');
|
|
||||||
}
|
|
||||||
if (myCmd.prefix === '/') {
|
if (myCmd.prefix === '/') {
|
||||||
myCmd.result.exe(roomId, myCmd.option);
|
myCmd.result.exe(roomId, myCmd.option);
|
||||||
viewEvent.emit('cmd_fired');
|
viewEvent.emit('cmd_fired');
|
||||||
|
@ -421,15 +269,11 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
|
||||||
};
|
};
|
||||||
}, [cmd]);
|
}, [cmd]);
|
||||||
|
|
||||||
if (typeof cmd?.error === 'string') {
|
const isError = typeof cmd?.error === 'string';
|
||||||
|
if (cmd === null || isError) {
|
||||||
return (
|
return (
|
||||||
<div className="cmd-bar">
|
<div className="cmd-bar">
|
||||||
<div className="cmd-bar__info">
|
<FollowingMembers roomTimeline={roomTimeline} />
|
||||||
<div className="cmd-bar__info-indicator--error" />
|
|
||||||
</div>
|
|
||||||
<div className="cmd-bar__content">
|
|
||||||
<Text className="cmd-bar__content-error" variant="b2">{cmd.error}</Text>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -437,27 +281,14 @@ function RoomViewCmdBar({ roomId, roomTimeline, viewEvent }) {
|
||||||
return (
|
return (
|
||||||
<div className="cmd-bar">
|
<div className="cmd-bar">
|
||||||
<div className="cmd-bar__info">
|
<div className="cmd-bar__info">
|
||||||
{cmd === null && <CmdHelp />}
|
<Text variant="b3">TAB</Text>
|
||||||
{cmd !== null && typeof cmd.suggestions === 'undefined' && <div className="cmd-bar__info-indicator" /> }
|
|
||||||
{cmd !== null && typeof cmd.suggestions !== 'undefined' && <Text variant="b3">TAB</Text>}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="cmd-bar__content">
|
<div className="cmd-bar__content">
|
||||||
{cmd === null && (
|
<ScrollView horizontal vertical={false} invisible>
|
||||||
<FollowingMembers
|
<div className="cmd-bar__content-suggestions">
|
||||||
roomId={roomId}
|
{ renderSuggestions(cmd, fireCmd) }
|
||||||
roomTimeline={roomTimeline}
|
</div>
|
||||||
viewEvent={viewEvent}
|
</ScrollView>
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{cmd !== null && typeof cmd.suggestions === 'undefined' && <Text className="cmd-bar__content-help" variant="b2">{getCmdActivationMessage(cmd.prefix)}</Text>}
|
|
||||||
{cmd !== null && typeof cmd.suggestions !== 'undefined' && (
|
|
||||||
<ScrollView horizontal vertical={false} invisible>
|
|
||||||
<div className="cmd-bar__content__suggestions">{getCmdSuggestions(cmd, fireCmd)}</div>
|
|
||||||
</ScrollView>
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
<div className="cmd-bar__more">
|
|
||||||
{cmd !== null && cmd.prefix === '/' && <ViewCmd />}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -11,37 +11,14 @@
|
||||||
|
|
||||||
&__info {
|
&__info {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: calc(2 * var(--sp-extra-loose));
|
width: 40px;
|
||||||
padding-left: var(--sp-ultra-tight);
|
margin: 0 10px 0 14px;
|
||||||
[dir=rtl] & {
|
[dir=rtl] & {
|
||||||
padding-left: 0;
|
margin: 0 14px 0 10px;
|
||||||
padding-right: var(--sp-ultra-tight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
& > * {
|
& > * {
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
& .ic-btn-surface {
|
|
||||||
padding: 0;
|
|
||||||
& .ic-raw {
|
|
||||||
background-color: var(--tc-surface-low);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .context-menu .text-b2 {
|
|
||||||
margin: var(--sp-extra-tight) var(--sp-tight);
|
|
||||||
}
|
|
||||||
|
|
||||||
&-indicator,
|
|
||||||
&-indicator--error {
|
|
||||||
width: 8px;
|
|
||||||
height: 8px;
|
|
||||||
border-radius: 50%;
|
|
||||||
background-color: var(--bg-positive);
|
|
||||||
}
|
|
||||||
&-indicator--error {
|
|
||||||
background-color: var(--bg-danger);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&__content {
|
&__content {
|
||||||
|
@ -49,58 +26,14 @@
|
||||||
flex: 1;
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
&-help,
|
&-suggestions {
|
||||||
&-error {
|
|
||||||
@extend .overflow-ellipsis;
|
|
||||||
align-self: center;
|
|
||||||
span {
|
|
||||||
color: var(--tc-surface-low);
|
|
||||||
&:first-child {
|
|
||||||
color: var(--tc-surface-normal)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&-error {
|
|
||||||
color: var(--bg-danger);
|
|
||||||
}
|
|
||||||
&__suggestions {
|
|
||||||
display: flex;
|
|
||||||
height: 100%;
|
height: 100%;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
display: flex;
|
||||||
}
|
align-items: center;
|
||||||
&__more {
|
|
||||||
display: flex;
|
|
||||||
& button {
|
|
||||||
min-width: 0;
|
|
||||||
height: 100%;
|
|
||||||
margin: 0 var(--sp-normal);
|
|
||||||
padding: 0 var(--sp-extra-tight);
|
|
||||||
box-shadow: none;
|
|
||||||
border-radius: var(--bo-radius) var(--bo-radius) 0 0;
|
|
||||||
& .text {
|
|
||||||
color: var(--tc-surface-normal);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
& .setting-tile {
|
|
||||||
margin: var(--sp-tight);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
& .timeline-change {
|
|
||||||
width: 100%;
|
|
||||||
justify-content: flex-end;
|
|
||||||
padding: var(--sp-ultra-tight) var(--sp-normal);
|
|
||||||
border-radius: var(--bo-radius) var(--bo-radius) 0 0;
|
|
||||||
|
|
||||||
&__content {
|
|
||||||
margin: 0;
|
|
||||||
flex: unset;
|
|
||||||
& > .text {
|
& > .text {
|
||||||
@extend .overflow-ellipsis;
|
@extend .overflow-ellipsis;
|
||||||
& b {
|
|
||||||
color: var(--tc-surface-normal);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,7 @@ import MarkdownIC from '../../../../public/res/ic/outlined/markdown.svg';
|
||||||
import FileIC from '../../../../public/res/ic/outlined/file.svg';
|
import FileIC from '../../../../public/res/ic/outlined/file.svg';
|
||||||
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
|
||||||
|
|
||||||
const CMD_REGEX = /(^\/|^>[#*@]|:|@)(\S*)$/;
|
const CMD_REGEX = /(^\/|:|@)(\S*)$/;
|
||||||
let isTyping = false;
|
let isTyping = false;
|
||||||
let isCmdActivated = false;
|
let isCmdActivated = false;
|
||||||
let cmdCursorPos = null;
|
let cmdCursorPos = null;
|
||||||
|
@ -45,8 +45,6 @@ function RoomViewInput({
|
||||||
const inputBaseRef = useRef(null);
|
const inputBaseRef = useRef(null);
|
||||||
const uploadInputRef = useRef(null);
|
const uploadInputRef = useRef(null);
|
||||||
const uploadProgressRef = useRef(null);
|
const uploadProgressRef = useRef(null);
|
||||||
const rightOptionsRef = useRef(null);
|
|
||||||
const escBtnRef = useRef(null);
|
|
||||||
|
|
||||||
const TYPING_TIMEOUT = 5000;
|
const TYPING_TIMEOUT = 5000;
|
||||||
const mx = initMatrix.matrixClient;
|
const mx = initMatrix.matrixClient;
|
||||||
|
@ -90,30 +88,11 @@ function RoomViewInput({
|
||||||
uploadInputRef.current.value = null;
|
uploadInputRef.current.value = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function rightOptionsA11Y(A11Y) {
|
|
||||||
const rightOptions = rightOptionsRef.current.children;
|
|
||||||
for (let index = 0; index < rightOptions.length; index += 1) {
|
|
||||||
rightOptions[index].disabled = !A11Y;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function activateCmd(prefix) {
|
function activateCmd(prefix) {
|
||||||
isCmdActivated = true;
|
isCmdActivated = true;
|
||||||
requestAnimationFrame(() => {
|
|
||||||
inputBaseRef.current.style.boxShadow = '0 0 0 1px var(--bg-positive)';
|
|
||||||
escBtnRef.current.style.display = 'block';
|
|
||||||
});
|
|
||||||
rightOptionsA11Y(false);
|
|
||||||
viewEvent.emit('cmd_activate', prefix);
|
viewEvent.emit('cmd_activate', prefix);
|
||||||
}
|
}
|
||||||
function deactivateCmd() {
|
function deactivateCmd() {
|
||||||
if (inputBaseRef.current !== null) {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
inputBaseRef.current.style.boxShadow = 'var(--bs-surface-border)';
|
|
||||||
escBtnRef.current.style.display = 'none';
|
|
||||||
});
|
|
||||||
rightOptionsA11Y(true);
|
|
||||||
}
|
|
||||||
isCmdActivated = false;
|
isCmdActivated = false;
|
||||||
cmdCursorPos = null;
|
cmdCursorPos = null;
|
||||||
}
|
}
|
||||||
|
@ -121,11 +100,6 @@ function RoomViewInput({
|
||||||
deactivateCmd();
|
deactivateCmd();
|
||||||
viewEvent.emit('cmd_deactivate');
|
viewEvent.emit('cmd_deactivate');
|
||||||
}
|
}
|
||||||
function errorCmd() {
|
|
||||||
requestAnimationFrame(() => {
|
|
||||||
inputBaseRef.current.style.boxShadow = '0 0 0 1px var(--bg-danger)';
|
|
||||||
});
|
|
||||||
}
|
|
||||||
function setCursorPosition(pos) {
|
function setCursorPosition(pos) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
textAreaRef.current.focus();
|
textAreaRef.current.focus();
|
||||||
|
@ -163,7 +137,6 @@ function RoomViewInput({
|
||||||
roomsInput.on(cons.events.roomsInput.UPLOAD_PROGRESS_CHANGES, uploadingProgress);
|
roomsInput.on(cons.events.roomsInput.UPLOAD_PROGRESS_CHANGES, uploadingProgress);
|
||||||
roomsInput.on(cons.events.roomsInput.ATTACHMENT_CANCELED, clearAttachment);
|
roomsInput.on(cons.events.roomsInput.ATTACHMENT_CANCELED, clearAttachment);
|
||||||
roomsInput.on(cons.events.roomsInput.FILE_UPLOADED, clearAttachment);
|
roomsInput.on(cons.events.roomsInput.FILE_UPLOADED, clearAttachment);
|
||||||
viewEvent.on('cmd_error', errorCmd);
|
|
||||||
viewEvent.on('cmd_fired', firedCmd);
|
viewEvent.on('cmd_fired', firedCmd);
|
||||||
navigation.on(cons.events.navigation.REPLY_TO_CLICKED, setUpReply);
|
navigation.on(cons.events.navigation.REPLY_TO_CLICKED, setUpReply);
|
||||||
if (textAreaRef?.current !== null) {
|
if (textAreaRef?.current !== null) {
|
||||||
|
@ -177,7 +150,6 @@ function RoomViewInput({
|
||||||
roomsInput.removeListener(cons.events.roomsInput.UPLOAD_PROGRESS_CHANGES, uploadingProgress);
|
roomsInput.removeListener(cons.events.roomsInput.UPLOAD_PROGRESS_CHANGES, uploadingProgress);
|
||||||
roomsInput.removeListener(cons.events.roomsInput.ATTACHMENT_CANCELED, clearAttachment);
|
roomsInput.removeListener(cons.events.roomsInput.ATTACHMENT_CANCELED, clearAttachment);
|
||||||
roomsInput.removeListener(cons.events.roomsInput.FILE_UPLOADED, clearAttachment);
|
roomsInput.removeListener(cons.events.roomsInput.FILE_UPLOADED, clearAttachment);
|
||||||
viewEvent.removeListener('cmd_error', errorCmd);
|
|
||||||
viewEvent.removeListener('cmd_fired', firedCmd);
|
viewEvent.removeListener('cmd_fired', firedCmd);
|
||||||
navigation.removeListener(cons.events.navigation.REPLY_TO_CLICKED, setUpReply);
|
navigation.removeListener(cons.events.navigation.REPLY_TO_CLICKED, setUpReply);
|
||||||
if (isCmdActivated) deactivateCmd();
|
if (isCmdActivated) deactivateCmd();
|
||||||
|
@ -193,7 +165,7 @@ function RoomViewInput({
|
||||||
};
|
};
|
||||||
}, [roomId]);
|
}, [roomId]);
|
||||||
|
|
||||||
async function sendMessage() {
|
const sendMessage = async () => {
|
||||||
const msgBody = textAreaRef.current.value;
|
const msgBody = textAreaRef.current.value;
|
||||||
if (roomsInput.isSending(roomId)) return;
|
if (roomsInput.isSending(roomId)) return;
|
||||||
if (msgBody.trim() === '' && attachment === null) return;
|
if (msgBody.trim() === '' && attachment === null) return;
|
||||||
|
@ -214,7 +186,7 @@ function RoomViewInput({
|
||||||
viewEvent.emit('message_sent');
|
viewEvent.emit('message_sent');
|
||||||
textAreaRef.current.style.height = 'unset';
|
textAreaRef.current.style.height = 'unset';
|
||||||
if (replyTo !== null) setReplyTo(null);
|
if (replyTo !== null) setReplyTo(null);
|
||||||
}
|
};
|
||||||
|
|
||||||
function processTyping(msg) {
|
function processTyping(msg) {
|
||||||
const isEmptyMsg = msg === '';
|
const isEmptyMsg = msg === '';
|
||||||
|
@ -259,19 +231,16 @@ function RoomViewInput({
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!isCmdActivated) activateCmd(cmdPrefix);
|
if (!isCmdActivated) activateCmd(cmdPrefix);
|
||||||
requestAnimationFrame(() => {
|
|
||||||
inputBaseRef.current.style.boxShadow = '0 0 0 1px var(--bg-caution)';
|
|
||||||
});
|
|
||||||
viewEvent.emit('cmd_process', cmdPrefix, cmdSlug);
|
viewEvent.emit('cmd_process', cmdPrefix, cmdSlug);
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleMsgTyping(e) {
|
const handleMsgTyping = (e) => {
|
||||||
const msg = e.target.value;
|
const msg = e.target.value;
|
||||||
recognizeCmd(e.target.value);
|
recognizeCmd(e.target.value);
|
||||||
if (!isCmdActivated) processTyping(msg);
|
if (!isCmdActivated) processTyping(msg);
|
||||||
}
|
};
|
||||||
|
|
||||||
function handleKeyDown(e) {
|
const handleKeyDown = (e) => {
|
||||||
if (e.keyCode === 13 && e.shiftKey === false) {
|
if (e.keyCode === 13 && e.shiftKey === false) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
|
|
||||||
|
@ -279,13 +248,9 @@ function RoomViewInput({
|
||||||
viewEvent.emit('cmd_exe');
|
viewEvent.emit('cmd_exe');
|
||||||
} else sendMessage();
|
} else sendMessage();
|
||||||
}
|
}
|
||||||
if (e.keyCode === 27 && isCmdActivated) {
|
};
|
||||||
deactivateCmdAndEmit();
|
|
||||||
e.preventDefault();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function handlePaste(e) {
|
const handlePaste = (e) => {
|
||||||
if (e.clipboardData === false) {
|
if (e.clipboardData === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -309,19 +274,19 @@ function RoomViewInput({
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
function addEmoji(emoji) {
|
function addEmoji(emoji) {
|
||||||
textAreaRef.current.value += emoji.unicode;
|
textAreaRef.current.value += emoji.unicode;
|
||||||
textAreaRef.current.focus();
|
textAreaRef.current.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleUploadClick() {
|
const handleUploadClick = () => {
|
||||||
if (attachment === null) uploadInputRef.current.click();
|
if (attachment === null) uploadInputRef.current.click();
|
||||||
else {
|
else {
|
||||||
roomsInput.cancelAttachment(roomId);
|
roomsInput.cancelAttachment(roomId);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
function uploadFileChange(e) {
|
function uploadFileChange(e) {
|
||||||
const file = e.target.files.item(0);
|
const file = e.target.files.item(0);
|
||||||
setAttachment(file);
|
setAttachment(file);
|
||||||
|
@ -356,9 +321,8 @@ function RoomViewInput({
|
||||||
</Text>
|
</Text>
|
||||||
</ScrollView>
|
</ScrollView>
|
||||||
{isMarkdown && <RawIcon size="extra-small" src={MarkdownIC} />}
|
{isMarkdown && <RawIcon size="extra-small" src={MarkdownIC} />}
|
||||||
<button ref={escBtnRef} tabIndex="-1" onClick={deactivateCmdAndEmit} className="btn-cmd-esc" type="button"><Text variant="b3">ESC</Text></button>
|
|
||||||
</div>
|
</div>
|
||||||
<div ref={rightOptionsRef} className="room-input__option-container">
|
<div className="room-input__option-container">
|
||||||
<IconButton
|
<IconButton
|
||||||
onClick={(e) => {
|
onClick={(e) => {
|
||||||
const cords = getEventCords(e);
|
const cords = getEventCords(e);
|
||||||
|
|
Loading…
Reference in a new issue