mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 10:16:26 +00:00
Compare commits
63 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
86cc9fb7d8 | ||
|
|
f98efe0b97 | ||
|
|
6c5345df64 | ||
|
|
2d97661d28 | ||
|
|
3efe0c1ce2 | ||
|
|
6099c91216 | ||
|
|
934e4d9607 | ||
|
|
1198f6112e | ||
|
|
777f7f9305 | ||
|
|
43fb37ab1d | ||
|
|
06734ec886 | ||
|
|
0b8ae93727 | ||
|
|
24cea97e08 | ||
|
|
18536e5db0 | ||
|
|
8c236cb5cb | ||
|
|
797c8ad7fa | ||
|
|
ba8d2dcb8b | ||
|
|
78a095d958 | ||
|
|
627172f6df | ||
|
|
a39f25961c | ||
|
|
e738ae5c8c | ||
|
|
749e85e8e6 | ||
|
|
cfa251b158 | ||
|
|
1ca38b8741 | ||
|
|
d7bc5a7088 | ||
|
|
3b9a2c3ee1 | ||
|
|
260ad77d39 | ||
|
|
5c508a0cd9 | ||
|
|
fd3d1607a4 | ||
|
|
abbc0fbcf1 | ||
|
|
00be41608d | ||
|
|
499c3f2e13 | ||
|
|
627845f6e4 | ||
|
|
07eea76057 | ||
|
|
fecc4e9b79 | ||
|
|
58e9302f15 | ||
|
|
86f649fab1 | ||
|
|
9ac0becfb2 | ||
|
|
eda547b868 | ||
|
|
f75e872415 | ||
|
|
aef0712165 | ||
|
|
bed4b7fd27 | ||
|
|
b53ff5daf3 | ||
|
|
bb0872b4fc | ||
|
|
b65101f4be | ||
|
|
593d242a4c | ||
|
|
db7f339c34 | ||
|
|
9f3575a874 | ||
|
|
1c9c59c512 | ||
|
|
127202b831 | ||
|
|
4f8a04ed21 | ||
|
|
63b2e0560b | ||
|
|
07291d71f2 | ||
|
|
d1ca1ec4d9 | ||
|
|
6907cf9972 | ||
|
|
d4f8d1498d | ||
|
|
0952e4a664 | ||
|
|
6a4e8c95ea | ||
|
|
983bfb7adf | ||
|
|
d7aaf5e210 | ||
|
|
50281132ad | ||
|
|
6a2b22015e | ||
|
|
2f90890f50 |
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,4 +1,7 @@
|
||||
.DS_Store
|
||||
.env
|
||||
Desktop.ini
|
||||
Thumbs.db
|
||||
node_modules/*
|
||||
!node_modules/boost
|
||||
/dist
|
||||
|
||||
18
LICENSE
18
LICENSE
@@ -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/>.
|
||||
|
||||
@@ -40,11 +40,22 @@ export default class CodeEditor extends React.Component {
|
||||
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()
|
||||
@@ -85,7 +96,8 @@ 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']
|
||||
}
|
||||
|
||||
this.silentChange = false
|
||||
@@ -103,7 +115,7 @@ 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)
|
||||
@@ -191,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)
|
||||
})
|
||||
|
||||
@@ -20,6 +20,7 @@ const sanitizeOpts = {
|
||||
allowedClasses: {
|
||||
'a': ['lineAnchor'],
|
||||
'div': ['math'],
|
||||
'pre': ['hljs'],
|
||||
'span': ['math', 'hljs-*'],
|
||||
'code': ['language-*']
|
||||
},
|
||||
|
||||
@@ -9,11 +9,27 @@ 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, 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) {
|
||||
@@ -29,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)
|
||||
}
|
||||
@@ -96,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()
|
||||
}
|
||||
|
||||
@@ -13,7 +13,10 @@ const defaultConfig = {
|
||||
'preview-font-size': '14',
|
||||
'preview-font-family': 'Lato',
|
||||
'switch-preview': 'blur',
|
||||
'disable-direct-write': false
|
||||
'disable-direct-write': false,
|
||||
'theme-ui': 'light',
|
||||
'theme-code': 'xcode',
|
||||
'theme-syntax': 'xcode'
|
||||
}
|
||||
|
||||
export default function fetchConfig () {
|
||||
|
||||
78
browser/lib/hljsThemes.js
Normal file
78
browser/lib/hljsThemes.js
Normal 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
|
||||
}
|
||||
@@ -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,10 +11,14 @@ 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.replace(/\&/g, '&').replace(/\</g, '<').replace(/\>/g, '>').replace(/\"/g, '"')
|
||||
return '<pre class="hljs"><code>' +
|
||||
str.replace(/\&/g, '&').replace(/\</g, '<').replace(/\>/g, '>').replace(/\"/g, '"') +
|
||||
'</code></pre>'
|
||||
}
|
||||
})
|
||||
md.use(emoji, {
|
||||
|
||||
@@ -125,6 +125,12 @@ export default class ArticleEditor extends React.Component {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -144,6 +150,12 @@ export default class ArticleEditor extends React.Component {
|
||||
}
|
||||
|
||||
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) {
|
||||
@@ -153,6 +165,12 @@ export default class ArticleEditor extends React.Component {
|
||||
}
|
||||
|
||||
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) {
|
||||
|
||||
@@ -15,6 +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'
|
||||
|
||||
let config = fetchConfig()
|
||||
ipc.on('config-apply', function (e, newConfig) {
|
||||
config = newConfig
|
||||
})
|
||||
|
||||
const BRAND_COLOR = '#18AF90'
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
@@ -83,10 +89,12 @@ export default class ArticleDetail extends React.Component {
|
||||
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']
|
||||
}
|
||||
}
|
||||
|
||||
@@ -101,6 +109,7 @@ export default class ArticleDetail extends React.Component {
|
||||
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 () {
|
||||
@@ -123,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'>
|
||||
@@ -309,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
|
||||
|
||||
@@ -231,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>
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -5,13 +5,30 @@ 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) {
|
||||
@@ -25,6 +42,15 @@ 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')
|
||||
@@ -59,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))
|
||||
}
|
||||
})
|
||||
|
||||
29
browser/main/modal/OSSAnnounceModal.js
Normal file
29
browser/main/modal/OSSAnnounceModal.js
Normal 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
|
||||
}
|
||||
@@ -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'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'/>
|
||||
@@ -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'/>
|
||||
@@ -178,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>
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
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>
|
||||
)
|
||||
}
|
||||
return (
|
||||
<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>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
@import '../mixins/*'
|
||||
global-reset()
|
||||
@import '../shared/*'
|
||||
@import '../theme/*'
|
||||
|
||||
iptBgColor = #E6E6E6
|
||||
iptFocusBorderColor = #369DCD
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
height 14px
|
||||
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
|
||||
|
||||
@@ -11,6 +11,7 @@ articleCount = #999
|
||||
.userInfo
|
||||
height 60px
|
||||
display block
|
||||
box-sizing content-box
|
||||
border-bottom 1px solid borderColor
|
||||
.userProfileName
|
||||
color brandColor
|
||||
|
||||
@@ -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%)
|
||||
|
||||
@@ -72,7 +72,7 @@ iptFocusBorderColor = #369DCD
|
||||
.confirmBtn
|
||||
display block
|
||||
position absolute
|
||||
left 180px
|
||||
left 205px
|
||||
bottom 44px
|
||||
width 240px
|
||||
font-size 24px
|
||||
|
||||
@@ -8,7 +8,7 @@ iptFocusBorderColor = #369DCD
|
||||
border-radius 5px
|
||||
overflow hidden
|
||||
width 720px
|
||||
height 450px
|
||||
height 600px
|
||||
&>.header
|
||||
absolute top left right
|
||||
height 50px
|
||||
@@ -177,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%)
|
||||
|
||||
padding 10px
|
||||
.title
|
||||
font-size 18px
|
||||
color brandColor
|
||||
margin-top 10px
|
||||
margin-bottom 10px
|
||||
p
|
||||
line-height 2
|
||||
&.AppSettingTab
|
||||
.description
|
||||
marked()
|
||||
|
||||
@@ -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
|
||||
@@ -116,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
|
||||
@@ -128,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
|
||||
|
||||
397
browser/styles/theme/dark.styl
Normal file
397
browser/styles/theme/dark.styl
Normal 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
35
contributing.md
Normal 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.
|
||||
70
gruntfile.js
70
gruntfile.js
@@ -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'])
|
||||
|
||||
@@ -12,7 +12,10 @@ const defaultConfig = {
|
||||
'preview-font-size': '14',
|
||||
'preview-font-family': 'Lato',
|
||||
'switch-preview': 'blur',
|
||||
'disable-direct-write': false
|
||||
'disable-direct-write': false,
|
||||
'theme-ui': 'light',
|
||||
'theme-code': 'xcode',
|
||||
'theme-syntax': 'xcode'
|
||||
}
|
||||
const configFile = 'config.json'
|
||||
|
||||
@@ -76,4 +79,3 @@ app.on('ready', function () {
|
||||
applyConfig()
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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') {
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -67,7 +67,7 @@ function toggleMain () {
|
||||
mainWindow.minimize()
|
||||
mainWindow.restore()
|
||||
}
|
||||
mainWindow.webContents.send('list-focus')
|
||||
mainWindow.webContents.send('top-focus-search')
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,4 +114,3 @@ ipc.on('hotkeyUpdated', function (event, newKeymap) {
|
||||
globalShortcut.unregisterAll()
|
||||
registerAllKeys()
|
||||
})
|
||||
|
||||
|
||||
@@ -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') {
|
||||
mainWindow.show()
|
||||
} else {
|
||||
mainWindow.minimize()
|
||||
mainWindow.restore()
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
mainWindow.show()
|
||||
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') {
|
||||
spawnFinder()
|
||||
} else {
|
||||
finderWindow = require('./finder-window')
|
||||
|
||||
finderWindow.on('close', function (e) {
|
||||
if (appQuit) return true
|
||||
e.preventDefault()
|
||||
finderWindow.hide()
|
||||
})
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
spawnFinder()
|
||||
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) {
|
||||
|
||||
@@ -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: [
|
||||
@@ -194,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]
|
||||
|
||||
@@ -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')
|
||||
|
||||
@@ -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>
|
||||
|
||||
37
package.json
37
package.json
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "boost",
|
||||
"version": "0.5.4",
|
||||
"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,24 +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": "^6.0.1",
|
||||
"markdown-it-checkbox": "^1.1.0",
|
||||
"markdown-it-emoji": "^1.1.0",
|
||||
"markdown-it-math": "^3.0.2",
|
||||
"markdown-it-emoji": "^1.1.1",
|
||||
"md5": "^2.0.0",
|
||||
"moment": "^2.10.3",
|
||||
"superagent": "^1.2.0",
|
||||
@@ -55,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",
|
||||
@@ -66,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": {
|
||||
"grunt-electron-installer-debian": "^0.2.0"
|
||||
},
|
||||
"optional": false,
|
||||
"standard": {
|
||||
"ignore": [],
|
||||
"ignore": [
|
||||
"submodules"
|
||||
],
|
||||
"globals": [
|
||||
"localStorage"
|
||||
]
|
||||
|
||||
54
readme.md
54
readme.md
@@ -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
|
||||
|
||||
[](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).
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ var config = {
|
||||
'highlight.js',
|
||||
'markdown-it-emoji',
|
||||
'fs-jetpack',
|
||||
'markdown-it-math',
|
||||
'@rokt33r/markdown-it-math',
|
||||
'@rokt33r/sanitize-html',
|
||||
'markdown-it-checkbox'
|
||||
]
|
||||
|
||||
Reference in New Issue
Block a user