Add dnd space shortcut (#153)
Signed-off-by: Ajay Bura <ajbura@gmail.com>
This commit is contained in:
parent
a7a5b08ad8
commit
b8fe4c937e
3 changed files with 353 additions and 105 deletions
129
package-lock.json
generated
129
package-lock.json
generated
|
@ -31,6 +31,8 @@
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-autosize-textarea": "^7.1.0",
|
"react-autosize-textarea": "^7.1.0",
|
||||||
|
"react-dnd": "^15.1.1",
|
||||||
|
"react-dnd-html5-backend": "^15.1.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-google-recaptcha": "^2.1.0",
|
"react-google-recaptcha": "^2.1.0",
|
||||||
"react-modal": "^3.14.4",
|
"react-modal": "^3.14.4",
|
||||||
|
@ -2422,6 +2424,21 @@
|
||||||
"url": "https://opencollective.com/popperjs"
|
"url": "https://opencollective.com/popperjs"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@react-dnd/asap": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ=="
|
||||||
|
},
|
||||||
|
"node_modules/@react-dnd/invariant": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-keberJRIqPX15IK3SWS/iO1t/kGETiL1oczKrDitAaMnQ+kpHf81l3MrRmFjvfqcnApE+izEvwM6GsyoIcpsVA=="
|
||||||
|
},
|
||||||
|
"node_modules/@react-dnd/shallowequal": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-1ELWQdJB2UrCXTKK5cCD9uGLLIwECLIEdttKA255owdpchtXohIjZBTlFJszwYi2ZKe2Do+QvUzsGyGCMNwbdw=="
|
||||||
|
},
|
||||||
"node_modules/@tippyjs/react": {
|
"node_modules/@tippyjs/react": {
|
||||||
"version": "4.2.6",
|
"version": "4.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
||||||
|
@ -2605,7 +2622,7 @@
|
||||||
"version": "16.11.6",
|
"version": "16.11.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
|
||||||
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
|
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
|
||||||
"dev": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"node_modules/@types/qs": {
|
"node_modules/@types/qs": {
|
||||||
"version": "6.9.7",
|
"version": "6.9.7",
|
||||||
|
@ -5267,6 +5284,16 @@
|
||||||
"node": ">=8"
|
"node": ">=8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/dnd-core": {
|
||||||
|
"version": "15.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-15.1.1.tgz",
|
||||||
|
"integrity": "sha512-Mtj/Sltcx7stVXzeDg4g7roTe/AmzRuIf/FYOxX6F8gULbY54w066BlErBOzQfn9RIJ3gAYLGX7wvVvoBSq7ig==",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-dnd/asap": "4.0.0",
|
||||||
|
"@react-dnd/invariant": "3.0.0",
|
||||||
|
"redux": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/dns-equal": {
|
"node_modules/dns-equal": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||||
|
@ -11324,6 +11351,43 @@
|
||||||
"react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0"
|
"react-dom": "^0.14.0 || ^15.0.0 || ^16.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-dnd": {
|
||||||
|
"version": "15.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-15.1.1.tgz",
|
||||||
|
"integrity": "sha512-QLrHtPU08U4c5zop0ANeqrHXaQw2EWLMn8DQoN6/e4eSN/UbB84P49/80Qg0MEF29VLB5vikSoiFh9N8ASNmpQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"@react-dnd/invariant": "3.0.0",
|
||||||
|
"@react-dnd/shallowequal": "3.0.0",
|
||||||
|
"dnd-core": "15.1.1",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"hoist-non-react-statics": "^3.3.2"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"@types/hoist-non-react-statics": ">= 3.3.1",
|
||||||
|
"@types/node": ">= 12",
|
||||||
|
"@types/react": ">= 16",
|
||||||
|
"react": ">= 16.14"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"@types/hoist-non-react-statics": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/node": {
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
|
"@types/react": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/react-dnd-html5-backend": {
|
||||||
|
"version": "15.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-15.1.2.tgz",
|
||||||
|
"integrity": "sha512-mem9QbutUF+aA2YC1y47G3ECjnYV/sCYKSnu5Jd7cbg3fLMPAwbnTf/JayYdnCH5l3eg9akD9dQt+cD0UdF8QQ==",
|
||||||
|
"dependencies": {
|
||||||
|
"dnd-core": "15.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/react-dom": {
|
"node_modules/react-dom": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||||
|
@ -11434,6 +11498,14 @@
|
||||||
"node": ">= 0.10"
|
"node": ">= 0.10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/redux": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
|
||||||
|
"dependencies": {
|
||||||
|
"@babel/runtime": "^7.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/regenerate": {
|
"node_modules/regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||||
|
@ -15715,6 +15787,21 @@
|
||||||
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.2.tgz",
|
"resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.10.2.tgz",
|
||||||
"integrity": "sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ=="
|
"integrity": "sha512-IXf3XA7+XyN7CP9gGh/XB0UxVMlvARGEgGXLubFICsUMGz6Q+DU+i4gGlpOxTjKvXjkJDJC8YdqdKkDj9qZHEQ=="
|
||||||
},
|
},
|
||||||
|
"@react-dnd/asap": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/asap/-/asap-4.0.0.tgz",
|
||||||
|
"integrity": "sha512-0XhqJSc6pPoNnf8DhdsPHtUhRzZALVzYMTzRwV4VI6DJNJ/5xxfL9OQUwb8IH5/2x7lSf7nAZrnzUD+16VyOVQ=="
|
||||||
|
},
|
||||||
|
"@react-dnd/invariant": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/invariant/-/invariant-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-keberJRIqPX15IK3SWS/iO1t/kGETiL1oczKrDitAaMnQ+kpHf81l3MrRmFjvfqcnApE+izEvwM6GsyoIcpsVA=="
|
||||||
|
},
|
||||||
|
"@react-dnd/shallowequal": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@react-dnd/shallowequal/-/shallowequal-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-1ELWQdJB2UrCXTKK5cCD9uGLLIwECLIEdttKA255owdpchtXohIjZBTlFJszwYi2ZKe2Do+QvUzsGyGCMNwbdw=="
|
||||||
|
},
|
||||||
"@tippyjs/react": {
|
"@tippyjs/react": {
|
||||||
"version": "4.2.6",
|
"version": "4.2.6",
|
||||||
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
"resolved": "https://registry.npmjs.org/@tippyjs/react/-/react-4.2.6.tgz",
|
||||||
|
@ -15891,7 +15978,7 @@
|
||||||
"version": "16.11.6",
|
"version": "16.11.6",
|
||||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
|
"resolved": "https://registry.npmjs.org/@types/node/-/node-16.11.6.tgz",
|
||||||
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
|
"integrity": "sha512-ua7PgUoeQFjmWPcoo9khiPum3Pd60k4/2ZGXt18sm2Slk0W0xZTqt5Y0Ny1NyBiN1EVQ/+FaF9NcY4Qe6rwk5w==",
|
||||||
"dev": true
|
"devOptional": true
|
||||||
},
|
},
|
||||||
"@types/qs": {
|
"@types/qs": {
|
||||||
"version": "6.9.7",
|
"version": "6.9.7",
|
||||||
|
@ -18041,6 +18128,16 @@
|
||||||
"path-type": "^4.0.0"
|
"path-type": "^4.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"dnd-core": {
|
||||||
|
"version": "15.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/dnd-core/-/dnd-core-15.1.1.tgz",
|
||||||
|
"integrity": "sha512-Mtj/Sltcx7stVXzeDg4g7roTe/AmzRuIf/FYOxX6F8gULbY54w066BlErBOzQfn9RIJ3gAYLGX7wvVvoBSq7ig==",
|
||||||
|
"requires": {
|
||||||
|
"@react-dnd/asap": "4.0.0",
|
||||||
|
"@react-dnd/invariant": "3.0.0",
|
||||||
|
"redux": "^4.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"dns-equal": {
|
"dns-equal": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/dns-equal/-/dns-equal-1.0.0.tgz",
|
||||||
|
@ -22591,6 +22688,26 @@
|
||||||
"prop-types": "^15.5.6"
|
"prop-types": "^15.5.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-dnd": {
|
||||||
|
"version": "15.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd/-/react-dnd-15.1.1.tgz",
|
||||||
|
"integrity": "sha512-QLrHtPU08U4c5zop0ANeqrHXaQw2EWLMn8DQoN6/e4eSN/UbB84P49/80Qg0MEF29VLB5vikSoiFh9N8ASNmpQ==",
|
||||||
|
"requires": {
|
||||||
|
"@react-dnd/invariant": "3.0.0",
|
||||||
|
"@react-dnd/shallowequal": "3.0.0",
|
||||||
|
"dnd-core": "15.1.1",
|
||||||
|
"fast-deep-equal": "^3.1.3",
|
||||||
|
"hoist-non-react-statics": "^3.3.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"react-dnd-html5-backend": {
|
||||||
|
"version": "15.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-dnd-html5-backend/-/react-dnd-html5-backend-15.1.2.tgz",
|
||||||
|
"integrity": "sha512-mem9QbutUF+aA2YC1y47G3ECjnYV/sCYKSnu5Jd7cbg3fLMPAwbnTf/JayYdnCH5l3eg9akD9dQt+cD0UdF8QQ==",
|
||||||
|
"requires": {
|
||||||
|
"dnd-core": "15.1.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"react-dom": {
|
"react-dom": {
|
||||||
"version": "17.0.2",
|
"version": "17.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
|
||||||
|
@ -22676,6 +22793,14 @@
|
||||||
"resolve": "^1.9.0"
|
"resolve": "^1.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"redux": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/redux/-/redux-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-SH8PglcebESbd/shgf6mii6EIoRM0zrQyjcuQ+ojmfxjTtE0z9Y8pa62iA/OJ58qjP6j27uyW4kUF4jl/jd6sw==",
|
||||||
|
"requires": {
|
||||||
|
"@babel/runtime": "^7.9.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"regenerate": {
|
"regenerate": {
|
||||||
"version": "1.4.2",
|
"version": "1.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
"resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz",
|
||||||
|
|
|
@ -37,6 +37,8 @@
|
||||||
"prop-types": "^15.8.1",
|
"prop-types": "^15.8.1",
|
||||||
"react": "^17.0.2",
|
"react": "^17.0.2",
|
||||||
"react-autosize-textarea": "^7.1.0",
|
"react-autosize-textarea": "^7.1.0",
|
||||||
|
"react-dnd": "^15.1.1",
|
||||||
|
"react-dnd-html5-backend": "^15.1.2",
|
||||||
"react-dom": "^17.0.2",
|
"react-dom": "^17.0.2",
|
||||||
"react-google-recaptcha": "^2.1.0",
|
"react-google-recaptcha": "^2.1.0",
|
||||||
"react-modal": "^3.14.4",
|
"react-modal": "^3.14.4",
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
import React, { useState, useEffect } from 'react';
|
import React, { useState, useEffect, useRef } from 'react';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
import './SideBar.scss';
|
import './SideBar.scss';
|
||||||
|
|
||||||
|
import { DndProvider, useDrag, useDrop } from 'react-dnd';
|
||||||
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
|
|
||||||
import initMatrix from '../../../client/initMatrix';
|
import initMatrix from '../../../client/initMatrix';
|
||||||
import cons from '../../../client/state/cons';
|
import cons from '../../../client/state/cons';
|
||||||
import colorMXID from '../../../util/colorMXID';
|
import colorMXID from '../../../util/colorMXID';
|
||||||
|
@ -8,6 +12,7 @@ import {
|
||||||
selectTab, openShortcutSpaces, openInviteList,
|
selectTab, openShortcutSpaces, openInviteList,
|
||||||
openSearch, openSettings, openReusableContextMenu,
|
openSearch, openSettings, openReusableContextMenu,
|
||||||
} from '../../../client/action/navigation';
|
} from '../../../client/action/navigation';
|
||||||
|
import { moveSpaceShortcut } from '../../../client/action/accountData';
|
||||||
import { abbreviateNumber, getEventCords } from '../../../util/common';
|
import { abbreviateNumber, getEventCords } from '../../../util/common';
|
||||||
|
|
||||||
import Avatar from '../../atoms/avatar/Avatar';
|
import Avatar from '../../atoms/avatar/Avatar';
|
||||||
|
@ -23,7 +28,21 @@ import SearchIC from '../../../../public/res/ic/outlined/search.svg';
|
||||||
import InviteIC from '../../../../public/res/ic/outlined/invite.svg';
|
import InviteIC from '../../../../public/res/ic/outlined/invite.svg';
|
||||||
|
|
||||||
import { useSelectedTab } from '../../hooks/useSelectedTab';
|
import { useSelectedTab } from '../../hooks/useSelectedTab';
|
||||||
import { useSpaceShortcut } from '../../hooks/useSpaceShortcut';
|
|
||||||
|
function useNotificationUpdate() {
|
||||||
|
const { notifications } = initMatrix;
|
||||||
|
const [, forceUpdate] = useState({});
|
||||||
|
useEffect(() => {
|
||||||
|
function onNotificationChanged(roomId, total, prevTotal) {
|
||||||
|
if (total === prevTotal) return;
|
||||||
|
forceUpdate({});
|
||||||
|
}
|
||||||
|
notifications.on(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
|
||||||
|
return () => {
|
||||||
|
notifications.removeListener(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
function ProfileAvatarMenu() {
|
function ProfileAvatarMenu() {
|
||||||
const mx = initMatrix.matrixClient;
|
const mx = initMatrix.matrixClient;
|
||||||
|
@ -66,54 +85,10 @@ function ProfileAvatarMenu() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function useTotalInvites() {
|
function FeaturedTab() {
|
||||||
const { roomList } = initMatrix;
|
|
||||||
const totalInviteCount = () => roomList.inviteRooms.size
|
|
||||||
+ roomList.inviteSpaces.size
|
|
||||||
+ roomList.inviteDirects.size;
|
|
||||||
const [totalInvites, updateTotalInvites] = useState(totalInviteCount());
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
const onInviteListChange = () => {
|
|
||||||
updateTotalInvites(totalInviteCount());
|
|
||||||
};
|
|
||||||
roomList.on(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
|
||||||
return () => {
|
|
||||||
roomList.removeListener(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return [totalInvites];
|
|
||||||
}
|
|
||||||
|
|
||||||
function SideBar() {
|
|
||||||
const { roomList, accountData, notifications } = initMatrix;
|
const { roomList, accountData, notifications } = initMatrix;
|
||||||
const mx = initMatrix.matrixClient;
|
|
||||||
|
|
||||||
const [selectedTab] = useSelectedTab();
|
const [selectedTab] = useSelectedTab();
|
||||||
const [spaceShortcut] = useSpaceShortcut();
|
useNotificationUpdate();
|
||||||
const [totalInvites] = useTotalInvites();
|
|
||||||
const [, forceUpdate] = useState({});
|
|
||||||
|
|
||||||
useEffect(() => {
|
|
||||||
function onNotificationChanged(roomId, total, prevTotal) {
|
|
||||||
if (total === prevTotal) return;
|
|
||||||
forceUpdate({});
|
|
||||||
}
|
|
||||||
notifications.on(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
|
|
||||||
return () => {
|
|
||||||
notifications.removeListener(cons.events.notifications.NOTI_CHANGED, onNotificationChanged);
|
|
||||||
};
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
const openSpaceOptions = (e, spaceId) => {
|
|
||||||
e.preventDefault();
|
|
||||||
openReusableContextMenu(
|
|
||||||
'right',
|
|
||||||
getEventCords(e, '.sidebar-avatar'),
|
|
||||||
(closeMenu) => <SpaceOptions roomId={spaceId} afterOptionSelect={closeMenu} />,
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
function getHomeNoti() {
|
function getHomeNoti() {
|
||||||
const orphans = roomList.getOrphans();
|
const orphans = roomList.getOrphans();
|
||||||
|
@ -145,17 +120,11 @@ function SideBar() {
|
||||||
return noti;
|
return noti;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: bellow operations are heavy.
|
|
||||||
// refactor this component into more smaller components.
|
|
||||||
const dmsNoti = getDMsNoti();
|
const dmsNoti = getDMsNoti();
|
||||||
const homeNoti = getHomeNoti();
|
const homeNoti = getHomeNoti();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="sidebar">
|
<>
|
||||||
<div className="sidebar__scrollable">
|
|
||||||
<ScrollView invisible>
|
|
||||||
<div className="scrollable-content">
|
|
||||||
<div className="featured-container">
|
|
||||||
<SidebarAvatar
|
<SidebarAvatar
|
||||||
tooltip="Home"
|
tooltip="Home"
|
||||||
active={selectedTab === cons.tabs.HOME}
|
active={selectedTab === cons.tabs.HOME}
|
||||||
|
@ -180,38 +149,190 @@ function SideBar() {
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
/>
|
/>
|
||||||
</div>
|
</>
|
||||||
<div className="sidebar-divider" />
|
);
|
||||||
<div className="space-container">
|
}
|
||||||
{
|
|
||||||
spaceShortcut.map((shortcut) => {
|
function DraggableSpaceShortcut({
|
||||||
const sRoomId = shortcut;
|
isActive, spaceId, index, moveShortcut, onDrop,
|
||||||
const room = mx.getRoom(sRoomId);
|
}) {
|
||||||
|
const mx = initMatrix.matrixClient;
|
||||||
|
const { notifications } = initMatrix;
|
||||||
|
const room = mx.getRoom(spaceId);
|
||||||
|
const shortcutRef = useRef(null);
|
||||||
|
const avatarRef = useRef(null);
|
||||||
|
|
||||||
|
const openSpaceOptions = (e, sId) => {
|
||||||
|
e.preventDefault();
|
||||||
|
openReusableContextMenu(
|
||||||
|
'right',
|
||||||
|
getEventCords(e, '.sidebar-avatar'),
|
||||||
|
(closeMenu) => <SpaceOptions roomId={sId} afterOptionSelect={closeMenu} />,
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const [, drop] = useDrop({
|
||||||
|
accept: 'SPACE_SHORTCUT',
|
||||||
|
collect(monitor) {
|
||||||
|
return {
|
||||||
|
handlerId: monitor.getHandlerId(),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
drop(item) {
|
||||||
|
onDrop(item.index, item.spaceId);
|
||||||
|
},
|
||||||
|
hover(item, monitor) {
|
||||||
|
if (!shortcutRef.current) return;
|
||||||
|
|
||||||
|
const dragIndex = item.index;
|
||||||
|
const hoverIndex = index;
|
||||||
|
if (dragIndex === hoverIndex) return;
|
||||||
|
|
||||||
|
const hoverBoundingRect = shortcutRef.current?.getBoundingClientRect();
|
||||||
|
const hoverMiddleY = (hoverBoundingRect.bottom - hoverBoundingRect.top) / 2;
|
||||||
|
const clientOffset = monitor.getClientOffset();
|
||||||
|
const hoverClientY = clientOffset.y - hoverBoundingRect.top;
|
||||||
|
|
||||||
|
if (dragIndex < hoverIndex && hoverClientY < hoverMiddleY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (dragIndex > hoverIndex && hoverClientY > hoverMiddleY) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
moveShortcut(dragIndex, hoverIndex);
|
||||||
|
// eslint-disable-next-line no-param-reassign
|
||||||
|
item.index = hoverIndex;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
const [{ isDragging }, drag] = useDrag({
|
||||||
|
type: 'SPACE_SHORTCUT',
|
||||||
|
item: () => ({ spaceId, index }),
|
||||||
|
collect: (monitor) => ({
|
||||||
|
isDragging: monitor.isDragging(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
|
||||||
|
drag(avatarRef);
|
||||||
|
drop(shortcutRef);
|
||||||
|
|
||||||
|
if (shortcutRef.current) {
|
||||||
|
if (isDragging) shortcutRef.current.style.opacity = 0;
|
||||||
|
else shortcutRef.current.style.opacity = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SidebarAvatar
|
<SidebarAvatar
|
||||||
active={selectedTab === sRoomId}
|
ref={shortcutRef}
|
||||||
key={sRoomId}
|
active={isActive}
|
||||||
tooltip={room.name}
|
tooltip={room.name}
|
||||||
onClick={() => selectTab(shortcut)}
|
onClick={() => selectTab(spaceId)}
|
||||||
onContextMenu={(e) => openSpaceOptions(e, sRoomId)}
|
onContextMenu={(e) => openSpaceOptions(e, spaceId)}
|
||||||
avatar={(
|
avatar={(
|
||||||
<Avatar
|
<Avatar
|
||||||
|
ref={avatarRef}
|
||||||
text={room.name}
|
text={room.name}
|
||||||
bgColor={colorMXID(room.roomId)}
|
bgColor={colorMXID(room.roomId)}
|
||||||
size="normal"
|
size="normal"
|
||||||
imageSrc={room.getAvatarUrl(initMatrix.matrixClient.baseUrl, 42, 42, 'crop') || null}
|
imageSrc={room.getAvatarUrl(initMatrix.matrixClient.baseUrl, 42, 42, 'crop') || null}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
notificationBadge={notifications.hasNoti(sRoomId) ? (
|
notificationBadge={notifications.hasNoti(spaceId) ? (
|
||||||
<NotificationBadge
|
<NotificationBadge
|
||||||
alert={notifications.getHighlightNoti(sRoomId) > 0}
|
alert={notifications.getHighlightNoti(spaceId) > 0}
|
||||||
content={abbreviateNumber(notifications.getTotalNoti(sRoomId)) || null}
|
content={abbreviateNumber(notifications.getTotalNoti(spaceId)) || null}
|
||||||
/>
|
/>
|
||||||
) : null}
|
) : null}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
}
|
||||||
|
|
||||||
|
DraggableSpaceShortcut.propTypes = {
|
||||||
|
spaceId: PropTypes.string.isRequired,
|
||||||
|
isActive: PropTypes.bool.isRequired,
|
||||||
|
index: PropTypes.number.isRequired,
|
||||||
|
moveShortcut: PropTypes.func.isRequired,
|
||||||
|
onDrop: PropTypes.func.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
function SpaceShortcut() {
|
||||||
|
const { accountData } = initMatrix;
|
||||||
|
const [selectedTab] = useSelectedTab();
|
||||||
|
useNotificationUpdate();
|
||||||
|
const [spaceShortcut, setSpaceShortcut] = useState([...accountData.spaceShortcut]);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const handleShortcut = () => setSpaceShortcut([...accountData.spaceShortcut]);
|
||||||
|
accountData.on(cons.events.accountData.SPACE_SHORTCUT_UPDATED, handleShortcut);
|
||||||
|
return () => {
|
||||||
|
accountData.removeListener(cons.events.accountData.SPACE_SHORTCUT_UPDATED, handleShortcut);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
const moveShortcut = (dragIndex, hoverIndex) => {
|
||||||
|
const dragSpaceId = spaceShortcut[dragIndex];
|
||||||
|
const newShortcuts = [...spaceShortcut];
|
||||||
|
newShortcuts.splice(dragIndex, 1);
|
||||||
|
newShortcuts.splice(hoverIndex, 0, dragSpaceId);
|
||||||
|
setSpaceShortcut(newShortcuts);
|
||||||
|
};
|
||||||
|
|
||||||
|
const handleDrop = (dragIndex, dragSpaceId) => {
|
||||||
|
if ([...accountData.spaceShortcut][dragIndex] === dragSpaceId) return;
|
||||||
|
moveSpaceShortcut(dragSpaceId, dragIndex);
|
||||||
|
};
|
||||||
|
|
||||||
|
return (
|
||||||
|
<DndProvider backend={HTML5Backend}>
|
||||||
|
{
|
||||||
|
spaceShortcut.map((shortcut, index) => (
|
||||||
|
<DraggableSpaceShortcut
|
||||||
|
key={shortcut}
|
||||||
|
index={index}
|
||||||
|
spaceId={shortcut}
|
||||||
|
isActive={selectedTab === shortcut}
|
||||||
|
moveShortcut={moveShortcut}
|
||||||
|
onDrop={handleDrop}
|
||||||
|
/>
|
||||||
|
))
|
||||||
}
|
}
|
||||||
|
</DndProvider>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
function useTotalInvites() {
|
||||||
|
const { roomList } = initMatrix;
|
||||||
|
const totalInviteCount = () => roomList.inviteRooms.size
|
||||||
|
+ roomList.inviteSpaces.size
|
||||||
|
+ roomList.inviteDirects.size;
|
||||||
|
const [totalInvites, updateTotalInvites] = useState(totalInviteCount());
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
const onInviteListChange = () => {
|
||||||
|
updateTotalInvites(totalInviteCount());
|
||||||
|
};
|
||||||
|
roomList.on(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
||||||
|
return () => {
|
||||||
|
roomList.removeListener(cons.events.roomList.INVITELIST_UPDATED, onInviteListChange);
|
||||||
|
};
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return [totalInvites];
|
||||||
|
}
|
||||||
|
|
||||||
|
function SideBar() {
|
||||||
|
const [totalInvites] = useTotalInvites();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="sidebar">
|
||||||
|
<div className="sidebar__scrollable">
|
||||||
|
<ScrollView invisible>
|
||||||
|
<div className="scrollable-content">
|
||||||
|
<div className="featured-container">
|
||||||
|
<FeaturedTab />
|
||||||
|
</div>
|
||||||
|
<div className="sidebar-divider" />
|
||||||
|
<div className="space-container">
|
||||||
|
<SpaceShortcut />
|
||||||
<SidebarAvatar
|
<SidebarAvatar
|
||||||
tooltip="Pin spaces"
|
tooltip="Pin spaces"
|
||||||
onClick={() => openShortcutSpaces()}
|
onClick={() => openShortcutSpaces()}
|
||||||
|
|
Loading…
Reference in a new issue