diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..b241190 Binary files /dev/null and b/.DS_Store differ diff --git a/.babelrc b/.babelrc index 9b7d435..f7598c3 100644 --- a/.babelrc +++ b/.babelrc @@ -1,3 +1,4 @@ { - "presets": ["es2015", "stage-0", "react"] + "presets": ["es2015", "stage-0", "react"], + "plugins": ["transform-decorators-legacy"] } diff --git a/.sass-lint.yml b/.sass-lint.yml new file mode 100644 index 0000000..ef6ce50 --- /dev/null +++ b/.sass-lint.yml @@ -0,0 +1,19 @@ +rules: + property-sort-order: + - 2 + force-element-nesting: + - 0 + no-color-literals: + - 2 + - + allow-rgba: true + no-url-protocols: + - 0 + nesting-depth: + - 2 + - + max-depth: 3 +files: + ignore: + - 'node_modules/**/*.scss' + - 'node_modules/**/*.sass' diff --git a/README.md b/README.md index ea4d9fa..f9a6d45 100644 --- a/README.md +++ b/README.md @@ -1 +1,4 @@ # Manage UI to Control tower api-gateway + + +[Map Icons by MapGlyphs.com](mapglyphs.com) diff --git a/app/.DS_Store b/app/.DS_Store new file mode 100644 index 0000000..dbe8f96 Binary files /dev/null and b/app/.DS_Store differ diff --git a/app/assets/.DS_Store b/app/assets/.DS_Store new file mode 100644 index 0000000..cfdaffc Binary files /dev/null and b/app/assets/.DS_Store differ diff --git a/app/assets/logo/logoSideBar.png b/app/assets/logo/logoSideBar.png new file mode 100644 index 0000000..2ec5a0f Binary files /dev/null and b/app/assets/logo/logoSideBar.png differ diff --git a/app/assets/maps/afghanistan.svg b/app/assets/maps/afghanistan.svg new file mode 100644 index 0000000..45a733d --- /dev/null +++ b/app/assets/maps/afghanistan.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/assets/maps/albania.svg b/app/assets/maps/albania.svg new file mode 100644 index 0000000..b644d77 --- /dev/null +++ b/app/assets/maps/albania.svg @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/maps/ecuador.svg b/app/assets/maps/ecuador.svg new file mode 100644 index 0000000..b7d0180 --- /dev/null +++ b/app/assets/maps/ecuador.svg @@ -0,0 +1,48 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/assets/maps/usa.svg b/app/assets/maps/usa.svg new file mode 100644 index 0000000..9719fe0 --- /dev/null +++ b/app/assets/maps/usa.svg @@ -0,0 +1,72 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/index.html b/app/index.html index 948f87f..6d2977a 100644 --- a/app/index.html +++ b/app/index.html @@ -3,8 +3,10 @@ Control Tower UI + + - + diff --git a/app/src/actions/endpoints.jsx b/app/src/actions/endpoints.jsx index 91e4568..d25c95f 100644 --- a/app/src/actions/endpoints.jsx +++ b/app/src/actions/endpoints.jsx @@ -1,12 +1,15 @@ import { BASE_API_URL, GET_ENDPOINTS } from '../constants'; import { showNotification } from './notification'; +import { showLoading } from './loading'; import fetch from '../utils/fetch'; export function getEndpoints() { return (dispatch) => { + dispatch(showLoading(true)); fetch(`${BASE_API_URL}/api/v1/endpoint`, { method: 'GET' }).then((response) => response.json()).then((data) => { dispatch(showNotification('Endpoints obtained successfully')); dispatch({ type: GET_ENDPOINTS, payload: data }); + dispatch(showLoading(false)); }); }; } diff --git a/app/src/actions/loading.jsx b/app/src/actions/loading.jsx new file mode 100644 index 0000000..6f61abf --- /dev/null +++ b/app/src/actions/loading.jsx @@ -0,0 +1,7 @@ +import { SET_VISIBLE } from '../constants'; +export function showLoading(visible) { + return { + type: SET_VISIBLE, + payload: visible, + }; +} diff --git a/app/src/actions/microservices.jsx b/app/src/actions/microservices.jsx index 0e63780..e979e40 100644 --- a/app/src/actions/microservices.jsx +++ b/app/src/actions/microservices.jsx @@ -1,12 +1,15 @@ import { BASE_API_URL, GET_MICROSERVICES } from '../constants'; import { showNotification } from './notification'; +import { showLoading } from './loading'; import fetch from '../utils/fetch'; export function getMicroservices() { return (dispatch) => { + dispatch(showLoading(true)); fetch(`${BASE_API_URL}/api/v1/microservice`, { method: 'GET' }).then((response) => response.json()).then((data) => { dispatch(showNotification('Microservices obtained successfully')); dispatch({ type: GET_MICROSERVICES, payload: data }); + dispatch(showLoading(false)); }); }; } diff --git a/app/src/actions/notification.jsx b/app/src/actions/notification.jsx index be4b4f0..e2185f9 100644 --- a/app/src/actions/notification.jsx +++ b/app/src/actions/notification.jsx @@ -1,9 +1,11 @@ -import { SHOW_NOTIFICATION, CLEAR_NOTIFICATION } from '../constants'; - export function showNotification(message) { - return { type: SHOW_NOTIFICATION, payload: message }; -} + return { + type: 'GROWLER__SHOW', + growler: { + text: message, + type: 'growler--success', + } + }; + -export function clearNotification() { - return { type: CLEAR_NOTIFICATION }; } diff --git a/app/src/actions/plugins.jsx b/app/src/actions/plugins.jsx index 4e987b3..12fda0b 100644 --- a/app/src/actions/plugins.jsx +++ b/app/src/actions/plugins.jsx @@ -1,17 +1,21 @@ import { BASE_API_URL, GET_PLUGINS } from '../constants'; import { showNotification } from './notification'; +import { showLoading } from './loading'; import fetch from '../utils/fetch'; export function getPlugins() { return (dispatch) => { + dispatch(showLoading(true)); fetch(`${BASE_API_URL}/api/v1/plugin`, { method: 'GET' }).then((response) => response.json()).then((data) => { dispatch({ type: GET_PLUGINS, payload: data }); + dispatch(showLoading(false)); }); }; } export function updatePlugin(id, plugin) { return (dispatch) => { + dispatch(showLoading(true)); fetch(`${BASE_API_URL}/api/v1/plugin/${id}`, { method: 'PATCH', body: JSON.stringify(plugin), @@ -21,6 +25,23 @@ export function updatePlugin(id, plugin) { }).then((response) => response.json()).then(() => { dispatch(showNotification('Plugin updated successfully')); dispatch(getPlugins()); + dispatch(showLoading(false)); + }); + }; +} + +export function flushCache() { + return (dispatch) => { + dispatch(showLoading(true)); + fetch(`${BASE_API_URL}/cache/flush`, { + method: 'GET', + }).then((response) => { + if (response.ok) { + dispatch(showNotification('Cache Flushed!')); + } else { + dispatch(showNotification('Error Flush cache')); + } + dispatch(showLoading(false)); }); }; } diff --git a/app/src/actions/stadistics.jsx b/app/src/actions/stadistics.jsx index 9cb092a..400b079 100644 --- a/app/src/actions/stadistics.jsx +++ b/app/src/actions/stadistics.jsx @@ -1,5 +1,6 @@ -import { BASE_API_URL, GET_STADISTICS, GET_TIME_BY_REQUEST_STADISTICS } from '../constants'; +import { BASE_API_URL, GET_STADISTICS } from '../constants'; import { showNotification } from './notification'; +import { showLoading } from './loading'; import fetch from '../utils/fetch'; function formatDate(date) { @@ -15,23 +16,42 @@ function orderRequestByDay(r1, r2) { return r1d - r2d; } +function orderRequestByNum(r1, r2) { + return r2.count - r1.count; +} + +function orderRequestBySum(r1, r2) { + return r2.sum - r1.sum; +} + export function getStadistics(fromDate, toDate) { return (dispatch) => { + dispatch(showLoading(true)); const from = formatDate(fromDate); const to = formatDate(toDate); const promises = []; - promises.push(fetch(`${BASE_API_URL}/api/v1/stadistic/timeByRequest?from=${from}&to=${to}`, { method: 'GET' }).then((response) => response.json())); + promises.push(fetch(`${BASE_API_URL}/api/v1/stadistic/avgByRequest?from=${from}&to=${to}`, { method: 'GET' }).then((response) => response.json())); promises.push(fetch(`${BASE_API_URL}/api/v1/stadistic/requestByDay?from=${from}&to=${to}`, { method: 'GET' }).then((response) => response.json())); + promises.push(fetch(`${BASE_API_URL}/api/v1/stadistic/countRequestToday`, { method: 'GET' }).then((response) => response.json())); + promises.push(fetch(`${BASE_API_URL}/api/v1/stadistic/countRequestLastWeek`, { method: 'GET' }).then((response) => response.json())); + promises.push(fetch(`${BASE_API_URL}/api/v1/stadistic/countRequestTodayByCountry`, { method: 'GET' }).then((response) => response.json())); Promise.all(promises).then((data) => { dispatch(showNotification('Stadistics obtained successfully')); dispatch({ type: GET_STADISTICS, payload: { - timeByRequest: data[0], + timeByRequest: data[0].sort(orderRequestBySum), requestByDay: data[1].sort(orderRequestByDay), + countRequestToday: data[2], + countRequestLastWeek: data[3], + countRequestTodayByCountry: data[4].sort(orderRequestByNum), } }); - }, () => dispatch(showNotification('Error obtaining stadistics'))); + dispatch(showLoading(false)); + }, () => { + dispatch(showNotification('Error obtaining stadistics')); + dispatch(showLoading(false)); + }); }; } diff --git a/app/src/actions/users.jsx b/app/src/actions/users.jsx index ce9d9c3..91c091c 100644 --- a/app/src/actions/users.jsx +++ b/app/src/actions/users.jsx @@ -1,18 +1,22 @@ import { BASE_API_URL, GET_USERS } from '../constants'; import { showNotification } from './notification'; +import { showLoading } from './loading'; import fetch from '../utils/fetch'; export function getUsers() { return (dispatch) => { + dispatch(showLoading(true)); fetch(`${BASE_API_URL}/auth/user`, { method: 'GET' }).then((response) => response.json()).then((data) => { dispatch(showNotification('Users obtained successfully')); dispatch({ type: GET_USERS, payload: data }); + dispatch(showLoading(false)); }); }; } export function updateUser(id, user) { return (dispatch) => { + dispatch(showLoading(true)); fetch(`${BASE_API_URL}/auth/user/${id}`, { method: 'PATCH', body: JSON.stringify(user), @@ -22,6 +26,7 @@ export function updateUser(id, user) { }).then((response) => response.json()).then(() => { dispatch(showNotification('User updated successfully')); dispatch(getUsers()); + dispatch(showLoading(false)); }); }; } diff --git a/app/src/components/appView.jsx b/app/src/components/appView.jsx index e28cc25..e514704 100644 --- a/app/src/components/appView.jsx +++ b/app/src/components/appView.jsx @@ -1,16 +1,7 @@ import React, { PropTypes } from 'react'; -import { - AppBar, - IconButton, - Layout, - NavDrawer, - Panel, - Navigation, - Button, -} from 'react-toolbox'; -import menu from '../../styles/menu'; -import generalStyles from '../../styles/general'; -import Notification from '../containers/notification'; +import SideBar from '../containers/sideBar/sideBar'; +import Loading from '../components/loading'; +import { GrowlerContainer } from 'flash-notification-react-redux'; class AppView extends React.Component { @@ -27,7 +18,6 @@ class AppView extends React.Component { componentWillUpdate(nextProps) { if (nextProps.login.correct === false && this.props.login.correct !== nextProps.login.correct) { this.props.goToLogin(); - } } @@ -43,40 +33,13 @@ class AppView extends React.Component { render() { return ( - - - - Menu - - - {this.props.login.user && this.props.login.user.role === 'ADMIN' && + -
- this.handleChange('to', value)} - value={this.state.to} - className={dashboardStyle.filter} - /> + {this.state.optionselect === 1 &&
+
+
+ this.handleChange('from', value)} + value={this.state.from} + /> +
+
+ this.handleChange('to', value)} + value={this.state.to} + /> +
+
+ +
+
+
+ Average time by request + +
+
+ Num request by day + {this.state.requestByDay && + } +
+
} + {this.state.optionselect === 2 &&
+
+

{this.props.users.list ? this.props.users.list.length : 0}

Users

+

{this.props.microservices.list ? this.props.microservices.list.length: 0}

Microservices

+

{this.props.endpoints.list ? this.props.endpoints.list.length : 0}

Endpoints

-
-
- Average time by request - -
-
- Num request by day - {this.state.requestByDay && } +
+

{this.props.stadistics.countRequestToday ? this.props.stadistics.countRequestToday.count : 0}

Requests today

+

{this.props.stadistics.countRequestLastWeek ? this.props.stadistics.countRequestLastWeek.count : 0}

Requests last week

+
+
+
+ {countries} +
+
}
); @@ -124,7 +207,13 @@ class DashboardView extends React.Component { DashboardView.propTypes = { getStadistics: PropTypes.func, + getMicroservice: PropTypes.func, + getUsers: PropTypes.func, + getEndpoints: PropTypes.func, stadistics: PropTypes.object, + users: PropTypes.object, + endpoints: PropTypes.object, + microservices: PropTypes.object, }; export default DashboardView; diff --git a/app/src/components/endpointView.jsx b/app/src/components/endpointView.jsx index 314773e..75ae515 100644 --- a/app/src/components/endpointView.jsx +++ b/app/src/components/endpointView.jsx @@ -1,36 +1,84 @@ import React, { PropTypes } from 'react'; -import generalStyle from '../../styles/general'; -import { Button, FontIcon } from 'react-toolbox'; - +import layoutContentStyle from '../../styles/layout/l-content.scss'; +import tableStyle from '../../styles/components/c-table.scss'; +import buttonStyle from '../../styles/components/c-button.scss'; +import searchStyle from '../../styles/components/c-search.scss'; class EndpointView extends React.Component { + constructor(props) { + super(props); + + this.state = { + endpoints: null, + filteredList: null, + filterValue: null, + }; + } + componentDidMount() { this.props.getEndpoints(); } + + componentWillReceiveProps(nextProps) { + if (nextProps.endpoints !== this.props.endpoints) { + const newState = { endpoints: nextProps.endpoints.list }; + if (this.state.filterValue) { + newState.filteredList = this.filterList(nextProps.endpoints.list, this.state.filterValue); + } else { + newState.filteredList = nextProps.endpoints.list; + } + this.setState(newState); + } + } + + filterList(list, value) { + return list.filter((endpoint) => endpoint.path.toLowerCase().indexOf(value) >= 0); + } + + filter(e) { + const newState = { filterValue: e.target.value }; + if (e.target.value) { + newState.filteredList = this.filterList(this.props.endpoints.list, e.target.value); + } else { + newState.filteredList = this.props.endpoints.list; + } + this.setState(newState); + } + render() { let rows = []; - if (this.props.endpoints.list) { - for (let i = 0, length = this.props.endpoints.list.length; i < length; i++) { - const endpoint = this.props.endpoints.list[i]; + if (this.state.filteredList) { + for (let i = 0, length = this.state.filteredList.length; i < length; i++) { + const endpoint = this.state.filteredList[i]; rows.push( {endpoint.path} {endpoint.method} - {endpoint.authenticated && } + {endpoint.authenticated && 'Yes'} ); } } return ( -
-

- - Endpoints -

- +
+
+ this.filter(e)} + > + +
+ +
diff --git a/app/src/components/loading.jsx b/app/src/components/loading.jsx new file mode 100644 index 0000000..a1a3977 --- /dev/null +++ b/app/src/components/loading.jsx @@ -0,0 +1,14 @@ +import React from 'react'; +import LoadingLib from 'react-loading'; + +import loadingStyle from '../../styles/components/c-loading.scss'; + +function Loading() { + return ( +
+ +
+ ); +} + +export default Loading; diff --git a/app/src/components/loginView.jsx b/app/src/components/loginView.jsx index a542028..e40b004 100644 --- a/app/src/components/loginView.jsx +++ b/app/src/components/loginView.jsx @@ -1,13 +1,6 @@ import React, { PropTypes } from 'react'; -import { - Button, - Input, -} from 'react-toolbox'; - -import loginStyle from '../../styles/login'; class LoginView extends React.Component { - constructor(props) { super(props); this.state = { diff --git a/app/src/components/microserviceView.jsx b/app/src/components/microserviceView.jsx index d1198c2..f1a0b54 100644 --- a/app/src/components/microserviceView.jsx +++ b/app/src/components/microserviceView.jsx @@ -1,35 +1,87 @@ import React, { PropTypes } from 'react'; -import generalStyle from '../../styles/general'; -import { Button, FontIcon } from 'react-toolbox'; import Time from 'react-time'; +import layoutContentStyle from '../../styles/layout/l-content.scss'; +import tableStyle from '../../styles/components/c-table.scss'; +import buttonStyle from '../../styles/components/c-button.scss'; +import searchStyle from '../../styles/components/c-search.scss'; class MicroserviceView extends React.Component { + constructor(props) { + super(props); + + this.state = { + microservices: null, + filteredList: null, + filterValue: null, + }; + } componentDidMount() { this.props.getMicroservices(); } + + componentWillReceiveProps(nextProps) { + if (nextProps.microservices !== this.props.microservices) { + const newState = { microservices: nextProps.microservices.list }; + if (this.state.filterValue) { + newState.filteredList = this.filterList(nextProps.microservices.list, this.state.filterValue); + } else { + newState.filteredList = nextProps.microservices.list; + } + this.setState(newState); + } + } + + filterList(list, value) { + return list.filter((microservice) => microservice.name.toLowerCase().indexOf(value) >= 0); + } + + filter(e) { + const newState = { filterValue: e.target.value }; + if (e.target.value) { + newState.filteredList = this.filterList(this.props.microservices.list, e.target.value); + } else { + newState.filteredList = this.props.microservices.list; + } + this.setState(newState); + } + render() { let rows = []; - if (this.props.microservices.list) { - for (let i = 0, length = this.props.microservices.list.length; i < length; i++) { - const microservice = this.props.microservices.list[i]; + if (this.state.filteredList) { + for (let i = 0, length = this.state.filteredList.length; i < length; i++) { + const microservice = this.state.filteredList[i]; rows.push( - + - + ); } } + return ( -
-

- - Microservices -

-
Path
{microservice.name} {microservice.url}{microservice.status}{microservice.status}
+
+
+ this.filter(e)} + > + +
+ +
@@ -38,7 +90,7 @@ class MicroserviceView extends React.Component { - + {rows}
NameLast check
diff --git a/app/src/components/notificationView.jsx b/app/src/components/notificationView.jsx deleted file mode 100644 index dab9b1e..0000000 --- a/app/src/components/notificationView.jsx +++ /dev/null @@ -1,47 +0,0 @@ -import React, { PropTypes } from 'react'; -import { Snackbar } from 'react-toolbox'; - -class NotificationView extends React.Component { - - constructor(props) { - super(props); - this.state = { - active: false, - }; - } - - componentWillReceiveProps(nextProps) { - if (nextProps.notification) { - this.setState({ active: true }); - } - } - - handleSnackbarTimeout() { - this.setState({ active: false }); - this.props.clearNotification(); - } - - render() { - - return ( - this.handleSnackbarClick()} - onTimeout={() => this.handleSnackbarTimeout()} - type="cancel" - /> - ); - } - -} - -NotificationView.propTypes = { - notification: PropTypes.string, - clearNotification: PropTypes.func, -}; - -export default NotificationView; diff --git a/app/src/components/pluginView.jsx b/app/src/components/pluginView.jsx index 6c13b59..7477ab7 100644 --- a/app/src/components/pluginView.jsx +++ b/app/src/components/pluginView.jsx @@ -1,15 +1,9 @@ import React, { PropTypes } from 'react'; -import { - Card, - CardTitle, - CardText, - CardActions, - Button, - FontIcon, - Dialog, -} from 'react-toolbox'; -import pluginStyle from '../../styles/plugin'; -import generalStyle from '../../styles/general'; +import classnames from 'classnames'; +import layoutContentStyle from '../../styles/layout/l-content.scss'; +import cardListStyle from '../../styles/components/c-card-list.scss'; +import modalQuestionStyle from '../../styles/components/c-modal-question.scss'; +import buttonStyle from '../../styles/components/c-button.scss'; class PluginView extends React.Component { @@ -48,38 +42,71 @@ class PluginView extends React.Component { if (this.props.plugins) { this.props.plugins.forEach((plugin, index) => { plugins.push( - - - File/module: {plugin.mainFile} - - } +
+

+ {plugin.name} +

+
+
+

File/module: {plugin.mainFile}

+
+
+ + {plugin.active && } + {!plugin.active && + } +
+
+ ); }); } return ( -
-

- - Plugins -

+
+ {this.state.showDialog && +
this.cancel(this)} + className={modalQuestionStyle.backgroundcolor} + > +
+

+ Sure that you want change the state of the plugin? +
+ + +
+

+
+
+ } {plugins} - this.cancel} - onOverlayClick={() => this.cancel} - title="Confirm" - > -

Sure that you want change the state of the plugin?

-
); } @@ -89,7 +116,8 @@ class PluginView extends React.Component { PluginView.propTypes = { getPlugins: PropTypes.func, updatePlugin: PropTypes.func, - plugins: PropTypes.array + flushCache: PropTypes.func, + plugins: PropTypes.array, }; export default PluginView; diff --git a/app/src/components/profileView.jsx b/app/src/components/profileView.jsx index fbe3581..316b45d 100644 --- a/app/src/components/profileView.jsx +++ b/app/src/components/profileView.jsx @@ -1,11 +1,8 @@ import React, { PropTypes } from 'react'; -import { - Button, - FontIcon, - Input, -} from 'react-toolbox'; import CopyToClipboard from 'react-copy-to-clipboard'; -import generalStyle from '../../styles/general'; +import layoutContentStyle from '../../styles/layout/l-content.scss'; +import profileStyle from '../../styles/components/c-profile-page.scss'; +import buttonStyle from '../../styles/components/c-button.scss'; class ProfileView extends React.Component { @@ -16,6 +13,10 @@ class ProfileView extends React.Component { }; } + componentDidMount() { + this.props.generateToken(); + } + componentWillReceiveProps(nextProps) { if (nextProps.login.token !== this.state.token) { this.setState({ token: nextProps.login.token }); @@ -24,19 +25,26 @@ class ProfileView extends React.Component { render() { return ( -
-

- - Profile -

- - + {this.state.token && this.setState({ copied: true })}> + + } +
+
); } diff --git a/app/src/components/sideBar/sideBar.jsx b/app/src/components/sideBar/sideBar.jsx new file mode 100644 index 0000000..9046d5c --- /dev/null +++ b/app/src/components/sideBar/sideBar.jsx @@ -0,0 +1,72 @@ +import React, { Component } from 'react'; +import { Link } from 'react-router'; +import sideBarStyles from '../../../styles/components/c-sidebar.scss'; +import buttonStyle from '../../../styles/components/c-button.scss'; + +class SideBar extends Component { + + constructor(props) { + super(props); + this.state = { + expanded: true, + }; + } + + expandSideBar() { + this.setState({ footerExpanded: !this.state.footerExpanded }); + } + + render() { + return ( +
+
+

control

tower.

+ Dashboard + Plugins + Microservices + Endpoints + Users + Profile +
+
+ +
+
+ ); + } + +} + +SideBar.propTypes = { + expandSideBa: React.PropTypes.func, + logout: React.PropTypes.func, +}; + +export default SideBar; diff --git a/app/src/components/userView.jsx b/app/src/components/userView.jsx index fa7ffaa..63374c3 100644 --- a/app/src/components/userView.jsx +++ b/app/src/components/userView.jsx @@ -1,21 +1,63 @@ import React, { PropTypes } from 'react'; -import { Button, FontIcon, Dropdown } from 'react-toolbox'; -import generalStyle from '../../styles/general'; -import userStyle from '../../styles/user'; +import classnames from 'classnames'; +import layoutContentStyle from '../../styles/layout/l-content.scss'; +import tableStyle from '../../styles/components/c-table.scss'; +import buttonStyle from '../../styles/components/c-button.scss'; +import searchStyle from '../../styles/components/c-search.scss'; +import modalQuestionStyle from '../../styles/components/c-modal-question.scss'; class UserView extends React.Component { constructor(props) { super(props); - this.state = {}; + this.state = { + users: null, + filteredList: null, + filterValue: null, + showDialog: false, + }; } componentDidMount() { this.props.getUsers(); } - changeUser(value, user) { - this.props.updateUser(user._id, { role: value }); + componentWillReceiveProps(nextProps) { + if (nextProps.users !== this.props.users) { + const newState = { users: nextProps.users.list }; + if (this.state.filterValue) { + newState.filteredList = this.filterList(nextProps.users.list, this.state.filterValue); + } else { + newState.filteredList = nextProps.users.list; + } + this.setState(newState); + } + } + + filterList(list, value) { + return list.filter((user) => user.email.toLowerCase().indexOf(value) >= 0); + } + + filter(e) { + const newState = { filterValue: e.target.value }; + if (e.target.value) { + newState.filteredList = this.filterList(this.props.users.list, e.target.value); + } else { + newState.filteredList = this.props.users.list; + } + this.setState(newState); + } + + changeUser(e, user) { + this.props.updateUser(user._id, { role: e.target.value }); + } + + showDialog() { + this.setState({showDialog: true }); + } + + closeDialog() { + this.setState({showDialog: false }); } render() { @@ -29,34 +71,94 @@ class UserView extends React.Component { }, ]; let rows = []; - if (this.props.users.list) { - for (let i = 0, length = this.props.users.list.length; i < length; i++) { - const user = this.props.users.list[i]; + let options = [ + , + , + ]; + if (this.state.filteredList) { + for (let i = 0, length = this.state.filteredList.length; i < length; i++) { + const user = this.state.filteredList[i]; rows.push( {user._id} {user.email} {user.provider} - this.changeUser(e, user)} - source={roles} - value={user.role} - /> +
+ +
); } } return ( -
-

- - Users -

- +
+ {this.state.showDialog && +
+
+

+ Create new user +

+
+ + + +
+ + +
+
+
+ } +
+ this.filter(e)} + > + +
+ + +
@@ -66,7 +168,7 @@ class UserView extends React.Component { - {rows} + {rows}
Id
diff --git a/app/src/constants.jsx b/app/src/constants.jsx index 54fa665..5356f5e 100644 --- a/app/src/constants.jsx +++ b/app/src/constants.jsx @@ -1,7 +1,4 @@ -export const BASE_API_URL = 'http://tower.dev:9000'; - -export const SHOW_NOTIFICATION = 'SHOW_NOTIFICATION'; -export const CLEAR_NOTIFICATION = 'CLEAR_NOTIFICATION'; +export const BASE_API_URL = 'http://api.resourcewatch.org'; export const GET_PLUGINS = 'GET_PLUGINS'; export const UPDATE_PLUGIN = 'UPDATE_PLUGIN'; @@ -19,3 +16,5 @@ export const LOGIN = 'LOGIN'; export const LOGIN_FAIL = 'LOGIN_FAIL'; export const GENERATE_TOKEN = 'GENERATE_TOKEN'; export const LOGOUT = 'LOGOUT'; + +export const SET_VISIBLE = 'SET_VISIBLE'; diff --git a/app/src/containers/app.jsx b/app/src/containers/app.jsx index 8d0f1a0..38cd130 100644 --- a/app/src/containers/app.jsx +++ b/app/src/containers/app.jsx @@ -6,6 +6,7 @@ import { login, logout, goToLogin } from '../actions/login'; const mapStateToProps = (state) => ({ login: state.login, + loading: state.loading.visible, }); const mapDispatchToProps = (dispatch) => ({ diff --git a/app/src/containers/dashboard.jsx b/app/src/containers/dashboard.jsx index dab1284..737b8fa 100644 --- a/app/src/containers/dashboard.jsx +++ b/app/src/containers/dashboard.jsx @@ -1,13 +1,22 @@ import { connect } from 'react-redux'; import { getStadistics } from '../actions/stadistics'; +import { getUsers } from '../actions/users'; +import { getEndpoints } from '../actions/endpoints'; +import { getMicroservices } from '../actions/microservices'; import Dashboard from '../components/dashboardView'; const mapStateToProps = (state) => ({ stadistics: state.stadistics, + users: state.users, + endpoints: state.endpoints, + microservices: state.microservices, }); const mapDispatchToProps = (dispatch) => ({ getStadistics: (from, to) => dispatch(getStadistics(from, to)), + getMicroservice: () => dispatch(getMicroservices()), + getEndpoints: () => dispatch(getEndpoints()), + getUsers: () => dispatch(getUsers()), }); export default connect(mapStateToProps, mapDispatchToProps)(Dashboard); diff --git a/app/src/containers/index.jsx b/app/src/containers/index.jsx index afa85d7..9d197ce 100644 --- a/app/src/containers/index.jsx +++ b/app/src/containers/index.jsx @@ -3,7 +3,6 @@ export Dashboard from './dashboard'; export Endpoint from './endpoint'; export Plugin from './plugin'; export Microservice from './microservice'; -export Notification from './notification'; export Profile from './profile'; export Login from './login'; export User from './user'; diff --git a/app/src/containers/notification.jsx b/app/src/containers/notification.jsx deleted file mode 100644 index a2913cb..0000000 --- a/app/src/containers/notification.jsx +++ /dev/null @@ -1,14 +0,0 @@ -import { connect } from 'react-redux'; - -import Notification from '../components/notificationView'; -import { clearNotification } from '../actions/notification'; - -const mapStateToProps = (state) => ({ - notification: state.notification, -}); - -const mapDispatchToProps = (dispatch) => ({ - clearNotification: () => dispatch(clearNotification()), -}); - -export default connect(mapStateToProps, mapDispatchToProps)(Notification); diff --git a/app/src/containers/plugin.jsx b/app/src/containers/plugin.jsx index f2e0bc9..8b58f92 100644 --- a/app/src/containers/plugin.jsx +++ b/app/src/containers/plugin.jsx @@ -1,5 +1,5 @@ import { connect } from 'react-redux'; -import { getPlugins, updatePlugin } from '../actions/plugins'; +import { getPlugins, updatePlugin, flushCache } from '../actions/plugins'; import Plugin from '../components/pluginView'; @@ -10,6 +10,7 @@ const mapStateToProps = (state) => ({ const mapDispatchToProps = (dispatch) => ({ getPlugins: () => dispatch(getPlugins()), updatePlugin: (id, plugin) => dispatch(updatePlugin(id, plugin)), + flushCache: () => dispatch(flushCache()), }); export default connect(mapStateToProps, mapDispatchToProps)(Plugin); diff --git a/app/src/containers/sideBar/sideBar.jsx b/app/src/containers/sideBar/sideBar.jsx new file mode 100644 index 0000000..8f5451f --- /dev/null +++ b/app/src/containers/sideBar/sideBar.jsx @@ -0,0 +1,13 @@ +import { connect } from 'react-redux'; + +import Sidebar from '../../components/sideBar/sideBar'; +import { logout } from '../../actions/login'; + +const mapStateToProps = () => ({ +}); + +const mapDispatchToProps = (dispatch) => ({ + logout: () => dispatch(logout()), +}); + +export default connect(mapStateToProps, mapDispatchToProps)(Sidebar); diff --git a/app/src/index.jsx b/app/src/index.jsx index 4238c55..7b82b57 100644 --- a/app/src/index.jsx +++ b/app/src/index.jsx @@ -1,4 +1,3 @@ -import 'react-toolbox/lib/commons.scss'; import React from 'react'; import { render } from 'react-dom'; import { createStore, combineReducers, applyMiddleware } from 'redux'; @@ -6,15 +5,16 @@ import { Provider } from 'react-redux'; import thunk from 'redux-thunk'; import { browserHistory, hashHistory } from 'react-router'; import { syncHistoryWithStore, routerReducer, routerMiddleware } from 'react-router-redux'; +import { GrowlerReducer } from 'flash-notification-react-redux'; import Routes from './routes'; import * as reducers from './reducers'; - -import '../styles/index.scss'; - +import '../styles/growler.scss'; +import '../styles/mapglyphs.scss'; const reducer = combineReducers({ ...reducers, routing: routerReducer, + growler: GrowlerReducer, }); diff --git a/app/src/reducers/index.jsx b/app/src/reducers/index.jsx index df90ca7..68e87e8 100644 --- a/app/src/reducers/index.jsx +++ b/app/src/reducers/index.jsx @@ -1,7 +1,7 @@ export plugins from './plugins'; -export notification from './notification'; export login from './login'; export users from './users'; export stadistics from './stadistics'; export microservices from './microservices'; export endpoints from './endpoints'; +export loading from './loading'; diff --git a/app/src/reducers/loading.jsx b/app/src/reducers/loading.jsx new file mode 100644 index 0000000..0e44336 --- /dev/null +++ b/app/src/reducers/loading.jsx @@ -0,0 +1,19 @@ +import { SET_VISIBLE } from '../constants'; + +const initialState = { + visible: false, +}; + +export default function (state = initialState, action) { + + switch (action.type) { + + case SET_VISIBLE: + return Object.assign({}, state, { visible: action.payload }); + + default: + return state; + + } + +} diff --git a/app/src/reducers/notification.jsx b/app/src/reducers/notification.jsx deleted file mode 100644 index 9dd2970..0000000 --- a/app/src/reducers/notification.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import { SHOW_NOTIFICATION, CLEAR_NOTIFICATION } from '../constants'; - -const initialState = null; - - -export default function(state = initialState, action) { - - switch (action.type) { - case SHOW_NOTIFICATION: - return action.payload; - case CLEAR_NOTIFICATION: - return null; - default: - return state; - } -}; diff --git a/app/src/routes.jsx b/app/src/routes.jsx index fdefe0f..c3e0d16 100644 --- a/app/src/routes.jsx +++ b/app/src/routes.jsx @@ -7,7 +7,7 @@ export default function (props) { return ( - + diff --git a/app/styles/_base.scss b/app/styles/_base.scss new file mode 100644 index 0000000..0c47ee9 --- /dev/null +++ b/app/styles/_base.scss @@ -0,0 +1,51 @@ +@import 'settings'; + +* { + -webkit-font-smoothing: antialiased; + box-sizing: border-box; + + &::after { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + box-sizing: border-box; + } + + &::before { + -moz-osx-font-smoothing: grayscale; + -webkit-font-smoothing: antialiased; + box-sizing: border-box; + } +} + +body, +html { + background-color: $color-4; + font-family: $font-family-2; + font-size: $font-size-normal; + font-weight: $font-weight-normal; + margin: 0; + padding: 0; +} + +body { + overflow-x: hidden; +} + +a { + text-decoration: none; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + -webkit-margin-before: 0; + -webkit-margin-after: 0; + font-family: $font-family-1; +} + +:global .hidden { + display: none; +} diff --git a/app/styles/_settings.scss b/app/styles/_settings.scss new file mode 100644 index 0000000..1b9787c --- /dev/null +++ b/app/styles/_settings.scss @@ -0,0 +1,60 @@ +@import 'normalize.css'; + +@import url('https://fonts.googleapis.com/css?family=Roboto:300,400,700'); +@import url('https://fonts.googleapis.com/css?family=Roboto+Slab:400,300,100,700'); +@import url('https://fonts.googleapis.com/css?family=Montserrat:400,700'); + + + +// Font families +$font-family-1: 'Roboto', sans-serif; +$font-family-2: 'Roboto Slab', serif; +$font-family-3: 'Montserrat', sans-serif; + +// Layout +$max-width: 1280px; +$wrap-mobile: 25px; +$wrap-tablet: 55px; +$wrap-desktop: 115px; + + +// Font sizes +$font-size-small: 12px; +$font-size-normal: 15px; +$font-size-xnormal: 17px; +$font-size-mediun: 20px; +$font-size-xxnormal: 25px; +$font-size-big: 40px; +$font-size-xbig: 60px; +$font-size-huge: 80px; +$font-size-xhuge: 120px; + +// Font weights +$font-weight-light: 300; +$font-weight-normal: 400; +$font-weight-bold: 700; + +// Colors +$color-1: #3c61e5; +$color-2: #111; +$color-3: #fff; +$color-4: #f7f7f7; +$color-5: #d5dee5; +$color-6: #858a94; +$color-7: #ff4646; +$color-8: #2448ca; +$color-9: #5bbd66; + + + +// Breakpoints +$breakpoint-mobile-small: 320px; +$breakpoint-mobile-large: 425px; +$breakpoint-tablet: 768px; +$breakpoint-laptop: 1024px; + +// Media queries +$mq-mobile-small: 'screen and (min-width: #{$breakpoint-mobile-small})'; +$mq-mobile-large: 'screen and (min-width: #{$breakpoint-mobile-large})'; +$mq-tablet: 'screen and (min-width: #{$breakpoint-tablet})'; +$mq-laptop: 'screen and (min-width: #{$breakpoint-laptop})'; diff --git a/app/styles/components/c-button.scss b/app/styles/components/c-button.scss new file mode 100644 index 0000000..4dcdb3d --- /dev/null +++ b/app/styles/components/c-button.scss @@ -0,0 +1,44 @@ +@import '../base'; + +.c-button { + border: 0; + cursor: pointer; + font-family: $font-family-1; + outline: 0; + + &.-basic { + background-color: $color-3; + border: 2px solid $color-2; + box-shadow: 4px 4px 0 $color-2; + padding: 15px 40px; + position: relative; + + &:active { + box-shadow: 0 0 0 transparent; + top: 4px; + } + + &.-small-table { + float: right; + padding: 10px; + } + } + + &.-blue { + background-color: $color-1; + border: 2px solid $color-3; + box-shadow: 4px 4px 0 $color-3; + color: $color-3; + padding: 15px 40px; + position: relative; + + &:active { + box-shadow: 0 0 0 transparent; + top: 4px; + } + } + + &.-distance-right { + margin-right: 20px; + } +} diff --git a/app/styles/components/c-card-list.scss b/app/styles/components/c-card-list.scss new file mode 100644 index 0000000..c290897 --- /dev/null +++ b/app/styles/components/c-card-list.scss @@ -0,0 +1,107 @@ +@import '../base'; + +.c-card-list { + background-color: $color-3; + border: 1px solid $color-6; + display: inline-block; + flex-grow: 1; + margin-bottom: 40px; + padding: 0; + padding-bottom: 0; + position: relative; + width: 100%; + + .button-refresh { + background-color: $color-3; + border: 1px solid $color-6; + cursor: pointer; + font-family: $font-family-1; + padding: 10px 15px; + position: absolute; + right: -1px; + top: -19px; + transition: .2s; + + &:hover { + background-color: $color-1; + color: $color-3; + } + } + + .card-title { + padding: 20px 20px 0; + + h2 { + color: $color-2; + font-family: $font-family-1; + font-size: $font-size-xnormal; + + @media #{$mq-laptop} { + font-size: $font-size-mediun; + } + + &::after { + background-color: $color-6; + content: ' '; + display: block; + height: 1px; + margin: 5px 0; + width: 100%; + } + } + } + + .card-main { + padding: 20px 20px 0; + + h3 { + font-size: $font-size-mediun; + word-break: break-word; + + @media #{$mq-laptop} { + font-size: $font-size-xxnormal; + } + } + } + + .card-button-contain { + padding-top: 20px; + + button { + background-color: $color-3; + border: 0; + cursor: pointer; + outline: 0; + padding: 10px; + position: relative; + width: 50%; + + &:first-child { + border-bottom: 8px solid $color-2; + + &:active { + border-bottom: 4px solid $color-2; + top: 5px; + } + } + + &:last-child { + border-bottom: 8px solid $color-7; + + &:active { + border-bottom: 4px solid $color-7; + top: 5px; + } + + &.green-active { + border-bottom: 8px solid $color-9; + + &:active { + border-bottom: 4px solid $color-9; + top: 5px; + } + } + } + } + } +} diff --git a/app/styles/components/c-dashboard.scss b/app/styles/components/c-dashboard.scss new file mode 100644 index 0000000..afada55 --- /dev/null +++ b/app/styles/components/c-dashboard.scss @@ -0,0 +1,219 @@ +@import '../base'; + +.c-dashboard { + + hr { + margin-top: 20px; + margin-bottom: 20px; + } + + .three-numbers { + display: flex; + justify-content: space-between; + + div { + background-color: $color-3; + flex-basis: 30%; + padding: 20px; + } + + h2 { + color: $color-2; + font-family: $font-family-1; + font-size: $font-size-huge; + + &::after { + background-color: $color-1; + content: ''; + display: block; + height: 4px; + width: 100px; + } + } + + p { + color: $color-2; + font-family: $font-family-2; + } + } + + .two-numbers { + display: flex; + margin-top: 40px; + justify-content: space-between; + + div { + background-color: $color-3; + flex-basis: 45%; + padding: 20px; + } + + h2 { + color: $color-2; + font-family: $font-family-1; + font-size: $font-size-xhuge; + + &::after { + background-color: $color-1; + content: ''; + display: block; + height: 4px; + width: 100px; + } + } + + p { + color: $color-2; + font-family: $font-family-2; + } + } + + .countries-list { + + .contain-map{ + padding: 20px; + float: left; + width: 50%; + + &:nth-child(2n+1) { + padding-left: 0; + } + + &:nth-child(2n) { + padding-right: 0; + } + + div { + background-color: $color-3; + padding: 20px; + position: relative; + } + + .text-country { + bottom: 22px; + font-family: $font-family-2; + font-size: $font-size-big; + position: absolute; + + b { + font-size: $font-size-xxnormal; + } + } + } + } + + .chartTitle { + display: block; + font-family: $font-family-2; + margin-bottom: 10px; + margin-top: 15px; + + &.-first{ + margin-top: 0; + } + } + + .contain-options { + background-color: $color-3; + margin-bottom: 20px; + padding: 10px; + + button { + background-color: $color-3; + cursor: pointer; + font-family: $font-family-2; + outline: 0; + padding: 20px; + + &:first-of-type { + border: 2px solid $color-2; + border-right: 1px; + position: relative; + } + + &:last-of-type { + border: 2px solid $color-2; + border-left: 1px; + } + + &.-select { + background-color: rgba($color-1, .5); + color: $color-3; + } + } + } + + .contain-date { + background-color: $color-3; + display: flex; + flex: wrap; + justify-content: space-between; + margin-bottom: 20px; + padding: 20px; + + div { + flex-basis: calc(100% / 3); + + label { + font-family: $font-family-2; + font-size: $font-size-normal !important; + padding-bottom: 20px !important; + + &::after { + background-color: $color-2; + content: ' '; + display: block; + height: 2px; + width: 80px; + } + } + + &.-button-refresh { + align-items: center; + display: flex; + justify-content: flex-end; + } + + b { + color: $color-6; + display: block; + font-family: $font-family-1; + font-size: $font-size-normal; + margin-bottom: 10px; + } + + input { + border: 0; + display: block; + font-size: $font-size-xnormal; + outline: 0; + padding: 10px; + padding-left: 0; + position: relative; + width: calc(100% - 20px); + + &::before { + background-color: $color-2; + content: ''; + display: block; + height: 2px; + left: 0; + position: absolute; + top: 0; + width: 30px; + } + + &::after { + background-color: $color-2; + bottom: 0; + content: ''; + display: block; + height: 2px; + left: 0; + position: absolute; + width: calc(100% - 20px); + } + } + } + } +} diff --git a/app/styles/components/c-loading.scss b/app/styles/components/c-loading.scss new file mode 100644 index 0000000..868f513 --- /dev/null +++ b/app/styles/components/c-loading.scss @@ -0,0 +1,17 @@ +@import '../base'; +.c-loading { + background-color: rgba($color-2, .95); + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 100%; + z-index: 100; + > div { + top: 40%; + left: 50%; + position: absolute; + } +} diff --git a/app/styles/components/c-modal-question.scss b/app/styles/components/c-modal-question.scss new file mode 100644 index 0000000..60d3160 --- /dev/null +++ b/app/styles/components/c-modal-question.scss @@ -0,0 +1,53 @@ +@import '../base'; + +.c-modal-question { + background-color: $color-3; + left: 50%; + min-width: 600px; + padding: 40px; + position: absolute; + top: 50%; + transform: translate(-50%, -50%); + z-index: 1; + + h3 { + color: $color-2; + font-family: $font-family-1; + font-size: $font-size-xxnormal; + text-align: center; + } + + div { + align-items: center; + display: flex; + justify-content: center; + margin-top: 20px; + + button { + font-size: $font-size-normal; + width: 100px; + + &:first-of-type { + margin-right: 20px; + } + } + } + + .input-dialog { + display: block; + height: 50px; + margin: 25px auto 0; + padding: 10px; + width: 80%; + } +} + +.backgroundcolor { + background-color: rgba($color-2, .95); + height: 100%; + left: 0; + position: fixed; + top: 0; + width: 100%; + z-index: 1000; +} diff --git a/app/styles/components/c-profile-page.scss b/app/styles/components/c-profile-page.scss new file mode 100644 index 0000000..2afea6d --- /dev/null +++ b/app/styles/components/c-profile-page.scss @@ -0,0 +1,48 @@ +@import '../base.scss'; + +.c-profile-page { + background-color: $color-3; + display: block; + margin: 0 auto; + max-width: 700px; + padding: 20px; + width: 100%; + + .text-token { + line-height: 1.7; + word-break: break-word; + } + + .content-buttons { + display: block; + + button { + display: block; + margin-bottom: 20px; + width: 100%; + + &:last-child { + margin-bottom: 0; + margin-right: 0; + } + + @media #{$mq-tablet} { + margin-bottom: 0; + margin-right: 100px; + width: auto; + } + } + + @media #{$mq-tablet} { + display: flex; + justify-content: center; + } + } + + hr { + background-color: $color-5; + border: 0; + height: 2px; + margin: 25px 0; + } +} diff --git a/app/styles/components/c-search.scss b/app/styles/components/c-search.scss new file mode 100644 index 0000000..8b1ddaa --- /dev/null +++ b/app/styles/components/c-search.scss @@ -0,0 +1,15 @@ +@import '../base'; + +.c-search { + background-color: $color-3; + float: left; + + input { + border: 2px solid $color-2; + font-family: $font-family-1; + min-width: 300px; + outline: 0; + padding: 10px; + width: 100%; + } +} diff --git a/app/styles/components/c-sidebar.scss b/app/styles/components/c-sidebar.scss new file mode 100644 index 0000000..344b538 --- /dev/null +++ b/app/styles/components/c-sidebar.scss @@ -0,0 +1,80 @@ +@import '../base.scss'; + +.c-sidebar { + background-color: $color-1; + display: flex; + flex-direction: column; + height: 100%; + justify-content: space-between; + overflow-y: auto; + padding: 40px 0 20px; + position: fixed; + width: 100px; + + .sidebar-top { + + h1 { + color: $color-3; + font-family: $font-family-3; + font-size: $font-size-xnormal; + padding: 0 10px 20px; + position: relative; + + @media #{$mq-tablet} { + font-size: $font-size-big; + padding: 0 30px 25px; + } + + &::before { + background-color: $color-3; + content: ''; + display: block; + height: 2px; + position: absolute; + top: -10px; + width: 40px; + + @media #{$mq-tablet} { + height: 4px; + width: 84px; + } + } + } + + .sidebar-option { + color: $color-3; + display: block; + font-family: $font-family-1; + font-size: $font-size-small; + padding: 20px 10px; + transition: background-color .2s ease-in-out; + + @media #{$mq-tablet} { + font-size: $font-size-xnormal; + padding: 25px 30px; + } + + &:hover { + background-color: $color-8; + } + + &.sidebar-option-selected { + background-color: $color-8; + } + } + } + + .sidebar-bottom { + + button { + display: block; + margin: 55px auto 0; + width: calc(100% - 50px); + } + } + + @media #{$mq-tablet} { + padding: 40px 0 45px; + width: 250px; + } +} diff --git a/app/styles/components/c-table.scss b/app/styles/components/c-table.scss new file mode 100644 index 0000000..4353fac --- /dev/null +++ b/app/styles/components/c-table.scss @@ -0,0 +1,88 @@ +@import '../base'; + +.c-table { + + table { + background: $color-3; + margin: 80px auto 0; + padding: 20px; + text-align: left; + width: 100%; + } + + thead, + tbody, + tfoot, + tr, + td, + th { + margin: auto; + text-align: left; + width: 100%; + } + + thead { + tr { + td { + border-bottom: 2px solid $color-2; + font-family: $font-family-1; + font-size: $font-size-normal; + // min-width: 200px; + padding: 0 15px 10px 0; + width: 100%; + + @media #{$mq-laptop} { + font-size: $font-size-xxnormal; + } + } + } + } + + tbody { + tr { + + &.-error { + background-color: rgba($color-7, .2); + } + + td { + font-family: $font-family-2; + font-size: $font-size-xnormal; + padding: 20px 15px 20px 10px; + + .content-select { + position: relative; + + &::after { + background: transparent; + border-bottom: 2px solid $color-2; + border-left: 2px solid $color-2; + content: ''; + height: 10px; + position: absolute; + right: 10px; + top: 5px; + transform: rotate(-45deg); + width: 10px; + } + + select { + -moz-appearance: none; + -webkit-appearance: none; + background-color: $color-3; + border: 0; + border-bottom: 2px solid $color-2; + border-radius: 0; + cursor: pointer; + font-family: $font-family-2; + max-width: 200px; + min-width: 100px; + outline: 0; + padding-bottom: 5px; + width: 100%; + } + } + } + } + } +} diff --git a/app/styles/dashboard.scss b/app/styles/dashboard.scss deleted file mode 100644 index 62a978d..0000000 --- a/app/styles/dashboard.scss +++ /dev/null @@ -1,26 +0,0 @@ -.filter { - float: left; - width: 30%; -} -.filterButton { - float: left; -} -.filterPanel { - display: block; - &:after { - content: ""; - display: table; - clear: both; - } -} - -.chartPanel{ - width: 50%; - float: left; - .chartTitle{ - font-weight: bold; - font-size: 14pt; - margin-bottom: 20px; - display: block; - } -} diff --git a/app/styles/fonts/MapGlyphs.eot b/app/styles/fonts/MapGlyphs.eot new file mode 100755 index 0000000..10ecc5e Binary files /dev/null and b/app/styles/fonts/MapGlyphs.eot differ diff --git a/app/styles/fonts/MapGlyphs.svg b/app/styles/fonts/MapGlyphs.svg new file mode 100755 index 0000000..6ebb658 --- /dev/null +++ b/app/styles/fonts/MapGlyphs.svg @@ -0,0 +1,387 @@ + + + + + + +{ + "fontFamily": "MapGlyphs", + "majorVersion": 1, + "minorVersion": 0, + "fontURL": "http://mapglyphs.com", + "description": "MapGlyphs - The Ultimate CSS Map Font\nFont generated by IcoMoon.", + "licenseURL": "http://mapglyphs.com/license", + "copyright": "© Ted Grajeda", + "license": "License", + "designerURL": "http://tedgrajeda.com", + "version": "Version 1.0", + "fontId": "MapGlyphs", + "psName": "MapGlyphs", + "subFamily": "Regular", + "fullName": "MapGlyphs" +} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/styles/fonts/MapGlyphs.ttf b/app/styles/fonts/MapGlyphs.ttf new file mode 100755 index 0000000..c933bfa Binary files /dev/null and b/app/styles/fonts/MapGlyphs.ttf differ diff --git a/app/styles/fonts/MapGlyphs.woff b/app/styles/fonts/MapGlyphs.woff new file mode 100755 index 0000000..51707ab Binary files /dev/null and b/app/styles/fonts/MapGlyphs.woff differ diff --git a/app/styles/general.scss b/app/styles/general.scss deleted file mode 100644 index 1946678..0000000 --- a/app/styles/general.scss +++ /dev/null @@ -1,13 +0,0 @@ -.mainIcon{ - font-size: 35px; -} -.mainTable{ - width: 100%; - thead{ - tr td{ - border-bottom: 1px solid #000; - font-weight: bold; - padding-bottom: 10px; - } - } -} diff --git a/app/styles/growler.scss b/app/styles/growler.scss new file mode 100644 index 0000000..0034a5d --- /dev/null +++ b/app/styles/growler.scss @@ -0,0 +1,59 @@ +@import './base'; + +:global .growler { + -webkit-transition: opacity .3s, margin-top .3s; + border-bottom: $color-9 5px solid; + font-family: $font-family-1; + background-color: $color-9; + color: $color-3; + display: block; + opacity: 0; + position: fixed; + top: 0; + left: 0; + visibility: hidden; + width: 100%; + z-index: 999999; + font-size: $font-size-xnormal; + height: 60px; + margin-top: -60px; + line-height: 60px; + text-align: center; + transition: opacity .3s, margin-top .3s; +} + +:global .growler--success { + background-color: $color-9; + margin-top: 0; + opacity: 1; + visibility: visible; + +} + +:global .growler__icon { + margin-bottom: -3px; + margin-right: 5px; +} + +:global .growler--error { + background-color: $color-7; + border-bottom: $color-7 5px solid; + margin-top: 0; + opacity: 1; + visibility: visible; +} + +:global .growler--hiding { + margin-top: -55px; + opacity: 0; + visibility: visible; +} + +:global .growler--hidden { + visibility: hidden; +} + +:global #growler.error .icon { + margin-bottom: -6px; + margin-right: 5px; +} diff --git a/app/styles/index.scss b/app/styles/index.scss deleted file mode 100644 index ba7c61d..0000000 --- a/app/styles/index.scss +++ /dev/null @@ -1,8 +0,0 @@ -html, body{ - height: 100%; - margin: 0; - padding: 0; - :global .app{ - height: 100%; - } -} diff --git a/app/styles/layout/l-content.scss b/app/styles/layout/l-content.scss new file mode 100644 index 0000000..e1b59c7 --- /dev/null +++ b/app/styles/layout/l-content.scss @@ -0,0 +1,40 @@ +@import '../base.scss'; + +.l-content { + height: 100%; + padding: 40px 20px; + position: absolute; + right: 0; + width: calc(100% - 100px); + + @media #{$mq-tablet} { + padding: 40px 20px; + width: calc(100% - 250px); + } + + &.-basic { + align-content: center; + align-items: center; + display: flex; + justify-content: center; + } + + &.-list-card { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + + .card-padding { + width: 100%; + + @media #{$mq-tablet} { + width: calc(100% * (1/2) - 20px); + } + + @media #{$mq-laptop} { + width: calc(100% * (1/3) - 20px); + } + } + } +} diff --git a/app/styles/login.scss b/app/styles/login.scss deleted file mode 100644 index f4fc937..0000000 --- a/app/styles/login.scss +++ /dev/null @@ -1,21 +0,0 @@ -.loginPanel{ - width: 260px; - margin: 0 auto; - margin-top: 50px; - padding: 20px; - box-shadow: 0 2px 2px 0 rgba(0,0,0,.14),0 3px 1px -2px rgba(0,0,0,.2),0 1px 5px 0 rgba(0,0,0,.12); - h3{ - text-align: center; - margin-bottom: 10px; - } - button{ - margin: 5px 0; - width: 100%; - } - .input{ - padding: 2rem 0 0 0; - } - hr{ - margin-bottom: 10px; - } -} diff --git a/app/styles/mapglyphs.scss b/app/styles/mapglyphs.scss new file mode 100755 index 0000000..845dbf3 --- /dev/null +++ b/app/styles/mapglyphs.scss @@ -0,0 +1,1128 @@ +/*! + * Map Glyphs 1.0 by @tedgrajeda - http://mapglyphs.com - @mapglyphs + * License - http://mapglyphs.com/license (CC BY-ND 3.0) + */ +@font-face { + font-family: 'MapGlyphs'; + src:url('./fonts/MapGlyphs.eot'); + src:url('./fonts/MapGlyphs.eot?#iefix') format('embedded-opentype'), + url('./fonts/MapGlyphs.ttf') format('truetype'), + url('./fonts/MapGlyphs.woff') format('woff'), + url('./fonts/MapGlyphs.svg#mapglyphs') format('svg'); + font-weight: normal; + font-style: normal; +} + +:global .mg { + display: inline-block; + font-family: 'MapGlyphs'; + font-style: normal; + font-weight: normal; + line-height: 1; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +:global .mg-fw{ + width:1.2em; + text-align:center +} + +:global .mg-2x { + font-size: 2em; +} +:global .mg-3x { + font-size: 3em; +} +:global .mg-4x { + font-size: 4em; +} +:global .mg-5x { + font-size: 6em; +} +:global .mg-6x { + font-size: 8em; +} +:global .huge { + font-size: 140px; + + &::after { + background-color: #3c61e5; + content: ''; + display: inline-block; + height: 50px; + margin-left: 10px; + margin-right: 20px; + width: 4px; + } +} + +/*Maps*/ +:global .map-sh-tc:before { + content: "\e755"; +} +:global .map-sh-ai:before { + content: "\e756"; +} +:global .map-sh-sh:before { + content: "\e757"; +} +:global .map-sc:before { + content: "\e758"; +} +:global .map-mv:before { + content: "\e759"; +} +:global .map-mu:before { + content: "\e75a"; +} +:global .map-io:before { + content: "\e75b"; +} +:global .map-mo:before { + content: "\e75c"; +} +:global .map-mh:before { + content: "\e75d"; +} +:global .map-km:before { + content: "\e75e"; +} +:global .map-je:before { + content: "\e75f"; +} +:global .map-im:before { + content: "\e760"; +} +:global .map-gg:before { + content: "\e761"; +} +:global .map-yt:before { + content: "\e762"; +} +:global .map-ag:before { + content: "\e763"; +} +:global .map-vg:before { + content: "\e72d"; +} +:global .map-vi:before { + content: "\e72e"; +} +:global .map-bl:before { + content: "\e72f"; +} +:global .map-ai:before { + content: "\e730"; +} +:global .map-cw:before { + content: "\e731"; +} +:global .map-bq:before { + content: "\e732"; +} +:global .map-aw:before { + content: "\e733"; +} +:global .map-sx:before { + content: "\e734"; +} +:global .map-ms:before { + content: "\e735"; +} +:global .map-mf:before { + content: "\e736"; +} +:global .map-ky:before { + content: "\e737"; +} +:global .map-kn:before { + content: "\e738"; +} +:global .map-bm:before { + content: "\e739"; +} +:global .map-ar-alt:before { + content: "\e73a"; +} +:global .map-bv:before { + content: "\e73b"; +} +:global .map-pn:before { + content: "\e73c"; +} +:global .map-pf:before { + content: "\e73d"; +} +:global .map-nu:before { + content: "\e73e"; +} +:global .map-pw:before { + content: "\e73f"; +} +:global .map-fm:before { + content: "\e740"; +} +:global .map-tk:before { + content: "\e741"; +} +:global .map-nr:before { + content: "\e742"; +} +:global .map-ck:before { + content: "\e743"; +} +:global .map-ki:before { + content: "\e744"; +} +:global .map-to:before { + content: "\e745"; +} +:global .map-tv:before { + content: "\e746"; +} +:global .map-mp:before { + content: "\e747"; +} +:global .map-wf:before { + content: "\e748"; +} +:global .map-nf:before { + content: "\e749"; +} +:global .map-cc:before { + content: "\e74a"; +} +:global .map-gu:before { + content: "\e74b"; +} +:global .map-cx:before { + content: "\e74c"; +} +:global .map-as:before { + content: "\e74d"; +} +:global .map-ws:before { + content: "\e74e"; +} +:global .map-pt-alt:before { + content: "\e74f"; +} +:global .map-es-alt:before { + content: "\e750"; +} +:global .map-gi:before { + content: "\e751"; +} +:global .map-va:before { + content: "\e752"; +} +:global .map-hk:before { + content: "\e753"; +} +:global .map-ie-alt:before { + content: "\e754"; +} +:global .map-sg:before { + content: "\e72c"; +} +:global .map-mc:before { + content: "\e72a"; +} +:global .map-sm:before { + content: "\e72b"; +} +:global .map-mm:before { + content: "\e727"; +} +:global .map-sy:before { + content: "\e728"; +} +:global .map-st:before { + content: "\e729"; +} +:global .map-ph:before { + content: "\e6e5"; +} +:global .map-id:before { + content: "\e6e7"; +} +:global .map-my:before { + content: "\e6e9"; +} +:global .map-bn:before { + content: "\e6eb"; +} +:global .map-tl:before { + content: "\e6ed"; +} +:global .map-th:before { + content: "\e6ef"; +} +:global .map-kh:before { + content: "\e6f1"; +} +:global .map-vn:before { + content: "\e6f3"; +} +:global .map-la:before { + content: "\e6f5"; +} +:global .map-jp:before { + content: "\e6f7"; +} +:global .map-tw:before { + content: "\e6f9"; +} +:global .map-kr:before { + content: "\e6fb"; +} +:global .map-kp:before { + content: "\e6fd"; +} +:global .map-bd:before { + content: "\e6fe"; +} +:global .map-bt:before { + content: "\e6ff"; +} +:global .map-np:before { + content: "\e700"; +} +:global .map-lk:before { + content: "\e701"; +} +:global .map-in:before { + content: "\e702"; +} +:global .map-mn:before { + content: "\e703"; +} +:global .map-tj:before { + content: "\e704"; +} +:global .map-kg:before { + content: "\e705"; +} +:global .map-pk:before { + content: "\e706"; +} +:global .map-af:before { + content: "\e707"; +} +:global .map-tm:before { + content: "\e708"; +} +:global .map-uz:before { + content: "\e709"; +} +:global .map-kz:before { + content: "\e70a"; +} +:global .map-cn:before { + content: "\e70b"; +} +:global .map-il:before { + content: "\e70c"; +} +:global .map-ps:before { + content: "\e70d"; +} +:global .map-lb:before { + content: "\e70e"; +} +:global .map-kw:before { + content: "\e70f"; +} +:global .map-bh:before { + content: "\e710"; +} +:global .map-qa:before { + content: "\e711"; +} +:global .map-om:before { + content: "\e712"; +} +:global .map-ye:before { + content: "\e713"; +} +:global .map-ae:before { + content: "\e714"; +} +:global .map-rw:before { + content: "\e715"; +} +:global .map-re:before { + content: "\e716"; +} +:global .map-cv:before { + content: "\e717"; +} +:global .map-gq:before { + content: "\e718"; +} +:global .map-dj:before { + content: "\e719"; +} +:global .map-bi:before { + content: "\e71a"; +} +:global .map-sz:before { + content: "\e71b"; +} +:global .map-ls:before { + content: "\e71c"; +} +:global .map-eh:before { + content: "\e71d"; +} +:global .map-er:before { + content: "\e71e"; +} +:global .map-ug:before { + content: "\e71f"; +} +:global .map-gw:before { + content: "\e720"; +} +:global .map-gm:before { + content: "\e721"; +} +:global .map-sl:before { + content: "\e722"; +} +:global .map-lr:before { + content: "\e723"; +} +:global .map-gh:before { + content: "\e724"; +} +:global .map-tg:before { + content: "\e725"; +} +:global .map-bj:before { + content: "\e726"; +} +:global .map-glb-ar:before { + content: "\e6ee"; +} +:global .map-glb-pa:before { + content: "\e6f0"; +} +:global .map-glb-at:before { + content: "\e6f2"; +} +:global .map-glb-sa:before { + content: "\e6f4"; +} +:global .map-glb-na:before { + content: "\e6f6"; +} +:global .map-glb-an:before { + content: "\e6f8"; +} +:global .map-glb-me:before { + content: "\e6fa"; +} +:global .map-glb-oc:before { + content: "\e6fc"; +} +:global .map-glb-af:before { + content: "\e6ec"; +} +:global .map-glb-as:before { + content: "\e6e6"; +} +:global .map-glb-eu:before { + content: "\e6e8"; +} +:global .map-glb-am:before { + content: "\e6ea"; +} +:global .map-wrld-an:before { + content: "\e6e4"; +} +:global .map-wrld-ca:before { + content: "\e6d9"; +} +:global .map-wrld-se:before { + content: "\e6da"; +} +:global .map-wrld-as:before { + content: "\e6db"; +} +:global .map-wrld-me:before { + content: "\e6dc"; +} +:global .map-wrld-af:before { + content: "\e6dd"; +} +:global .map-wrld-eu:before { + content: "\e6de"; +} +:global .map-wrld-am:before { + content: "\e6df"; +} +:global .map-wrld-na:before { + content: "\e6e0"; +} +:global .map-wrld-sa:before { + content: "\e6e1"; +} +:global .map-wrld-oc:before { + content: "\e6e2"; +} +:global .map-wrld-alt:before { + content: "\e6e3"; +} +:global .map-wrld:before { + content: "\e6d8"; +} +:global .map-ao:before { + content: "\e6b2"; +} +:global .map-bf:before { + content: "\e6b3"; +} +:global .map-bw:before { + content: "\e6b4"; +} +:global .map-cd:before { + content: "\e6b5"; +} +:global .map-cf:before { + content: "\e6b6"; +} +:global .map-cg:before { + content: "\e6b7"; +} +:global .map-ci:before { + content: "\e6b8"; +} +:global .map-cm:before { + content: "\e6b9"; +} +:global .map-dz:before { + content: "\e6ba"; +} +:global .map-eg:before { + content: "\e6bb"; +} +:global .map-et:before { + content: "\e6bc"; +} +:global .map-ga:before { + content: "\e6bd"; +} +:global .map-gn:before { + content: "\e6be"; +} +:global .map-iq:before { + content: "\e6bf"; +} +:global .map-ir:before { + content: "\e6c0"; +} +:global .map-jo:before { + content: "\e6c1"; +} +:global .map-ke:before { + content: "\e6c2"; +} +:global .map-ly:before { + content: "\e6c3"; +} +:global .map-ma:before { + content: "\e6c4"; +} +:global .map-mg:before { + content: "\e6c5"; +} +:global .map-ml:before { + content: "\e6c6"; +} +:global .map-mr:before { + content: "\e6c7"; +} +:global .map-mw:before { + content: "\e6c8"; +} +:global .map-mz:before { + content: "\e6c9"; +} +:global .map-na:before { + content: "\e6ca"; +} +:global .map-ne:before { + content: "\e6cb"; +} +:global .map-ng:before { + content: "\e6cc"; +} +:global .map-sa:before { + content: "\e6cd"; +} +:global .map-sd:before { + content: "\e6ce"; +} +:global .map-sn:before { + content: "\e6cf"; +} +:global .map-so:before { + content: "\e6d0"; +} +:global .map-ss:before { + content: "\e6d1"; +} +:global .map-td:before { + content: "\e6d2"; +} +:global .map-tn:before { + content: "\e6d3"; +} +:global .map-tz:before { + content: "\e6d4"; +} +:global .map-za:before { + content: "\e6d5"; +} +:global .map-zm:before { + content: "\e6d6"; +} +:global .map-zw:before { + content: "\e6d7"; +} +:global .map-fo:before { + content: "\e695"; +} +:global .map-ge:before { + content: "\e696"; +} +:global .map-am:before { + content: "\e697"; +} +:global .map-az:before { + content: "\e698"; +} +:global .map-ca-nb:before { + content: "\e699"; +} +:global .map-mt:before { + content: "\e65a"; +} +:global .map-ad:before { + content: "\e65b"; +} +:global .map-li:before { + content: "\e65c"; +} +:global .map-lu:before { + content: "\e65d"; +} +:global .map-sj:before { + content: "\e65e"; +} +:global .map-lt:before { + content: "\e65f"; +} +:global .map-lv:before { + content: "\e660"; +} +:global .map-ee:before { + content: "\e661"; +} +:global .map-ru:before { + content: "\e662"; +} +:global .map-gl:before { + content: "\e663"; +} +:global .map-no:before { + content: "\e664"; +} +:global .map-se:before { + content: "\e665"; +} +:global .map-fi:before { + content: "\e666"; +} +:global .map-cy:before { + content: "\e667"; +} +:global .map-xk:before { + content: "\e668"; +} +:global .map-rs:before { + content: "\e669"; +} +:global .map-hr:before { + content: "\e66a"; +} +:global .map-ba:before { + content: "\e66b"; +} +:global .map-me:before { + content: "\e66c"; +} +:global .map-mk:before { + content: "\e66d"; +} +:global .map-by:before { + content: "\e66e"; +} +:global .map-si:before { + content: "\e66f"; +} +:global .map-hu:before { + content: "\e670"; +} +:global .map-md:before { + content: "\e671"; +} +:global .map-ro:before { + content: "\e672"; +} +:global .map-al:before { + content: "\e673"; +} +:global .map-bg:before { + content: "\e674"; +} +:global .map-sk:before { + content: "\e675"; +} +:global .map-cz:before { + content: "\e676"; +} +:global .map-ua:before { + content: "\e677"; +} +:global .map-tr:before { + content: "\e678"; +} +:global .map-gr:before { + content: "\e679"; +} +:global .map-dk:before { + content: "\e67a"; +} +:global .map-at:before { + content: "\e67b"; +} +:global .map-nl:before { + content: "\e67c"; +} +:global .map-be:before { + content: "\e67d"; +} +:global .map-ch:before { + content: "\e67e"; +} +:global .map-pl:before { + content: "\e67f"; +} +:global .map-pt:before { + content: "\e680"; +} +:global .map-es:before { + content: "\e681"; +} +:global .map-it:before { + content: "\e682"; +} +:global .map-fr:before { + content: "\e683"; +} +:global .map-de:before { + content: "\e684"; +} +:global .map-ie:before { + content: "\e685"; +} +:global .map-is:before { + content: "\e686"; +} +:global .map-uk:before { + content: "\e687"; +} +:global .map-uk-sc:before { + content: "\e69a"; +} +:global .map-uk-en:before { + content: "\e69b"; +} +:global .map-uk-wa:before { + content: "\e69c"; +} +:global .map-uk-ni:before { + content: "\e69d"; +} +:global .map-aq:before { + content: "\e691"; +} +:global .map-tf:before { + content: "\e692"; +} +:global .map-hm:before { + content: "\e693"; +} +:global .map-gs:before { + content: "\e694"; +} +:global .map-au:before { + content: "\e635"; +} +:global .map-au-wa:before { + content: "\e69e"; +} +:global .map-au-nt:before { + content: "\e69f"; +} +:global .map-au-ql:before { + content: "\e6a0"; +} +:global .map-au-sa:before { + content: "\e6a1"; +} +:global .map-au-nw:before { + content: "\e6a2"; +} +:global .map-au-vc:before { + content: "\e6a3"; +} +:global .map-au-ts:before { + content: "\e6a4"; +} +:global .map-au-ac:before { + content: "\e6a5"; +} +:global .map-fj:before { + content: "\e636"; +} +:global .map-nc:before { + content: "\e637"; +} +:global .map-nz:before { + content: "\e638"; +} +:global .map-pg:before { + content: "\e639"; +} +:global .map-sb:before { + content: "\e63a"; +} +:global .map-vu:before { + content: "\e63b"; +} +:global .map-ar:before { + content: "\e63c"; +} +:global .map-bo:before { + content: "\e63d"; +} +:global .map-br:before { + content: "\e63e"; +} +:global .map-bb:before { + content: "\e688"; +} +:global .map-bs:before { + content: "\e63f"; +} +:global .map-bz:before { + content: "\e640"; +} +:global .map-ca:before { + content: "\e641"; +} +:global .map-ca-yt:before { + content: "\e6a6"; +} +:global .map-ca-bc:before { + content: "\e6a7"; +} +:global .map-ca-nt:before { + content: "\e6a8"; +} +:global .map-ca-nu:before { + content: "\e6a9"; +} +:global .map-ca-ab:before { + content: "\e6aa"; +} +:global .map-ca-sk:before { + content: "\e6ab"; +} +:global .map-ca-mb:before { + content: "\e6ac"; +} +:global .map-ca-on:before { + content: "\e6ad"; +} +:global .map-ca-qc:before { + content: "\e6ae"; +} +:global .map-ca-pe:before { + content: "\e6af"; +} +:global .map-ca-nl:before { + content: "\e6b0"; +} +:global .map-ca-ns:before { + content: "\e6b1"; +} +:global .map-cl:before { + content: "\e642"; +} +:global .map-co:before { + content: "\e643"; +} +:global .map-cr:before { + content: "\e644"; +} +:global .map-cu:before { + content: "\e645"; +} +:global .map-do:before { + content: "\e646"; +} +:global .map-dm:before { + content: "\e689"; +} +:global .map-ec:before { + content: "\e647"; +} +:global .map-fk:before { + content: "\e648"; +} +:global .map-gf:before { + content: "\e649"; +} +:global .map-gd:before { + content: "\e68a"; +} +:global .map-gp:before { + content: "\e68b"; +} +:global .map-gt:before { + content: "\e64a"; +} +:global .map-gy:before { + content: "\e64b"; +} +:global .map-hn:before { + content: "\e64c"; +} +:global .map-ht:before { + content: "\e64d"; +} +:global .map-jm:before { + content: "\e64e"; +} +:global .map-mq:before { + content: "\e68c"; +} +:global .map-mx:before { + content: "\e64f"; +} +:global .map-ni:before { + content: "\e650"; +} +:global .map-pa:before { + content: "\e651"; +} +:global .map-pe:before { + content: "\e652"; +} +:global .map-pm:before { + content: "\e68d"; +} +:global .map-pr:before { + content: "\e653"; +} +:global .map-py:before { + content: "\e654"; +} +:global .map-sr:before { + content: "\e655"; +} +:global .map-sv:before { + content: "\e656"; +} +:global .map-vc:before { + content: "\e68e"; +} +:global .map-lc:before { + content: "\e68f"; +} +:global .map-tt:before { + content: "\e657"; +} +:global .map-tc:before { + content: "\e690"; +} +:global .map-uy:before { + content: "\e658"; +} +:global .map-ve:before { + content: "\e659"; +} +:global .map-us-ak:before { + content: "\e601"; +} +:global .map-us-al:before { + content: "\e602"; +} +:global .map-us-ar:before { + content: "\e603"; +} +:global .map-us-az:before { + content: "\e604"; +} +:global .map-us-ca:before { + content: "\e605"; +} +:global .map-us-co:before { + content: "\e606"; +} +:global .map-us-ct:before { + content: "\e607"; +} +:global .map-us-de:before { + content: "\e608"; +} +:global .map-us-fl:before { + content: "\e609"; +} +:global .map-us-ga:before { + content: "\e60a"; +} +:global .map-us-hi:before { + content: "\e60b"; +} +:global .map-us-ia:before { + content: "\e60c"; +} +:global .map-us-id:before { + content: "\e60d"; +} +:global .map-us-il:before { + content: "\e60e"; +} +:global .map-us-in:before { + content: "\e60f"; +} +:global .map-us-ks:before { + content: "\e610"; +} +:global .map-us-ky:before { + content: "\e611"; +} +:global .map-us-la:before { + content: "\e612"; +} +:global .map-us-ma:before { + content: "\e613"; +} +:global .map-us-md:before { + content: "\e614"; +} +:global .map-us-me:before { + content: "\e615"; +} +:global .map-us-mi:before { + content: "\e616"; +} +:global .map-us-mn:before { + content: "\e617"; +} +:global .map-us-mo:before { + content: "\e618"; +} +:global .map-us-ms:before { + content: "\e619"; +} +:global .map-us-mt:before { + content: "\e61a"; +} +:global .map-us-nc:before { + content: "\e61b"; +} +:global .map-us-nd:before { + content: "\e61c"; +} +:global .map-us-ne:before { + content: "\e61d"; +} +:global .map-us-nh:before { + content: "\e61e"; +} +:global .map-us-nj:before { + content: "\e61f"; +} +:global .map-us-nm:before { + content: "\e620"; +} +:global .map-us-nv:before { + content: "\e621"; +} +:global .map-us-ny:before { + content: "\e622"; +} +:global .map-us-oh:before { + content: "\e623"; +} +:global .map-us-ok:before { + content: "\e624"; +} +:global .map-us-or:before { + content: "\e625"; +} +:global .map-us-pa:before { + content: "\e626"; +} +:global .map-us-ri:before { + content: "\e627"; +} +:global .map-us-sc:before { + content: "\e628"; +} +:global .map-us-sd:before { + content: "\e629"; +} +:global .map-us-tn:before { + content: "\e62a"; +} +:global .map-us-tx:before { + content: "\e62b"; +} +:global .map-us-ut:before { + content: "\e62c"; +} +:global .map-us-va:before { + content: "\e62d"; +} +:global .map-us-vt:before { + content: "\e62e"; +} +:global .map-us-wa:before { + content: "\e62f"; +} +:global .map-us-wi:before { + content: "\e630"; +} +:global .map-us-wv:before { + content: "\e631"; +} +:global .map-us-wy:before { + content: "\e632"; +} +:global .map-us-dc:before { + content: "\e634"; +} +:global .map-us:before { + content: "\e600"; +} +:global .map-us-alt:before { + content: "\e633"; +} diff --git a/app/styles/menu.scss b/app/styles/menu.scss deleted file mode 100644 index 292d46d..0000000 --- a/app/styles/menu.scss +++ /dev/null @@ -1,8 +0,0 @@ -.listMenu { - display: flex; - flex-direction: column; - flex: 1; - button{ - text-align: left; - } -} diff --git a/app/styles/normalize.css b/app/styles/normalize.css new file mode 100644 index 0000000..f623a65 --- /dev/null +++ b/app/styles/normalize.css @@ -0,0 +1,431 @@ +/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Correct the line height in all browsers. + * 3. Prevent adjustments of font size after orientation changes in IE and iOS. + */ + +html { + font-family: sans-serif; /* 1 */ + line-height: 1.15; /* 2 */ + -ms-text-size-adjust: 100%; /* 3 */ + -webkit-text-size-adjust: 100%; /* 3 */ +} + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + * 2. Add the correct display in IE. + */ + +article, +aside, +details, /* 1 */ +figcaption, +figure, +footer, +header, +main, /* 2 */ +menu, +nav, +section, +summary { /* 1 */ + display: block; +} + +/** + * Add the correct display in IE 9-. + */ + +audio, +canvas, +progress, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Add the correct display in IE 10-. + * 1. Add the correct display in IE. + */ + +template, /* 1 */ +[hidden] { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ + +a:active, +a:hover { + outline-width: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + -webkit-margin-before: 0; + -webkit-margin-after: 0; +} +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change font properties to `inherit` in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font: inherit; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Restore the font weight unset by the previous rule. + */ + +optgroup { + font-weight: bold; +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Change the border, margin, and padding in all browsers (opinionated). + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on OS X. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Correct the text style of placeholders in Chrome, Edge, and Safari. + */ + +::-webkit-input-placeholder { + color: inherit; + opacity: 0.54; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} diff --git a/app/styles/plugin.scss b/app/styles/plugin.scss deleted file mode 100644 index 8efa56e..0000000 --- a/app/styles/plugin.scss +++ /dev/null @@ -1,15 +0,0 @@ -.mainIcon{ - font-size: 35px; -} -.card{ - float: left; - margin: 2%; - width: 21%; - - .deactivate:hover{ - background: rgba(255, 0 , 0, 0.2) !important; - } - .activate:hover{ - background: rgba(0, 255 , 0, 0.2) !important; - } -} diff --git a/app/styles/profile.scss b/app/styles/profile.scss deleted file mode 100644 index 8ec6684..0000000 --- a/app/styles/profile.scss +++ /dev/null @@ -1,3 +0,0 @@ -.mainIcon{ - font-size: 35px; -} diff --git a/app/styles/theme.scss b/app/styles/theme.scss new file mode 100644 index 0000000..807eb40 --- /dev/null +++ b/app/styles/theme.scss @@ -0,0 +1,156 @@ +@import './base'; +@import 'datepicker/colors'; +@import 'datepicker/globals'; +@import 'datepicker/mixins'; +@import 'datepicker/config'; + +:global .input:not(.disabled) > .inputElement { + cursor: pointer; +} + +:global .header { + padding: 15 * $unit 5 * $unit; + color: $datepicker-primary-contrast-color; + cursor: pointer; + background-color: $datepicker-primary-color; +} + +:global .year { + display: inline-block; + font-size: $datepicker-year-font-size; + transition: opacity, font-size $animation-duration $animation-curve-default; +} + +:global .date { + display: block; + font-weight: $font-weight-semi-bold; + text-transform: capitalize; + transition: opacity $animation-duration $animation-curve-default; +} + +:global .calendarWrapper { + padding: $unit .5 * $unit 0; +} + +:global .yearsDisplay { + .date { + opacity: $datepicker-inactive-opacity; + } + .year { + font-size: $font-size-normal; + } +} + +:global .monthsDisplay { + .year { + opacity: $datepicker-inactive-opacity; + } +} + +:global .dialog { + width: $datepicker-dialog-width; + > [role="body"] { + padding: 0; + } + > [role="navigation"] > .button { + color: $datepicker-primary-color; + &:hover { + background: $datepicker-primary-hover-color; + } + &:focus:not(:active) { + background: $datepicker-primary-hover-color; + } + } +} + +:global .calendar { + position: relative; + height: $calendar-total-height; + overflow: hidden; + font-size: $font-size-small; + line-height: $calendar-row-height; + text-align: center; + background: $calendar-primary-contrast-color; + .prev, .next { + position: absolute; + top: 0; + z-index: $z-index-high; + height: 3.6 * $unit; + cursor: pointer; + opacity: .7; + } + .prev { + left: 0; + } + .next { + right: 0; + } +} + +:global .title { + display: inline-block; + font-weight: 500; + line-height: $calendar-row-height; +} + +:global .years { + height: 100%; + overflow-y: auto; + font-size: $font-size-big; + > li { + line-height: 2.4; + cursor: pointer; + &.active { + font-size: $calendar-year-font-size; + color: $calendar-primary-color; + } + } +} + +:global .week { + display: flex; + height: $calendar-row-height; + flex-wrap: wrap; + font-size: $calendar-day-font-size; + line-height: $calendar-row-height; + opacity: .5; + > span { + flex: 0 0 (100% / 7); + } +} + +:global .days { + display: flex; + flex-wrap: wrap; + font-size: $calendar-day-font-size; +} + +:global .day { + flex: 0 0 (100% / 7); + padding: $calendar-day-padding-topbottom $calendar-day-padding-leftright; + > span { + display: inline-block; + width: $calendar-row-height; + height: $calendar-row-height; + line-height: $calendar-row-height; + border-radius: 50%; + } + &:hover:not(.active):not(.disabled) > span { + color: $calendar-primary-contrast-color; + background: $calendar-primary-hover-color; + } + &.active > span { + color: $calendar-primary-contrast-color; + background: $calendar-primary-color; + } + &:hover:not(.disabled) > span { + cursor: pointer; + } + &.disabled { + opacity: $calendar-day-disable-opacity; + } +} + +:global .month { + background-color: $calendar-primary-contrast-color; +} diff --git a/app/styles/user.scss b/app/styles/user.scss deleted file mode 100644 index 8b13789..0000000 --- a/app/styles/user.scss +++ /dev/null @@ -1 +0,0 @@ - diff --git a/app/template.html b/app/template.html index fb6f813..8f46383 100644 --- a/app/template.html +++ b/app/template.html @@ -3,7 +3,8 @@ Control Tower UI - + +
diff --git a/curl-format.txt b/curl-format.txt new file mode 100644 index 0000000..c69cc30 --- /dev/null +++ b/curl-format.txt @@ -0,0 +1,8 @@ + time_namelookup: %{time_namelookup}\n + time_connect: %{time_connect}\n + time_appconnect: %{time_appconnect}\n + time_pretransfer: %{time_pretransfer}\n + time_redirect: %{time_redirect}\n + time_starttransfer: %{time_starttransfer}\n + ----------\n + time_total: %{time_total}\n diff --git a/normalize.css b/normalize.css new file mode 100644 index 0000000..8710595 --- /dev/null +++ b/normalize.css @@ -0,0 +1,422 @@ +/*! normalize.css v4.1.1 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Correct the line height in all browsers. + * 3. Prevent adjustments of font size after orientation changes in IE and iOS. + */ + +html { + font-family: sans-serif; /* 1 */ + line-height: 1.15; /* 2 */ + -ms-text-size-adjust: 100%; /* 3 */ + -webkit-text-size-adjust: 100%; /* 3 */ +} + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/* HTML5 display definitions + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + * 2. Add the correct display in IE. + */ + +article, +aside, +details, /* 1 */ +figcaption, +figure, +footer, +header, +main, /* 2 */ +menu, +nav, +section, +summary { /* 1 */ + display: block; +} + +/** + * Add the correct display in IE 9-. + */ + +audio, +canvas, +progress, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + vertical-align: baseline; +} + +/** + * Add the correct display in IE 10-. + * 1. Add the correct display in IE. + */ + +template, /* 1 */ +[hidden] { + display: none; +} + +/* Links + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ + +a:active, +a:hover { + outline-width: 0; +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Grouping content + ========================================================================== */ + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +pre, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change font properties to `inherit` in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font: inherit; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Restore the font weight unset by the previous rule. + */ + +optgroup { + font-weight: bold; +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Change the border, margin, and padding in all browsers (opinionated). + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on OS X. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * Correct the text style of placeholders in Chrome, Edge, and Safari. + */ + +::-webkit-input-placeholder { + color: inherit; + opacity: 0.54; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} diff --git a/package.json b/package.json index 044b449..c9027b1 100644 --- a/package.json +++ b/package.json @@ -4,8 +4,8 @@ "description": "", "main": "index.js", "scripts": { - "dev": "webpack-dev-server --config webpack.config.js --progress --colors --inline", - "build": "webpack -p" + "dev": "NODE_ENV=dev webpack-dev-server --config webpack.config.js --progress --colors --inline", + "build": "NODE_ENV=prod webpack -p" }, "author": "", "license": "MIT", @@ -21,14 +21,20 @@ "dotenv": "^2.0.0", "express": "^4.13.4", "extract-text-webpack-plugin": "^1.0.1", + "file-loader": "^0.9.0", + "flash-notification-react-redux": "^1.0.5", + "holmes.js": "^1.13.3", "html-webpack-plugin": "^2.19.0", + "image-webpack-loader": "^2.0.0", + "immutability-helper": "^2.0.0", "jade": "^1.11.0", "json-loader": "^0.5.4", - "lodash": "^4.13.1", + "lodash": "^4.16.0", "moment": "^2.14.1", "morgan": "^1.7.0", "node-sass": "^3.7.0", "normalize.css": "^4.2.0", + "numeral": "^1.5.3", "postcss-loader": "^0.9.1", "pretty-error": "^2.0.0", "react": "^15.2.1", @@ -39,31 +45,34 @@ "react-d3": "^0.4.0", "react-dom": "^15.0.2", "react-google-maps": "^4.11.0", + "react-loading": "0.0.9", "react-redux": "^4.4.5", "react-router": "^2.4.1", "react-router-redux": "^4.0.4", "react-time": "^4.2.0", - "react-toolbox": "^1.0.1", + "react-toolbox": "^1.2.1", "redux": "^3.5.2", "redux-thunk": "^2.1.0", "sass-loader": "^3.2.0", "style-loader": "^0.13.1", + "url-loader": "^0.5.7", "webpack": "^1.13.0", "webpack-dev-middleware": "^1.6.1", "webpack-hot-middleware": "^2.12.1", "whatwg-fetch": "^1.0.0" }, "devDependencies": { + "babel-plugin-transform-decorators-legacy": "^1.3.4", + "babel-preset-es2015": "^6.1.18", + "babel-preset-react": "^6.1.18", + "babel-preset-react-hmre": "^1.1.1", + "babel-preset-stage-0": "^6.5.0", "eslint": "^2.12.0", "eslint-config-airbnb": "^9.0.1", "eslint-plugin-import": "^1.8.1", "eslint-plugin-jsx-a11y": "^1.4.2", "eslint-plugin-react": "^5.1.1", - "webpack-dev-server": "^1.14.1", - "babel-preset-react-hmre": "^1.1.1", - "babel-preset-stage-0": "^6.5.0", "react-hot-loader": "^1.3.0", - "babel-preset-es2015": "^6.1.18", - "babel-preset-react": "^6.1.18" + "webpack-dev-server": "^1.14.1" } } diff --git a/webpack.config.js b/webpack.config.js index 86c7fbd..34c1a42 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,67 +1,92 @@ -const path = require('path'); +/* eslint-env node */ const webpack = require('webpack'); -const autoprefixer = require('autoprefixer'); -const ExtractTextPlugin = require('extract-text-webpack-plugin'); const HtmlWebpackPlugin = require('html-webpack-plugin'); +const ExtractTextPlugin = require('extract-text-webpack-plugin'); +const autoprefixer = require('autoprefixer'); const rootPath = process.cwd(); +const path = require('path'); +require('dotenv').config({ + silent: true, +}); + const webpackConfig = { - context: __dirname, - devtool: 'inline-source-map', - devServer: { - port: 3000, - historyApiFallback: true, - }, entry: [ 'whatwg-fetch', './app/src/index.jsx', ], - output: { - path: path.join(rootPath, 'dist/'), - filename: '[name]-[hash].js', - publicPath: '/', - }, - resolve: { - extensions: ['', '.scss', '.css', '.jsx', '.js', '.json'], - modulesDirectories: [ - 'node_modules', - path.resolve(__dirname, './node_modules') - ] - }, - module: { - loaders: [{ - test: /(\.js|\.jsx)$/, - exclude: /(node_modules)/, - loader: 'babel', - query: { - presets: ['es2015', 'stage-0', 'react'], - } - }, { - test: /(\.scss|\.css)$/, - loader: ExtractTextPlugin.extract('style', 'css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') - }] + devtool: 'source-map', + devServer: { + port: 3000, + historyApiFallback: true, }, - postcss: [autoprefixer], plugins: [ new ExtractTextPlugin('styles.css', { allChunks: true, }), new HtmlWebpackPlugin({ - template: 'app/index.html', + template: 'app/template.html', inject: 'body', - filename: 'index.html' + filename: 'index.html', }), new webpack.optimize.OccurenceOrderPlugin(), new webpack.NoErrorsPlugin(), new webpack.DefinePlugin({ ENVIRONMENT: JSON.stringify(process.env.NODE_ENV || 'development'), VERSION: JSON.stringify(require('./package.json').version), + 'process.env.API_URL': JSON.stringify(process.env.API_URL), }), - ] + ], + output: { + path: 'dist', + filename: '[name].bundle.js', + publicPath: '/', + }, + // this section allows imports with absolute paths (as if usiong node_modules) + resolve: { + extensions: ['', '.js', '.jsx', '.json'], + }, + module: { + loaders: [{ + test: /(\.js|\.jsx)$/, + include: [ + path.resolve(__dirname, 'app'), + path.resolve(__dirname, 'node_modules/flash-notification-react-redux'), + ], + loaders: ['babel-loader'], + }, { + test: /\.json$/, + loader: 'json', + }, { + test: /\.(ttf|eot|svg)(\?v=[0-9].[0-9].[0-9])?$/i, + loaders: ['file?name=[path][name].[ext]'], + }, { + test: /\.woff(2)?(\?v=[0-9].[0-9].[0-9])?$/i, + loaders: ['url-loader?mimetype=application/font-woff'], + }], + }, + postcss: function () { + return [autoprefixer]; + }, }; + // Environment configuration if (process.env.NODE_ENV === 'production') { + // Loaders + webpackConfig.module.loaders.push({ + test: /(\.scss|\.css)$/, + loader: ExtractTextPlugin.extract('css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') + }); + webpackConfig.module.loaders.push({ + test: /\.(jpe?g|png|gif|svg)$/i, + loaders: [ + 'file?hash=sha512&digest=hex&name=[hash].[ext]', + 'image-webpack?{progressive:true, optimizationLevel: 7,' + + ' interlaced: false, pngquant:{quality: "65-90", speed: 4}}', + ], + }); + // Plugins webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false, @@ -71,8 +96,19 @@ if (process.env.NODE_ENV === 'production') { }, comments: false, })); + webpackConfig.plugins.push(new ExtractTextPlugin('styles-[hash].css')); } else { - webpackConfig.devtool = 'eval-source-map'; + // Activating source map + webpackConfig.devtool = 'source-map'; + // Loaders + webpackConfig.module.loaders.push({ + test: /(\.scss|\.css)$/, + loader: ExtractTextPlugin.extract('css?sourceMap&modules&importLoaders=1&localIdentName=[name]__[local]___[hash:base64:5]!postcss!sass') + }); + webpackConfig.module.loaders.push({ + test: /\.(jpe?g|png|gif|svg)$/i, + loaders: ['file?name=[path][name].[ext]'], + }); } module.exports = webpackConfig;