mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 09:46:22 +00:00
行動データ, contact form, default articleに英語文追加, Intro fix
This commit is contained in:
@@ -8,6 +8,7 @@ import FinderList from './FinderList'
|
|||||||
import FinderDetail from './FinderDetail'
|
import FinderDetail from './FinderDetail'
|
||||||
import { selectArticle, searchArticle, refreshData } from './actions'
|
import { selectArticle, searchArticle, refreshData } from './actions'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
|
import activityRecord from 'boost/activityRecord'
|
||||||
|
|
||||||
import remote from 'remote'
|
import remote from 'remote'
|
||||||
var hideFinder = remote.getGlobal('hideFinder')
|
var hideFinder = remote.getGlobal('hideFinder')
|
||||||
@@ -46,6 +47,7 @@ class FinderMain extends React.Component {
|
|||||||
if (e.keyCode === 13) {
|
if (e.keyCode === 13) {
|
||||||
let { activeArticle } = this.props
|
let { activeArticle } = this.props
|
||||||
clipboard.writeText(activeArticle.content)
|
clipboard.writeText(activeArticle.content)
|
||||||
|
activityRecord.emit('FINDER_COPY')
|
||||||
hideFinder()
|
hideFinder()
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
@@ -174,6 +176,7 @@ var store = createStore(reducer)
|
|||||||
|
|
||||||
window.onfocus = e => {
|
window.onfocus = e => {
|
||||||
store.dispatch(refreshData())
|
store.dispatch(refreshData())
|
||||||
|
activityRecord.emit('FINDER_OPEN')
|
||||||
}
|
}
|
||||||
|
|
||||||
ReactDOM.render((
|
ReactDOM.render((
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import linkState from 'boost/linkState'
|
|||||||
import FolderMark from 'boost/components/FolderMark'
|
import FolderMark from 'boost/components/FolderMark'
|
||||||
import TagLink from 'boost/components/TagLink'
|
import TagLink from 'boost/components/TagLink'
|
||||||
import TagSelect from 'boost/components/TagSelect'
|
import TagSelect from 'boost/components/TagSelect'
|
||||||
|
import activityRecord from 'boost/activityRecord'
|
||||||
|
|
||||||
var modeOptions = aceModes.map(function (mode) {
|
var modeOptions = aceModes.map(function (mode) {
|
||||||
return {
|
return {
|
||||||
@@ -93,6 +94,7 @@ export default class ArticleDetail extends React.Component {
|
|||||||
let { dispatch, activeArticle } = this.props
|
let { dispatch, activeArticle } = this.props
|
||||||
|
|
||||||
dispatch(destroyArticle(activeArticle.key))
|
dispatch(destroyArticle(activeArticle.key))
|
||||||
|
activityRecord.emit('ARTICLE_DESTROY')
|
||||||
this.setState({openDeleteConfirmMenu: false})
|
this.setState({openDeleteConfirmMenu: false})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +184,12 @@ export default class ArticleDetail extends React.Component {
|
|||||||
|
|
||||||
delete newArticle.status
|
delete newArticle.status
|
||||||
newArticle.updatedAt = new Date()
|
newArticle.updatedAt = new Date()
|
||||||
if (newArticle.createdAt == null) newArticle.createdAt = new Date()
|
if (newArticle.createdAt == null) {
|
||||||
|
newArticle.createdAt = new Date()
|
||||||
|
activityRecord.emit('ARTICLE_CREATE')
|
||||||
|
} else {
|
||||||
|
activityRecord.emit('ARTICLE_UPDATE')
|
||||||
|
}
|
||||||
|
|
||||||
dispatch(updateArticle(newArticle))
|
dispatch(updateArticle(newArticle))
|
||||||
dispatch(switchMode(IDLE_MODE))
|
dispatch(switchMode(IDLE_MODE))
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ import ReactDOM from 'react-dom'
|
|||||||
require('../styles/main/index.styl')
|
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'
|
||||||
|
|
||||||
|
activityRecord.init()
|
||||||
|
|
||||||
let routes = (
|
let routes = (
|
||||||
<Route path='/' component={MainPage}>
|
<Route path='/' component={MainPage}>
|
||||||
|
|||||||
@@ -119,6 +119,70 @@ iptFocusBorderColor = #369DCD
|
|||||||
&.error
|
&.error
|
||||||
color errorTextColor
|
color errorTextColor
|
||||||
background-color errorBackgroundColor
|
background-color errorBackgroundColor
|
||||||
|
&.ContactTab
|
||||||
|
&.done
|
||||||
|
.message
|
||||||
|
margin-top 75px
|
||||||
|
margin-bottom 15px
|
||||||
|
text-align center
|
||||||
|
font-size 22px
|
||||||
|
.checkIcon
|
||||||
|
margin-bottom 15px
|
||||||
|
font-size 144px
|
||||||
|
color brandColor
|
||||||
|
text-align center
|
||||||
|
.control
|
||||||
|
text-align center
|
||||||
|
button
|
||||||
|
border solid 1px borderColor
|
||||||
|
border-radius 5px
|
||||||
|
background-color white
|
||||||
|
padding 15px 15px
|
||||||
|
font-size 14px
|
||||||
|
&:hover
|
||||||
|
background-color darken(white, 10%)
|
||||||
|
&.form
|
||||||
|
padding 10px
|
||||||
|
.title
|
||||||
|
font-size 18px
|
||||||
|
color brandColor
|
||||||
|
margin-top 10px
|
||||||
|
margin-bottom 10px
|
||||||
|
.description
|
||||||
|
margin-bottom 15px
|
||||||
|
.iptGroup
|
||||||
|
margin-bottom 10px
|
||||||
|
input, textarea
|
||||||
|
border-radius 5px
|
||||||
|
border 1px solid borderColor
|
||||||
|
font-size 14px
|
||||||
|
outline none
|
||||||
|
padding 10px 15px
|
||||||
|
width 100%
|
||||||
|
&:focus
|
||||||
|
border-color iptFocusBorderColor
|
||||||
|
textarea
|
||||||
|
resize vertical
|
||||||
|
min-height 150px
|
||||||
|
.formControl
|
||||||
|
clearfix()
|
||||||
|
.alert
|
||||||
|
float right
|
||||||
|
padding 10px 15px
|
||||||
|
margin 0 5px 0
|
||||||
|
font-size 14px
|
||||||
|
line-height normal
|
||||||
|
button
|
||||||
|
padding 10px 15px
|
||||||
|
background-color brandColor
|
||||||
|
color white
|
||||||
|
font-size 14px
|
||||||
|
border-radius 5px
|
||||||
|
border none
|
||||||
|
float right
|
||||||
|
&:hover
|
||||||
|
background-color lighten(brandColor, 10%)
|
||||||
|
|
||||||
&.AppSettingTab
|
&.AppSettingTab
|
||||||
.description
|
.description
|
||||||
marked()
|
marked()
|
||||||
|
|||||||
@@ -109,8 +109,9 @@ slideBgColor4 = #00B493
|
|||||||
.slide3
|
.slide3
|
||||||
background-color slideBgColor3
|
background-color slideBgColor3
|
||||||
.content
|
.content
|
||||||
|
font-size 18px
|
||||||
&>img
|
&>img
|
||||||
margin-top 45px
|
margin-top 25px
|
||||||
.slide4
|
.slide4
|
||||||
background-color slideBgColor4
|
background-color slideBgColor4
|
||||||
.content
|
.content
|
||||||
|
|||||||
122
lib/activityRecord.js
Normal file
122
lib/activityRecord.js
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
import _ from 'lodash'
|
||||||
|
import moment from 'moment'
|
||||||
|
import keygen from 'boost/keygen'
|
||||||
|
import dataStore from 'boost/dataStore'
|
||||||
|
import { request, WEB_URL } from 'boost/api'
|
||||||
|
|
||||||
|
function isSameDate (a, b) {
|
||||||
|
a = moment(a).utcOffset(+540).format('YYYYMMDD')
|
||||||
|
b = moment(b).utcOffset(+540).format('YYYYMMDD')
|
||||||
|
|
||||||
|
return a === b
|
||||||
|
}
|
||||||
|
|
||||||
|
export function init () {
|
||||||
|
let records = getAllRecords()
|
||||||
|
if (records == null) {
|
||||||
|
saveAllRecords([])
|
||||||
|
}
|
||||||
|
|
||||||
|
postRecords()
|
||||||
|
if (window != null) {
|
||||||
|
window.addEventListener('online', postRecords)
|
||||||
|
window.setInterval(postRecords, 1000 * 60 * 60 * 24)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getClientKey () {
|
||||||
|
let clientKey = localStorage.getItem('clientKey')
|
||||||
|
if (!_.isString(clientKey) || clientKey.length !== 40) {
|
||||||
|
clientKey = keygen()
|
||||||
|
localStorage.setItem('clientKey', clientKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
return clientKey
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAllRecords () {
|
||||||
|
return JSON.parse(localStorage.getItem('activityRecords'))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function saveAllRecords (records) {
|
||||||
|
localStorage.setItem('activityRecords', JSON.stringify(records))
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Post all records(except today)
|
||||||
|
and remove all posted records
|
||||||
|
*/
|
||||||
|
export function postRecords (data) {
|
||||||
|
let records = getAllRecords()
|
||||||
|
records = records.filter(record => {
|
||||||
|
return !isSameDate(new Date(), record.date)
|
||||||
|
})
|
||||||
|
|
||||||
|
if (records.length === 0) {
|
||||||
|
console.log('No records to post')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('posting...', records)
|
||||||
|
let input = {
|
||||||
|
clientKey: getClientKey(),
|
||||||
|
records
|
||||||
|
}
|
||||||
|
return request.post(WEB_URL + 'apis/activity')
|
||||||
|
.send(input)
|
||||||
|
.then(res => {
|
||||||
|
let records = getAllRecords()
|
||||||
|
let todayRecord = _.find(records, record => {
|
||||||
|
return isSameDate(new Date(), record.date)
|
||||||
|
})
|
||||||
|
if (todayRecord != null) saveAllRecords([todayRecord])
|
||||||
|
else saveAllRecords([])
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
console.error(err)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
export function emit (type, data) {
|
||||||
|
let records = getAllRecords()
|
||||||
|
|
||||||
|
let index = _.findIndex(records, record => {
|
||||||
|
return isSameDate(new Date(), record.date)
|
||||||
|
})
|
||||||
|
|
||||||
|
let todayRecord
|
||||||
|
if (index < 0) {
|
||||||
|
todayRecord = {date: new Date()}
|
||||||
|
records.push(todayRecord)
|
||||||
|
}
|
||||||
|
else todayRecord = records[index]
|
||||||
|
console.log(type)
|
||||||
|
switch (type) {
|
||||||
|
case 'ARTICLE_CREATE':
|
||||||
|
case 'ARTICLE_UPDATE':
|
||||||
|
case 'ARTICLE_DESTROY':
|
||||||
|
case 'FOLDER_CREATE':
|
||||||
|
case 'FOLDER_UPDATE':
|
||||||
|
case 'FOLDER_DESTROY':
|
||||||
|
case 'FINDER_OPEN':
|
||||||
|
case 'FINDER_COPY':
|
||||||
|
todayRecord[type] = todayRecord[type] == null
|
||||||
|
? 1
|
||||||
|
: todayRecord[type] + 1
|
||||||
|
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
let storeData = dataStore.getData()
|
||||||
|
todayRecord.FOLDER_COUNT = _.isArray(storeData.folders) ? storeData.folders.length : 0
|
||||||
|
todayRecord.ARTICLE_COUNT = _.isArray(storeData.articles) ? storeData.articles.length : 0
|
||||||
|
|
||||||
|
saveAllRecords(records)
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
init,
|
||||||
|
emit,
|
||||||
|
getClientKey,
|
||||||
|
postRecords
|
||||||
|
}
|
||||||
10
lib/api.js
10
lib/api.js
@@ -1,9 +1,12 @@
|
|||||||
import superagent from 'superagent'
|
import superagent from 'superagent'
|
||||||
import superagentPromise from 'superagent-promise'
|
import superagentPromise from 'superagent-promise'
|
||||||
import { API_URL } from '../config'
|
|
||||||
import auth from 'boost/auth'
|
import auth from 'boost/auth'
|
||||||
|
|
||||||
const request = superagentPromise(superagent, Promise)
|
export const API_URL = 'http://boost-api4.elasticbeanstalk.com/'
|
||||||
|
// export const WEB_URL = 'http://b00st.io/'
|
||||||
|
export const WEB_URL = 'http://localhost:3333/'
|
||||||
|
|
||||||
|
export const request = superagentPromise(superagent, Promise)
|
||||||
|
|
||||||
export function login (input) {
|
export function login (input) {
|
||||||
return request
|
return request
|
||||||
@@ -163,6 +166,9 @@ export function sendEmail (input) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
API_URL,
|
||||||
|
WEB_URL,
|
||||||
|
request,
|
||||||
login,
|
login,
|
||||||
signup,
|
signup,
|
||||||
updateUserInfo,
|
updateUserInfo,
|
||||||
|
|||||||
123
lib/components/modal/Preference/ContactTab.js
Normal file
123
lib/components/modal/Preference/ContactTab.js
Normal file
@@ -0,0 +1,123 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import ReactDOM from 'react-dom'
|
||||||
|
import { getClientKey } from 'boost/activityRecord'
|
||||||
|
import linkState from 'boost/linkState'
|
||||||
|
import _ from 'lodash'
|
||||||
|
import { request, WEB_URL } from 'boost/api'
|
||||||
|
|
||||||
|
const FORM_MODE = 'FORM_MODE'
|
||||||
|
const DONE_MODE = 'DONE_MODE'
|
||||||
|
|
||||||
|
export default class ContactTab extends React.Component {
|
||||||
|
constructor (props) {
|
||||||
|
super(props)
|
||||||
|
|
||||||
|
this.state = {
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
email: '',
|
||||||
|
mode: FORM_MODE,
|
||||||
|
alert: null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
let titleInput = ReactDOM.findDOMNode(this.refs.title)
|
||||||
|
if (titleInput != null) titleInput.focus()
|
||||||
|
}
|
||||||
|
|
||||||
|
handleBackButtonClick (e) {
|
||||||
|
this.setState({
|
||||||
|
mode: FORM_MODE
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
handleSendButtonClick (e) {
|
||||||
|
let input = _.pick(this.state, ['title', 'content', 'email'])
|
||||||
|
input.clientKey = getClientKey()
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
alert: {
|
||||||
|
type: 'info',
|
||||||
|
message: 'Sending...'
|
||||||
|
}
|
||||||
|
}, () => {
|
||||||
|
request.post(WEB_URL + 'apis/inquiry')
|
||||||
|
.send(input)
|
||||||
|
.then(res => {
|
||||||
|
console.log('sent')
|
||||||
|
this.setState({
|
||||||
|
title: '',
|
||||||
|
content: '',
|
||||||
|
mode: DONE_MODE,
|
||||||
|
alert: null
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.catch(err => {
|
||||||
|
if (err.code === 'ECONNREFUSED') {
|
||||||
|
this.setState({
|
||||||
|
alert: {
|
||||||
|
type: 'error',
|
||||||
|
message: 'Can\'t connect to API server.'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
console.error(err)
|
||||||
|
this.setState({
|
||||||
|
alert: {
|
||||||
|
type: 'error',
|
||||||
|
message: err.message
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
switch (this.state.mode) {
|
||||||
|
case DONE_MODE:
|
||||||
|
return (
|
||||||
|
<div className='ContactTab content done'>
|
||||||
|
<div className='message'>
|
||||||
|
<i className='checkIcon fa fa-check-circle'/><br/>
|
||||||
|
Your message has been sent successfully!!
|
||||||
|
</div>
|
||||||
|
<div className='control'>
|
||||||
|
<button onClick={e => this.handleBackButtonClick(e)}>Back to Contact form</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
case FORM_MODE:
|
||||||
|
default:
|
||||||
|
let alertElement = this.state.alert != null
|
||||||
|
? (
|
||||||
|
<div className={'alert ' + this.state.alert.type}>{this.state.alert.message}</div>
|
||||||
|
)
|
||||||
|
: null
|
||||||
|
return (
|
||||||
|
<div className='ContactTab content form'>
|
||||||
|
<div className='title'>Contact form</div>
|
||||||
|
<div className='description'>
|
||||||
|
Your feedback is highly appreciated and will help us to improve our app. :D
|
||||||
|
</div>
|
||||||
|
<div className='iptGroup'>
|
||||||
|
<input ref='title' valueLink={this.linkState('title')} placeholder='Title' type='text'/>
|
||||||
|
</div>
|
||||||
|
<div className='iptGroup'>
|
||||||
|
<textarea valueLink={this.linkState('content')} placeholder='Content'/>
|
||||||
|
</div>
|
||||||
|
<div className='iptGroup'>
|
||||||
|
<input valueLink={this.linkState('email')} placeholder='E-mail (Optional)' type='email'/>
|
||||||
|
</div>
|
||||||
|
<div className='formControl'>
|
||||||
|
<button onClick={e => this.handleSendButtonClick(e)} className='primary'>Send</button>
|
||||||
|
{alertElement}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ContactTab.prototype.linkState = linkState
|
||||||
@@ -5,11 +5,13 @@ import store from 'boost/store'
|
|||||||
import AppSettingTab from './Preference/AppSettingTab'
|
import AppSettingTab from './Preference/AppSettingTab'
|
||||||
import HelpTab from './Preference/HelpTab'
|
import HelpTab from './Preference/HelpTab'
|
||||||
import FolderSettingTab from './Preference/FolderSettingTab'
|
import FolderSettingTab from './Preference/FolderSettingTab'
|
||||||
|
import ContactTab from './Preference/ContactTab'
|
||||||
import { closeModal } from 'boost/modal'
|
import { closeModal } from 'boost/modal'
|
||||||
|
|
||||||
const APP = 'APP'
|
const APP = 'APP'
|
||||||
const HELP = 'HELP'
|
const HELP = 'HELP'
|
||||||
const FOLDER = 'FOLDER'
|
const FOLDER = 'FOLDER'
|
||||||
|
const CONTACT = 'CONTACT'
|
||||||
|
|
||||||
class Preferences extends React.Component {
|
class Preferences extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -35,7 +37,8 @@ class Preferences extends React.Component {
|
|||||||
|
|
||||||
let tabs = [
|
let tabs = [
|
||||||
{target: APP, label: 'Preferences'},
|
{target: APP, label: 'Preferences'},
|
||||||
{target: FOLDER, label: 'Manage folder'}
|
{target: FOLDER, label: 'Manage folder'},
|
||||||
|
{target: CONTACT, label: 'Contact form'}
|
||||||
]
|
]
|
||||||
|
|
||||||
let navButtons = tabs.map(tab => (
|
let navButtons = tabs.map(tab => (
|
||||||
@@ -71,6 +74,10 @@ class Preferences extends React.Component {
|
|||||||
folders={folders}
|
folders={folders}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
|
case CONTACT:
|
||||||
|
return (
|
||||||
|
<ContactTab/>
|
||||||
|
)
|
||||||
case APP:
|
case APP:
|
||||||
default:
|
default:
|
||||||
return (<AppSettingTab/>)
|
return (<AppSettingTab/>)
|
||||||
@@ -239,7 +246,6 @@ Preferences.prototype.linkState = linkState
|
|||||||
|
|
||||||
function remap (state) {
|
function remap (state) {
|
||||||
let { folders, status } = state
|
let { folders, status } = state
|
||||||
console.log(state)
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
folders,
|
folders,
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import React from 'react'
|
import React, { PropTypes } from 'react'
|
||||||
import MarkdownPreview from 'boost/components/MarkdownPreview'
|
import MarkdownPreview from 'boost/components/MarkdownPreview'
|
||||||
import CodeEditor from 'boost/components/CodeEditor'
|
import CodeEditor from 'boost/components/CodeEditor'
|
||||||
|
|
||||||
@@ -88,8 +88,11 @@ export default class Tutorial extends React.Component {
|
|||||||
return (<div className='slide slide3'>
|
return (<div className='slide slide3'>
|
||||||
<div className='title'>Easy to access with Finder</div>
|
<div className='title'>Easy to access with Finder</div>
|
||||||
<div className='content'>
|
<div className='content'>
|
||||||
Finder is a small popup window.<br/>
|
With Finder, You can search your articles faster.<br/>
|
||||||
With finder, You can search your articles faster.<br/>
|
You can open Finder by pressing Control + shift + tab<br/>
|
||||||
|
To put the content of an article in the clipboard, press Enter.<br/>
|
||||||
|
So you can paste it with Cmd(⌘) + V
|
||||||
|
|
||||||
<img width='480' src='../../resources/finder.png'/>
|
<img width='480' src='../../resources/finder.png'/>
|
||||||
</div>
|
</div>
|
||||||
</div>)
|
</div>)
|
||||||
@@ -105,3 +108,7 @@ export default class Tutorial extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Tutorial.propTypes = {
|
||||||
|
close: PropTypes.func
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import keygen from 'boost/keygen'
|
import keygen from 'boost/keygen'
|
||||||
|
|
||||||
let defaultContent = '**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 +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**'
|
||||||
|
|
||||||
export function init () {
|
export function init () {
|
||||||
console.log('initialize data store')
|
console.log('initialize data store')
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import _ from 'lodash'
|
|||||||
import { SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, SET_SEARCH_FILTER, SET_TAG_FILTER, CLEAR_SEARCH, ARTICLE_UPDATE, ARTICLE_DESTROY, FOLDER_CREATE, FOLDER_UPDATE, FOLDER_DESTROY, IDLE_MODE, CREATE_MODE } from './actions'
|
import { SWITCH_FOLDER, SWITCH_MODE, SWITCH_ARTICLE, SET_SEARCH_FILTER, SET_TAG_FILTER, CLEAR_SEARCH, ARTICLE_UPDATE, ARTICLE_DESTROY, FOLDER_CREATE, FOLDER_UPDATE, FOLDER_DESTROY, IDLE_MODE, CREATE_MODE } from './actions'
|
||||||
import dataStore from 'boost/dataStore'
|
import dataStore from 'boost/dataStore'
|
||||||
import keygen from 'boost/keygen'
|
import keygen from 'boost/keygen'
|
||||||
|
import activityRecord from 'boost/activityRecord'
|
||||||
|
|
||||||
const initialStatus = {
|
const initialStatus = {
|
||||||
mode: IDLE_MODE,
|
mode: IDLE_MODE,
|
||||||
@@ -36,6 +37,7 @@ function folders (state = initialFolders, action) {
|
|||||||
state.push(newFolder)
|
state.push(newFolder)
|
||||||
|
|
||||||
dataStore.setFolders(null, state)
|
dataStore.setFolders(null, state)
|
||||||
|
activityRecord.emit('FOLDER_CREATE')
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
case FOLDER_UPDATE:
|
case FOLDER_UPDATE:
|
||||||
@@ -54,7 +56,6 @@ function folders (state = initialFolders, action) {
|
|||||||
let conflictFolder = _.find(state, _folder => {
|
let conflictFolder = _.find(state, _folder => {
|
||||||
return folder.name === _folder.name && folder.key !== _folder.key
|
return folder.name === _folder.name && folder.key !== _folder.key
|
||||||
})
|
})
|
||||||
console.log(conflictFolder)
|
|
||||||
if (conflictFolder != null) throw new Error('Name conflicted')
|
if (conflictFolder != null) throw new Error('Name conflicted')
|
||||||
}
|
}
|
||||||
Object.assign(targetFolder, folder, {
|
Object.assign(targetFolder, folder, {
|
||||||
@@ -62,6 +63,7 @@ function folders (state = initialFolders, action) {
|
|||||||
})
|
})
|
||||||
|
|
||||||
dataStore.setFolders(null, state)
|
dataStore.setFolders(null, state)
|
||||||
|
activityRecord.emit('FOLDER_UPDATE')
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
case FOLDER_DESTROY:
|
case FOLDER_DESTROY:
|
||||||
@@ -74,6 +76,7 @@ function folders (state = initialFolders, action) {
|
|||||||
state.splice(targetIndex, 1)
|
state.splice(targetIndex, 1)
|
||||||
}
|
}
|
||||||
dataStore.setFolders(null, state)
|
dataStore.setFolders(null, state)
|
||||||
|
activityRecord.emit('FOLDER_DESTROY')
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
|
|||||||
Reference in New Issue
Block a user