From 62f069ef0af1444089a4d477f05ac7279897fa32 Mon Sep 17 00:00:00 2001 From: elijah Date: Fri, 26 Aug 2016 21:09:53 -0700 Subject: [feat] added initial bitmask_js (WIP) --- .../app/components/main_panel/account_list.js | 113 +++++++++++ .../app/components/main_panel/email_section.js | 0 .../bitmask_js/app/components/main_panel/index.js | 57 ++++++ .../app/components/main_panel/main_panel.less | 208 +++++++++++++++++++++ .../app/components/main_panel/section_layout.js | 59 ++++++ .../app/components/main_panel/user_section.js | 71 +++++++ .../app/components/main_panel/vpn_section.js | 0 7 files changed, 508 insertions(+) create mode 100644 src/leap/bitmask_js/app/components/main_panel/account_list.js create mode 100644 src/leap/bitmask_js/app/components/main_panel/email_section.js create mode 100644 src/leap/bitmask_js/app/components/main_panel/index.js create mode 100644 src/leap/bitmask_js/app/components/main_panel/main_panel.less create mode 100644 src/leap/bitmask_js/app/components/main_panel/section_layout.js create mode 100644 src/leap/bitmask_js/app/components/main_panel/user_section.js create mode 100644 src/leap/bitmask_js/app/components/main_panel/vpn_section.js (limited to 'src/leap/bitmask_js/app/components/main_panel') diff --git a/src/leap/bitmask_js/app/components/main_panel/account_list.js b/src/leap/bitmask_js/app/components/main_panel/account_list.js new file mode 100644 index 00000000..d0ef092f --- /dev/null +++ b/src/leap/bitmask_js/app/components/main_panel/account_list.js @@ -0,0 +1,113 @@ +import React from 'react' +import {Button, ButtonGroup, ButtonToolbar, Glyphicon} from 'react-bootstrap' + +import App from 'app' +import Account from 'models/account' + +export default class AccountList extends React.Component { + + static get defaultProps() {return{ + account: null, + accounts: [], + onAdd: null, + onRemove: null, + onSelect: null + }} + + constructor(props) { + super(props) + + this.state = { + mode: 'expanded' + } + + // prebind: + this.select = this.select.bind(this) + this.add = this.add.bind(this) + this.remove = this.remove.bind(this) + this.expand = this.expand.bind(this) + this.collapse = this.collapse.bind(this) + } + + select(e) { + let account = this.props.accounts.find( + account => account.id == e.currentTarget.dataset.id + ) + if (this.props.onSelect) { + this.props.onSelect(account) + } + } + + add() { + App.show('wizard') + } + + remove() { + } + + expand() { + this.setState({mode: 'expanded'}) + } + + collapse() { + this.setState({mode: 'collapsed'}) + } + + render() { + let style = {} + let expandButton = null + let plusminusButtons = null + + if (this.state.mode == 'expanded') { + expandButton = ( + + ) + plusminusButtons = ( + + + + + ) + } else { + style.width = '60px' + expandButton = ( + + ) + } + + let items = this.props.accounts.map((account, i) => { + let className = account == this.props.account ? 'active' : 'inactive' + return ( +
  • + {account.userpart} + {account.domain} + + +
  • + ) + }) + + + return ( +
    + + + {plusminusButtons} + {expandButton} + +
    + ) + } + + +} diff --git a/src/leap/bitmask_js/app/components/main_panel/email_section.js b/src/leap/bitmask_js/app/components/main_panel/email_section.js new file mode 100644 index 00000000..e69de29b diff --git a/src/leap/bitmask_js/app/components/main_panel/index.js b/src/leap/bitmask_js/app/components/main_panel/index.js new file mode 100644 index 00000000..910d58b6 --- /dev/null +++ b/src/leap/bitmask_js/app/components/main_panel/index.js @@ -0,0 +1,57 @@ +// +// The main panel manages the current account and the list of available accounts +// +// It displays multiple sections, one for each service. +// + +import React from 'react' +import App from 'app' +import Login from 'components/login' + +import './main_panel.less' +import AccountList from './account_list' +import UserSection from './user_section' + +export default class MainPanel extends React.Component { + + static get defaultProps() {return{ + initialAccount: null + }} + + constructor(props) { + super(props) + this.state = { + account: null, + accounts: [] + } + this.activateAccount = this.activateAccount.bind(this) + } + + componentWillMount() { + if (this.props.initialAccount) { + this.setState({ + account: this.props.initialAccount, + accounts: [this.props.initialAccount] + }) + } + } + + activateAccount(account) { + this.setState({ + account: account, + accounts: [account] + }) + } + + render() { + return ( +
    + +
    + +
    +
    + ) + } + +} diff --git a/src/leap/bitmask_js/app/components/main_panel/main_panel.less b/src/leap/bitmask_js/app/components/main_panel/main_panel.less new file mode 100644 index 00000000..3172bba5 --- /dev/null +++ b/src/leap/bitmask_js/app/components/main_panel/main_panel.less @@ -0,0 +1,208 @@ +// The space around account entries: +@accounts-padding: 8px; +@accounts-width: 200px; + +// +// LAYOUT +// + +.main-panel { + position: absolute; + height: 100%; + width: 100%; + display: flex; + flex-direction: row; + + > .body { + flex: 1 1 auto; + overflow: auto; + } + + .accounts { + flex: 0 0 auto; + overflow-y: auto; + overflow-x: hidden; + + display: flex; + flex-direction: column; + ul { + flex: 1 1 1000px; + } + .btn-toolbar { + flex: 0 0 auto; + } + + } + +} + +// +// Style +// + +.main-panel > .body { + padding: 20px; +} + +.main-panel .accounts { + background-color: #333; + width: @accounts-width; + padding: @accounts-padding; + padding-right: 0px; +} + +.main-panel .accounts ul { + list-style: none; + margin: 0; + padding: 0; +} + +.main-panel .accounts li { + position: relative; + cursor: pointer; + color: white; + padding: 15px; + background-color: #444; + margin-bottom: @accounts-padding; + border-top-left-radius: @accounts-padding; + border-bottom-left-radius: @accounts-padding; + z-index: 100; +} + +.main-panel .accounts li span.domain { + display: block; + font-weight: bold; + //margin-left: 40px; +} + +.main-panel .accounts li span.username { + display: block; + //margin-left: 40px; + //line-height: 7px; + //margin-bottom: 4px; +} + +/*.main-panel .accounts li span.icon { + display: block; + height: 32px; + width: 32px; + background-color: #999; + float: left; +} +*/ + +.main-panel .accounts li.active { + background-color: white; + color: #333; +} + +.main-panel .accounts li.active span.arc { + display: block; + height: @accounts-padding; + width: @accounts-padding; + background-color: white; + position: absolute; + right: 0; +} + +.main-panel .accounts li.active span.arc.top { + top: 0; + margin-top: -@accounts-padding; +} +.main-panel .accounts li.active span.arc.bottom { + bottom: 0; + margin-bottom: -@accounts-padding; +} +.main-panel .accounts li.active span.arc:after { + display: block; + content: ""; + border-radius: 100%; + height: 0px; + width: 0px; + margin-left: -@accounts-padding; +} +.main-panel .accounts li.active span.arc.top:after { + border: @accounts-padding solid transparent; + border-right: @accounts-padding solid #333; + margin-top: -@accounts-padding; + transform: rotate(45deg); +} +.main-panel .accounts li.active span.arc.bottom:after { + border: @accounts-padding solid #333; +} + +.main-panel .accounts .btn.expander { + margin-right: @accounts-padding; +} + + +// +// SECTIONS +// + +@icon-size: 32px; +@status-size: 24px; +@section-padding: 10px; + +// service sections layout + +.main-panel .service-section { + display: flex; + flex-direction: row; + > .icon { + flex: 0 0 auto; + } + > .body { + flex: 1 1 auto; + } + > .buttons { + flex: 0 0 auto; + } + > .status { + flex: 0 0 auto; + display: flex; + align-items: center; + } +} + +.main-panel .service-section div { + //outline: 1px solid rgba(0,0,0,0.1); +} + +// service sections style + +.main-panel .service-section { + background: #f6f6f6; + border-radius: 4px; + padding: 10px; + &.wide-margin { + padding: 20px 20px 20px 10px; // arbitrary, looks nice + } + > .icon { + padding-right: @section-padding; + img { + width: @icon-size; + height: @icon-size; + } + } + > .body { + h1 { + margin: 0; + padding: 0; + font-size: @icon-size - 10; + line-height: @icon-size; + } + } + > .buttons { + padding-left: 10px; + } + > .status { + padding-left: @section-padding; + width: @section-padding + @status-size; + img { + width: @status-size; + height: @status-size; + } + } +} + diff --git a/src/leap/bitmask_js/app/components/main_panel/section_layout.js b/src/leap/bitmask_js/app/components/main_panel/section_layout.js new file mode 100644 index 00000000..e7c6f2ab --- /dev/null +++ b/src/leap/bitmask_js/app/components/main_panel/section_layout.js @@ -0,0 +1,59 @@ +// +// This is the layout for a service section in the main window. +// It does not do anything except for arrange items using css and html. +// + +import React from 'react' + +export default class SectionLayout extends React.Component { + + static get defaultProps() {return{ + icon: null, + buttons: null, + status: null, + className: "", + style: {} + }} + + constructor(props) { + super(props) + } + + render() { + let className = ["service-section", this.props.className].join(' ') + let status = null + let icon = null + let buttons = null + + if (this.props.status) { + status = ( +
    + +
    + ) + } + if (this.props.icon) { + icon = ( +
    + +
    + ) + } + if (this.props.buttons) + buttons = ( +
    + {this.props.buttons} +
    + ) + return( +
    + {icon} +
    + {this.props.children} +
    + {buttons} + {status} +
    + ) + } +} diff --git a/src/leap/bitmask_js/app/components/main_panel/user_section.js b/src/leap/bitmask_js/app/components/main_panel/user_section.js new file mode 100644 index 00000000..0b4ba136 --- /dev/null +++ b/src/leap/bitmask_js/app/components/main_panel/user_section.js @@ -0,0 +1,71 @@ +import React from 'react' +import { Button, Glyphicon, Alert } from 'react-bootstrap' +import SectionLayout from './section_layout' +import Login from 'components/login' +import Spinner from 'components/spinner' +import Account from 'models/account' + +import bitmask from 'lib/bitmask' + +export default class UserSection extends React.Component { + + static get defaultProps() {return{ + account: null, + onLogout: null, + onLogin: null + }} + + constructor(props) { + super(props) + this.state = { + error: null, + loading: false + } + this.logout = this.logout.bind(this) + } + + logout() { + this.setState({loading: true}) + this.props.account.logout().then( + account => { + this.setState({error: null, loading: false}) + if (this.props.onLogout) { + this.props.onLogout(account) + } + }, error => { + this.setState({error: error, loading: false}) + } + ) + } + + render () { + let message = null + if (this.state.error) { + // style may be: success, warning, danger, info + message = ( + {this.state.error} + ) + } + + if (this.props.account.authenticated) { + let button = null + if (this.state.loading) { + button = + } else { + button = + } + return ( + +

    {this.props.account.address}

    + {message} +
    + ) + } else { + return ( + + + + ) + } + } +} diff --git a/src/leap/bitmask_js/app/components/main_panel/vpn_section.js b/src/leap/bitmask_js/app/components/main_panel/vpn_section.js new file mode 100644 index 00000000..e69de29b -- cgit v1.2.3