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

Compare commits

...

94 Commits

Author SHA1 Message Date
Rokt33r
86cc9fb7d8 bump up to v0.5.10 & add Contributors 2016-04-23 14:52:53 +09:00
Rokt33r
f98efe0b97 fix changelog link 2016-04-23 14:47:46 +09:00
Rokt33r
6c5345df64 disable asar & ignore node_modules/grunt 2016-04-23 13:03:10 +09:00
Dick Choi
2d97661d28 set grunt-electron-installer-debian optional 2016-04-23 12:13:57 +09:00
Dick Choi
3efe0c1ce2 use forked markdown-it-math 2016-04-23 11:20:37 +09:00
Rokt33r
6099c91216 standarded 2016-04-21 21:37:43 +09:00
Rokt33r
934e4d9607 Enhance style & Fix bug 2016-04-21 21:03:28 +09:00
Dick Choi
1198f6112e Merge pull request #20 from dojineko/dark-theme
Add dark theme
2016-04-21 20:03:11 +09:00
dojineko
777f7f9305 Add code theme selector 2016-04-17 21:52:55 +09:00
dojineko
43fb37ab1d Add dark theme and UI theme selector 2016-04-17 21:52:50 +09:00
dojineko
06734ec886 Add syntax theme selector 2016-04-17 21:03:27 +09:00
dojineko
0b8ae93727 Fix border shift 2016-04-17 21:03:27 +09:00
dojineko
24cea97e08 Replace single quote to entity reference 2016-04-16 13:58:05 +09:00
dojineko
18536e5db0 Ignore meta files 2016-04-16 13:16:45 +09:00
Rokt33r
8c236cb5cb add testing targets 2016-04-12 14:46:14 +09:00
Rokt33r
797c8ad7fa update readme.md 2016-04-12 13:47:37 +09:00
Rokt33r
ba8d2dcb8b add more option to gruntfile for installer-debian 2016-04-12 11:06:20 +09:00
Rokt33r
78a095d958 bumpup to 0.5.9 2016-04-11 08:08:52 +09:00
Rokt33r
627172f6df discard wrong error notification(There is no newer version.) 2016-04-11 08:08:42 +09:00
Dick Choi
a39f25961c reorganize menu for Linux 2016-04-07 08:35:51 +09:00
Dick Choi
e738ae5c8c Add more info to gruntfile for Linux app 2016-04-07 08:35:40 +09:00
Dick Choi
749e85e8e6 remove a depreciated option of mainWIndow 2016-04-07 08:22:54 +09:00
Dick Choi
cfa251b158 Disable Finder and Auto-update on Linux 2016-04-07 08:19:04 +09:00
Dick Choi
1ca38b8741 Update package urls 2016-04-04 08:03:32 +09:00
Dick Choi
d7bc5a7088 ready for linux app :) 2016-04-04 08:02:53 +09:00
Dick Choi
3b9a2c3ee1 Merged branch linux into master 2016-04-04 07:29:40 +09:00
Dick Choi
260ad77d39 Merged branch linux into master 2016-04-04 07:02:39 +09:00
Dick Choi
5c508a0cd9 Merge pull request #10 from brpaz/linux
Add support for creating .deb file on linux
2016-04-04 06:28:23 +09:00
Dick Choi
fd3d1607a4 Merge pull request #11 from brpaz/master
Fix case on style import
2016-04-02 23:38:26 +09:00
Bruno Paz
abbc0fbcf1 Fix case on style import 2016-04-02 14:09:23 +01:00
Bruno Paz
00be41608d Add support for creating .deb file on linux 2016-04-02 13:25:54 +01:00
Rokt33r
499c3f2e13 bump up version to 0.5.8 and upgrade electron packager 2016-04-02 20:45:45 +09:00
Rokt33r
627845f6e4 fix file drop behaviour 2016-04-02 20:15:14 +09:00
Rokt33r
07eea76057 fix editor selection bug 2016-04-02 20:14:47 +09:00
Rokt33r
fecc4e9b79 bump up to v0.5.7 2016-03-28 01:26:11 +09:00
Rokt33r
58e9302f15 remove email address 2016-03-28 01:09:43 +09:00
Rokt33r
86f649fab1 v0.5.6 2016-03-27 23:18:54 +09:00
Dick Choi
9ac0becfb2 Update readme.md 2016-03-26 03:53:13 +09:00
Rokt33r
eda547b868 Merge branch 'master' into linux
* master:
  configuring zoomfactor with Ctrl + Wheelscroll only works on windows and linux
  fix style bug of TagSelect
  bump up electron version to  0.36.11
  fix again(never break long tag)
  tags in ArticleList will be wrapped properly
  fix emacs key binding
  ctrl +  wheel to change zoom factor
  set Editor fontFamily to Title input
  add Link of Trello Kanban to readme.md
  Update contributing
  Focus to search box, when hotkey pushed
2016-03-16 16:52:17 +09:00
Rokt33r
f75e872415 configuring zoomfactor with Ctrl + Wheelscroll only works on windows and linux 2016-03-16 08:08:42 +09:00
Rokt33r
aef0712165 fix style bug of TagSelect 2016-03-16 08:02:46 +09:00
Rokt33r
bed4b7fd27 bump up electron version to 0.36.11 2016-03-15 16:17:39 +09:00
Rokt33r
b53ff5daf3 fix again(never break long tag) 2016-03-15 16:09:17 +09:00
Rokt33r
bb0872b4fc tags in ArticleList will be wrapped properly 2016-03-15 15:51:35 +09:00
Rokt33r
b65101f4be fix emacs key binding 2016-03-15 14:05:33 +09:00
Rokt33r
593d242a4c ctrl + wheel to change zoom factor 2016-03-15 02:24:28 +09:00
Rokt33r
db7f339c34 set Editor fontFamily to Title input 2016-03-15 01:32:31 +09:00
Rokt33r
9f3575a874 Merge branch 'master' into v0.5.5
* master:
  add Link of Trello Kanban to readme.md
2016-03-13 23:04:08 +09:00
Rokt33r
1c9c59c512 add Link of Trello Kanban to readme.md 2016-03-13 23:03:50 +09:00
Rokt33r
127202b831 Update contributing 2016-03-10 20:32:59 +09:00
Dick Choi
4f8a04ed21 Merge pull request #1 from dojineko/quick-search
Top search will be focused when Main window showed by hotkey.
2016-03-10 19:44:57 +09:00
dojineko
63b2e0560b Focus to search box, when hotkey pushed 2016-03-10 08:49:44 +09:00
Rokt33r
07291d71f2 add comment for linux version 2016-03-09 20:34:16 +09:00
Rokt33r
d1ca1ec4d9 Merge branch 'v0.5.5' into linux
* v0.5.5:
  The notification of 'Copy to Clipboard' must be slient
  modify window API to fit the new version of electron
  bump up version of electron
2016-03-09 20:03:07 +09:00
Rokt33r
6907cf9972 The notification of 'Copy to Clipboard' must be slient 2016-03-09 19:43:34 +09:00
Rokt33r
d4f8d1498d modify window API to fit the new version of electron 2016-03-09 19:42:45 +09:00
Rokt33r
0952e4a664 bump up version of electron 2016-03-09 03:16:40 +09:00
Rokt33r
6a4e8c95ea Merge branch 'master' into linux
* master:
  fix contributing
  add contributing
  modify readme
  modify LICENSE and readme
2016-03-09 02:52:06 +09:00
Rokt33r
983bfb7adf fix contributing 2016-03-09 02:50:33 +09:00
Rokt33r
d7aaf5e210 add contributing 2016-03-09 02:45:07 +09:00
Rokt33r
50281132ad modify readme 2016-03-09 02:44:57 +09:00
Rokt33r
6a2b22015e modify LICENSE and readme 2016-03-09 02:44:38 +09:00
Rokt33r
2f90890f50 setup gruntfile for linux deploy & disable finder and updater 2016-03-09 01:57:36 +09:00
Rokt33r
0fe83a0583 fix anchor target 2016-01-25 10:28:46 +09:00
Rokt33r
ce74e69480 check href exists 2016-01-22 08:00:26 +09:00
Rokt33r
ddea2aeb22 fix verticla-align of img in anchor 2016-01-22 07:58:25 +09:00
Rokt33r
7bbe69cce9 Merge branch 'v0.5.4'
* v0.5.4:
  bump up version to v0.5.4
  emit ARTICLE_CREATE when new post clicked
  update h1 style of markdown
  fix go to line end
  clean old code
  fix sanitizing bug in Code block
  done but bugged

Conflicts:
	package.json
2016-01-22 03:01:13 +09:00
Rokt33r
e921e30d64 bump up version to v0.5.4 2016-01-22 02:59:35 +09:00
Rokt33r
cd4f9d8bb4 emit ARTICLE_CREATE when new post clicked 2016-01-22 02:58:06 +09:00
Rokt33r
a0553788b6 update h1 style of markdown 2016-01-22 02:55:02 +09:00
Rokt33r
1a183d78af fix go to line end 2016-01-21 08:29:09 +09:00
Rokt33r
cabcaa892c clean old code 2016-01-21 05:50:53 +09:00
Rokt33r
01c9d62a2b fix sanitizing bug in Code block 2016-01-21 05:50:40 +09:00
Rokt33r
ba76df863c bump up version 2016-01-19 20:13:17 +09:00
Rokt33r
81441a0895 done but bugged 2016-01-19 20:11:38 +09:00
Rokt33r
da0222f213 esc to show preview when rightclick to toggle set 2016-01-19 18:58:27 +09:00
Rokt33r
fb8a2eb2e0 show proper error when hotkey updated 2016-01-19 18:47:35 +09:00
Rokt33r
cde2e27e04 must override default config 2016-01-19 18:47:10 +09:00
Dick Choi
3758ea2cf4 bump up version 2016-01-18 01:02:05 +09:00
Rokt33r
e62fc11328 switch folder properly after moving an article to other folder 2016-01-17 08:43:01 +09:00
Dick Choi
3cbfae83c1 fix basefonts again 2016-01-17 07:27:38 +09:00
Dick Choi
57667654ef add Base fonts for windows 2016-01-17 00:19:20 +09:00
Rokt33r
eadd66fa91 decode entities to parse properly by katex 2016-01-16 19:40:03 +09:00
Rokt33r
75cd94a39a refactor MarkdownPreview & protocol must be defined in 'href' to open in browser 2016-01-16 05:28:27 +09:00
Rokt33r
7872bfe19d Merge branch 'markdown' into v0.5.2
* markdown:
  markdown strike bug fixed, no emoji shortcut, checkbox syntax added
2016-01-16 04:54:02 +09:00
Rokt33r
af008e69c2 modify default hotkey(toggle-main-window) 2016-01-16 04:53:49 +09:00
Rokt33r
a549abc20f Refactor event handlers in ArticleEditor 2016-01-16 04:53:06 +09:00
Rokt33r
116344737a right click to quick preview(edit on focus) 2016-01-16 04:24:09 +09:00
Rokt33r
93c03f4e88 add right click to switch edit/preview option to app settings 2016-01-16 02:40:31 +09:00
Rokt33r
445332c27c Find command of ace won't fire blur 2016-01-16 00:58:49 +09:00
Rokt33r
c42e1892d0 fix a little 2016-01-15 23:35:41 +09:00
Rokt33r
b6b526dd57 activity record bug fix 2016-01-15 15:41:37 +09:00
Rokt33r
3ef7f19ffc devtools will automatically removed in production 2016-01-15 15:41:18 +09:00
Rokt33r
9d0d851c2e markdown strike bug fixed, no emoji shortcut, checkbox syntax added 2016-01-13 13:10:46 +09:00
47 changed files with 1401 additions and 496 deletions

3
.gitignore vendored
View File

@@ -1,4 +1,7 @@
.DS_Store
.env
Desktop.ini
Thumbs.db
node_modules/*
!node_modules/boost
/dist

18
LICENSE
View File

@@ -1,2 +1,16 @@
本製品をインストール、または使用することによって、お客様は利用規約(
https://b00st.io/regulations.htmlより拘束されることに承諾されたものとします。利用規約に同意されない場合、Boostnoteは、お客様に本製品のインストール、使用のいずれも許諾できません。
Boostnote - the simplest note app
Copyright (C) 2016 MAISIN&CO.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.

View File

@@ -21,12 +21,83 @@ export default class CodeEditor extends React.Component {
this.configApplyHandler = (e, config) => this.handleConfigApply(e, config)
this.changeHandler = e => this.handleChange(e)
this.blurHandler = (e) => {
if (e.relatedTarget === null) {
return
}
let isFocusingToSearch = e.relatedTarget.className && e.relatedTarget.className.split(' ').some(clss => {
return clss === 'ace_search_field' || clss === 'ace_searchbtn' || clss === 'ace_replacebtn' || clss === 'ace_searchbtn_close' || clss === 'ace_text-input'
})
if (isFocusingToSearch) {
return
}
if (this.props.onBlur) this.props.onBlur(e)
}
this.killedBuffer = ''
this.execHandler = (e) => {
console.log(e.command.name)
switch (e.command.name) {
case 'gotolinestart':
e.preventDefault()
{
let position = this.editor.getCursorPosition()
this.editor.navigateTo(position.row, 0)
}
break
case 'gotolineend':
e.preventDefault()
let position = this.editor.getCursorPosition()
this.editor.navigateTo(position.row, this.editor.getSession().getLine(position.row).length)
break
case 'jumptomatching':
e.preventDefault()
this.editor.navigateUp()
break
case 'removetolineend':
e.preventDefault()
let range = this.editor.getSelectionRange()
let session = this.editor.getSession()
if (range.isEmpty()) {
range.setEnd(range.start.row, session.getLine(range.start.row).length)
this.killedBuffer = session.getTextRange(range)
if (this.killedBuffer.length > 0) {
console.log('remove to lineend')
session.remove(range)
} else {
if (session.getLength() === range.start.row) {
return
}
range.setStart(range.start.row, range.end.col)
range.setEnd(range.start.row + 1, 0)
this.killedBuffer = '\n'
session.remove(range)
}
} else {
this.killedBuffer = session.getTextRange(range)
session.remove(range)
}
}
}
this.afterExecHandler = (e) => {
switch (e.command.name) {
case 'find':
Array.prototype.forEach.call(ReactDOM.findDOMNode(this).querySelectorAll('.ace_search_field, .ace_searchbtn, .ace_replacebtn, .ace_searchbtn_close'), el => {
el.removeEventListener('blur', this.blurHandler)
el.addEventListener('blur', this.blurHandler)
})
break
}
}
this.state = {
fontSize: config['editor-font-size'],
fontFamily: config['editor-font-family'],
indentType: config['editor-indent-type'],
indentSize: config['editor-indent-size']
indentSize: config['editor-indent-size'],
themeSyntax: config['theme-syntax']
}
this.silentChange = false
@@ -44,11 +115,13 @@ export default class CodeEditor extends React.Component {
var editor = this.editor = ace.edit(el)
editor.$blockScrolling = Infinity
editor.renderer.setShowGutter(true)
editor.setTheme('ace/theme/xcode')
editor.setTheme('ace/theme/' + this.state.themeSyntax)
editor.moveCursorTo(0, 0)
editor.setReadOnly(!!this.props.readOnly)
editor.setFontSize(this.state.fontSize)
editor.on('blur', this.blurHandler)
editor.commands.addCommand({
name: 'Emacs cursor up',
bindKey: {mac: 'Ctrl-P'},
@@ -58,18 +131,29 @@ export default class CodeEditor extends React.Component {
},
readOnly: true
})
editor.commands.addCommand({
name: 'Emacs cursor up',
bindKey: {mac: 'Ctrl-Y'},
exec: function (editor) {
editor.insert(this.killedBuffer)
}.bind(this),
readOnly: true
})
editor.commands.addCommand({
name: 'Focus title',
bindKey: {win: 'Esc', mac: 'Esc'},
exec: function (editor, e) {
remote.getCurrentWebContents().send('list-focus')
let currentWindow = remote.getCurrentWebContents()
if (config['switch-preview'] === 'rightclick') {
currentWindow.send('detail-preview')
}
currentWindow.send('list-focus')
},
readOnly: true
})
editor.on('blur', () => {
if (this.props.onBlur) this.props.onBlur()
})
editor.commands.on('exec', this.execHandler)
editor.commands.on('afterExec', this.afterExecHandler)
var session = editor.getSession()
let mode = _.findWhere(modes, {name: article.mode})
@@ -92,6 +176,9 @@ export default class CodeEditor extends React.Component {
componentWillUnmount () {
ipc.removeListener('config-apply', this.configApplyHandler)
this.editor.getSession().removeListener('change', this.changeHandler)
this.editor.removeListener('blur', this.blurHandler)
this.editor.commands.removeListener('exec', this.execHandler)
this.editor.commands.removeListener('afterExec', this.afterExecHandler)
}
componentDidUpdate (prevProps, prevState) {
@@ -116,9 +203,13 @@ export default class CodeEditor extends React.Component {
fontSize: config['editor-font-size'],
fontFamily: config['editor-font-family'],
indentType: config['editor-indent-type'],
indentSize: config['editor-indent-size']
indentSize: config['editor-indent-size'],
themeSyntax: config['theme-syntax']
}, function () {
var session = this.editor.getSession()
var editor = this.editor
editor.setTheme('ace/theme/' + this.state.themeSyntax)
var session = editor.getSession()
session.setUseSoftTabs(this.state.indentType === 'space')
session.setTabSize(!isNaN(this.state.indentSize) ? parseInt(this.state.indentSize, 10) : 4)
})
@@ -166,8 +257,8 @@ CodeEditor.propTypes = {
key: PropTypes.string
}),
className: PropTypes.string,
onChange: PropTypes.func,
onBlur: PropTypes.func,
onChange: PropTypes.func,
readOnly: PropTypes.bool
}

View File

@@ -11,27 +11,36 @@ const ipc = electron.ipcRenderer
const katex = window.katex
const OSX = global.process.platform === 'darwin'
const sanitizeOpts = {
allowedTags: [ 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'blockquote', 'p', 'a', 'ul', 'ol',
'nl', 'li', 'b', 'i', 'strong', 'em', 'strike', 'code', 'hr', 'br', 'div',
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'img', 'span', 'cite', 'del', 'u', 'sub', 'sup' ],
'table', 'thead', 'caption', 'tbody', 'tr', 'th', 'td', 'pre', 'img', 'span', 'cite', 'del', 'u', 'sub', 'sup', 's', 'input', 'label' ],
allowedClasses: {
'a': ['lineAnchor'],
'div': ['math'],
'pre': ['hljs'],
'span': ['math', 'hljs-*'],
'code': ['language-*']
},
allowedAttributes: {
a: ['href', 'data-key'],
img: [ 'src' ],
label: ['for'],
input: ['checked', 'type'],
'*': ['id', 'name']
},
transformTags: {
'*': function (tagName, attribs) {
let href = attribs.href
if (tagName === 'input' && attribs.type !== 'checkbox') {
return false
}
if (_.isString(href) && href.match(/^#.+$/)) attribs.href = href.replace(/^#/, '#md-anchor-')
if (attribs.id) attribs.id = 'md-anchor-' + attribs.id
if (attribs.name) attribs.name = 'md-anchor-' + attribs.name
if (attribs.for) attribs.for = 'md-anchor-' + attribs.for
return {
tagName: tagName,
attribs: attribs
@@ -41,12 +50,15 @@ const sanitizeOpts = {
}
function handleAnchorClick (e) {
if (e.target.attributes.href && e.target.attributes.href.nodeValue.match(/#.+/)) {
if (this.attributes.href && this.attributes.href.nodeValue.match(/^#.+/)) {
return
}
e.preventDefault()
e.stopPropagation()
shell.openExternal(e.target.href)
let href = this.href
if (href && href.match(/^http:\/\/|https:\/\/|mailto:\/\//)) {
shell.openExternal(href)
}
}
function stopPropagation (e) {
@@ -57,7 +69,7 @@ function stopPropagation (e) {
function math2Katex (display) {
return function (el) {
try {
katex.render(el.innerHTML, el, {display: display})
katex.render(el.innerHTML.replace(/&lt;/g, '<').replace(/&gt;/g, '>').replace(/&quot;/g, '"').replace(/&amp;/g, '&'), el, {display: display})
el.className = 'math-rendered'
} catch (e) {
el.innerHTML = e.message
@@ -111,22 +123,30 @@ export default class MarkdownPreview extends React.Component {
addListener () {
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
var inputs = ReactDOM.findDOMNode(this).querySelectorAll('input')
for (var i = 0; i < anchors.length; i++) {
anchors[i].addEventListener('click', handleAnchorClick)
anchors[i].addEventListener('mousedown', stopPropagation)
anchors[i].addEventListener('mouseup', stopPropagation)
}
Array.prototype.forEach.call(anchors, anchor => {
anchor.addEventListener('click', handleAnchorClick)
anchor.addEventListener('mousedown', stopPropagation)
anchor.addEventListener('mouseup', stopPropagation)
})
Array.prototype.forEach.call(inputs, input => {
input.addEventListener('click', stopPropagation)
})
}
removeListener () {
var anchors = ReactDOM.findDOMNode(this).querySelectorAll('a:not(.lineAnchor)')
var inputs = ReactDOM.findDOMNode(this).querySelectorAll('input')
for (var i = 0; i < anchors.length; i++) {
anchors[i].removeEventListener('click', handleAnchorClick)
anchors[i].removeEventListener('mousedown', stopPropagation)
anchors[i].removeEventListener('mouseup', stopPropagation)
}
Array.prototype.forEach.call(anchors, anchor => {
anchor.removeEventListener('click', handleAnchorClick)
anchor.removeEventListener('mousedown', stopPropagation)
anchor.removeEventListener('mouseup', stopPropagation)
})
Array.prototype.forEach.call(inputs, input => {
input.removeEventListener('click', stopPropagation)
})
}
handleClick (e) {
@@ -185,7 +205,7 @@ export default class MarkdownPreview extends React.Component {
dangerouslySetInnerHTML={{__html: ' ' + content}}
style={{
fontSize: this.state.fontSize,
fontFamily: this.state.fontFamily.trim() + ', helvetica, arial, sans-serif'
fontFamily: this.state.fontFamily.trim() + (OSX ? '' : ', meiryo, \'Microsoft YaHei\'') + ', helvetica, arial, sans-serif'
}}
/>
)

View File

@@ -9,11 +9,35 @@ import FinderDetail from './FinderDetail'
import actions, { selectArticle, searchArticle } from './actions'
import _ from 'lodash'
import dataStore from 'browser/lib/dataStore'
import fetchConfig from '../lib/fetchConfig'
const electron = require('electron')
const { clipboard, ipcRenderer } = electron
const { clipboard, ipcRenderer, remote } = electron
const path = require('path')
let config = fetchConfig()
applyConfig(config)
ipcRenderer.on('config-apply', function (e, newConfig) {
config = newConfig
applyConfig(config)
})
function applyConfig () {
let body = document.body
body.setAttribute('data-theme', config['theme-ui'])
let hljsCss = document.getElementById('hljs-css')
hljsCss.setAttribute('href', '../node_modules/highlight.js/styles/' + config['theme-code'] + '.css')
}
if (process.env.NODE_ENV !== 'production') {
window.addEventListener('keydown', function (e) {
if (e.keyCode === 73 && e.metaKey && e.altKey) {
remote.getCurrentWindow().toggleDevTools()
}
})
}
function hideFinder () {
ipcRenderer.send('hide-finder')
}
@@ -21,7 +45,6 @@ function hideFinder () {
function notify (title, options) {
if (process.platform === 'win32') {
options.icon = path.join('file://', global.__dirname, '../../resources/app.png')
options.silent = false
}
return new window.Notification(title, options)
}
@@ -88,7 +111,8 @@ class FinderMain extends React.Component {
ipcRenderer.send('copy-finder')
notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!'
body: 'Paste it wherever you want!',
silent: true
})
hideFinder()
}

View File

@@ -41,7 +41,7 @@ Post all records(except today)
and remove all posted records
*/
export function postRecords (data) {
if (process.NODE_ENV !== 'production') {
if (process.env.NODE_ENV !== 'production') {
console.log('post failed - NOT PRODUCTION ')
return
}
@@ -108,7 +108,7 @@ export function emit (type, data = {}) {
}
// Count ARTICLE_CREATE and ARTICLE_UPDATE again by syntax
if ((type === 'ARTICLE_CREATE' || type === 'ARTICLE_UPDATE') && data.mode != null) {
if (type === 'ARTICLE_UPDATE' && data.mode != null) {
let recordKey = type + '_BY_SYNTAX'
if (todayRecord[recordKey] == null) todayRecord[recordKey] = {}

View File

@@ -5,6 +5,20 @@ const jetpack = require('fs-jetpack')
const userDataPath = remote.app.getPath('userData')
const configFile = 'config.json'
export default function fetchConfig () {
return Object.assign({}, JSON.parse(jetpack.cwd(userDataPath).read(configFile, 'utf-8')))
const defaultConfig = {
'editor-font-size': '14',
'editor-font-family': 'Monaco, Consolas',
'editor-indent-type': 'space',
'editor-indent-size': '4',
'preview-font-size': '14',
'preview-font-family': 'Lato',
'switch-preview': 'blur',
'disable-direct-write': false,
'theme-ui': 'light',
'theme-code': 'xcode',
'theme-syntax': 'xcode'
}
export default function fetchConfig () {
return Object.assign({}, defaultConfig, JSON.parse(jetpack.cwd(userDataPath).read(configFile, 'utf-8')))
}

78
browser/lib/hljsThemes.js Normal file
View File

@@ -0,0 +1,78 @@
const hljsThemeList = [
{caption: 'Default', name: 'default'},
{caption: 'Agate', name: 'agate'},
{caption: 'Androidstudio', name: 'androidstudio'},
{caption: 'Arduino Light', name: 'arduino-light'},
{caption: 'Arta', name: 'arta'},
{caption: 'Ascetic', name: 'ascetic'},
{caption: 'Atelier Cave Dark', name: 'atelier-cave-dark'},
{caption: 'Atelier Cave Light', name: 'atelier-cave-light'},
{caption: 'Atelier Dune Dark', name: 'atelier-dune-dark'},
{caption: 'Atelier Dune Light', name: 'atelier-dune-light'},
{caption: 'Atelier Estuary Dark', name: 'atelier-estuary-dark'},
{caption: 'Atelier Estuary Light', name: 'atelier-estuary-light'},
{caption: 'Atelier Forest Dark', name: 'atelier-forest-dark'},
{caption: 'Atelier Forest Light', name: 'atelier-forest-light'},
{caption: 'Atelier Heath Dark', name: 'atelier-heath-dark'},
{caption: 'Atelier Heath Light', name: 'atelier-heath-light'},
{caption: 'Atelier Lakeside Dark', name: 'atelier-lakeside-dark'},
{caption: 'Atelier Lakeside Light', name: 'atelier-lakeside-light'},
{caption: 'Atelier Plateau Dark', name: 'atelier-plateau-dark'},
{caption: 'Atelier Plateau Light', name: 'atelier-plateau-light'},
{caption: 'Atelier Savanna Dark', name: 'atelier-savanna-dark'},
{caption: 'Atelier Savanna Light', name: 'atelier-savanna-light'},
{caption: 'Atelier Seaside Dark', name: 'atelier-seaside-dark'},
{caption: 'Atelier Seaside Light', name: 'atelier-seaside-light'},
{caption: 'Atelier Sulphurpool Dark', name: 'atelier-sulphurpool-dark'},
{caption: 'Atelier Sulphurpool Light', name: 'atelier-sulphurpool-light'},
{caption: 'Brown Paper', name: 'brown-paper'},
{caption: 'Codepen Embed', name: 'codepen-embed'},
{caption: 'Color Brewer', name: 'color-brewer'},
{caption: 'Dark', name: 'dark'},
{caption: 'Darkula', name: 'darkula'},
{caption: 'Docco', name: 'docco'},
{caption: 'Dracula', name: 'dracula'},
{caption: 'Far', name: 'far'},
{caption: 'Foundation', name: 'foundation'},
{caption: 'Github Gist', name: 'github-gist'},
{caption: 'Github', name: 'github'},
{caption: 'Googlecode', name: 'googlecode'},
{caption: 'Grayscale', name: 'grayscale'},
{caption: 'Gruvbox Dark', name: 'gruvbox.dark'},
{caption: 'Gruvbox Light', name: 'gruvbox.light'},
{caption: 'Hopscotch', name: 'hopscotch'},
{caption: 'Hybrid', name: 'hybrid'},
{caption: 'Idea', name: 'idea'},
{caption: 'Ir Black', name: 'ir-black'},
{caption: 'Kimbie Dark', name: 'kimbie.dark'},
{caption: 'Kimbie Light', name: 'kimbie.light'},
{caption: 'Magula', name: 'magula'},
{caption: 'Mono Blue', name: 'mono-blue'},
{caption: 'Monokai Sublime', name: 'monokai-sublime'},
{caption: 'Monokai', name: 'monokai'},
{caption: 'Obsidian', name: 'obsidian'},
{caption: 'Paraiso Dark', name: 'paraiso-dark'},
{caption: 'Paraiso Light', name: 'paraiso-light'},
{caption: 'Pojoaque', name: 'pojoaque'},
{caption: 'Qtcreator Dark', name: 'qtcreator_dark'},
{caption: 'Qtcreator Light', name: 'qtcreator_light'},
{caption: 'Railscasts', name: 'railscasts'},
{caption: 'Rainbow', name: 'rainbow'},
{caption: 'School Book', name: 'school-book'},
{caption: 'Solarized Dark', name: 'solarized-dark'},
{caption: 'Solarized Light', name: 'solarized-light'},
{caption: 'Sunburst', name: 'sunburst'},
{caption: 'Tomorrow Night Blue', name: 'tomorrow-night-blue'},
{caption: 'Tomorrow Night Bright', name: 'tomorrow-night-bright'},
{caption: 'Tomorrow Night Eighties', name: 'tomorrow-night-eighties'},
{caption: 'Tomorrow Night', name: 'tomorrow-night'},
{caption: 'Tomorrow', name: 'tomorrow'},
{caption: 'Vs', name: 'vs'},
{caption: 'Xcode', name: 'xcode'},
{caption: 'Xt 256', name: 'xt256'},
{caption: 'Zenburn', name: 'zenburn'}
]
export default function hljsTheme () {
return hljsThemeList
}

View File

@@ -1,6 +1,6 @@
import markdownit from 'markdown-it'
import emoji from 'markdown-it-emoji'
import math from 'markdown-it-math'
import math from '@rokt33r/markdown-it-math'
import hljs from 'highlight.js'
var md = markdownit({
@@ -11,13 +11,19 @@ var md = markdownit({
highlight: function (str, lang) {
if (lang && hljs.getLanguage(lang)) {
try {
return hljs.highlight(lang, str).value
return '<pre class="hljs"><code>' +
hljs.highlight(lang, str).value +
'</code></pre>'
} catch (e) {}
}
return str
return '<pre class="hljs"><code>' +
str.replace(/\&/g, '&amp;').replace(/\</g, '&lt;').replace(/\>/g, '&gt;').replace(/\"/g, '&quot;') +
'</code></pre>'
}
})
md.use(emoji)
md.use(emoji, {
shortcuts: {}
})
md.use(math, {
inlineRenderer: function (str) {
return `<span class='math'>${str}</span>`
@@ -26,6 +32,7 @@ md.use(math, {
return `<div class='math'>${str}</div>`
}
})
md.use(require('markdown-it-checkbox'))
let originalRenderToken = md.renderer.renderToken
md.renderer.renderToken = function renderToken (tokens, idx, options) {

View File

@@ -2,21 +2,43 @@ import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import CodeEditor from 'browser/components/CodeEditor'
import activityRecord from 'browser/lib/activityRecord'
import fetchConfig from 'browser/lib/fetchConfig'
const electron = require('electron')
const ipc = electron.ipcRenderer
export const PREVIEW_MODE = 'PREVIEW_MODE'
export const EDIT_MODE = 'EDIT_MODE'
let config = fetchConfig()
ipc.on('config-apply', function (e, newConfig) {
config = newConfig
})
export default class ArticleEditor extends React.Component {
constructor (props) {
super(props)
this.configApplyHandler = (e, config) => this.handleConfigApply(e, config)
this.isMouseDown = false
this.state = {
status: PREVIEW_MODE,
cursorPosition: null,
firstVisibleRow: null
firstVisibleRow: null,
switchPreview: config['switch-preview'],
isTemporary: false
}
}
componentDidMount () {
ipc.on('config-apply', this.configApplyHandler)
}
componentWillUnmount () {
ipc.removeListener('config-apply', this.configApplyHandler)
}
componentWillReceiveProps (nextProps) {
if (nextProps.article.key !== this.props.article.key) {
this.setState({
@@ -25,6 +47,12 @@ export default class ArticleEditor extends React.Component {
}
}
handleConfigApply (e, newConfig) {
this.setState({
switchPreview: newConfig['switch-preview']
})
}
resetCursorPosition () {
this.setState({
cursorPosition: null,
@@ -35,13 +63,15 @@ export default class ArticleEditor extends React.Component {
})
}
switchPreviewMode () {
switchPreviewMode (isTemporary = false) {
if (this.props.article.mode !== 'markdown') return true
let cursorPosition = this.refs.editor.getCursorPosition()
let firstVisibleRow = this.refs.editor.getFirstVisibleRow()
this.setState({
status: PREVIEW_MODE,
cursorPosition,
firstVisibleRow
firstVisibleRow,
isTemporary: isTemporary
}, function () {
let previewEl = ReactDOM.findDOMNode(this.refs.preview)
let anchors = previewEl.querySelectorAll('.lineAnchor')
@@ -55,43 +85,27 @@ export default class ArticleEditor extends React.Component {
})
}
switchEditMode () {
switchEditMode (isTemporary = false) {
this.setState({
status: EDIT_MODE
status: EDIT_MODE,
isTemporary: false
}, function () {
if (this.state.cursorPosition != null) {
this.refs.editor.moveCursorTo(this.state.cursorPosition.row, this.state.cursorPosition.column)
this.refs.editor.scrollToLine(this.state.firstVisibleRow)
}
this.refs.editor.editor.focus()
if (!isTemporary) activityRecord.emit('ARTICLE_UPDATE', this.props.article)
})
}
handlePreviewMouseDown (e) {
if (e.button === 2) return true
this.isDrag = false
this.isMouseDown = true
this.moveCount = 0
handleBlurCodeEditor (e) {
let isFocusingToThis = e.relatedTarget === ReactDOM.findDOMNode(this)
if (isFocusingToThis || this.state.switchPreview !== 'blur') {
return
}
handlePreviewMouseMove () {
if (this.isMouseDown) {
this.moveCount++
if (this.moveCount > 5) {
this.isDrag = true
}
}
}
handlePreviewMouseUp () {
this.isMouseDown = false
this.moveCount = 0
if (!this.isDrag) {
this.switchEditMode()
}
}
handleBlurCodeEditor () {
let { article } = this.props
if (article.mode === 'markdown') {
this.switchPreviewMode()
@@ -102,36 +116,115 @@ export default class ArticleEditor extends React.Component {
this.props.onChange(value)
}
handleRightClick (e) {
let { article } = this.props
if (this.state.switchPreview === 'rightclick' && article.mode === 'markdown') {
if (this.state.status === EDIT_MODE) this.switchPreviewMode()
else this.switchEditMode()
}
}
handleMouseUp (e) {
let { article } = this.props
let showPreview = article.mode === 'markdown' && this.state.status === PREVIEW_MODE
if (!showPreview) {
return false
}
switch (this.state.switchPreview) {
case 'blur':
switch (e.button) {
case 0:
this.isMouseDown = false
this.moveCount = 0
if (!this.isDrag) {
this.switchEditMode()
}
break
case 2:
if (this.state.isTemporary) this.switchEditMode(true)
}
break
case 'rightclick':
}
}
handleMouseMove (e) {
let { article } = this.props
let showPreview = article.mode === 'markdown' && this.state.status === PREVIEW_MODE
if (!showPreview) {
return false
}
if (this.state.switchPreview === 'blur' && this.isMouseDown) {
this.moveCount++
if (this.moveCount > 5) {
this.isDrag = true
}
}
}
handleMouseDowm (e) {
let { article } = this.props
let showPreview = article.mode === 'markdown' && this.state.status === PREVIEW_MODE
if (!showPreview) {
return false
}
switch (this.state.switchPreview) {
case 'blur':
switch (e.button) {
case 0:
this.isDrag = false
this.isMouseDown = true
this.moveCount = 0
break
case 2:
if (this.state.status === EDIT_MODE && this.props.article.mode === 'markdown') {
this.switchPreviewMode(true)
}
}
break
case 'rightclick':
}
}
render () {
let { article } = this.props
let showPreview = article.mode === 'markdown' && this.state.status === PREVIEW_MODE
if (showPreview) {
return (
<div className='ArticleEditor'>
<MarkdownPreview
ref='preview'
onMouseUp={e => this.handlePreviewMouseUp(e)}
onMouseDown={e => this.handlePreviewMouseDown(e)}
onMouseMove={e => this.handlePreviewMouseMove(e)}
content={article.content}
/>
<div className='ArticleDetail-panel-content-tooltip'>Click to Edit</div>
</div>
)
}
return (
<div className='ArticleEditor'>
<CodeEditor
<div
tabIndex='5'
onContextMenu={e => this.handleRightClick(e)}
onMouseUp={e => this.handleMouseUp(e)}
onMouseMove={e => this.handleMouseMove(e)}
onMouseDown={e => this.handleMouseDowm(e)}
className='ArticleEditor'
>
{showPreview
? <MarkdownPreview
ref='preview'
content={article.content}
/>
: <CodeEditor
ref='editor'
onBlur={e => this.handleBlurCodeEditor(e)}
onChange={value => this.handleCodeEditorChange(value)}
article={article}
/>
}
{article.mode === 'markdown'
? (
<div className='ArticleDetail-panel-content-tooltip'>Press ESC to watch Preview</div>
)
? <div className='ArticleDetail-panel-content-tooltip' children={
showPreview
? this.state.switchPreview === 'blur'
? 'Click to Edit'
: 'Right Click to Edit'
: this.state.switchPreview === 'blur'
? 'Press ESC to Watch Preview'
: 'Right Click to Watch Preview'
}
/>
: null
}
</div>
@@ -145,5 +238,6 @@ ArticleEditor.propTypes = {
key: PropTypes.string,
mode: PropTypes.string
}),
onChange: PropTypes.func
onChange: PropTypes.func,
parent: PropTypes.object
}

View File

@@ -4,10 +4,7 @@ import moment from 'moment'
import _ from 'lodash'
import {
switchFolder,
updateArticle,
// cacheArticle,
// saveArticle,
// uncacheArticle
updateArticle
} from '../../actions'
import linkState from 'browser/lib/linkState'
import TagSelect from 'browser/components/TagSelect'
@@ -18,22 +15,12 @@ import DeleteArticleModal from '../../modal/DeleteArticleModal'
import ArticleEditor from './ArticleEditor'
const electron = require('electron')
const ipc = electron.ipcRenderer
import fetchConfig from 'browser/lib/fetchConfig'
// const remote = electron.remote
// const { Menu, MenuItem } = remote
// const othersMenu = new Menu()
// othersMenu.append(new MenuItem({
// label: 'Delete Post',
// click: function () {
// remote.getCurrentWebContents().send('detail-delete')
// }
// }))
// othersMenu.append(new MenuItem({
// label: 'Discard Change',
// click: function (item) {
// remote.getCurrentWebContents().send('detail-uncache')
// }
// }))
let config = fetchConfig()
ipc.on('config-apply', function (e, newConfig) {
config = newConfig
})
const BRAND_COLOR = '#18AF90'
const OSX = global.process.platform === 'darwin'
@@ -80,10 +67,6 @@ export default class ArticleDetail extends React.Component {
constructor (props) {
super(props)
this.saveHandler = e => {
if (isModalOpen()) return true
this.handleSaveButtonClick()
}
this.deleteHandler = e => {
if (isModalOpen()) return true
this.handleDeleteButtonClick()
@@ -102,10 +85,16 @@ export default class ArticleDetail extends React.Component {
if (isModalOpen()) return true
if (this.refs.editor) this.refs.editor.switchEditMode()
}
this.previewHandler = e => {
if (isModalOpen()) return true
if (this.refs.editor) this.refs.editor.switchPreviewMode()
}
this.configApplyHandler = (e, config) => this.handleConfigApply(e, config)
this.state = {
article: Object.assign({content: ''}, props.activeArticle),
openShareDropdown: false
openShareDropdown: false,
fontFamily: config['editor-font-family']
}
}
@@ -115,21 +104,22 @@ export default class ArticleDetail extends React.Component {
e.stopPropagation()
}
// ipc.on('detail-save', this.saveHandler)
ipc.on('detail-delete', this.deleteHandler)
ipc.on('detail-uncache', this.uncacheHandler)
ipc.on('detail-title', this.titleHandler)
ipc.on('detail-edit', this.editHandler)
ipc.on('detail-preview', this.previewHandler)
ipc.on('config-apply', this.configApplyHandler)
}
componentWillUnmount () {
clearInterval(this.refreshTimer)
// ipc.removeListener('detail-save', this.saveHandler)
ipc.removeListener('detail-delete', this.deleteHandler)
ipc.removeListener('detail-uncache', this.uncacheHandler)
ipc.removeListener('detail-title', this.titleHandler)
ipc.removeListener('detail-edit', this.editHandler)
ipc.removeListener('detail-preview', this.previewHandler)
}
componentDidUpdate (prevProps, prevState) {
@@ -142,6 +132,12 @@ export default class ArticleDetail extends React.Component {
}
}
handleConfigApply (e, config) {
this.setState({
fontFamily: config['editor-font-family']
})
}
renderEmpty () {
return (
<div className='ArticleDetail empty'>
@@ -165,7 +161,7 @@ export default class ArticleDetail extends React.Component {
dispatch(updateArticle(article))
let targetFolderKey = this.state.article.FolderKey
let targetFolderKey = e.target.value
if (status.targetFolders.length > 0) {
let targetFolder = _.findWhere(folders, {key: targetFolderKey})
dispatch(switchFolder(targetFolder.name))
@@ -328,6 +324,9 @@ export default class ArticleDetail extends React.Component {
ref='title'
value={activeArticle.title}
onChange={e => this.handleTitleChange(e)}
style={{
fontFamily: this.state.fontFamily
}}
/>
</div>
<ModeSelect

View File

@@ -4,6 +4,7 @@ import ExternalLink from 'browser/components/ExternalLink'
import { setSearchFilter, clearSearch, toggleTutorial, saveArticle, switchFolder } from '../actions'
import { isModalOpen } from 'browser/lib/modal'
import keygen from 'browser/lib/keygen'
import activityRecord from 'browser/lib/activityRecord'
const electron = require('electron')
const remote = electron.remote
@@ -167,6 +168,7 @@ export default class ArticleTopBar extends React.Component {
dispatch(saveArticle(newArticle.key, newArticle, true))
if (isFolderFilterApplied) dispatch(switchFolder(targetFolders[0].name))
remote.getCurrentWebContents().send('detail-title')
activityRecord.emit('ARTICLE_CREATE')
}
handleTutorialButtonClick (e) {
@@ -229,8 +231,8 @@ export default class ArticleTopBar extends React.Component {
<ExternalLink className='ArticleTopBar-right-links-button-dropdown-item' href='https://b00st.io'>
<i className='fa fa-fw fa-home'/>Boost official page
</ExternalLink>
<ExternalLink className='ArticleTopBar-right-links-button-dropdown-item' href='https://github.com/BoostIO/boost-app-discussions/issues'>
<i className='fa fa-fw fa-bullhorn'/> Discuss
<ExternalLink className='ArticleTopBar-right-links-button-dropdown-item' href='https://github.com/BoostIO/Boostnote/issues'>
<i className='fa fa-fw fa-github'/> Issues
</ExternalLink>
</div>
)

View File

@@ -19,9 +19,27 @@ export default class MainContainer extends React.Component {
ipc.send('update-app', 'Deal with it.')
}
handleWheel (e) {
if (e.ctrlKey && global.process.platform !== 'darwin') {
if (window.document.body.style.zoom == null) {
window.document.body.style.zoom = 1
}
let zoom = Number(window.document.body.style.zoom)
if (e.deltaY > 0 && zoom < 4) {
document.body.style.zoom = zoom + 0.05
} else if (e.deltaY < 0 && zoom > 0.5) {
document.body.style.zoom = zoom - 0.05
}
}
}
render () {
return (
<div className='Main'>
<div
className='Main'
onWheel={(e) => this.handleWheel(e)}
>
{this.state.updateAvailable ? (
<button onClick={this.updateApp} className='appUpdateButton'><i className='fa fa-cloud-download'/> Update available!</button>
) : null}

View File

@@ -5,17 +5,52 @@ import React from 'react'
import ReactDOM from 'react-dom'
require('../styles/main/index.styl')
import { openModal } from 'browser/lib/modal'
import Tutorial from './modal/Tutorial'
import OSSAnnounceModal from './modal/OSSAnnounceModal'
import activityRecord from 'browser/lib/activityRecord'
import fetchConfig from '../lib/fetchConfig'
const electron = require('electron')
const ipc = electron.ipcRenderer
const path = require('path')
const remote = electron.remote
let config = fetchConfig()
applyConfig(config)
ipc.on('config-apply', function (e, newConfig) {
config = newConfig
applyConfig(config)
})
function applyConfig (config) {
let body = document.body
body.setAttribute('data-theme', config['theme-ui'])
let hljsCss = document.getElementById('hljs-css')
hljsCss.setAttribute('href', '../node_modules/highlight.js/styles/' + config['theme-code'] + '.css')
}
if (process.env.NODE_ENV !== 'production') {
window.addEventListener('keydown', function (e) {
if (e.keyCode === 73 && e.metaKey && e.altKey) {
remote.getCurrentWindow().toggleDevTools()
}
})
}
activityRecord.init()
window.addEventListener('online', function () {
ipc.send('check-update', 'check-update')
})
document.addEventListener('drop', function (e) {
e.preventDefault()
e.stopPropagation()
})
document.addEventListener('dragover', function (e) {
e.preventDefault()
e.stopPropagation()
})
function notify (title, options) {
if (process.platform === 'win32') {
options.icon = path.join('file://', global.__dirname, '../../resources/app.png')
@@ -50,9 +85,10 @@ ReactDOM.render((
loadingCover.parentNode.removeChild(loadingCover)
let status = JSON.parse(localStorage.getItem('status'))
if (status == null) status = {}
if (!status.introWatched) {
openModal(Tutorial)
status.introWatched = true
if (!status.ossAnnounceWatched) {
openModal(OSSAnnounceModal)
status.ossAnnounceWatched = true
localStorage.setItem('status', JSON.stringify(status))
}
})

View File

@@ -0,0 +1,29 @@
import React, { PropTypes } from 'react'
import ExternalLink from 'browser/components/ExternalLink'
export default class OSSAnnounceModal extends React.Component {
handleCloseBtnClick (e) {
this.props.close()
}
render () {
return (
<div className='OSSAnnounceModal modal'>
<div className='OSSAnnounceModal-title'>Boostnote has been Open-sourced</div>
<ExternalLink className='OSSAnnounceModal-link' href='https://github.com/BoostIO/Boostnote'>
https://github.com/BoostIO/Boostnote
</ExternalLink>
<button
className='OSSAnnounceModal-closeBtn'
onClick={(e) => this.handleCloseBtnClick(e)}
>Close</button>
</div>
)
}
}
OSSAnnounceModal.propTypes = {
close: PropTypes.func
}

View File

@@ -2,10 +2,12 @@ import React, { PropTypes } from 'react'
import linkState from 'browser/lib/linkState'
import { updateUser } from '../../actions'
import fetchConfig from 'browser/lib/fetchConfig'
import hljsTheme from 'browser/lib/hljsThemes'
const electron = require('electron')
const ipc = electron.ipcRenderer
const remote = electron.remote
const ace = window.ace
const OSX = global.process.platform === 'darwin'
@@ -114,11 +116,13 @@ export default class AppSettingTab extends React.Component {
{userAlert.message}
</p>
) : null
let aceThemeList = ace.require("ace/ext/themelist")
let hljsThemeList = hljsTheme()
return (
<div className='AppSettingTab content'>
<div className='section'>
<div className='sectionTitle'>User's info</div>
<div className='sectionTitle'>User&apos;s info</div>
<div className='sectionInput'>
<label>User name</label>
<input valueLink={this.linkState('user.name')} type='text'/>
@@ -129,7 +133,7 @@ export default class AppSettingTab extends React.Component {
</div>
</div>
<div className='section'>
<div className='sectionTitle'>Text</div>
<div className='sectionTitle'>Editor</div>
<div className='sectionInput'>
<label>Editor Font Size</label>
<input valueLink={this.linkState('config.editor-font-size')} onKeyDown={e => this.handleConfigKeyDown(e)} type='text'/>
@@ -138,9 +142,9 @@ export default class AppSettingTab extends React.Component {
<label>Editor Font Family</label>
<input valueLink={this.linkState('config.editor-font-family')} onKeyDown={e => this.handleConfigKeyDown(e)} type='text'/>
</div>
<div className='sectionSelect'>
<div className='sectionMultiSelect'>
<label>Editor Indent Style</label>
<div className='sectionSelect-input'>
<div className='sectionMultiSelect-input'>
type
<select valueLink={this.linkState('config.editor-indent-type')}>
<option value='space'>Space</option>
@@ -154,6 +158,7 @@ export default class AppSettingTab extends React.Component {
</select>
</div>
</div>
<div className='sectionTitle'>Preview</div>
<div className='sectionInput'>
<label>Preview Font Size</label>
<input valueLink={this.linkState('config.preview-font-size')} onKeyDown={e => this.handleConfigKeyDown(e)} type='text'/>
@@ -162,8 +167,15 @@ export default class AppSettingTab extends React.Component {
<label>Preview Font Family</label>
<input valueLink={this.linkState('config.preview-font-family')} onKeyDown={e => this.handleConfigKeyDown(e)} type='text'/>
</div>
<div className='sectionSelect'>
<label>Switching Preview</label>
<select valueLink={this.linkState('config.switch-preview')}>
<option value='blur'>When Editor Blurred</option>
<option value='rightclick'>When Right Clicking</option>
</select>
</div>
{
true// !OSX
global.process.platform === 'win32'
? (
<div className='sectionCheck'>
<label><input onClick={e => this.handleDisableDirectWriteClick(e)} checked={this.state.config['disable-direct-write']} disabled={OSX} type='checkbox'/>Disable Direct Write<span className='sectionCheck-warn'>It will be applied after restarting</span></label>
@@ -171,7 +183,34 @@ export default class AppSettingTab extends React.Component {
)
: null
}
<div className='sectionTitle'>Theme</div>
<div className='sectionSelect'>
<label>UI Theme</label>
<select valueLink={this.linkState('config.theme-ui')}>
<option value='light'>Light</option>
<option value='dark'>Dark</option>
</select>
</div>
<div className='sectionSelect'>
<label>Code Theme</label>
<select valueLink={this.linkState('config.theme-code')}>
{
hljsThemeList.map(function(v, i){
return (<option value={v.name} key={v.name}>{v.caption}</option>)
})
}
</select>
</div>
<div className='sectionSelect'>
<label>Syntax Theme</label>
<select valueLink={this.linkState('config.theme-syntax')}>
{
aceThemeList.themes.map(function(v, i){
return (<option value={v.name} key={v.name}>{v.caption}</option>)
})
}
</select>
</div>
<div className='sectionConfirm'>
<button onClick={e => this.handleConfigSaveButtonClick(e)}>Save</button>
</div>

View File

@@ -1,122 +1,23 @@
import React from 'react'
import ReactDOM from 'react-dom'
import clientKey from 'browser/lib/clientKey'
import linkState from 'browser/lib/linkState'
import _ from 'lodash'
import { request, SERVER_URL } from 'browser/lib/api'
const FORM_MODE = 'FORM_MODE'
const DONE_MODE = 'DONE_MODE'
import ExternalLink from 'browser/components/ExternalLink'
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 = clientKey.get()
this.setState({
alert: {
type: 'info',
message: 'Sending...'
}
}, () => {
request.post(SERVER_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 className='ContactTab content'>
<div className='title'>Contact</div>
<p>
- Issues: <ExternalLink href='https://github.com/BoostIO/Boostnote/issues'>https://github.com/BoostIO/Boostnote/issues</ExternalLink>
</p>
</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>
)
}
}
}

View File

@@ -63,7 +63,7 @@ export default class FolderRow extends React.Component {
}
handleColorButtonClick (index) {
return e => {
return (e) => {
this.setState({
color: index,
isColorEditing: false
@@ -116,7 +116,7 @@ export default class FolderRow extends React.Component {
? 'active'
: null
return (
<button onClick={e => this.handleColorButtonClick(index)(e)} className={className} key={index}>
<button onClick={(e) => this.handleColorButtonClick(index)(e)} className={className} key={index}>
<FolderMark color={index}/>
</button>
)
@@ -125,7 +125,7 @@ export default class FolderRow extends React.Component {
return (
<div className='FolderRow edit'>
<div className='folderColor'>
<button onClick={e => this.handleColorSelectClick(e)} className='select'>
<button onClick={(e) => this.handleColorSelectClick(e)} className='select'>
<FolderMark color={this.state.color}/>
</button>
{this.state.isColorEditing
@@ -139,11 +139,11 @@ export default class FolderRow extends React.Component {
}
</div>
<div className='folderName'>
<input onKeyDown={e => this.handleNameInputKeyDown(e)} valueLink={this.linkState('name')} type='text'/>
<input onKeyDown={(e) => this.handleNameInputKeyDown(e)} valueLink={this.linkState('name')} type='text'/>
</div>
<div className='folderControl'>
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Save</button>
<button onClick={e => this.handleCancelButtonClick(e)}>Cancel</button>
<button onClick={(e) => this.handleSaveButtonClick(e)} className='primary'>Save</button>
<button onClick={(e) => this.handleCancelButtonClick(e)}>Cancel</button>
</div>
</div>
)
@@ -152,8 +152,8 @@ export default class FolderRow extends React.Component {
<div className='FolderRow delete'>
<div className='folderDeleteLabel'>Are you sure to delete <strong>{folder.name}</strong> folder?</div>
<div className='folderControl'>
<button onClick={e => this.handleDeleteConfirmButtonClick(e)} className='primary'>Sure</button>
<button onClick={e => this.handleCancelButtonClick(e)}>Cancel</button>
<button onClick={(e) => this.handleDeleteConfirmButtonClick(e)} className='primary'>Sure</button>
<button onClick={(e) => this.handleCancelButtonClick(e)}>Cancel</button>
</div>
</div>
)
@@ -162,14 +162,14 @@ export default class FolderRow extends React.Component {
return (
<div className='FolderRow'>
<div className='sortBtns'>
<button onClick={e => this.handleUpClick(e)}><i className='fa fa-sort-up fa-fw'/></button>
<button onClick={e => this.handleDownClick(e)}><i className='fa fa-sort-down fa-fw'/></button>
<button onClick={(e) => this.handleUpClick(e)}><i className='fa fa-sort-up fa-fw'/></button>
<button onClick={(e) => this.handleDownClick(e)}><i className='fa fa-sort-down fa-fw'/></button>
</div>
<div className='folderColor'><FolderMark color={folder.color}/></div>
<div className='folderName'>{folder.name}</div>
<div className='folderControl'>
<button onClick={e => this.handleEditButtonClick(e)}><i className='fa fa-fw fa-edit'/></button>
<button onClick={e => this.handleDeleteButtonClick(e)}><i className='fa fa-fw fa-close'/></button>
<button onClick={(e) => this.handleEditButtonClick(e)}><i className='fa fa-fw fa-edit'/></button>
<button onClick={(e) => this.handleDeleteButtonClick(e)}><i className='fa fa-fw fa-close'/></button>
</div>
</div>
)

View File

@@ -75,10 +75,10 @@ export default class FolderSettingTab extends React.Component {
{folderElements}
<div className='newFolder'>
<div className='folderName'>
<input onKeyDown={e => this.handleNewFolderNameKeyDown(e)} valueLink={this.linkState('name')} type='text' placeholder='New Folder'/>
<input onKeyDown={(e) => this.handleNewFolderNameKeyDown(e)} valueLink={this.linkState('name')} type='text' placeholder='New Folder'/>
</div>
<div className='folderControl'>
<button onClick={e => this.handleSaveButtonClick(e)} className='primary'>Add</button>
<button onClick={(e) => this.handleSaveButtonClick(e)} className='primary'>Add</button>
</div>
</div>
{alertElement}

View File

@@ -8,7 +8,6 @@ import ContactTab from './Preference/ContactTab'
import { closeModal } from 'browser/lib/modal'
const APP = 'APP'
const HELP = 'HELP'
const FOLDER = 'FOLDER'
const CONTACT = 'CONTACT'
@@ -64,8 +63,6 @@ class Preferences extends React.Component {
let { user, folders, dispatch } = this.props
switch (this.state.currentTab) {
case HELP:
return (<HelpTab/>)
case FOLDER:
return (
<FolderSettingTab

View File

@@ -33,10 +33,10 @@ export default class Tutorial extends React.Component {
return (
<div className='Tutorial modal'>
<button onClick={e => this.handlePriorSlideClick()} className={'priorBtn' + (this.state.slideIndex === 0 ? ' hide' : '')}>
<button onClick={(e) => this.handlePriorSlideClick()} className={'priorBtn' + (this.state.slideIndex === 0 ? ' hide' : '')}>
<i className='fa fa-fw fa-angle-left'/>
</button>
<button onClick={e => this.handleNextSlideClick()} className={'nextBtn' + (this.state.slideIndex === 4 ? ' hide' : '')}>
<button onClick={(e) => this.handleNextSlideClick()} className={'nextBtn' + (this.state.slideIndex === 4 ? ' hide' : '')}>
<i className='fa fa-fw fa-angle-right'/>
</button>
{content}
@@ -80,7 +80,7 @@ export default class Tutorial extends React.Component {
Boost supports code syntax highlighting.<br/>
There are more than 100 different type of language.
<div className='code'>
<CodeEditor readOnly article={{content:code, mode: 'jsx'}}/>
<CodeEditor readOnly article={{content: code, mode: 'jsx'}}/>
</div>
</div>
</div>)
@@ -101,7 +101,7 @@ export default class Tutorial extends React.Component {
return (<div className='slide slide4'>
<div className='title'>Are you ready?</div>
<div className='content'>
<button onClick={e => this.startButtonClick(e)}>Start<br/>Boost</button>
<button onClick={(e) => this.startButtonClick(e)}>Start<br/>Boost</button>
</div>
</div>)
default:

View File

@@ -74,7 +74,7 @@ function folders (state = initialFolders, action) {
if (newFolder.name == null || newFolder.name.length === 0) throw new Error('Folder name is required')
if (newFolder.name.match(/\//)) throw new Error('`/` is not available for folder name')
let conflictFolder = _.find(state, folder => folder.name.toLowerCase() === newFolder.name.toLowerCase())
let conflictFolder = _.find(state, (folder) => folder.name.toLowerCase() === newFolder.name.toLowerCase())
if (conflictFolder != null) throw new Error(`${conflictFolder.name} already exists!`)
state.push(newFolder)
@@ -96,7 +96,7 @@ function folders (state = initialFolders, action) {
if (targetFolder == null) throw new Error('Folder doesnt exist')
// Name conflict check
if (targetFolder.name !== folder.name) {
let conflictFolder = _.find(state, _folder => {
let conflictFolder = _.find(state, (_folder) => {
return folder.name.toLowerCase() === _folder.name.toLowerCase() && folder.key !== _folder.key
})
if (conflictFolder != null) throw new Error('Name conflicted')
@@ -114,7 +114,7 @@ function folders (state = initialFolders, action) {
if (state.length < 2) throw new Error('Folder must exist more than one')
let targetKey = action.data.key
let targetIndex = _.findIndex(state, folder => folder.key === targetKey)
let targetIndex = _.findIndex(state, (folder) => folder.key === targetKey)
if (targetIndex >= 0) {
state.splice(targetIndex, 1)
}
@@ -159,9 +159,9 @@ function articles (state = initialArticles, action) {
{
let modified = action.data.article
let targetKey = action.data.key
let originalIndex = _.findIndex(state.data, _article => targetKey === _article.key)
let originalIndex = _.findIndex(state.data, (_article) => targetKey === _article.key)
if (originalIndex === -1) return state
let modifiedIndex = _.findIndex(state.modified, _article => targetKey === _article.key)
let modifiedIndex = _.findIndex(state.modified, (_article) => targetKey === _article.key)
modified = compareArticle(state.data[originalIndex], modified)
if (modified == null) {

View File

@@ -3,6 +3,7 @@
@import '../mixins/*'
global-reset()
@import '../shared/*'
@import '../theme/*'
iptBgColor = #E6E6E6
iptFocusBorderColor = #369DCD

View File

@@ -25,7 +25,6 @@ infoButton()
padding 10px
background-color #E6E6E6
border-top 1px solid borderColor
border-left 1px solid borderColor
&.empty
.ArticleDetail-empty-box
line-height 72px
@@ -257,9 +256,10 @@ infoButton()
width 150px
max-height 150px
background-color white
z-index 5
z-index 50
border 1px solid borderColor
border-radius 5px
overflow-y auto
&>button
width 100%
display block

View File

@@ -16,7 +16,7 @@ articleItemColor = #777
.ArticleList-item
border solid 2px transparent
position relative
height 110px
min-height 110px
width 100%
cursor pointer
transition 0.1s
@@ -68,18 +68,27 @@ articleItemColor = #777
code
font-family Monaco, Menlo, 'Ubuntu Mono', Consolas, source-code-pro, monospace
.ArticleList-item-bottom
overflow-x auto
white-space nowrap
padding-top 6px
padding-bottom 5px
.tags
color articleItemColor
line-height 18px
word-wrap break-word
clearfix()
i.fa-tags
display inline
float left
padding 2px 2px 0 0
height 14px
line-height 13px
a
background-color brandColor
float left
color white
border-radius 2px
padding 1px 5px
margin 2px
height 14px
line-height 13px
font-size 10px
opacity 0.8
&:hover

View File

@@ -11,6 +11,7 @@ articleCount = #999
.userInfo
height 60px
display block
box-sizing content-box
border-bottom 1px solid borderColor
.userProfileName
color brandColor

View File

@@ -4,10 +4,11 @@
global-reset()
@import '../shared/*'
@import './ArticleNavigator'
@import './ArticleTopbar'
@import './ArticleTopBar'
@import './ArticleList'
@import './ArticleDetail'
@import './modal/*'
@import '../theme/*'
DEFAULT_FONTS = 'Lato', helvetica, arial, sans-serif
@@ -126,3 +127,28 @@ textarea.block-input
margin-left -107px
&:hover .tooltip
opacity 1
.OSSAnnounceModal
height 250
text-align center
.OSSAnnounceModal-title
font-size 32px
padding 45px 0
.OSSAnnounceModal-link
display block
font-size 20px
margin 25px 0 65px
.OSSAnnounceModal-closeBtn
display block
margin 0 auto
border none
border-radius 5px
width 150px
height 33px
background-color brandColor
color white
opacity 0.7
&:hover
opacity 1
background-color lighten(brandColor, 10%)

View File

@@ -72,7 +72,7 @@ iptFocusBorderColor = #369DCD
.confirmBtn
display block
position absolute
left 180px
left 205px
bottom 44px
width 240px
font-size 24px

View File

@@ -8,7 +8,7 @@ iptFocusBorderColor = #369DCD
border-radius 5px
overflow hidden
width 720px
height 450px
height 600px
&>.header
absolute top left right
height 50px
@@ -60,7 +60,7 @@ iptFocusBorderColor = #369DCD
left 180px
overflow-y auto
&>.section
padding 10px
padding 10px 20px
border-bottom 1px solid borderColor
overflow-y auto
&:nth-last-child(1)
@@ -102,7 +102,6 @@ iptFocusBorderColor = #369DCD
&:focus
border-color iptFocusBorderColor
&>.sectionSelect
margin-bottom 5px
clearfix()
height 33px
@@ -111,7 +110,28 @@ iptFocusBorderColor = #369DCD
padding-left 15px
float left
line-height 33px
.sectionSelect-input
select
float left
width 200px
height 25px
margin-top 4px
border-radius 5px
border 1px solid borderColor
padding 0 10px
font-size 14px
outline none
&:focus
border-color iptFocusBorderColor
&>.sectionMultiSelect
margin-bottom 5px
clearfix()
height 33px
label
width 150px
padding-left 15px
float left
line-height 33px
.sectionMultiSelect-input
float left
select
width 80px
@@ -157,69 +177,14 @@ iptFocusBorderColor = #369DCD
color errorTextColor
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%)
p
line-height 2
&.AppSettingTab
.description
marked()

View File

@@ -6,7 +6,7 @@ marked()
background-color alpha(red, 0.1)
color darken(red, 15%)
padding 5px
margin -5px
margin 5px 0
border-radius 5px
sup
position relative
@@ -26,6 +26,8 @@ marked()
margin -5px
transition .1s
display inline-block
img
vertical-align sub
&:hover
color lighten(brandColor, 5%)
text-decoration underline
@@ -48,12 +50,12 @@ marked()
*:not(a.lineAnchor) + h1, *:not(a.lineAnchor) + h2, *:not(a.lineAnchor) + h3, *:not(a.lineAnchor) + h4, *:not(a.lineAnchor) + h5, *:not(a.lineAnchor) + h6
margin-top 25px
h1
font-size 2em
font-size 1.8em
border-bottom solid 2px borderColor
line-height 2.333em
line-height 2em
h2
font-size 1.66em
line-height 2.07em
line-height 1.8em
h3
font-size 1.33em
line-height 1.6625em
@@ -78,7 +80,7 @@ marked()
font-weight bold
em, i
font-style italic
s
s, del, strike
text-decoration line-through
u
text-decoration underline
@@ -114,9 +116,7 @@ marked()
border solid 1px alpha(borderColor, 0.3)
border-radius 4px
font-size 0.9em
color black
text-decoration none
background-color #F6F6F6
margin-right 2px
*:not(a.lineAnchor) + code
margin-left 2px
@@ -126,14 +126,15 @@ marked()
border-radius 5px
overflow-x auto
margin 0 0 15px
background-color #F6F6F6
line-height 1.35em
&>code
margin 0
padding 0
border none
border-radius 0
color black
&>pre
border none
margin -5px
table
width 100%
margin 15px 0 25px

View File

@@ -0,0 +1,397 @@
@import '../vars'
themeDarkBackground = darken(#21252B, 10%)
themeDarkModal = darken(#21252B, 10%)
themeDarkList = #282C34
themeDarkPreview = #282C34
themeDarkSidebar = darken(#21252B, 10%)
themeDarkText = #DDDDDD
themeDarkBorder = lighten(themeDarkBackground, 20%)
themeDarkTopicColor = #369dcd
themeDarkTooltip = rgba(0, 0, 0, 0.7)
themeDarkFocusText = #FFFFFF
themeDarkFocusButton = lighten(themeDarkTopicColor, 30%)
themeDarkBoxShadow = alpha(lighten(themeDarkTopicColor, 10%), 0.4);
body[data-theme="dark"]
.Main
.ArticleNavigator .userInfo .settingBtn .tooltip,
.ArticleNavigator .ArticleNavigator-folders .ArticleNavigator-folders-header .addBtn .tooltip,
.ArticleTopBar>.ArticleTopBar-left>.ArticleTopBar-left-search .tooltip,
.ArticleTopBar>.ArticleTopBar-left .ArticleTopBar-left-control button.ArticleTopBar-left-control-new-post-button .tooltip
.ArticleTopBar>.ArticleTopBar-right>button .tooltip,
.ArticleTopBar>.ArticleTopBar-right>.ArticleTopBar-right-links-button-dropdown,
.ArticleDetail .ArticleDetail-info .ArticleDetail-info-control>button .tooltip,
.ArticleDetail .ArticleDetail-info .ArticleDetail-info-control .ShareButton-open-button .tooltip {
background-color themeDarkTooltip
}
.ArticleNavigator
border-color lighten(themeDarkBorder, 10%)
background-color themeDarkSidebar
.userInfo
border-color themeDarkBorder
.userName
color themeDarkText
.ArticleNavigator-folders
border-color lighten(themeDarkBorder, 10%)
background-color themeDarkSidebar
.ArticleNavigator-folders-header
border-color themeDarkBorder
.title
color themeDarkText
.folderList,
.folderList>button
color themeDarkText
.folderList>button
transition 0.1s
&:hover
background-color lighten(themeDarkSidebar, 10%)
&.active,
$:active
background-color darken(brandColor, 15%)
.userInfo .settingBtn,
.ArticleNavigator-folders .ArticleNavigator-folders-header .addBtn
transition 0.1s
color themeDarkText
border none
background-color lighten(themeDarkBackground, 10%)
.userInfo .settingBtn:hover,
.ArticleNavigator-folders .ArticleNavigator-folders-header .addBtn:hover
background-color themeDarkTopicColor
.userInfo .settingBtn:focus,
.ArticleNavigator-folders .ArticleNavigator-folders-header .addBtn:focus
background-color darken(themeDarkTopicColor, 20%)
.ArticleTopBar
color themeDarkText
background-color themeDarkBackground
.ArticleTopBar-left
.ArticleTopBar-left-search input
color themeDarkText
background-color lighten(themeDarkBackground, 10%)
.ArticleTopBar-left-control button.ArticleTopBar-left-control-new-post-button
color themeDarkText
background-color lighten(themeDarkBackground, 10%)
&:hover
color themeDarkText
background-color themeDarkTopicColor
&:focus
color themeDarkText
background-color darken(themeDarkTopicColor, 20%)
.ArticleTopBar-right
&>button
color themeDarkText
border none
background-color lighten(themeDarkBackground, 10%)
&:hover
color themeDarkText
background-color themeDarkTopicColor
&:focus
color themeDarkText
background-color darken(themeDarkTopicColor, 20%)
.ArticleList
color themeDarkText
border-color themeDarkBorder
background-color themeDarkList
.ArticleList-item
color themeDarkText
background-color themeDarkList
&:hover
background-color lighten(themeDarkList, 5%)
.divider
border-color themeDarkBorder
.ArticleDetail
color themeDarkText
border-color themeDarkBorder
background-color themeDarkBackground
.ArticleDetail-info
.ArticleDetail-info-folder
color themeDarkText
background-color lighten(themeDarkBackground, 10%)
.ArticleDetail-info-row2 .TagSelect .TagSelect-tags
border-color themeDarkBorder
background-color themeDarkBackground
input
color themeDarkText
.ArticleDetail-info-control
&>button,
& .ShareButton-open-button
transition 0.1s
color themeDarkText
border none
background-color lighten(themeDarkBackground, 10%)
&>button:hover,
& .ShareButton-open-button:hover
background-color themeDarkTopicColor
&>button:focus,
& .ShareButton-open-button:focus
background-color darken(themeDarkTopicColor, 20%)
& .ShareButton-dropdown
color themeDarkText
box-shadow 0px 0px 10px 1px themeDarkBoxShadow;
border 1px solid themeDarkBorder;
background-color themeDarkBackground
& .ShareButton-dropdown>button
color themeDarkText
&:hover
background-color darken(themeDarkTopicColor, 20%)
.ArticleDetail-panel
border-color themeDarkBackground
.ArticleDetail-panel-header,
.ArticleDetail-panel-header .ArticleDetail-panel-header-title input
color themeDarkText
border-color themeDarkBorder
background-color themeDarkPreview
.ArticleEditor
.CodeEditor
border-color themeDarkBorder
&>.ArticleDetail-panel-header .ArticleDetail-panel-header-mode
transition 0.1s
color themeDarkText
background-color lighten(themeDarkBackground, 10%)
input
color themeDarkText
&.idle
border-color themeDarkBorder
background-color themeDarkPreview
&.idle:hover
background-color themeDarkTopicColor
&.edit .ModeSelect-options
color themeDarkText
border-color themeDarkBackground
background-color themeDarkBackground
.ModeSelect-options-item
&:hover
color lighten(themeDarkText, 100%)
background-color darken(themeDarkTopicColor, 20%)
.ModalBase
.modal
color themeDarkText
background-color themeDarkModal
box-shadow 0px 0px 10px 1px themeDarkBoxShadow;
input
color themeDarkText
border-color lighten(themeDarkBackground, 10%)
background-color lighten(themeDarkBackground, 10%)
&:hover
border-color themeDarkBorder
&:focus
border-color themeDarkTopicColor
button
&:hover
background-color lighten(themeDarkBackground, 10%)
.CreateNewFolder.modal
.closeBtn
transition 0.1s
border-radius 24px
color themeDarkText
&:hover
background-color darken(#BF360C, 10%)
.confirmBtn
background-color darken(brandColor, 10%)
&:hover
background-color brandColor
.Preferences.modal
.sectionInput input,
.sectionSelect select
.sectionMultiSelect .sectionMultiSelect-input select
color themeDarkText
border-color lighten(themeDarkBackground, 10%)
background-color lighten(themeDarkBackground, 10%)
&:hover
border-color themeDarkBorder
&:focus
border-color themeDarkTopicColor
.header
border-color themeDarkBorder
background-color darken(themeDarkModal, 40%)
.nav
border-color themeDarkBorder
background-color darken(themeDarkModal, 20%)
&>button
&:hover
color themeDarkFocusText
background-color lighten(themeDarkModal, 10%)
&.active,
&:active
background-color darken(brandColor, 15%)
.section
border-color themeDarkBorder
&>.content
&.AppSettingTab
.description
code
color themeDarkText
border-color darken(themeDarkBorder, 10%)
background-color lighten(themeDarkPreview, 5%)
&.FolderSettingTab
.folderTable
&>div
border-color themeDarkBorder
&:last-child
border-color transparent
&>div.FolderRow
.sortBtns button
transition 0.1s
color themeDarkText
&:hover
color themeDarkFocusButton
.folderColor
&>button,
.options
color themeDarkText
border-color themeDarkBorder
&>button
border-color lighten(themeDarkBackground, 10%)
background-color lighten(themeDarkBackground, 10%)
&:hover
border-color themeDarkBorder
&:focus
border-color themeDarkTopicColor
.options
background-color themeDarkBackground
&>div.FolderRow .folderName input,
&>div.newFolder .folderName input
color themeDarkText
border-color lighten(themeDarkBackground, 10%)
background-color lighten(themeDarkBackground, 10%)
&:hover
border-color themeDarkBorder
&:focus
border-color themeDarkTopicColor
.folderControl
button
transition 0.1s
color themeDarkText
&:hover
color themeDarkFocusButton
.Finder
.FinderInput
color themeDarkText
border-color themeDarkBorder
background-color themeDarkBackground
input
color themeDarkText
border-color lighten(themeDarkBackground, 10%)
background-color lighten(themeDarkBackground, 10%)
&:focus
border-color themeDarkTopicColor
.FinderList
color themeDarkText
border-color themeDarkBorder
background-color themeDarkList
.divider
border-color themeDarkBorder
.FinderDetail
color themeDarkText
border-color themeDarkBorder
background-color themeDarkPreview
box-shadow 0px 0px 10px 0 darken(themeDarkBorder, 20%);
.header
border-color themeDarkBorder
.right
.clipboardBtn
transition 0.1s
&:hover
color themeDarkFocusButton
.tooltip
background-color themeDarkTooltip
.ArticleDetail-panel
border-radius 0
// Markdown Preview
.Finder .FinderDetail .content,
.ArticleDetail .ArticleDetail-panel .ArticleEditor
.MarkdownPreview
color themeDarkText
border-color themeDarkBorder
background-color themeDarkPreview
a:hover
background-color alpha(lighten(brandColor, 30%), 0.2) !important

35
contributing.md Normal file
View File

@@ -0,0 +1,35 @@
# Contributing to Boostnote
> English below.
## About Pull Request
### やり方
現状特に`dev`ブランチを用意しないつもりなので、最新VersionのブランチにPullrequestを送ってください。
### Pull requsetの著作権
Pull requestをすることはその変化分のコードの著作権をMAISIN&CO.に譲渡することに同意することになります。
アプリケーションのLicenseのをいつでも変える選択肢を残したいからです。
しかし、これはいずれかBoostnoteが有料の商用アプリになる可能性がある話ではありません。
もし、このアプリケーションで金を稼ごうとするならBoostnote専用のCloud storageの提供やMobile appとの連動、何か特殊なプレミアム機能の提供など形になると思います。
現在考えられているのは、GPL v3の場合、他のライセンスとの互換が不可能であるため、もしより自由なLicense(BSD, MIT)に変える時に改めて著作権者としてライセンスし直す選択肢を残したいぐらいのイメージです。
---
# Contributing to Boostnote(ENG)
## About Pull Request
### How to
Make a new PR to the branch named latest version. This is because there is no `dev` branch currently.
### Copyright of Pull Request
If you make a pull request, It means you agree to transfer the copyright of the code changes to MAISIN&CO.
It doesn't mean Boostnote will become a paid app. If we want to earn some money, We will try other way, which is some kind of cloud storage, Mobile app integration or some SPECIAL features.
Because GPL v3 is too strict to be compatible with any other License, We thought this is needed to replace the license with much freer one(like BSD, MIT) somewhen.

View File

@@ -2,6 +2,8 @@ const path = require('path')
const ChildProcess = require('child_process')
const packager = require('electron-packager')
const WIN = process.platform === 'win32'
module.exports = function (grunt) {
var auth_code
try {
@@ -29,10 +31,33 @@ module.exports = function (grunt) {
certificatePassword: WIN_CERT_PASSWORD,
noMsi: true
}
},
'electron-installer-debian': {
app: {
options: {
name: 'boostnote',
productName: 'Boostnote',
genericName: 'Boostnote',
productDescription: 'The opensource note app for developer.',
arch: 'amd64',
categories: [
'Development',
'Utility'
],
icon: path.join(__dirname, 'resources/app.png'),
bin: 'Boostnote'
},
src: path.join(__dirname, 'dist', 'Boostnote-linux-x64'),
dest: path.join(__dirname, 'dist')
}
}
}
grunt.initConfig(initConfig)
grunt.loadNpmTasks('grunt-electron-installer')
if (!WIN) {
grunt.loadNpmTasks('grunt-electron-installer-debian')
}
grunt.registerTask('compile', function () {
var done = this.async()
@@ -69,11 +94,11 @@ module.exports = function (grunt) {
version: grunt.config.get('pkg.config.electron-version'),
'app-version': grunt.config.get('pkg.version'),
'app-bundle-id': 'com.maisin.boost',
asar: true,
asar: false,
prune: true,
overwrite: true,
out: path.join(__dirname, 'dist'),
ignore: /submodules\/ace\/(?!src-min)|submodules\/ace\/(?=src-min-noconflict)|node_modules\/devicon\/icons|dist|^\/browser|^\/secret|\.babelrc|\.gitignore|^\/\.gitmodules|^\/gruntfile|^\/readme.md|^\/webpack|^\/appdmg\.json/
ignore: /submodules\/ace\/(?!src-min)|submodules\/ace\/(?=src-min-noconflict)|node_modules\/devicon\/icons|dist|^\/browser|^\/secret|\.babelrc|\.gitignore|^\/\.gitmodules|^\/gruntfile|^\/readme.md|^\/webpack|^\/appdmg\.json|^\/node_modules\/grunt/
}
switch (platform) {
case 'win':
@@ -115,6 +140,21 @@ module.exports = function (grunt) {
done()
})
break
case 'linux':
Object.assign(opts, {
platform: 'linux',
icon: path.join(__dirname, 'resources/app.icns'),
'app-category-type': 'public.app-category.developer-tools'
})
packager(opts, function (err, appPath) {
if (err) {
grunt.log.writeln(err)
done(err)
return
}
done()
})
break
}
})
@@ -180,10 +220,22 @@ module.exports = function (grunt) {
}
})
grunt.registerTask('build', function (platform) {
if (!platform) {
platform = process.platform === 'darwin' ? 'osx' : process.platform === 'win32' ? 'win' : null
function getTarget () {
switch (process.platform) {
case 'darwin':
return 'osx'
case 'win32':
return 'win'
case 'linux':
return 'linux'
default:
return process.platform
}
}
grunt.registerTask('build', function (platform) {
if (platform == null) platform = getTarget()
switch (platform) {
case 'win':
grunt.task.run(['compile', 'pack:win', 'create-windows-installer'])
@@ -191,13 +243,15 @@ module.exports = function (grunt) {
case 'osx':
grunt.task.run(['compile', 'pack:osx', 'codesign', 'create-osx-installer', 'zip:osx'])
break
case 'linux':
grunt.task.run(['compile', 'pack:linux', 'electron-installer-debian'])
break
}
})
grunt.registerTask('pre-build', function (platform) {
if (!platform) {
platform = process.platform === 'darwin' ? 'osx' : process.platform === 'win32' ? 'win' : null
}
if (platform == null) platform = getTarget()
switch (platform) {
case 'win':
grunt.task.run(['compile', 'pack:win'])

View File

@@ -11,7 +11,11 @@ const defaultConfig = {
'editor-indent-size': '4',
'preview-font-size': '14',
'preview-font-family': 'Lato',
'disable-direct-write': false
'switch-preview': 'blur',
'disable-direct-write': false,
'theme-ui': 'light',
'theme-code': 'xcode',
'theme-syntax': 'xcode'
}
const configFile = 'config.json'
@@ -75,4 +79,3 @@ app.on('ready', function () {
applyConfig()
})
})

View File

@@ -2,7 +2,7 @@ const electron = require('electron')
const BrowserWindow = electron.BrowserWindow
const OSX = process.platform === 'darwin'
const WIN = process.platform === 'win32'
// const WIN = process.platform === 'win32'
var edit = {
label: 'Edit',
@@ -75,16 +75,6 @@ var view = {
click: function () {
BrowserWindow.getFocusedWindow().reload()
}
// },
// {
// label: 'Toggle Developer Tools',
// accelerator: (function () {
// if (process.platform === 'darwin') return 'Alt+Command+I'
// else return 'Ctrl+Shift+I'
// })(),
// click: function (item, focusedWindow) {
// if (focusedWindow) BrowserWindow.getFocusedWindow().toggleDevTools()
// }
}
]
}

View File

@@ -79,12 +79,12 @@ var config = {
show: false,
frame: false,
resizable: false,
'zoom-factor': 1.0,
'web-preferences': {
'overlay-scrollbars': true,
'skip-taskbar': true
zoomFactor: 1.0,
webPreferences: {
blinkFeatures: 'OverlayScrollbars'
},
'standard-window': false
skipTaskbar: true,
standardWindow: false
}
if (process.platform === 'darwin') {

View File

@@ -9,7 +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/devicon/devicon.min.css">
<link rel="stylesheet" href="../node_modules/highlight.js/styles/xcode.css">
<link rel="stylesheet" href="../node_modules/highlight.js/styles/xcode.css" id="hljs-css">
<link rel="shortcut icon" href="favicon.ico">
<link rel="stylesheet" href="../resources/katex.min.css">
@@ -39,7 +39,7 @@
var scriptEl=document.createElement('script')
scriptEl.setAttribute("type","text/javascript")
scriptEl.setAttribute("src", scriptUrl)
document.getElementsByTagName("head")[0].appendChild(scriptEl)
document.body.appendChild(scriptEl)
</script>
</body>
</html>

View File

@@ -6,12 +6,13 @@ const globalShortcut = electron.globalShortcut
const jetpack = require('fs-jetpack')
const mainWindow = require('./main-window')
const nodeIpc = require('@rokt33r/node-ipc')
const _ = require('lodash')
const OSX = global.process.platform === 'darwin'
const defaultKeymap = {
toggleFinder: OSX ? 'Cmd + alt + s' : 'Super + alt + s',
toggleMain: OSX ? 'Cmd + alt + v' : 'Super + alt + v'
toggleFinder: OSX ? 'Cmd + Alt + S' : 'Super + Alt + S',
toggleMain: OSX ? 'Cmd + Alt + L' : 'Super + Alt + E'
}
const keymapFilename = 'keymap.json'
@@ -66,35 +67,43 @@ function toggleMain () {
mainWindow.minimize()
mainWindow.restore()
}
mainWindow.webContents.send('list-focus')
mainWindow.webContents.send('top-focus-search')
}
}
// Init
global.keymap = Object.assign({}, defaultKeymap, getKeymap())
function registerKey (name, callback, broadcast) {
if (broadcast == null) broadcast = true
try {
function registerKey (name, callback) {
if (_.isString(global.keymap[name]) && global.keymap[name].trim().length > 0) {
globalShortcut.register(global.keymap[name], callback)
if (broadcast) {
mainWindow.webContents.send('APP_SETTING_DONE', {})
}
} catch (err) {
console.log(err)
if (broadcast) {
mainWindow.webContents.send('APP_SETTING_ERROR', {
message: 'Failed to apply hotkey: Invalid format'
})
}
}
}
function registerAllKeys (broadcast) {
if (broadcast == null) broadcast = true
registerKey('toggleFinder', toggleFinder, broadcast)
registerKey('toggleMain', toggleMain, broadcast)
var errors = []
try {
registerKey('toggleFinder', toggleFinder)
} catch (err) {
errors.push('toggleFinder')
}
try {
registerKey('toggleMain', toggleMain)
} catch (err) {
errors.push('toggleMain')
}
if (broadcast) {
if (errors.length === 0) {
mainWindow.webContents.send('APP_SETTING_DONE', {})
} else {
mainWindow.webContents.send('APP_SETTING_ERROR', {
message: 'Failed to apply hotkey: ' + errors.join(' ')
})
}
}
}
registerAllKeys(false)
@@ -105,4 +114,3 @@ ipc.on('hotkeyUpdated', function (event, newKeymap) {
globalShortcut.unregisterAll()
registerAllKeys()
})

View File

@@ -16,14 +16,11 @@ var finderProcess = null
var finderWindow = null
var update = null
// app.on('window-all-closed', function () {
// if (process.platform !== 'darwin') app.quit()
// })
const appRootPath = path.join(process.execPath, '../..')
const updateDotExePath = path.join(appRootPath, 'Update.exe')
const exeName = path.basename(process.execPath)
// For windows app
function spawnUpdate (args, cb) {
var stdout = ''
var updateProcess = null
@@ -128,10 +125,13 @@ const updater = new GhReleases(ghReleasesOpts)
// Check for updates
// `status` returns true if there is a new update available
function checkUpdate () {
if (process.platform === 'linux') {
return true
}
updater.check((err, status) => {
if (err) {
console.error(err)
if (!versionNotified) notify('Updater error!', message)
var isLatest = err.message === 'There is no newer version.'
if (!isLatest && !versionNotified) notify('Updater error!', err.message)
}
if (!err) {
if (status) {
@@ -159,15 +159,6 @@ nodeIpc.config.id = 'node'
nodeIpc.config.retry = 1500
nodeIpc.config.silent = true
function spawnFinder() {
if (process.platform === 'darwin') {
var finderArgv = [path.join(__dirname, 'finder-app.js'), '--finder']
if (_.find(process.argv, a => a === '--hot')) finderArgv.push('--hot')
finderProcess = ChildProcess
.execFile(process.execPath, finderArgv)
}
}
nodeIpc.serve(
path.join(app.getPath('userData'), 'boost.service'),
function () {
@@ -184,7 +175,7 @@ nodeIpc.serve(
'message',
function (data, socket) {
console.log('>>', data)
format(data)
handleIpcEvent(data)
}
)
nodeIpc.server.on(
@@ -196,14 +187,18 @@ nodeIpc.serve(
}
)
function format (payload) {
function handleIpcEvent (payload) {
switch (payload.type) {
case 'show-main-window':
if (process.platform === 'darwin') {
switch (process.platform) {
case 'darwin':
mainWindow.show()
} else {
case 'win32':
mainWindow.minimize()
mainWindow.restore()
case 'linux':
// Do nothing
// due to bug of `app.focus()` some desktop Env
}
break
case 'copy-finder':
@@ -215,6 +210,15 @@ function format (payload) {
}
}
function spawnFinder() {
if (process.platform === 'darwin') {
var finderArgv = [path.join(__dirname, 'finder-app.js'), '--finder']
if (_.find(process.argv, a => a === '--hot')) finderArgv.push('--hot')
finderProcess = ChildProcess
.execFile(process.execPath, finderArgv)
}
}
function quitApp () {
appQuit = true
if (finderProcess) finderProcess.kill()
@@ -223,7 +227,6 @@ function quitApp () {
app.on('ready', function () {
app.on('before-quit', function () {
console.log('before quite')
appQuit = true
if (finderProcess) finderProcess.kill()
})
@@ -244,7 +247,7 @@ app.on('ready', function () {
})
}
var menu = Menu.buildFromTemplate(template)
if (process.platform === 'darwin') {
if (process.platform === 'darwin' || process.platform === 'linux') {
Menu.setApplicationMenu(menu)
}
@@ -266,25 +269,26 @@ app.on('ready', function () {
checkUpdate()
mainWindow = require('./main-window')
if (process.platform === 'win32') {
if (process.platform === 'win32' || process.platform === 'linux') {
mainWindow.setMenu(menu)
}
mainWindow.on('close', function (e) {
if (appQuit) return true
e.preventDefault()
mainWindow.hide()
app.quit()
})
if (finderProcess == null && process.platform === 'darwin') {
switch (process.platform) {
case 'darwin':
spawnFinder()
} else {
break
case 'win32':
finderWindow = require('./finder-window')
finderWindow.on('close', function (e) {
if (appQuit) return true
e.preventDefault()
finderWindow.hide()
})
break
case 'linux':
// Do nothing.
}
nodeIpc.server.start(function (err) {

View File

@@ -4,7 +4,8 @@ const shell = electron.shell
const mainWindow = require('./main-window')
const OSX = process.platform === 'darwin'
const WIN = process.platform === 'win32'
// const WIN = process.platform === 'win32'
const LINUX = process.platform === 'linux'
var boost = {
label: 'Boostnote',
@@ -58,23 +59,6 @@ var file = {
mainWindow.webContents.send('nav-new-folder')
}
},
// {
// type: 'separator'
// },
// {
// label: 'Save Post',
// accelerator: OSX ? 'Command + S' : 'Control + S',
// click: function () {
// mainWindow.webContents.send('detail-save')
// }
// },
// {
// label: 'Save All Posts',
// accelerator: OSX ? 'Command + Shift + S' : 'Control + Shift + S',
// click: function () {
// mainWindow.webContents.send('top-save-all')
// }
// },
{
type: 'separator'
},
@@ -88,6 +72,19 @@ var file = {
]
}
if (LINUX) {
file.submenu.push({
type: 'separator'
})
file.submenu.push({
label: 'Quit Boostnote',
accelerator: 'Control + Q',
click: function () {
mainWindow.close()
}
})
}
var edit = {
label: 'Edit',
submenu: [
@@ -149,16 +146,6 @@ var view = {
click: function () {
BrowserWindow.getFocusedWindow().reload()
}
// },
// {
// label: 'Toggle Developer Tools',
// accelerator: (function () {
// if (process.platform === 'darwin') return 'Alt+Command+I'
// else return 'Ctrl+Shift+I'
// })(),
// click: function (item, focusedWindow) {
// if (focusedWindow) BrowserWindow.getFocusedWindow().toggleDevTools()
// }
}
]
}
@@ -204,11 +191,13 @@ var help = {
},
{
label: 'Changelog',
click: function () { shell.openExternal('https://github.com/BoostIO/boost-releases/blob/master/changelog.md') }
click: function () { shell.openExternal('https://github.com/BoostIO/boost-releases') }
}
]
}
module.exports = process.platform === 'darwin'
? [boost, file, edit, view, window, help]
: process.platform === 'win32'
? [file, view, help]
: [file, view, help]

View File

@@ -6,11 +6,10 @@ const path = require('path')
var mainWindow = new BrowserWindow({
width: 1080,
height: 720,
'zoom-factor': 1.0,
'web-preferences': {
'overlay-scrollbars': true
},
'standard-window': false
zoomFactor: 1.0,
webPreferences: {
blinkFeatures: 'OverlayScrollbars'
}
})
const url = path.resolve(__dirname, './main.html')

View File

@@ -6,7 +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/devicon/devicon.min.css">
<link rel="stylesheet" href="../node_modules/highlight.js/styles/xcode.css">
<link rel="stylesheet" href="../node_modules/highlight.js/styles/xcode.css" id="hljs-css">
<link rel="shortcut icon" href="../resources/favicon.ico">
<title>Boostnote</title>
<link rel="stylesheet" href="../resources/katex.min.css">
@@ -56,6 +56,7 @@
<div id="content"></div>
<script src="../submodules/ace/src-min/ace.js"></script>
<script src="../submodules/ace/src-min/ext-themelist.js"></script>
<script src="../resources/katex.min.js"></script>
<script type='text/javascript'>
const electron = require('electron')
@@ -68,7 +69,7 @@
var scriptEl = document.createElement('script')
scriptEl.setAttribute("type","text/javascript")
scriptEl.setAttribute("src", scriptUrl)
document.getElementsByTagName("head")[0].appendChild(scriptEl)
document.body.appendChild(scriptEl)
</script>
</body>
</html>

View File

@@ -1,6 +1,6 @@
{
"name": "boost",
"version": "0.5.1",
"version": "0.5.10",
"description": "Boostnote",
"main": "index.js",
"scripts": {
@@ -9,11 +9,11 @@
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js"
},
"config": {
"electron-version": "0.35.4"
"electron-version": "0.36.11"
},
"repository": {
"type": "git",
"url": "git+https://github.com/Rokt33r/codexen-app.git"
"url": "git+https://github.com/BoostIO/Boostnote.git"
},
"keywords": [
"boostnote",
@@ -24,23 +24,28 @@
"storage",
"electron"
],
"author": "Dick Choi <fluke8259@gmail.com> (http://kazup.co)",
"author": "Dick Choi <fluke8259@gmail.com> (https://github.com/Rokt33r)",
"contributors": [
"dojineko (https://github.com/dojineko)",
"Romain Bazile (https://github.com/gromain)"
],
"bugs": {
"url": "https://github.com/Rokt33r/codexen-app/issues"
"url": "https://github.com/BoostIO/Boostnote/issues"
},
"homepage": "https://github.com/Rokt33r/codexen-app#readme",
"homepage": "https://b00st.io",
"dependencies": {
"@rokt33r/markdown-it-math": "^4.0.1",
"@rokt33r/node-ipc": "^5.0.4",
"@rokt33r/sanitize-html": "^1.11.2",
"devicon": "^2.0.0",
"electron-gh-releases": "^2.0.2",
"font-awesome": "^4.3.0",
"fs-jetpack": "^0.7.0",
"highlight.js": "^8.9.1",
"highlight.js": "^9.3.0",
"lodash": "^3.10.1",
"markdown-it": "^4.4.0",
"markdown-it-emoji": "^1.1.0",
"markdown-it-math": "^3.0.2",
"markdown-it": "^6.0.1",
"markdown-it-checkbox": "^1.1.0",
"markdown-it-emoji": "^1.1.1",
"md5": "^2.0.0",
"moment": "^2.10.3",
"superagent": "^1.2.0",
@@ -54,8 +59,8 @@
"babel-preset-react": "^6.3.13",
"babel-preset-react-hmre": "^1.0.1",
"css-loader": "^0.19.0",
"electron-packager": "^5.1.0",
"electron-prebuilt": "^0.35.1",
"electron-packager": "^6.0.0",
"electron-prebuilt": "^0.36.11",
"electron-release": "^2.2.0",
"grunt": "^0.4.5",
"grunt-electron-installer": "^1.2.0",
@@ -65,16 +70,21 @@
"react-dom": "^0.14.3",
"react-redux": "^4.0.6",
"redux": "^3.0.5",
"standard": "^5.3.1",
"standard": "^6.0.8",
"style-loader": "^0.12.4",
"stylus": "^0.52.4",
"stylus-loader": "^1.3.1",
"webpack": "^1.12.2",
"webpack-dev-server": "^1.12.0"
},
"optionalDependencies": {},
"optionalDependencies": {
"grunt-electron-installer-debian": "^0.2.0"
},
"optional": false,
"standard": {
"ignore": [],
"ignore": [
"submodules"
],
"globals": [
"localStorage"
]

View File

@@ -1,8 +1,42 @@
# Boostnote
Hack your memory
Simple note app
## Develope
## Progress Kanban
https://trello.com/b/wJlinZJx/boostnote-todo-list
This is a public Kanban board. Also everyone can comment here.
If you want to join us, ask me to add you.
## System requirement
This app is built on Electron.
You can check it from [here](https://github.com/electron/electron/blob/master/docs/tutorial/supported-platforms.md).
Currently, I'm testing this app on Windows 10(64bit), OS X El Capitan, Ubuntu Linux, Arch Linux.
## About note storage
Currently, Boostnote stores data to a single json file.
You can find it from the path below.
OS X
```
/Users/$USER_NAME$/Library/Application Support/boost/local.json
```
Windows
```
C:\Users\$USER_NAME$\AppData\Roaming\boost\local.json
```
On v0.6.0, You will be able to select any folder in your file system.
## Develop
1. turn on HMR server
@@ -18,8 +52,12 @@ npm run hot
> `npm start` is using compiled scripts. see [Build](#Build) to compile scripts.
## Build
> '3. Codesign' and '4. Create' installer are needed to deploy this app.
> You can skip these steps.
1. Compile scripts
compile all browser stuff(Javascript, Stylus).
@@ -78,15 +116,23 @@ grunt zip:osx
- Webpack
... check [`package.json`](./package.json)
## Codestyle
[![js-standard-style](https://cdn.rawgit.com/feross/standard/master/badge.svg)](https://github.com/feross/standard)
## Author
[Rokt33r(Dick Choi)](https://github.com/rokt33r)
[Rokt33r(Dick Choi of MAISIN&CO.)](https://github.com/rokt33r)
## License
## Contributors
[dojineko](https://github.com/dojineko)
[Romain Bazile](https://github.com/gromain)
## Copyright & License
Copyright (C) 2016 MAISIN&CO.
[Check here](./LICENSE).

View File

@@ -31,8 +31,9 @@ var config = {
'highlight.js',
'markdown-it-emoji',
'fs-jetpack',
'markdown-it-math',
'@rokt33r/sanitize-html'
'@rokt33r/markdown-it-math',
'@rokt33r/sanitize-html',
'markdown-it-checkbox'
]
}

View File

@@ -1,5 +1,4 @@
const skeleton = require('./webpack-skeleton')
const webpack = require('webpack')
const path = require('path')
var config = Object.assign({}, skeleton, {