Commit 14170274 authored by elijah's avatar elijah
Browse files

webkit support: get the js and css working in older webkit engines

parent ec52670d
......@@ -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
......
......@@ -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>
......
......@@ -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})
......
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>
)
}
}
......@@ -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>
)
......
// 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
}
......
......@@ -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)}
}
......@@ -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% {
......
......@@ -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
......@@ -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;
}
......@@ -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 = {};
......
//
// 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
)
......@@ -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
//
......@@ -70,6 +78,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
//
......@@ -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
//
// 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
}
)
}
}
......@@ -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",
......
......@@ -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' },