1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-15 02:36:36 +00:00

Compare commits

..

109 Commits

Author SHA1 Message Date
Kohei TAKATA
e1a75a13e9 Merge pull request #891 from BoostIO/v0.8.15
v0.8.15
2017-09-23 17:02:56 +09:00
Kazu Yokomizo
ee6f4de183 v0.8.15 2017-09-23 14:41:13 +09:00
Kazu Yokomizo
475885b3ef Merge pull request #893 from BoostIO/downgrade_striptags_version
Downgrade striptags version
2017-09-23 14:35:54 +09:00
Kohei TAKATA
2d2b2d4c6c Downgrade striptags version 2017-09-23 14:20:53 +09:00
SuenagaRyota
4d00454539 Merge pull request #892 from asmsuechan/fix-typo
Fix typo addNotes to addNotesFromFiles
2017-09-23 12:34:15 +09:00
asmsuechan
bf590b5614 Fix typo addNotes to addNotesFromFiles 2017-09-23 12:29:08 +09:00
Kazu Yokomizo
3ef33c065c Merge pull request #793 from asmsuechan/add-drop-on-notelist
Add file drop on NoteList
2017-09-23 12:09:55 +09:00
Kazu Yokomizo
8e89fb8b92 Merge pull request #890 from asmsuechan/iss-888
iss #888 Fix letter count
2017-09-23 11:43:09 +09:00
asmsuechan
8e81cfcf89 iss #888 Fix letter count 2017-09-23 11:40:26 +09:00
Kazu Yokomizo
515736262d Merge pull request #889 from asmsuechan/cloud-sync-comment
Add link for cloud integration
2017-09-23 11:38:01 +09:00
Kazu Yokomizo
bd266dc602 Merge pull request #885 from asmsuechan/exit-by-comma-q-in-vim-mode
iss #832 Make :q work in vim mode
2017-09-23 11:34:01 +09:00
asmsuechan
9b3306157c Add link for cloud integration 2017-09-23 11:15:16 +09:00
asmsuechan
f8e6a939ca Fix comment 2017-09-23 10:20:48 +09:00
Kazu Yokomizo
8c48ee6fc1 Merge pull request #887 from BoostIO/fix-layout
Fix layout
2017-09-23 01:38:28 +09:00
Kazu Yokomizo
5e476054d7 Fix layout at NewNoteModal 2017-09-23 01:34:51 +09:00
Kazu Yokomizo
2fc8547384 Fix layout at CreateFolderModal 2017-09-23 01:20:39 +09:00
asmsuechan
2af2d71540 Rename addNotes to addNotesFromFiles 2017-09-23 00:28:55 +09:00
asmsuechan
6aaf9d9eb2 Change disable drop on trash 2017-09-23 00:28:55 +09:00
asmsuechan
42a9caf5a3 Add file drop on NoteList 2017-09-23 00:28:52 +09:00
asmsuechan
e6c1d7a383 iss #832 Make :qw work in vim mode 2017-09-23 00:21:20 +09:00
asmsuechan
02100bbc0a iss #832 Make :q! and :qw work in vim mode 2017-09-23 00:16:51 +09:00
Kazu Yokomizo
ce7c5f5d40 Merge pull request #884 from BoostIO/fix-layout-at-bottom
Fix layout at bottom
2017-09-23 00:07:14 +09:00
Kazu Yokomizo
69f1ad6eb3 Sorry CI 2017-09-23 00:00:27 +09:00
Kazu Yokomizo
8320fb5024 Fix layout at bottom 2017-09-22 23:57:43 +09:00
asmsuechan
4b79bca6bf iss #832 Make :q work in vim mode 2017-09-22 23:57:14 +09:00
Kazu Yokomizo
4a5fd41249 Fix layout at description in SnippetNoteDetail 2017-09-22 23:48:41 +09:00
Kazu Yokomizo
4e90a93b30 Fix layout at NoteDetail 2017-09-22 23:46:41 +09:00
Kazu Yokomizo
9861fbf7c8 Fix layout at RealtimeNotification 2017-09-22 22:56:32 +09:00
Kohei TAKATA
c762b9ae00 Merge pull request #877 from asmsuechan/add-realtime-info
Add RealtimeNotification
2017-09-22 20:26:20 +09:00
Kazu Yokomizo
cc667a6edf Merge pull request #882 from BoostIO/fix-layout
Fix layout
2017-09-22 16:20:05 +09:00
Kazu Yokomizo
419c57ed3f Fix CI error 2017-09-22 16:14:06 +09:00
Kazu Yokomizo
601f0b0de8 Fix layout at narrow the width of description in SnippetNoteDetail 2017-09-22 16:06:40 +09:00
Kazu Yokomizo
7b1c6c10b7 Change expand icon at NoteDetail 2017-09-22 15:56:49 +09:00
Kazu Yokomizo
5a85c257cf Fix layout at SideNab in PreferenceModal 2017-09-22 15:46:08 +09:00
Kazu Yokomizo
beceb851c2 Fix layout at selector size in PreferenceModal 2017-09-22 15:41:40 +09:00
Kazu Yokomizo
31485d3387 Fix layout at head in PreferenceModal 2017-09-22 15:27:22 +09:00
Kazu Yokomizo
fc552e030a Change save button position to top 2017-09-22 15:21:04 +09:00
Kazu Yokomizo
bf4c9f920a Fix layout at preference modal 2017-09-22 15:13:34 +09:00
Kazu Yokomizo
4ebd503664 Merge pull request #880 from xxdavid/feature-strip-html-from-title
Strip HTML tags from the note title
2017-09-22 13:05:01 +09:00
David Pavlík
0907bc80ef Strip HTML from the note title 2017-09-21 16:48:13 +02:00
Kazu Yokomizo
2cf46a3332 Merge pull request #878 from BoostIO/update-readme
Update readme
2017-09-21 00:38:34 +09:00
Kazu Yokomizo
41868f28e6 Update readme
- Renew slack invitation url
- Change name "Boostnote Team" to "10hz"
2017-09-21 00:34:13 +09:00
asmsuechan
964b7b62de Change url development to production 2017-09-20 10:31:50 +09:00
SuenagaRyota
0d34a03fe0 Merge pull request #857 from BoostIO/feature-ama-event-main-focused
add MAIN_FOCUSED event
2017-09-16 10:57:08 +09:00
Sosuke Suzuki
a62faa471c change the event name for app start from MAIN_FOCUSED to APP_STARTED 2017-09-15 00:23:31 +09:00
Sosuke Suzuki
66f3ce2cb2 add MAIN_FOCUSED event 2017-09-12 19:43:59 +09:00
asmsuechan
e313b5e59d Add RealtimeNotification 2017-09-09 13:47:30 +09:00
SuenagaRyota
bb26d9a0a8 Merge pull request #834 from KuangLei/master
Translate contributing.md to Simplified Chinese
2017-09-09 09:18:35 +09:00
Kazu Yokomizo
0ca41fbdb4 Merge pull request #844 from BoostIO/fix-layout
Fix layout
2017-09-08 01:39:02 +09:00
Kazu Yokomizo
2cfb883bad Merge pull request #847 from BoostIO/update-readme
Update Readme
2017-09-05 16:01:37 +09:00
Kazu Yokomizo
ec8c8bb669 Update Readme 2017-09-05 15:54:47 +09:00
Kazu Yokomizo
0b54f01107 Fix layout at code block in markdown 2017-09-04 11:48:16 +09:00
Kazu Yokomizo
67be198bee Merge pull request #815 from asmsuechan/add-word-count-to-InfoPanel
Add wordcount and lettercount to InfoPanel
2017-09-01 12:22:38 +09:00
Kazu Yokomizo
32a4a1aae1 Merge pull request #837 from BoostIO/update-readme
Update Readme
2017-08-30 16:22:47 +09:00
Kazu Yokomizo
dac7372839 Update Readme 2017-08-30 16:09:38 +09:00
Kazu Yokomizo
521c261a37 Merge pull request #836 from BoostIO/move-to-image
Create repository folder and move top image to here.
2017-08-30 16:06:43 +09:00
Kazu Yokomizo
27367488c2 Create repository folder and move top image to here. 2017-08-30 14:39:37 +09:00
Kazu Yokomizo
0d5c3b1be6 Merge pull request #835 from BoostIO/delete-top-image
Delete top image
2017-08-30 14:35:25 +09:00
Kazu Yokomizo
a67d5ffacb Upload new top image 2017-08-30 14:23:52 +09:00
Kazu Yokomizo
687440a7c7 Delete old top.png 2017-08-30 14:21:40 +09:00
KLsz
bafdc24a6d Add a link from the english doc pages to doc pages in other languages 2017-08-28 19:54:13 +08:00
KLsz
047f9c93c5 Translate debug.md to Simplified Chinese 2017-08-28 19:46:36 +08:00
KLsz
116fafc117 Translate build.md to Simplified Chinese 2017-08-28 18:00:12 +08:00
KLsz
060c92091c Translate contributing.md to Simplified Chinese 2017-08-28 16:26:00 +08:00
Kazu Yokomizo
5802525b73 Merge pull request #829 from BoostIO/add-backers
Add Backers
2017-08-25 09:57:32 +09:00
Kazu Yokomizo
c3580caabc Merge pull request #828 from BoostIO/update-slack-link
Update slack invitation link
2017-08-25 09:57:16 +09:00
Kazu Yokomizo
08c027acc5 Add Backers 2017-08-25 09:52:54 +09:00
Kazu Yokomizo
4468792346 Update slack invitation link 2017-08-25 09:51:25 +09:00
SuenagaRyota
1b16c68cf9 Merge pull request #818 from asmsuechan/work-paste-image
Make pasting an image in CodeEditor work
2017-08-23 13:05:28 +09:00
asmsuechan
b99c1e3b32 Remove unnecessary bind 2017-08-22 13:48:50 +09:00
SuenagaRyota
eb2994e3c2 Merge pull request #820 from asmsuechan/drag-drop-image-caret-ubuntu
Fix image insesration problem
2017-08-20 09:19:23 +09:00
asmsuechan
d88dd26186 Fix image insesration problem, Use a function of CodeMirror instead of dom function 2017-08-20 08:11:00 +09:00
asmsuechan
59fcc58e9c Make pasting an image in CodeEditor work 2017-08-19 18:37:51 +09:00
SuenagaRyota
acba61f36a Merge pull request #816 from asmsuechan/iss-809
iss #809 normalize text works only in img tag
2017-08-19 09:44:56 +09:00
asmsuechan
a3a55a8bb4 iss #809 normalize text only in img tag 2017-08-19 09:25:45 +09:00
SuenagaRyota
22929d84fc Merge pull request #812 from asmsuechan/add-anchor
Add markdown-it-named-headers and adjust to use Japanese or Chinese
2017-08-19 08:42:00 +09:00
asmsuechan
9ea9d30947 Add wordcount and lettercount to InfoPanel 2017-08-19 08:26:55 +09:00
SuenagaRyota
7f08428fe2 Merge pull request #813 from asmsuechan/fix-build.md
Add to specify npm version
2017-08-18 23:51:10 +09:00
asmsuechan
0d80a7d961 Add to specify npm version 2017-08-18 18:52:18 +09:00
SuenagaRyota
2899264b54 Merge pull request #806 from sferra/fix-app-name-and-icon-on-linux
Fix app name and icon on linux
2017-08-18 18:44:37 +09:00
asmsuechan
923de0aa0d Add markdown-it-named-headers and adjust to use Japanese or Chinese 2017-08-18 16:07:15 +09:00
SuenagaRyota
2b729dad15 Merge pull request #811 from RedBug312/multimd-table
Support for extended table markdown syntax
2017-08-18 14:16:20 +09:00
RedBug312
b9b5bae78a Add markdown-it plugin for multimarkdown table 2017-08-18 12:48:55 +08:00
Cristian Beskid
a9acde07d1 Add missing 'productName' attribute to package.json
Fixes incorrect application name displayed in linux/gnome-shell. See
BoostIO/Boostnote#251
2017-08-15 13:52:01 +02:00
Cristian Beskid
a46b8d3079 Configure the icon of the main window
Fixes the incorrect application icon in linux/gnome-shell. See
BoostIO/Boostnote#251
2017-08-15 13:49:32 +02:00
SuenagaRyota
8b92e2cbb7 Merge pull request #805 from asmsuechan/fix-typo-of-fullscreen
Fix typo regarding fullscreen
2017-08-15 20:29:22 +09:00
asmsuechan
881f5a5110 Fix typo regarding fullscreen 2017-08-15 20:22:26 +09:00
SuenagaRyota
4e986a6384 Merge pull request #802 from asmsuechan/fix-by-eslint-react
Fix by eslint react
2017-08-15 10:16:33 +09:00
SuenagaRyota
ce5e1babb7 Merge pull request #803 from asmsuechan/fix-note-creation-in-all-notes
Fix note creation in All Notes
2017-08-15 10:16:07 +09:00
asmsuechan
b85790d2fa Fix note creation in All Notes 2017-08-15 10:09:17 +09:00
asmsuechan
6bc3e7fcf1 [eslint] react/no-direct-mutation-state 2017-08-15 10:01:04 +09:00
asmsuechan
1ca968201d [eslint] react/no-unescaped-entities 2017-08-14 11:56:55 +09:00
SuenagaRyota
f2a03e4cc7 Merge pull request #800 from asmsuechan/componentnize-NewNoteButton
Componentnize NewNoteButton
2017-08-14 11:45:37 +09:00
asmsuechan
a752730718 Change to use sdialog.showMEssageBox() instead of window.alert 2017-08-14 11:39:06 +09:00
asmsuechan
9d20fd91ec Change ee to eventEmitter 2017-08-14 11:20:54 +09:00
asmsuechan
70a6a3acb8 Remove unused variable 2017-08-14 11:20:54 +09:00
asmsuechan
7f52eed4d5 Move condition of trash or not 2017-08-14 11:20:54 +09:00
asmsuechan
105119e1a4 Change let to const 2017-08-14 11:20:54 +09:00
asmsuechan
169e30e029 Fix by lint 2017-08-14 11:20:54 +09:00
asmsuechan
a5fa3e9e7a 🗑️ Remove unused file 2017-08-14 11:20:54 +09:00
asmsuechan
8985062d34 ♻️ Refactor 2017-08-14 11:20:54 +09:00
asmsuechan
56eb9c76ae Componentnize NewNoteButton 2017-08-14 11:20:54 +09:00
SuenagaRyota
e5b6762bf3 Merge pull request #801 from asmsuechan/add-eslint-plugin-react
Add eslint plugin react
2017-08-14 11:17:06 +09:00
asmsuechan
e8bccaef88 Add a rule 2017-08-14 11:13:25 +09:00
asmsuechan
afdb038244 Add rules 2017-08-14 11:10:15 +09:00
asmsuechan
56942d55eb Add eslint-plugin-react to .eslintrc 2017-08-14 11:02:56 +09:00
asmsuechan
9d742c8435 Add eslint-plugin-react 2017-08-14 10:46:40 +09:00
Kazu Yokomizo
6ee4e48de2 Merge pull request #795 from BoostIO/feature-v0-8-14
v0.8.14
2017-08-12 14:50:16 +09:00
Kazu Yokomizo
184f3dc04b v0.8.14 2017-08-12 12:20:30 +09:00
48 changed files with 995 additions and 575 deletions

View File

@@ -1,10 +1,16 @@
{ {
"extends": ["standard", "standard-jsx"], "extends": ["standard", "standard-jsx", "plugin:react/recommended"],
"plugins": ["react"],
"rules": { "rules": {
"no-useless-escape": 0, "no-useless-escape": 0,
"prefer-const": "warn", "prefer-const": "warn",
"no-unused-vars": "warn", "no-unused-vars": "warn",
"no-undef": "warn", "no-undef": "warn",
"no-lone-blocks": "warn" "no-lone-blocks": "warn",
"react/prop-types": 0,
"react/no-string-refs": 0,
"react/no-find-dom-node": "warn",
"react/no-render-return-value": "warn",
"react/no-deprecated": "warn"
} }
} }

View File

@@ -3,3 +3,7 @@ You can support Boostnote from $ 5 a month!
# Backers # Backers
[Kazu Yokomizo](https://twitter.com/kazup_bot) [Kazu Yokomizo](https://twitter.com/kazup_bot)
kolchan11
RonWalker22

View File

@@ -3,6 +3,7 @@ import _ from 'lodash'
import CodeMirror from 'codemirror' import CodeMirror from 'codemirror'
import path from 'path' import path from 'path'
import copyImage from 'browser/main/lib/dataApi/copyImage' import copyImage from 'browser/main/lib/dataApi/copyImage'
import { findStorage } from 'browser/lib/findStorage'
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js' CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
@@ -39,6 +40,7 @@ export default class CodeEditor extends React.Component {
} }
this.props.onBlur != null && this.props.onBlur(e) this.props.onBlur != null && this.props.onBlur(e)
} }
this.pasteHandler = (editor, e) => this.handlePaste(editor, e)
this.loadStyleHandler = (e) => { this.loadStyleHandler = (e) => {
this.editor.refresh() this.editor.refresh()
} }
@@ -98,14 +100,25 @@ export default class CodeEditor extends React.Component {
this.editor.on('blur', this.blurHandler) this.editor.on('blur', this.blurHandler)
this.editor.on('change', this.changeHandler) this.editor.on('change', this.changeHandler)
this.editor.on('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme') let editorTheme = document.getElementById('editorTheme')
editorTheme.addEventListener('load', this.loadStyleHandler) editorTheme.addEventListener('load', this.loadStyleHandler)
CodeMirror.Vim.defineEx('quit', 'q', this.quitEditor)
CodeMirror.Vim.defineEx('q!', 'q!', this.quitEditor)
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
}
quitEditor () {
document.querySelector('textarea').blur()
} }
componentWillUnmount () { componentWillUnmount () {
this.editor.off('blur', this.blurHandler) this.editor.off('blur', this.blurHandler)
this.editor.off('change', this.changeHandler) this.editor.off('change', this.changeHandler)
this.editor.off('paste', this.pasteHandler)
let editorTheme = document.getElementById('editorTheme') let editorTheme = document.getElementById('editorTheme')
editorTheme.removeEventListener('load', this.loadStyleHandler) editorTheme.removeEventListener('load', this.loadStyleHandler)
} }
@@ -201,7 +214,30 @@ export default class CodeEditor extends React.Component {
insertImageMd (imageMd) { insertImageMd (imageMd) {
const textarea = this.editor.getInputField() const textarea = this.editor.getInputField()
const cm = this.editor const cm = this.editor
textarea.value = `${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}` cm.replaceSelection(`${textarea.value.substr(0, textarea.selectionStart)}${imageMd}${textarea.value.substr(textarea.selectionEnd)}`)
}
handlePaste (editor, e) {
const dataTransferItem = e.clipboardData.items[0]
if (!dataTransferItem.type.match('image')) return
const blob = dataTransferItem.getAsFile()
let reader = new FileReader()
let base64data
reader.readAsDataURL(blob)
reader.onloadend = () => {
base64data = reader.result.replace(/^data:image\/png;base64,/, '')
base64data += base64data.replace('+', ' ')
const binaryData = new Buffer(base64data, 'base64').toString('binary')
const imageName = Math.random().toString(36).slice(-16)
const storagePath = findStorage(this.props.storageKey).path
const imagePath = path.join(`${storagePath}`, 'images', `${imageName}.png`)
require('fs').writeFile(imagePath, binaryData, 'binary')
const imageMd = `![${imageName}](${path.join('/:storage', `${imageName}.png`)})`
this.insertImageMd(imageMd)
}
} }
render () { render () {

View File

@@ -51,12 +51,12 @@ code {
color: rgba(147,147,149,0.8);; color: rgba(147,147,149,0.8);;
fill: rgba(147,147,149,1);; fill: rgba(147,147,149,1);;
border-radius: 50%; border-radius: 50%;
margin: 7px; margin: 0px 10px;
border: none; border: none;
background-color: transparent; background-color: transparent;
outline: none; outline: none;
height: 32px; height: 15px;
width: 32px; width: 15px;
cursor: pointer; cursor: pointer;
} }
@@ -291,8 +291,9 @@ export default class MarkdownPreview extends React.Component {
}) })
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('img'), (el) => { _.forEach(this.refs.root.contentWindow.document.querySelectorAll('img'), (el) => {
el.src = markdown.normalizeLinkText(el.src)
if (!/\/:storage/.test(el.src)) return if (!/\/:storage/.test(el.src)) return
el.src = `file:///${path.join(storagePath, 'images', path.basename(el.src))}` el.src = `file:///${markdown.normalizeLinkText(path.join(storagePath, 'images', path.basename(el.src)))}`
}) })
codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme) codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme)

View File

@@ -6,7 +6,7 @@ const ModalEscButton = ({
handleEscButtonClick handleEscButtonClick
}) => ( }) => (
<button styleName='escButton' onClick={handleEscButtonClick}> <button styleName='escButton' onClick={handleEscButtonClick}>
<div styleName='esc-mark'>x</div> <div styleName='esc-mark'>×</div>
<div styleName='esc-text'>esc</div> <div styleName='esc-text'>esc</div>
</button> </button>
) )

View File

@@ -11,4 +11,6 @@
height top-bar-height height top-bar-height
.esc-mark .esc-mark
font-size 15px font-size 28px
margin-top -5px
margin-bottom -7px

View File

@@ -0,0 +1,55 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './RealtimeNotification.styl'
const electron = require('electron')
const { shell } = electron
class RealtimeNotification extends React.Component {
constructor (props) {
super(props)
this.state = {
notifications: []
}
}
componentDidMount () {
this.fetchNotifications()
}
fetchNotifications () {
const notificationsUrl = 'https://raw.githubusercontent.com/BoostIO/notification/master/notification.json'
fetch(notificationsUrl)
.then(response => {
return response.json()
})
.then(json => {
this.setState({notifications: json.notifications})
})
}
handleLinkClick (e) {
shell.openExternal(e.currentTarget.href)
e.preventDefault()
}
render () {
const { notifications } = this.state
const link = notifications.length > 0
? <a styleName='notification-link' href={notifications[0].linkUrl}
onClick={(e) => this.handleLinkClick(e)}
>
{notifications[0].text}
</a>
: ''
return (
<div styleName='notification-area'>{link}</div>
)
}
}
RealtimeNotification.propTypes = {}
export default CSSModules(RealtimeNotification, styles)

View File

@@ -0,0 +1,35 @@
.notification-area
z-index 1000
font-size 12px
position absolute
bottom 0px
background-color #EBEBEB
width 100vw
height 30px
text-align center
.notification-link
text-decoration none
color #282A36
border 1px solid #6FA8E6
background-color alpha(#6FA8E6, 0.2)
padding 3px 9px
border-radius 2px
position absolute
bottom 4px
margin-left -10%
transition 0.2s
&:hover
color #1378BD
body[data-theme="dark"]
.notification-area
background-color #1E2124
.notification-link
color #fff
border 1px solid alpha(#5CB85C, 0.6)
background-color alpha(#5CB85C, 0.2)
transition 0.2s
&:hover
color #5CB85C

View File

@@ -2,6 +2,7 @@
.root .root
absolute top bottom left right absolute top bottom left right
bottom 30px
left $note-detail-left-margin left $note-detail-left-margin
right $note-detail-right-margin right $note-detail-right-margin
height 100% height 100%

View File

@@ -59,6 +59,15 @@ md.use(math, {
}) })
md.use(require('markdown-it-imsize')) md.use(require('markdown-it-imsize'))
md.use(require('markdown-it-footnote')) md.use(require('markdown-it-footnote'))
md.use(require('markdown-it-multimd-table'))
md.use(require('markdown-it-named-headers'), {
slugify: (header) => {
return encodeURI(header.trim()
.replace(/[\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~]/g, '')
.replace(/\s+/g, '-'))
.replace(/\-+$/, '')
}
})
// Override task item // Override task item
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) { md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
let content, terminate, i, l, token let content, terminate, i, l, token
@@ -156,12 +165,17 @@ function strip (input) {
return output return output
} }
function normalizeLinkText (linkText) {
return md.normalizeLinkText(linkText)
}
const markdown = { const markdown = {
render: function markdown (content) { render: function markdown (content) {
if (!_.isString(content)) content = '' if (!_.isString(content)) content = ''
const renderedContent = md.render(content) const renderedContent = md.render(content)
return md.normalizeLinkText(renderedContent) return renderedContent
}, },
strip strip,
normalizeLinkText
} }
export default markdown export default markdown

View File

@@ -3,7 +3,7 @@ import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl' import styles from './InfoPanel.styl'
const InfoPanel = ({ const InfoPanel = ({
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, wordCount, letterCount, type
}) => ( }) => (
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}> <div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
<div styleName='group-section'> <div styleName='group-section'>
@@ -46,6 +46,27 @@ const InfoPanel = ({
<input value={noteLink} onClick={(e) => { e.target.select() }} /> <input value={noteLink} onClick={(e) => { e.target.select() }} />
</div> </div>
</div> </div>
{type === 'SNIPPET_NOTE'
? ''
: <div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Words
</div>
<div styleName='group-section-control'>
{wordCount}
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>
Letters
</div>
<div styleName='group-section-control'>
{letterCount}
</div>
</div>
</div>
}
<div id='export-wrap'> <div id='export-wrap'>
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}> <button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
@@ -73,7 +94,10 @@ InfoPanel.propTypes = {
updatedAt: PropTypes.string.isRequired, updatedAt: PropTypes.string.isRequired,
createdAt: PropTypes.string.isRequired, createdAt: PropTypes.string.isRequired,
exportAsMd: PropTypes.func.isRequired, exportAsMd: PropTypes.func.isRequired,
exportAsTxt: PropTypes.func.isRequired exportAsTxt: PropTypes.func.isRequired,
wordCount: PropTypes.number,
letterCount: PropTypes.number,
type: PropTypes.string.isRequired
} }
export default CSSModules(InfoPanel, styles) export default CSSModules(InfoPanel, styles)

View File

@@ -20,6 +20,7 @@ import InfoPanel from './InfoPanel'
import InfoPanelTrashed from './InfoPanelTrashed' import InfoPanelTrashed from './InfoPanelTrashed'
import { formatDate } from 'browser/lib/date-formatter' import { formatDate } from 'browser/lib/date-formatter'
import { getTodoPercentageOfCompleted } from 'browser/lib/getTodoStatus' import { getTodoPercentageOfCompleted } from 'browser/lib/getTodoStatus'
import striptags from 'striptags'
const electron = require('electron') const electron = require('electron')
const { remote } = electron const { remote } = electron
@@ -76,7 +77,7 @@ class MarkdownNoteDetail extends React.Component {
note.content = this.refs.content.value note.content = this.refs.content.value
if (this.refs.tags) note.tags = this.refs.tags.value if (this.refs.tags) note.tags = this.refs.tags.value
note.title = markdown.strip(findNoteTitle(note.content)) note.title = markdown.strip(striptags(findNoteTitle(note.content)))
note.updatedAt = new Date() note.updatedAt = new Date()
this.setState({ this.setState({
@@ -340,7 +341,7 @@ class MarkdownNoteDetail extends React.Component {
<button styleName='control-fullScreenButton' <button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)} onMouseDown={(e) => this.handleFullScreenButton(e)}
> >
<i className='fa fa-expand' styleName='fullScreen-button' /> <i className='fa fa-window-maximize' styleName='fullScreen-button' />
</button> </button>
<InfoButton <InfoButton
onClick={(e) => this.handleInfoButtonClick(e)} onClick={(e) => this.handleInfoButtonClick(e)}
@@ -353,6 +354,9 @@ class MarkdownNoteDetail extends React.Component {
createdAt={formatDate(note.createdAt)} createdAt={formatDate(note.createdAt)}
exportAsMd={this.exportAsMd} exportAsMd={this.exportAsMd}
exportAsTxt={this.exportAsTxt} exportAsTxt={this.exportAsTxt}
wordCount={note.content.split(' ').length}
letterCount={note.content.replace(/\r?\n/g, '').length}
type={note.type}
/> />
</div> </div>
</div> </div>

View File

@@ -271,7 +271,7 @@ class SnippetNoteDetail extends React.Component {
let syntax = CodeMirror.findModeByFileName(name.trim()) let syntax = CodeMirror.findModeByFileName(name.trim())
let mode = syntax != null ? syntax.name : null let mode = syntax != null ? syntax.name : null
if (mode != null) snippets[index].mode = mode if (mode != null) snippets[index].mode = mode
this.state.note.snippets = snippets this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({ this.setState({
note: this.state.note note: this.state.note
@@ -284,7 +284,7 @@ class SnippetNoteDetail extends React.Component {
return (e) => { return (e) => {
let snippets = this.state.note.snippets.slice() let snippets = this.state.note.snippets.slice()
snippets[index].mode = name snippets[index].mode = name
this.state.note.snippets = snippets this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({ this.setState({
note: this.state.note note: this.state.note
@@ -298,7 +298,7 @@ class SnippetNoteDetail extends React.Component {
return (e) => { return (e) => {
let snippets = this.state.note.snippets.slice() let snippets = this.state.note.snippets.slice()
snippets[index].content = this.refs['code-' + index].value snippets[index].content = this.refs['code-' + index].value
this.state.note.snippets = snippets this.setState({note: Object.assign(this.state.note, {snippets: snippets})})
this.setState({ this.setState({
note: this.state.note note: this.state.note
}, () => { }, () => {
@@ -598,7 +598,7 @@ class SnippetNoteDetail extends React.Component {
<button styleName='control-fullScreenButton' <button styleName='control-fullScreenButton'
onMouseDown={(e) => this.handleFullScreenButton(e)} onMouseDown={(e) => this.handleFullScreenButton(e)}
> >
<i className='fa fa-expand' styleName='fullScreen-button' /> <i className='fa fa-window-maximize' styleName='fullScreen-button' />
</button> </button>
<InfoButton <InfoButton
onClick={(e) => this.handleInfoButtonClick(e)} onClick={(e) => this.handleInfoButtonClick(e)}
@@ -611,6 +611,7 @@ class SnippetNoteDetail extends React.Component {
createdAt={formatDate(note.createdAt)} createdAt={formatDate(note.createdAt)}
exportAsMd={this.showWarning} exportAsMd={this.showWarning}
exportAsTxt={this.showWarning} exportAsTxt={this.showWarning}
type={note.type}
/> />
</div> </div>
</div> </div>

View File

@@ -19,7 +19,7 @@
.body .description .body .description
absolute top left right absolute top left right
height 80px height 50px
.body .description textarea .body .description textarea
outline none outline none
@@ -27,14 +27,14 @@
height 100% height 100%
width 100% width 100%
resize none resize none
border none border 1px solid $ui-borderColor
padding 10px padding 2px 5px
line-height 1.6 line-height 1.6
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor
.tabList .tabList
absolute left right absolute left right
top 80px top 55px
height 30px height 30px
display flex display flex
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor
@@ -50,16 +50,17 @@
.tabView .tabView
absolute left right bottom absolute left right bottom
top 130px top 100px
.tabView-content .tabView-content
absolute top left right bottom absolute top left right bottom
.override .override
absolute bottom left absolute bottom left
bottom 30px
left 60px left 60px
height 23px height 23px
z-index 1 z-index 101
button button
navButtonColor() navButtonColor()
height 24px height 24px
@@ -83,6 +84,7 @@ body[data-theme="dark"]
.body .description textarea .body .description textarea
background-color $ui-dark-noteDetail-backgroundColor background-color $ui-dark-noteDetail-backgroundColor
color $ui-dark-text-color color $ui-dark-text-color
border 1px solid $ui-dark-borderColor
.tabList .tabList
background-color $ui-button--active-backgroundColor background-color $ui-button--active-backgroundColor

View File

@@ -14,6 +14,7 @@ import InitModal from 'browser/main/modals/InitModal'
import mixpanel from 'browser/main/lib/mixpanel' import mixpanel from 'browser/main/lib/mixpanel'
import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig' import mobileAnalytics from 'browser/main/lib/AwsMobileAnalyticsConfig'
import eventEmitter from 'browser/main/lib/eventEmitter' import eventEmitter from 'browser/main/lib/eventEmitter'
import RealtimeNotification from 'browser/components/RealtimeNotification'
function focused () { function focused () {
mixpanel.track('MAIN_FOCUSED') mixpanel.track('MAIN_FOCUSED')
@@ -172,8 +173,8 @@ class Main extends React.Component {
} }
hideLeftLists (noteDetail, noteList, mainBody) { hideLeftLists (noteDetail, noteList, mainBody) {
this.state.noteDetailWidth = noteDetail.style.left this.setState({noteDetailWidth: noteDetail.style.left})
this.state.mainBodyWidth = mainBody.style.left this.setState({mainBodyWidth: mainBody.style.left})
noteDetail.style.left = '0px' noteDetail.style.left = '0px'
mainBody.style.left = '0px' mainBody.style.left = '0px'
noteList.style.display = 'none' noteList.style.display = 'none'
@@ -255,6 +256,7 @@ class Main extends React.Component {
ignorePreviewPointerEvents={this.state.isRightSliderFocused} ignorePreviewPointerEvents={this.state.isRightSliderFocused}
/> />
</div> </div>
<RealtimeNotification />
</div> </div>
) )
} }

View File

@@ -0,0 +1,68 @@
.root
position relative
background-color $ui-noteList-backgroundColor
height $topBar-height - 1
margin-left: auto;
width: 64px;
margin-right: -15px;
.root--expanded
@extend .root
$control-height = 34px
.control
position absolute
top 13px
left 8px
right 8px
height $control-height
overflow hidden
display flex
.control-newNoteButton
display block
width 32px
height $control-height - 2
navButtonColor()
font-size 16px
line-height 28px
padding 0
&:active
border-color $ui-button--active-backgroundColor
&:hover .control-newNoteButton-tooltip
opacity 1
.control-newNoteButton-tooltip
tooltip()
position fixed
pointer-events none
top 50px
left 433px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
body[data-theme="dark"]
.root, .root--expanded
background-color $ui-dark-noteList-backgroundColor
.control
border-color $ui-dark-borderColor
.control-newNoteButton
color $ui-inactive-text-color
border-color $ui-dark-borderColor
background-color $ui-dark-noteList-backgroundColor
&:hover
transition 0.15s
color $ui-dark-text-color
&:active
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
border-color $ui-dark-button--active-backgroundColor
.control-newNoteButton-tooltip
darkTooltip()

View File

@@ -0,0 +1,106 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './NewNoteButton.styl'
import _ from 'lodash'
import modal from 'browser/main/lib/modal'
import NewNoteModal from 'browser/main/modals/NewNoteModal'
import { hashHistory } from 'react-router'
import eventEmitter from 'browser/main/lib/eventEmitter'
import dataApi from 'browser/main/lib/dataApi'
const { remote } = require('electron')
const { dialog } = remote
const OSX = window.process.platform === 'darwin'
class NewNoteButton extends React.Component {
constructor (props) {
super(props)
this.state = {
}
this.newNoteHandler = () => {
this.handleNewNoteButtonClick()
}
}
componentDidMount () {
eventEmitter.on('top:new-note', this.newNoteHandler)
}
componentWillUnmount () {
eventEmitter.off('top:new-note', this.newNoteHandler)
}
handleNewNoteButtonClick (e) {
const { config, location, dispatch } = this.props
const { storage, folder } = this.resolveTargetFolder()
modal.open(NewNoteModal, {
storage: storage.key,
folder: folder.key,
dispatch,
location
})
}
resolveTargetFolder () {
const { data, params } = this.props
let storage = data.storageMap.get(params.storageKey)
// Find first storage
if (storage == null) {
for (let kv of data.storageMap) {
storage = kv[1]
break
}
}
if (storage == null) this.showMessageBox('No storage to create a note')
const folder = _.find(storage.folders, {key: params.folderKey}) || storage.folders[0]
if (folder == null) this.showMessageBox('No folder to create a note')
return {
storage,
folder
}
}
showMessageBox (message) {
dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: message,
buttons: ['OK']
})
}
render () {
const { config, style } = this.props
return (
<div className='NewNoteButton'
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}
style={style}
>
<div styleName='control'>
<button styleName='control-newNoteButton'
onClick={(e) => this.handleNewNoteButtonClick(e)}>
<i className='fa fa-pencil-square-o' />
<span styleName='control-newNoteButton-tooltip'>
Make a Note {OSX ? '⌘' : '^'} + n
</span>
</button>
</div>
</div>
)
}
}
NewNoteButton.propTypes = {
dispatch: PropTypes.func,
config: PropTypes.shape({
isSideNavFolded: PropTypes.bool
})
}
export default CSSModules(NewNoteButton, styles)

View File

@@ -2,6 +2,7 @@ $control-height = 30px
.root .root
absolute left bottom absolute left bottom
bottom 30px
top $topBar-height - 1 top $topBar-height - 1
background-color $ui-noteList-backgroundColor background-color $ui-noteList-backgroundColor

View File

@@ -13,6 +13,7 @@ import fs from 'fs'
import { hashHistory } from 'react-router' import { hashHistory } from 'react-router'
import markdown from 'browser/lib/markdown' import markdown from 'browser/lib/markdown'
import { findNoteTitle } from 'browser/lib/findNoteTitle' import { findNoteTitle } from 'browser/lib/findNoteTitle'
import stripgtags from 'striptags'
const { remote } = require('electron') const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote const { Menu, MenuItem, dialog } = remote
@@ -347,6 +348,22 @@ class NoteList extends React.Component {
properties: ['openFile', 'multiSelections'] properties: ['openFile', 'multiSelections']
} }
dialog.showOpenDialog(remote.getCurrentWindow(), options, (filepaths) => {
this.addNotesFromFiles(filepaths)
})
}
handleDrop (e) {
e.preventDefault()
const { location } = this.props
const filepaths = Array.from(e.dataTransfer.files).map(file => { return file.path })
if (!location.pathname.match(/\/trashed/)) this.addNotesFromFiles(filepaths)
}
// Add notes to the current folder
addNotesFromFiles (filepaths) {
const { dispatch, location } = this.props
const targetIndex = _.findIndex(this.notes, (note) => { const targetIndex = _.findIndex(this.notes, (note) => {
return note !== null && `${note.storage}-${note.key}` === location.query.key return note !== null && `${note.storage}-${note.key}` === location.query.key
}) })
@@ -354,28 +371,26 @@ class NoteList extends React.Component {
const storageKey = this.notes[targetIndex].storage const storageKey = this.notes[targetIndex].storage
const folderKey = this.notes[targetIndex].folder const folderKey = this.notes[targetIndex].folder
dialog.showOpenDialog(remote.getCurrentWindow(), options, (filepaths) => { if (filepaths === undefined) return
if (filepaths === undefined) return filepaths.forEach((filepath) => {
filepaths.forEach((filepath) => { fs.readFile(filepath, (err, data) => {
fs.readFile(filepath, (err, data) => { if (err) throw Error('File reading error: ', err)
if (err) throw Error('File reading error: ', err) const content = data.toString()
const content = data.toString() const newNote = {
const newNote = { content: content,
content: content, folder: folderKey,
folder: folderKey, title: markdown.strip(findNoteTitle(content)),
title: markdown.strip(findNoteTitle(content)), type: 'MARKDOWN_NOTE'
type: 'MARKDOWN_NOTE' }
} dataApi.createNote(storageKey, newNote)
dataApi.createNote(storageKey, newNote) .then((note) => {
.then((note) => { dispatch({
dispatch({ type: 'UPDATE_NOTE',
type: 'UPDATE_NOTE', note: note
note: note })
}) hashHistory.push({
hashHistory.push({ pathname: location.pathname,
pathname: location.pathname, query: {key: `${note.storage}-${note.key}`}
query: {key: `${note.storage}-${note.key}`}
})
}) })
}) })
}) })
@@ -438,6 +453,7 @@ class NoteList extends React.Component {
<div className='NoteList' <div className='NoteList'
styleName='root' styleName='root'
style={this.props.style} style={this.props.style}
onDrop={(e) => this.handleDrop(e)}
> >
<div styleName='control'> <div styleName='control'>
<div styleName='control-sortBy'> <div styleName='control-sortBy'>

View File

@@ -3,6 +3,8 @@
.root .root
absolute bottom left right absolute bottom left right
height $statusBar-height height $statusBar-height
bottom 16px
z-index 100
background-color $ui-noteDetail-backgroundColor background-color $ui-noteDetail-backgroundColor
display flex display flex

View File

@@ -59,8 +59,6 @@ class StatusBar extends React.Component {
{Math.floor(config.zoom * 100)}% {Math.floor(config.zoom * 100)}%
</button> </button>
<div styleName='blank' />
{status.updateReady {status.updateReady
? <button onClick={this.updateApp} styleName='update'> ? <button onClick={this.updateApp} styleName='update'>
<i styleName='update-icon' className='fa fa-cloud-download' /> Ready to Update! <i styleName='update-icon' className='fa fa-cloud-download' /> Ready to Update!

View File

@@ -2,12 +2,9 @@ import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './TopBar.styl' import styles from './TopBar.styl'
import _ from 'lodash' import _ from 'lodash'
import modal from 'browser/main/lib/modal'
import NewNoteModal from 'browser/main/modals/NewNoteModal' import NewNoteModal from 'browser/main/modals/NewNoteModal'
import { hashHistory } from 'react-router'
import ee from 'browser/main/lib/eventEmitter' import ee from 'browser/main/lib/eventEmitter'
import ConfigManager from 'browser/main/lib/ConfigManager' import NewNoteButton from 'browser/main/NewNoteButton'
import dataApi from 'browser/main/lib/dataApi'
const { remote } = require('electron') const { remote } = require('electron')
const { dialog } = remote const { dialog } = remote
@@ -24,81 +21,19 @@ class TopBar extends React.Component {
isSearching: false isSearching: false
} }
this.newNoteHandler = () => {
this.handleNewPostButtonClick()
}
this.focusSearchHandler = () => { this.focusSearchHandler = () => {
this.handleOnSearchFocus() this.handleOnSearchFocus()
} }
} }
componentDidMount () { componentDidMount () {
ee.on('top:new-note', this.newNoteHandler)
ee.on('top:focus-search', this.focusSearchHandler) ee.on('top:focus-search', this.focusSearchHandler)
} }
componentWillUnmount () { componentWillUnmount () {
ee.off('top:new-note', this.newNoteHandler)
ee.off('top:focus-search', this.focusSearchHandler) ee.off('top:focus-search', this.focusSearchHandler)
} }
handleNewPostButtonClick (e) {
let { config, location } = this.props
if (location.pathname === '/trashed') {
dialog.showMessageBox(remote.getCurrentWindow(), {
type: 'warning',
message: 'Cannot create new note',
detail: 'You cannot create new note in trash box.',
buttons: ['OK']
})
return
}
switch (config.ui.defaultNote) {
case 'MARKDOWN_NOTE':
this.createNote('MARKDOWN_NOTE')
break
case 'SNIPPET_NOTE':
this.createNote('SNIPPET_NOTE')
break
case 'ALWAYS_ASK':
default:
let { dispatch, location } = this.props
let { storage, folder } = this.resolveTargetFolder()
modal.open(NewNoteModal, {
storage: storage.key,
folder: folder.key,
dispatch,
location
})
}
}
resolveTargetFolder () {
let { data, params } = this.props
let storage = data.storageMap.get(params.storageKey)
// Find first storage
if (storage == null) {
for (let kv of data.storageMap) {
storage = kv[1]
break
}
}
if (storage == null) window.alert('No storage to create a note')
let folder = _.find(storage.folders, {key: params.folderKey})
if (folder == null) folder = storage.folders[0]
if (folder == null) window.alert('No folder to create a note')
return {
storage,
folder
}
}
handleSearchChange (e) { handleSearchChange (e) {
let { router } = this.context let { router } = this.context
router.push('/searched') router.push('/searched')
@@ -107,22 +42,6 @@ class TopBar extends React.Component {
}) })
} }
handleOptionClick (uniqueKey) {
return (e) => {
this.setState({
isSearching: false
}, () => {
let { location } = this.props
hashHistory.push({
pathname: location.pathname,
query: {
key: uniqueKey
}
})
})
}
}
handleSearchFocus (e) { handleSearchFocus (e) {
this.setState({ this.setState({
isSearching: true isSearching: true
@@ -147,60 +66,6 @@ class TopBar extends React.Component {
} }
} }
createNote (noteType) {
let { dispatch, location } = this.props
if (noteType !== 'MARKDOWN_NOTE' && noteType !== 'SNIPPET_NOTE') throw new Error('Invalid note type.')
let { storage, folder } = this.resolveTargetFolder()
let newNote = noteType === 'MARKDOWN_NOTE'
? {
type: 'MARKDOWN_NOTE',
folder: folder.key,
title: '',
content: ''
}
: {
type: 'SNIPPET_NOTE',
folder: folder.key,
title: '',
description: '',
snippets: [{
name: '',
mode: 'text',
content: ''
}]
}
dataApi
.createNote(storage.key, newNote)
.then((note) => {
dispatch({
type: 'UPDATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: {key: note.storage + '-' + note.key}
})
ee.emit('detail:focus')
})
}
setDefaultNote (defaultNote) {
let { config, dispatch } = this.props
let ui = Object.assign(config.ui)
ui.defaultNote = defaultNote
ConfigManager.set({
ui
})
dispatch({
type: 'SET_UI',
config: ConfigManager.get()
})
}
handleOnSearchFocus () { handleOnSearchFocus () {
if (this.state.isSearching) { if (this.state.isSearching) {
this.refs.search.childNodes[0].blur() this.refs.search.childNodes[0].blur()
@@ -210,7 +75,7 @@ class TopBar extends React.Component {
} }
render () { render () {
let { config, style, data } = this.props let { config, style, data, location } = this.props
return ( return (
<div className='TopBar' <div className='TopBar'
styleName={config.isSideNavFolded ? 'root--expanded' : 'root'} styleName={config.isSideNavFolded ? 'root--expanded' : 'root'}
@@ -242,14 +107,17 @@ class TopBar extends React.Component {
} }
</div> </div>
<button styleName='control-newPostButton'
onClick={(e) => this.handleNewPostButtonClick(e)}>
<i className='fa fa-pencil-square-o' />
<span styleName='control-newPostButton-tooltip'>
Make a Note {OSX ? '⌘' : '^'} + n
</span>
</button>
</div> </div>
{location.pathname === '/trashed' ? ''
: <NewNoteButton
{..._.pick(this.props, [
'dispatch',
'data',
'config',
'params',
'location'
])}
/>}
</div> </div>
) )
} }

View File

@@ -64,7 +64,7 @@ textarea.block-input
fullsize() fullsize()
modalZIndex= 1000 modalZIndex= 1000
modalBackColor = transparentify(white, 65%) modalBackColor = white
.ace_focus .ace_focus
outline-color rgb(59, 153, 252) outline-color rgb(59, 153, 252)
outline-offset 0px outline-offset 0px
@@ -86,12 +86,12 @@ modalBackColor = transparentify(white, 65%)
body[data-theme="dark"] body[data-theme="dark"]
.ModalBase .ModalBase
.modalBack .modalBack
background-color alpha(black, 60%) background-color $ui-dark-backgroundColor
.CodeMirror .CodeMirror
font-family inherit !important font-family inherit !important
line-height 1.4em line-height 1.4em
height 100% height 96%
.CodeMirror > div > textarea .CodeMirror > div > textarea
margin-bottom -1em margin-bottom -1em
.CodeMirror-focused .CodeMirror-selected .CodeMirror-focused .CodeMirror-selected

View File

@@ -18,9 +18,10 @@ function initAwsMobileAnalytics () {
AWS.config.credentials.get((err) => { AWS.config.credentials.get((err) => {
if (!err) { if (!err) {
console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId) console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId)
recordDynamicCustomEvent('APP_STARTED')
recordStaticCustomEvent()
} }
}) })
recordStaticCustomEvent()
} }
function recordDynamicCustomEvent (type) { function recordDynamicCustomEvent (type) {

View File

@@ -4,10 +4,9 @@
height 270px height 270px
overflow hidden overflow hidden
position relative position relative
padding 0 40px
.header .header
height 70px height 80px
margin-bottom 10px margin-bottom 10px
margin-top 20px margin-top 20px
font-size 18px font-size 18px
@@ -15,23 +14,27 @@
background-color $ui-backgroundColor background-color $ui-backgroundColor
color $ui-text-color color $ui-text-color
.title
font-size 36px
font-weight 600
.control-folder-label .control-folder-label
text-align left text-align left
font-size 12px font-size 14px
color $ui-text-color color $ui-text-color
.control-folder-input .control-folder-input
display block display block
height 30px height 40px
width 420px width 490px
padding 0 5px padding 0 5px
margin 10px auto 15px margin 10px 0
border 1px solid #C9C9C9 // TODO: use variable. border 1px solid #C9C9C9 // TODO: use variable.
border-radius 2px border-radius 2px
background-color transparent background-color transparent
outline none outline none
vertical-align middle vertical-align middle
font-size 14px font-size 16px
&:disabled &:disabled
background-color $ui-input--disabled-backgroundColor background-color $ui-input--disabled-backgroundColor
&:focus, &:active &:focus, &:active
@@ -39,14 +42,13 @@
.control-confirmButton .control-confirmButton
display block display block
float right height 35px
height 30px width 140px
width 100px
border none border none
border-radius 2px border-radius 2px
padding 0 25px padding 0 25px
margin 20px auto margin 20px auto
font-size 12px font-size 14px
colorPrimaryButton() colorPrimaryButton()
body[data-theme="dark"] body[data-theme="dark"]
@@ -56,7 +58,6 @@ body[data-theme="dark"]
height 270px height 270px
overflow hidden overflow hidden
position relative position relative
padding 0 40px
.header .header
background-color transparent background-color transparent

View File

@@ -1,51 +0,0 @@
import React, { PropTypes } from 'react'
import ReactDOM from 'react-dom'
const electron = require('electron')
const ipc = electron.ipcRenderer
export default class DeleteArticleModal extends React.Component {
constructor (props) {
super(props)
this.confirmHandler = (e) => this.handleYesButtonClick()
}
componentDidMount () {
ReactDOM.findDOMNode(this.refs.no).focus()
ipc.on('modal-confirm', this.confirmHandler)
}
componentWillUnmount () {
ipc.removeListener('modal-confirm', this.confirmHandler)
}
handleNoButtonClick (e) {
this.props.close()
}
handleYesButtonClick (e) {
this.props.close()
}
render () {
return (
<div className='DeleteArticleModal modal'>
<div className='title'><i className='fa fa-fw fa-trash' /> Delete an article.</div>
<div className='message'>Do you really want to delete?</div>
<div className='control'>
<button ref='no' onClick={(e) => this.handleNoButtonClick(e)}><i className='fa fa-fw fa-close' /> No</button>
<button ref='yes' onClick={(e) => this.handleYesButtonClick(e)} className='danger'><i className='fa fa-fw fa-check' /> Yes</button>
</div>
</div>
)
}
}
DeleteArticleModal.propTypes = {
action: PropTypes.object,
articleKey: PropTypes.string,
close: PropTypes.func
}

View File

@@ -9,16 +9,19 @@
font-size 18px font-size 18px
line-height 50px line-height 50px
padding 0 15px padding 0 15px
background-color $ui-backgroundColor
border-bottom solid 1px $ui-borderColor
color $ui-text-color color $ui-text-color
margin-bottom 20px
.title
font-size 36px
font-weight 600
.control .control
padding 25px 15px 15px padding 25px 0px
text-align center text-align center
.control-button .control-button
width 220px width 240px
height 220px height 220px
margin 0 15px margin 0 15px
border $ui-border border $ui-border
@@ -30,8 +33,8 @@
colorPrimaryButton() colorPrimaryButton()
.control-button-icon .control-button-icon
font-size 50px font-size 48px
margin-bottom 15px margin-bottom 25px
.control-button-label .control-button-label
font-size 18px font-size 18px
@@ -49,8 +52,6 @@ body[data-theme="dark"]
modalDark() modalDark()
.header .header
background-color $ui-dark-button--hover-backgroundColor
border-color $ui-dark-borderColor
color $ui-dark-text-color color $ui-dark-text-color
.control-button .control-button

View File

@@ -31,10 +31,15 @@
.group-section-control .group-section-control
flex 1 flex 1
margin-left 5px
.group-section-control select .group-section-control select
outline none outline none
border 1px solid $ui-borderColor border 1px solid $ui-borderColor
font-size 16px
height 30px
width 250px
margin-bottom 5px
background-color transparent background-color transparent
.group-section-control-input .group-section-control-input
@@ -77,14 +82,16 @@
margin-right 10px margin-right 10px
.group-control-rightButton .group-control-rightButton
float right position absolute
top 10px
right 20px
colorPrimaryButton() colorPrimaryButton()
border none border none
border-radius 2px border-radius 2px
font-size $tab--button-font-size font-size $tab--button-font-size
height 35px height 40px
width 100px width 120px
margin-right 10px padding 0 15px
.group-hint .group-hint
border $ui-border border $ui-border

View File

@@ -81,7 +81,7 @@ class InfoTab extends React.Component {
<li> <li>
<a href='https://github.com/BoostIO/Boostnote/issues' <a href='https://github.com/BoostIO/Boostnote/issues'
onClick={(e) => this.handleLinkClick(e)} onClick={(e) => this.handleLinkClick(e)}
>GitHub Issues</a> : We'd love to hear your feedback 🙌 >GitHub Issues</a> : We&apos;d love to hear your feedback 🙌
</li> </li>
<li> <li>
<a href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md' <a href='https://github.com/BoostIO/Boostnote/blob/master/docs/build.md'
@@ -97,9 +97,9 @@ class InfoTab extends React.Component {
</ul> </ul>
<hr /> <hr />
<div styleName='policy'>Data collection policy</div> <div styleName='policy'>Data collection policy</div>
<p>We collect only the number of DAU for Boostnote and DO NOT collect any detail information</p> <div>We collect only the number of DAU for Boostnote and **DO NOT collect** any detail information such as your note content.</div>
<p>such as your note content. You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</p> <div>You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</div>
<p>These data are only used for Boostnote improvements.</p> <div>These data are only used for Boostnote improvements.</div>
<input onChange={(e) => this.handleConfigChange(e)} <input onChange={(e) => this.handleConfigChange(e)}
checked={this.state.config.amaEnabled} checked={this.state.config.amaEnabled}
ref='amaEnabled' ref='amaEnabled'

View File

@@ -43,6 +43,7 @@
text-decoration none text-decoration none
.policy .policy
width 100%
font-size 20px font-size 20px
margin-bottom 10px margin-bottom 10px

View File

@@ -4,9 +4,10 @@ top-bar--height = 50px
.root .root
modal() modal()
max-width 800px max-width 100vw
min-height 500px min-height 100vh
height 80% height 100vh
width 100vw
overflow hidden overflow hidden
position relative position relative
@@ -25,22 +26,22 @@ top-bar--height = 50px
top top-bar--height top top-bar--height
left 0 left 0
width 140px width 140px
margin-left 30px margin-left 10px
margin-top 20px margin-top 20px
background-color $ui-backgroundColor background-color $ui-backgroundColor
.nav-button .nav-button
font-size 14px font-size 14px
text-align left text-align left
width 100px width 120px
margin 4px 0 margin 5px 0
padding 5px 0 padding 7px 0
padding-left 10px padding-left 10px
border none border none
border-radius 2px border-radius 2px
background-color transparent background-color transparent
color $ui-text-color color $ui-text-color
font-size 14px font-size 16px
.nav-button--active .nav-button--active
@extend .nav-button @extend .nav-button

View File

@@ -5,7 +5,7 @@ import dataApi from 'browser/main/lib/dataApi'
import StorageItem from './StorageItem' import StorageItem from './StorageItem'
const electron = require('electron') const electron = require('electron')
const remote = electron.remote const { shell, remote } = electron
function browseFolder () { function browseFolder () {
let dialog = remote.dialog let dialog = remote.dialog
@@ -50,6 +50,11 @@ class StoragesTab extends React.Component {
}) })
} }
handleLinkClick (e) {
shell.openExternal(e.currentTarget.href)
e.preventDefault()
}
renderList () { renderList () {
let { data, boundingBox } = this.props let { data, boundingBox } = this.props
@@ -161,7 +166,10 @@ class StoragesTab extends React.Component {
<option value='FILESYSTEM'>File System</option> <option value='FILESYSTEM'>File System</option>
</select> </select>
<div styleName='addStorage-body-section-type-description'> <div styleName='addStorage-body-section-type-description'>
3rd party cloud integration(such as Google Drive and Dropbox) will be available soon. 3rd party cloud integration:
<a href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing'
onClick={(e) => this.handleLinkClick(e)}
>Cloud-Syncing</a>
</div> </div>
</div> </div>
</div> </div>

View File

@@ -10,8 +10,8 @@ $tab--button-font-size = 14px
$tab--dark-text-color = #E5E5E5 $tab--dark-text-color = #E5E5E5
.header .header
font-size 24px font-size 36px
margin-bottom 30px margin-bottom 60px
body[data-theme="dark"] body[data-theme="dark"]
.header .header

View File

@@ -90,9 +90,8 @@ class UiTab extends React.Component {
<div styleName='group'> <div styleName='group'>
<div styleName='group-header'>UI</div> <div styleName='group-header'>UI</div>
<div styleName='group-header2'>Theme</div>
<div styleName='group-section'> <div styleName='group-section'>
Color Theme
<div styleName='group-section-control'> <div styleName='group-section-control'>
<select value={config.ui.theme} <select value={config.ui.theme}
onChange={(e) => this.handleUIChange(e)} onChange={(e) => this.handleUIChange(e)}

View File

@@ -5,7 +5,7 @@ $danger-color = #c9302c
$danger-lighten-color = lighten(#c9302c, 5%) $danger-lighten-color = lighten(#c9302c, 5%)
// Layouts // Layouts
$statusBar-height = 24px $statusBar-height = 36px
$sideNav-width = 200px $sideNav-width = 200px
$sideNav--folded-width = 44px $sideNav--folded-width = 44px
$topBar-height = 60px $topBar-height = 60px
@@ -150,10 +150,13 @@ modal()
position relative position relative
z-index $modal-z-index z-index $modal-z-index
width 100% width 100%
margin-left 80px
margin-right 80px
margin-bottom 80px
margin-top 100px
background-color $modal-background background-color $modal-background
overflow hidden overflow hidden
border-radius $modal-border-radius border-radius $modal-border-radius
box-shadow 0 0 1px rgba(76,86,103,.15), 0 2px 18px rgba(31,37,50,.22)
topBarButtonLight() topBarButtonLight()
width 34px width 34px
@@ -260,4 +263,3 @@ modalDark()
background-color $ui-dark-backgroundColor background-color $ui-dark-backgroundColor
overflow hidden overflow hidden
border-radius $modal-border-radius border-radius $modal-border-radius
box-shadow 2px 2px 10px black

View File

@@ -69,3 +69,21 @@ Pull requestをすることはその変化分のコードの著作権をMaisin&C
これはいずれかBoostnoteが有料の商用アプリになる可能性がある話ではありません。 これはいずれかBoostnoteが有料の商用アプリになる可能性がある話ではありません。
もし、このアプリケーションに料金が発生する時は、Boostnote専用のCloud storageの提供やMobile appとの連動、何か特殊なプレミアム機能の提供など形になります。 もし、このアプリケーションに料金が発生する時は、Boostnote専用のCloud storageの提供やMobile appとの連動、何か特殊なプレミアム機能の提供など形になります。
現在考えられているのは、GPL v3の場合、他のライセンスとの互換が不可能であるため、もしより自由なLicense(BSD, MIT)に変える時に改めて著作権者としてライセンスし直す選択肢を残すイメージです。 現在考えられているのは、GPL v3の場合、他のライセンスとの互換が不可能であるため、もしより自由なLicense(BSD, MIT)に変える時に改めて著作権者としてライセンスし直す選択肢を残すイメージです。
---
# Contributing to Boostnote (Simplified Chinese)
### 当您创建一个issue的时候
我们对您的issue格式没有要求但是我们有一个请求
**如果可能,请在开发者模式打开的情况下,为我们提供屏幕截图**
(您可以通过`Ctrl+Shift+I`打开开发者模式)。
感谢您对我们的支持。
### 关于您提供的Pull Request的著作权版权问题
如果您提供了一个Pull Request这表示您将您所修改的代码的著作权移交给Maisin&Co。
这并不表示Boostnote会成为一个需要付费的软件。如果我们想获得收益我们会尝试一些其他的方法比如说云存储、绑定手机软件等。
因为GPLv3过于严格不能和其他的一些协议兼容所以我们有可能在将来会把BoostNote的协议改为一些较为宽松的协议比如说BSD、MIT。

View File

@@ -1,4 +1,5 @@
# Build # Build
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md).
## Environments ## Environments
* npm: 4.x * npm: 4.x
@@ -43,6 +44,8 @@ You can build the program by using `grunt`. However, we don't recommend this bec
So, we've prepared a separate script which just makes an executable file. So, we've prepared a separate script which just makes an executable file.
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
``` ```
grunt pre-build grunt pre-build
``` ```

View File

@@ -1,4 +1,6 @@
# How to debug Boostnote (Electron app) # How to debug Boostnote (Electron app)
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), and [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md)
Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome. Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome.
You can toggle the `Developer Tools` like this: You can toggle the `Developer Tools` like this:

View File

@@ -37,6 +37,8 @@ Gruntを使います。
それで、実行ファイルを作るスクリプトを用意しておきました。 それで、実行ファイルを作るスクリプトを用意しておきました。
このビルドはnpm v5.3.0では動かないのでv5.2.0で動かす必要があります。
``` ```
grunt pre-build grunt pre-build
``` ```

View File

@@ -37,6 +37,8 @@ yarn run hot
그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다. 그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다.
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
``` ```
grunt pre-build grunt pre-build
``` ```

View File

@@ -43,6 +43,8 @@ $ yarn run dev-start
Мы подготовили отдельный скрипт, который просто создает исполняемый файл: Мы подготовили отдельный скрипт, который просто создает исполняемый файл:
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
``` ```
grunt pre-build grunt pre-build
``` ```

56
docs/zh_CN/build.md Normal file
View File

@@ -0,0 +1,56 @@
# 构建Boostnote
## 环境
* npm: 4.x
* node: 7.x
因为`$ grand pre-build`的问题,您只能使用`npm v4.x`而不能使用`npm v5.x`
## 开发
我们使用Webpack HMR来开发Boostnote。
在代码根目录下运行下列指令可以以默认配置运行Boostnote。
### 首先使用yarn安装所需的依赖包。
```
$ yarn
```
### 接着编译并且运行Boostnote。
```
$ yarn run dev-start
```
这个指令相当于在两个终端内同时运行`yarn run webpack``yarn run hot`
如果出现错误`Failed to load resource: net::ERR_CONNECTION_REFUSED`请尝试重新运行Boostnote。
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
### 然后您就可以进行开发了
当您对代码作出更改的时候,`webpack`会自动抓取并应用所有代码更改。
> ### 提示
> 在如下情况中您可能需要重新运行Boostnote才能应用代码更改
> 1. 当您在修改了一个组件的构造函数的时候When editing a constructor method of a component
> 2. 当您新建了一个CSS类的时候其实这和第1项是相同的因为每个CSS类都需在组件的构造函数中被重写
## 部署
我们使用Grunt来自动部署Boostnote。
因为部署需要协同设计(codesign)与验证码(authenticode),所以您可以但我们不建议通过`grunt`来部署。
所以我们准备了一个脚本文件来生成执行文件。
```
grunt pre-build
```
您只能使用`npm v5.2.0`而不能使用`npm v5.3.0`
接下来您就可以在`dist`目录中找到可执行文件。
> ### 提示
> 因为此可执行文件并没有被注册,所以自动更新不可用。
> 如果需要,您也可将协同设计(codesign)与验证码(authenticode)使用于这个可执行文件中。

15
docs/zh_CN/debug.md Normal file
View File

@@ -0,0 +1,15 @@
# 在Boostnote上Debug
Boostnote基于Electron所以Boostnote上的开发者工具和Google Chrome相同。
您可以像这样或者按下快捷键`Ctrl+Shift+I`打开开发者工具:
![how_to_toggle_devTools](https://cloud.githubusercontent.com/assets/11307908/24343585/162187e2-127c-11e7-9c01-23578db03ecf.png)
开发者工具大概形如这样:
![Developer_Tools](https://cloud.githubusercontent.com/assets/11307908/24343545/eff9f3a6-127b-11e7-94cf-cb67bfda634a.png)
您可以在`console`选项卡中找到运行错误,
也可以像这样在`debugger`选项卡中设置断点去分步Debug
![debugger](https://cloud.githubusercontent.com/assets/11307908/24343879/9459efea-127d-11e7-9943-f60bf7f66d4a.png)
关于具体如何使用开发者工具,详见[Chrome 官档](https://developer.chrome.com/devtools)。如果您在中国大陆您可能需要一个VPN才能正常访问

View File

@@ -17,7 +17,8 @@ const mainWindow = new BrowserWindow({
webPreferences: { webPreferences: {
zoomFactor: 1.0, zoomFactor: 1.0,
blinkFeatures: 'OverlayScrollbars' blinkFeatures: 'OverlayScrollbars'
} },
icon: path.resolve(__dirname, '../resources/app.png')
}) })
const url = path.resolve(__dirname, './main.html') const url = path.resolve(__dirname, './main.html')

View File

@@ -1,6 +1,7 @@
{ {
"name": "boost", "name": "boost",
"version": "0.8.13", "productName": "Boostnote",
"version": "0.8.15",
"main": "index.js", "main": "index.js",
"description": "Boostnote", "description": "Boostnote",
"license": "GPL-3.0", "license": "GPL-3.0",
@@ -65,6 +66,8 @@
"markdown-it-emoji": "^1.1.1", "markdown-it-emoji": "^1.1.1",
"markdown-it-footnote": "^3.0.0", "markdown-it-footnote": "^3.0.0",
"markdown-it-imsize": "^2.0.1", "markdown-it-imsize": "^2.0.1",
"markdown-it-multimd-table": "^2.0.1",
"markdown-it-named-headers": "^0.0.4",
"md5": "^2.0.0", "md5": "^2.0.0",
"mixpanel": "^0.4.1", "mixpanel": "^0.4.1",
"moment": "^2.10.3", "moment": "^2.10.3",
@@ -76,6 +79,7 @@
"react-redux": "^4.4.5", "react-redux": "^4.4.5",
"redux": "^3.5.2", "redux": "^3.5.2",
"sander": "^0.5.1", "sander": "^0.5.1",
"striptags": "^2.2.1",
"superagent": "^1.2.0", "superagent": "^1.2.0",
"superagent-promise": "^1.0.3" "superagent-promise": "^1.0.3"
}, },
@@ -99,6 +103,7 @@
"eslint": "^3.13.1", "eslint": "^3.13.1",
"eslint-config-standard": "^6.2.1", "eslint-config-standard": "^6.2.1",
"eslint-config-standard-jsx": "^3.2.0", "eslint-config-standard-jsx": "^3.2.0",
"eslint-plugin-react": "^7.2.0",
"faker": "^3.1.0", "faker": "^3.1.0",
"grunt": "^0.4.5", "grunt": "^0.4.5",
"grunt-electron-installer": "^1.2.0", "grunt-electron-installer": "^1.2.0",

View File

@@ -1,16 +1,13 @@
<h1 align="center"> New:zap:
<a href="https://github.com/BoostIO/Boostnote"><img src="./resources/app.png" alt="Boostnote" width="180"></a>
<br> [Android and iOS apps](https://github.com/BoostIO/Boostnote-mobile) are released!
Boostnote
<br>
<br>
</h1>
<h4 align="center">Note-taking app for programmers. </h4>
<h5 align="center">macOS, Windows and Linux. Android and iOS apps will be released soon!</h5>
<h5 align="center">Built with Electron, React + Redux, Webpack and CSSModules</h5>
![Boostnote app screenshot](./resources/repository/top.png) ![Boostnote app screenshot](./resources/repository/top.png)
<h4 align="center">Note-taking app for programmers. </h4>
<h5 align="center">Apps available for Mac, Windows, Linux, Android and iOS!</h5>
<h5 align="center">Built with Electron, React + Redux, Webpack and CSSModules</h5>
[![Build Status](https://travis-ci.org/BoostIO/Boostnote.svg?branch=master)](https://travis-ci.org/BoostIO/Boostnote) [![Build Status](https://travis-ci.org/BoostIO/Boostnote.svg?branch=master)](https://travis-ci.org/BoostIO/Boostnote)
## Authors & Maintainers ## Authors & Maintainers
@@ -25,11 +22,11 @@
## Slack Group ## Slack Group
Let's talk about Boostnote's great features, new feature requests and things like Japanese gourmet. 🍣 <br> Let's talk about Boostnote's great features, new feature requests and things like Japanese gourmet. 🍣 <br>
[Join us](https://join.slack.com/t/boostnote-group/shared_invite/MjE3NDcwODQ3NTkwLTE1MDA4NjQ3ODktM2IxOTk4ZTNjYQ) [Join us](https://join.slack.com/t/boostnote-group/shared_invite/enQtMjQ0MjYxNTMxNjY5LTI0NWFkZDEyYWYxYWE0YTMyYjI4NzA2YjBlNmFmOGVhNGFjY2I1MTNmZWJjYmMxYTdkM2VjNWNjYTFiYWQ3ZmQ)
## More Information ## More Information
* [Website](https://boostnote.io) * [Website](https://boostnote.io)
* [Boostnote Team](https://boostnote.io/team/) : Boostnote for the creative hacker teams. Share your markdown notes and snippets instantly with your team. **We will release it at August!** 🏃💨 * [10hz](https://boostnote.io/team/) : Boostnote for the creative hacker teams. Share your markdown notes and snippets instantly with your team. **We will release it at October!** 🏃💨
* [Support us via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉 * [Support us via Bountysource](https://salt.bountysource.com/teams/boostnote) : Thank you for your support 🎉
* [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md) : Development configurations for Boostnote 🚀 * [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md) : Development configurations for Boostnote 🚀
* Copyright (C) 2017 Maisin&Co. * Copyright (C) 2017 Maisin&Co.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 426 KiB

After

Width:  |  Height:  |  Size: 250 KiB

633
yarn.lock

File diff suppressed because it is too large Load Diff