1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-14 10:16:26 +00:00

Compare commits

...

13 Commits
0.2.2 ... 0.2.5

Author SHA1 Message Date
Rokt33r
85f833c865 Merge branch 'dev'
* dev:
  v0.2.5 - bugfix - Alert message added(Private planet/Team member)

Conflicts:
	package.json
2015-08-24 13:46:32 +09:00
Rokt33r
15133d00c7 v0.2.5
- bugfix
- Alert message added(Private planet/Team member)
2015-08-24 13:45:28 +09:00
Rokt33r
b93990d10b bump version 2015-08-24 06:23:41 +09:00
Rokt33r
a0bcb8edbe Merge branch 'dev'
* dev:
  実装 - MemberがOwnerではないときにTeam設定ボターンを全部隠す
  v0.2.4 - Minor fix
  fix minor bug
2015-08-24 06:22:32 +09:00
Rokt33r
bfdf691bed 実装 - MemberがOwnerではないときにTeam設定ボターンを全部隠す 2015-08-24 06:22:16 +09:00
Rokt33r
f60856b998 v0.2.4 - Minor fix 2015-08-24 06:14:13 +09:00
Rokt33r
3308eeaf82 fix minor bug 2015-08-23 04:00:18 +09:00
Rokt33r
19930a2472 fix minor bug 2015-08-23 03:49:19 +09:00
Rokt33r
e75d95b1fc Merge branch 'dev'
* dev:
  実装 - PlanetArticleListへのAuto scroll追加
  実装 - tooltip (Refresh, Planet setting, Planet refresh, Edit article, Delete article, Contact)
  #14 改善適用 - アプリが立ち上がったら最初はmy planetが表示されるようにしたい - Noteがスクロールできない - Note行間がなくて読みづらい
  実装 - Hotkey
2015-08-23 03:42:40 +09:00
Rokt33r
4319711dc6 実装 - PlanetArticleListへのAuto scroll追加 2015-08-23 03:42:00 +09:00
Rokt33r
9712be909d 実装 - tooltip (Refresh, Planet setting, Planet refresh, Edit article, Delete article, Contact) 2015-08-23 03:05:30 +09:00
Rokt33r
04060ce252 #14 改善適用
- アプリが立ち上がったら最初はmy planetが表示されるようにしたい
- Noteがスクロールできない
- Note行間がなくて読みづらい
2015-08-23 00:52:03 +09:00
Rokt33r
da066fe694 実装 - Hotkey 2015-08-22 23:57:37 +09:00
38 changed files with 601 additions and 181 deletions

View File

@@ -4,12 +4,20 @@ var version = remote.getGlobal('version')
var React = require('react/addons') var React = require('react/addons')
var ExternalLink = require('../Mixins/ExternalLink') var ExternalLink = require('../Mixins/ExternalLink')
var KeyCaster = require('../Mixins/KeyCaster')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [ExternalLink], mixins: [ExternalLink, KeyCaster('aboutModal')],
propTypes: { propTypes: {
close: React.PropTypes.func close: React.PropTypes.func
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
render: function () { render: function () {
return ( return (
<div className='AboutModal modal'> <div className='AboutModal modal'>

View File

@@ -5,6 +5,8 @@ var LinkedState = require('../Mixins/LinkedState')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
var getOptions = function (input, callback) { var getOptions = function (input, callback) {
@@ -26,7 +28,7 @@ var getOptions = function (input, callback) {
} }
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('addMemberModal')],
propTypes: { propTypes: {
team: React.PropTypes.object, team: React.PropTypes.object,
close: React.PropTypes.func close: React.PropTypes.func
@@ -37,7 +39,18 @@ module.exports = React.createClass({
role: 'member' role: 'member'
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitAddMemberModal':
this.handleSubmit()
break
}
},
handleSubmit: function () { handleSubmit: function () {
this.setState({errorMessage: null}, function () {
Hq Hq
.addMember(this.props.team.name, { .addMember(this.props.team.name, {
userName: this.state.userName, userName: this.state.userName,
@@ -50,6 +63,10 @@ module.exports = React.createClass({
}.bind(this)) }.bind(this))
.catch(function (err) { .catch(function (err) {
console.error(err) console.error(err)
if (err.status === 403) {
this.setState({errorMessage: err.response.body.message})
}
}.bind(this))
}) })
}, },
handleChange: function (value) { handleChange: function (value) {
@@ -76,6 +93,8 @@ module.exports = React.createClass({
role role
</div> </div>
{this.state.errorMessage != null ? (<p className='errorAlert'>{this.state.errorMessage}</p>) : null}
<button onClick={this.handleSubmit} className='submitButton'><i className='fa fa-check'/></button> <button onClick={this.handleSubmit} className='submitButton'><i className='fa fa-check'/></button>
</div> </div>
) )

View File

@@ -2,19 +2,26 @@ var React = require('react')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [KeyCaster('codeDeleteModal')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
code: React.PropTypes.object, code: React.PropTypes.object,
close: React.PropTypes.func close: React.PropTypes.func
}, },
componentDidMount: function () { onKeyCast: function (e) {
React.findDOMNode(this).focus() switch (e.status) {
}, case 'submitCodeDeleteModal':
stopPropagation: function (e) { this.submit()
e.stopPropagation() break
case 'closeModal':
this.props.close()
break
}
}, },
submit: function () { submit: function () {
var planet = this.props.planet var planet = this.props.planet

View File

@@ -7,13 +7,19 @@ module.exports = React.createClass({
code: React.PropTypes.object, code: React.PropTypes.object,
planet: React.PropTypes.object planet: React.PropTypes.object
}, },
componentDidMount: function () {
// TODO: Hacked!! should fix later
setTimeout(function () {
React.findDOMNode(this.refs.form.refs.description).focus()
}.bind(this), 1)
},
render: function () { render: function () {
return ( return (
<div className='CodeEditModal modal'> <div className='CodeEditModal modal'>
<div className='modal-header'> <div className='modal-header'>
<h1>Edit Code</h1> <h1>Edit Code</h1>
</div> </div>
<CodeForm code={this.props.code} planet={this.props.planet} close={this.props.close}/> <CodeForm ref='form' code={this.props.code} planet={this.props.planet} close={this.props.close}/>
</div> </div>
) )
} }

View File

@@ -6,6 +6,7 @@ module.exports = React.createClass({
propTypes: { propTypes: {
code: React.PropTypes.string, code: React.PropTypes.string,
mode: React.PropTypes.string, mode: React.PropTypes.string,
className: React.PropTypes.string,
onChange: React.PropTypes.func onChange: React.PropTypes.func
}, },
componentDidMount: function () { componentDidMount: function () {
@@ -52,7 +53,7 @@ module.exports = React.createClass({
}, },
render: function () { render: function () {
return ( return (
<div ref='target'></div> <div ref='target' className={this.props.className}></div>
) )
} }
}) })

View File

@@ -5,6 +5,7 @@ var Select = require('react-select')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
@@ -29,7 +30,7 @@ var getOptions = function (input, callback) {
} }
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('codeForm')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
close: React.PropTypes.func, close: React.PropTypes.func,
@@ -55,6 +56,16 @@ module.exports = React.createClass({
code: code code: code
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'submitCodeForm':
this.submit()
break
case 'closeModal':
this.props.close()
break
}
},
handleModeChange: function (selected) { handleModeChange: function (selected) {
var code = this.state.code var code = this.state.code
code.mode = selected code.mode = selected

View File

@@ -5,7 +5,8 @@ var ace = window.ace
module.exports = React.createClass({ module.exports = React.createClass({
propTypes: { propTypes: {
code: React.PropTypes.string, code: React.PropTypes.string,
mode: React.PropTypes.string mode: React.PropTypes.string,
className: React.PropTypes.string
}, },
componentDidMount: function () { componentDidMount: function () {
var el = React.findDOMNode(this.refs.target) var el = React.findDOMNode(this.refs.target)
@@ -46,7 +47,7 @@ module.exports = React.createClass({
}, },
render: function () { render: function () {
return ( return (
<div ref='target'></div> <div ref='target' className={this.props.className}></div>
) )
} }
}) })

View File

@@ -1,11 +1,12 @@
var React = require('react') var React = require('react')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('contactModal')],
propTypes: { propTypes: {
close: React.PropTypes.func close: React.PropTypes.func
}, },
@@ -18,6 +19,23 @@ module.exports = React.createClass({
} }
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitContactModal':
if (this.state.isSent) {
this.props.close()
return
}
this.sendEmail()
break
}
},
componentDidMount: function () {
React.findDOMNode(this.refs.title).focus()
},
sendEmail: function () { sendEmail: function () {
Hq.sendEmail(this.state.mail) Hq.sendEmail(this.state.mail)
.then(function (res) { .then(function (res) {
@@ -36,7 +54,7 @@ module.exports = React.createClass({
<div className='contactForm'> <div className='contactForm'>
<div className='modal-body'> <div className='modal-body'>
<div className='formField'> <div className='formField'>
<input valueLink={this.linkState('mail.title')} placeholder='Title'/> <input ref='title' valueLink={this.linkState('mail.title')} placeholder='Title'/>
</div> </div>
<div className='formField'> <div className='formField'>
<textarea valueLink={this.linkState('mail.content')} placeholder='Content'/> <textarea valueLink={this.linkState('mail.content')} placeholder='Content'/>

View File

@@ -5,17 +5,19 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('editProfileModal')],
propTypes: { propTypes: {
user: React.PropTypes.shape({ user: React.PropTypes.shape({
name: React.PropTypes.string, name: React.PropTypes.string,
profileName: React.PropTypes.string, profileName: React.PropTypes.string,
email: React.PropTypes.string email: React.PropTypes.string
}) }),
close: React.PropTypes.func
}, },
getInitialState: function () { getInitialState: function () {
var user = this.props.user var user = this.props.user
@@ -34,6 +36,13 @@ module.exports = React.createClass({
passwordSubmitStatus: null passwordSubmitStatus: null
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
selectTab: function (tabName) { selectTab: function (tabName) {
return function () { return function () {
this.setState({currentTab: tabName}) this.setState({currentTab: tabName})

View File

@@ -71,16 +71,6 @@ module.exports = React.createClass({
openPlanetCreateModal: function () { openPlanetCreateModal: function () {
this.openModal(PlanetCreateModal, {transitionTo: this.transitionTo}) this.openModal(PlanetCreateModal, {transitionTo: this.transitionTo})
}, },
handleKeyDown: function (e) {
if (this.state.currentUser == null) return
if (e.metaKey && e.keyCode > 48 && e.keyCode < 58) {
var planet = this.state.currentUser.Planets[e.keyCode - 49]
if (planet != null) {
this.transitionTo('planet', {userName: planet.userName, planetName: planet.name})
}
e.preventDefault()
}
},
toggleProfilePopup: function () { toggleProfilePopup: function () {
this.openProfilePopup() this.openProfilePopup()
}, },
@@ -96,6 +86,10 @@ module.exports = React.createClass({
handleLogoutClick: function () { handleLogoutClick: function () {
this.openModal(LogoutModal, {transitionTo: this.transitionTo}) this.openModal(LogoutModal, {transitionTo: this.transitionTo})
}, },
switchPlanetByIndex: function (index) {
var planetProps = this.refs.planets.props.children[index - 1].props
this.transitionTo('planet', {userName: planetProps.userName, planetName: planetProps.planetName})
},
render: function () { render: function () {
var params = this.getParams() var params = this.getParams()
@@ -110,12 +104,12 @@ module.exports = React.createClass({
return team.Planets == null ? planets : planets.concat(team.Planets) return team.Planets == null ? planets : planets.concat(team.Planets)
}, []))).map(function (planet, index) { }, []))).map(function (planet, index) {
return ( return (
<li key={planet.id} className={params.userName === planet.userName && params.planetName === planet.name ? 'active' : ''}> <li userName={planet.userName} planetName={planet.name} key={planet.id} className={params.userName === planet.userName && params.planetName === planet.name ? 'active' : ''}>
<Link to='planet' params={{userName: planet.userName, planetName: planet.name}}> <Link to='planet' params={{userName: planet.userName, planetName: planet.name}}>
{planet.name[0]} {planet.name[0]}
<div className='planetTooltip'>{planet.userName}/{planet.name}</div> <div className='planetTooltip'>{planet.userName}/{planet.name}</div>
</Link> </Link>
<div className='shortCut'>{index + 1}</div> {index < 9 ? (<div className='shortCut'>{index + 1}</div>) : null}
</li> </li>
) )
}) })
@@ -128,12 +122,12 @@ module.exports = React.createClass({
<ProfileImage size='55' email={this.state.currentUser.email}/> <ProfileImage size='55' email={this.state.currentUser.email}/>
</button> </button>
{popup} {popup}
<ul className='planetList'> <ul ref='planets' className='planetList'>
{planets} {planets}
</ul> </ul>
<button onClick={this.openPlanetCreateModal} className='newPlanet'> <button onClick={this.openPlanetCreateModal} className='newPlanet'>
<i className='fa fa-plus'/> <i className='fa fa-plus'/>
<div className='newPlanetTooltip'>Create new planet</div> <div className='tooltip'>Create new planet</div>
</button> </button>
</div> </div>
) )

View File

@@ -15,34 +15,52 @@ module.exports = React.createClass({
} }
}, },
componentDidMount: function () { componentDidMount: function () {
var codeButton = React.findDOMNode(this.refs.codeButton)
codeButton.addEventListener('keydown', this.handleKeyDown)
React.findDOMNode(this.refs.noteButton).addEventListener('keydown', this.handleKeyDown)
codeButton.focus()
}, },
stopPropagation: function (e) { componentWillUnmount: function () {
e.stopPropagation() React.findDOMNode(this.refs.codeButton).removeEventListener('keydown', this.handleKeyDown)
}, React.findDOMNode(this.refs.noteButton).removeEventListener('keydown', this.handleKeyDown)
selectCodeTab: function () {
this.setState({currentTab: 'code'})
},
selectNoteTab: function () {
this.setState({currentTab: 'note'})
}, },
handleKeyDown: function (e) { handleKeyDown: function (e) {
if (e.keyCode === 37 && e.metaKey) { if (e.keyCode === 37 && e.metaKey) {
this.selectCodeTab() this.selectCodeTab()
e.stopPropagation()
return
} }
if (e.keyCode === 39 && e.metaKey) { if (e.keyCode === 39 && e.metaKey) {
this.selectNoteTab() this.selectNoteTab()
e.stopPropagation()
return
} }
if (e.keyCode === 9) {
if (this.state.currentTab === 'code') React.findDOMNode(this.refs.form.refs.description).focus()
else React.findDOMNode(this.refs.form.refs.title).focus()
e.preventDefault()
}
},
selectCodeTab: function () {
this.setState({currentTab: 'code'}, function () {
React.findDOMNode(this.refs.codeButton).focus()
})
},
selectNoteTab: function () {
this.setState({currentTab: 'note'}, function () {
React.findDOMNode(this.refs.noteButton).focus()
})
}, },
render: function () { render: function () {
var modalBody var modalBody
if (this.state.currentTab === 'code') { if (this.state.currentTab === 'code') {
modalBody = ( modalBody = (
<CodeForm planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/> <CodeForm ref='form' planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/>
) )
} else { } else {
modalBody = ( modalBody = (
<NoteForm planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/> <NoteForm ref='form' planet={this.props.planet} transitionTo={this.props.transitionTo} close={this.props.close}/>
) )
} }
@@ -50,7 +68,8 @@ module.exports = React.createClass({
<div className='LaunchModal modal'> <div className='LaunchModal modal'>
<div className='modal-header'> <div className='modal-header'>
<div className='modal-tab'> <div className='modal-tab'>
<button className={this.state.currentTab === 'code' ? 'btn-primary active' : 'btn-default'} onClick={this.selectCodeTab}>Code</button><button className={this.state.currentTab === 'note' ? 'btn-primary active' : 'btn-default'} onClick={this.selectNoteTab}>Note</button> <button ref='codeButton' className={this.state.currentTab === 'code' ? 'btn-primary active' : 'btn-default'} onClick={this.selectCodeTab}>Code</button>
<button ref='noteButton' className={this.state.currentTab === 'note' ? 'btn-primary active' : 'btn-default'} onClick={this.selectNoteTab}>Note</button>
</div> </div>
</div> </div>
{modalBody} {modalBody}

View File

@@ -2,11 +2,24 @@
var React = require('react') var React = require('react')
var KeyCaster = require('../Mixins/KeyCaster')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [KeyCaster('logoutModal')],
propTypes: { propTypes: {
transitionTo: React.PropTypes.func, transitionTo: React.PropTypes.func,
close: React.PropTypes.func close: React.PropTypes.func
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitLogoutModal':
this.logout()
break
}
},
logout: function () { logout: function () {
localStorage.removeItem('currentUser') localStorage.removeItem('currentUser')
localStorage.removeItem('token') localStorage.removeItem('token')

View File

@@ -2,16 +2,26 @@ var React = require('react')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [KeyCaster('noteDeleteModal')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
note: React.PropTypes.object, note: React.PropTypes.object,
close: React.PropTypes.func close: React.PropTypes.func
}, },
componentDidMount: function () { onKeyCast: function (e) {
React.findDOMNode(this).focus() switch (e.status) {
case 'submitNoteDeleteModal':
this.submit()
break
case 'closeModal':
this.props.close()
break
}
}, },
submit: function () { submit: function () {
var planet = this.props.planet var planet = this.props.planet

View File

@@ -8,13 +8,19 @@ module.exports = React.createClass({
note: React.PropTypes.object, note: React.PropTypes.object,
planet: React.PropTypes.object planet: React.PropTypes.object
}, },
componentDidMount: function () {
// TODO: Hacked!! should fix later
setTimeout(function () {
React.findDOMNode(this.refs.form.refs.title).focus()
}.bind(this), 1)
},
render: function () { render: function () {
return ( return (
<div className='NoteEditModal modal'> <div className='NoteEditModal modal'>
<div className='modal-header'> <div className='modal-header'>
<h1>Edit Note</h1> <h1>Edit Note</h1>
</div> </div>
<NoteForm note={this.props.note} planet={this.props.planet} close={this.props.close}/> <NoteForm ref='form' note={this.props.note} planet={this.props.planet} close={this.props.close}/>
</div> </div>
) )
} }

View File

@@ -1,11 +1,11 @@
var React = require('react/addons') var React = require('react/addons')
var ReactRouter = require('react-router')
var Select = require('react-select') var Select = require('react-select')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var Markdown = require('../Mixins/Markdown') var Markdown = require('../Mixins/Markdown')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
@@ -34,7 +34,7 @@ var EDIT_MODE = 0
var PREVIEW_MODE = 1 var PREVIEW_MODE = 1
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState, Markdown], mixins: [LinkedState, Markdown, KeyCaster('noteForm')],
propTypes: { propTypes: {
planet: React.PropTypes.object, planet: React.PropTypes.object,
close: React.PropTypes.func, close: React.PropTypes.func,
@@ -58,8 +58,15 @@ module.exports = React.createClass({
mode: EDIT_MODE mode: EDIT_MODE
} }
}, },
componentDidMount: function () { onKeyCast: function (e) {
React.findDOMNode(this.refs.title).focus() switch (e.status) {
case 'submitNoteForm':
this.submit()
break
case 'closeModal':
this.props.close()
break
}
}, },
handleTagsChange: function (selected, all) { handleTagsChange: function (selected, all) {
var note = this.state.note var note = this.state.note

View File

@@ -25,6 +25,7 @@ module.exports = React.createClass({
} }
}, },
openEditModal: function () { openEditModal: function () {
if (this.props.article == null) return
switch (this.props.article.type) { switch (this.props.article.type) {
case 'code' : case 'code' :
this.openModal(CodeEditModal, {code: this.props.article, planet: this.props.planet}) this.openModal(CodeEditModal, {code: this.props.article, planet: this.props.planet})
@@ -34,6 +35,7 @@ module.exports = React.createClass({
} }
}, },
openDeleteModal: function () { openDeleteModal: function () {
if (this.props.article == null) return
switch (this.props.article.type) { switch (this.props.article.type) {
case 'code' : case 'code' :
this.openModal(CodeDeleteModal, {code: this.props.article, planet: this.props.planet}) this.openModal(CodeDeleteModal, {code: this.props.article, planet: this.props.planet})
@@ -74,14 +76,18 @@ module.exports = React.createClass({
</div> </div>
<span className='itemControl'> <span className='itemControl'>
<button onClick={this.openEditModal} className='btn-default btn-square btn-sm'><i className='fa fa-edit fa-fw'></i></button> <button id='articleEditButton' onClick={this.openEditModal} className='editButton'>
<button onClick={this.openDeleteModal} className='btn-default btn-square btn-sm'><i className='fa fa-trash fa-fw'></i></button> <i className='fa fa-edit fa-fw'></i>
<div className='tooltip'>Edit</div>
</button>
<button onClick={this.openDeleteModal} className='deleteButton'>
<i className='fa fa-trash fa-fw'></i>
<div className='tooltip'>Delete</div>
</button>
</span> </span>
</div> </div>
<div className='detailBody'> <div className='detailBody'>
<div className='content'> <CodeViewer className='content' code={article.content} mode={article.mode}/>
<CodeViewer code={article.content} mode={article.mode}/>
</div>
</div> </div>
</div> </div>
) )
@@ -101,8 +107,14 @@ module.exports = React.createClass({
</div> </div>
<span className='itemControl'> <span className='itemControl'>
<button onClick={this.openEditModal} className='btn-default btn-square btn-sm'><i className='fa fa-edit fa-fw'></i></button> <button id='articleEditButton' onClick={this.openEditModal} className='editButton'>
<button onClick={this.openDeleteModal} className='btn-default btn-square btn-sm'><i className='fa fa-trash fa-fw'></i></button> <i className='fa fa-edit fa-fw'></i>
<div className='tooltip'>Edit</div>
</button>
<button onClick={this.openDeleteModal} className='deleteButton'>
<i className='fa fa-trash fa-fw'></i>
<div className='tooltip'>Delete</div>
</button>
</span> </span>
</div> </div>
<div className='detailBody'> <div className='detailBody'>

View File

@@ -1,6 +1,5 @@
var React = require('react/addons') var React = require('react/addons')
var ReactRouter = require('react-router') var ReactRouter = require('react-router')
var Link = ReactRouter.Link
var moment = require('moment') var moment = require('moment')
var ForceUpdate = require('../Mixins/ForceUpdate') var ForceUpdate = require('../Mixins/ForceUpdate')
@@ -16,9 +15,10 @@ module.exports = React.createClass({
}, },
handleArticleClikck: function (article) { handleArticleClikck: function (article) {
if (article.type === 'code') { if (article.type === 'code') {
return function () { return function (e) {
var params = this.getParams() var params = this.getParams()
document.getElementById('articleEditButton').focus()
this.transitionTo('codes', { this.transitionTo('codes', {
userName: params.userName, userName: params.userName,
planetName: params.planetName, planetName: params.planetName,
@@ -28,9 +28,10 @@ module.exports = React.createClass({
} }
if (article.type === 'note') { if (article.type === 'note') {
return function () { return function (e) {
var params = this.getParams() var params = this.getParams()
document.getElementById('articleEditButton').focus()
this.transitionTo('notes', { this.transitionTo('notes', {
userName: params.userName, userName: params.userName,
planetName: params.planetName, planetName: params.planetName,
@@ -51,8 +52,6 @@ module.exports = React.createClass({
var params = this.getParams() var params = this.getParams()
var isActive = article.type === 'code' ? this.isActive('codes') && parseInt(params.localId, 10) === article.localId : this.isActive('notes') && parseInt(params.localId, 10) === article.localId var isActive = article.type === 'code' ? this.isActive('codes') && parseInt(params.localId, 10) === article.localId : this.isActive('notes') && parseInt(params.localId, 10) === article.localId
var handleClick
if (article.type === 'code') { if (article.type === 'code') {
return ( return (
<li onClick={this.handleArticleClikck(article)} key={'code-' + article.id}> <li onClick={this.handleArticleClikck(article)} key={'code-' + article.id}>
@@ -94,7 +93,7 @@ module.exports = React.createClass({
return ( return (
<div className='PlanetArticleList'> <div className='PlanetArticleList'>
<ul> <ul ref='articles'>
{articles} {articles}
</ul> </ul>
</div> </div>

View File

@@ -5,11 +5,12 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('planetCreateModal')],
propTypes: { propTypes: {
ownerName: React.PropTypes.string, ownerName: React.PropTypes.string,
transitionTo: React.PropTypes.func, transitionTo: React.PropTypes.func,
@@ -30,12 +31,18 @@ module.exports = React.createClass({
componentDidMount: function () { componentDidMount: function () {
React.findDOMNode(this.refs.name).focus() React.findDOMNode(this.refs.name).focus()
}, },
onListen: function (res) { onKeyCast: function (e) {
if (res.status === 'planetCreated') { switch (e.status) {
case 'closeModal':
this.props.close() this.props.close()
break
case 'submitPlanetCreateModal':
this.handleSubmit()
break
} }
}, },
handleSubmit: function () { handleSubmit: function () {
this.setState({errorMessage: null}, function () {
Hq.createPlanet(this.state.ownerName, this.state.planet) Hq.createPlanet(this.state.ownerName, this.state.planet)
.then(function (res) { .then(function (res) {
var planet = res.body var planet = res.body
@@ -50,6 +57,10 @@ module.exports = React.createClass({
}.bind(this)) }.bind(this))
.catch(function (err) { .catch(function (err) {
console.error(err) console.error(err)
if (err.status === 403) {
this.setState({errorMessage: err.response.body.message})
}
}.bind(this))
}) })
}, },
render: function () { render: function () {
@@ -75,6 +86,8 @@ module.exports = React.createClass({
</select> </select>
</div> </div>
{this.state.errorMessage != null ? (<p className='errorAlert'>{this.state.errorMessage}</p>) : null}
<button onClick={this.handleSubmit} className='submitButton'> <button onClick={this.handleSubmit} className='submitButton'>
<i className='fa fa-check'/> <i className='fa fa-check'/>
</button> </button>

View File

@@ -21,7 +21,22 @@ module.exports = React.createClass({
} }
}, },
componentDidMount: function () { componentDidMount: function () {
React.findDOMNode(this.refs.search).focus() var search = React.findDOMNode(this.refs.search)
search.addEventListener('keydown', this.handleSearchKeyDown)
},
componentWillUnmount: function () {
var search = React.findDOMNode(this.refs.search)
search.removeEventListener('keydown', this.handleSearchKeyDown)
},
handleSearchKeyDown: function (e) {
if (e.keyCode === 38 || e.keyCode === 40) {
var search = React.findDOMNode(this.refs.search)
search.blur()
e.preventDefault()
}
if (e.keyCode !== 27 && (e.keyCode !== 13 || !e.metaKey)) {
e.stopPropagation()
}
}, },
openPlanetSettingModal: function () { openPlanetSettingModal: function () {
this.openModal(PlanetSettingModal, {planet: this.props.currentPlanet}) this.openModal(PlanetSettingModal, {planet: this.props.currentPlanet})
@@ -42,12 +57,13 @@ module.exports = React.createClass({
{this.props.currentPlanet.public ? null : ( {this.props.currentPlanet.public ? null : (
<div className='private'> <div className='private'>
<i className='fa fa-lock'/> <i className='fa fa-lock'/>
<div className='privateTooltip'>Private planet</div> <div className='tooltip'>Private planet</div>
</div> </div>
)} )}
<button onClick={this.openPlanetSettingModal} className='menuBtn'> <button onClick={this.openPlanetSettingModal} className='planetSettingButton'>
<i className='fa fa-chevron-down'></i> <i className='fa fa-chevron-down'></i>
<div className='tooltip'>Planet setting</div>
</button> </button>
</div> </div>
<div className='headerControl'> <div className='headerControl'>
@@ -55,9 +71,13 @@ module.exports = React.createClass({
<i className='fa fa-search'/> <i className='fa fa-search'/>
<input onChange={this.props.onSearchChange} value={this.props.search} ref='search' type='text' className='inline-input circleInput' placeholder='Search...'/> <input onChange={this.props.onSearchChange} value={this.props.search} ref='search' type='text' className='inline-input circleInput' placeholder='Search...'/>
</div> </div>
<button onClick={this.refresh} className='refreshButton'><i className='fa fa-refresh'/></button> <button onClick={this.refresh} className='refreshButton'>
<i className='fa fa-refresh'/>
<div className='tooltip'>Refresh planet</div>
</button>
<a onClick={this.openExternal} href='http://b00st.io' className='logo'> <a onClick={this.openExternal} href='http://b00st.io' className='logo'>
<img width='44' height='44' src='resources/favicon-230x230.png'/> <img width='44' height='44' src='resources/favicon-230x230.png'/>
<div className='tooltip'>Boost official page</div>
</a> </a>
</div> </div>
</div> </div>

View File

@@ -3,9 +3,10 @@ var ReactRouter = require('react-router')
var Navigation = ReactRouter.Navigation var Navigation = ReactRouter.Navigation
var Modal = require('../Mixins/Modal') var Modal = require('../Mixins/Modal')
var LaunchModal = require('../Components/LaunchModal') var LaunchModal = require('../Components/LaunchModal')
var PlanetNavigator = React.createClass({ module.exports = React.createClass({
mixins: [Modal, Navigation], mixins: [Modal, Navigation],
propTypes: { propTypes: {
planet: React.PropTypes.shape({ planet: React.PropTypes.shape({
@@ -20,9 +21,6 @@ var PlanetNavigator = React.createClass({
isLaunchModalOpen: false isLaunchModalOpen: false
} }
}, },
submitLaunchModal: function (ret) {
this.setState({isLaunchModalOpen: false})
},
openLaunchModal: function () { openLaunchModal: function () {
this.openModal(LaunchModal, {planet: this.props.planet, transitionTo: this.transitionTo}) this.openModal(LaunchModal, {planet: this.props.planet, transitionTo: this.transitionTo})
}, },
@@ -54,5 +52,3 @@ var PlanetNavigator = React.createClass({
) )
} }
}) })
module.exports = PlanetNavigator

View File

@@ -3,11 +3,12 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('planetSettingModal')],
propTypes: { propTypes: {
close: React.PropTypes.func, close: React.PropTypes.func,
planet: React.PropTypes.shape({ planet: React.PropTypes.shape({
@@ -35,6 +36,13 @@ module.exports = React.createClass({
deleteConfirmation: '' deleteConfirmation: ''
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
activePlanetProfile: function () { activePlanetProfile: function () {
this.setState({currentTab: 'profile'}) this.setState({currentTab: 'profile'})
}, },

View File

@@ -5,11 +5,12 @@ var React = require('react/addons')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState], mixins: [LinkedState, KeyCaster('teamCreateModal')],
propTypes: { propTypes: {
user: React.PropTypes.shape({ user: React.PropTypes.shape({
name: React.PropTypes.string name: React.PropTypes.string
@@ -24,6 +25,19 @@ module.exports = React.createClass({
} }
} }
}, },
componentDidMount: function () {
React.findDOMNode(this.refs.teamName).focus()
},
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
case 'submitTeamCreateModal':
this.handleSubmit()
break
}
},
handleSubmit: function () { handleSubmit: function () {
Hq.createTeam(this.props.user.name, this.state.team) Hq.createTeam(this.props.user.name, this.state.team)
.then(function (res) { .then(function (res) {
@@ -46,7 +60,7 @@ module.exports = React.createClass({
render: function () { render: function () {
return ( return (
<div className='TeamCreateModal modal'> <div className='TeamCreateModal modal'>
<input valueLink={this.linkState('team.name')} className='nameInput stripInput' placeholder='Create new team'/> <input ref='teamName' valueLink={this.linkState('team.name')} className='nameInput stripInput' placeholder='Create new team'/>
<button onClick={this.handleSubmit} className='submitButton'> <button onClick={this.handleSubmit} className='submitButton'>
<i className='fa fa-check'/> <i className='fa fa-check'/>

View File

@@ -8,6 +8,7 @@ var Hq = require('../Services/Hq')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var Helper = require('../Mixins/Helper') var Helper = require('../Mixins/Helper')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
@@ -30,7 +31,7 @@ var getOptions = function (input, callback) {
} }
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState, Reflux.listenTo(UserStore, 'onUserChange'), Helper], mixins: [LinkedState, Reflux.listenTo(UserStore, 'onUserChange'), Helper, KeyCaster('teamSettingsModal')],
propTypes: { propTypes: {
team: React.PropTypes.shape({ team: React.PropTypes.shape({
id: React.PropTypes.number, id: React.PropTypes.number,
@@ -38,7 +39,8 @@ module.exports = React.createClass({
profileName: React.PropTypes.string, profileName: React.PropTypes.string,
email: React.PropTypes.string, email: React.PropTypes.string,
Members: React.PropTypes.array Members: React.PropTypes.array
}) }),
close: React.PropTypes.func
}, },
getInitialState: function () { getInitialState: function () {
var team = this.props.team var team = this.props.team
@@ -55,6 +57,13 @@ module.exports = React.createClass({
updatingMember: false updatingMember: false
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
onUserChange: function (res) { onUserChange: function (res) {
var member var member
switch (res.status) { switch (res.status) {

View File

@@ -7,21 +7,33 @@ var State = ReactRouter.State
var Navigation = ReactRouter.Navigation var Navigation = ReactRouter.Navigation
var AuthFilter = require('../Mixins/AuthFilter') var AuthFilter = require('../Mixins/AuthFilter')
var KeyCaster = require('../Mixins/KeyCaster')
var HomeNavigator = require('../Components/HomeNavigator') var HomeNavigator = require('../Components/HomeNavigator')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [AuthFilter.OnlyUser, State, Navigation], mixins: [AuthFilter.OnlyUser, State, Navigation, KeyCaster('homeContainer')],
componentDidMount: function () { componentDidMount: function () {
if (this.isActive('homeEmpty')) { if (this.isActive('homeEmpty')) {
var user = JSON.parse(localStorage.getItem('currentUser')) var user = JSON.parse(localStorage.getItem('currentUser'))
if (user.Planets != null && user.Planets.length > 0) {
this.transitionTo('planet', {userName: user.name, planetName: user.Planets[0].name})
return
}
this.transitionTo('userHome', {userName: user.name}) this.transitionTo('userHome', {userName: user.name})
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'switchPlanet':
this.refs.navigator.switchPlanetByIndex(e.data)
break
}
},
render: function () { render: function () {
return ( return (
<div className='HomeContainer'> <div className='HomeContainer'>
<HomeNavigator/> <HomeNavigator ref='navigator'/>
<RouteHandler/> <RouteHandler/>
</div> </div>
) )

View File

@@ -96,7 +96,10 @@ module.exports = React.createClass({
{this.state.updateAvailable ? ( {this.state.updateAvailable ? (
<button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button> <button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button>
) : null} ) : null}
<button onClick={this.openContactModal} className='contactButton'><i className='fa fa-paper-plane-o'/></button> <button onClick={this.openContactModal} className='contactButton'>
<i className='fa fa-paper-plane-o'/>
<div className='tooltip'>Contact us</div>
</button>
<RouteHandler/> <RouteHandler/>
</div> </div>
) )

View File

@@ -14,12 +14,13 @@ var Hq = require('../Services/Hq')
var Modal = require('../Mixins/Modal') var Modal = require('../Mixins/Modal')
var ArticleFilter = require('../Mixins/ArticleFilter') var ArticleFilter = require('../Mixins/ArticleFilter')
var Helper = require('../Mixins/Helper') var Helper = require('../Mixins/Helper')
var KeyCaster = require('../Mixins/KeyCaster')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
var PlanetStore = require('../Stores/PlanetStore') var PlanetStore = require('../Stores/PlanetStore')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [ReactRouter.Navigation, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), ArticleFilter, Helper], mixins: [ReactRouter.Navigation, ReactRouter.State, Modal, Reflux.listenTo(UserStore, 'onUserChange'), Reflux.listenTo(PlanetStore, 'onPlanetChange'), ArticleFilter, Helper, KeyCaster('planetContainer')],
propTypes: { propTypes: {
params: React.PropTypes.object, params: React.PropTypes.object,
planetName: React.PropTypes.string planetName: React.PropTypes.string
@@ -62,6 +63,28 @@ module.exports = React.createClass({
}) })
} }
}, },
onKeyCast: function (e) {
switch (e.status) {
case 'openLaunchModal':
this.refs.navigator.openLaunchModal()
break
case 'selectNextArticle':
this.selectNextArticle()
break
case 'selectPriorArticle':
this.selectPriorArticle()
break
case 'toggleFocusSearchInput':
this.toggleFocusSearchInput()
break
case 'openEditModal':
this.refs.detail.openEditModal()
break
case 'openDeleteModal':
this.refs.detail.openDeleteModal()
break
}
},
onPlanetChange: function (res) { onPlanetChange: function (res) {
if (this.state.planet == null) return if (this.state.planet == null) return
@@ -207,6 +230,18 @@ module.exports = React.createClass({
return return
} }
var listElement = this.refs.list.refs.articles.getDOMNode()
var articleElement = listElement.querySelectorAll('li')[index]
var overflowBelow = listElement.clientHeight + listElement.scrollTop < articleElement.offsetTop + articleElement.clientHeight
if (overflowBelow) {
listElement.scrollTop = articleElement.offsetTop + articleElement.clientHeight - listElement.clientHeight
}
var overflowAbove = listElement.scrollTop > articleElement.offsetTop
if (overflowAbove) {
listElement.scrollTop = articleElement.offsetTop
}
if (article.type === 'code') { if (article.type === 'code') {
params.localId = article.localId params.localId = article.localId
this.transitionTo('codes', params) this.transitionTo('codes', params)
@@ -237,9 +272,17 @@ module.exports = React.createClass({
if (index > 0) { if (index > 0) {
this.selectArticleByListIndex(index - 1) this.selectArticleByListIndex(index - 1)
} else { } else {
React.findDOMNode(this).querySelector('.PlanetHeader .searchInput input').focus() React.findDOMNode(this.refs.header.refs.search).focus()
} }
}, },
toggleFocusSearchInput: function () {
var search = React.findDOMNode(this.refs.header.refs.search)
if (document.activeElement === search) {
React.findDOMNode(this.refs.header.refs.search).blur()
return
}
React.findDOMNode(this.refs.header.refs.search).focus()
},
handleSearchChange: function (e) { handleSearchChange: function (e) {
this.setState({search: e.target.value}, function () { this.setState({search: e.target.value}, function () {
this.selectArticleByListIndex(0) this.selectArticleByListIndex(0)
@@ -309,9 +352,6 @@ module.exports = React.createClass({
this.setState({search: '#' + tag}) this.setState({search: '#' + tag})
}.bind(this) }.bind(this)
}, },
focus: function () {
React.findDOMNode(this).focus()
},
render: function () { render: function () {
if (this.state.planet == null) return (<div/>) if (this.state.planet == null) return (<div/>)
@@ -346,6 +386,7 @@ module.exports = React.createClass({
return ( return (
<div className='PlanetContainer'> <div className='PlanetContainer'>
<PlanetHeader <PlanetHeader
ref='header'
search={this.state.search} search={this.state.search}
fetchPlanet={this.fetchPlanet} fetchPlanet={this.fetchPlanet}
onSearchChange={this.handleSearchChange} onSearchChange={this.handleSearchChange}

View File

@@ -190,7 +190,6 @@ module.exports = React.createClass({
return this.renderUserHome(currentUser) return this.renderUserHome(currentUser)
} }
} else if (this.isActive('planet') && user != null && user.userType === 'team') { } else if (this.isActive('planet') && user != null && user.userType === 'team') {
console.log(user.Members)
var members = user.Members.map(function (member) { var members = user.Members.map(function (member) {
return ( return (
<li key={'user-' + member.id}><Link to='userHome' params={{userName: member.name}}> <li key={'user-' + member.id}><Link to='userHome' params={{userName: member.name}}>
@@ -224,7 +223,9 @@ module.exports = React.createClass({
renderTeamHome: function (currentUser) { renderTeamHome: function (currentUser) {
var user = this.state.user var user = this.state.user
var isOwner = true var isOwner = user.Members == null ? false : user.Members.some(function (member) {
return member.id === currentUser.id && member.TeamMember.role === 'owner'
})
var userPlanets = user.Planets.map(function (planet) { var userPlanets = user.Planets.map(function (planet) {
return ( return (
@@ -258,7 +259,7 @@ module.exports = React.createClass({
<div className='userName'>{user.name}</div> <div className='userName'>{user.name}</div>
</div> </div>
<button onClick={this.openTeamSettingsModal} className='editProfileButton'>Team settings</button> {isOwner ? (<button onClick={this.openTeamSettingsModal} className='editProfileButton'>Team settings</button>) : null}
</div> </div>
<div className='memberList'> <div className='memberList'>
<div className='memberLabel'>{members.length} {members.length > 1 ? 'Members' : 'Member'}</div> <div className='memberLabel'>{members.length} {members.length > 1 ? 'Members' : 'Member'}</div>

View File

@@ -1,4 +1,5 @@
function deleteItemFromTargetArray (item, targetArray) { function deleteItemFromTargetArray (item, targetArray) {
if (targetArray == null) targetArray = []
targetArray.some(function (_item, index) { targetArray.some(function (_item, index) {
if (_item.id === item.id) { if (_item.id === item.id) {
targetArray.splice(index, 1) targetArray.splice(index, 1)
@@ -11,6 +12,8 @@ function deleteItemFromTargetArray (item, targetArray) {
} }
function updateItemToTargetArray (item, targetArray) { function updateItemToTargetArray (item, targetArray) {
if (targetArray == null) targetArray = []
var isNew = !targetArray.some(function (_item, index) { var isNew = !targetArray.some(function (_item, index) {
if (_item.id === item.id) { if (_item.id === item.id) {
targetArray.splice(index, 1, item) targetArray.splice(index, 1, item)

View File

@@ -0,0 +1,100 @@
var Reflux = require('reflux')
var state = {
}
var keyDown = Reflux.createAction()
var KeyStore = Reflux.createStore({
init: function () {
this.listenTo(keyDown, this.onKeyDown)
document.addEventListener('keydown', function (e) {
keyDown(e)
})
},
setState: function (newState, cb) {
for (var key in newState) {
state[key] = newState[key]
}
if (typeof cb === 'function') cb()
},
onKeyDown: function (e) {
/*
Modals
*/
if (state.codeForm || state.noteForm || state.noteDeleteModal || state.codeDeleteModal || state.addMemberModal || state.aboutModal || state.editProfileModal || state.contactModal || state.teamCreateModal || state.planetCreateModal || state.planetSettingModal || state.teamSettingsModal || state.logoutModal) {
// ESC
if (e.keyCode === 27) this.cast('closeModal')
// Cmd + Enter
if (e.keyCode === 13 && e.metaKey) {
if (state.codeForm) this.cast('submitCodeForm')
if (state.noteForm) this.cast('submitNoteForm')
if (state.codeDeleteModal) this.cast('submitCodeDeleteModal')
if (state.noteDeleteModal) this.cast('submitNoteDeleteModal')
if (state.addMemberModal) this.cast('submitAddMemberModal')
if (state.contactModal) this.cast('submitContactModal')
if (state.teamCreateModal) this.cast('submitTeamCreateModal')
if (state.planetCreateModal) this.cast('submitPlanetCreateModal')
if (state.logoutModal) this.cast('submitLogoutModal')
}
return
}
/*
PlanetContainer
*/
if (state.planetContainer) {
// Cmd + Enter, A
if ((e.keyCode === 13 && e.metaKey) || e.keyCode === 65) this.cast('openLaunchModal')
// Esc
if (e.keyCode === 27) this.cast('toggleFocusSearchInput')
// Up
if (e.keyCode === 38) this.cast('selectPriorArticle')
// Down
if (e.keyCode === 40) this.cast('selectNextArticle')
// E
if (e.keyCode === 69) this.cast('openEditModal')
// D
if (e.keyCode === 68) this.cast('openDeleteModal')
}
/*
HomeContainer
*/
if (state.homeContainer) {
if (e.keyCode > 48 && e.keyCode < 58 && e.metaKey) {
this.cast('switchPlanet', e.keyCode - 48)
}
}
},
cast: function (status, data) {
this.trigger({
status: status,
data: data
})
}
})
module.exports = function (stateKey) {
return {
mixins: [Reflux.listenTo(KeyStore, 'onKeyCast')],
componentDidMount: function () {
var newState = {}
newState[stateKey] = true
KeyStore.setState(newState)
},
componentWillUnmount: function () {
var newState = {}
newState[stateKey] = false
KeyStore.setState(newState)
}
}
}

View File

@@ -35,6 +35,9 @@ module.exports = {
fetchUser: function (userName) { fetchUser: function (userName) {
return request return request
.get(apiUrl + 'resources/' + userName) .get(apiUrl + 'resources/' + userName)
.set({
Authorization: 'Bearer ' + localStorage.getItem('token')
})
}, },
updateUser: function (userName, input) { updateUser: function (userName, input) {
return request return request
@@ -79,6 +82,9 @@ module.exports = {
fetchPlanet: function (userName, planetName) { fetchPlanet: function (userName, planetName) {
return request return request
.get(apiUrl + 'resources/' + userName + '/planets/' + planetName) .get(apiUrl + 'resources/' + userName + '/planets/' + planetName)
.set({
Authorization: 'Bearer ' + localStorage.getItem('token')
})
}, },
updatePlanet: function (userName, planetName, input) { updatePlanet: function (userName, planetName, input) {
return request return request

View File

@@ -64,40 +64,35 @@ articleListWidth= 275px
color inactiveColor color inactiveColor
&:hover &:hover
color textColor color textColor
.privateTooltip .tooltip
position fixed tooltip()
z-index popupZIndex
background-color transparentify(invBackgroundColor, 80%)
color invTextColor
padding 10px
font-size 0.9em
line-height 0.9em
border-radius 5px
white-space nowrap
opacity 0
transition 0.1s
pointer-events none
margin-left -30px margin-left -30px
&:hover .privateTooltip &:hover .tooltip
opacity 1 opacity 1
.menuBtn .planetSettingButton
position absolute position absolute
top 12px top 15px
right 5px right 5px
font-size 1em font-size 0.8em
btnDefault() btnDefault()
box-sizing border-box box-sizing border-box
circle() circle()
width 33px width 26px
height 33px height 26px
text-align center text-align center
cursor pointer cursor pointer
transition 0.1s transition 0.1s
transform scale(0.8)
&:focus, &.focus &:focus, &.focus
outline none outline none
.tooltip
tooltip()
margin-top 11px
margin-left -36px
&:hover .tooltip
opacity 1
.headerControl .headerControl
noSelect() noSelect()
absolute top bottom right absolute top bottom right
@@ -118,10 +113,11 @@ articleListWidth= 275px
.refreshButton .refreshButton
display block display block
position absolute position absolute
top 12px top 15px
right 55px right 55px
width 28px width 26px
height 28px height 26px
font-size 0.8em
btnDefault() btnDefault()
circle() circle()
text-align center text-align center
@@ -129,16 +125,28 @@ articleListWidth= 275px
transition 0.1s transition 0.1s
&:focus, &.focus &:focus, &.focus
outline none outline none
.tooltip
tooltip()
margin-top 11px
margin-left -39px
&:hover .tooltip
opacity 1
.logo .logo
display block display block
position absolute position absolute
top 4px top 4px
right 10px right 10px
cursor pointer cursor pointer
img
transition 0.1s transition 0.1s
opacity 0.9 opacity 0.9
&:hover, &.hover &:hover img, &:hover .tooltip
opacity 1 opacity 1
.tooltip
tooltip()
margin-top -5px
margin-left -67px
.PlanetNavigator .PlanetNavigator
absolute bottom left absolute bottom left
@@ -178,6 +186,7 @@ articleListWidth= 275px
overflow-y auto overflow-y auto
li li
.articleItem .articleItem
noSelect()
border solid 2px transparent border solid 2px transparent
position relative position relative
height 94px height 94px
@@ -283,23 +292,41 @@ articleListWidth= 275px
z-index 1 z-index 1
top 2px top 2px
right 2px right 2px
.deleteButton, .editButton
btnDefault()
text-align center
width 33px
height 33px
border-radius 16.5px
font-size 15px
margin 0 3px
.tooltip
tooltip()
margin-top 10px
&:hover .tooltip
opacity 1
.editButton .tooltip
margin-left -12px
.deleteButton .tooltip
margin-left -26px
.detailBody .detailBody
absolute left right bottom absolute left right bottom
top 105px top 105px
.content .content
box-sizing border-box
padding 5px
border-top solid 1px borderColor
overflow-x hidden
overflow-y auto
&.noteDetail
.detailBody .content
marked()
&.codeDetail
.detailBody .content
.ace_editor
position absolute position absolute
top 5px top 5px
bottom 5px bottom 5px
left 2px left 2px
right 2px right 2px
box-sizing border-box
padding 5px
border-top solid 1px borderColor
&.noteDetail
.detailBody .content
overflow-x hidden
overflow-y auto
marked()
&.codeDetail
.detailBody .content
.ace_editor
absolute left right top bottom

View File

@@ -1,5 +1,6 @@
.HomeContainer .HomeContainer
.HomeNavigator .HomeNavigator
noSelect()
background-color planetNavBgColor background-color planetNavBgColor
absolute left top bottom absolute left top bottom
width 55px width 55px
@@ -159,22 +160,11 @@
border-color darken(brandBorderColor, 10%) border-color darken(brandBorderColor, 10%)
background-color brandColor background-color brandColor
color white color white
.newPlanetTooltip .tooltip
position fixed tooltip()
z-index 500 margin-top -22px
background-color transparentify(invBackgroundColor, 80%)
color invTextColor
padding 10px
line-height 1em
border-radius 5px
margin-top -23px
margin-left 33px margin-left 33px
white-space nowrap &:hover .tooltip
font-size 1.1em
opacity 0
transition 0.1s
pointer-events none
&:hover .newPlanetTooltip
opacity 1 opacity 1
.UserContainer .UserContainer
absolute top bottom right absolute top bottom right

View File

@@ -16,6 +16,8 @@ body
color textColor color textColor
font-size fontSize font-size fontSize
font-weight 400 font-weight 400
button
font-family "Lato"
div, span, a, button, input, textarea div, span, a, button, input, textarea
box-sizing border-box box-sizing border-box
@@ -118,3 +120,9 @@ textarea.block-input
padding 10px 15px padding 10px 15px
border-radius 5px border-radius 5px
background-color backgroundColor background-color backgroundColor
.tooltip
tooltip()
margin-top -22px
margin-left -97px
&:hover .tooltip
opacity 1

View File

@@ -22,10 +22,11 @@ marked()
font-size 0.67em font-size 0.67em
margin 2.33em auto margin 2.33em auto
h1, h2, h3, h4, h5, h6 h1, h2, h3, h4, h5, h6
font-weight font-weight 400 font-weight 400
line-height 1.2em line-height 1.4em
p p
line-height 1.2em line-height 1.4em
margin-bottom 15px
img img
max-width 100% max-width 100%
strong strong
@@ -36,14 +37,14 @@ marked()
text-decoration line-through text-decoration line-through
blockquote blockquote
border-left solid 4px brandBorderColor border-left solid 4px brandBorderColor
margin 1em 0 margin 15px 0 15px
padding 0 25px padding 0 25px
ul ul
list-style-type disc list-style-type disc
padding-left 35px padding-left 35px
li li
display list-item display list-item
margin 0.5em 0 margin 15px 0
&>li>ul &>li>ul
list-style-type circle list-style-type circle
&>li>ul &>li>ul
@@ -53,33 +54,36 @@ marked()
padding-left 35px padding-left 35px
li li
display list-item display list-item
margin 0.5em 0 margin 15px 0
code code
font-family monospace font-family monospace
padding 2px 4px padding 2px 4px
border solid 1px borderColor border solid 1px borderColor
border-radius 4px border-radius 4px
font-size 0.9em font-size 0.9em
color black
text-decoration none
pre pre
padding 5px padding 5px
border solid 1px borderColor border solid 1px borderColor
border-radius 5px border-radius 5px
margin-bottom 0.5em
overflow-x auto overflow-x auto
margin-bottom 15px
&>code &>code
padding 0 padding 0
border none border none
border-radius 0 border-radius 0
color black
table table
width 100% width 100%
margin 15px 0 margin 15px 0 25px
thead thead
tr tr
background-color tableHeadBgColor background-color tableHeadBgColor
th th
border-style: solid; border-style solid
padding: 5px; padding 15px 5px
border-width: 1px 0 2px 1px; border-width 1px 0 2px 1px
border-color borderColor border-color borderColor
&:last-child &:last-child
border-right solid 1px borderColor border-right solid 1px borderColor
@@ -89,9 +93,9 @@ marked()
tr:nth-child(2n) tr:nth-child(2n)
background-color tableEvenBgColor background-color tableEvenBgColor
td td
border-style: solid; border-style solid
padding: 5px; padding 15px 5px
border-width: 0 0 1px 1px; border-width 0 0 1px 1px
border-color borderColor border-color borderColor
&:last-child &:last-child
border-right solid 1px borderColor border-right solid 1px borderColor

View File

@@ -0,0 +1,13 @@
tooltip()
position fixed
z-index popupZIndex
background-color transparentify(invBackgroundColor, 80%)
color invTextColor
padding 10px
font-size 12px
line-height 12px
border-radius 5px
white-space nowrap
opacity 0
transition 0.1s
pointer-events none

View File

@@ -196,7 +196,6 @@
border-radius 5px border-radius 5px
float left float left
.LaunchModal .LaunchModal
.modal-tab .modal-tab
text-align center text-align center
@@ -314,6 +313,14 @@
height 55px height 55px
circle() circle()
btnPrimary() btnPrimary()
.errorAlert
alertError()
padding 12px 10px
border-radius 5px
text-align center
display block
width 360px
margin 0 auto 15px
.ContactModal .ContactModal
padding 15px padding 15px
@@ -341,6 +348,7 @@
padding 0 15px padding 0 15px
border-radius 5px border-radius 5px
margin-left 5px margin-left 5px
font-size 1em
button.sendButton button.sendButton
btnPrimary() btnPrimary()
.confirmation .confirmation

View File

@@ -178,6 +178,10 @@ function makeNewMainWindow () {
mainWindow.loadUrl('file://' + __dirname + '/browser/main/index.electron.html') mainWindow.loadUrl('file://' + __dirname + '/browser/main/index.electron.html')
mainWindow.webContents.on('new-window', function (e) {
e.preventDefault()
})
mainWindow.on('closed', function () { mainWindow.on('closed', function () {
console.log('main closed') console.log('main closed')
mainWindow = null mainWindow = null

View File

@@ -1,6 +1,6 @@
{ {
"name": "boost", "name": "boost",
"version": "0.2.2", "version": "0.2.5",
"description": "Boost App", "description": "Boost App",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {