diff options
| -rw-r--r-- | www/README.md | 2 | ||||
| -rw-r--r-- | www/app/components/center.js | 23 | ||||
| -rw-r--r-- | www/app/components/login.js | 2 | ||||
| -rw-r--r-- | www/app/components/main_panel/email_section.js | 48 | ||||
| -rw-r--r-- | www/app/components/main_panel/index.js | 27 | ||||
| -rw-r--r-- | www/app/components/main_panel/main_panel.less | 60 | ||||
| -rw-r--r-- | www/app/components/panel_switcher.js | 4 | ||||
| -rw-r--r-- | www/app/components/spinner/spinner.css | 20 | ||||
| -rw-r--r-- | www/app/components/wizard/wizard.less | 8 | ||||
| -rw-r--r-- | www/app/css/common.css | 23 | ||||
| -rw-r--r-- | www/app/lib/bitmask.js | 3 | ||||
| -rw-r--r-- | www/app/main.js | 11 | ||||
| -rw-r--r-- | www/app/models/account.js | 67 | ||||
| -rw-r--r-- | www/app/models/dummy_account.js | 33 | ||||
| -rw-r--r-- | www/package.json | 1 | ||||
| -rw-r--r-- | www/webpack.config.js | 4 | 
16 files changed, 271 insertions, 65 deletions
| diff --git a/www/README.md b/www/README.md index f1d7c34..17c5042 100644 --- a/www/README.md +++ b/www/README.md @@ -64,6 +64,8 @@ way. We have enabled these plugins:  * babel-presets-stage-0: Allows the use of some ES7 proposals, even though    these are not standardized yet. Makes classes nicer. +* babel-polyfill: This is not part of the babel transpiling, but is distributed by babel. This polyfill will give you a full ES2015 environment even if the browser is missing some javascript features. We include this in the 'entry' option of the webpack config. https://babeljs.io/docs/usage/polyfill/ +  **react**  React is an efficient way to generate HTML views with Javascript. It allows you diff --git a/www/app/components/center.js b/www/app/components/center.js index a3b6409..6fa6212 100644 --- a/www/app/components/center.js +++ b/www/app/components/center.js @@ -4,22 +4,6 @@  import React from 'react' -const CONTAINER_CSS = { -  position: 'absolute', -  display: 'flex', -  justifyContent: 'center', -  alignContent: 'center', -  alignItems: 'center', -  top: "0px", -  left: "0px", -  height: "100%", -  width: "100%" -} - -const ITEM_CSS = { -  flex: "0 1 auto" -} -  class Center extends React.Component {    static get defaultProps() {return{ @@ -31,9 +15,12 @@ class Center extends React.Component {    }    render() { -    let style = this.props.width ? Object.assign({width: this.props.width + 'px'}, ITEM_CSS) : ITEM_CSS +    let style = null +    if (this.props.width) { +      style = {width: this.props.width + 'px'} +    }      return ( -      <div className="center-container" style={CONTAINER_CSS}> +      <div className="center-container">          <div className="center-item" style={style}>            {this.props.children}          </div> diff --git a/www/app/components/login.js b/www/app/components/login.js index 4f7b628..fe4ef5b 100644 --- a/www/app/components/login.js +++ b/www/app/components/login.js @@ -274,7 +274,7 @@ class Login extends React.Component {      if (!this.maySubmit()) { return }      this.setState({loading: true}) -    let account = new Account(this.state.username) +    let account = Account.find(this.state.username)      account.login(this.state.password).then(        account => {          this.setState({loading: false}) diff --git a/www/app/components/main_panel/email_section.js b/www/app/components/main_panel/email_section.js index e69de29..a6525d9 100644 --- a/www/app/components/main_panel/email_section.js +++ b/www/app/components/main_panel/email_section.js @@ -0,0 +1,48 @@ +import React from 'react' +//import { Button, Glyphicon, Alert } from 'react-bootstrap' +import SectionLayout from './section_layout' +import Account from 'models/account' +import Spinner from 'components/spinner' +import bitmask from 'lib/bitmask' + +export default class EmailSection extends React.Component { + +  static get defaultProps() {return{ +    account: null +  }} + +  constructor(props) { +    super(props) +    this.state = { +      status: null +    } +    this.openKeys  = this.openKeys.bind(this) +    this.openApp   = this.openApp.bind(this) +    this.openPrefs = this.openPrefs.bind(this) + +    console.log('email constructor') +  } + +  openKeys() {} +  openApp() {} +  openPrefs() {} + +  render () { +    //let message = null +    //if (this.state.error) { +    //  // style may be: success, warning, danger, info +    //  message = ( +    //    <Alert bsStyle="danger">{this.state.error}</Alert> +    //  ) +    //} +    let button = null +    if (this.state.status == 'ready') { +      button = <Button onClick={this.openApp}>Open Email</Button> +    } +    return ( +      <SectionLayout icon="envelope" status="on" button={button}> +        <h1>inbox: </h1> +      </SectionLayout> +    ) +  } +} diff --git a/www/app/components/main_panel/index.js b/www/app/components/main_panel/index.js index 910d58b..3cc6c11 100644 --- a/www/app/components/main_panel/index.js +++ b/www/app/components/main_panel/index.js @@ -7,10 +7,13 @@  import React from 'react'  import App from 'app'  import Login from 'components/login' +import Account from 'models/account' +import DummyAccount from 'models/dummy_account'  import './main_panel.less'  import AccountList from './account_list'  import UserSection from './user_section' +import EmailSection from './email_section'  export default class MainPanel extends React.Component { @@ -29,9 +32,12 @@ export default class MainPanel extends React.Component {    componentWillMount() {      if (this.props.initialAccount) { +      console.log(Account.list) +      Account.add(this.props.initialAccount) +      Account.add(new DummyAccount(this.props.initialAccount))        this.setState({          account: this.props.initialAccount, -        accounts: [this.props.initialAccount] +        accounts: Account.list        })      }    } @@ -39,16 +45,33 @@ export default class MainPanel extends React.Component {    activateAccount(account) {      this.setState({        account: account, -      accounts: [account] +      accounts: Account.list      })    } +  //setAccounts(accounts) { +  //  this.setState({ +  //    accounts: accounts +  //  }) +  //} +    render() { +    let emailSection = null +    let vpnSection = null + +    if (this.state.account.authenticated) { +      if (this.state.account.hasEmail) { +        emailSection = <EmailSection account={this.state.account} /> +      } +    } +      return (        <div className="main-panel">          <AccountList account={this.state.account} accounts={this.state.accounts} onSelect={this.activateAccount} />          <div className="body">            <UserSection account={this.state.account} onLogin={this.activateAccount} onLogout={this.activateAccount}/> +          {vpnSection} +          {emailSection}          </div>        </div>      ) diff --git a/www/app/components/main_panel/main_panel.less b/www/app/components/main_panel/main_panel.less index 3172bba..4e0ecb0 100644 --- a/www/app/components/main_panel/main_panel.less +++ b/www/app/components/main_panel/main_panel.less @@ -1,5 +1,6 @@  // The space around account entries:  @accounts-padding: 8px; +@accounts-corner: 6px;  @accounts-width: 200px;  // @@ -10,26 +11,26 @@    position: absolute;    height: 100%;    width: 100%; -  display: flex; -  flex-direction: row; +  display: -webkit-flex; +  -webkit-flex-direction: row;    > .body { -    flex: 1 1 auto; +    -webkit-flex: 1 1 auto;      overflow: auto;    }    .accounts { -    flex: 0 0 auto; +    -webkit-flex: 0 0 auto;      overflow-y: auto;      overflow-x: hidden; -    display: flex; -    flex-direction: column; +    display: -webkit-flex; +    -webkit-flex-direction: column;      ul { -      flex: 1 1 1000px; +      -webkit-flex: 1 1 1000px;      }      .btn-toolbar { -      flex: 0 0 auto; +      -webkit-flex: 0 0 auto;      }    } @@ -40,6 +41,7 @@  // Style  // +  .main-panel > .body {    padding: 20px;  } @@ -64,8 +66,8 @@    padding: 15px;    background-color: #444;    margin-bottom: @accounts-padding; -  border-top-left-radius: @accounts-padding; -  border-bottom-left-radius: @accounts-padding; +  border-top-left-radius: @accounts-corner - 1; +  border-bottom-left-radius: @accounts-corner - 1;    z-index: 100;  } @@ -98,8 +100,8 @@  .main-panel .accounts li.active span.arc {    display: block; -  height: @accounts-padding; -  width: @accounts-padding; +  height: @accounts-corner; +  width: @accounts-corner;    background-color: white;    position: absolute;    right: 0; @@ -107,11 +109,11 @@  .main-panel .accounts li.active span.arc.top {    top: 0; -  margin-top: -@accounts-padding; +  margin-top: -@accounts-corner;  }  .main-panel .accounts li.active span.arc.bottom {    bottom: 0; -  margin-bottom: -@accounts-padding; +  margin-bottom: -@accounts-corner;  }  .main-panel .accounts li.active span.arc:after {    display: block; @@ -119,23 +121,23 @@    border-radius: 100%;    height: 0px;    width: 0px; -  margin-left: -@accounts-padding; +  margin-left: -@accounts-corner;  }  .main-panel .accounts li.active span.arc.top:after { -  border: @accounts-padding solid transparent; -  border-right: @accounts-padding solid #333; -  margin-top: -@accounts-padding; +  border: @accounts-corner solid transparent; +  border-right: @accounts-corner solid #333; +  margin-top: -@accounts-corner; +  -webkit-transform: rotate(45deg);    transform: rotate(45deg);  }  .main-panel .accounts li.active span.arc.bottom:after { -  border: @accounts-padding solid #333; +  border: @accounts-corner solid #333;  }  .main-panel .accounts .btn.expander {     margin-right: @accounts-padding;  } -  //  // SECTIONS  // @@ -147,22 +149,23 @@  // service sections layout  .main-panel .service-section { -  display: flex; -  flex-direction: row; +  display: -webkit-flex; +  -webkit-flex-direction: row;    > .icon { -    flex: 0 0 auto; +    -webkit-flex: 0 0 auto;    }    > .body { -    flex: 1 1 auto; +    -webkit-flex: 1 1 auto;    }    > .buttons { -    flex: 0 0 auto; +    -webkit-flex: 0 0 auto;    }    > .status { -    flex: 0 0 auto; -    display: flex; -    align-items: center; +    -webkit-flex: 0 0 auto; +    display: -webkit-flex; +    -webkit-align-items: center;    } +  }  .main-panel .service-section div { @@ -175,6 +178,7 @@    background: #f6f6f6;    border-radius: 4px;    padding: 10px; +  margin-bottom: 10px;    &.wide-margin {      padding: 20px 20px 20px 10px; // arbitrary, looks nice    } diff --git a/www/app/components/panel_switcher.js b/www/app/components/panel_switcher.js index f4f32cf..aaf2dc5 100644 --- a/www/app/components/panel_switcher.js +++ b/www/app/components/panel_switcher.js @@ -53,4 +53,6 @@ export default class PanelSwitcher extends React.Component {    render_splash(props)  {return elem(Splash, props)}    render_wizard(props)  {return elem(Wizard, props)}    render_greeter(props) {return elem(GreeterPanel, props)} -  render_main(props)    {return elem(MainPanel, props)}} +  render_main(props)    {return elem(MainPanel, props)} + +} diff --git a/www/app/components/spinner/spinner.css b/www/app/components/spinner/spinner.css index 4e7f3ee..5e8535c 100644 --- a/www/app/components/spinner/spinner.css +++ b/www/app/components/spinner/spinner.css @@ -10,12 +10,28 @@    vertical-align: middle;    border-radius: 100%;    display: inline-block; +  -webkit-animation: bouncedelay 1.5s infinite ease-in-out;    animation: bouncedelay 1.5s infinite ease-in-out; +  -webkit-animation-fill-mode: both;    animation-fill-mode: both;  } -.spinner .spin1 { animation-delay: -.46s } -.spinner .spin2 { animation-delay: -.24s } +.spinner .spin1 { +  -webkit-animation-delay: -.46s; +  animation-delay: -.46s; +} +.spinner .spin2 { +  -webkit-animation-delay: -.24s; +  animation-delay: -.24s; +} + +@-webkit-keyframes bouncedelay { +  0%, 80%, 100% { +    -webkit-transform: scale(0.5); +  } 40% { +    -webkit-transform: scale(0.9); +  } +}  @keyframes bouncedelay {    0%, 80%, 100% { diff --git a/www/app/components/wizard/wizard.less b/www/app/components/wizard/wizard.less index 3336ffb..29efc20 100644 --- a/www/app/components/wizard/wizard.less +++ b/www/app/components/wizard/wizard.less @@ -3,12 +3,16 @@    height: 100%;    width: 100%; +  display: -webkit-flex;    display: flex; +  -webkit-flex-direction: column;    flex-direction: column; +  -webkit-flex: 1;    flex: 1;  }  .wizard .stage .footer { +  -webkit-flex: 0 0 auto;    flex: 0 0 auto;    background-color: #ddd;    padding: 20px; @@ -16,6 +20,7 @@  }  .wizard .stage .header { +  -webkit-flex: 0 0 auto;    flex: 0 0 auto;    padding: 20px;    background-color: #333; @@ -28,9 +33,12 @@  }  .wizard .stage .body { +  -webkit-flex: 1 1 auto;    flex: 1 1 auto;    padding: 20px;    overflow: auto; +  display: -webkit-flex;    display: flex; +  -webkit-flex-direction: column;    flex-direction: column;  }
\ No newline at end of file diff --git a/www/app/css/common.css b/www/app/css/common.css index 4b48010..acf164e 100644 --- a/www/app/css/common.css +++ b/www/app/css/common.css @@ -56,4 +56,25 @@ body {  /*.btn.btn-default {    background-color: #eee !important;  } -*/
\ No newline at end of file +*/ + +/* + * center component + */ + +.center-container { +  position: absolute; +  display: -webkit-flex; +  -webkit-flex-flow: row nowrap; +  -webkit-justify-content: center; +  -webkit-align-content: center; +  -webkit-align-items: center; +  top: 0px; +  left: 0px; +  height: 100%; +  width: 100%; +} + +.center-container .center-item { +  -webkit-flex: 0 1 auto; +} diff --git a/www/app/lib/bitmask.js b/www/app/lib/bitmask.js index 03b6c7b..af019b1 100644 --- a/www/app/lib/bitmask.js +++ b/www/app/lib/bitmask.js @@ -27,6 +27,9 @@   * finished or will fail if there was any error. Errors are always user readable   * strings.   */ + +import Promise from 'promise' +  var bitmask = function(){      var event_handlers = {}; diff --git a/www/app/main.js b/www/app/main.js index 0d712af..b162895 100644 --- a/www/app/main.js +++ b/www/app/main.js @@ -1,3 +1,9 @@ +// +// main entry point for app execution +// +// This is determined by the 'entry' option in webpack.config.js +// +  import React from 'react'  import ReactDOM from 'react-dom' @@ -9,9 +15,6 @@ class Main extends React.Component {      return React.createElement(PanelSwitcher)    } -  // -  // main entry point for app execution -  //    componentDidMount() {      App.start()    } @@ -20,4 +23,4 @@ class Main extends React.Component {  ReactDOM.render(    React.createElement(Main),    document.getElementById('app') -)
\ No newline at end of file +) diff --git a/www/app/models/account.js b/www/app/models/account.js index 367961b..fa3b981 100644 --- a/www/app/models/account.js +++ b/www/app/models/account.js @@ -8,11 +8,7 @@ import bitmask from 'lib/bitmask'  export default class Account {    constructor(address, props={}) { -    if (!address.match('@')) { -      this._address = '@' + address -    } else { -      this._address = address -    } +    this.address = address      this._authenticated = props.authenticated    } @@ -34,6 +30,14 @@ export default class Account {      return this._address    } +  set address(address) { +    if (!address.match('@')) { +      this._address = '@' + address +    } else { +      this._address = address +    } +  } +    get userpart() {      return this._address.split('@')[0]    } @@ -42,6 +46,10 @@ export default class Account {      return this._authenticated    } +  get hasEmail() { +    return true +  } +    //    // returns a promise, fulfill is passed account object    // @@ -71,6 +79,33 @@ export default class Account {    }    // +  // returns the matching account in the list of accounts, or adds it +  // if it is not already present. +  // +  static find(address) { +    // search by full address +    let account = Account.list.find(i => { +      return i.address == address +    }) +    // failing that, search by domain +    if (!account) { +      let domain = '@' + address.split('@')[1] +      account = Account.list.find(i => { +        return i.address == domain +      }) +      if (account) { +        account.address = address +      } +    } +    // failing that, create new account +    if (!account) { +      account = new Account(address) +      Account.list.push(account) +    } +    return account +  } + +  //    // returns a promise, fullfill is passed account object    //    static active() { @@ -85,4 +120,24 @@ export default class Account {      )    } -}
\ No newline at end of file +  static add(account) { +    if (!Account.list.find(i => {return i.id == account.id})) { +      Account.list.push(account) +    } +  } + +  static remove(account) { +    Account.list = Account.list.filter(i => { +      return i.id != account.id +    }) +  } +  //   return Account.list +  //   return new Promise(function(resolve, reject) { +  //     window.setTimeout(function() { +  //       resolve(['@blah', '@lala']) +  //     }, 1000) +  //   }) +  // } +} + +Account.list = []
\ No newline at end of file diff --git a/www/app/models/dummy_account.js b/www/app/models/dummy_account.js new file mode 100644 index 0000000..bf0391b --- /dev/null +++ b/www/app/models/dummy_account.js @@ -0,0 +1,33 @@ +// +// A proxy of an account, but with a different ID. For testing. +// + +import bitmask from 'lib/bitmask' + +export default class DummyAccount { + +  constructor(account) { +    this.account = account +  } + +  get id() { +    return 'dummy--' + this.account.address +  } + +  get domain() {return this.account.domain} +  get address() {return this.account.address} +  get userpart() {return this.account.userpart} +  get authenticated() {return this.account.authenticated} +  get hasEmail() {return this.account.hasEmail} +  login(password) {return this.account.login(password)} + +  logout() { +    return bitmask.user.logout(this.address).then( +      response => { +        this._authenticated = false +        this._address = '@' + this.domain +        return this +      } +    ) +  } +} diff --git a/www/package.json b/www/package.json index 128a9e7..d491edd 100644 --- a/www/package.json +++ b/www/package.json @@ -9,6 +9,7 @@    "devDependencies": {      "babel": "^6.5.2",      "babel-loader": "^6.2.4", +    "babel-polyfill": "^6.13.0",      "babel-preset-es2015": "^6.9.0",      "babel-preset-react": "^6.11.1",      "babel-preset-stage-0": "^6.5.0", diff --git a/www/webpack.config.js b/www/webpack.config.js index 7b46e1b..a29e575 100644 --- a/www/webpack.config.js +++ b/www/webpack.config.js @@ -4,7 +4,7 @@ var CopyWebpackPlugin = require('copy-webpack-plugin');  var config = {    context: path.join(__dirname, 'app'), -  entry: './main.js', +  entry: ['babel-polyfill', './main.js'],    output: {      path: path.join(__dirname, 'public'),      filename: 'app.bundle.js' @@ -47,7 +47,7 @@ var config = {        { from: 'img/*'},        { from: 'index.html' },        { from: '../node_modules/bootstrap/dist/css/bootstrap.min.css', to: 'css' }, -      { from: '../node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff2', to: 'fonts' }, +      { from: '../node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.woff', to: 'fonts' },        { from: '../node_modules/zxcvbn/dist/zxcvbn.js', to: 'js' }      ])    ], | 
