Merge pull request #540 from yuya-oc/css

Use CSS to style UI
This commit is contained in:
Yuya Ochiai 2017-05-24 23:58:54 +09:00 committed by GitHub
commit 5352be1c95
20 changed files with 298 additions and 218 deletions

View file

@ -1131,6 +1131,38 @@ SOFTWARE.
---
## css-loader
This product contains 'css-loader', a css loader module for webpack, by Webpack community.
* HOMEPAGE:
* https://github.com/webpack-contrib/css-loader
* LICENSE:
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
## devtron
This product contains 'devtron', an Electron DevTools extension, by Electron.
@ -1428,6 +1460,38 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
## style-loader
This product contains 'style-loader', a style loader module for webpack, by Webpack community.
* HOMEPAGE:
* https://github.com/webpack-contrib/style-loader
* LICENSE:
Copyright JS Foundation and other contributors
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
'Software'), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
---
## webpack
This product contains 'webpack', a bundler for JavaScript, by Webpack.

View file

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

View file

@ -4,48 +4,21 @@ const React = require('react');
const PropTypes = require('prop-types');
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) {
const classNames = ['container', 'errorView'];
const classNames = ['container', 'ErrorView'];
if (!props.active) {
classNames.push('errorView-hidden');
classNames.push('ErrorView-hidden');
}
if (props.withTab) {
classNames.push('errorView-with-tab');
classNames.push('ErrorView-with-tab');
}
return (
<Grid
id={props.id}
bsClass={classNames.join(' ')}
>
<div style={errorPage.tableStyle}>
<div style={errorPage.cellStyle}>
<div className='ErrorView-table'>
<div className='ErrorView-cell'>
<Row>
<Col
xs={0}
@ -63,7 +36,7 @@ function ErrorView(props) {
<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>
<br/>
<ul style={errorPage.bullets}>
<ul className='ErrorView-bullets' >
<li>{'Your computer is connected to the internet.'}</li>
<li>{'The Mattermost URL '}
<a href={props.errorInfo.validatedURL}>
@ -75,7 +48,7 @@ function ErrorView(props) {
</a>{' from a browser window.'}</li>
</ul>
<br/>
<div style={errorPage.techInfo}>
<div className='ErrorView-techInfo'>
{props.errorInfo.errorDescription}{' ('}
{props.errorInfo.errorCode }{')'}</div>
</Col>

View file

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

View file

@ -14,28 +14,6 @@ const HoveringURL = require('./HoveringURL.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({
propTypes: {
onUnreadCountChange: PropTypes.func.isRequired,
@ -313,7 +291,7 @@ const MainPage = createReactClass({
/>
);
return (
<div>
<div className='MainPage'>
<LoginModal
show={this.state.loginQueue.length !== 0}
request={request}
@ -335,7 +313,6 @@ const MainPage = createReactClass({
null :
<HoveringURL
key='hoveringURL'
style={styles.hoveringURL}
targetURL={this.state.targetURL}
/> }
</ReactCSSTransitionGroup>

View file

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

View file

@ -2,48 +2,55 @@ const React = require('react');
const PropTypes = require('prop-types');
const {Nav, NavItem, Button} = require('react-bootstrap');
class TabBar extends React.Component {
render() {
var self = this;
var tabs = this.props.teams.map((team, index) => {
var unreadCount = 0;
var badgeStyle = {
background: '#FF1744',
float: 'right',
color: 'white',
minWidth: '19px',
fontSize: '12px',
textAlign: 'center',
lineHeight: '20px',
height: '19px',
marginLeft: '5px',
marginTop: '5px',
borderRadius: '50%'
function AddServerButton(props) {
return (
<NavItem
className='AddServerButton'
key='addServerButton'
eventKey='addServerButton'
>
<Button
id='tabBarAddNewTeam'
onClick={props.onClick}
className='AddServerButton-button'
title='Add new server'
>
{'+'}
</Button>
</NavItem>
);
}
AddServerButton.propTypes = {
onClick: PropTypes.func
};
if (self.props.unreadCounts[index] > 0) {
unreadCount = self.props.unreadCounts[index];
function TabBar(props) {
const tabs = props.teams.map((team, index) => {
let unreadCount = 0;
if (props.unreadCounts[index] > 0) {
unreadCount = props.unreadCounts[index];
}
if (self.props.unreadAtActive[index]) {
if (props.unreadAtActive[index]) {
unreadCount += 1;
}
var mentionCount = 0;
if (self.props.mentionCounts[index] > 0) {
mentionCount = self.props.mentionCounts[index];
let mentionCount = 0;
if (props.mentionCounts[index] > 0) {
mentionCount = props.mentionCounts[index];
}
if (self.props.mentionAtActiveCounts[index] > 0) {
mentionCount += self.props.mentionAtActiveCounts[index];
if (props.mentionAtActiveCounts[index] > 0) {
mentionCount += props.mentionAtActiveCounts[index];
}
var badgeDiv;
let badgeDiv;
if (mentionCount !== 0) {
badgeDiv = (
<div style={badgeStyle}>
<div className='TabBar-badge'>
{mentionCount}
</div>);
}
var id = 'teamTabItem' + index;
const id = 'teamTabItem' + index;
if (unreadCount === 0) {
return (
<NavItem
@ -71,56 +78,25 @@ class TabBar extends React.Component {
});
return (
<Nav
id={this.props.id}
className='TabBar'
id={props.id}
bsStyle='tabs'
activeKey={this.props.activeKey}
onSelect={this.props.onSelect}
activeKey={props.activeKey}
onSelect={props.onSelect}
>
{ tabs }
{ this.renderAddTeamButton() }
<AddServerButton onClick={props.onAddServer}/>
</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 (
<NavItem
className='buttonTab'
key='addServerButton'
eventKey='addServerButton'
>
<Button
id='tabBarAddNewTeam'
onClick={this.props.onAddServer}
style={tabButton}
className='btn-tabButton'
title='Add new server'
>
{'+'}
</Button>
</NavItem>
);
}
}
TabBar.propTypes = {
activeKey: PropTypes.number,
id: PropTypes.string,
onSelect: PropTypes.func,
teams: PropTypes.array,
mentionCounts: PropTypes.array,
mentionAtActiveCounts: PropTypes.array,
onAddServer: PropTypes.func
};

View file

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

View file

@ -1,4 +1,4 @@
.errorView {
.ErrorView {
position: absolute;
top: 0px;
right: 0px;
@ -6,10 +6,35 @@
left: 0px;
}
.errorView-with-tab {
.ErrorView-with-tab {
top: 32px;
}
.errorView-hidden {
.ErrorView-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/ErrorView.css");
@import url("components/index.css");
.hovering-enter {
opacity: 0.01;
@ -19,40 +18,6 @@
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 .help-block {
color: #333;

View file

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

View file

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

View file

@ -1,5 +1,7 @@
'use strict';
require('./css/index.css');
window.eval = global.eval = () => {
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']
}
}
}, {
test: /\.css$/,
use: [
{loader: 'style-loader'},
{loader: 'css-loader'}
]
}, {
test: /\.mp3$/,
use: {