diff --git a/src/app/hooks/useRoomStateUpdate.js b/src/app/hooks/useRoomStateUpdate.js new file mode 100644 index 00000000..49979146 --- /dev/null +++ b/src/app/hooks/useRoomStateUpdate.js @@ -0,0 +1,23 @@ +/* eslint-disable import/prefer-default-export */ +import { useEffect } from 'react'; + +import initMatrix from '../../client/initMatrix'; + +import { useForceUpdate } from './useForceUpdate'; + +export function useRoomStateUpdate(roomId) { + const [, forceUpdate] = useForceUpdate(); + const mx = initMatrix.matrixClient; + + useEffect(() => { + const handleStateEvent = (event) => { + if (event.getRoomId() !== roomId) return; + forceUpdate(); + }; + + mx.on('RoomState.events', handleStateEvent); + return () => { + mx.removeListener('RoomState.events', handleStateEvent); + }; + }, [roomId]); +} diff --git a/src/app/molecules/room-integrations/RoomIntegrations.jsx b/src/app/molecules/room-integrations/RoomIntegrations.jsx new file mode 100644 index 00000000..83b7dce5 --- /dev/null +++ b/src/app/molecules/room-integrations/RoomIntegrations.jsx @@ -0,0 +1,82 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './RoomIntegrations.scss'; + +import { getHttpUriForMxc } from 'matrix-js-sdk'; +import { blurOnBubbling } from '../../atoms/button/script'; + +import initMatrix from '../../../client/initMatrix'; +import colorMXID from '../../../util/colorMXID'; + +import Avatar from '../../atoms/avatar/Avatar'; +import Text from '../../atoms/text/Text'; +import { MenuHeader } from '../../atoms/context-menu/ContextMenu'; +import { useRoomStateUpdate } from '../../hooks/useRoomStateUpdate'; + +function Bridge({ + name, bot, avatarSrc, channel, url, +}) { + return ( +
+ blurOnBubbling(e, '.bridge')} + target="_blank" + rel="noreferrer" + > + +
+ {name} + {channel} +
+
+
+ ); +} + +Bridge.defaultProps = { + bot: null, + avatarSrc: null, + url: null, +}; + +Bridge.propTypes = { + name: PropTypes.string.isRequired, + bot: PropTypes.string, + avatarSrc: PropTypes.string, + channel: PropTypes.string.isRequired, + url: PropTypes.string, +}; + +function RoomIntegrations({ roomId }) { + useRoomStateUpdate(roomId); + const mx = initMatrix.matrixClient; + const room = mx.getRoom(roomId); + const bEvents = room.currentState.getStateEvents('uk.half-shot.bridge'); + + return ( +
+ Bridges + {bEvents.map((event) => { + const { protocol, channel, bridgebot } = event.getContent(); + return ( + + ); + })} +
+ ); +} + +RoomIntegrations.propTypes = { + roomId: PropTypes.string.isRequired, +}; + +export default RoomIntegrations; diff --git a/src/app/molecules/room-integrations/RoomIntegrations.scss b/src/app/molecules/room-integrations/RoomIntegrations.scss new file mode 100644 index 00000000..b5b82c53 --- /dev/null +++ b/src/app/molecules/room-integrations/RoomIntegrations.scss @@ -0,0 +1,28 @@ +.bridge { + width: 100%; + padding: var(--sp-extra-tight) var(--sp-normal); + display: flex; + align-items: center; + + &__container { + display: flex; + } + + @media (hover: hover) { + &:hover { + background-color: var(--bg-surface-hover); + text-decoration: none; + } + } + &:focus { + outline: none; + background-color: var(--bg-surface-hover); + } + &:active { + background-color: var(--bg-surface-active); + } + + &__text { + margin-left: var(--sp-tight); + } +} diff --git a/src/app/molecules/room-permissions/RoomPermissions.jsx b/src/app/molecules/room-permissions/RoomPermissions.jsx index da8720cd..734fa7b2 100644 --- a/src/app/molecules/room-permissions/RoomPermissions.jsx +++ b/src/app/molecules/room-permissions/RoomPermissions.jsx @@ -15,7 +15,7 @@ import SettingTile from '../setting-tile/SettingTile'; import ChevronBottomIC from '../../../../public/res/ic/outlined/chevron-bottom.svg'; -import { useForceUpdate } from '../../hooks/useForceUpdate'; +import { useRoomStateUpdate } from '../../hooks/useRoomStateUpdate'; const permissionsInfo = { users_default: { @@ -155,23 +155,6 @@ const spacePermsGroups = { 'Settings permissions': ['state_default', 'm.room.canonical_alias', 'm.room.power_levels'], }; -function useRoomStateUpdate(roomId) { - const [, forceUpdate] = useForceUpdate(); - const mx = initMatrix.matrixClient; - - useEffect(() => { - const handleStateEvent = (event) => { - if (event.getRoomId() !== roomId) return; - forceUpdate(); - }; - - mx.on('RoomState.events', handleStateEvent); - return () => { - mx.removeListener('RoomState.events', handleStateEvent); - }; - }, [roomId]); -} - function RoomPermissions({ roomId }) { useRoomStateUpdate(roomId); const mx = initMatrix.matrixClient; diff --git a/src/app/organisms/room/RoomSettings.jsx b/src/app/organisms/room/RoomSettings.jsx index 63277347..21f9d53f 100644 --- a/src/app/organisms/room/RoomSettings.jsx +++ b/src/app/organisms/room/RoomSettings.jsx @@ -23,6 +23,7 @@ import RoomVisibility from '../../molecules/room-visibility/RoomVisibility'; import RoomAliases from '../../molecules/room-aliases/RoomAliases'; import RoomHistoryVisibility from '../../molecules/room-history-visibility/RoomHistoryVisibility'; import RoomEncryption from '../../molecules/room-encryption/RoomEncryption'; +import RoomIntegrations from '../../molecules/room-integrations/RoomIntegrations'; import RoomPermissions from '../../molecules/room-permissions/RoomPermissions'; import RoomMembers from '../../molecules/room-members/RoomMembers'; import RoomEmojis from '../../molecules/room-emojis/RoomEmojis'; @@ -32,6 +33,7 @@ import SettingsIC from '../../../../public/res/ic/outlined/settings.svg'; import EmojiIC from '../../../../public/res/ic/outlined/emoji.svg'; import SearchIC from '../../../../public/res/ic/outlined/search.svg'; import ShieldUserIC from '../../../../public/res/ic/outlined/shield-user.svg'; +import CategoryIC from '../../../../public/res/ic/outlined/category.svg'; import LockIC from '../../../../public/res/ic/outlined/lock.svg'; import AddUserIC from '../../../../public/res/ic/outlined/add-user.svg'; import LeaveArrowIC from '../../../../public/res/ic/outlined/leave-arrow.svg'; @@ -45,6 +47,7 @@ const tabText = { SEARCH: 'Search', MEMBERS: 'Members', EMOJIS: 'Emojis', + INTEGRATIONS: 'Integrations', PERMISSIONS: 'Permissions', SECURITY: 'Security', }; @@ -65,6 +68,10 @@ const tabItems = [{ iconSrc: EmojiIC, text: tabText.EMOJIS, disabled: false, +}, { + iconSrc: CategoryIC, + text: tabText.INTEGRATIONS, + disabled: false, }, { iconSrc: ShieldUserIC, text: tabText.PERMISSIONS, @@ -205,6 +212,7 @@ function RoomSettings({ roomId }) { {selectedTab.text === tabText.SEARCH && } {selectedTab.text === tabText.MEMBERS && } {selectedTab.text === tabText.EMOJIS && } + {selectedTab.text === tabText.INTEGRATIONS && } {selectedTab.text === tabText.PERMISSIONS && } {selectedTab.text === tabText.SECURITY && } diff --git a/src/app/organisms/room/RoomSettings.scss b/src/app/organisms/room/RoomSettings.scss index ab7fca5c..07a9c6db 100644 --- a/src/app/organisms/room/RoomSettings.scss +++ b/src/app/organisms/room/RoomSettings.scss @@ -18,8 +18,8 @@ padding: var(--sp-ultra-tight) var(--sp-extra-tight); border-radius: calc(var(--bo-radius) / 2); cursor: pointer; - - @media (hover:hover) { + + @media (hover: hover) { &:hover { background-color: var(--bg-surface-hover); box-shadow: var(--bs-surface-outline); @@ -40,7 +40,7 @@ margin: var(--sp-extra-loose); } } - + & .tabs { position: sticky; top: 0; @@ -54,7 +54,7 @@ padding: 0 var(--sp-normal); } } - + &__cards-wrapper { padding: 0 var(--sp-normal); @include dir.side(padding, var(--sp-normal), var(--sp-extra-tight)); @@ -74,8 +74,9 @@ } .room-settings .room-permissions__card, +.room-settings .room-integrations__bridges, .room-settings .room-search__form, -.room-settings .room-search__result-item , +.room-settings .room-search__result-item, .room-settings .room-members { @extend .room-settings__card; -} \ No newline at end of file +}