From e1a67acde12acbd583978709f9d2ce1d20d142ba Mon Sep 17 00:00:00 2001 From: Ajay Bura Date: Sun, 6 Mar 2022 17:52:04 +0530 Subject: [PATCH] Add manage pin spaces Signed-off-by: Ajay Bura --- src/app/organisms/navigation/SideBar.jsx | 10 +- src/app/organisms/pw/Dialogs.jsx | 2 + .../shortcut-spaces/ShortcutSpaces.jsx | 169 ++++++++++++++++++ .../shortcut-spaces/ShortcutSpaces.scss | 52 ++++++ src/client/action/navigation.js | 6 + src/client/state/cons.js | 2 + src/client/state/navigation.js | 3 + 7 files changed, 242 insertions(+), 2 deletions(-) create mode 100644 src/app/organisms/shortcut-spaces/ShortcutSpaces.jsx create mode 100644 src/app/organisms/shortcut-spaces/ShortcutSpaces.scss diff --git a/src/app/organisms/navigation/SideBar.jsx b/src/app/organisms/navigation/SideBar.jsx index fe4645d2..8ddcd3bc 100644 --- a/src/app/organisms/navigation/SideBar.jsx +++ b/src/app/organisms/navigation/SideBar.jsx @@ -5,8 +5,8 @@ import initMatrix from '../../../client/initMatrix'; import cons from '../../../client/state/cons'; import colorMXID from '../../../util/colorMXID'; import { - selectTab, openInviteList, openSearch, - openSettings, openReusableContextMenu, + selectTab, openShortcutSpaces, openInviteList, + openSearch, openSettings, openReusableContextMenu, } from '../../../client/action/navigation'; import { abbreviateNumber, getEventCords } from '../../../util/common'; @@ -16,6 +16,7 @@ import SpaceOptions from '../../molecules/space-options/SpaceOptions'; import HomeIC from '../../../../public/res/ic/outlined/home.svg'; import UserIC from '../../../../public/res/ic/outlined/user.svg'; +import AddPinIC from '../../../../public/res/ic/outlined/add-pin.svg'; import SearchIC from '../../../../public/res/ic/outlined/search.svg'; import InviteIC from '../../../../public/res/ic/outlined/invite.svg'; @@ -190,6 +191,11 @@ function SideBar() { ); }) } + openShortcutSpaces()} + tooltip="Pin spaces" + iconSrc={AddPinIC} + /> diff --git a/src/app/organisms/pw/Dialogs.jsx b/src/app/organisms/pw/Dialogs.jsx index ca79818a..5c5e115c 100644 --- a/src/app/organisms/pw/Dialogs.jsx +++ b/src/app/organisms/pw/Dialogs.jsx @@ -2,6 +2,7 @@ import React from 'react'; import ReadReceipts from '../read-receipts/ReadReceipts'; import ProfileViewer from '../profile-viewer/ProfileViewer'; +import ShortcutSpaces from '../shortcut-spaces/ShortcutSpaces'; import SpaceAddExisting from '../../molecules/space-add-existing/SpaceAddExisting'; import Search from '../search/Search'; import ViewSource from '../view-source/ViewSource'; @@ -13,6 +14,7 @@ function Dialogs() { + diff --git a/src/app/organisms/shortcut-spaces/ShortcutSpaces.jsx b/src/app/organisms/shortcut-spaces/ShortcutSpaces.jsx new file mode 100644 index 00000000..c379b6b9 --- /dev/null +++ b/src/app/organisms/shortcut-spaces/ShortcutSpaces.jsx @@ -0,0 +1,169 @@ +import React, { useState, useEffect } from 'react'; +import './ShortcutSpaces.scss'; + +import initMatrix from '../../../client/initMatrix'; +import cons from '../../../client/state/cons'; +import navigation from '../../../client/state/navigation'; +import { createSpaceShortcut, deleteSpaceShortcut } from '../../../client/action/accountData'; +import { joinRuleToIconSrc } from '../../../util/matrixUtil'; + +import Text from '../../atoms/text/Text'; +import Button from '../../atoms/button/Button'; +import IconButton from '../../atoms/button/IconButton'; +import Checkbox from '../../atoms/button/Checkbox'; +import Spinner from '../../atoms/spinner/Spinner'; +import RoomSelector from '../../molecules/room-selector/RoomSelector'; +import Dialog from '../../molecules/dialog/Dialog'; + +import PinIC from '../../../../public/res/ic/outlined/pin.svg'; +import PinFilledIC from '../../../../public/res/ic/filled/pin.svg'; +import CrossIC from '../../../../public/res/ic/outlined/cross.svg'; + +import { useSpaceShortcut } from '../../hooks/useSpaceShortcut'; +import { AtoZ } from '../navigation/common'; + +function ShortcutSpacesContent() { + const mx = initMatrix.matrixClient; + const { spaces, roomIdToParents } = initMatrix.roomList; + + const [spaceShortcut] = useSpaceShortcut(); + const spaceWithoutShortcut = [...spaces].filter( + (spaceId) => !spaceShortcut.includes(spaceId), + ).sort(AtoZ); + + const [process, setProcess] = useState(null); + const [selected, setSelected] = useState([]); + + useEffect(() => { + if (process !== null) { + setProcess(null); + setSelected([]); + } + }, [spaceShortcut]); + + const toggleSelection = (sId) => { + if (process !== null) return; + const newSelected = [...selected]; + const selectedIndex = newSelected.indexOf(sId); + + if (selectedIndex > -1) { + newSelected.splice(selectedIndex, 1); + setSelected(newSelected); + return; + } + newSelected.push(sId); + setSelected(newSelected); + }; + + const handleAdd = () => { + setProcess(`Pinning ${selected.length} spaces...`); + createSpaceShortcut(selected); + }; + + const renderSpace = (spaceId, isShortcut) => { + const room = mx.getRoom(spaceId); + if (!room) return null; + + const parentSet = roomIdToParents.get(spaceId); + const parentNames = parentSet + ? [...parentSet].map((parentId) => mx.getRoom(parentId).name) + : undefined; + const parents = parentNames ? parentNames.join(', ') : null; + + const toggleSelected = () => toggleSelection(spaceId); + const deleteShortcut = () => deleteSpaceShortcut(spaceId); + + return ( + + ) : ( + + )} + /> + ); + }; + + return ( + <> + Pinned spaces + {spaceShortcut.length === 0 && No pinned spaces} + {spaceShortcut.map((spaceId) => renderSpace(spaceId, true))} + Unpinned spaces + {spaceWithoutShortcut.length === 0 && No unpinned spaces} + {spaceWithoutShortcut.map((spaceId) => renderSpace(spaceId, false))} + {selected.length !== 0 && ( +
+ {process && } + {process || `${selected.length} spaces selected`} + { !process && ( + + )} +
+ )} + + ); +} + +function useVisibilityToggle() { + const [isOpen, setIsOpen] = useState(false); + + useEffect(() => { + const handleOpen = () => setIsOpen(true); + navigation.on(cons.events.navigation.SHORTCUT_SPACES_OPENED, handleOpen); + return () => { + navigation.removeListener(cons.events.navigation.SHORTCUT_SPACES_OPENED, handleOpen); + }; + }, []); + + const requestClose = () => setIsOpen(false); + + return [isOpen, requestClose]; +} + +function ShortcutSpaces() { + const [isOpen, requestClose] = useVisibilityToggle(); + + return ( + + Pin spaces + + )} + contentOptions={} + onRequestClose={requestClose} + > + { + isOpen + ? + :
+ } +
+ ); +} + +export default ShortcutSpaces; diff --git a/src/app/organisms/shortcut-spaces/ShortcutSpaces.scss b/src/app/organisms/shortcut-spaces/ShortcutSpaces.scss new file mode 100644 index 00000000..686c8cc0 --- /dev/null +++ b/src/app/organisms/shortcut-spaces/ShortcutSpaces.scss @@ -0,0 +1,52 @@ +@use '../../partials/dir'; +@use '../../partials/flex'; + +.shortcut-spaces { + height: 100%; + .dialog__content-container { + padding: 0; + padding-bottom: 80px; + @include dir.side(padding, var(--sp-extra-tight), 0); + + & > .text-b1 { + padding: 0 var(--sp-extra-tight); + } + } + + &__header { + margin-top: var(--sp-extra-tight); + padding: var(--sp-extra-tight); + text-transform: uppercase; + } + + .room-selector { + margin: 0 var(--sp-extra-tight); + } + .room-selector__options { + display: flex; + .checkbox { + margin: 0 6px; + } + } + + &__footer { + position: absolute; + bottom: 0; + left: 0; + width: 100%; + padding: var(--sp-normal); + background-color: var(--bg-surface); + border-top: 1px solid var(--bg-surface-border); + display: flex; + align-items: center; + + & > .text { + @extend .cp-fx__item-one; + padding: 0 var(--sp-tight); + } + + & > button { + @include dir.side(margin, var(--sp-normal), 0); + } + } +} diff --git a/src/client/action/navigation.js b/src/client/action/navigation.js index 817caddf..c145502a 100644 --- a/src/client/action/navigation.js +++ b/src/client/action/navigation.js @@ -52,6 +52,12 @@ export function toggleRoomSettings(tabText) { }); } +export function openShortcutSpaces() { + appDispatcher.dispatch({ + type: cons.actions.navigation.OPEN_SHORTCUT_SPACES, + }); +} + export function openInviteList() { appDispatcher.dispatch({ type: cons.actions.navigation.OPEN_INVITE_LIST, diff --git a/src/client/state/cons.js b/src/client/state/cons.js index aae179f9..141cb1fc 100644 --- a/src/client/state/cons.js +++ b/src/client/state/cons.js @@ -34,6 +34,7 @@ const cons = { OPEN_SPACE_MANAGE: 'OPEN_SPACE_MANAGE', OPEN_SPACE_ADDEXISTING: 'OPEN_SPACE_ADDEXISTING', TOGGLE_ROOM_SETTINGS: 'TOGGLE_ROOM_SETTINGS', + OPEN_SHORTCUT_SPACES: 'OPEN_SHORTCUT_SPACES', OPEN_INVITE_LIST: 'OPEN_INVITE_LIST', OPEN_PUBLIC_ROOMS: 'OPEN_PUBLIC_ROOMS', OPEN_CREATE_ROOM: 'OPEN_CREATE_ROOM', @@ -76,6 +77,7 @@ const cons = { SPACE_MANAGE_OPENED: 'SPACE_MANAGE_OPENED', SPACE_ADDEXISTING_OPENED: 'SPACE_ADDEXISTING_OPENED', ROOM_SETTINGS_TOGGLED: 'ROOM_SETTINGS_TOGGLED', + SHORTCUT_SPACES_OPENED: 'SHORTCUT_SPACES_OPENED', INVITE_LIST_OPENED: 'INVITE_LIST_OPENED', PUBLIC_ROOMS_OPENED: 'PUBLIC_ROOMS_OPENED', CREATE_ROOM_OPENED: 'CREATE_ROOM_OPENED', diff --git a/src/client/state/navigation.js b/src/client/state/navigation.js index ee8d06c2..88de35fb 100644 --- a/src/client/state/navigation.js +++ b/src/client/state/navigation.js @@ -106,6 +106,9 @@ class Navigation extends EventEmitter { action.tabText, ); }, + [cons.actions.navigation.OPEN_SHORTCUT_SPACES]: () => { + this.emit(cons.events.navigation.SHORTCUT_SPACES_OPENED); + }, [cons.actions.navigation.OPEN_INVITE_LIST]: () => { this.emit(cons.events.navigation.INVITE_LIST_OPENED); },