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

Compare commits

...

36 Commits

Author SHA1 Message Date
Rokt33r
5fa37dbffb Merge branch 'dev'
* dev:
  version 0.2.10 - Hotkeyの設定機能 - Stylus refactor
2015-09-02 01:02:32 +09:00
Rokt33r
c6307e4ad3 version 0.2.10
- Hotkeyの設定機能
- Stylus refactor
2015-09-02 01:02:04 +09:00
Rokt33r
06a54d451c Merge branch 'dev'
* dev:
  0.2.9 API server changed, bump electron version 0.31.0
2015-08-31 01:34:15 +09:00
Rokt33r
e317075815 0.2.9 API server changed, bump electron version 0.31.0 2015-08-31 01:33:32 +09:00
Rokt33r
45541a255b Merge branch 'dev'
* dev:
  - StylusでコンパイルされたCSSをCachingする(ロディングが短くなる) - Planet name changeのときにエラーハンドリング追加 + Bug fix - TeamのMemberを編集する場合、自分を編集することはできない - FinderにMarkdownのリンクがちゃんと外部に飛ぶように - Tray iconがちゃんと表示 - ArticleDetailのCodeアイコンがちゃんと表示されない
2015-08-30 05:31:13 +09:00
Rokt33r
3ab423d695 - StylusでコンパイルされたCSSをCachingする(ロディングが短くなる)
- Planet name changeのときにエラーハンドリング追加 + Bug fix
- TeamのMemberを編集する場合、自分を編集することはできない
- FinderにMarkdownのリンクがちゃんと外部に飛ぶように
- Tray iconがちゃんと表示
- ArticleDetailのCodeアイコンがちゃんと表示されない
2015-08-30 05:30:54 +09:00
Rokt33r
345d7b427a Merge branch 'dev'
* dev:
  Loading font 微調整
2015-08-26 18:27:42 +09:00
Rokt33r
de6d6b692e Loading font 微調整 2015-08-26 18:27:19 +09:00
Rokt33r
b2845e2284 Merge branch 'dev'
* dev:
  version 0.2.7  - Planet, Team作成の時Error message表示  - MarkdownのCode blockの背景を薄い灰色にする  - 権限なしのPlanetには  - SignUpに規約/Privacyの外部リンク追加  - Loading画面追加  - Font 添付(Lato regular)  - UserContainerでのTeam Label変更
2015-08-26 18:23:04 +09:00
Rokt33r
47383c347c version 0.2.7
- Planet, Team作成の時Error message表示
 - MarkdownのCode blockの背景を薄い灰色にする
 - 権限なしのPlanetには
 - SignUpに規約/Privacyの外部リンク追加
 - Loading画面追加
 - Font 添付(Lato regular)
 - UserContainerでのTeam Label変更
2015-08-26 18:22:46 +09:00
Rokt33r
4bda84d69c cleanup old files 2015-08-24 17:42:43 +09:00
Rokt33r
b510aa11f5 Merge branch 'dev'
* dev:
  fix bugs - ArticleList text overflow behaviour in Finder, PlanetContainer - No DevTools
2015-08-24 17:42:00 +09:00
Rokt33r
8dab6d5e04 fix bugs
- ArticleList text overflow behaviour in Finder, PlanetContainer
- No DevTools
2015-08-24 17:41:38 +09:00
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
Rokt33r
3b7215b36a Merge branch 'dev'
* dev:
  改善 - Finder descriptionのTextoverflow対策, 最初起動の時のFinderの異常振る舞い
2015-08-22 03:46:51 +09:00
Rokt33r
b88d5cfb06 改善 - Finder descriptionのTextoverflow対策, 最初起動の時のFinderの異常振る舞い 2015-08-22 03:46:30 +09:00
Rokt33r
8ab96cf2fb fix version 2015-08-22 03:36:04 +09:00
Rokt33r
63af2fd8b1 fix submodule setting 2015-08-22 03:33:32 +09:00
Rokt33r
fcf26f7844 Merge branch 'dev'
* dev:
  改善 - PlanetArticleList, PlanetArticleDetail
  #14 改善点4つ適用  - Team member 管理画面でのスペルミス  - Member profile imageを丸にする  - Profile popup 改善  - 文字サイズ大きく(UserContainerのみ)
2015-08-22 03:28:56 +09:00
Rokt33r
657ebc99df 改善 - PlanetArticleList, PlanetArticleDetail 2015-08-22 03:27:42 +09:00
Rokt33r
9500f9a8c9 #14 改善点4つ適用
- Team member 管理画面でのスペルミス
 - Member profile imageを丸にする
 - Profile popup 改善
 - 文字サイズ大きく(UserContainerのみ)
2015-08-22 00:27:05 +09:00
Rokt33r
a05bba15e7 Merge branch 'dev'
* dev: (79 commits)
  version 0.2.1
  修正 - Member list, Team listのデザイン修正
  実装 - Team pageとPlanet pageにMember List表示
  実装 - PlanetHeaderにPrivate鍵表示
  Noteから外部Linkを開くときにBrowserを使う
  LogoutModal実装
  Contact Modal追加
  on Refactor... #4
  on Refactor... #3
  on Refactor... #2
  on Refactoring...
  test 0.2.0
  Fix: Personal Settingボターンを右にする。写真からまっすぐProfile pageに入れるようにする
  Add: Refresh button
  Fix: Design changed
  Fix: Disable pinch to zoom
  Fix: Preview button修正
  Fix: PlanetNavigatorのHome削除 & SnippetsとBlueprintsはToggleができるように
  Fix: minor features 設定ボタンアイコンの変更 削除Modalでcmd+enterの使用 検索バーデザイン
  Add: Log in / Sign upの時にエラーが出たらAlertを表示する Debug: Tray Icon, PopUpWindow, Menuがいつの間にか消える
  ...

Conflicts:
	src/browser/main/controllers/AppController.js
	src/browser/main/controllers/directives/SideNavController.js
	src/browser/main/controllers/states/AuthRegisterController.js
	src/browser/main/index.html
	src/browser/main/services/Modal.js
	src/browser/main/styles/app.css
	src/browser/main/styles/app.styl
	src/browser/main/styles/directives/side-nav.styl
	src/browser/main/tpls/directives/side-nav.tpl.html
	src/browser/main/tpls/states/home.tpl.html
2015-08-21 04:58:01 +09:00
Rokt33r
3b907627f7 fix links 2015-07-03 18:35:10 +09:00
Rokt33r
2284fd41b9 add agreement 2015-07-03 16:41:42 +09:00
57 changed files with 1191 additions and 406 deletions

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "browser/ace"] [submodule "browser/ace"]
path = browser/ace path = browser/ace
url = https://github.com/ajaxorg/ace-builds.git url = https://github.com/ajaxorg/ace-builds.git
[submodule "browser/electron-stylus"]
path = browser/electron-stylus
url = https://github.com/Rokt33r/electron-stylus.git

BIN
Lato-Regular.ttf Normal file

Binary file not shown.

BIN
Lato-Regular.woff Normal file

Binary file not shown.

BIN
Lato-Regular.woff2 Normal file

Binary file not shown.

View File

@@ -2,10 +2,9 @@ var React = require('react/addons')
var CodeViewer = require('../../main/Components/CodeViewer') var CodeViewer = require('../../main/Components/CodeViewer')
var Markdown = require('../../main/Mixins/Markdown') var MarkdownPreview = require('../../main/Components/MarkdownPreview')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [Markdown],
propTypes: { propTypes: {
currentArticle: React.PropTypes.object currentArticle: React.PropTypes.object
}, },
@@ -28,7 +27,7 @@ module.exports = React.createClass({
<div className='FinderDetail'> <div className='FinderDetail'>
<div className='header'><i className='fa fa-file-text-o fa-fw'/> {article.title}</div> <div className='header'><i className='fa fa-file-text-o fa-fw'/> {article.title}</div>
<div className='content'> <div className='content'>
<div className='marked' dangerouslySetInnerHTML={{__html: ' ' + this.markdown(article.content)}}></div> <MarkdownPreview className='marked' content={article.content}/>
</div> </div>
</div> </div>
) )

View File

@@ -8,6 +8,17 @@
<link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" title="no title" charset="utf-8"> <link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" title="no title" charset="utf-8">
<link rel="shortcut icon" href="favicon.ico"> <link rel="shortcut icon" href="favicon.ico">
<style>
@font-face {
font-family: 'Lato';
src: url('../../Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
url('../../Lato-Regular.woff') format('woff'), /* Modern Browsers */
url('../../Lato-Regular.ttf') format('truetype');
font-style: normal;
font-weight: normal;
text-rendering: optimizeLegibility;
}
</style>
<script> <script>
document.addEventListener('mousewheel', function(e) { document.addEventListener('mousewheel', function(e) {
if(e.deltaY % 1 !== 0) { if(e.deltaY % 1 !== 0) {
@@ -47,14 +58,13 @@
} }
}); });
} }
require('electron-stylus')(__dirname + '/../styles/finder/index.styl')
</script> </script>
</head> </head>
<body> <body>
<div id="content"></div> <div id="content"></div>
<script src="../ace/src-min/ace.js"></script> <script src="../ace/src-min/ace.js"></script>
<script> <script>
require('../electron-stylus')(__dirname + '/../styles/finder/index.styl', 'finderCss')
require('node-jsx').install({ harmony: true, extension: '.jsx' }) require('node-jsx').install({ harmony: true, extension: '.jsx' })
require('./index.jsx') require('./index.jsx')
</script> </script>

View File

@@ -49,6 +49,7 @@ var Finder = React.createClass({
document.addEventListener('keydown', this.handleKeyDown) document.addEventListener('keydown', this.handleKeyDown)
document.addEventListener('click', this.handleClick) document.addEventListener('click', this.handleClick)
window.addEventListener('focus', this.handleFinderFocus) window.addEventListener('focus', this.handleFinderFocus)
this.handleFinderFocus()
}, },
componentWillUnmount: function () { componentWillUnmount: function () {
document.removeEventListener('keydown', this.handleKeyDown) document.removeEventListener('keydown', this.handleKeyDown)

View File

@@ -1,18 +1,24 @@
var remote = require('remote')
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 () {
var version = global.version
return ( return (
<div className='AboutModal modal'> <div className='PreferencesModal sideNavModal modal'>
<div className='about1'> <div className='about1'>
<img className='logo' src='resources/favicon-230x230.png'/> <img className='logo' src='resources/favicon-230x230.png'/>
<div className='appInfo'>Boost {version == null || version.length === 0 ? 'DEV version' : 'v' + version}</div> <div className='appInfo'>Boost {version == null || version.length === 0 ? 'DEV version' : 'v' + version}</div>

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,20 +39,35 @@ module.exports = React.createClass({
role: 'member' role: 'member'
} }
}, },
handleSubmit: function () { onKeyCast: function (e) {
Hq switch (e.status) {
.addMember(this.props.team.name, { case 'closeModal':
userName: this.state.userName,
role: this.state.role
})
.then(function (res) {
console.log(res.body)
UserStore.Actions.addMember(res.body)
this.props.close() this.props.close()
}.bind(this)) break
.catch(function (err) { case 'submitAddMemberModal':
console.error(err) this.handleSubmit()
}) break
}
},
handleSubmit: function () {
this.setState({errorMessage: null}, function () {
Hq
.addMember(this.props.team.name, {
userName: this.state.userName,
role: this.state.role
})
.then(function (res) {
console.log(res.body)
UserStore.Actions.addMember(res.body)
this.props.close()
}.bind(this))
.catch(function (err) {
console.error(err)
if (err.status === 403) {
this.setState({errorMessage: err.response.body.message})
}
}.bind(this))
})
}, },
handleChange: function (value) { handleChange: function (value) {
this.setState({userName: value}) this.setState({userName: 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})
@@ -60,7 +69,6 @@ module.exports = React.createClass({
this.setState({ this.setState({
passwordSubmitStatus: 'sending' passwordSubmitStatus: 'sending'
}, function () { }, function () {
console.log(this.state.password)
Hq.changePassword(this.state.password) Hq.changePassword(this.state.password)
.then(function (res) { .then(function (res) {
this.setState({ this.setState({
@@ -94,9 +102,9 @@ module.exports = React.createClass({
} }
return ( return (
<div className='EditProfileModal modal tabModal'> <div className='EditProfileModal sideNavModal modal'>
<div className='leftPane'> <div className='leftPane'>
<div className='tabLabel'>Edit profile</div> <div className='modalLabel'>Edit profile</div>
<div className='tabList'> <div className='tabList'>
<button className={this.state.currentTab === 'userInfo' ? 'active' : ''} onClick={this.selectTab('userInfo')}><i className='fa fa-user fa-fw'/> User Info</button> <button className={this.state.currentTab === 'userInfo' ? 'active' : ''} onClick={this.selectTab('userInfo')}><i className='fa fa-user fa-fw'/> User Info</button>
<button className={this.state.currentTab === 'password' ? 'active' : ''} onClick={this.selectTab('password')}><i className='fa fa-lock fa-fw'/> Password</button> <button className={this.state.currentTab === 'password' ? 'active' : ''} onClick={this.selectTab('password')}><i className='fa fa-lock fa-fw'/> Password</button>
@@ -110,7 +118,7 @@ module.exports = React.createClass({
}, },
renderUserInfoTab: function () { renderUserInfoTab: function () {
return ( return (
<div className='userInfoTab'> <div className='userInfoTab tab'>
<div className='formField'> <div className='formField'>
<label>Profile Name</label> <label>Profile Name</label>
<input valueLink={this.linkState('user.profileName')}/> <input valueLink={this.linkState('user.profileName')}/>
@@ -133,18 +141,18 @@ module.exports = React.createClass({
}, },
renderPasswordTab: function () { renderPasswordTab: function () {
return ( return (
<div className='passwordTab'> <div className='passwordTab tab'>
<div className='formField'> <div className='formField'>
<label>Current password</label> <label>Current password</label>
<input valueLink={this.linkState('password.currentPassword')}/> <input type='password' valueLink={this.linkState('password.currentPassword')}/>
</div> </div>
<div className='formField'> <div className='formField'>
<label>New password</label> <label>New password</label>
<input valueLink={this.linkState('password.newPassword')}/> <input type='password' valueLink={this.linkState('password.newPassword')}/>
</div> </div>
<div className='formField'> <div className='formField'>
<label>Confirmation</label> <label>Confirmation</label>
<input valueLink={this.linkState('password.passwordConfirmation')}/> <input type='password' valueLink={this.linkState('password.passwordConfirmation')}/>
</div> </div>
<div className='formConfirm'> <div className='formConfirm'>

View File

@@ -11,7 +11,7 @@ var Modal = require('../Mixins/Modal')
var UserStore = require('../Stores/UserStore') var UserStore = require('../Stores/UserStore')
var AboutModal = require('./AboutModal') var PreferencesModal = require('./PreferencesModal')
var PlanetCreateModal = require('./PlanetCreateModal') var PlanetCreateModal = require('./PlanetCreateModal')
var TeamCreateModal = require('./TeamCreateModal') var TeamCreateModal = require('./TeamCreateModal')
var LogoutModal = require('./LogoutModal') var LogoutModal = require('./LogoutModal')
@@ -65,22 +65,12 @@ module.exports = React.createClass({
openTeamCreateModal: function () { openTeamCreateModal: function () {
this.openModal(TeamCreateModal, {user: this.state.currentUser, transitionTo: this.transitionTo}) this.openModal(TeamCreateModal, {user: this.state.currentUser, transitionTo: this.transitionTo})
}, },
openAboutModal: function () { openPreferencesModal: function () {
this.openModal(AboutModal) this.openModal(PreferencesModal)
}, },
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>
) )
@@ -143,7 +137,6 @@ module.exports = React.createClass({
return ( return (
<li key={'user-' + team.id}> <li key={'user-' + team.id}>
<Link to='userHome' params={{userName: team.name}} className='userName'>{team.profileName} ({team.name})</Link> <Link to='userHome' params={{userName: team.name}} className='userName'>{team.profileName} ({team.name})</Link>
<div className='userSetting'><i className='fa fa-gear'/></div>
</li> </li>
) )
}) })
@@ -157,7 +150,6 @@ module.exports = React.createClass({
<ul className='profileGroupList'> <ul className='profileGroupList'>
<li> <li>
<Link to='userHome' params={{userName: this.state.currentUser.name}} className='userName'>Profile ({this.state.currentUser.name})</Link> <Link to='userHome' params={{userName: this.state.currentUser.name}} className='userName'>Profile ({this.state.currentUser.name})</Link>
<div className='userSetting'><i className='fa fa-gear'/></div>
</li> </li>
</ul> </ul>
</div> </div>
@@ -176,7 +168,7 @@ module.exports = React.createClass({
<ul className='controlGroup'> <ul className='controlGroup'>
<li> <li>
<button onClick={this.openAboutModal}><i className='fa fa-info-circle fa-fw'/> About this app</button> <button onClick={this.openPreferencesModal}><i className='fa fa-gears fa-fw'/> Preferences</button>
</li> </li>
<li> <li>
<button onClick={this.handleLogoutClick}><i className='fa fa-sign-out fa-fw'/> Log out</button> <button onClick={this.handleLogoutClick}><i className='fa fa-sign-out fa-fw'/> Log out</button>

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

@@ -1,13 +1,13 @@
var React = require('react/addons') var React = require('react/addons')
var moment = require('moment') var moment = require('moment')
var CodeViewer = require('../Components/CodeViewer') var CodeViewer = require('./CodeViewer')
var CodeEditModal = require('./CodeEditModal')
var CodeEditModal = require('../Components/CodeEditModal') var CodeDeleteModal = require('./CodeDeleteModal')
var CodeDeleteModal = require('../Components/CodeDeleteModal') var NoteEditModal = require('./NoteEditModal')
var NoteEditModal = require('../Components/NoteEditModal') var NoteDeleteModal = require('./NoteDeleteModal')
var NoteDeleteModal = require('../Components/NoteDeleteModal') var MarkdownPreview = require('./MarkdownPreview')
var MarkdownPreview = require('../Components/MarkdownPreview') var ProfileImage = require('./ProfileImage')
var Modal = require('../Mixins/Modal') var Modal = require('../Mixins/Modal')
var ForceUpdate = require('../Mixins/ForceUpdate') var ForceUpdate = require('../Mixins/ForceUpdate')
@@ -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})
@@ -61,36 +63,61 @@ module.exports = React.createClass({
if (article.type === 'code') { if (article.type === 'code') {
return ( return (
<div className='PlanetArticleDetail codeDetail'> <div className='PlanetArticleDetail codeDetail'>
<div className='viewer-header'> <div className='detailHeader'>
<i className='fa fa-code fa-fw'></i> {article.callSign} <small className='updatedAt'>{moment(article.updatedAt).fromNow()}</small> <div className='itemLeft'>
<span className='control-group'> <ProfileImage className='profileImage' size='25' email={article.User.email}/>
<button onClick={this.openEditModal} className='btn-default btn-square btn-sm'><i className='fa fa-edit fa-fw'></i></button> <i className='fa fa-code fa-fw'></i>
<button onClick={this.openDeleteModal} className='btn-default btn-square btn-sm'><i className='fa fa-trash fa-fw'></i></button> </div>
</span>
</div> <div className='itemRight'>
<div className='viewer-body'> <div className='itemInfo'>{moment(article.updatedAt).fromNow()} by <span className='userProfileName'>{article.User.profileName}</span></div>
<div className='viewer-detail'>
<div className='description'>{article.description}</div> <div className='description'>{article.description}</div>
<div className='tags'><i className='fa fa-tags'/>{tags}</div> <div className='tags'><i className='fa fa-tags'/>{tags}</div>
</div> </div>
<div className='content'>
<CodeViewer code={article.content} mode={article.mode}/> <span className='itemControl'>
</div> <button id='articleEditButton' onClick={this.openEditModal} className='editButton'>
<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>
</div>
<div className='detailBody'>
<CodeViewer className='content' code={article.content} mode={article.mode}/>
</div> </div>
</div> </div>
) )
} }
return ( return (
<div className='PlanetArticleDetail noteDetail'> <div className='PlanetArticleDetail noteDetail'>
<div className='viewer-header'> <div className='detailHeader'>
<i className='fa fa-file-text-o fa-fw'></i> {article.title} <small className='updatedAt'>{moment(article.updatedAt).fromNow()}</small> <div className='itemLeft'>
<span className='control-group'> <ProfileImage className='profileImage' size='25' email={article.User.email}/>
<button onClick={this.openEditModal} className='btn-default btn-square btn-sm'><i className='fa fa-edit fa-fw'></i></button> <i className='fa fa-file-text-o fa-fw'></i>
<button onClick={this.openDeleteModal} className='btn-default btn-square btn-sm'><i className='fa fa-trash fa-fw'></i></button> </div>
<div className='itemRight'>
<div className='itemInfo'>{moment(article.updatedAt).fromNow()} by <span className='userProfileName'>{article.User.profileName}</span></div>
<div className='description'>{article.title}</div>
<div className='tags'><i className='fa fa-tags'/>{tags}</div>
</div>
<span className='itemControl'>
<button id='articleEditButton' onClick={this.openEditModal} className='editButton'>
<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='viewer-body'> <div className='detailBody'>
<div className='tags'><i className='fa fa-tags'/>{tags}</div>
<MarkdownPreview className='content' content={article.content}/> <MarkdownPreview className='content' content={article.content}/>
</div> </div>
</div> </div>

View File

@@ -13,6 +13,33 @@ module.exports = React.createClass({
articles: React.PropTypes.array, articles: React.PropTypes.array,
showOnlyWithTag: React.PropTypes.func showOnlyWithTag: React.PropTypes.func
}, },
handleArticleClikck: function (article) {
if (article.type === 'code') {
return function (e) {
var params = this.getParams()
document.getElementById('articleEditButton').focus()
this.transitionTo('codes', {
userName: params.userName,
planetName: params.planetName,
localId: article.localId
})
}.bind(this)
}
if (article.type === 'note') {
return function (e) {
var params = this.getParams()
document.getElementById('articleEditButton').focus()
this.transitionTo('notes', {
userName: params.userName,
planetName: params.planetName,
localId: article.localId
})
}.bind(this)
}
},
render: function () { render: function () {
var articles = this.props.articles.map(function (article) { var articles = this.props.articles.map(function (article) {
var tags = article.Tags.length > 0 ? article.Tags.map(function (tag) { var tags = article.Tags.length > 0 ? article.Tags.map(function (tag) {
@@ -25,28 +52,17 @@ 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') {
handleClick = function () {
this.transitionTo('codes', {
userName: params.userName,
planetName: params.planetName,
localId: article.localId
})
}.bind(this)
return ( return (
<li onClick={handleClick} key={'code-' + article.id}> <li onClick={this.handleArticleClikck(article)} key={'code-' + article.id}>
<div className={'articleItem' + (isActive ? ' active' : '')}> <div className={'articleItem' + (isActive ? ' active' : '')}>
<div className='itemLeft'> <div className='itemLeft'>
<ProfileImage className='profileImage' size='25' email={article.User.email}/> <ProfileImage className='profileImage' size='25' email={article.User.email}/>
<i className='fa fa-code fa-fw'></i> <i className='fa fa-code fa-fw'></i>
</div> </div>
<div className='itemRight'> <div className='itemRight'>
<div className='updatedAt'>{moment(article.updatedAt).fromNow()}</div> <div className='itemInfo'>{moment(article.updatedAt).fromNow()} by <span className='userProfileName'>{article.User.profileName}</span></div>
<div className='description'>{article.description.length > 50 ? article.description.substring(0, 50) + ' …' : article.description}</div> <div className='description'>{article.description}</div>
<div className='tags'><i className='fa fa-tags'/>{tags}</div> <div className='tags'><i className='fa fa-tags'/>{tags}</div>
</div> </div>
</div> </div>
@@ -55,16 +71,8 @@ module.exports = React.createClass({
) )
} }
handleClick = function () {
this.transitionTo('notes', {
userName: params.userName,
planetName: params.planetName,
localId: article.localId
})
}.bind(this)
return ( return (
<li onClick={handleClick} key={'note-' + article.id}> <li onClick={this.handleArticleClikck(article)} key={'note-' + article.id}>
<div className={'articleItem blueprintItem' + (isActive ? ' active' : '')}> <div className={'articleItem blueprintItem' + (isActive ? ' active' : '')}>
<div className='itemLeft'> <div className='itemLeft'>
<ProfileImage className='profileImage' size='25' email={article.User.email}/> <ProfileImage className='profileImage' size='25' email={article.User.email}/>
@@ -72,7 +80,7 @@ module.exports = React.createClass({
</div> </div>
<div className='itemRight'> <div className='itemRight'>
<div className='updatedAt'>{moment(article.updatedAt).fromNow()}</div> <div className='itemInfo'>{moment(article.updatedAt).fromNow()} by <span className='userProfileName'>{article.User.profileName}</span></div>
<div className='description'>{article.title}</div> <div className='description'>{article.title}</div>
<div className='tags'><i className='fa fa-tags'/>{tags}</div> <div className='tags'><i className='fa fa-tags'/>{tags}</div>
</div> </div>
@@ -85,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,
@@ -24,33 +25,57 @@ module.exports = React.createClass({
name: '', name: '',
public: true public: true
}, },
ownerName: ownerName ownerName: ownerName,
error: null
} }
}, },
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) {
this.props.close() case 'closeModal':
this.props.close()
break
case 'submitPlanetCreateModal':
this.handleSubmit()
break
} }
}, },
handleSubmit: function () { handleSubmit: function () {
Hq.createPlanet(this.state.ownerName, this.state.planet) this.setState({error: null}, function () {
.then(function (res) { Hq.createPlanet(this.state.ownerName, this.state.planet)
var planet = res.body .then(function (res) {
var planet = res.body
PlanetStore.Actions.update(planet) PlanetStore.Actions.update(planet)
if (this.props.transitionTo != null) { if (this.props.transitionTo != null) {
this.props.transitionTo('planetHome', {userName: planet.userName, planetName: planet.name}) this.props.transitionTo('planetHome', {userName: planet.userName, planetName: planet.name})
} }
this.props.close() this.props.close()
}.bind(this)) }.bind(this))
.catch(function (err) { .catch(function (err) {
console.error(err) console.error(err)
})
if (err.status == null) return this.setState({error: {message: 'Check your network connection'}})
switch (err.status) {
case 403:
this.setState({error: err.response.body})
break
case 422:
this.setState({error: {message: 'Planet name should be Alphanumeric with _, -'}})
break
case 409:
this.setState({error: {message: 'The entered name already in use'}})
break
default:
this.setState({error: {message: 'Unexpected error occured! please try again'}})
}
}.bind(this))
})
}, },
render: function () { render: function () {
var teamOptions = this.state.user.Teams.map(function (team) { var teamOptions = this.state.user.Teams.map(function (team) {
@@ -75,6 +100,8 @@ module.exports = React.createClass({
</select> </select>
</div> </div>
{this.state.error != null ? (<p className='errorAlert'>{this.state.error.message != null ? this.state.error.message : 'Error message undefined'}</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,29 +3,47 @@ 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({
name: React.PropTypes.string name: React.PropTypes.string,
Owner: React.PropTypes.shape({
id: React.PropTypes.number,
userType: React.PropTypes.string
})
}), }),
search: React.PropTypes.string, search: React.PropTypes.string,
toggleCodeFilter: React.PropTypes.func, toggleCodeFilter: React.PropTypes.func,
toggleNoteFilter: React.PropTypes.func toggleNoteFilter: React.PropTypes.func,
currentUser: React.PropTypes.shape({
id: React.PropTypes.number,
userType: React.PropTypes.string,
Teams: React.PropTypes.array
})
}, },
getInitialState: function () { getInitialState: function () {
return { return {
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})
}, },
isMyPlanet: function () {
if (this.props.currentUser == null) return false
if (this.props.planet.Owner.userType === 'person' && this.props.planet.Owner.id !== this.props.currentUser.id) return false
if (this.props.planet.Owner.userType === 'team' && !this.props.currentUser.Teams.some(function (team) {
if (team.id === this.props.planet.Owner.id) return true
return false
}.bind(this))) return false
return true
},
render: function () { render: function () {
var keywords = this.props.search.split(' ') var keywords = this.props.search.split(' ')
var usingCodeFilter = keywords.some(function (keyword) { var usingCodeFilter = keywords.some(function (keyword) {
@@ -39,9 +57,11 @@ var PlanetNavigator = React.createClass({
return ( return (
<div className='PlanetNavigator'> <div className='PlanetNavigator'>
<button onClick={this.openLaunchModal} className='launchButton btn-primary btn-block'> {this.isMyPlanet() ? (
<i className='fa fa-rocket fa-fw'/> Launch <button onClick={this.openLaunchModal} className='launchButton btn-primary btn-block'>
</button> <i className='fa fa-rocket fa-fw'/> Launch
</button>
) : null}
<nav className='articleFilters'> <nav className='articleFilters'>
<a className={usingCodeFilter && !usingNoteFilter ? 'active' : ''} onClick={this.props.toggleCodeFilter}> <a className={usingCodeFilter && !usingNoteFilter ? 'active' : ''} onClick={this.props.toggleCodeFilter}>
<i className='fa fa-code fa-fw'/> Codes <i className='fa fa-code fa-fw'/> Codes
@@ -54,5 +74,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'})
}, },
@@ -50,18 +58,44 @@ module.exports = React.createClass({
handleSavePlanetProfile: function (e) { handleSavePlanetProfile: function (e) {
var planet = this.props.planet var planet = this.props.planet
this.setState({profileSubmitStatus: 'sending'}, function () { this.setState({profileFormStatus: 'sending', profileFormError: null}, function () {
Hq.updatePlanet(planet.userName, planet.name, this.state.planet) Hq.updatePlanet(planet.userName, planet.name, this.state.planet)
.then(function (res) { .then(function (res) {
var planet = res.body var planet = res.body
console.log(planet)
this.setState({profileSubmitStatus: 'done'}) this.setState({profileFormStatus: 'done'})
PlanetStore.Actions.update(planet) PlanetStore.Actions.update(planet)
this.props.close()
}.bind(this)) }.bind(this))
.catch(function (err) { .catch(function (err) {
this.setState({profileSubmitStatus: 'error'})
console.error(err) console.error(err)
var newState = {
profileFormStatus: 'error'
}
if (err.status == null) {
newState.profileFormError = {message: 'Check your network connection'}
return this.setState(newState)
}
switch (err.status) {
case 403:
newState.profileFormError = err.response.body
this.setState(newState)
break
case 422:
newState.profileFormError = {message: 'Planet name should be Alphanumeric with _, -'}
this.setState(newState)
break
case 409:
newState.profileFormError = {message: 'The entered name already in use'}
this.setState(newState)
break
default:
newState.profileFormError = {message: 'Undefined error please try again'}
this.setState(newState)
}
}.bind(this)) }.bind(this))
}) })
}, },
@@ -91,9 +125,9 @@ module.exports = React.createClass({
content = this.state.currentTab === 'profile' ? this.renderPlanetProfileTab() : this.renderPlanetDeleteTab() content = this.state.currentTab === 'profile' ? this.renderPlanetProfileTab() : this.renderPlanetDeleteTab()
return ( return (
<div className='PlanetSettingModal modal tabModal'> <div className='PlanetSettingModal sideNavModal modal'>
<div className='leftPane'> <div className='leftPane'>
<h1 className='tabLabel'>Planet setting</h1> <h1 className='modalLabel'>Planet setting</h1>
<nav className='tabList'> <nav className='tabList'>
<button onClick={this.activePlanetProfile} className={this.state.currentTab === 'profile' ? 'active' : ''}><i className='fa fa-globe fa-fw'/> Planet profile</button> <button onClick={this.activePlanetProfile} className={this.state.currentTab === 'profile' ? 'active' : ''}><i className='fa fa-globe fa-fw'/> Planet profile</button>
<button onClick={this.activePlanetDelete} className={this.state.currentTab === 'delete' ? 'active' : ''}><i className='fa fa-trash fa-fw'/> Delete Planet</button> <button onClick={this.activePlanetDelete} className={this.state.currentTab === 'delete' ? 'active' : ''}><i className='fa fa-trash fa-fw'/> Delete Planet</button>
@@ -108,7 +142,7 @@ module.exports = React.createClass({
}, },
renderPlanetProfileTab: function () { renderPlanetProfileTab: function () {
return ( return (
<div className='planetProfileTab'> <div className='planetProfileTab tab'>
<div className='formField'> <div className='formField'>
<label>Planet name </label> <label>Planet name </label>
<input valueLink={this.linkState('planet.name')}/> <input valueLink={this.linkState('planet.name')}/>
@@ -122,11 +156,11 @@ module.exports = React.createClass({
<div className='formConfirm'> <div className='formConfirm'>
<button onClick={this.handleSavePlanetProfile} className='saveButton btn-primary'>Save</button> <button onClick={this.handleSavePlanetProfile} className='saveButton btn-primary'>Save</button>
<div className={'alertInfo' + (this.state.profileSubmitStatus === 'sending' ? '' : ' hide')}>on Sending...</div> <div className={'alertInfo' + (this.state.profileFormStatus === 'sending' ? '' : ' hide')}>on Sending...</div>
<div className={'alertError' + (this.state.profileSubmitStatus === 'error' ? '' : ' hide')}>Connection failed.. Try again.</div> <div className={'alertError' + (this.state.profileFormStatus === 'error' ? '' : ' hide')}>{this.state.profileFormError != null ? this.state.profileFormError.message : 'Unexpected error occured! please try again'}</div>
<div className={'alertSuccess' + (this.state.profileSubmitStatus === 'done' ? '' : ' hide')}>Successfully done!!</div> <div className={'alertSuccess' + (this.state.profileFormStatus === 'done' ? '' : ' hide')}>Successfully done!!</div>
</div> </div>
</div> </div>
) )
@@ -135,7 +169,7 @@ module.exports = React.createClass({
var disabled = !this.state.deleteConfirmation.match(new RegExp('^' + this.props.planet.userName + '/' + this.props.planet.name + '$')) var disabled = !this.state.deleteConfirmation.match(new RegExp('^' + this.props.planet.userName + '/' + this.props.planet.name + '$'))
return ( return (
<div className='planetDeleteTab'> <div className='planetDeleteTab tab'>
<p>Are you sure to destroy <strong>'{this.props.planet.userName + '/' + this.props.planet.name}'</strong>?</p> <p>Are you sure to destroy <strong>'{this.props.planet.userName + '/' + this.props.planet.name}'</strong>?</p>
<p>If you are sure, write <strong>'{this.props.planet.userName + '/' + this.props.planet.name}'</strong> to input below and click <strong>'{this.state.randomDeleteText}'</strong> button.</p> <p>If you are sure, write <strong>'{this.props.planet.userName + '/' + this.props.planet.name}'</strong> to input below and click <strong>'{this.state.randomDeleteText}'</strong> button.</p>
<input valueLink={this.linkState('deleteConfirmation')} placeholder='userName/planetName'/> <input valueLink={this.linkState('deleteConfirmation')} placeholder='userName/planetName'/>

View File

@@ -0,0 +1,112 @@
var ipc = require('ipc')
var remote = require('remote')
var React = require('react/addons')
var LinkedState = require('../Mixins/LinkedState')
var ExternalLink = require('../Mixins/ExternalLink')
var KeyCaster = require('../Mixins/KeyCaster')
module.exports = React.createClass({
mixins: [LinkedState, ExternalLink, KeyCaster('aboutModal')],
propTypes: {
close: React.PropTypes.func
},
getInitialState: function () {
var keymap = remote.getGlobal('keymap')
console.log(keymap)
return {
currentTab: 'settings',
keymap: keymap
}
},
onKeyCast: function (e) {
switch (e.status) {
case 'closeModal':
this.props.close()
break
}
},
activeSettings: function () {
this.setState({currentTab: 'settings'})
},
activeAbout: function () {
this.setState({currentTab: 'about'})
},
saveKeymap: function () {
ipc.send('hotkeyUpdated', JSON.stringify(this.state.keymap))
},
render: function () {
var content = this.state.currentTab === 'settings' ? this.renderSettingsTab() : this.renderAboutTab()
return (
<div className='PreferencesModal sideNavModal modal'>
<div className='leftPane'>
<h1 className='modalLabel'>Preferences</h1>
<nav className='tabList'>
<button onClick={this.activeSettings} className={this.state.currentTab === 'settings' ? 'active' : ''}><i className='fa fa-gear fa-fw'/> Settings</button>
<button onClick={this.activeAbout} className={this.state.currentTab === 'about' ? 'active' : ''}><i className='fa fa-info-circle fa-fw'/> About this app</button>
</nav>
</div>
<div className='rightPane'>
{content}
</div>
</div>
)
},
renderSettingsTab: function () {
return (
<div className='settingsTab tab'>
<div className='categoryLabel'>Hotkey</div>
<div className='formField'>
<label>Toggle finder</label>
<input valueLink={this.linkState('keymap.toggleFinder')}/>
</div>
<div className='formConfirm'>
<button onClick={this.saveKeymap}>Save</button>
</div>
<div className='example'>
<h3>Example</h3>
<ul>
<li><code>0</code> to <code>9</code></li>
<li><code>A</code> to <code>Z</code></li>
<li><code>F1</code> to <code>F24</code></li>
<li>Punctuations like <code>~</code>, <code>!</code>, <code>@</code>, <code>#</code>, <code>$</code>, etc.</li>
<li><code>Plus</code></li>
<li><code>Space</code></li>
<li><code>Backspace</code></li>
<li><code>Delete</code></li>
<li><code>Insert</code></li>
<li><code>Return</code> (or <code>Enter</code> as alias)</li>
<li><code>Up</code>, <code>Down</code>, <code>Left</code> and <code>Right</code></li>
<li><code>Home</code> and <code>End</code></li>
<li><code>PageUp</code> and <code>PageDown</code></li>
<li><code>Escape</code> (or <code>Esc</code> for short)</li>
<li><code>VolumeUp</code>, <code>VolumeDown</code> and <code>VolumeMute</code></li>
<li><code>MediaNextTrack</code>, <code>MediaPreviousTrack</code>, <code>MediaStop</code> and <code>MediaPlayPause</code></li>
</ul>
</div>
</div>
)
},
renderAboutTab: function () {
var version = global.version
return (
<div className='aboutTab tab'>
<div className='about1'>
<img className='logo' src='resources/favicon-230x230.png'/>
<div className='appInfo'>Boost {version == null || version.length === 0 ? 'DEV version' : 'v' + version}</div>
</div>
<div className='about2'>
<div className='externalLabel'>External links</div>
<ul className='externalList'>
<li><a onClick={this.openExternal} href='http://b00st.io'>Boost Homepage <i className='fa fa-external-link'/></a></li>
<li><a onClick={this.openExternal} href='http://boostio.github.io/regulations.html'>Regulation <i className='fa fa-external-link'/></a></li>
<li><a onClick={this.openExternal} href='http://boostio.github.io/privacypolicies.html'>Private policy <i className='fa fa-external-link'/></a></li>
</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 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
@@ -21,33 +22,62 @@ module.exports = React.createClass({
return { return {
team: { team: {
name: '' name: ''
} },
error: null
}
},
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) this.setState({error: null}, function () {
.then(function (res) { Hq.createTeam(this.props.user.name, this.state.team)
var currentUser = JSON.parse(localStorage.getItem('currentUser')) .then(function (res) {
var team = res.body var currentUser = JSON.parse(localStorage.getItem('currentUser'))
var team = res.body
currentUser.Teams.push(team) currentUser.Teams.push(team)
localStorage.setItem('currentUser', JSON.stringify(currentUser)) localStorage.setItem('currentUser', JSON.stringify(currentUser))
UserStore.Actions.update(currentUser) UserStore.Actions.update(currentUser)
if (this.props.transitionTo != null) { if (this.props.transitionTo != null) {
this.props.transitionTo('userHome', {userName: team.name}) this.props.transitionTo('userHome', {userName: team.name})
} }
this.props.close() this.props.close()
}.bind(this)) }.bind(this))
.catch(function (err) { .catch(function (err) {
console.error(err) console.error(err)
})
if (err.status == null) return this.setState({error: {message: 'Check your network connection'}})
switch (err.status) {
case 422:
this.setState({error: {message: 'Team name should be Alphanumeric with _, -'}})
break
case 409:
this.setState({error: {message: 'The entered name already in use'}})
break
default:
this.setState({error: {message: 'Error message undefined'}})
}
}.bind(this))
})
}, },
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'/>
{this.state.error != null ? (<p className='errorAlert'>{this.state.error.message != null ? this.state.error.message : 'Unintended error occured'}</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

@@ -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) {
@@ -167,9 +176,9 @@ module.exports = React.createClass({
} }
return ( return (
<div className='TeamSettingsModal modal tabModal'> <div className='TeamSettingsModal sideNavModal modal'>
<div className='leftPane'> <div className='leftPane'>
<div className='tabLabel'>Team settings</div> <div className='modalLabel'>Team settings</div>
<div className='tabList'> <div className='tabList'>
<button className={this.state.currentTab === 'teamInfo' ? 'active' : ''} onClick={this.selectTab('teamInfo')}><i className='fa fa-info-circle fa-fw'/> Team Info</button> <button className={this.state.currentTab === 'teamInfo' ? 'active' : ''} onClick={this.selectTab('teamInfo')}><i className='fa fa-info-circle fa-fw'/> Team Info</button>
<button className={this.state.currentTab === 'members' ? 'active' : ''} onClick={this.selectTab('members')}><i className='fa fa-users fa-fw'/> Members</button> <button className={this.state.currentTab === 'members' ? 'active' : ''} onClick={this.selectTab('members')}><i className='fa fa-users fa-fw'/> Members</button>
@@ -183,7 +192,7 @@ module.exports = React.createClass({
}, },
renderTeamInfoTab: function () { renderTeamInfoTab: function () {
return ( return (
<div className='userInfoTab'> <div className='userInfoTab tab'>
<div className='formField'> <div className='formField'>
<label>Profile Name</label> <label>Profile Name</label>
<input valueLink={this.linkState('team.profileName')}/> <input valueLink={this.linkState('team.profileName')}/>
@@ -230,7 +239,7 @@ module.exports = React.createClass({
var belowLimit = members.length < 5 var belowLimit = members.length < 5
return ( return (
<div className='membersTab'> <div className='membersTab tab'>
<table className='memberTable'> <table className='memberTable'>
<thead> <thead>
<tr> <tr>
@@ -264,7 +273,7 @@ module.exports = React.createClass({
</div> </div>
) : ( ) : (
<div> <div>
Maximum numbr of members is 5 on Beta version. Please contact us if you want futher use. Maximum number of members is 5 on Beta version. Please contact us if you want futher use.
</div> </div>
)} )}
</div> </div>

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

@@ -55,7 +55,6 @@ module.exports = React.createClass({
return return
} else { } else {
this.transitionTo('home') this.transitionTo('home')
return
} }
} }
@@ -96,7 +95,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}
@@ -358,7 +399,8 @@ module.exports = React.createClass({
showAll={this.showAll} showAll={this.showAll}
toggleCodeFilter={this.toggleCodeFilter} toggleCodeFilter={this.toggleCodeFilter}
toggleNoteFilter={this.toggleNoteFilter} toggleNoteFilter={this.toggleNoteFilter}
planet={this.state.planet}/> planet={this.state.planet}
currentUser={this.state.currentUser}/>
<PlanetArticleList showOnlyWithTag={this.applyTagFilter} ref='list' articles={filteredArticles}/> <PlanetArticleList showOnlyWithTag={this.applyTagFilter} ref='list' articles={filteredArticles}/>

View File

@@ -6,10 +6,11 @@ var Link = ReactRouter.Link
var AuthFilter = require('../Mixins/AuthFilter') var AuthFilter = require('../Mixins/AuthFilter')
var LinkedState = require('../Mixins/LinkedState') var LinkedState = require('../Mixins/LinkedState')
var ExternalLink = require('../Mixins/ExternalLink')
var Hq = require('../Services/Hq') var Hq = require('../Services/Hq')
module.exports = React.createClass({ module.exports = React.createClass({
mixins: [LinkedState, ReactRouter.Navigation, AuthFilter.OnlyGuest], mixins: [LinkedState, ReactRouter.Navigation, AuthFilter.OnlyGuest, ExternalLink],
getInitialState: function () { getInitialState: function () {
return { return {
user: {}, user: {},
@@ -129,7 +130,7 @@ module.exports = React.createClass({
</div> </div>
</form> </form>
<p className='alert'>会員登録することで当サイトの利用規約及びCookieの使用を含むデータに関するポリシーに同意するものとします</p> <p className='alert'>会員登録することで<a onClick={this.openExternal} href='http://boostio.github.io/regulations.html'>当サイトの利用規約</a>及び<a onClick={this.openExternal} href='http://boostio.github.io/privacypolicies.html'>Cookieの使用を含むデータに関するポリシー</a>に同意するものとします</p>
</div> </div>
) )
} }

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>
@@ -317,7 +318,7 @@ module.exports = React.createClass({
}) })
return ( return (
<div key={'user-' + team.id} className='planetGroup'> <div key={'user-' + team.id} className='planetGroup'>
<div className='planetGroupLabel'>{team.name}</div> <div className='planetGroupLabel'>{team.profileName} <small>@{team.name}</small></div>
<ul className='planets'> <ul className='planets'>
{planets} {planets}
{isOwner ? (<li><button onClick={this.openPlanetCreateModalWithOwnerName(team.name)} className='createPlanetButton'><i className='fa fa-plus-square-o'/> Create new planet</button></li>) : null} {isOwner ? (<li><button onClick={this.openPlanetCreateModalWithOwnerName(team.name)} className='createPlanetButton'><i className='fa fa-plus-square-o'/> Create new planet</button></li>) : null}
@@ -352,7 +353,7 @@ module.exports = React.createClass({
<div className='planetList'> <div className='planetList'>
<div className='planetLabel'>{planetCount} {planetCount > 1 ? 'Planets' : 'Planet'}</div> <div className='planetLabel'>{planetCount} {planetCount > 1 ? 'Planets' : 'Planet'}</div>
<div className='planetGroup'> <div className='planetGroup'>
<div className='planetGroupLabel'>{user.profileName}</div> <div className='planetGroupLabel'>{user.profileName} <small>@{user.name}</small></div>
<ul className='planets'> <ul className='planets'>
{userPlanets} {userPlanets}
{isOwner ? (<li><button onClick={this.openPlanetCreateModalWithOwnerName(user.name)} className='createPlanetButton'><i className='fa fa-plus-square-o'/> Create new planet</button></li>) : null} {isOwner ? (<li><button onClick={this.openPlanetCreateModalWithOwnerName(user.name)} className='createPlanetButton'><i className='fa fa-plus-square-o'/> Create new planet</button></li>) : null}

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

@@ -53,6 +53,14 @@ module.exports = Reflux.createStore({
localStorage.setItem('currentUser', JSON.stringify(currentUser)) localStorage.setItem('currentUser', JSON.stringify(currentUser))
UserStore.Actions.update(currentUser) UserStore.Actions.update(currentUser)
planet.Codes.forEach(function (code) {
code.type = 'code'
})
planet.Notes.forEach(function (note) {
note.type = 'note'
})
// Update the planet // Update the planet
localStorage.setItem('planet-' + planet.id, JSON.stringify(planet)) localStorage.setItem('planet-' + planet.id, JSON.stringify(planet))

View File

@@ -1,16 +1,55 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<script>
var version = require('remote').getGlobal('version')
document.title = 'Boost ' + ((version == null || version.length === 0) ? 'DEV version' : 'v' + version)
</script>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" title="no title" charset="utf-8"> <link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" title="no title" charset="utf-8">
<link rel="shortcut icon" href="favicon.ico"> <link rel="shortcut icon" href="favicon.ico">
<style>
@font-face {
font-family: 'Lato';
src: url('../../Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
url('../../Lato-Regular.woff') format('woff'), /* Modern Browsers */
url('../../Lato-Regular.ttf') format('truetype');
font-style: normal;
font-weight: normal;
text-rendering: optimizeLegibility;
}
#loadingCover{
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
box-sizing: border-box;
padding: 65px 0;
font-family: sans-serif;
}
#loadingCover img{
display: block;
margin: 75px auto 5px;
width: 160px;
height: 160px;
}
#loadingCover .message{
font-size: 30px;
text-align: center;
line-height: 1.6;
font-weight: 100;
color: #888;
}
</style>
</head>
<body>
<div id="loadingCover">
<img src="resources/favicon-230x230.png">
<div class='message'>Loading...</div>
</div>
<div id="content"></div>
<script> <script>
if (!Object.assign) { if (!Object.assign) {
Object.defineProperty(Object, 'assign', { Object.defineProperty(Object, 'assign', {
@@ -45,13 +84,14 @@
}); });
} }
require('electron-stylus')(__dirname + '/../styles/main/index.styl')
</script> </script>
</head>
<body>
<div id="content"></div>
<script src="../ace/src-min/ace.js"></script> <script src="../ace/src-min/ace.js"></script>
<script> <script>
var version = require('remote').require('app').getVersion()
global.version = version
document.title = 'Boost ' + ((version == null || version.length === 0) ? 'DEV version' : 'v' + version)
require('../electron-stylus')(__dirname + '/../styles/main/index.styl', 'mainCss')
// require('../electron-stylus')(__dirname + '/../styles/main/index.styl')
require('node-jsx').install({ harmony: true, extension: '.jsx' }) require('node-jsx').install({ harmony: true, extension: '.jsx' })
require('./index.jsx') require('./index.jsx')
</script> </script>

View File

@@ -34,7 +34,13 @@ var routes = (
</Route> </Route>
</Route> </Route>
) )
var loadingCover = document.getElementById('loadingCover')
ReactRouter.run(routes, ReactRouter.HashLocation, function (Root) { ReactRouter.run(routes, ReactRouter.HashLocation, function (Root) {
React.render(<Root/>, document.getElementById('content')) React.render(<Root/>, document.getElementById('content'))
if (loadingCover != null) {
loadingCover.parentNode.removeChild(loadingCover)
loadingCover = null
}
}) })

View File

@@ -46,6 +46,9 @@ body
border solid 2px transparent border solid 2px transparent
box-sizing border-box box-sizing border-box
cursor pointer cursor pointer
white-space nowrap
overflow-x hidden
text-overflow ellipsis
.divider .divider
box-sizing border-box box-sizing border-box
border-bottom solid 1px borderColor border-bottom solid 1px borderColor
@@ -65,6 +68,9 @@ body
border-bottom solid 1px borderColor border-bottom solid 1px borderColor
line-height 44px line-height 44px
font-size 1.3em font-size 1.3em
white-space nowrap
text-overflow ellipsis
overflow-x hidden
.content .content
.ace_editor, .marked .ace_editor, .marked
position absolute position absolute

View File

@@ -10,7 +10,7 @@ articleListWidth= 275px
margin 0 2px margin 0 2px
text-decoration underline text-decoration underline
cursor pointer cursor pointer
font-size 0.9em font-size 0.95em
&.noTag &.noTag
color inactiveTextColor color inactiveTextColor
font-size 0.8em font-size 0.8em
@@ -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
transition 0.1s img
opacity 0.9 transition 0.1s
&:hover, &.hover opacity 0.9
&: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,33 +186,51 @@ articleListWidth= 275px
overflow-y auto overflow-y auto
li li
.articleItem .articleItem
user-select none noSelect()
border solid 2px transparent border solid 2px transparent
padding 10px position relative
height 94px
width 100%
cursor pointer cursor pointer
transition 0.1s transition 0.1s
clearfix()
.itemLeft .itemLeft
float left position absolute
width 25px top 4px
bottom 4px
width 38px
padding 3px 0 3px 3px
text-align center text-align center
.profileImage .profileImage
margin-bottom 5px margin-bottom 5px
circle()
.fa .fa
line-height 25px line-height 25px
.itemRight .itemRight
float left position absolute
width 225px top 4px
bottom 4px
right 2px
left 40px
overflow-x hidden overflow-x hidden
padding-left 10px padding 3px 10px 3px 3px
.updatedAt .itemInfo
margin-bottom 10px margin 5px 0 13px
color lighten(textColor, 25%) color lighten(textColor, 25%)
font-size 0.7em font-size 0.7em
.userProfileName
color brandColor
font-size 1.2em
.description .description
line-height 120% line-height 120%
margin-bottom 15px margin-bottom 10px
font-size 1em font-size 1em
overflow-x hidden
white-space nowrap
text-overflow ellipsis
.tags
position absolute
bottom 5px
font-size 0.9em
&:hover, &.hover &:hover, &.hover
background-color hoverBackgroundColor background-color hoverBackgroundColor
&:active, &.active &:active, &.active
@@ -218,57 +244,89 @@ articleListWidth= 275px
absolute right bottom absolute right bottom
top 55px top 55px
left navigationWidth + articleListWidth left navigationWidth + articleListWidth
&>.viewer-header .detailHeader
height 44px border solid 2px transparent
line-height 44px position relative
padding 0 15px height 105px
box-sizing border-box width 100%
font-size 1.2em transition 0.1s
small .itemLeft
font-size 0.8em position absolute
color lighten(textColor, 25%) top 7px
.control-group bottom 4px
float right width 38px
button padding 3px 0 3px 3px
margin 10px 3px text-align center
.viewer-body .profileImage
absolute bottom right margin-bottom 5px
left 1px circle()
top 44px .fa
&.codeDetail>.viewer-body line-height 25px
.viewer-detail .itemRight
border-bottom solid 1px borderColor position absolute
height 150px top 7px
box-sizing border-box bottom 4px
padding 10px right 2px
left 40px
overflow-x hidden
padding 3px 10px 3px 3px
.itemInfo
margin 5px 0 13px
color lighten(textColor, 25%)
font-size 0.7em
.userProfileName
color brandColor
font-size 1.2em
.description .description
height 100px line-height 120%
line-height 1.4em margin-bottom 10px
overflow-y auto font-size 1em
overflow-x auto
white-space nowrap
.tags .tags
position absolute position absolute
left 15px
right 15px
top 120px
.content
.ace_editor
absolute left right
top 155px
bottom 5px bottom 5px
&.noteDetail>.viewer-body font-size 0.9em
.tags .itemControl
absolute top position absolute
left 15px z-index 1
right 15px top 2px
height 24px right 2px
line-height 24px .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
absolute left right bottom
top 105px
.content .content
absolute left right bottom position absolute
top 30px top 5px
bottom 5px
left 2px
right 2px
box-sizing border-box box-sizing border-box
padding 5px padding 5px
border-top solid 1px borderColor border-top solid 1px borderColor
padding 10px &.noteDetail
.detailBody .content
overflow-x hidden overflow-x hidden
overflow-y auto overflow-y auto
marked() 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
@@ -63,19 +64,12 @@
&:hover &:hover
background-color hoverBackgroundColor background-color hoverBackgroundColor
.userName .userName
float left
width 155px width 155px
padding 10px 15px padding 10px 15px
text-align left text-align left
display block display block
text-decoration none text-decoration none
cursor pointer cursor pointer
.userSetting
float right
display block
padding 10px 0
width 45px
cursor pointer
.createNewTeam .createNewTeam
btnStripDefault() btnStripDefault()
width 100% width 100%
@@ -166,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
@@ -189,7 +172,7 @@
.memberPopup .memberPopup
absolute left absolute left
top 235px top 235px
z-index popupZIndex z-index 1
padding 0 15px 10px padding 0 15px 10px
width 200px width 200px
.label .label
@@ -205,13 +188,15 @@
.memberImage .memberImage
float left float left
margin-right 7px margin-right 7px
circle()
.memberInfo .memberInfo
float left float left
.memberProfileName .memberProfileName
margin-bottom 5px margin-bottom 5px
font-size 1.05em
.memberName .memberName
margin-left 5px margin-left 5px
font-size 0.8em font-size 0.9em
color inactiveTextColor color inactiveTextColor
a:hover .memberProfileName, a:hover .memberName a:hover .memberProfileName, a:hover .memberName
text-decoration underline text-decoration underline
@@ -259,9 +244,10 @@
float left float left
.teamProfileName .teamProfileName
margin-bottom 5px margin-bottom 5px
font-size 1.05em
.teamName .teamName
margin-left 5px margin-left 5px
font-size 0.8em font-size 0.9em
color inactiveTextColor color inactiveTextColor
a:hover .teamProfileName, a:hover .teamName a:hover .teamProfileName, a:hover .teamName
text-decoration underline text-decoration underline
@@ -277,16 +263,18 @@
.memberImage .memberImage
float left float left
margin-right 7px margin-right 7px
circle()
.memberInfo .memberInfo
float left float left
.memberProfileName .memberProfileName
margin-bottom 5px margin-bottom 5px
font-size 1.05em
.memberRole .memberRole
font-size 0.8em font-size 0.9em
color inactiveTextColor color inactiveTextColor
.memberName .memberName
margin-left 5px margin-left 5px
font-size 0.8em font-size 0.9em
color inactiveTextColor color inactiveTextColor
.createTeamButton, .addMemberButton .createTeamButton, .addMemberButton
btnStripDefault() btnStripDefault()
@@ -306,6 +294,9 @@
.planetGroupLabel .planetGroupLabel
font-size 1.1em font-size 1.1em
margin-bottom 15px margin-bottom 15px
small
font-size 0.8em
color inactiveTextColor
.planets .planets
margin-left 15px margin-left 15px
li li

View File

@@ -7,15 +7,17 @@ global-reset()
@import './containers/*' @import './containers/*'
html, body html, body
width 100% width 100%
height 100% height 100%
overflow hidden overflow hidden
body body
font-family "Lato" font-family "Lato"
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
@@ -105,14 +107,22 @@ textarea.block-input
z-index 2000 z-index 2000
bottom 5px bottom 5px
right 53px right 53px
btnDefault() btnPrimary()
padding 10px 15px padding 10px 15px
border-radius 5px border-radius 5px
background-color backgroundColor
.contactButton .contactButton
position fixed position fixed
z-index 2000 z-index 2000
bottom 5px bottom 5px
right 5px right 5px
btnDefault() btnPrimary()
padding 10px 15px padding 10px 15px
border-radius 5px border-radius 5px
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,38 @@ 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
background-color #F6F6F6
pre pre
padding 5px padding 5px
border solid 1px borderColor border solid 1px borderColor
border-radius 5px border-radius 5px
margin 0.5em 0
overflow-x auto overflow-x auto
margin-bottom 15px
background-color #F6F6F6
&>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 +95,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

@@ -32,14 +32,14 @@
.modal-control .modal-control
float right float right
.tabModal .sideNavModal
height 500px height 500px
.leftPane .leftPane
absolute top bottom left absolute top bottom left
width 175px width 175px
padding 20px padding 20px
border-right solid 1px borderColor border-right solid 1px borderColor
.tabLabel .modalLabel
font-size 1.5em font-size 1.5em
margin-top 25px margin-top 25px
margin-bottom 35px margin-bottom 35px
@@ -57,9 +57,7 @@
left 175px left 175px
padding 15px padding 15px
overflow-y auto overflow-y auto
.tab
.EditProfileModal, .PlanetSettingModal, .TeamSettingsModal
.userInfoTab, .passwordTab, .planetProfileTab, .userInfoTab, .membersTab
padding-top 45px padding-top 45px
.formField .formField
position relative position relative
@@ -97,7 +95,7 @@
float right float right
padding 12px 10px padding 12px 10px
border-radius 5px border-radius 5px
width 200px width 320px
font-size 1em font-size 1em
overflow-x hidden overflow-x hidden
white-space nowrap white-space nowrap
@@ -111,6 +109,33 @@
alertSuccess() alertSuccess()
.alertError .alertError
alertError() alertError()
.PreferencesModal
.settingsTab
.categoryLabel
font-size 1.5em
margin-bottom 25px
.example
marked()
.aboutTab
padding-top 30px
.about1
margin-bottom 25px
.logo
display block
margin 0 auto
.appInfo
font-size 1.5em
text-align center
.about2
width 200px
margin 0 auto
.externalLabel
font-size 1.2em
margin-bottom 15px
.externalList
li
margin-bottom 15px
.PlanetSettingModal
.planetDeleteTab .planetDeleteTab
padding-top 65px padding-top 65px
p p
@@ -139,7 +164,7 @@
float right float right
padding 12px 10px padding 12px 10px
border-radius 5px border-radius 5px
width 200px width 320px
font-size 1em font-size 1em
overflow-x hidden overflow-x hidden
white-space nowrap white-space nowrap
@@ -153,6 +178,7 @@
alertSuccess() alertSuccess()
.alertError .alertError
alertError() alertError()
.TeamSettingsModal
.membersTab .membersTab
.memberTable .memberTable
width 100% width 100%
@@ -196,7 +222,6 @@
border-radius 5px border-radius 5px
float left float left
.LaunchModal .LaunchModal
.modal-tab .modal-tab
text-align center text-align center
@@ -263,25 +288,6 @@
border-radius 5px border-radius 5px
marked() marked()
.AboutModal
width 320px
.about1
margin-bottom 25px
.logo
display block
margin 0 auto
.appInfo
font-size 1.5em
text-align center
.about2
width 200px
margin 0 auto
.externalLabel
font-size 1.2em
margin-bottom 15px
.externalList
li
margin-bottom 15px
.PlanetCreateModal.modal, .TeamCreateModal.modal, .AddMemberModal.modal .PlanetCreateModal.modal, .TeamCreateModal.modal, .AddMemberModal.modal
padding 60px 0 padding 60px 0
@@ -314,6 +320,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 +355,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

@@ -1,4 +1,4 @@
module.exports = { module.exports = {
apiUrl: 'http://codexen-server-dev2.elasticbeanstalk.com/' apiUrl: 'https://api.b00st.io/'
// apiUrl: 'http://localhost:8000/' // apiUrl: 'http://localhost:8000/'
} }

73
main.js
View File

@@ -4,6 +4,7 @@ var Menu = require('menu')
var MenuItem = require('menu-item') var MenuItem = require('menu-item')
var Tray = require('tray') var Tray = require('tray')
var ipc = require('ipc') var ipc = require('ipc')
var jetpack = require('fs-jetpack')
require('crash-reporter').start() require('crash-reporter').start()
@@ -19,7 +20,6 @@ var update = null
// }) // })
var version = app.getVersion() var version = app.getVersion()
global.version = version
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
var nn = require('node-notifier') var nn = require('node-notifier')
var autoUpdater = require('auto-updater') var autoUpdater = require('auto-updater')
@@ -27,6 +27,7 @@ var path = require('path')
autoUpdater autoUpdater
.on('error', function (err, message) { .on('error', function (err, message) {
console.error(message)
nn.notify({ nn.notify({
title: 'Error! ' + versionText, title: 'Error! ' + versionText,
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'), icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
@@ -34,11 +35,7 @@ autoUpdater
}) })
}) })
.on('checking-for-update', function () { .on('checking-for-update', function () {
nn.notify({ // Connecting
title: 'Boost launched!! ' + versionText,
icon: path.join(__dirname, 'browser/main/resources/favicon-230x230.png'),
message: 'Checking update is available....'
})
}) })
.on('update-available', function () { .on('update-available', function () {
nn.notify({ nn.notify({
@@ -85,7 +82,7 @@ app.on('ready', function () {
Menu.setApplicationMenu(menu) Menu.setApplicationMenu(menu)
// menu end // menu end
appIcon = new Tray(__dirname + '/tray-icon.png') appIcon = new Tray(__dirname + '/tray-icon.png')
appIcon.setToolTip('Codexen') appIcon.setToolTip('Boost')
var trayMenu = new Menu() var trayMenu = new Menu()
trayMenu.append(new MenuItem({ trayMenu.append(new MenuItem({
@@ -131,9 +128,10 @@ app.on('ready', function () {
'zoom-factor': 1.0, 'zoom-factor': 1.0,
'always-on-top': true, 'always-on-top': true,
'web-preferences': { 'web-preferences': {
'overlay-scrollbars': true, 'overlay-scrollbars': true,
'skip-taskbar': true 'skip-taskbar': true
} },
'standard-window': false
}) })
popUpWindow.loadUrl('file://' + __dirname + '/browser/finder/index.electron.html') popUpWindow.loadUrl('file://' + __dirname + '/browser/finder/index.electron.html')
@@ -141,15 +139,53 @@ app.on('ready', function () {
popUpWindow.on('blur', function () { popUpWindow.on('blur', function () {
popUpWindow.hide() popUpWindow.hide()
}) })
popUpWindow.setVisibleOnAllWorkspaces(true) popUpWindow.setVisibleOnAllWorkspaces(true)
var globalShortcut = require('global-shortcut') var globalShortcut = require('global-shortcut')
console.log('jetpack launch')
var userDataPath = app.getPath('userData')
if (!jetpack.cwd(userDataPath).exists('keymap.json')) {
jetpack.cwd(userDataPath).file('keymap.json', {content: '{}'})
}
try {
global.keymap = JSON.parse(jetpack.cwd(userDataPath).read('keymap.json', 'utf-8'))
} catch (err) {
jetpack.cwd(userDataPath).file('keymap.json', {content: '{}'})
global.keymap = {}
}
if (global.keymap.toggleFinder == null) global.keymap.toggleFinder = 'ctrl+tab+shift'
var toggleFinderKey = global.keymap.toggleFinder
globalShortcut.register('ctrl+tab+shift', function () { try {
if (mainWindow != null && !mainWindow.isFocused()) { globalShortcut.register(toggleFinderKey, function () {
mainWindow.hide() if (mainWindow != null && !mainWindow.isFocused()) {
mainWindow.hide()
}
popUpWindow.show()
})
} catch (err) {
console.log(err.name)
}
ipc.on('hotkeyUpdated', function (event, newKeymap) {
console.log('got new keymap')
console.log(newKeymap)
globalShortcut.unregisterAll()
global.keymap = JSON.parse(newKeymap)
jetpack.cwd(userDataPath).file('keymap.json', {content: JSON.stringify(global.keymap)})
var toggleFinderKey = global.keymap.toggleFinder != null ? global.keymap.toggleFinder : 'ctrl+tab+shift'
try {
globalShortcut.register(toggleFinderKey, function () {
if (mainWindow != null && !mainWindow.isFocused()) {
mainWindow.hide()
}
popUpWindow.show()
})
} catch (err) {
console.log(err.name)
} }
popUpWindow.show()
}) })
global.hideFinder = function () { global.hideFinder = function () {
@@ -167,8 +203,9 @@ function makeNewMainWindow () {
height: 720, height: 720,
'zoom-factor': 1.0, 'zoom-factor': 1.0,
'web-preferences': { 'web-preferences': {
'overlay-scrollbars': true 'overlay-scrollbars': true
} },
'standard-window': false
}) })
if (update != null) { if (update != null) {
mainWindow.webContents.on('did-finish-load', function () { mainWindow.webContents.on('did-finish-load', function () {
@@ -178,6 +215,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

@@ -5,7 +5,7 @@ module.exports = [
label: 'Electron', label: 'Electron',
submenu: [ submenu: [
{ {
label: 'About Electron', label: 'About Boost',
selector: 'orderFrontStandardAboutPanel:' selector: 'orderFrontStandardAboutPanel:'
}, },
{ {
@@ -19,7 +19,7 @@ module.exports = [
type: 'separator' type: 'separator'
}, },
{ {
label: 'Hide Electron', label: 'Hide Boost',
accelerator: 'Command+H', accelerator: 'Command+H',
selector: 'hide:' selector: 'hide:'
}, },

View File

@@ -1,6 +1,6 @@
{ {
"name": "boost", "name": "boost",
"version": "0.2.1", "version": "0.2.10",
"description": "Boost App", "description": "Boost App",
"main": "main.js", "main": "main.js",
"scripts": { "scripts": {
@@ -31,8 +31,8 @@
}, },
"homepage": "https://github.com/Rokt33r/codexen-app#readme", "homepage": "https://github.com/Rokt33r/codexen-app#readme",
"dependencies": { "dependencies": {
"electron-stylus": "^0.1.0",
"font-awesome": "^4.3.0", "font-awesome": "^4.3.0",
"fs-jetpack": "^0.7.0",
"markdown-it": "^4.3.1", "markdown-it": "^4.3.1",
"md5": "^2.0.0", "md5": "^2.0.0",
"moment": "^2.10.3", "moment": "^2.10.3",
@@ -43,6 +43,7 @@
"react-router": "^0.13.3", "react-router": "^0.13.3",
"react-select": "^0.5.4", "react-select": "^0.5.4",
"reflux": "^0.2.8", "reflux": "^0.2.8",
"stylus": "^0.52.0",
"superagent": "^1.2.0", "superagent": "^1.2.0",
"superagent-promise": "^1.0.3" "superagent-promise": "^1.0.3"
}, },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 463 B

After

Width:  |  Height:  |  Size: 959 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 924 B

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB