diff --git a/app/lib/components/ChatWidget.jsx b/app/lib/components/ChatWidget.jsx deleted file mode 100644 index 654b7ec..0000000 --- a/app/lib/components/ChatWidget.jsx +++ /dev/null @@ -1,131 +0,0 @@ -import React, { Component } from 'react'; -import { connect } from 'react-redux'; -import PropTypes from 'prop-types'; -import * as stateActions from '../redux/stateActions'; -import * as requestActions from '../redux/requestActions'; -import MessageList from './Chat/MessageList'; - -class ChatWidget extends Component -{ - componentWillReceiveProps(nextProps) - { - if (nextProps.chatmessages.length !== this.props.chatmessages.length) - if (!this.props.showChat) - this.props.increaseBadge(); - } - - render() - { - const { - senderPlaceHolder, - onSendMessage, - onToggleChat, - showChat, - disabledInput, - badge, - autofocus, - displayName - } = this.props; - - return ( -
- { - showChat && -
- -
{ onSendMessage(e, displayName); }} - > - -
-
- } - { -
- { - badge > 0 && {badge} - } -
- } -
- ); - } -} - -ChatWidget.propTypes = -{ - onToggleChat : PropTypes.func, - showChat : PropTypes.bool, - senderPlaceHolder : PropTypes.string, - onSendMessage : PropTypes.func, - disabledInput : PropTypes.bool, - badge : PropTypes.number, - autofocus : PropTypes.bool, - displayName : PropTypes.string, - chatmessages : PropTypes.arrayOf(PropTypes.object), - increaseBadge : PropTypes.func -}; - -ChatWidget.defaultProps = -{ - senderPlaceHolder : 'Type a message...', - autofocus : true -}; - -const mapStateToProps = (state) => -{ - return { - showChat : state.chatbehavior.showChat, - disabledInput : state.chatbehavior.disabledInput, - displayName : state.me.displayName, - badge : state.chatbehavior.badge, - chatmessages : state.chatmessages - }; -}; - -const mapDispatchToProps = (dispatch) => -{ - return { - onToggleChat : () => - { - dispatch(stateActions.toggleChat()); - }, - onSendMessage : (event, displayName) => - { - event.preventDefault(); - const userInput = event.target.message.value; - - if (userInput) - { - dispatch(stateActions.addUserMessage(userInput)); - dispatch(requestActions.sendChatMessage(userInput, displayName)); - } - event.target.message.value = ''; - }, - increaseBadge : () => - { - dispatch(stateActions.increaseBadge()); - } - }; -}; - -const ChatWidgetContainer = connect( - mapStateToProps, - mapDispatchToProps -)(ChatWidget); - -export default ChatWidgetContainer; diff --git a/app/lib/components/Room.jsx b/app/lib/components/Room.jsx index 8232103..cf394ef 100644 --- a/app/lib/components/Room.jsx +++ b/app/lib/components/Room.jsx @@ -65,7 +65,6 @@ class Room extends React.Component { const { room, - toolAreaOpen, amActiveSpeaker, onRoomLinkCopy } = this.props; @@ -155,16 +154,8 @@ class Room extends React.Component delayHide={100} /> -
- {toolAreaOpen ? - - :null - } -
+ + diff --git a/app/lib/components/ToolArea/TabHeader.jsx b/app/lib/components/ToolArea/TabHeader.jsx new file mode 100644 index 0000000..a9514b1 --- /dev/null +++ b/app/lib/components/ToolArea/TabHeader.jsx @@ -0,0 +1,41 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { connect } from 'react-redux'; +import classNames from 'classnames'; +import * as stateActions from '../../redux/stateActions'; + +const TabHeader = ({ currentToolTab, setToolTab, id, name, badge }) => ( +
setToolTab(id)} + > + {name} + + {badge > 0 && ( + {badge} + )} +
+); + +TabHeader.propTypes = { + currentToolTab : PropTypes.string.isRequired, + setToolTab : PropTypes.func.isRequired, + id : PropTypes.string.isRequired, + name : PropTypes.string.isRequired, + badge : PropTypes.number +}; + +const mapStateToProps = (state) => ({ + currentToolTab : state.toolarea.currentToolTab +}); + +const mapDispatchToProps = { + setToolTab : stateActions.setToolTab +}; + +export default connect( + mapStateToProps, + mapDispatchToProps +)(TabHeader); \ No newline at end of file diff --git a/app/lib/components/ToolArea/ToolArea.jsx b/app/lib/components/ToolArea/ToolArea.jsx index 19545c0..0d331c9 100644 --- a/app/lib/components/ToolArea/ToolArea.jsx +++ b/app/lib/components/ToolArea/ToolArea.jsx @@ -1,11 +1,13 @@ -import React from 'react'; +import React, { Fragment } from 'react'; import { connect } from 'react-redux'; import PropTypes from 'prop-types'; +import classNames from 'classnames'; import * as toolTabActions from '../../redux/stateActions'; import ParticipantList from '../ParticipantList/ParticipantList'; import Chat from '../Chat/Chat'; import Settings from '../Settings'; import FileSharing from '../FileSharing'; +import TabHeader from './TabHeader'; class ToolArea extends React.Component { @@ -18,88 +20,61 @@ class ToolArea extends React.Component { const { currentToolTab, + toolAreaOpen, unreadMessages, - unreadFiles, - setToolTab + unreadFiles } = this.props; + const VisibleTab = { + chat : Chat, + files : FileSharing, + users : ParticipantList, + settings : Settings + }[currentToolTab]; + return ( -
-
- - { - setToolTab('chat'); - }} - checked={currentToolTab === 'chat'} - /> - + +
-
- +
+
+ + + + + + +
- setToolTab('files')} - checked={currentToolTab === 'files'} - /> - -
- -
- - - { - setToolTab('users'); - }} - checked={currentToolTab === 'users'} - /> - - -
- -
- - - { - setToolTab('settings'); - }} - checked={currentToolTab === 'settings'} - /> - - -
- +
-
+ ); } } @@ -110,13 +85,15 @@ ToolArea.propTypes = currentToolTab : PropTypes.string.isRequired, setToolTab : PropTypes.func.isRequired, unreadMessages : PropTypes.number.isRequired, - unreadFiles : PropTypes.number.isRequired + unreadFiles : PropTypes.number.isRequired, + toolAreaOpen : PropTypes.bool }; const mapStateToProps = (state) => ({ currentToolTab : state.toolarea.currentToolTab, unreadMessages : state.toolarea.unreadMessages, - unreadFiles : state.toolarea.unreadFiles + unreadFiles : state.toolarea.unreadFiles, + toolAreaOpen : state.toolarea.toolAreaOpen }); const mapDispatchToProps = { diff --git a/app/stylus/components/Chat.styl b/app/stylus/components/Chat.styl index 0541e70..eeaa916 100644 --- a/app/stylus/components/Chat.styl +++ b/app/stylus/components/Chat.styl @@ -1,76 +1,22 @@ -[data-component='ChatWidget'] { - position: absolute; - bottom: 0; - display: flex; - flex-direction: column; - margin: 0 10px 10px 0; - max-width: 300px; - right: 0; - width: 90vw; - z-index: 100; - - > .launcher { - align-self: flex-end; - margin-top: 10px; - background-position: center; - background-size: 70%; - background-repeat: no-repeat; - background-color: rgba(#fff, 0.3); - background-image: url('/resources/images/chat-icon.svg'); - cursor: pointer; - transition-property: opacity, background-color; - transition-duration: 0.15s; - border-radius: 100%; - height: 45px; - width: 45px; - position: relative; - - &.focus { - outline: none; - } - - &.on { - background-color: rgba(#fff, 0.7); - } - - &.disabled { - pointer-events: none; - opacity: 0.5; - } - > .badge{ - border-radius: 50%; - padding: 0.7vmin; - top: -1vmin; - font-size: 1.5vmin; - left: -1vmin; - background: rgba(255,0,0,0.9); - color: #fff; - font-weight: bold; - position: absolute; - } - } -} - -[data-component='Conversation'] { - border-radius: 5px; - box-shadow: 0px 2px 10px 1px #000; -} - [data-component='Chat'] { height: 100%; + display: flex; + flex-grow: 1; + flex-direction: column; } [data-component='MessageList'] { - background-color: rgba(#000, 0.1); - height: 91vmin; overflow-y: scroll; - padding-top: 5px; - border-radius: 5px 5px 0px 0px; + flex-grow: 1; > .message { - margin: 5px; display: flex; word-wrap: break-word; + word-break: break-all; + + &:not(:first-child) { + margin-top: 0.5rem; + } > .client { margin-left: auto; @@ -79,10 +25,10 @@ > .client, > .response { background-color: rgba(#000, 0.1); border-radius: 5px; - max-width: 215px; + max-width: 85%; display: flex; align-items: center; - padding: 6px; + padding: 0.5rem; > .message-avatar { height: 2rem; @@ -90,14 +36,14 @@ } > .message-content { - padding-left: 6px; + padding-left: 0.5rem; > .message-text { - font-size: 1.3vmin; + font-size: 1rem; } > .message-time { - font-size: 1vmin; + font-size: 0.8rem; opacity: 0.8; } } @@ -106,25 +52,22 @@ } [data-component='Sender'] { - align-items: center; display: flex; - background-color: rgba(#000, 0.1); - height: 6vmin; - padding: 0.5vmin; - border-radius: 0 0 5px 5px; + background-color: rgba(0, 0, 0, 0.1); + padding: 1rem; + flex-shrink: 0; + border-radius: 5px; + margin-top: 0.5rem; + height: 3rem; > .new-message { width: 100%; border: 0; - border-radius: 5px; - background-color: rgba(#000, 0.1); - color: #fff; - height: 30px; - padding-left: 10px; - font-size: 1.4vmin; + color: #FFF; + font-size: 1rem; &.focus { outline: none; } } -} +} \ No newline at end of file diff --git a/app/stylus/components/FileSharing.styl b/app/stylus/components/FileSharing.styl index f2c5c31..45ef52a 100644 --- a/app/stylus/components/FileSharing.styl +++ b/app/stylus/components/FileSharing.styl @@ -1,7 +1,7 @@ [data-component='FileSharing'] { display: flex; flex-direction: column; - height: 100%; + flex-grow: 1; > .sharing-toolbar { > .share-file { @@ -22,6 +22,7 @@ > .shared-files { flex-grow: 1; overflow-y: scroll; + margin-top: 0.5rem; > .file-entry { background-color: rgba(0,0,0,0.1); @@ -29,7 +30,10 @@ width: 100%; padding: 0.5rem; display: flex; - margin-top: 0.5rem; + + &:not(:first-child) { + margin-top: 0.5rem; + } &:last-child { margin-bottom: 1.5rem; diff --git a/app/stylus/components/ParticipantList.styl b/app/stylus/components/ParticipantList.styl index 6dd24cc..2096b35 100644 --- a/app/stylus/components/ParticipantList.styl +++ b/app/stylus/components/ParticipantList.styl @@ -6,7 +6,7 @@ 0 4px 20px 0 rgba(0,0,0,0.19); > .list-item { - padding: 0.5vmin; + padding: 0.5rem; border-bottom: 1px solid #CBCBCB; width: 100%; overflow: hidden; @@ -31,15 +31,14 @@ left: 0; top: 0; display: flex; - flex-direction:; row; + flex-direction: row; justify-content: flex-start; align-items: center; - padding: 0.4vmin; transition: opacity 0.3s; > .icon { flex: 0 0 auto; - margin: 0.2vmin; + margin: 0.3rem; border-radius: 2px; background-position: center; background-size: 75%; @@ -85,7 +84,7 @@ > .button { flex: 0 0 auto; - margin: 0.2vmin; + margin: 0.3rem; border-radius: 2px; background-position: center; background-size: 75%; @@ -176,10 +175,10 @@ } > .peer-info { - font-size: 1.4vmin; + font-size: 1rem; border: none; display: flex; - padding: 1vmin; + padding-left: 0.5rem; flex-grow: 1; align-items: center; } diff --git a/app/stylus/components/Room.styl b/app/stylus/components/Room.styl index a21ca60..46e9fd7 100644 --- a/app/stylus/components/Room.styl +++ b/app/stylus/components/Room.styl @@ -164,21 +164,6 @@ } } } - - > .toolarea-wrapper { - position: fixed; - width: 0; - top: 0; - right: 0; - height: 100%; - background-color: rgba(50, 50, 50, 0.9); - transition: width 0.3s; - z-index: 1000; - - &.open { - width: 25%; - } - } } .room-controls { diff --git a/app/stylus/components/ToolArea.styl b/app/stylus/components/ToolArea.styl index d1aa415..12b6428 100644 --- a/app/stylus/components/ToolArea.styl +++ b/app/stylus/components/ToolArea.styl @@ -1,6 +1,83 @@ +.toolarea-shade { + position: fixed; + z-index: 1000; + top: 0; + left: 0; + right: 0; + bottom: 0; + background: rgba(0, 0, 0, 0.6); + display: none; + + &.open { + display: block; + } +} + +[data-component='ToolAreaButton'] { + &.on { + right: 80%; + } +} + +[data-component='ToolArea'] { + &.open { + width: 80%; + } + + .toolarea-shade.open { + display: block; + } +} + +@media (min-width: 600px) { + [data-component='ToolAreaButton'] { + &.on { + right: 60%; + } + } + + [data-component='ToolArea'] { + &.open { + width: 60%; + } + } + + .toolarea-shade.open { + display: none; + } +} + +@media (min-width: 900px) { + [data-component='ToolAreaButton'] { + &.on { + right: 40%; + } + } + + [data-component='ToolArea'] { + &.open { + width: 40%; + } + } +} + +@media (min-width: 1500px) { + [data-component='ToolAreaButton'] { + &.on { + right: 25%; + } + } + + [data-component='ToolArea'] { + &.open { + width: 25%; + } + } +} + [data-component='ToolAreaButton'] { position: absolute; - z-index: 1000; + z-index: 1020; right: 0; height: 36px; width: 36px; @@ -11,10 +88,6 @@ align-items: center; transition: right 0.3s; - &.on { - right: 25%; - } - > .button { flex: 0 0 auto; margin: 4px 0; @@ -79,58 +152,51 @@ width: 100%; height: 100%; color: #fff; + position: fixed; + width: 0; + top: 0; + right: 0; + height: 100%; + background-color: rgba(50, 50, 50, 0.9); + transition: width 0.3s; + z-index: 1010; + display: flex; + flex-direction: column; + border-left: 1px solid #222; - > .tabs { + > .tab-headers { display: flex; - flex-wrap: wrap; - height: 100%; + background: rgba(0, 0, 0, 0.1); + flex-shrink: 0; - > label { - order: 1; - display: block; - padding: 1vmin 0 0.8vmin 0; + > .tab-header { + flex-grow: 1; cursor: pointer; - background: rgba(0,0,0,0.3); - font-weight: bold; - transition: background ease 0.2s; + padding: 1rem; + font-size: 1.2rem; text-align: center; - width: 25%; - font-size: 1.3vmin; - height: 3vmin; + + &.checked { + background: rgba(0, 0, 0, 0.3); + } > .badge { - padding: 0.1vmin 1vmin; + padding: 0.2rem 0.6rem; text-align: center; font-weight: 300; - font-size: 1.2vmin; + font-size: 1rem; color: #fff; background-color: #b12525; border-radius: 2px; margin-left: 1vmin; } } - - > .tab { - order: 99; - flex-grow: 1; - width: 100%; - height: 100%; - display: none; - padding: 1vmin; - background: rgba(0,0,0,0.1); - } - - > input[type="radio"] { - display: none; - } - - > input[type="radio"]:checked + label { - background: rgba(0,0,0,0.1); - } - - > input[type="radio"]:checked + label + .tab { - display: block; - background: rgba(0,0,0,0.1); - } } -} + + > .tab { + flex-grow: 1; + padding: 0.5rem; + display: flex; + flex-direction: column; + } +} \ No newline at end of file