mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 10:16:26 +00:00
Compare commits
41 Commits
0.4.1-beta
...
v0.4.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b384b1d15 | ||
|
|
a1d61edb9c | ||
|
|
96a8687896 | ||
|
|
0448773682 | ||
|
|
57998ba727 | ||
|
|
de83447cb3 | ||
|
|
eba19468d5 | ||
|
|
65c78df671 | ||
|
|
a7096aa89f | ||
|
|
15a50ef452 | ||
|
|
04036e5c87 | ||
|
|
2bbb5ef74e | ||
|
|
91eb7feb3c | ||
|
|
978d77142c | ||
|
|
e36478b9ac | ||
|
|
e1fe4dd693 | ||
|
|
b1ee949b1c | ||
|
|
a0e5f8e97e | ||
|
|
e9cfb2c4ee | ||
|
|
190b6edfb1 | ||
|
|
80a0c59f87 | ||
|
|
823fdec705 | ||
|
|
fe87dcced7 | ||
|
|
137eb44516 | ||
|
|
f60d957102 | ||
|
|
8f0b04504f | ||
|
|
2c39d8b1c8 | ||
|
|
d4d1c32288 | ||
|
|
e4f39d2b6a | ||
|
|
e5a2bfbcbd | ||
|
|
de3b76b31d | ||
|
|
53455496bf | ||
|
|
cc2a2f6dfb | ||
|
|
ee4ac7371c | ||
|
|
d5265407b9 | ||
|
|
954b3e9fc5 | ||
|
|
7d9894bef7 | ||
|
|
3b34698e8b | ||
|
|
263cb581c4 | ||
|
|
1c9cb4516c | ||
|
|
ac4ceccb4f |
@@ -1,5 +1,6 @@
|
|||||||
var BrowserWindow = require('browser-window')
|
const electron = require('electron')
|
||||||
var path = require('path')
|
const BrowserWindow = electron.BrowserWindow
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
var finderWindow = new BrowserWindow({
|
var finderWindow = new BrowserWindow({
|
||||||
width: 640,
|
width: 640,
|
||||||
@@ -18,12 +19,10 @@ var finderWindow = new BrowserWindow({
|
|||||||
|
|
||||||
var url = path.resolve(__dirname, '../browser/finder/index.html')
|
var url = path.resolve(__dirname, '../browser/finder/index.html')
|
||||||
|
|
||||||
finderWindow.loadUrl('file://' + url)
|
finderWindow.loadURL('file://' + url)
|
||||||
|
|
||||||
finderWindow.on('blur', function () {
|
finderWindow.on('blur', function () {
|
||||||
finderWindow.hide()
|
finderWindow.hide()
|
||||||
})
|
})
|
||||||
|
|
||||||
finderWindow.setVisibleOnAllWorkspaces(true)
|
|
||||||
|
|
||||||
module.exports = finderWindow
|
module.exports = finderWindow
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
var BrowserWindow = require('browser-window')
|
const electron = require('electron')
|
||||||
var path = require('path')
|
const BrowserWindow = electron.BrowserWindow
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
var mainWindow = new BrowserWindow({
|
var mainWindow = new BrowserWindow({
|
||||||
width: 1080,
|
width: 1080,
|
||||||
@@ -11,11 +12,9 @@ var mainWindow = new BrowserWindow({
|
|||||||
'standard-window': false
|
'standard-window': false
|
||||||
})
|
})
|
||||||
|
|
||||||
var url = path.resolve(__dirname, '../browser/main/index.html')
|
const url = path.resolve(__dirname, '../browser/main/index.html')
|
||||||
|
|
||||||
mainWindow.loadUrl('file://' + url)
|
mainWindow.loadURL('file://' + url)
|
||||||
|
|
||||||
mainWindow.setVisibleOnAllWorkspaces(true)
|
|
||||||
|
|
||||||
mainWindow.webContents.on('new-window', function (e) {
|
mainWindow.webContents.on('new-window', function (e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
var BrowserWindow = require('browser-window')
|
const electron = require('electron')
|
||||||
|
const BrowserWindow = electron.BrowserWindow
|
||||||
|
|
||||||
module.exports = [
|
module.exports = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
var autoUpdater = require('auto-updater')
|
|
||||||
var nn = require('node-notifier')
|
|
||||||
var app = require('app')
|
|
||||||
var path = require('path')
|
|
||||||
|
|
||||||
var version = app.getVersion()
|
|
||||||
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
|
||||||
var versionNotified = false
|
|
||||||
autoUpdater
|
|
||||||
.on('error', function (err, message) {
|
|
||||||
console.error(err)
|
|
||||||
console.error(message)
|
|
||||||
console.log(path.resolve(__dirname, '../resources/favicon-230x230.png'))
|
|
||||||
nn.notify({
|
|
||||||
title: 'Error! ' + versionText,
|
|
||||||
icon: path.resolve(__dirname, '../resources/favicon-230x230.png'),
|
|
||||||
message: message
|
|
||||||
})
|
|
||||||
})
|
|
||||||
// .on('checking-for-update', function () {
|
|
||||||
// // Connecting
|
|
||||||
// console.log('checking...')
|
|
||||||
// })
|
|
||||||
.on('update-available', function () {
|
|
||||||
nn.notify({
|
|
||||||
title: 'Update is available!! ' + versionText,
|
|
||||||
icon: path.resolve(__dirname, '../resources/favicon-230x230.png'),
|
|
||||||
message: 'Download started.. wait for the update ready.'
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.on('update-not-available', function () {
|
|
||||||
if (!versionNotified) {
|
|
||||||
nn.notify({
|
|
||||||
title: 'Latest Build!! ' + versionText,
|
|
||||||
icon: path.resolve(__dirname, '../resources/favicon-230x230.png'),
|
|
||||||
message: 'Hope you to enjoy our app :D'
|
|
||||||
})
|
|
||||||
versionNotified = true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
module.exports = autoUpdater
|
|
||||||
@@ -16,11 +16,8 @@ export function searchArticle (input) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function refreshData () {
|
export function refreshData (data) {
|
||||||
console.log('refreshing data')
|
console.log('refreshing data')
|
||||||
let data = JSON.parse(localStorage.getItem('local'))
|
|
||||||
if (data == null) return null
|
|
||||||
|
|
||||||
let { folders, articles } = data
|
let { folders, articles } = data
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -31,3 +28,12 @@ export function refreshData () {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
SELECT_ARTICLE,
|
||||||
|
SEARCH_ARTICLE,
|
||||||
|
REFRESH_DATA,
|
||||||
|
selectArticle,
|
||||||
|
searchArticle,
|
||||||
|
refreshData
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
|
<link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
|
||||||
<link rel="stylesheet" href="../../node_modules/devicon/devicon.min.css">
|
<link rel="stylesheet" href="../../node_modules/devicon/devicon.min.css">
|
||||||
|
<link rel="stylesheet" href="../../node_modules/highlight.js/styles/xcode.css">
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<link rel="shortcut icon" href="favicon.ico">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -27,7 +28,8 @@
|
|||||||
<div id="content"></div>
|
<div id="content"></div>
|
||||||
<script src="../../submodules/ace/src-min/ace.js"></script>
|
<script src="../../submodules/ace/src-min/ace.js"></script>
|
||||||
<script>
|
<script>
|
||||||
require('web-frame').setZoomLevelLimits(1, 1)
|
const electron = require('electron')
|
||||||
|
electron.webFrame.setZoomLevelLimits(1, 1)
|
||||||
var scriptUrl = process.env.BOOST_ENV === 'development'
|
var scriptUrl = process.env.BOOST_ENV === 'development'
|
||||||
? 'http://localhost:8080/assets/finder.js'
|
? 'http://localhost:8080/assets/finder.js'
|
||||||
: '../../compiled/finder.js'
|
: '../../compiled/finder.js'
|
||||||
|
|||||||
@@ -6,18 +6,17 @@ import { createStore } from 'redux'
|
|||||||
import FinderInput from './FinderInput'
|
import FinderInput from './FinderInput'
|
||||||
import FinderList from './FinderList'
|
import FinderList from './FinderList'
|
||||||
import FinderDetail from './FinderDetail'
|
import FinderDetail from './FinderDetail'
|
||||||
import { selectArticle, searchArticle, refreshData } from './actions'
|
import actions, { selectArticle, searchArticle } from './actions'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import activityRecord from 'boost/activityRecord'
|
import dataStore from 'boost/dataStore'
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
|
const { remote, clipboard } = electron
|
||||||
|
|
||||||
import remote from 'remote'
|
|
||||||
var hideFinder = remote.getGlobal('hideFinder')
|
var hideFinder = remote.getGlobal('hideFinder')
|
||||||
import clipboard from 'clipboard'
|
|
||||||
|
|
||||||
var notifier = require('node-notifier')
|
function notify (...args) {
|
||||||
var path = require('path')
|
return new window.Notification(...args)
|
||||||
function getIconPath () {
|
|
||||||
return path.resolve(global.__dirname, '../../resources/favicon-230x230.png')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
require('../styles/finder/index.styl')
|
require('../styles/finder/index.styl')
|
||||||
@@ -64,12 +63,9 @@ class FinderMain extends React.Component {
|
|||||||
saveToClipboard () {
|
saveToClipboard () {
|
||||||
let { activeArticle } = this.props
|
let { activeArticle } = this.props
|
||||||
clipboard.writeText(activeArticle.content)
|
clipboard.writeText(activeArticle.content)
|
||||||
activityRecord.emit('FINDER_COPY')
|
|
||||||
|
|
||||||
notifier.notify({
|
notify('Saved to Clipboard!', {
|
||||||
icon: getIconPath(),
|
body: 'Paste it wherever you want!'
|
||||||
'title': 'Saved to Clipboard!',
|
|
||||||
'message': 'Paste it wherever you want!'
|
|
||||||
})
|
})
|
||||||
hideFinder()
|
hideFinder()
|
||||||
}
|
}
|
||||||
@@ -216,13 +212,19 @@ function remap (state) {
|
|||||||
var Finder = connect(remap)(FinderMain)
|
var Finder = connect(remap)(FinderMain)
|
||||||
var store = createStore(reducer)
|
var store = createStore(reducer)
|
||||||
|
|
||||||
|
function refreshData () {
|
||||||
|
let data = dataStore.getData()
|
||||||
|
store.dispatch(actions.refreshData(data))
|
||||||
|
}
|
||||||
|
|
||||||
window.onfocus = e => {
|
window.onfocus = e => {
|
||||||
store.dispatch(refreshData())
|
refreshData()
|
||||||
activityRecord.emit('FINDER_OPEN')
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<Finder/>
|
<Finder/>
|
||||||
</Provider>
|
</Provider>
|
||||||
), document.getElementById('content'))
|
), document.getElementById('content'), function () {
|
||||||
|
refreshData()
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
import { combineReducers } from 'redux'
|
import { combineReducers } from 'redux'
|
||||||
import { SELECT_ARTICLE, SEARCH_ARTICLE, REFRESH_DATA } from './actions'
|
import { SELECT_ARTICLE, SEARCH_ARTICLE, REFRESH_DATA } from './actions'
|
||||||
|
|
||||||
let data = JSON.parse(localStorage.getItem('local'))
|
let initialArticles = []
|
||||||
|
let initialFolders = []
|
||||||
let initialArticles = data != null ? data.articles : []
|
|
||||||
let initialFolders = data != null ? data.folders : []
|
|
||||||
let initialStatus = {
|
let initialStatus = {
|
||||||
articleKey: null,
|
articleKey: null,
|
||||||
search: ''
|
search: ''
|
||||||
|
|||||||
@@ -1,14 +1,15 @@
|
|||||||
import React, { PropTypes} from 'react'
|
import React, { PropTypes} from 'react'
|
||||||
import { connect } from 'react-redux'
|
import { connect } from 'react-redux'
|
||||||
import { CREATE_MODE, EDIT_MODE, IDLE_MODE, NEW, toggleTutorial } from 'boost/actions'
|
import { EDIT_MODE, IDLE_MODE, NEW, toggleTutorial } from 'boost/actions'
|
||||||
// import UserNavigator from './HomePage/UserNavigator'
|
// import UserNavigator from './HomePage/UserNavigator'
|
||||||
import ArticleNavigator from './HomePage/ArticleNavigator'
|
import ArticleNavigator from './HomePage/ArticleNavigator'
|
||||||
import ArticleTopBar from './HomePage/ArticleTopBar'
|
import ArticleTopBar from './HomePage/ArticleTopBar'
|
||||||
import ArticleList from './HomePage/ArticleList'
|
import ArticleList from './HomePage/ArticleList'
|
||||||
import ArticleDetail from './HomePage/ArticleDetail'
|
import ArticleDetail from './HomePage/ArticleDetail'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import keygen from 'boost/keygen'
|
|
||||||
import { isModalOpen, closeModal } from 'boost/modal'
|
import { isModalOpen, closeModal } from 'boost/modal'
|
||||||
|
const electron = require('electron')
|
||||||
|
const BrowserWindow = electron.remote.BrowserWindow
|
||||||
|
|
||||||
const TEXT_FILTER = 'TEXT_FILTER'
|
const TEXT_FILTER = 'TEXT_FILTER'
|
||||||
const FOLDER_FILTER = 'FOLDER_FILTER'
|
const FOLDER_FILTER = 'FOLDER_FILTER'
|
||||||
@@ -28,6 +29,13 @@ class HomePage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown (e) {
|
handleKeyDown (e) {
|
||||||
|
if (process.env.BOOST_ENV === 'development' && e.keyCode === 73 && e.metaKey && e.altKey) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
BrowserWindow.getFocusedWindow().toggleDevTools()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
if (isModalOpen()) {
|
if (isModalOpen()) {
|
||||||
if (e.keyCode === 27) closeModal()
|
if (e.keyCode === 27) closeModal()
|
||||||
return
|
return
|
||||||
@@ -49,7 +57,7 @@ class HomePage extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
switch (status.mode) {
|
switch (status.mode) {
|
||||||
case CREATE_MODE:
|
|
||||||
case EDIT_MODE:
|
case EDIT_MODE:
|
||||||
if (e.keyCode === 27) {
|
if (e.keyCode === 27) {
|
||||||
detail.handleCancelButtonClick()
|
detail.handleCancelButtonClick()
|
||||||
@@ -57,6 +65,13 @@ class HomePage extends React.Component {
|
|||||||
if ((e.keyCode === 13 && e.metaKey) || (e.keyCode === 83 && e.metaKey)) {
|
if ((e.keyCode === 13 && e.metaKey) || (e.keyCode === 83 && e.metaKey)) {
|
||||||
detail.handleSaveButtonClick()
|
detail.handleSaveButtonClick()
|
||||||
}
|
}
|
||||||
|
if (e.keyCode === 80 && e.metaKey) {
|
||||||
|
detail.handleTogglePreviewButtonClick()
|
||||||
|
}
|
||||||
|
if (e.keyCode === 78 && e.metaKey) {
|
||||||
|
nav.handleNewPostButtonClick()
|
||||||
|
e.preventDefault()
|
||||||
|
}
|
||||||
break
|
break
|
||||||
case IDLE_MODE:
|
case IDLE_MODE:
|
||||||
if (e.keyCode === 69) {
|
if (e.keyCode === 69) {
|
||||||
@@ -91,7 +106,7 @@ class HomePage extends React.Component {
|
|||||||
list.selectNextArticle()
|
list.selectNextArticle()
|
||||||
}
|
}
|
||||||
|
|
||||||
if (e.keyCode === 65 || e.keyCode === 13 && e.metaKey) {
|
if (e.keyCode === 65 || (e.keyCode === 13 && e.metaKey) || (e.keyCode === 78 && e.metaKey)) {
|
||||||
nav.handleNewPostButtonClick()
|
nav.handleNewPostButtonClick()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
@@ -218,42 +233,6 @@ function remap (state) {
|
|||||||
let activeArticle = _.findWhere(articles, {key: status.articleKey})
|
let activeArticle = _.findWhere(articles, {key: status.articleKey})
|
||||||
if (activeArticle == null) activeArticle = articles[0]
|
if (activeArticle == null) activeArticle = articles[0]
|
||||||
|
|
||||||
// remove Unsaved new article if user is not CREATE_MODE
|
|
||||||
if (status.mode !== CREATE_MODE) {
|
|
||||||
let targetIndex = _.findIndex(articles, article => article.status === NEW)
|
|
||||||
|
|
||||||
if (targetIndex >= 0) articles.splice(targetIndex, 1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// switching CREATE_MODE
|
|
||||||
// restrict
|
|
||||||
// 1. team have one folder at least
|
|
||||||
// or Change IDLE MODE
|
|
||||||
if (status.mode === CREATE_MODE) {
|
|
||||||
let newArticle = _.findWhere(articles, {status: 'NEW'})
|
|
||||||
console.log('targetFolders')
|
|
||||||
let FolderKey = targetFolders.length > 0
|
|
||||||
? targetFolders[0].key
|
|
||||||
: folders[0].key
|
|
||||||
|
|
||||||
if (newArticle == null) {
|
|
||||||
newArticle = {
|
|
||||||
id: null,
|
|
||||||
key: keygen(),
|
|
||||||
title: '',
|
|
||||||
content: '',
|
|
||||||
mode: 'markdown',
|
|
||||||
tags: [],
|
|
||||||
FolderKey: FolderKey,
|
|
||||||
status: NEW
|
|
||||||
}
|
|
||||||
articles.unshift(newArticle)
|
|
||||||
}
|
|
||||||
activeArticle = newArticle
|
|
||||||
} else if (status.mode === CREATE_MODE) {
|
|
||||||
status.mode = IDLE_MODE
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
folders,
|
folders,
|
||||||
status,
|
status,
|
||||||
@@ -285,7 +264,8 @@ HomePage.propTypes = {
|
|||||||
folder: PropTypes.array,
|
folder: PropTypes.array,
|
||||||
tag: PropTypes.array,
|
tag: PropTypes.array,
|
||||||
text: PropTypes.array
|
text: PropTypes.array
|
||||||
})
|
}),
|
||||||
|
tags: PropTypes.array
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(remap)(HomePage)
|
export default connect(remap)(HomePage)
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import MarkdownPreview from 'boost/components/MarkdownPreview'
|
|||||||
import CodeEditor from 'boost/components/CodeEditor'
|
import CodeEditor from 'boost/components/CodeEditor'
|
||||||
import {
|
import {
|
||||||
IDLE_MODE,
|
IDLE_MODE,
|
||||||
CREATE_MODE,
|
|
||||||
EDIT_MODE,
|
EDIT_MODE,
|
||||||
switchMode,
|
switchMode,
|
||||||
switchArticle,
|
switchArticle,
|
||||||
@@ -26,6 +25,9 @@ import TagSelect from 'boost/components/TagSelect'
|
|||||||
import ModeSelect from 'boost/components/ModeSelect'
|
import ModeSelect from 'boost/components/ModeSelect'
|
||||||
import activityRecord from 'boost/activityRecord'
|
import activityRecord from 'boost/activityRecord'
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
|
const clipboard = electron.clipboard
|
||||||
|
|
||||||
const BRAND_COLOR = '#18AF90'
|
const BRAND_COLOR = '#18AF90'
|
||||||
|
|
||||||
const editDeleteTutorialElement = (
|
const editDeleteTutorialElement = (
|
||||||
@@ -85,6 +87,10 @@ const modeSelectTutorialElement = (
|
|||||||
</svg>
|
</svg>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
function notify (...args) {
|
||||||
|
return new window.Notification(...args)
|
||||||
|
}
|
||||||
|
|
||||||
function makeInstantArticle (article) {
|
function makeInstantArticle (article) {
|
||||||
return Object.assign({}, article)
|
return Object.assign({}, article)
|
||||||
}
|
}
|
||||||
@@ -114,7 +120,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
componentDidUpdate (prevProps) {
|
componentDidUpdate (prevProps) {
|
||||||
let isModeChanged = prevProps.status.mode !== this.props.status.mode
|
let isModeChanged = prevProps.status.mode !== this.props.status.mode
|
||||||
if (isModeChanged && this.props.status.mode !== IDLE_MODE) {
|
if (isModeChanged && this.props.status.mode === EDIT_MODE) {
|
||||||
ReactDOM.findDOMNode(this.refs.title).focus()
|
ReactDOM.findDOMNode(this.refs.title).focus()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -124,6 +130,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
let isArticleChanged = nextProps.activeArticle != null && (nextProps.activeArticle.key !== this.state.article.key)
|
let isArticleChanged = nextProps.activeArticle != null && (nextProps.activeArticle.key !== this.state.article.key)
|
||||||
let isModeChanged = nextProps.status.mode !== this.props.status.mode
|
let isModeChanged = nextProps.status.mode !== this.props.status.mode
|
||||||
|
|
||||||
// Reset article input
|
// Reset article input
|
||||||
if (isArticleChanged || (isModeChanged && nextProps.status.mode !== IDLE_MODE)) {
|
if (isArticleChanged || (isModeChanged && nextProps.status.mode !== IDLE_MODE)) {
|
||||||
Object.assign(nextState, {
|
Object.assign(nextState, {
|
||||||
@@ -154,6 +161,13 @@ export default class ArticleDetail extends React.Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleClipboardButtonClick (e) {
|
||||||
|
clipboard.writeText(this.props.activeArticle.content)
|
||||||
|
notify('Saved to Clipboard!', {
|
||||||
|
body: 'Paste it wherever you want!'
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
handleEditButtonClick (e) {
|
handleEditButtonClick (e) {
|
||||||
let { dispatch } = this.props
|
let { dispatch } = this.props
|
||||||
dispatch(switchMode(EDIT_MODE))
|
dispatch(switchMode(EDIT_MODE))
|
||||||
@@ -185,8 +199,13 @@ export default class ArticleDetail extends React.Component {
|
|||||||
: (
|
: (
|
||||||
<span className='noTags'>Not tagged yet</span>
|
<span className='noTags'>Not tagged yet</span>
|
||||||
) : null
|
) : null
|
||||||
|
|
||||||
let folder = _.findWhere(folders, {key: activeArticle.FolderKey})
|
let folder = _.findWhere(folders, {key: activeArticle.FolderKey})
|
||||||
|
|
||||||
|
let title = activeArticle.title.trim().length === 0
|
||||||
|
? <small>(Untitled)</small>
|
||||||
|
: activeArticle.title
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='ArticleDetail idle'>
|
<div className='ArticleDetail idle'>
|
||||||
{this.state.openDeleteConfirmMenu
|
{this.state.openDeleteConfirmMenu
|
||||||
@@ -214,6 +233,9 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
<div className='tags'><i className='fa fa-fw fa-tags'/>{tags}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='right'>
|
<div className='right'>
|
||||||
|
<button onClick={e => this.handleClipboardButtonClick(e)} className='editBtn'>
|
||||||
|
<i className='fa fa-fw fa-clipboard'/><span className='tooltip'>Copy to clipboard</span>
|
||||||
|
</button>
|
||||||
<button onClick={e => this.handleEditButtonClick(e)} className='editBtn'>
|
<button onClick={e => this.handleEditButtonClick(e)} className='editBtn'>
|
||||||
<i className='fa fa-fw fa-edit'/><span className='tooltip'>Edit (e)</span>
|
<i className='fa fa-fw fa-edit'/><span className='tooltip'>Edit (e)</span>
|
||||||
</button>
|
</button>
|
||||||
@@ -232,7 +254,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<div className='detailPanel'>
|
<div className='detailPanel'>
|
||||||
<div className='header'>
|
<div className='header'>
|
||||||
<ModeIcon className='mode' mode={activeArticle.mode}/>
|
<ModeIcon className='mode' mode={activeArticle.mode}/>
|
||||||
<div className='title'>{activeArticle.title}</div>
|
<div className='title'>{title}</div>
|
||||||
</div>
|
</div>
|
||||||
{activeArticle.mode === 'markdown'
|
{activeArticle.mode === 'markdown'
|
||||||
? <MarkdownPreview content={activeArticle.content}/>
|
? <MarkdownPreview content={activeArticle.content}/>
|
||||||
@@ -247,13 +269,14 @@ export default class ArticleDetail extends React.Component {
|
|||||||
handleCancelButtonClick (e) {
|
handleCancelButtonClick (e) {
|
||||||
let { activeArticle, dispatch } = this.props
|
let { activeArticle, dispatch } = this.props
|
||||||
|
|
||||||
dispatch(unlockStatus())
|
if (activeArticle.status === NEW) {
|
||||||
if (activeArticle.status === NEW) dispatch(switchArticle(null))
|
dispatch(switchArticle(null))
|
||||||
|
}
|
||||||
dispatch(switchMode(IDLE_MODE))
|
dispatch(switchMode(IDLE_MODE))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSaveButtonClick (e) {
|
handleSaveButtonClick (e) {
|
||||||
let { dispatch, folders, filters } = this.props
|
let { dispatch, folders, status } = this.props
|
||||||
let article = this.state.article
|
let article = this.state.article
|
||||||
let newArticle = Object.assign({}, article)
|
let newArticle = Object.assign({}, article)
|
||||||
|
|
||||||
@@ -264,8 +287,12 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
delete newArticle.status
|
delete newArticle.status
|
||||||
newArticle.updatedAt = new Date()
|
newArticle.updatedAt = new Date()
|
||||||
|
newArticle.title = newArticle.title.trim()
|
||||||
if (newArticle.createdAt == null) {
|
if (newArticle.createdAt == null) {
|
||||||
newArticle.createdAt = new Date()
|
newArticle.createdAt = new Date()
|
||||||
|
if (newArticle.title.length === 0) {
|
||||||
|
newArticle.title = `Created at ${moment(newArticle.createdAt).format('YYYY/MM/DD HH:mm')}`
|
||||||
|
}
|
||||||
activityRecord.emit('ARTICLE_CREATE')
|
activityRecord.emit('ARTICLE_CREATE')
|
||||||
} else {
|
} else {
|
||||||
activityRecord.emit('ARTICLE_UPDATE')
|
activityRecord.emit('ARTICLE_UPDATE')
|
||||||
@@ -277,7 +304,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
// Searchを初期化し、更新先のFolder filterをかける
|
// Searchを初期化し、更新先のFolder filterをかける
|
||||||
// かかれていない時に
|
// かかれていない時に
|
||||||
// Searchを初期化する
|
// Searchを初期化する
|
||||||
if (filters.folder.length !== 0) dispatch(switchFolder(folder.name))
|
if (status.targetFolders.length > 0) dispatch(switchFolder(folder.name))
|
||||||
else dispatch(clearSearch())
|
else dispatch(clearSearch())
|
||||||
dispatch(switchArticle(newArticle.key))
|
dispatch(switchArticle(newArticle.key))
|
||||||
}
|
}
|
||||||
@@ -319,8 +346,6 @@ export default class ArticleDetail extends React.Component {
|
|||||||
let article = this.state.article
|
let article = this.state.article
|
||||||
article.tags = tags
|
article.tags = tags
|
||||||
|
|
||||||
this.setState({article: article})
|
|
||||||
|
|
||||||
let _isTagChanged = _.difference(article.tags, this.props.activeArticle.tags).length > 0 || _.difference(this.props.activeArticle.tags, article.tags).length > 0
|
let _isTagChanged = _.difference(article.tags, this.props.activeArticle.tags).length > 0 || _.difference(this.props.activeArticle.tags, article.tags).length > 0
|
||||||
|
|
||||||
let { isTitleChanged, isContentChanged, isArticleEdited, isModeChanged } = this.state
|
let { isTitleChanged, isContentChanged, isArticleEdited, isModeChanged } = this.state
|
||||||
@@ -409,7 +434,9 @@ export default class ArticleDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleTogglePreviewButtonClick (e) {
|
handleTogglePreviewButtonClick (e) {
|
||||||
this.setState({previewMode: !this.state.previewMode})
|
if (this.state.article.mode === 'markdown') {
|
||||||
|
this.setState({previewMode: !this.state.previewMode})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTitleKeyDown (e) {
|
handleTitleKeyDown (e) {
|
||||||
@@ -454,18 +481,36 @@ export default class ArticleDetail extends React.Component {
|
|||||||
<div className='right'>
|
<div className='right'>
|
||||||
{
|
{
|
||||||
this.state.article.mode === 'markdown'
|
this.state.article.mode === 'markdown'
|
||||||
? (<button className='preview' onClick={e => this.handleTogglePreviewButtonClick(e)}>{!this.state.previewMode ? 'Preview' : 'Edit'}</button>)
|
? (<button className='preview' onClick={e => this.handleTogglePreviewButtonClick(e)}>
|
||||||
|
{
|
||||||
|
!this.state.previewMode
|
||||||
|
? 'Preview'
|
||||||
|
: 'Edit'
|
||||||
|
}
|
||||||
|
</button>)
|
||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
<button onClick={e => this.handleCancelButtonClick(e)}>Cancel</button>
|
<button onClick={e => this.handleCancelButtonClick(e)}>
|
||||||
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Save</button>
|
Cancel
|
||||||
|
</button>
|
||||||
|
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='detailBody'>
|
<div className='detailBody'>
|
||||||
<div className='detailPanel'>
|
<div className='detailPanel'>
|
||||||
<div className='header'>
|
<div className='header'>
|
||||||
<div className='title'>
|
<div className='title'>
|
||||||
<input onKeyDown={e => this.handleTitleKeyDown(e)} placeholder='Title' ref='title' value={this.state.article.title} onChange={e => this.handleTitleChange(e)}/>
|
<input
|
||||||
|
onKeyDown={e => this.handleTitleKeyDown(e)}
|
||||||
|
placeholder={this.state.article.createdAt == null
|
||||||
|
? `Created at ${moment().format('YYYY/MM/DD HH:mm')}`
|
||||||
|
: 'Title'}
|
||||||
|
ref='title'
|
||||||
|
value={this.state.article.title}
|
||||||
|
onChange={e => this.handleTitleChange(e)}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<ModeSelect
|
<ModeSelect
|
||||||
ref='mode'
|
ref='mode'
|
||||||
@@ -500,7 +545,6 @@ export default class ArticleDetail extends React.Component {
|
|||||||
if (activeArticle == null) return this.renderEmpty()
|
if (activeArticle == null) return this.renderEmpty()
|
||||||
|
|
||||||
switch (status.mode) {
|
switch (status.mode) {
|
||||||
case CREATE_MODE:
|
|
||||||
case EDIT_MODE:
|
case EDIT_MODE:
|
||||||
return this.renderEdit()
|
return this.renderEdit()
|
||||||
case IDLE_MODE:
|
case IDLE_MODE:
|
||||||
|
|||||||
@@ -80,6 +80,12 @@ export default class ArticleList extends React.Component {
|
|||||||
: (<span>Not tagged yet</span>)
|
: (<span>Not tagged yet</span>)
|
||||||
let folder = _.findWhere(folders, {key: article.FolderKey})
|
let folder = _.findWhere(folders, {key: article.FolderKey})
|
||||||
|
|
||||||
|
let title = article.status !== NEW
|
||||||
|
? article.title.trim().length === 0
|
||||||
|
? <small>(Untitled)</small>
|
||||||
|
: article.title
|
||||||
|
: '(New article)'
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div key={'article-' + article.key}>
|
<div key={'article-' + article.key}>
|
||||||
<div onClick={e => this.handleArticleClick(article)(e)} className={'articleItem' + (activeArticle.key === article.key ? ' active' : '')}>
|
<div onClick={e => this.handleArticleClick(article)(e)} className={'articleItem' + (activeArticle.key === article.key ? ' active' : '')}>
|
||||||
@@ -91,7 +97,7 @@ export default class ArticleList extends React.Component {
|
|||||||
<span className='updatedAt'>{article.status != null ? article.status : moment(article.updatedAt).fromNow()}</span>
|
<span className='updatedAt'>{article.status != null ? article.status : moment(article.updatedAt).fromNow()}</span>
|
||||||
</div>
|
</div>
|
||||||
<div className='middle'>
|
<div className='middle'>
|
||||||
<ModeIcon className='mode' mode={article.mode}/> <div className='title'>{article.status !== NEW ? article.title : '(New article)'}</div>
|
<ModeIcon className='mode' mode={article.mode}/> <div className='title'>{title}</div>
|
||||||
</div>
|
</div>
|
||||||
<div className='bottom'>
|
<div className='bottom'>
|
||||||
<div className='tags'><i className='fa fa-fw fa-tags'/>{tagElements}</div>
|
<div className='tags'><i className='fa fa-fw fa-tags'/>{tagElements}</div>
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import { findWhere } from 'lodash'
|
import { findWhere } from 'lodash'
|
||||||
import { setSearchFilter, switchFolder, switchMode, CREATE_MODE } from 'boost/actions'
|
import { setSearchFilter, switchFolder, switchMode, switchArticle, updateArticle, clearNewArticle, EDIT_MODE } from 'boost/actions'
|
||||||
import { openModal } from 'boost/modal'
|
import { openModal } from 'boost/modal'
|
||||||
import FolderMark from 'boost/components/FolderMark'
|
import FolderMark from 'boost/components/FolderMark'
|
||||||
import Preferences from 'boost/components/modal/Preferences'
|
import Preferences from 'boost/components/modal/Preferences'
|
||||||
import CreateNewFolder from 'boost/components/modal/CreateNewFolder'
|
import CreateNewFolder from 'boost/components/modal/CreateNewFolder'
|
||||||
|
import keygen from 'boost/keygen'
|
||||||
|
|
||||||
import remote from 'remote'
|
const electron = require('electron')
|
||||||
|
const remote = electron.remote
|
||||||
let userName = remote.getGlobal('process').env.USER
|
let userName = remote.getGlobal('process').env.USER
|
||||||
|
|
||||||
const BRAND_COLOR = '#18AF90'
|
const BRAND_COLOR = '#18AF90'
|
||||||
@@ -65,9 +67,28 @@ export default class ArticleNavigator extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleNewPostButtonClick (e) {
|
handleNewPostButtonClick (e) {
|
||||||
let { dispatch } = this.props
|
let { dispatch, folders, status } = this.props
|
||||||
|
let { targetFolders } = status
|
||||||
|
|
||||||
dispatch(switchMode(CREATE_MODE))
|
let FolderKey = targetFolders.length > 0
|
||||||
|
? targetFolders[0].key
|
||||||
|
: folders[0].key
|
||||||
|
|
||||||
|
let newArticle = {
|
||||||
|
id: null,
|
||||||
|
key: keygen(),
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
mode: 'markdown',
|
||||||
|
tags: [],
|
||||||
|
FolderKey: FolderKey,
|
||||||
|
status: 'NEW'
|
||||||
|
}
|
||||||
|
|
||||||
|
dispatch(clearNewArticle())
|
||||||
|
dispatch(updateArticle(newArticle))
|
||||||
|
dispatch(switchArticle(newArticle.key, true))
|
||||||
|
dispatch(switchMode(EDIT_MODE))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleNewFolderButton (e) {
|
handleNewFolderButton (e) {
|
||||||
@@ -94,7 +115,7 @@ export default class ArticleNavigator extends React.Component {
|
|||||||
|
|
||||||
let folderElememts = folders.map((folder, index) => {
|
let folderElememts = folders.map((folder, index) => {
|
||||||
let isActive = findWhere(targetFolders, {key: folder.key})
|
let isActive = findWhere(targetFolders, {key: folder.key})
|
||||||
let articleCount = allArticles.filter(article => article.FolderKey === folder.key).length
|
let articleCount = allArticles.filter(article => article.FolderKey === folder.key && article.status !== 'NEW').length
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button onClick={e => this.handleFolderButtonClick(folder.name)(e)} key={'folder-' + folder.key} className={isActive ? 'active' : ''}>
|
<button onClick={e => this.handleFolderButtonClick(folder.name)(e)} key={'folder-' + folder.key} className={isActive ? 'active' : ''}>
|
||||||
|
|||||||
@@ -35,18 +35,33 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isTooltipHidden: true
|
isTooltipHidden: true,
|
||||||
|
isLinksDropdownOpen: false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.searchInput = ReactDOM.findDOMNode(this.refs.searchInput)
|
this.searchInput = ReactDOM.findDOMNode(this.refs.searchInput)
|
||||||
|
this.linksButton = ReactDOM.findDOMNode(this.refs.links)
|
||||||
|
this.showLinksDropdown = e => {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
if (!this.state.isLinksDropdownOpen) {
|
||||||
|
this.setState({isLinksDropdownOpen: true})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.linksButton.addEventListener('click', this.showLinksDropdown)
|
||||||
|
this.hideLinksDropdown = e => {
|
||||||
|
if (this.state.isLinksDropdownOpen) {
|
||||||
|
this.setState({isLinksDropdownOpen: false})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
document.addEventListener('click', this.hideLinksDropdown)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
this.searchInput.removeEventListener('keydown', this.showTooltip)
|
document.removeEventListener('click', this.hideLinksDropdown)
|
||||||
this.searchInput.removeEventListener('focus', this.showTooltip)
|
this.linksButton.removeEventListener('click', this.showLinksDropdown())
|
||||||
this.searchInput.removeEventListener('blur', this.showTooltip)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleTooltipRequest (e) {
|
handleTooltipRequest (e) {
|
||||||
@@ -118,8 +133,11 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
: null
|
: null
|
||||||
}
|
}
|
||||||
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
|
<div className={'tooltip' + (this.state.isTooltipHidden ? ' hide' : '')}>
|
||||||
- Search by tag : #{'{string}'}<br/>
|
<ul>
|
||||||
- Search by folder : /{'{folder_name}'}
|
<li>- Search by tag : #{'{string}'}</li>
|
||||||
|
<li>- Search by folder : /{'{folder_name}'}</li>
|
||||||
|
<li><small>exact match : //{'{folder_name}'}</small></li>
|
||||||
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -129,10 +147,23 @@ export default class ArticleTopBar extends React.Component {
|
|||||||
<div className='right'>
|
<div className='right'>
|
||||||
<button onClick={e => this.handleTutorialButtonClick(e)}>?<span className='tooltip'>How to use</span>
|
<button onClick={e => this.handleTutorialButtonClick(e)}>?<span className='tooltip'>How to use</span>
|
||||||
</button>
|
</button>
|
||||||
<ExternalLink className='logo' href='http://b00st.io'>
|
<a ref='links' className='linksBtn' href>
|
||||||
<img src='../../resources/favicon-230x230.png' width='44' height='44'/>
|
<img src='../../resources/favicon-230x230.png' width='44' height='44'/>
|
||||||
<span className='tooltip'>Boost official page</span>
|
</a>
|
||||||
</ExternalLink>
|
{
|
||||||
|
this.state.isLinksDropdownOpen
|
||||||
|
? (
|
||||||
|
<div className='links-dropdown'>
|
||||||
|
<ExternalLink className='links-item' href='https://b00st.io'>
|
||||||
|
<i className='fa fa-fw fa-home'/>Boost official page
|
||||||
|
</ExternalLink>
|
||||||
|
<ExternalLink className='links-item' href='https://github.com/BoostIO/boost-app-discussions/issues'>
|
||||||
|
<i className='fa fa-fw fa-bullhorn'/> Discuss
|
||||||
|
</ExternalLink>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{status.isTutorialOpen ? (
|
{status.isTutorialOpen ? (
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import ipc from 'ipc'
|
const electron = require('electron')
|
||||||
|
const ipc = electron.ipcRenderer
|
||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
|
|
||||||
var ContactModal = require('boost/components/modal/ContactModal')
|
var ContactModal = require('boost/components/modal/ContactModal')
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
|
|
||||||
<link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
|
<link rel="stylesheet" href="../../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
|
||||||
<link rel="stylesheet" href="../../node_modules/devicon/devicon.min.css">
|
<link rel="stylesheet" href="../../node_modules/devicon/devicon.min.css">
|
||||||
|
<link rel="stylesheet" href="../../node_modules/highlight.js/styles/xcode.css">
|
||||||
<link rel="shortcut icon" href="favicon.ico">
|
<link rel="shortcut icon" href="favicon.ico">
|
||||||
|
|
||||||
<style>
|
<style>
|
||||||
@@ -53,8 +54,9 @@
|
|||||||
|
|
||||||
<script src="../../submodules/ace/src-min/ace.js"></script>
|
<script src="../../submodules/ace/src-min/ace.js"></script>
|
||||||
<script type='text/javascript'>
|
<script type='text/javascript'>
|
||||||
require('web-frame').setZoomLevelLimits(1, 1)
|
const electron = require('electron')
|
||||||
var version = require('remote').require('app').getVersion()
|
electron.webFrame.setZoomLevelLimits(1, 1)
|
||||||
|
var version = electron.remote.app.getVersion()
|
||||||
document.title = 'Boost' + ((version == null || version.length === 0) ? ' DEV' : '')
|
document.title = 'Boost' + ((version == null || version.length === 0) ? ' DEV' : '')
|
||||||
var scriptUrl = process.env.BOOST_ENV === 'development'
|
var scriptUrl = process.env.BOOST_ENV === 'development'
|
||||||
? 'http://localhost:8080/assets/main.js'
|
? 'http://localhost:8080/assets/main.js'
|
||||||
|
|||||||
@@ -11,13 +11,24 @@ require('../styles/main/index.styl')
|
|||||||
import { openModal } from 'boost/modal'
|
import { openModal } from 'boost/modal'
|
||||||
import Tutorial from 'boost/components/modal/Tutorial'
|
import Tutorial from 'boost/components/modal/Tutorial'
|
||||||
import activityRecord from 'boost/activityRecord'
|
import activityRecord from 'boost/activityRecord'
|
||||||
import ipc from 'ipc'
|
const electron = require('electron')
|
||||||
|
const ipc = electron.ipcRenderer
|
||||||
|
|
||||||
activityRecord.init()
|
activityRecord.init()
|
||||||
window.addEventListener('online', function () {
|
window.addEventListener('online', function () {
|
||||||
ipc.send('check-update', 'check-update')
|
ipc.send('check-update', 'check-update')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
function notify (...args) {
|
||||||
|
return new window.Notification(...args)
|
||||||
|
}
|
||||||
|
|
||||||
|
ipc.on('notify', function (e, payload) {
|
||||||
|
notify(payload.title, {
|
||||||
|
body: payload.body
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
let routes = (
|
let routes = (
|
||||||
<Route path='/' component={MainPage}>
|
<Route path='/' component={MainPage}>
|
||||||
<IndexRoute name='home' component={HomePage}/>
|
<IndexRoute name='home' component={HomePage}/>
|
||||||
|
|||||||
@@ -323,7 +323,8 @@ iptFocusBorderColor = #369DCD
|
|||||||
right 15px
|
right 15px
|
||||||
font-size 24px
|
font-size 24px
|
||||||
line-height 60px
|
line-height 60px
|
||||||
|
|
||||||
white-space nowrap
|
white-space nowrap
|
||||||
overflow-x auto
|
overflow-x auto
|
||||||
overflow-y hidden
|
overflow-y hidden
|
||||||
|
small
|
||||||
|
color #AAA
|
||||||
|
|||||||
@@ -48,6 +48,8 @@ articleItemColor = #777
|
|||||||
left 19px
|
left 19px
|
||||||
right 0
|
right 0
|
||||||
overflow ellipsis
|
overflow ellipsis
|
||||||
|
small
|
||||||
|
color #AAA
|
||||||
.bottom
|
.bottom
|
||||||
padding 5px 0
|
padding 5px 0
|
||||||
overflow-x auto
|
overflow-x auto
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ articleCount = #999
|
|||||||
.userProfileName
|
.userProfileName
|
||||||
color brandColor
|
color brandColor
|
||||||
font-size 28px
|
font-size 28px
|
||||||
padding 6px 0 0 10px
|
padding 6px 37px 0 10px
|
||||||
white-space nowrap
|
white-space nowrap
|
||||||
text-overflow ellipsis
|
text-overflow ellipsis
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
|||||||
@@ -62,6 +62,13 @@ infoBtnActiveBgColor = #3A3A3A
|
|||||||
opacity 1
|
opacity 1
|
||||||
&.hide
|
&.hide
|
||||||
opacity 0
|
opacity 0
|
||||||
|
ul
|
||||||
|
li:last-child
|
||||||
|
line-height 10px
|
||||||
|
margin-bottom 3px
|
||||||
|
small
|
||||||
|
font-size 10px
|
||||||
|
margin-left 15px
|
||||||
input
|
input
|
||||||
absolute top left
|
absolute top left
|
||||||
width 350px
|
width 350px
|
||||||
@@ -140,17 +147,33 @@ infoBtnActiveBgColor = #3A3A3A
|
|||||||
.tooltip
|
.tooltip
|
||||||
opacity 1
|
opacity 1
|
||||||
|
|
||||||
&>.logo
|
&>.linksBtn
|
||||||
display block
|
display block
|
||||||
position absolute
|
position absolute
|
||||||
top 8px
|
top 8px
|
||||||
right 15px
|
right 15px
|
||||||
opacity 0.7
|
opacity 0.7
|
||||||
.tooltip
|
|
||||||
tooltip()
|
|
||||||
margin-top 44px
|
|
||||||
margin-left -120px
|
|
||||||
&:hover
|
&:hover
|
||||||
opacity 1
|
opacity 1
|
||||||
.tooltip
|
.tooltip
|
||||||
opacity 1
|
opacity 1
|
||||||
|
&>.links-dropdown
|
||||||
|
position fixed
|
||||||
|
z-index 50
|
||||||
|
right 10px
|
||||||
|
top 40px
|
||||||
|
background-color transparentify(invBackgroundColor, 80%)
|
||||||
|
padding 5px 0
|
||||||
|
.links-item
|
||||||
|
padding 0 10px
|
||||||
|
height 33px
|
||||||
|
width 100%
|
||||||
|
display block
|
||||||
|
line-height 33px
|
||||||
|
text-decoration none
|
||||||
|
color white
|
||||||
|
&:hover
|
||||||
|
background-color transparentify(lighten(invBackgroundColor, 30%), 80%)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ marked()
|
|||||||
display list-item
|
display list-item
|
||||||
line-height 1.8em
|
line-height 1.8em
|
||||||
code
|
code
|
||||||
font-family monospace
|
font-family Monaco, Menlo, 'Ubuntu Mono', Consolas, source-code-pro, monospace;
|
||||||
padding 2px 4px
|
padding 2px 4px
|
||||||
border solid 1px borderColor
|
border solid 1px borderColor
|
||||||
border-radius 4px
|
border-radius 4px
|
||||||
@@ -77,6 +77,7 @@ marked()
|
|||||||
overflow-x auto
|
overflow-x auto
|
||||||
margin 15px 0 25px
|
margin 15px 0 25px
|
||||||
background-color #F6F6F6
|
background-color #F6F6F6
|
||||||
|
line-height 1.35em
|
||||||
&>code
|
&>code
|
||||||
padding 0
|
padding 0
|
||||||
border none
|
border none
|
||||||
|
|||||||
72
finder.js
Executable file
72
finder.js
Executable file
@@ -0,0 +1,72 @@
|
|||||||
|
const electron = require('electron')
|
||||||
|
const app = electron.app
|
||||||
|
const Tray = electron.Tray
|
||||||
|
const Menu = electron.Menu
|
||||||
|
const MenuItem = electron.MenuItem
|
||||||
|
|
||||||
|
process.stdin.setEncoding('utf8')
|
||||||
|
|
||||||
|
console.log = function () {
|
||||||
|
process.stdout.write(JSON.stringify({
|
||||||
|
type: 'log',
|
||||||
|
data: JSON.stringify(Array.prototype.slice.call(arguments).join(' '))
|
||||||
|
}), 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
function emit (type, data) {
|
||||||
|
process.stdout.write(JSON.stringify({
|
||||||
|
type: type,
|
||||||
|
data: JSON.stringify(data)
|
||||||
|
}), 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
|
var finderWindow
|
||||||
|
app.on('ready', function () {
|
||||||
|
app.dock.hide()
|
||||||
|
var appIcon = new Tray(__dirname + '/resources/tray-icon.png')
|
||||||
|
appIcon.setToolTip('Boost')
|
||||||
|
|
||||||
|
finderWindow = require('./atom-lib/finder-window')
|
||||||
|
finderWindow.webContents.on('did-finish-load', function () {
|
||||||
|
var trayMenu = new Menu()
|
||||||
|
trayMenu.append(new MenuItem({
|
||||||
|
label: 'Open Main window',
|
||||||
|
click: function () {
|
||||||
|
emit('show-main-window')
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
trayMenu.append(new MenuItem({
|
||||||
|
label: 'Open Finder window',
|
||||||
|
click: function () {
|
||||||
|
finderWindow.show()
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
trayMenu.append(new MenuItem({
|
||||||
|
label: 'Quit',
|
||||||
|
click: function () {
|
||||||
|
emit('quit-app')
|
||||||
|
}
|
||||||
|
}))
|
||||||
|
appIcon.setContextMenu(trayMenu)
|
||||||
|
|
||||||
|
process.stdin.on('data', function (payload) {
|
||||||
|
try {
|
||||||
|
payload = JSON.parse(payload)
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Not parsable payload : ', payload)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('from main >> ', payload.type)
|
||||||
|
switch (payload.type) {
|
||||||
|
case 'open-finder':
|
||||||
|
finderWindow.show()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
global.hideFinder = function () {
|
||||||
|
Menu.sendActionToFirstResponder('hide:')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
10
index.js
Normal file
10
index.js
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
function isFinderCalled () {
|
||||||
|
var argv = process.argv.slice(1)
|
||||||
|
return argv.some(arg => arg.match(/--finder/))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isFinderCalled()) {
|
||||||
|
require('./finder.js')
|
||||||
|
} else {
|
||||||
|
require('./main.js')
|
||||||
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
// Action types
|
// Action types
|
||||||
|
export const CLEAR_NEW_ARTICLE = 'CLEAR_NEW_ARTICLE'
|
||||||
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
|
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
|
||||||
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
|
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
|
||||||
export const FOLDER_CREATE = 'FOLDER_CREATE'
|
export const FOLDER_CREATE = 'FOLDER_CREATE'
|
||||||
@@ -18,13 +19,18 @@ export const TOGGLE_TUTORIAL = 'TOGGLE_TUTORIAL'
|
|||||||
|
|
||||||
// Status - mode
|
// Status - mode
|
||||||
export const IDLE_MODE = 'IDLE_MODE'
|
export const IDLE_MODE = 'IDLE_MODE'
|
||||||
export const CREATE_MODE = 'CREATE_MODE'
|
|
||||||
export const EDIT_MODE = 'EDIT_MODE'
|
export const EDIT_MODE = 'EDIT_MODE'
|
||||||
|
|
||||||
// Article status
|
// Article status
|
||||||
export const NEW = 'NEW'
|
export const NEW = 'NEW'
|
||||||
|
|
||||||
// DB
|
// DB
|
||||||
|
export function clearNewArticle () {
|
||||||
|
return {
|
||||||
|
type: CLEAR_NEW_ARTICLE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
export function updateArticle (article) {
|
export function updateArticle (article) {
|
||||||
return {
|
return {
|
||||||
type: ARTICLE_UPDATE,
|
type: ARTICLE_UPDATE,
|
||||||
@@ -84,10 +90,13 @@ export function switchMode (mode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function switchArticle (articleKey) {
|
export function switchArticle (articleKey, isNew) {
|
||||||
return {
|
return {
|
||||||
type: SWITCH_ARTICLE,
|
type: SWITCH_ARTICLE,
|
||||||
data: articleKey
|
data: {
|
||||||
|
key: articleKey,
|
||||||
|
isNew: isNew
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,10 @@ Post all records(except today)
|
|||||||
and remove all posted records
|
and remove all posted records
|
||||||
*/
|
*/
|
||||||
export function postRecords (data) {
|
export function postRecords (data) {
|
||||||
|
if (process.env.BOOST_ENV === 'development') {
|
||||||
|
console.log('post failed - on development')
|
||||||
|
return
|
||||||
|
}
|
||||||
let records = getAllRecords()
|
let records = getAllRecords()
|
||||||
records = records.filter(record => {
|
records = records.filter(record => {
|
||||||
return !isSameDate(new Date(), record.date)
|
return !isSameDate(new Date(), record.date)
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import shell from 'shell'
|
const electron = require('electron')
|
||||||
|
const shell = electron.shell
|
||||||
|
|
||||||
export default class ExternalLink extends React.Component {
|
export default class ExternalLink extends React.Component {
|
||||||
handleClick (e) {
|
handleClick (e) {
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
import shell from 'shell'
|
|
||||||
var React = require('react')
|
var React = require('react')
|
||||||
var { PropTypes } = React
|
var { PropTypes } = React
|
||||||
import markdown from 'boost/markdown'
|
import markdown from 'boost/markdown'
|
||||||
var ReactDOM = require('react-dom')
|
var ReactDOM = require('react-dom')
|
||||||
|
|
||||||
|
const electron = require('electron')
|
||||||
|
const shell = electron.shell
|
||||||
|
|
||||||
function handleAnchorClick (e) {
|
function handleAnchorClick (e) {
|
||||||
shell.openExternal(e.target.href)
|
shell.openExternal(e.target.href)
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
import linkState from 'boost/linkState'
|
import linkState from 'boost/linkState'
|
||||||
import { createFolder } from 'boost/actions'
|
import { createFolder } from 'boost/actions'
|
||||||
import store from 'boost/store'
|
import store from 'boost/store'
|
||||||
@@ -15,6 +16,10 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
ReactDOM.findDOMNode(this.refs.folderName).focus()
|
||||||
|
}
|
||||||
|
|
||||||
handleCloseButton (e) {
|
handleCloseButton (e) {
|
||||||
this.props.close()
|
this.props.close()
|
||||||
}
|
}
|
||||||
@@ -84,7 +89,7 @@ export default class CreateNewFolder extends React.Component {
|
|||||||
|
|
||||||
<div className='title'>Create new folder</div>
|
<div className='title'>Create new folder</div>
|
||||||
|
|
||||||
<input onKeyDown={e => this.handleKeyDown(e)} className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
|
<input ref='folderName' onKeyDown={e => this.handleKeyDown(e)} className='ipt' type='text' valueLink={this.linkState('name')} placeholder='Enter folder name'/>
|
||||||
<div className='colorSelect'>
|
<div className='colorSelect'>
|
||||||
{colorElements}
|
{colorElements}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
import React, { PropTypes } from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
import store from 'boost/store'
|
import store from 'boost/store'
|
||||||
import { unlockStatus } from 'boost/actions'
|
import { unlockStatus, clearNewArticle } from 'boost/actions'
|
||||||
|
|
||||||
export default class EditedAlert extends React.Component {
|
export default class EditedAlert extends React.Component {
|
||||||
|
componentDidMount () {
|
||||||
|
ReactDOM.findDOMNode(this.refs.no).focus()
|
||||||
|
}
|
||||||
|
|
||||||
handleNoButtonClick (e) {
|
handleNoButtonClick (e) {
|
||||||
this.props.close()
|
this.props.close()
|
||||||
}
|
}
|
||||||
@@ -10,6 +15,7 @@ export default class EditedAlert extends React.Component {
|
|||||||
handleYesButtonClick (e) {
|
handleYesButtonClick (e) {
|
||||||
store.dispatch(unlockStatus())
|
store.dispatch(unlockStatus())
|
||||||
store.dispatch(this.props.action)
|
store.dispatch(this.props.action)
|
||||||
|
store.dispatch(clearNewArticle())
|
||||||
this.props.close()
|
this.props.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -21,8 +27,8 @@ export default class EditedAlert extends React.Component {
|
|||||||
<div className='message'>Do you really want to leave without finishing?</div>
|
<div className='message'>Do you really want to leave without finishing?</div>
|
||||||
|
|
||||||
<div className='control'>
|
<div className='control'>
|
||||||
<button onClick={e => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close'/> No</button>
|
<button ref='no' onClick={e => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close'/> No</button>
|
||||||
<button onClick={e => this.handleYesButtonClick(e)} className='primary'><i className='fa fa-fw fa-check'/> Yes</button>
|
<button ref='yes' onClick={e => this.handleYesButtonClick(e)} className='primary'><i className='fa fa-fw fa-check'/> Yes</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import linkState from 'boost/linkState'
|
import linkState from 'boost/linkState'
|
||||||
import remote from 'remote'
|
|
||||||
import ipc from 'ipc'
|
const electron = require('electron')
|
||||||
|
const ipc = electron.ipcRenderer
|
||||||
|
const remote = electron.remote
|
||||||
|
|
||||||
export default class AppSettingTab extends React.Component {
|
export default class AppSettingTab extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -47,7 +49,9 @@ export default class AppSettingTab extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleKeyDown (e) {
|
handleKeyDown (e) {
|
||||||
this.submitHotKey()
|
if (e.keyCode === 13) {
|
||||||
|
this.submitHotKey()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
|||||||
@@ -83,158 +83,6 @@ class Preferences extends React.Component {
|
|||||||
return (<AppSettingTab/>)
|
return (<AppSettingTab/>)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// handleProfileSaveButtonClick (e) {
|
|
||||||
// let profileState = this.state.profile
|
|
||||||
// profileState.userInfo.alert = {
|
|
||||||
// type: 'info',
|
|
||||||
// message: 'Sending...'
|
|
||||||
// }
|
|
||||||
// this.setState({profile: profileState}, () => {
|
|
||||||
// let input = {
|
|
||||||
// profileName: profileState.userInfo.profileName,
|
|
||||||
// email: profileState.userInfo.email
|
|
||||||
// }
|
|
||||||
// api.updateUserInfo(input)
|
|
||||||
// .then(res => {
|
|
||||||
// let profileState = this.state.profile
|
|
||||||
// profileState.userInfo.alert = {
|
|
||||||
// type: 'success',
|
|
||||||
// message: 'Successfully done!'
|
|
||||||
// }
|
|
||||||
// this.setState({profile: profileState})
|
|
||||||
// })
|
|
||||||
// .catch(err => {
|
|
||||||
// var message
|
|
||||||
// if (err.status != null) {
|
|
||||||
// message = err.response.body.message
|
|
||||||
// } else if (err.code === 'ECONNREFUSED') {
|
|
||||||
// message = 'Can\'t connect to API server.'
|
|
||||||
// } else throw err
|
|
||||||
|
|
||||||
// let profileState = this.state.profile
|
|
||||||
// profileState.userInfo.alert = {
|
|
||||||
// type: 'error',
|
|
||||||
// message: message
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.setState({profile: profileState})
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// handlePasswordSaveButton (e) {
|
|
||||||
// let profileState = this.state.profile
|
|
||||||
|
|
||||||
// if (profileState.password.newPassword !== profileState.password.confirmation) {
|
|
||||||
// profileState.password.alert = {
|
|
||||||
// type: 'error',
|
|
||||||
// message: 'Confirmation doesn\'t match'
|
|
||||||
// }
|
|
||||||
// this.setState({profile: profileState})
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
|
|
||||||
// profileState.password.alert = {
|
|
||||||
// type: 'info',
|
|
||||||
// message: 'Sending...'
|
|
||||||
// }
|
|
||||||
|
|
||||||
// this.setState({profile: profileState}, () => {
|
|
||||||
// let input = {
|
|
||||||
// password: profileState.password.currentPassword,
|
|
||||||
// newPassword: profileState.password.newPassword
|
|
||||||
// }
|
|
||||||
// api.updatePassword(input)
|
|
||||||
// .then(res => {
|
|
||||||
// let profileState = this.state.profile
|
|
||||||
// profileState.password.alert = {
|
|
||||||
// type: 'success',
|
|
||||||
// message: 'Successfully done!'
|
|
||||||
// }
|
|
||||||
// profileState.password.currentPassword = ''
|
|
||||||
// profileState.password.newPassword = ''
|
|
||||||
// profileState.password.confirmation = ''
|
|
||||||
|
|
||||||
// this.setState({profile: profileState})
|
|
||||||
// })
|
|
||||||
// .catch(err => {
|
|
||||||
// var message
|
|
||||||
// if (err.status != null) {
|
|
||||||
// message = err.response.body.message
|
|
||||||
// } else if (err.code === 'ECONNREFUSED') {
|
|
||||||
// message = 'Can\'t connect to API server.'
|
|
||||||
// } else throw err
|
|
||||||
|
|
||||||
// let profileState = this.state.profile
|
|
||||||
// profileState.password.alert = {
|
|
||||||
// type: 'error',
|
|
||||||
// message: message
|
|
||||||
// }
|
|
||||||
// profileState.password.currentPassword = ''
|
|
||||||
// profileState.password.newPassword = ''
|
|
||||||
// profileState.password.confirmation = ''
|
|
||||||
|
|
||||||
// this.setState({profile: profileState}, () => {
|
|
||||||
// if (this.refs.currentPassword != null) findDOMNode(this.refs.currentPassword).focus()
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// renderProfile () {
|
|
||||||
// let profileState = this.state.profile
|
|
||||||
// return (
|
|
||||||
// <div className='content profile'>
|
|
||||||
// <div className='section userSection'>
|
|
||||||
// <div className='sectionTitle'>User Info</div>
|
|
||||||
// <div className='sectionInput'>
|
|
||||||
// <label>Profile Name</label>
|
|
||||||
// <input valueLink={this.linkState('profile.userInfo.profileName')} type='text'/>
|
|
||||||
// </div>
|
|
||||||
// <div className='sectionInput'>
|
|
||||||
// <label>E-mail</label>
|
|
||||||
// <input valueLink={this.linkState('profile.userInfo.email')} type='text'/>
|
|
||||||
// </div>
|
|
||||||
// <div className='sectionConfirm'>
|
|
||||||
// <button onClick={e => this.handleProfileSaveButtonClick(e)}>Save</button>
|
|
||||||
|
|
||||||
// {this.state.profile.userInfo.alert != null
|
|
||||||
// ? (
|
|
||||||
// <div className={'alert ' + profileState.userInfo.alert.type}>{profileState.userInfo.alert.message}</div>
|
|
||||||
// )
|
|
||||||
// : null}
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
|
|
||||||
// <div className='section passwordSection'>
|
|
||||||
// <div className='sectionTitle'>Password</div>
|
|
||||||
// <div className='sectionInput'>
|
|
||||||
// <label>Current Password</label>
|
|
||||||
// <input ref='currentPassword' valueLink={this.linkState('profile.password.currentPassword')} type='password' placeholder='Current Password'/>
|
|
||||||
// </div>
|
|
||||||
// <div className='sectionInput'>
|
|
||||||
// <label>New Password</label>
|
|
||||||
// <input valueLink={this.linkState('profile.password.newPassword')} type='password' placeholder='New Password'/>
|
|
||||||
// </div>
|
|
||||||
// <div className='sectionInput'>
|
|
||||||
// <label>Confirmation</label>
|
|
||||||
// <input valueLink={this.linkState('profile.password.confirmation')} type='password' placeholder='Confirmation'/>
|
|
||||||
// </div>
|
|
||||||
// <div className='sectionConfirm'>
|
|
||||||
// <button onClick={e => this.handlePasswordSaveButton(e)}>Save</button>
|
|
||||||
|
|
||||||
// {profileState.password.alert != null
|
|
||||||
// ? (
|
|
||||||
// <div className={'alert ' + profileState.password.alert.type}>{profileState.password.alert.message}</div>
|
|
||||||
// )
|
|
||||||
// : null}
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// </div>
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Preferences.propTypes = {
|
Preferences.propTypes = {
|
||||||
|
|||||||
@@ -1,11 +1,27 @@
|
|||||||
import keygen from 'boost/keygen'
|
import keygen from 'boost/keygen'
|
||||||
|
const electron = require('electron')
|
||||||
|
const remote = electron.remote
|
||||||
|
const jetpack = require('fs-jetpack')
|
||||||
|
const path = require('path')
|
||||||
|
|
||||||
let defaultContent = 'Boost is a brand new note App for programmers.\n\n> 下に日本語版があります。\n\n# \u25CEfeature\n\nBoost has some preponderant functions for efficient engineer\'s task.See some part of it.\n\n1. classify information by\u300CFolders\u300D\n2. deal with great variety of syntax\n3. Finder function\n\n\uFF0A\u3000\uFF0A\u3000\uFF0A\u3000\uFF0A\n\n# 1. classify information by \u300CFolders\u300D- access the information you needed easily.\n\n\u300CFolders\u300D which on the left side bar. Press plus button now. flexible way of classification.\n- Create Folder every language or flamework\n- Make Folder for your own casual memos\n\n# 2. Deal with a great variety of syntax \u2013 instead of your brain\nSave handy all information related with programming\n- Use markdown and gather api specification\n- Well using module and snippet\n\nSave them on Boost, you don\'t need to rewrite or re-search same code again.\n\n# 3. Load Finder function \u2013 now you don\'t need to spell command by hand typing.\n\n**Shift +cmd+tab** press buttons at same time.\nThen, the window will show up for search Boost contents that instant.\n\nUsing cursor key to chose, press enter, cmd+v to paste and\u2026 please check it out by your own eye.\n\n- Such command spl or linux which programmers often use but troublesome to hand type\n\n- (Phrases commonly used for e-mail or customer support)\n\nWe support preponderant efficiency\n\n\uFF0A\u3000\uFF0A\u3000\uFF0A\u3000\uFF0A\n\n## \u25CEfor more information\nFrequently updated with this blog ( http:\/\/blog-jp.b00st.io )\n\nHave wonderful programmer life!\n\n## Hack your memory**\n\n\n\n# 日本語版\n\n**Boost**は全く新しいエンジニアライクのノートアプリです。\n\n# ◎特徴\nBoostはエンジニアの仕事を圧倒的に効率化するいくつかの機能を備えています。\nその一部をご紹介します。\n1. Folderで情報を分類\n2. 豊富なsyantaxに対応\n3. Finder機能\n4. チーム機能(リアルタイム搭載)\n\n* * * *\n\n# 1. Folderで情報を分類、欲しい情報にすぐアクセス。\n左側のバーに存在する「Folders」。\n今すぐプラスボタンを押しましょう。\n分類の仕方も自由自在です。\n- 言語やフレームワークごとにFolderを作成\n- 自分用のカジュアルなメモをまとめる場としてFolderを作成\n\n\n# 2. 豊富なsyntaxに対応、自分の脳の代わりに。\nプログラミングに関する情報を全て、手軽に保存しましょう。\n- mdで、apiの仕様をまとめる\n- よく使うモジュールやスニペット\n\nBoostに保存しておくことで、何度も同じコードを書いたり調べたりする必要がなくなります。\n\n# 3. Finder機能を搭載、もうコマンドを手打ちする必要はありません。\n**「shift+cmd+tab」** を同時に押してみてください。\nここでは、一瞬でBoostの中身を検索するウィンドウを表示させることができます。\n\n矢印キーで選択、Enterを押し、cmd+vでペーストすると…続きはご自身の目でお確かめください。\n- sqlやlinux等の、よく使うが手打ちが面倒なコマンド\n- (メールやカスタマーサポート等でよく使うフレーズ)\n\n私たちは、圧倒的な効率性を支援します。\n\* * * *\n\n\n## ◎詳しくは\nこちらのブログ( http://blog-jp.b00st.io )にて随時更新しています。\n\nそれでは素晴らしいエンジニアライフを!\n\n## Hack your memory**'
|
let defaultContent = 'Boost is a brand new note App for programmers.\n\n> 下に日本語版があります。\n\n# \u25CEfeature\n\nBoost has some preponderant functions for efficient engineer\'s task.See some part of it.\n\n1. classify information by\u300CFolders\u300D\n2. deal with great variety of syntax\n3. Finder function\n\n\uFF0A\u3000\uFF0A\u3000\uFF0A\u3000\uFF0A\n\n# 1. classify information by \u300CFolders\u300D- access the information you needed easily.\n\n\u300CFolders\u300D which on the left side bar. Press plus button now. flexible way of classification.\n- Create Folder every language or flamework\n- Make Folder for your own casual memos\n\n# 2. Deal with a great variety of syntax \u2013 instead of your brain\nSave handy all information related with programming\n- Use markdown and gather api specification\n- Well using module and snippet\n\nSave them on Boost, you don\'t need to rewrite or re-search same code again.\n\n# 3. Load Finder function \u2013 now you don\'t need to spell command by hand typing.\n\n**Shift +ctrl+tab** press buttons at same time.\nThen, the window will show up for search Boost contents that instant.\n\nUsing cursor key to chose, press enter, cmd+v to paste and\u2026 please check it out by your own eye.\n\n- Such command spl or linux which programmers often use but troublesome to hand type\n\n- (Phrases commonly used for e-mail or customer support)\n\nWe support preponderant efficiency\n\n\uFF0A\u3000\uFF0A\u3000\uFF0A\u3000\uFF0A\n\n## \u25CEfor more information\nFrequently updated with this blog ( http:\/\/blog-jp.b00st.io )\n\nHave wonderful programmer life!\n\n## Hack your memory**\n\n\n\n# 日本語版\n\n**Boost**は全く新しいエンジニアライクのノートアプリです。\n\n# ◎特徴\nBoostはエンジニアの仕事を圧倒的に効率化するいくつかの機能を備えています。\nその一部をご紹介します。\n1. Folderで情報を分類\n2. 豊富なsyantaxに対応\n3. Finder機能\n\n\n* * * *\n\n# 1. Folderで情報を分類、欲しい情報にすぐアクセス。\n左側のバーに存在する「Folders」。\n今すぐプラスボタンを押しましょう。\n分類の仕方も自由自在です。\n- 言語やフレームワークごとにFolderを作成\n- 自分用のカジュアルなメモをまとめる場としてFolderを作成\n\n\n# 2. 豊富なsyntaxに対応、自分の脳の代わりに。\nプログラミングに関する情報を全て、手軽に保存しましょう。\n- mdで、apiの仕様をまとめる\n- よく使うモジュールやスニペット\n\nBoostに保存しておくことで、何度も同じコードを書いたり調べたりする必要がなくなります。\n\n# 3. Finder機能を搭載、もうコマンドを手打ちする必要はありません。\n**「shift+ctrl+tab」** を同時に押してみてください。\nここでは、一瞬でBoostの中身を検索するウィンドウを表示させることができます。\n\n矢印キーで選択、Enterを押し、cmd+vでペーストすると…続きはご自身の目でお確かめください。\n- sqlやlinux等の、よく使うが手打ちが面倒なコマンド\n- (メールやカスタマーサポート等でよく使うフレーズ)\n\n私たちは、圧倒的な効率性を支援します。\n\* * * *\n\n\n## ◎詳しくは\nこちらのブログ( http://blog-jp.b00st.io )にて随時更新しています。\n\nそれでは素晴らしいエンジニアライフを!\n\n## Hack your memory**'
|
||||||
|
|
||||||
|
function getLocalPath () {
|
||||||
|
return path.join(remote.app.getPath('userData'), 'local.json')
|
||||||
|
}
|
||||||
|
|
||||||
export function init () {
|
export function init () {
|
||||||
console.log('initialize data store')
|
console.log('initialize data store')
|
||||||
let data = JSON.parse(localStorage.getItem('local'))
|
let data = jetpack.read(getLocalPath(), 'json')
|
||||||
|
|
||||||
if (data == null) {
|
if (data == null) {
|
||||||
|
if (localStorage.getItem('local') != null) {
|
||||||
|
data = JSON.parse(localStorage.getItem('local'))
|
||||||
|
jetpack.write(getLocalPath(), data)
|
||||||
|
localStorage.removeItem('local')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
let defaultFolder = {
|
let defaultFolder = {
|
||||||
name: 'default',
|
name: 'default',
|
||||||
key: keygen()
|
key: keygen()
|
||||||
@@ -24,37 +40,35 @@ export function init () {
|
|||||||
folders: [defaultFolder],
|
folders: [defaultFolder],
|
||||||
version: '0.4'
|
version: '0.4'
|
||||||
}
|
}
|
||||||
localStorage.setItem('local', JSON.stringify(data))
|
jetpack.write(getLocalPath(), data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getKey (teamId) {
|
export function getData () {
|
||||||
return teamId == null
|
return jetpack.read(getLocalPath(), 'json')
|
||||||
? 'local'
|
|
||||||
: `team-${teamId}`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getData (teamId) {
|
export function setArticles (articles) {
|
||||||
let key = getKey(teamId)
|
let data = getData()
|
||||||
return JSON.parse(localStorage.getItem(key))
|
|
||||||
}
|
|
||||||
|
|
||||||
export function setArticles (teamId, articles) {
|
|
||||||
let key = getKey(teamId)
|
|
||||||
let data = JSON.parse(localStorage.getItem(key))
|
|
||||||
data.articles = articles
|
data.articles = articles
|
||||||
localStorage.setItem(key, JSON.stringify(data))
|
jetpack.write(getLocalPath(), data)
|
||||||
}
|
}
|
||||||
|
|
||||||
export function setFolders (teamId, folders) {
|
export function setFolders (folders) {
|
||||||
let key = getKey(teamId)
|
let data = getData()
|
||||||
let data = JSON.parse(localStorage.getItem(key))
|
|
||||||
data.folders = folders
|
data.folders = folders
|
||||||
localStorage.setItem(key, JSON.stringify(data))
|
jetpack.write(getLocalPath(), data)
|
||||||
|
}
|
||||||
|
|
||||||
|
function isFinderCalled () {
|
||||||
|
var argv = process.argv.slice(1)
|
||||||
|
return argv.some(arg => arg.match(/--finder/))
|
||||||
}
|
}
|
||||||
|
|
||||||
export default (function () {
|
export default (function () {
|
||||||
init()
|
if (!isFinderCalled()) {
|
||||||
|
init()
|
||||||
|
}
|
||||||
return {
|
return {
|
||||||
init,
|
init,
|
||||||
getData,
|
getData,
|
||||||
|
|||||||
@@ -1,9 +1,25 @@
|
|||||||
import markdownit from 'markdown-it'
|
import markdownit from 'markdown-it'
|
||||||
|
import hljs from 'highlight.js'
|
||||||
|
import emoji from 'markdown-it-emoji'
|
||||||
|
|
||||||
var md = markdownit({
|
var md = markdownit({
|
||||||
typographer: true,
|
typographer: true,
|
||||||
linkify: true
|
linkify: true,
|
||||||
|
highlight: function (str, lang) {
|
||||||
|
if (lang && hljs.getLanguage(lang)) {
|
||||||
|
try {
|
||||||
|
return hljs.highlight(lang, str).value;
|
||||||
|
} catch (__) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return hljs.highlightAuto(str).value;
|
||||||
|
} catch (__) {}
|
||||||
|
|
||||||
|
return ''; // use external default escaping
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
md.use(emoji)
|
||||||
|
|
||||||
export default function markdown (content) {
|
export default function markdown (content) {
|
||||||
if (content == null) content = ''
|
if (content == null) content = ''
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
var shell = require('shell')
|
const electron = require('electron')
|
||||||
|
const shell = electron.shell
|
||||||
|
|
||||||
export default function (e) {
|
export default function (e) {
|
||||||
shell.openExternal(e.currentTarget.href)
|
shell.openExternal(e.currentTarget.href)
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import {
|
|||||||
// Article action type
|
// Article action type
|
||||||
ARTICLE_UPDATE,
|
ARTICLE_UPDATE,
|
||||||
ARTICLE_DESTROY,
|
ARTICLE_DESTROY,
|
||||||
|
CLEAR_NEW_ARTICLE,
|
||||||
|
|
||||||
// Folder action type
|
// Folder action type
|
||||||
FOLDER_CREATE,
|
FOLDER_CREATE,
|
||||||
@@ -23,8 +24,7 @@ import {
|
|||||||
FOLDER_REPLACE,
|
FOLDER_REPLACE,
|
||||||
|
|
||||||
// view mode
|
// view mode
|
||||||
IDLE_MODE,
|
IDLE_MODE
|
||||||
CREATE_MODE
|
|
||||||
} from './actions'
|
} from './actions'
|
||||||
import dataStore from 'boost/dataStore'
|
import dataStore from 'boost/dataStore'
|
||||||
import keygen from 'boost/keygen'
|
import keygen from 'boost/keygen'
|
||||||
@@ -43,6 +43,9 @@ let data = dataStore.getData()
|
|||||||
let initialArticles = data.articles
|
let initialArticles = data.articles
|
||||||
let initialFolders = data.folders
|
let initialFolders = data.folders
|
||||||
|
|
||||||
|
let isStatusLocked = false
|
||||||
|
let isCreatingNew = false
|
||||||
|
|
||||||
function folders (state = initialFolders, action) {
|
function folders (state = initialFolders, action) {
|
||||||
state = state.slice()
|
state = state.slice()
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
@@ -64,7 +67,7 @@ function folders (state = initialFolders, action) {
|
|||||||
if (conflictFolder != null) throw new Error(`${newFolder.name} already exists!`)
|
if (conflictFolder != null) throw new Error(`${newFolder.name} already exists!`)
|
||||||
state.push(newFolder)
|
state.push(newFolder)
|
||||||
|
|
||||||
dataStore.setFolders(null, state)
|
dataStore.setFolders(state)
|
||||||
activityRecord.emit('FOLDER_CREATE')
|
activityRecord.emit('FOLDER_CREATE')
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@@ -91,7 +94,7 @@ function folders (state = initialFolders, action) {
|
|||||||
updatedAt: new Date()
|
updatedAt: new Date()
|
||||||
})
|
})
|
||||||
|
|
||||||
dataStore.setFolders(null, state)
|
dataStore.setFolders(state)
|
||||||
activityRecord.emit('FOLDER_UPDATE')
|
activityRecord.emit('FOLDER_UPDATE')
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@@ -104,7 +107,7 @@ function folders (state = initialFolders, action) {
|
|||||||
if (targetIndex >= 0) {
|
if (targetIndex >= 0) {
|
||||||
state.splice(targetIndex, 1)
|
state.splice(targetIndex, 1)
|
||||||
}
|
}
|
||||||
dataStore.setFolders(null, state)
|
dataStore.setFolders(state)
|
||||||
activityRecord.emit('FOLDER_DESTROY')
|
activityRecord.emit('FOLDER_DESTROY')
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
@@ -121,10 +124,41 @@ function folders (state = initialFolders, action) {
|
|||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let isCleaned = true
|
||||||
function articles (state = initialArticles, action) {
|
function articles (state = initialArticles, action) {
|
||||||
state = state.slice()
|
state = state.slice()
|
||||||
|
|
||||||
|
if (!isCreatingNew && !isCleaned) {
|
||||||
|
state = state.filter(article => article.status !== 'NEW')
|
||||||
|
isCleaned = true
|
||||||
|
}
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
|
case SWITCH_ARTICLE:
|
||||||
|
if (action.data.isNew) {
|
||||||
|
isCleaned = false
|
||||||
|
}
|
||||||
|
if (!isStatusLocked && !action.data.isNew) {
|
||||||
|
isCreatingNew = false
|
||||||
|
if (!isCleaned) {
|
||||||
|
state = state.filter(article => article.status !== 'NEW')
|
||||||
|
isCleaned = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
case SWITCH_FOLDER:
|
||||||
|
case SET_SEARCH_FILTER:
|
||||||
|
case SET_TAG_FILTER:
|
||||||
|
case CLEAR_SEARCH:
|
||||||
|
if (!isStatusLocked) {
|
||||||
|
isCreatingNew = false
|
||||||
|
if (!isCleaned) {
|
||||||
|
state = state.filter(article => article.status !== 'NEW')
|
||||||
|
isCleaned = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return state
|
||||||
|
case CLEAR_NEW_ARTICLE:
|
||||||
|
return state.filter(article => article.status !== 'NEW')
|
||||||
case ARTICLE_UPDATE:
|
case ARTICLE_UPDATE:
|
||||||
{
|
{
|
||||||
let article = action.data.article
|
let article = action.data.article
|
||||||
@@ -133,7 +167,8 @@ function articles (state = initialArticles, action) {
|
|||||||
if (targetIndex < 0) state.unshift(article)
|
if (targetIndex < 0) state.unshift(article)
|
||||||
else state.splice(targetIndex, 1, article)
|
else state.splice(targetIndex, 1, article)
|
||||||
|
|
||||||
dataStore.setArticles(null, state)
|
if (article.status !== 'NEW') dataStore.setArticles(state)
|
||||||
|
else isCreatingNew = true
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
case ARTICLE_DESTROY:
|
case ARTICLE_DESTROY:
|
||||||
@@ -143,7 +178,7 @@ function articles (state = initialArticles, action) {
|
|||||||
let targetIndex = _.findIndex(state, _article => articleKey === _article.key)
|
let targetIndex = _.findIndex(state, _article => articleKey === _article.key)
|
||||||
if (targetIndex >= 0) state.splice(targetIndex, 1)
|
if (targetIndex >= 0) state.splice(targetIndex, 1)
|
||||||
|
|
||||||
dataStore.setArticles(null, state)
|
dataStore.setArticles(state)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
case FOLDER_DESTROY:
|
case FOLDER_DESTROY:
|
||||||
@@ -152,7 +187,7 @@ function articles (state = initialArticles, action) {
|
|||||||
|
|
||||||
state = state.filter(article => article.FolderKey !== folderKey)
|
state = state.filter(article => article.FolderKey !== folderKey)
|
||||||
|
|
||||||
dataStore.setArticles(null, state)
|
dataStore.setArticles(state)
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@@ -162,16 +197,15 @@ function articles (state = initialArticles, action) {
|
|||||||
|
|
||||||
function status (state = initialStatus, action) {
|
function status (state = initialStatus, action) {
|
||||||
state = Object.assign({}, state)
|
state = Object.assign({}, state)
|
||||||
|
|
||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case TOGGLE_TUTORIAL:
|
case TOGGLE_TUTORIAL:
|
||||||
state.isTutorialOpen = !state.isTutorialOpen
|
state.isTutorialOpen = !state.isTutorialOpen
|
||||||
return state
|
return state
|
||||||
case LOCK_STATUS:
|
case LOCK_STATUS:
|
||||||
state.isStatusLocked = true
|
isStatusLocked = state.isStatusLocked = true
|
||||||
return state
|
return state
|
||||||
case UNLOCK_STATUS:
|
case UNLOCK_STATUS:
|
||||||
state.isStatusLocked = false
|
isStatusLocked = state.isStatusLocked = false
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -188,11 +222,10 @@ function status (state = initialStatus, action) {
|
|||||||
return state
|
return state
|
||||||
case SWITCH_MODE:
|
case SWITCH_MODE:
|
||||||
state.mode = action.data
|
state.mode = action.data
|
||||||
if (state.mode === CREATE_MODE) state.articleKey = null
|
|
||||||
|
|
||||||
return state
|
return state
|
||||||
case SWITCH_ARTICLE:
|
case SWITCH_ARTICLE:
|
||||||
state.articleKey = action.data
|
state.articleKey = action.data.key
|
||||||
state.mode = IDLE_MODE
|
state.mode = IDLE_MODE
|
||||||
|
|
||||||
return state
|
return state
|
||||||
|
|||||||
190
main.js
190
main.js
@@ -1,61 +1,83 @@
|
|||||||
var app = require('app')
|
const electron = require('electron')
|
||||||
var Menu = require('menu')
|
const app = electron.app
|
||||||
var MenuItem = require('menu-item')
|
const Menu = electron.Menu
|
||||||
var Tray = require('tray')
|
const ipc = electron.ipcMain
|
||||||
var ipc = require('ipc')
|
const globalShortcut = electron.globalShortcut
|
||||||
var jetpack = require('fs-jetpack')
|
const autoUpdater = electron.autoUpdater
|
||||||
|
const jetpack = require('fs-jetpack')
|
||||||
require('crash-reporter').start()
|
const path = require('path')
|
||||||
|
const ChildProcess = require('child_process')
|
||||||
|
electron.crashReporter.start()
|
||||||
|
|
||||||
var mainWindow = null
|
var mainWindow = null
|
||||||
var appIcon = null
|
var finderProcess
|
||||||
var menu = null
|
|
||||||
var finderWindow = null
|
|
||||||
|
|
||||||
var update = null
|
var update = null
|
||||||
|
|
||||||
// app.on('window-all-closed', function () {
|
// app.on('window-all-closed', function () {
|
||||||
// if (process.platform !== 'darwin') app.quit()
|
// if (process.platform !== 'darwin') app.quit()
|
||||||
// })
|
// })
|
||||||
|
|
||||||
var version = app.getVersion()
|
|
||||||
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
|
||||||
var nn = require('node-notifier')
|
|
||||||
var updater = require('./atom-lib/updater')
|
|
||||||
var path = require('path')
|
|
||||||
|
|
||||||
var appQuit = false
|
var appQuit = false
|
||||||
|
|
||||||
updater
|
var version = app.getVersion()
|
||||||
.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
|
var versionText = (version == null || version.length === 0) ? 'DEV version' : 'v' + version
|
||||||
nn.notify({
|
var versionNotified = false
|
||||||
title: 'Ready to Update!! ' + versionText,
|
|
||||||
icon: path.join(__dirname, '/resources/favicon-230x230.png'),
|
function notify (title, body) {
|
||||||
message: 'Click update button on Main window: ' + releaseName
|
if (mainWindow != null) {
|
||||||
|
mainWindow.webContents.send('notify', {
|
||||||
|
title: title,
|
||||||
|
body: body
|
||||||
})
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
autoUpdater
|
||||||
|
.on('update-downloaded', function (event, releaseNotes, releaseName, releaseDate, updateUrl, quitAndUpdate) {
|
||||||
update = quitAndUpdate
|
update = quitAndUpdate
|
||||||
|
|
||||||
if (mainWindow != null && !mainWindow.webContents.isLoading()) {
|
if (mainWindow != null) {
|
||||||
|
notify('Ready to Update! ' + releaseName, 'Click update button on Main window.')
|
||||||
mainWindow.webContents.send('update-available', 'Update available!')
|
mainWindow.webContents.send('update-available', 'Update available!')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
.on('error', function (err, message) {
|
||||||
|
console.error(err)
|
||||||
|
if (!versionNotified) {
|
||||||
|
notify('Updater error!', message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
// .on('checking-for-update', function () {
|
||||||
|
// // Connecting
|
||||||
|
// console.log('checking...')
|
||||||
|
// })
|
||||||
|
.on('update-available', function () {
|
||||||
|
notify('Update is available!', 'Download started.. wait for the update ready.')
|
||||||
|
})
|
||||||
|
.on('update-not-available', function () {
|
||||||
|
if (mainWindow != null && !versionNotified) {
|
||||||
|
versionNotified = true
|
||||||
|
notify('Latest Build!! ' + versionText, 'Hope you to enjoy our app :D')
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
app.on('ready', function () {
|
app.on('ready', function () {
|
||||||
app.on('before-quit', function () {
|
app.on('before-quit', function () {
|
||||||
|
if (finderProcess) finderProcess.kill()
|
||||||
appQuit = true
|
appQuit = true
|
||||||
})
|
})
|
||||||
console.log('Version ' + version)
|
autoUpdater.setFeedURL('https://orbital.b00st.io/rokt33r/boost-app/latest?version=' + version)
|
||||||
updater.setFeedUrl('http://orbital.b00st.io/rokt33r/boost-app/latest?version=' + version)
|
|
||||||
updater.checkForUpdates()
|
|
||||||
// menu start
|
|
||||||
var template = require('./atom-lib/menu-template')
|
var template = require('./atom-lib/menu-template')
|
||||||
|
var menu = Menu.buildFromTemplate(template)
|
||||||
|
Menu.setApplicationMenu(menu)
|
||||||
|
|
||||||
setInterval(function () {
|
setInterval(function () {
|
||||||
if (update == null) updater.checkForUpdates()
|
if (update == null) autoUpdater.checkForUpdates()
|
||||||
}, 1000 * 60 * 60 * 24)
|
}, 1000 * 60 * 60 * 24)
|
||||||
|
|
||||||
ipc.on('check-update', function (event, msg) {
|
ipc.on('check-update', function (event, msg) {
|
||||||
if (update == null) updater.checkForUpdates()
|
if (update == null) autoUpdater.checkForUpdates()
|
||||||
})
|
})
|
||||||
|
|
||||||
ipc.on('update-app', function (event, msg) {
|
ipc.on('update-app', function (event, msg) {
|
||||||
@@ -65,48 +87,76 @@ app.on('ready', function () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
menu = Menu.buildFromTemplate(template)
|
|
||||||
|
|
||||||
Menu.setApplicationMenu(menu)
|
|
||||||
// menu end
|
|
||||||
appIcon = new Tray(__dirname + '/resources/tray-icon.png')
|
|
||||||
appIcon.setToolTip('Boost')
|
|
||||||
|
|
||||||
var trayMenu = new Menu()
|
|
||||||
trayMenu.append(new MenuItem({
|
|
||||||
label: 'Open main window',
|
|
||||||
click: function () {
|
|
||||||
if (mainWindow != null) mainWindow.show()
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
trayMenu.append(new MenuItem({
|
|
||||||
label: 'Quit',
|
|
||||||
click: function () {
|
|
||||||
app.quit()
|
|
||||||
}
|
|
||||||
}))
|
|
||||||
appIcon.setContextMenu(trayMenu)
|
|
||||||
|
|
||||||
mainWindow = require('./atom-lib/main-window')
|
mainWindow = require('./atom-lib/main-window')
|
||||||
mainWindow.on('close', function (e) {
|
mainWindow.on('close', function (e) {
|
||||||
if (appQuit) return true
|
if (appQuit) return true
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
mainWindow.hide()
|
mainWindow.hide()
|
||||||
})
|
})
|
||||||
if (update != null) {
|
mainWindow.webContents.on('did-finish-load', function () {
|
||||||
mainWindow.webContents.on('did-finish-load', function () {
|
if (finderProcess == null) {
|
||||||
mainWindow.webContents.send('update-available', 'whoooooooh!')
|
finderProcess = ChildProcess
|
||||||
})
|
.execFile(process.execPath, [path.resolve(__dirname, 'finder.js'), '--finder'])
|
||||||
}
|
finderProcess.stdout.setEncoding('utf8')
|
||||||
|
finderProcess.stderr.setEncoding('utf8')
|
||||||
|
finderProcess.stdout.on('data', format)
|
||||||
|
finderProcess.stderr.on('data', errorFormat)
|
||||||
|
}
|
||||||
|
|
||||||
app.on('activate-with-no-open-windows', function () {
|
if (update != null) {
|
||||||
|
mainWindow.webContents.send('update-available', 'whoooooooh!')
|
||||||
|
} else {
|
||||||
|
autoUpdater.checkForUpdates()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
app.on('activate', function () {
|
||||||
if (mainWindow == null) return null
|
if (mainWindow == null) return null
|
||||||
mainWindow.show()
|
mainWindow.show()
|
||||||
})
|
})
|
||||||
|
|
||||||
finderWindow = require('./atom-lib/finder-window')
|
function format (payload) {
|
||||||
|
// console.log('from finder >> ', payload)
|
||||||
|
try {
|
||||||
|
payload = JSON.parse(payload)
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Not parsable payload : ', payload)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
switch (payload.type) {
|
||||||
|
case 'log':
|
||||||
|
console.log('FINDER(stdout): ' + payload.data)
|
||||||
|
break
|
||||||
|
case 'show-main-window':
|
||||||
|
if (mainWindow != null) {
|
||||||
|
mainWindow.show()
|
||||||
|
}
|
||||||
|
break
|
||||||
|
case 'request-data':
|
||||||
|
mainWindow.webContents.send('request-data')
|
||||||
|
break
|
||||||
|
case 'quit-app':
|
||||||
|
appQuit = true
|
||||||
|
app.quit()
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function errorFormat (output) {
|
||||||
|
console.error('FINDER(stderr):' + output)
|
||||||
|
}
|
||||||
|
|
||||||
|
function emitToFinder (type, data) {
|
||||||
|
if (!finderProcess) {
|
||||||
|
console.log('finder process is not ready')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var payload = {
|
||||||
|
type: type,
|
||||||
|
data: data
|
||||||
|
}
|
||||||
|
finderProcess.stdin.write(JSON.stringify(payload), 'utf-8')
|
||||||
|
}
|
||||||
|
|
||||||
var globalShortcut = require('global-shortcut')
|
|
||||||
var userDataPath = app.getPath('userData')
|
var userDataPath = app.getPath('userData')
|
||||||
if (!jetpack.cwd(userDataPath).exists('keymap.json')) {
|
if (!jetpack.cwd(userDataPath).exists('keymap.json')) {
|
||||||
jetpack.cwd(userDataPath).file('keymap.json', {content: '{}'})
|
jetpack.cwd(userDataPath).file('keymap.json', {content: '{}'})
|
||||||
@@ -122,10 +172,7 @@ app.on('ready', function () {
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
globalShortcut.register(toggleFinderKey, function () {
|
globalShortcut.register(toggleFinderKey, function () {
|
||||||
if (mainWindow != null && !mainWindow.isFocused()) {
|
emitToFinder('open-finder')
|
||||||
mainWindow.hide()
|
|
||||||
}
|
|
||||||
finderWindow.show()
|
|
||||||
})
|
})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(err.name)
|
console.log(err.name)
|
||||||
@@ -141,10 +188,7 @@ app.on('ready', function () {
|
|||||||
var toggleFinderKey = global.keymap.toggleFinder != null ? global.keymap.toggleFinder : 'ctrl+tab+shift'
|
var toggleFinderKey = global.keymap.toggleFinder != null ? global.keymap.toggleFinder : 'ctrl+tab+shift'
|
||||||
try {
|
try {
|
||||||
globalShortcut.register(toggleFinderKey, function () {
|
globalShortcut.register(toggleFinderKey, function () {
|
||||||
if (mainWindow != null && !mainWindow.isFocused()) {
|
emitToFinder('open-finder')
|
||||||
mainWindow.hide()
|
|
||||||
}
|
|
||||||
finderWindow.show()
|
|
||||||
})
|
})
|
||||||
mainWindow.webContents.send('APP_SETTING_DONE', {})
|
mainWindow.webContents.send('APP_SETTING_DONE', {})
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@@ -154,12 +198,4 @@ app.on('ready', function () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
global.hideFinder = function () {
|
|
||||||
if (!mainWindow.isVisible()) {
|
|
||||||
Menu.sendActionToFirstResponder('hide:')
|
|
||||||
} else {
|
|
||||||
mainWindow.focus()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|||||||
14
package.json
14
package.json
@@ -1,8 +1,8 @@
|
|||||||
{
|
{
|
||||||
"name": "boost",
|
"name": "boost",
|
||||||
"version": "0.4.1-beta.2",
|
"version": "0.4.3",
|
||||||
"description": "Boost App",
|
"description": "Boost App",
|
||||||
"main": "main.js",
|
"main": "index.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "BOOST_ENV=development electron ./main.js",
|
"start": "BOOST_ENV=development electron ./main.js",
|
||||||
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
|
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
"codesign": "codesign --verbose --deep --force --sign \"MAISIN solutions Inc.\" Boost-darwin-x64/Boost.app"
|
"codesign": "codesign --verbose --deep --force --sign \"MAISIN solutions Inc.\" Boost-darwin-x64/Boost.app"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"version": "--version=0.34.0 --app-bundle-id=com.maisin.boost",
|
"version": "--version=0.35.1 --app-bundle-id=com.maisin.boost",
|
||||||
"platform": "--platform=darwin --arch=x64 --prune --icon=resources/app.icns",
|
"platform": "--platform=darwin --arch=x64 --prune --icon=resources/app.icns",
|
||||||
"ignore": "--ignore=Boost-darwin-x64 --ignore=node_modules/devicon/icons --ignore=submodules/ace/(?!src-min)|submodules/ace/(?=src-min-noconflict)"
|
"ignore": "--ignore=Boost-darwin-x64 --ignore=node_modules/devicon/icons --ignore=submodules/ace/(?!src-min)|submodules/ace/(?=src-min-noconflict)"
|
||||||
},
|
},
|
||||||
@@ -40,11 +40,12 @@
|
|||||||
"devicon": "^2.0.0",
|
"devicon": "^2.0.0",
|
||||||
"font-awesome": "^4.3.0",
|
"font-awesome": "^4.3.0",
|
||||||
"fs-jetpack": "^0.7.0",
|
"fs-jetpack": "^0.7.0",
|
||||||
|
"highlight.js": "^8.9.1",
|
||||||
"lodash": "^3.10.1",
|
"lodash": "^3.10.1",
|
||||||
"markdown-it": "^4.3.1",
|
"markdown-it": "^4.3.1",
|
||||||
|
"markdown-it-emoji": "^1.1.0",
|
||||||
"md5": "^2.0.0",
|
"md5": "^2.0.0",
|
||||||
"moment": "^2.10.3",
|
"moment": "^2.10.3",
|
||||||
"node-notifier": "^4.2.3",
|
|
||||||
"socket.io-client": "^1.3.6",
|
"socket.io-client": "^1.3.6",
|
||||||
"superagent": "^1.2.0",
|
"superagent": "^1.2.0",
|
||||||
"superagent-promise": "^1.0.3"
|
"superagent-promise": "^1.0.3"
|
||||||
@@ -54,16 +55,15 @@
|
|||||||
"babel-plugin-react-transform": "^1.1.1",
|
"babel-plugin-react-transform": "^1.1.1",
|
||||||
"css-loader": "^0.19.0",
|
"css-loader": "^0.19.0",
|
||||||
"electron-packager": "^5.1.0",
|
"electron-packager": "^5.1.0",
|
||||||
"electron-prebuilt": "^0.33.6",
|
"electron-prebuilt": "^0.35.1",
|
||||||
"nib": "^1.1.0",
|
"nib": "^1.1.0",
|
||||||
"react": "^0.14.0",
|
"react": "^0.14.0",
|
||||||
"react-dom": "^0.14.0",
|
"react-dom": "^0.14.0",
|
||||||
"react-redux": "^4.0.0",
|
"react-redux": "^4.0.0",
|
||||||
"react-router": "^1.0.0-rc1",
|
"react-router": "^1.0.0-rc1",
|
||||||
"react-select": "^0.8.1",
|
|
||||||
"react-transform-catch-errors": "^1.0.0",
|
"react-transform-catch-errors": "^1.0.0",
|
||||||
"react-transform-hmr": "^1.0.1",
|
"react-transform-hmr": "^1.0.1",
|
||||||
"redbox-react": "^1.1.1",
|
"redbox-react": "^1.2.0",
|
||||||
"redux": "^3.0.2",
|
"redux": "^3.0.2",
|
||||||
"standard": "^5.3.1",
|
"standard": "^5.3.1",
|
||||||
"style-loader": "^0.12.4",
|
"style-loader": "^0.12.4",
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ var path = require('path')
|
|||||||
var JsonpTemplatePlugin = webpack.JsonpTemplatePlugin
|
var JsonpTemplatePlugin = webpack.JsonpTemplatePlugin
|
||||||
var FunctionModulePlugin = require('webpack/lib/FunctionModulePlugin')
|
var FunctionModulePlugin = require('webpack/lib/FunctionModulePlugin')
|
||||||
var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin')
|
var NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin')
|
||||||
var ExternalsPlugin = webpack.ExternalsPlugin
|
|
||||||
var opt = {
|
var opt = {
|
||||||
path: path.join(__dirname, 'compiled'),
|
path: path.join(__dirname, 'compiled'),
|
||||||
filename: '[name].js',
|
filename: '[name].js',
|
||||||
@@ -39,29 +38,10 @@ var config = {
|
|||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
new webpack.NoErrorsPlugin(),
|
new webpack.NoErrorsPlugin(),
|
||||||
new ExternalsPlugin('commonjs', [
|
|
||||||
'app',
|
|
||||||
'auto-updater',
|
|
||||||
'browser-window',
|
|
||||||
'content-tracing',
|
|
||||||
'dialog',
|
|
||||||
'global-shortcut',
|
|
||||||
'ipc',
|
|
||||||
'menu',
|
|
||||||
'menu-item',
|
|
||||||
'power-monitor',
|
|
||||||
'protocol',
|
|
||||||
'tray',
|
|
||||||
'remote',
|
|
||||||
'web-frame',
|
|
||||||
'clipboard',
|
|
||||||
'crash-reporter',
|
|
||||||
'screen',
|
|
||||||
'shell'
|
|
||||||
]),
|
|
||||||
new NodeTargetPlugin()
|
new NodeTargetPlugin()
|
||||||
],
|
],
|
||||||
externals: [
|
externals: [
|
||||||
|
'electron',
|
||||||
'socket.io-client',
|
'socket.io-client',
|
||||||
'md5',
|
'md5',
|
||||||
'superagent',
|
'superagent',
|
||||||
@@ -69,7 +49,9 @@ var config = {
|
|||||||
'lodash',
|
'lodash',
|
||||||
'markdown-it',
|
'markdown-it',
|
||||||
'moment',
|
'moment',
|
||||||
'node-notifier'
|
'highlight.js',
|
||||||
|
'markdown-it-emoji',
|
||||||
|
'fs-jetpack'
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ module.exports = {
|
|||||||
})
|
})
|
||||||
],
|
],
|
||||||
externals: [
|
externals: [
|
||||||
|
'electron',
|
||||||
'socket.io-client',
|
'socket.io-client',
|
||||||
'md5',
|
'md5',
|
||||||
'superagent',
|
'superagent',
|
||||||
@@ -45,10 +46,11 @@ module.exports = {
|
|||||||
'lodash',
|
'lodash',
|
||||||
'markdown-it',
|
'markdown-it',
|
||||||
'moment',
|
'moment',
|
||||||
'node-notifier'
|
'highlight.js',
|
||||||
|
'markdown-it-emoji',
|
||||||
|
'fs-jetpack'
|
||||||
],
|
],
|
||||||
resolve: {
|
resolve: {
|
||||||
extensions: ['', '.js', '.jsx', 'styl']
|
extensions: ['', '.js', '.jsx', 'styl']
|
||||||
},
|
}
|
||||||
target: 'atom'
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user