Use css to style UI

This commit is contained in:
Yuya Ochiai 2017-05-17 01:38:03 +09:00
parent a6b27238bc
commit 7be7f8dcc2
19 changed files with 234 additions and 218 deletions

View file

@ -45,6 +45,7 @@
"babel-preset-react": "^6.24.1", "babel-preset-react": "^6.24.1",
"chai": "^3.5.0", "chai": "^3.5.0",
"cross-env": "^4.0.0", "cross-env": "^4.0.0",
"css-loader": "^0.28.1",
"devtron": "^1.4.0", "devtron": "^1.4.0",
"electron": "1.6.6", "electron": "1.6.6",
"electron-builder": "17.4.0", "electron-builder": "17.4.0",
@ -56,6 +57,7 @@
"mocha-circleci-reporter": "0.0.2", "mocha-circleci-reporter": "0.0.2",
"npm-run-all": "^4.0.2", "npm-run-all": "^4.0.2",
"spectron": "~3.6.2", "spectron": "~3.6.2",
"style-loader": "^0.17.0",
"url-loader": "^0.5.8", "url-loader": "^0.5.8",
"webpack": "^2.5.1", "webpack": "^2.5.1",
"webpack-dev-server": "^2.4.5", "webpack-dev-server": "^2.4.5",

View file

@ -4,48 +4,21 @@ const React = require('react');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const {Grid, Row, Col} = require('react-bootstrap'); const {Grid, Row, Col} = require('react-bootstrap');
const errorPage = {
tableStyle: {
display: 'table',
width: '100%',
height: '100%',
position: 'absolute',
top: '0',
left: '0'
},
cellStyle: {
display: 'table-cell',
verticalAlign: 'top',
paddingTop: '2em'
},
bullets: {
paddingLeft: '15px',
lineHeight: '1.7'
},
techInfo: {
fontSize: '12px',
color: '#aaa'
}
};
function ErrorView(props) { function ErrorView(props) {
const classNames = ['container', 'errorView']; const classNames = ['container', 'ErrorView'];
if (!props.active) { if (!props.active) {
classNames.push('errorView-hidden'); classNames.push('ErrorView-hidden');
} }
if (props.withTab) { if (props.withTab) {
classNames.push('errorView-with-tab'); classNames.push('ErrorView-with-tab');
} }
return ( return (
<Grid <Grid
id={props.id} id={props.id}
bsClass={classNames.join(' ')} bsClass={classNames.join(' ')}
> >
<div style={errorPage.tableStyle}> <div className='ErrorView-table'>
<div style={errorPage.cellStyle}> <div className='ErrorView-cell'>
<Row> <Row>
<Col <Col
xs={0} xs={0}
@ -63,7 +36,7 @@ function ErrorView(props) {
<hr/> <hr/>
<p>{'We\'re having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work please verify that:'}</p> <p>{'We\'re having trouble connecting to Mattermost. If refreshing this page (Ctrl+R or Command+R) does not work please verify that:'}</p>
<br/> <br/>
<ul style={errorPage.bullets}> <ul className='ErrorView-bullets' >
<li>{'Your computer is connected to the internet.'}</li> <li>{'Your computer is connected to the internet.'}</li>
<li>{'The Mattermost URL '} <li>{'The Mattermost URL '}
<a href={props.errorInfo.validatedURL}> <a href={props.errorInfo.validatedURL}>
@ -75,7 +48,7 @@ function ErrorView(props) {
</a>{' from a browser window.'}</li> </a>{' from a browser window.'}</li>
</ul> </ul>
<br/> <br/>
<div style={errorPage.techInfo}> <div className='ErrorView-techInfo'>
{props.errorInfo.errorDescription}{' ('} {props.errorInfo.errorDescription}{' ('}
{props.errorInfo.errorCode }{')'}</div> {props.errorInfo.errorCode }{')'}</div>
</Col> </Col>

View file

@ -3,14 +3,13 @@ const PropTypes = require('prop-types');
function HoveringURL(props) { function HoveringURL(props) {
return ( return (
<div style={props.style}> <div className='HoveringURL HoveringURL-left'>
{props.targetURL} {props.targetURL}
</div> </div>
); );
} }
HoveringURL.propTypes = { HoveringURL.propTypes = {
style: PropTypes.object,
targetURL: PropTypes.string targetURL: PropTypes.string
}; };

View file

@ -14,28 +14,6 @@ const HoveringURL = require('./HoveringURL.jsx');
const NewTeamModal = require('./NewTeamModal.jsx'); const NewTeamModal = require('./NewTeamModal.jsx');
// Todo: Need to consider better way to apply styles
const styles = {
hoveringURL: {
color: 'gray',
backgroundColor: 'whitesmoke',
maxWidth: '95%',
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
position: 'absolute',
bottom: 0,
paddingLeft: 4,
paddingRight: 16,
paddingTop: 2,
paddingBottom: 2,
borderTopRightRadius: 4,
borderTop: 'solid thin lightgray',
borderRight: 'solid thin lightgray',
pointerEvents: 'none'
}
};
const MainPage = createReactClass({ const MainPage = createReactClass({
propTypes: { propTypes: {
onUnreadCountChange: PropTypes.func.isRequired, onUnreadCountChange: PropTypes.func.isRequired,
@ -313,7 +291,7 @@ const MainPage = createReactClass({
/> />
); );
return ( return (
<div> <div className='MainPage'>
<LoginModal <LoginModal
show={this.state.loginQueue.length !== 0} show={this.state.loginQueue.length !== 0}
request={request} request={request}
@ -335,7 +313,6 @@ const MainPage = createReactClass({
null : null :
<HoveringURL <HoveringURL
key='hoveringURL' key='hoveringURL'
style={styles.hoveringURL}
targetURL={this.state.targetURL} targetURL={this.state.targetURL}
/> } /> }
</ReactCSSTransitionGroup> </ReactCSSTransitionGroup>

View file

@ -105,11 +105,6 @@ class NewTeamModal extends React.Component {
} }
render() { render() {
const noBottomSpaceing = {
paddingBottom: 0,
marginBottom: 0
};
if (this.wasShown !== this.props.show && this.props.show) { if (this.wasShown !== this.props.show && this.props.show) {
this.initializeOnShow(); this.initializeOnShow();
} }
@ -117,6 +112,8 @@ class NewTeamModal extends React.Component {
return ( return (
<Modal <Modal
bsClass='modal'
className='NewTeamModal'
show={this.props.show} show={this.props.show}
id='newServerModal' id='newServerModal'
onHide={this.props.onClose} onHide={this.props.onClose}
@ -156,8 +153,8 @@ class NewTeamModal extends React.Component {
<HelpBlock>{'The name of the server displayed on your desktop app tab bar.'}</HelpBlock> <HelpBlock>{'The name of the server displayed on your desktop app tab bar.'}</HelpBlock>
</FormGroup> </FormGroup>
<FormGroup <FormGroup
className='NewTeamModal-noBottomSpace'
validationState={this.getTeamUrlValidationState()} validationState={this.getTeamUrlValidationState()}
style={noBottomSpaceing}
> >
<ControlLabel>{'Server URL'}</ControlLabel> <ControlLabel>{'Server URL'}</ControlLabel>
<FormControl <FormControl
@ -168,9 +165,7 @@ class NewTeamModal extends React.Component {
onChange={this.handleTeamUrlChange.bind(this)} onChange={this.handleTeamUrlChange.bind(this)}
/> />
<FormControl.Feedback/> <FormControl.Feedback/>
<HelpBlock <HelpBlock className='NewTeamModal-noBottomSpace'>{'The URL of your Mattermost server. Must start with http:// or https://.'}</HelpBlock>
style={noBottomSpaceing}
>{'The URL of your Mattermost server. Must start with http:// or https://.'}</HelpBlock>
</FormGroup> </FormGroup>
</form> </form>
</Modal.Body> </Modal.Body>

View file

@ -2,61 +2,56 @@ const React = require('react');
const PropTypes = require('prop-types'); const PropTypes = require('prop-types');
const {Nav, NavItem, Button} = require('react-bootstrap'); const {Nav, NavItem, Button} = require('react-bootstrap');
class TabBar extends React.Component { function AddServerButton(props) {
render() { return (
var self = this; <NavItem
var tabs = this.props.teams.map((team, index) => { className='AddServerButton'
var unreadCount = 0; key='addServerButton'
var badgeStyle = { eventKey='addServerButton'
background: '#FF1744', >
float: 'right', <Button
color: 'white', id='tabBarAddNewTeam'
minWidth: '19px', onClick={props.onClick}
fontSize: '12px', className='AddServerButton-button'
textAlign: 'center', title='Add new server'
lineHeight: '20px', >
height: '19px', {'+'}
marginLeft: '5px', </Button>
marginTop: '5px', </NavItem>
borderRadius: '50%' );
}; }
if (self.props.unreadCounts[index] > 0) { AddServerButton.propTypes = {
unreadCount = self.props.unreadCounts[index]; onClick: PropTypes.func
} };
if (self.props.unreadAtActive[index]) {
unreadCount += 1;
}
var mentionCount = 0; function TabBar(props) {
if (self.props.mentionCounts[index] > 0) { const tabs = props.teams.map((team, index) => {
mentionCount = self.props.mentionCounts[index]; let unreadCount = 0;
} if (props.unreadCounts[index] > 0) {
if (self.props.mentionAtActiveCounts[index] > 0) { unreadCount = props.unreadCounts[index];
mentionCount += self.props.mentionAtActiveCounts[index]; }
} if (props.unreadAtActive[index]) {
unreadCount += 1;
}
var badgeDiv; let mentionCount = 0;
if (mentionCount !== 0) { if (props.mentionCounts[index] > 0) {
badgeDiv = ( mentionCount = props.mentionCounts[index];
<div style={badgeStyle}> }
{mentionCount} if (props.mentionAtActiveCounts[index] > 0) {
</div>); mentionCount += props.mentionAtActiveCounts[index];
} }
var id = 'teamTabItem' + index;
if (unreadCount === 0) { let badgeDiv;
return ( if (mentionCount !== 0) {
<NavItem badgeDiv = (
className='teamTabItem' <div className='TabBar-badge'>
key={id} {mentionCount}
id={id} </div>);
eventKey={index} }
> const id = 'teamTabItem' + index;
{ team.name } if (unreadCount === 0) {
{ ' ' }
{ badgeDiv }
</NavItem>);
}
return ( return (
<NavItem <NavItem
className='teamTabItem' className='teamTabItem'
@ -64,56 +59,35 @@ class TabBar extends React.Component {
id={id} id={id}
eventKey={index} eventKey={index}
> >
<b>{ team.name }</b> { team.name }
{ ' ' } { ' ' }
{ badgeDiv } { badgeDiv }
</NavItem>); </NavItem>);
}); }
return (
<Nav
id={this.props.id}
bsStyle='tabs'
activeKey={this.props.activeKey}
onSelect={this.props.onSelect}
>
{ tabs }
{ this.renderAddTeamButton() }
</Nav>
);
}
renderAddTeamButton() {
var tabButton = {
border: 'none',
fontSize: '20px',
height: '31px',
padding: '2px 0 0 0',
width: '40px',
color: '#999',
fontWeight: 'bold',
margin: '0',
borderRadius: '2px 2px 0 0',
outline: 'none'
};
return ( return (
<NavItem <NavItem
className='buttonTab' className='teamTabItem'
key='addServerButton' key={id}
eventKey='addServerButton' id={id}
eventKey={index}
> >
<Button <b>{ team.name }</b>
id='tabBarAddNewTeam' { ' ' }
onClick={this.props.onAddServer} { badgeDiv }
style={tabButton} </NavItem>);
className='btn-tabButton' });
title='Add new server' return (
> <Nav
{'+'} className='TabBar'
</Button> id={props.id}
</NavItem> bsStyle='tabs'
); activeKey={props.activeKey}
} onSelect={props.onSelect}
>
{ tabs }
<AddServerButton onClick={props.onAddServer}/>
</Nav>
);
} }
TabBar.propTypes = { TabBar.propTypes = {
@ -121,6 +95,8 @@ TabBar.propTypes = {
id: PropTypes.string, id: PropTypes.string,
onSelect: PropTypes.func, onSelect: PropTypes.func,
teams: PropTypes.array, teams: PropTypes.array,
mentionCounts: PropTypes.array,
mentionAtActiveCounts: PropTypes.array,
onAddServer: PropTypes.func onAddServer: PropTypes.func
}; };

View file

@ -15,17 +15,10 @@ class TeamListItem extends React.Component {
this.props.onTeamEditing(); this.props.onTeamEditing();
} }
render() { render() {
var style = {
left: {
display: 'inline-block',
width: 'calc(100% - 100px)',
cursor: 'pointer'
}
};
return ( return (
<div className='teamListItem list-group-item'> <div className='TeamListItem list-group-item'>
<div <div
style={style.left} className='TeamListItem-left'
onClick={this.props.onTeamClick} onClick={this.props.onTeamClick}
> >
<h4 className='list-group-item-heading'>{ this.props.name }</h4> <h4 className='list-group-item-heading'>{ this.props.name }</h4>

View file

@ -1,4 +1,4 @@
.errorView { .ErrorView {
position: absolute; position: absolute;
top: 0px; top: 0px;
right: 0px; right: 0px;
@ -6,10 +6,35 @@
left: 0px; left: 0px;
} }
.errorView-with-tab { .ErrorView-with-tab {
top: 32px; top: 32px;
} }
.errorView-hidden { .ErrorView-hidden {
visibility: hidden; visibility: hidden;
} }
.ErrorView-tableStyle {
display: table;
width: 100%;
height: 100%;
position: absolute;
top: 0;
left: 0;
}
.ErrorView-cellStyle {
display: table-cell;
vertical-align: top;
padding-top: 2em;
}
.ErrorView-bullets {
padding-left: 15px;
line-height: 1.7;
}
.ErrorView-techInfo {
font-size: 12px;
color: #aaa;
}

View file

@ -0,0 +1,18 @@
.HoveringURL {
color: gray;
background-color: whitesmoke;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
padding-left: 4px;
padding-right: 16px;
padding-top: 2px;
padding-bottom: 2px;
border-top: solid thin lightgray;
pointer-events: none;
}
.HoveringURL-left {
border-top-right-radius: 4px;
border-right: solid thin lightgray;
}

View file

@ -0,0 +1,9 @@
/*.mainPage,.mainPage > .container-fluid, .mainPage-viewsRow {
height: 100%;
}*/
.MainPage .HoveringURL {
max-width: 95%;
position: absolute;
bottom: 0px;
}

View file

@ -0,0 +1,4 @@
.NewTeamModal-noBottomSpace {
padding-bottom: 0px;
margin-bottom: 0px;
}

View file

@ -0,0 +1,61 @@
.TabBar>li>a {
background: rgba(0, 0, 0, 0.05);
border-radius: 2px 2px 0 0;
border: 1px solid #ddd;
color: #888;
height: 31px;
line-height: 29px;
margin-right: -1px;
margin-top: 0px;
padding: 0 15px;
}
.TabBar .AddServerButton>a {
border: none;
background: transparent;
margin: 0px;
margin-left: 1px; /*Has no border and would be placed above the last item's border due to it's margin-right: -1px */
padding: 0;
margin-bottom: 1px;
}
.TabBar .TabBar-badge {
background: #FF1744;
float: right;
color: white;
min-width: 19px;
font-size: 12px;
text-align: center;
line-height: 20px;
height: 19px;
margin-left: 5px;
margin-top: 5px;
border-radius: 50%;
};
.TabBar .AddServerButton-button {
background-color: #fff;
border-color: #ccc;
color: #333;
margin-top: 3px;
}
.TabBar .AddServerButton-button {
border: none;
font-size: 20px;
height: 31px;
padding: 2px 0 0 0;
width: 40px;
color: #999;
font-weight: bold;
margin: 0;
border-radius: 2px 2px 0 0;
outline: none;
}
.TabBar .AddServerButton-button:hover {
color: #333;
background-color: #e6e6e6;
border-color: #adadad;
}

View file

@ -0,0 +1,9 @@
.TeamListItem:hover {
background: #eee;
}
.TeamListItem-left {
display: inline-block;
width: calc(100% - 100px);
cursor: pointer;
}

View file

@ -0,0 +1,7 @@
@import url("ErrorView.css");
@import url("HoveringURL.css");
@import url("MainPage.css");
@import url("MattermostView.css");
@import url("NewTeamModal.css");
@import url("TabBar.css");
@import url("TeamListItem.css");

View file

@ -1,5 +1,4 @@
@import url("components/MattermostView.css"); @import url("components/index.css");
@import url("components/ErrorView.css");
.hovering-enter { .hovering-enter {
opacity: 0.01; opacity: 0.01;
@ -19,40 +18,6 @@
transition: opacity 500ms ease-in-out; transition: opacity 500ms ease-in-out;
} }
.btn-tabButton {
background-color: #fff;
border-color: #ccc;
color: #333;
margin-top: 3px;
}
.btn-tabButton:hover {
color: #333;
background-color: #e6e6e6;
border-color: #adadad;
}
.nav-tabs>li>a {
background: rgba(0, 0, 0, 0.05);
border-radius: 2px 2px 0 0;
border: 1px solid #ddd;
color: #888;
height: 31px;
line-height: 29px;
margin-right: -1px;
margin-top: 0px;
padding: 0 15px;
}
.nav-tabs>li.buttonTab>a {
border: none;
background: transparent;
margin: 0px;
margin-left: 1px; /*Has no border and would be placed above the last item's border due to it's margin-right: -1px */
padding: 0;
margin-bottom: 1px;
}
.has-error .control-label, .has-error .control-label,
.has-error .help-block { .has-error .help-block {
color: #333; color: #333;

View file

@ -1,8 +1,4 @@
.teamListItem:hover {
background: #eee;
}
.IndicatorContainer { .IndicatorContainer {
position: absolute; position: absolute;
height: 100%; height: 100%;

View file

@ -4,7 +4,6 @@
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css"> <link rel="stylesheet" href="../node_modules/bootstrap/dist/css/bootstrap.min.css">
<link rel="stylesheet" href="css/index.css">
</head> </head>
<body> <body>

View file

@ -1,5 +1,7 @@
'use strict'; 'use strict';
require('./css/index.css');
window.eval = global.eval = () => { window.eval = global.eval = () => {
throw new Error('Sorry, Mattermost does not support window.eval() for security reasons.'); throw new Error('Sorry, Mattermost does not support window.eval() for security reasons.');
}; };

View file

@ -25,6 +25,12 @@ module.exports = merge(base, {
plugins: ['transform-object-rest-spread'] plugins: ['transform-object-rest-spread']
} }
} }
}, {
test: /\.css$/,
use: [
{loader: 'style-loader'},
{loader: 'css-loader'}
]
}, { }, {
test: /\.mp3$/, test: /\.mp3$/,
use: { use: {