1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-14 02:06:29 +00:00

Compare commits

...

9 Commits

Author SHA1 Message Date
Rokt33r
7fcaaa297a Merge branch 'dev'
* dev:
  alert fix
  debug missing argument
  bump version
  rollback: setVisibleOnAllWorkspaces(true)
  FinderのActivity logをちゃんと取ってくる
  FinderのInputにLato fontが使われていない問題修正
  Search inputにRegExp operatorが入ると使えなかった問題改善
  User name change and modify style

Conflicts:
	package.json
2015-12-04 04:56:55 +09:00
Rokt33r
7c2d2044a9 alert fix 2015-12-04 04:56:04 +09:00
Rokt33r
aa32f59dc6 debug missing argument 2015-12-03 12:15:07 +09:00
Rokt33r
182af99e7c bump version 2015-12-03 12:02:29 +09:00
Rokt33r
5b520a7a81 rollback: setVisibleOnAllWorkspaces(true) 2015-12-03 12:02:21 +09:00
Rokt33r
364917c910 FinderのActivity logをちゃんと取ってくる 2015-12-03 07:59:47 +09:00
Rokt33r
ca7b9c786a FinderのInputにLato fontが使われていない問題修正 2015-12-03 07:25:35 +09:00
Rokt33r
15c2363098 Search inputにRegExp operatorが入ると使えなかった問題改善 2015-12-03 06:44:52 +09:00
Rokt33r
1a11095121 User name change and modify style 2015-12-03 05:32:10 +09:00
15 changed files with 210 additions and 47 deletions

View File

@@ -25,4 +25,6 @@ finderWindow.on('blur', function () {
finderWindow.hide()
})
finderWindow.setVisibleOnAllWorkspaces(true)
module.exports = finderWindow

View File

@@ -11,7 +11,7 @@ import _ from 'lodash'
import dataStore from 'boost/dataStore'
const electron = require('electron')
const { remote, clipboard } = electron
const { remote, clipboard, ipcRenderer } = electron
var hideFinder = remote.getGlobal('hideFinder')
@@ -64,6 +64,7 @@ class FinderMain extends React.Component {
let { activeArticle } = this.props
clipboard.writeText(activeArticle.content)
ipcRenderer.send('copy-finder')
notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!'
})
@@ -152,6 +153,14 @@ function buildFilter (key) {
return {type: TEXT_FILTER, value: key}
}
function isContaining (target, needle) {
return target.match(new RegExp(_.escapeRegExp(needle)))
}
function startsWith (target, needle) {
return target.match(new RegExp('^' + _.escapeRegExp(needle)))
}
function remap (state) {
let { articles, folders, status } = state
@@ -168,10 +177,10 @@ function remap (state) {
let targetFolders
if (folders != null) {
let exactTargetFolders = folders.filter(folder => {
return _.find(folderExactFilters, filter => folder.name.match(new RegExp(`^${filter.value}$`)))
return _.find(folderExactFilters, filter => isContaining(folder.name, filter.value))
})
let fuzzyTargetFolders = folders.filter(folder => {
return _.find(folderFilters, filter => folder.name.match(new RegExp(`^${filter.value}`)))
return _.find(folderFilters, filter => startsWith(folder.name, filter.value))
})
targetFolders = status.targetFolders = exactTargetFolders.concat(fuzzyTargetFolders)
@@ -184,7 +193,7 @@ function remap (state) {
if (textFilters.length > 0) {
articles = textFilters.reduce((articles, textFilter) => {
return articles.filter(article => {
return article.title.match(new RegExp(textFilter.value, 'i')) || article.content.match(new RegExp(textFilter.value, 'i'))
return isContaining(article.title, textFilter.value) || isContaining(article.content, textFilter.value)
})
}, articles)
}
@@ -192,7 +201,7 @@ function remap (state) {
if (tagFilters.length > 0) {
articles = tagFilters.reduce((articles, tagFilter) => {
return articles.filter(article => {
return _.find(article.tags, tag => tag.match(new RegExp(tagFilter.value, 'i')))
return _.find(article.tags, tag => isContaining(tag, tagFilter.value))
})
}, articles)
}
@@ -201,7 +210,6 @@ function remap (state) {
let activeArticle = _.findWhere(articles, {key: status.articleKey})
if (activeArticle == null) activeArticle = articles[0]
console.log(status.search)
return {
articles,
activeArticle,

View File

@@ -1,13 +1,13 @@
import React, { PropTypes} from 'react'
import { connect } from 'react-redux'
import { EDIT_MODE, IDLE_MODE, NEW, toggleTutorial } from 'boost/actions'
// import UserNavigator from './HomePage/UserNavigator'
import { EDIT_MODE, IDLE_MODE, toggleTutorial } from 'boost/actions'
import ArticleNavigator from './HomePage/ArticleNavigator'
import ArticleTopBar from './HomePage/ArticleTopBar'
import ArticleList from './HomePage/ArticleList'
import ArticleDetail from './HomePage/ArticleDetail'
import _ from 'lodash'
import { isModalOpen, closeModal } from 'boost/modal'
const electron = require('electron')
const BrowserWindow = electron.remote.BrowserWindow
@@ -114,13 +114,14 @@ class HomePage extends React.Component {
}
render () {
let { dispatch, status, articles, allArticles, activeArticle, folders, tags, filters } = this.props
let { dispatch, status, user, articles, allArticles, activeArticle, folders, tags, filters } = this.props
return (
<div className='HomePage'>
<ArticleNavigator
ref='nav'
dispatch={dispatch}
user={user}
folders={folders}
status={status}
allArticles={allArticles}
@@ -171,8 +172,16 @@ function buildFilter (key) {
return {type: TEXT_FILTER, value: key}
}
function isContaining (target, needle) {
return target.match(new RegExp(_.escapeRegExp(needle)))
}
function startsWith (target, needle) {
return target.match(new RegExp('^' + _.escapeRegExp(needle)))
}
function remap (state) {
let { folders, articles, status } = state
let { user, folders, articles, status } = state
if (articles == null) articles = []
articles.sort((a, b) => {
@@ -199,10 +208,10 @@ function remap (state) {
let targetFolders
if (folders != null) {
let exactTargetFolders = folders.filter(folder => {
return _.find(folderExactFilters, filter => folder.name.match(new RegExp(`^${filter.value}$`)))
return _.findWhere(folderExactFilters, {value: folder.name})
})
let fuzzyTargetFolders = folders.filter(folder => {
return _.find(folderFilters, filter => folder.name.match(new RegExp(`^${filter.value}`)))
return _.find(folderFilters, filter => startsWith(folder.name, filter.value))
})
targetFolders = status.targetFolders = exactTargetFolders.concat(fuzzyTargetFolders)
@@ -215,7 +224,7 @@ function remap (state) {
if (textFilters.length > 0) {
articles = textFilters.reduce((articles, textFilter) => {
return articles.filter(article => {
return article.title.match(new RegExp(textFilter.value, 'i')) || article.content.match(new RegExp(textFilter.value, 'i'))
return isContaining(article.title, textFilter.value) || isContaining(article.content, textFilter.value)
})
}, articles)
}
@@ -223,7 +232,7 @@ function remap (state) {
if (tagFilters.length > 0) {
articles = tagFilters.reduce((articles, tagFilter) => {
return articles.filter(article => {
return _.find(article.tags, tag => tag.match(new RegExp(tagFilter.value, 'i')))
return _.find(article.tags, tag => isContaining(tag, tagFilter.value))
})
}, articles)
}
@@ -234,6 +243,7 @@ function remap (state) {
if (activeArticle == null) activeArticle = articles[0]
return {
user,
folders,
status,
allArticles,
@@ -249,11 +259,9 @@ function remap (state) {
}
HomePage.propTypes = {
params: PropTypes.shape({
userId: PropTypes.string
}),
status: PropTypes.shape({
userId: PropTypes.string
status: PropTypes.shape(),
user: PropTypes.shape({
name: PropTypes.string
}),
articles: PropTypes.array,
allArticles: PropTypes.array,

View File

@@ -7,10 +7,6 @@ import Preferences from 'boost/components/modal/Preferences'
import CreateNewFolder from 'boost/components/modal/CreateNewFolder'
import keygen from 'boost/keygen'
const electron = require('electron')
const remote = electron.remote
let userName = remote.getGlobal('process').env.USER
const BRAND_COLOR = '#18AF90'
const preferenceTutorialElement = (
@@ -109,7 +105,7 @@ export default class ArticleNavigator extends React.Component {
}
render () {
let { status, folders, allArticles } = this.props
let { status, user, folders, allArticles } = this.props
let { targetFolders } = status
if (targetFolders == null) targetFolders = []
@@ -127,7 +123,7 @@ export default class ArticleNavigator extends React.Component {
return (
<div className='ArticleNavigator'>
<div className='userInfo'>
<div className='userProfileName'>{userName}</div>
<div className='userProfileName'>{user.name}</div>
<div className='userName'>localStorage</div>
<button onClick={e => this.handlePreferencesButtonClick(e)} className='settingBtn'>
<i className='fa fa-fw fa-chevron-down'/>

View File

@@ -29,6 +29,13 @@ ipc.on('notify', function (e, payload) {
})
})
ipc.on('copy-finder', function () {
activityRecord.emit('FINDER_COPY')
})
ipc.on('open-finder', function () {
activityRecord.emit('FINDER_OPEN')
})
let routes = (
<Route path='/' component={MainPage}>
<IndexRoute name='home' component={HomePage}/>

View File

@@ -14,6 +14,8 @@ body
width 100%
height 100%
overflow hidden
button, input
font-family "Lato"
.Finder
absolute top bottom left right

View File

@@ -3,6 +3,7 @@ const app = electron.app
const Tray = electron.Tray
const Menu = electron.Menu
const MenuItem = electron.MenuItem
const ipcMain = electron.ipcMain
process.stdin.setEncoding('utf8')
@@ -63,6 +64,10 @@ app.on('ready', function () {
break
}
})
ipcMain.on('copy-finder', function () {
emit('copy-finder')
})
})
global.hideFinder = function () {

View File

@@ -1,4 +1,6 @@
// Action types
export const USER_UPDATE = 'USER_UPDATE'
export const CLEAR_NEW_ARTICLE = 'CLEAR_NEW_ARTICLE'
export const ARTICLE_UPDATE = 'ARTICLE_UPDATE'
export const ARTICLE_DESTROY = 'ARTICLE_DESTROY'
@@ -24,6 +26,13 @@ export const EDIT_MODE = 'EDIT_MODE'
// Article status
export const NEW = 'NEW'
export function updateUser (input) {
return {
type: USER_UPDATE,
data: input
}
}
// DB
export function clearNewArticle () {
return {

View File

@@ -1,5 +1,6 @@
import React from 'react'
import React, { PropTypes } from 'react'
import linkState from 'boost/linkState'
import { updateUser } from 'boost/actions'
const electron = require('electron')
const ipc = electron.ipcRenderer
@@ -9,24 +10,32 @@ export default class AppSettingTab extends React.Component {
constructor (props) {
super(props)
let keymap = remote.getGlobal('keymap')
let userName = props.user != null ? props.user.name : null
this.state = {
toggleFinder: keymap.toggleFinder,
alert: null
user: {
name: userName,
alert: null
},
userAlert: null,
keymap: {
toggleFinder: keymap.toggleFinder
},
keymapAlert: null
}
}
componentDidMount () {
this.handleSettingDone = () => {
this.setState({alert: {
this.setState({keymapAlert: {
type: 'success',
message: 'Successfully done!'
}})
}
this.handleSettingError = err => {
this.setState({alert: {
this.setState({keymapAlert: {
type: 'error',
message: err.message
message: err.message != null ? err.message : 'Error occurs!'
}})
}
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
@@ -40,7 +49,7 @@ export default class AppSettingTab extends React.Component {
submitHotKey () {
ipc.send('hotkeyUpdated', {
toggleFinder: this.state.toggleFinder
toggleFinder: this.state.keymap.toggleFinder
})
}
@@ -54,25 +63,56 @@ export default class AppSettingTab extends React.Component {
}
}
handleNameSaveButtonClick (e) {
let { dispatch } = this.props
dispatch(updateUser({name: this.state.user.name}))
this.setState({
userAlert: {
type: 'success',
message: 'Successfully done!'
}
})
}
render () {
let alert = this.state.alert
let alertElement = alert != null ? (
<p className={`alert ${alert.type}`}>
{alert.message}
let keymapAlert = this.state.keymapAlert
let keymapAlertElement = keymapAlert != null
? (
<p className={`alert ${keymapAlert.type}`}>
{keymapAlert.message}
</p>
) : null
let userAlert = this.state.userAlert
let userAlertElement = userAlert != null
? (
<p className={`alert ${userAlert.type}`}>
{userAlert.message}
</p>
) : null
return (
<div className='AppSettingTab content'>
<div className='section'>
<div className='sectionTitle'>User's info</div>
<div className='sectionInput'>
<label>User name</label>
<input valueLink={this.linkState('user.name')} type='text'/>
</div>
<div className='sectionConfirm'>
<button onClick={e => this.handleNameSaveButtonClick(e)}>Save</button>
{userAlertElement}
</div>
</div>
<div className='section'>
<div className='sectionTitle'>Hotkey</div>
<div className='sectionInput'>
<label>Toggle Finder(popup)</label>
<input onKeyDown={e => this.handleKeyDown(e)} valueLink={this.linkState('toggleFinder')} type='text'/>
<input onKeyDown={e => this.handleKeyDown(e)} valueLink={this.linkState('keymap.toggleFinder')} type='text'/>
</div>
<div className='sectionConfirm'>
<button onClick={e => this.handleSaveButtonClick(e)}>Save</button>
{alertElement}
{keymapAlertElement}
</div>
<div className='description'>
<ul>
@@ -101,3 +141,6 @@ export default class AppSettingTab extends React.Component {
}
AppSettingTab.prototype.linkState = linkState
AppSettingTab.propTypes = {
dispatch: PropTypes.func
}

View File

@@ -62,7 +62,7 @@ class Preferences extends React.Component {
}
renderContent () {
let { folders, dispatch } = this.props
let { user, folders, dispatch } = this.props
switch (this.state.currentTab) {
case HELP:
@@ -80,12 +80,20 @@ class Preferences extends React.Component {
)
case APP:
default:
return (<AppSettingTab/>)
return (
<AppSettingTab
user={user}
dispatch={dispatch}
/>
)
}
}
}
Preferences.propTypes = {
user: PropTypes.shape({
name: PropTypes.string
}),
folders: PropTypes.array,
dispatch: PropTypes.func
}
@@ -93,9 +101,10 @@ Preferences.propTypes = {
Preferences.prototype.linkState = linkState
function remap (state) {
let { folders, status } = state
let { user, folders, status } = state
return {
user,
folders,
status
}

View File

@@ -1,4 +1,6 @@
import keygen from 'boost/keygen'
import _ from 'lodash'
const electron = require('electron')
const remote = electron.remote
const jetpack = require('fs-jetpack')
@@ -10,15 +12,66 @@ function getLocalPath () {
return path.join(remote.app.getPath('userData'), 'local.json')
}
function forgeInitialRepositories () {
return [{
key: keygen(),
name: 'local',
type: 'userData',
user: {
name: remote.getGlobal('process').env.USER
}
}]
}
function getRepositories () {
let raw = localStorage.getItem('repositories')
try {
let parsed = JSON.parse(raw)
if (!_.isArray(parsed)) {
throw new Error('repositories data is currupte. re-init data.')
}
return parsed
} catch (e) {
console.log(e)
let newRepos = forgeInitialRepositories()
saveRepositories(newRepos)
return newRepos
}
}
function saveRepositories (repos) {
localStorage.setItem('repositories', JSON.stringify(repos))
}
export function getUser (repoName) {
if (repoName == null) {
return getRepositories()[0]
}
return null
}
export function saveUser (repoName, user) {
let repos = getRepositories()
if (repoName == null) {
Object.assign(repos[0].user, user)
}
saveRepositories(repos)
}
export function init () {
console.log('initialize data store')
// set repositories info
getRepositories()
// set local.json
let data = jetpack.read(getLocalPath(), 'json')
if (data == null) {
// for 0.4.1 -> 0.4.2
if (localStorage.getItem('local') != null) {
data = JSON.parse(localStorage.getItem('local'))
jetpack.write(getLocalPath(), data)
localStorage.removeItem('local')
console.log('update 0.4.1 => 0.4.2')
return
}
@@ -70,6 +123,8 @@ export default (function () {
init()
}
return {
getUser,
saveUser,
init,
getData,
setArticles,

View File

@@ -2,6 +2,6 @@ var crypto = require('crypto')
module.exports = function () {
var shasum = crypto.createHash('sha1')
shasum.update(((new Date()).getTime()).toString())
shasum.update(((new Date()).getTime() + Math.round(Math.random()*1000)).toString())
return shasum.digest('hex')
}

View File

@@ -12,6 +12,9 @@ import {
UNLOCK_STATUS,
TOGGLE_TUTORIAL,
// user
USER_UPDATE,
// Article action type
ARTICLE_UPDATE,
ARTICLE_DESTROY,
@@ -42,10 +45,22 @@ const initialStatus = {
let data = dataStore.getData()
let initialArticles = data.articles
let initialFolders = data.folders
let initialUser = dataStore.getUser().user
let isStatusLocked = false
let isCreatingNew = false
function user (state = initialUser, action) {
switch (action.type) {
case USER_UPDATE:
let updated = Object.assign(state, action.data)
dataStore.saveUser(null, updated)
return updated
default:
return state
}
}
function folders (state = initialFolders, action) {
state = state.slice()
switch (action.type) {
@@ -250,6 +265,7 @@ function status (state = initialStatus, action) {
}
export default combineReducers({
user,
folders,
articles,
status

View File

@@ -128,9 +128,10 @@ app.on('ready', function () {
console.log('FINDER(stdout): ' + payload.data)
break
case 'show-main-window':
if (mainWindow != null) {
mainWindow.show()
}
mainWindow.show()
break
case 'copy-finder':
mainWindow.webContents.send('copy-finder')
break
case 'request-data':
mainWindow.webContents.send('request-data')
@@ -173,6 +174,7 @@ app.on('ready', function () {
try {
globalShortcut.register(toggleFinderKey, function () {
emitToFinder('open-finder')
mainWindow.webContents.send('open-finder', {})
})
} catch (err) {
console.log(err.name)
@@ -189,6 +191,7 @@ app.on('ready', function () {
try {
globalShortcut.register(toggleFinderKey, function () {
emitToFinder('open-finder')
mainWindow.webContents.send('open-finder', {})
})
mainWindow.webContents.send('APP_SETTING_DONE', {})
} catch (err) {

View File

@@ -1,6 +1,6 @@
{
"name": "boost",
"version": "0.4.3",
"version": "0.4.4",
"description": "Boost App",
"main": "index.js",
"scripts": {