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

Compare commits

...

95 Commits

Author SHA1 Message Date
Masahide Morio
9d98f0cb03 for v0.9 2018-02-04 05:51:39 +09:00
Masahide Morio
3503233631 Merge remote-tracking branch 'upstream/master' 2018-02-04 05:40:24 +09:00
Masahide Morio
c39393c453 for Windows 32bit 2018-02-04 05:40:15 +09:00
Junyoung Choi
8e1bf48cd1 Close immediately on windows 2018-02-04 00:59:54 +09:00
Junyoung Choi
8dd82e1a3b Disable uglify 2018-02-04 00:12:38 +09:00
Junyoung Choi
4418bfe965 v0.9.0 2018-02-03 23:50:49 +09:00
Junyoung Choi
39c4d710bc Remove unnecessary logging 2018-02-03 23:45:46 +09:00
Junyoung Choi (Sai)
51a8c47afd Discard finder (#1497)
* Discard finder

* Upgrade electron

* Discard anything related with finder

* Fix lint errors

* Run test serial

* Test on v6

* Test on v6 only
2018-02-03 23:39:53 +09:00
Kazz Yokomizo
922570bb5c Merge pull request #1495 from BoostIO/fix-todo-style
Fix percentage bar in markdown preview
2018-02-03 16:32:37 +09:00
Kazu Yokomizo
ca282d5635 Fix percentage bar in markdown preview 2018-02-03 16:32:02 +09:00
Junyoung Choi
ff67043210 Bump version 2018-02-03 15:52:51 +09:00
Junyoung Choi
31da231c1c Rollback .travis.yml 2018-02-03 15:28:19 +09:00
Junyoung Choi
eb698a7430 Fix lint error 2018-02-03 15:10:16 +09:00
Junyoung Choi
03be809ba9 Text stable version only
The current version of boostnote doesn't support the latest stable version, v9.x
2018-02-03 15:03:33 +09:00
Junyoung Choi
69601bf15a Fix but: line numbers of editor isnt applied properly 2018-02-03 15:02:26 +09:00
Junyoung Choi
7cad3d403b Discard unnecessary logging 2018-02-03 15:00:06 +09:00
Junyoung Choi (Sai)
cc84af3346 Merge pull request #1458 from cyalins/cyalins-patch-1
Improved overall wording and grammar of preferences
2018-02-03 14:27:55 +09:00
Junyoung Choi
33ef54a162 Fix lint errors 2018-02-03 14:16:26 +09:00
Junyoung Choi (Sai)
ac43ff886a Merge pull request #1494 from Paalon/katex_update
Update KaTeX library from 0.7.1 to 0.8.3
2018-02-03 13:57:30 +09:00
Junyoung Choi (Sai)
a64f73ca0c Merge pull request #879 from xxdavid/feature-editor-line-lines
Make line numbers in the editor optional
2018-02-03 13:57:00 +09:00
Paalon
314477d2fc Update yarn.lock 2018-02-02 17:01:15 +09:00
Paalon
c63fc93daa Update katex from 0.7.1 to 0.8.3. 2018-02-02 16:45:33 +09:00
Kazz Yokomizo
2183c4bda6 Merge pull request #1480 from allejo/feature-preview-scroll
Allow preview area to scroll past end of file
2018-01-31 18:01:32 +09:00
Kazz Yokomizo
6ba91c1515 Merge pull request #1472 from Antogin/feat/add-ability-to-clone-note
Feat/add ability to clone note
2018-01-31 17:55:46 +09:00
Vladimir Jimenez
d0559c16b5 Pass correct preview prop to MarkdownEditor 2018-01-30 07:42:16 -08:00
Kazz Yokomizo
eb693f7b48 Merge pull request #1481 from andyklimczak/1476-tag-check
Remove leading # when creating tag
2018-01-30 21:50:12 +09:00
Georges Indrianjafy
ef5639ff4b chore: removing space 2018-01-30 11:56:59 +02:00
Georges Indrianjafy
34a335797c chore: remove trailing space 2018-01-30 11:49:39 +02:00
Georges Indrianjafy
edda3a4d23 chore: cleanup 2018-01-30 11:45:47 +02:00
Georges Indrianjafy
184839423f fix(NoteList): remove router 2018-01-30 10:37:58 +02:00
Kazz Yokomizo
c0f3600a52 Merge pull request #1484 from BoostIO/fix-#1477
Fix #1477
2018-01-30 01:00:13 -05:00
Kazu Yokomizo
2b1302aa07 Fix #1477 2018-01-30 14:38:53 +09:00
Andy Klimczak
470c071344 Remove leading # when creating tag
- Remove leading # from tags that are created with leading #
- Convenience method for users who tend to type them, but did not want a
tag with double #
- If a user wants a tag with a leading #, then can double it (ie: ##OfPeople)
2018-01-29 20:42:59 -05:00
Vladimir Jimenez
4bd639c6c4 Allow preview area to scroll past end of file 2018-01-29 17:11:42 -08:00
Georges Indrianjafy
4cb7e63421 chore: clean up 2018-01-29 09:25:01 +02:00
Georges Indrianjafy
9f14a503d8 fix(history): use hashHistory 2018-01-29 09:24:12 +02:00
Georges Indrianjafy
d5da6de86c fix(NoteList): fix router issue 2018-01-29 09:13:09 +02:00
Georges Indrianjafy
4c2b233722 fix: resolve ci issues 2018-01-27 17:45:50 +02:00
Georges Indrianjafy
ca5b1eea13 chore: removing console.log 2018-01-27 17:33:22 +02:00
Georges Indrianjafy
614e9b6d55 feat(NoteList): add ability to clone note 2018-01-27 14:16:29 +02:00
cyalins
27b2530b8d Undoing an accidental edit 2018-01-26 21:12:10 +11:00
Kazz Yokomizo
2259167200 Merge pull request #1464 from BoostIO/fix-editor-lock-btn
Fix the editor lock button layout
2018-01-25 13:38:33 -05:00
Kazu Yokomizo
2e05214828 Fix the editor lock button layout 2018-01-25 13:30:36 -05:00
Kazz Yokomizo
cfb996039b Merge pull request #1453 from BoostIO/fix-info-right-layout
WIP - Fix info right buttons layout
2018-01-25 09:37:24 -05:00
Kazz Yokomizo
44c4d56214 Merge pull request #1457 from stevequinn/1238
Allows keyboard text selection in Finder search box
2018-01-25 09:34:59 -05:00
cyalins
8e6be91f7c Improved consistency of wording in Storage tab 2018-01-25 13:57:15 +11:00
cyalins
00816fb2c8 Improved clarity of wording in UI Tab 2018-01-25 13:56:11 +11:00
cyalins
535356b77f Improved clarity of tab titles 2018-01-25 13:53:50 +11:00
cyalins
5e558746ce Reworded Hotkey preferences 2018-01-25 13:52:04 +11:00
cyalins
f7bd52ac0c Improved clarity of crowdfunding message 2018-01-25 13:46:08 +11:00
cyalins
9165f518a9 Improved wording of data collection 2018-01-25 13:41:24 +11:00
Steve Quinn
01605aa221 Allows keyboard text selection in Finder search box 2018-01-25 13:27:43 +11:00
cyalins
8b0b29c424 Improved clarity of wording 2018-01-25 13:27:02 +11:00
Kazu Yokomizo
7a116966fa Add tooltip to full-screen-btn on the snippet note detail 2018-01-24 16:16:14 -05:00
Kazu Yokomizo
e7e8f11a74 Fix tooltips position 2018-01-24 16:08:44 -05:00
Kazu Yokomizo
f235d832d5 Fix note detail layout 2018-01-24 16:03:50 -05:00
Kazu Yokomizo
7730b5e20b Change size of icons on note detail 2018-01-24 15:39:27 -05:00
Kazu Yokomizo
8c3ba4ce48 Fix infopanel 2018-01-24 15:26:45 -05:00
Kazu Yokomizo
e9a126f586 Fix multiple colors 2018-01-24 15:19:13 -05:00
Kazu Yokomizo
097e7d2ff2 Fix tooltip 2018-01-24 15:13:45 -05:00
Kazu Yokomizo
81265f1238 Reorder of buttons 2018-01-23 21:02:19 -05:00
Kazu Yokomizo
2b507e6e20 Zoom button to display none 2018-01-23 20:57:57 -05:00
Kazu Yokomizo
747d3a8f13 Fix note detail width 2018-01-23 20:55:29 -05:00
Kazu Yokomizo
30f6f07434 Fix info right buttons layout 2018-01-23 20:50:48 -05:00
Kazz Yokomizo
6de5488a15 Merge pull request #1451 from BoostIO/update-readme
Update readme
2018-01-23 11:50:32 -05:00
Kazz Yokomizo
5413647166 Update readme 2018-01-23 11:46:22 -05:00
Kazz Yokomizo
e83fe73b18 Merge pull request #1271 from mslourens/utf8-uml
convert uml to utf8 before converting to base64
2018-01-17 09:47:56 -05:00
Kazz Yokomizo
87a289ec65 Merge pull request #1429 from yamash723/fix-markdown-list-link-style
Remove inline-style from markdown link list
2018-01-17 09:33:51 -05:00
yamash723
8a0a118dba Remove inline-style from markdown link list 2018-01-17 16:32:43 +09:00
Masahide Morio
564cc80ef7 for Windows 32bit 2018-01-17 01:01:45 +09:00
Kazz Yokomizo
687126ce87 Merge pull request #1419 from mslourens/html-export-encoding
added encoding meta tag
2018-01-16 08:06:30 -05:00
Kazz Yokomizo
8a05d577da Merge pull request #1425 from BoostIO/fixed-save-button
make save button position:fixed
2018-01-16 08:05:08 -05:00
Kazz Yokomizo
4c3ebfc0f8 Merge pull request #1418 from mslourens/import-note-name
name note to imported file
2018-01-16 08:04:25 -05:00
Sosuke Suzuki
6093f25f9a make save button position:fixed 2018-01-16 19:37:01 +09:00
Maurits Lourens
ecab68d676 removed unused imports 2018-01-16 10:09:02 +01:00
Masahide.MORIO
77f7144fbf test 2018-01-16 10:01:20 +09:00
Maurits Lourens
1cb4f37c95 moved the import outside the use config section 2018-01-15 22:27:38 +01:00
Maurits Lourens
14318528b9 added encoding meta tag 2018-01-15 22:18:23 +01:00
Maurits Lourens
9c0e1f8f1a name note to imported file 2018-01-15 21:33:17 +01:00
Kazz Yokomizo
2034ce9e4d Merge pull request #1416 from mslourens/copy-note-link
added button for copy note link
2018-01-15 15:17:17 -05:00
Maurits Lourens
657489caf6 added button for copy note link 2018-01-15 21:01:18 +01:00
Kazz Yokomizo
94be3d1fe5 Merge pull request #1413 from BoostIO/fix-folded-layout
Fix the folded layout on side bar
2018-01-15 08:39:32 -05:00
Kazz Yokomizo
f6eae41cee Merge pull request #1412 from BoostIO/fix-1409
Fix the Solarized Dark Styling
2018-01-15 08:34:04 -05:00
Kazu Yokomizo
69c64434e3 Fix the folded layout on side bar 2018-01-15 08:33:23 -05:00
Kazz Yokomizo
256cabfce1 Merge pull request #1411 from BoostIO/change-ctrl-icon-windows
Change the control icon on Windows
2018-01-15 08:26:41 -05:00
Kazu Yokomizo
e8b8272cf9 Fix #1409 - Fix the Solarized Dark Styling 2018-01-15 08:22:02 -05:00
Kazu Yokomizo
bd5ab4881c Change the control icon on Windows 2018-01-15 07:57:36 -05:00
Junyoung Choi (Sai)
9630744bdb Merge pull request #1395 from BoostIO/feature-v0-8-20
v0.8.20
2018-01-13 19:43:49 +09:00
David Pavlík
da1098e441 Merge branch 'master' into feature-editor-line-lines 2017-12-23 23:06:26 +01:00
David Pavlík
85065357e2 Make the option to disable line numbers in editor affect snippet notes too 2017-12-23 22:52:50 +01:00
David Pavlík
1f5f6c3b0e Rename 'lineNumber' to 'displayLineNumbers' 2017-12-23 22:51:38 +01:00
Maurits Lourens
6906c0ab0d changed var into const 2017-12-13 17:16:28 +01:00
Maurits Lourens
4cdfc738c0 forgot to run eslint (again) 2017-12-11 15:14:02 +01:00
Maurits Lourens
46d46f21e4 convert uml to utf8 before converting to base64 2017-12-11 15:02:42 +01:00
David Pavlík
7a4258bb20 Make line numbers in the editor optional 2017-09-20 22:34:18 +02:00
81 changed files with 1525 additions and 2029 deletions

View File

@@ -10,7 +10,6 @@
"theme": "monokai"
},
"hotkey": {
"toggleFinder": "Cmd + Alt + S",
"toggleMain": "Cmd + Alt + L"
},
"isSideNavFolded": false,

View File

@@ -1,7 +1,6 @@
language: node_js
node_js:
- stable
- lts/*
- 6
script:
- npm run lint && npm run test
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" ]]; then npm install -g grunt npm@5.2 && grunt pre-build; fi'
@@ -18,3 +17,4 @@ deploy:
script: if [ ${TRAVIS_NODE_VERSION} = "stable" ];then docker run -v $(pwd):$(pwd) -t snapcore/snapcraft sh -c "apt update -qq
&& cd $(pwd) && snapcraft && snapcraft push *.snap --release edge"; fi
skip_cleanup: true

View File

@@ -51,9 +51,10 @@ export default class CodeEditor extends React.Component {
componentDidMount () {
this.value = this.props.value
this.editor = CodeMirror(this.refs.root, {
value: this.props.value,
lineNumbers: true,
lineNumbers: this.props.displayLineNumbers,
lineWrapping: true,
theme: this.props.theme,
indentUnit: this.props.indentSize,
@@ -71,7 +72,7 @@ export default class CodeEditor extends React.Component {
if (cm.somethingSelected()) cm.indentSelection('add')
else {
const tabs = cm.getOption('indentWithTabs')
if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)\] )?$/)) {
if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)] )?$/)) {
cm.execCommand('goLineStart')
if (tabs) {
cm.execCommand('insertTab')
@@ -156,6 +157,10 @@ export default class CodeEditor extends React.Component {
this.editor.setOption('indentWithTabs', this.props.indentType !== 'space')
}
if (prevProps.displayLineNumbers !== this.props.displayLineNumbers) {
this.editor.setOption('lineNumbers', this.props.displayLineNumbers)
}
if (prevProps.scrollPastEnd !== this.props.scrollPastEnd) {
this.editor.setOption('scrollPastEnd', this.props.scrollPastEnd)
}
@@ -230,7 +235,7 @@ export default class CodeEditor extends React.Component {
if (!dataTransferItem.type.match('image')) return
const blob = dataTransferItem.getAsFile()
const reader = new FileReader()
const reader = new window.FileReader()
let base64data
reader.readAsDataURL(blob)

View File

@@ -242,6 +242,7 @@ class MarkdownEditor extends React.Component {
fontSize={editorFontSize}
indentType={config.editor.indentType}
indentSize={editorIndentSize}
displayLineNumbers={config.editor.displayLineNumbers}
scrollPastEnd={config.editor.scrollPastEnd}
storageKey={storageKey}
onChange={(e) => this.handleChange(e)}
@@ -260,7 +261,7 @@ class MarkdownEditor extends React.Component {
codeBlockFontFamily={config.editor.fontFamily}
lineNumber={config.preview.lineNumber}
indentSize={editorIndentSize}
scrollPastEnd={config.editor.scrollPastEnd}
scrollPastEnd={config.preview.scrollPastEnd}
ref='preview'
onContextMenu={(e) => this.handleContextMenu(e)}
tabIndex='0'

View File

@@ -24,7 +24,7 @@ const appPath = 'file://' + (process.env.NODE_ENV === 'production'
? app.getAppPath()
: path.resolve())
function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber) {
function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd) {
return `
@font-face {
font-family: 'Lato';
@@ -48,6 +48,7 @@ ${markdownStyle}
body {
font-family: '${fontFamily.join("','")}';
font-size: ${fontSize}px;
${scrollPastEnd && 'padding-bottom: 90vh;'}
}
code {
font-family: '${codeBlockFontFamily.join("','")}';
@@ -226,6 +227,7 @@ export default class MarkdownPreview extends React.Component {
<link rel="stylesheet" href="${appPath}/node_modules/katex/dist/katex.min.css">
<link rel="stylesheet" href="${appPath}/node_modules/codemirror/lib/codemirror.css">
<link rel="stylesheet" id="codeTheme">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
`
this.rewriteIframe()
this.applyStyle()
@@ -260,14 +262,15 @@ export default class MarkdownPreview extends React.Component {
prevProps.codeBlockTheme !== this.props.codeBlockTheme ||
prevProps.lineNumber !== this.props.lineNumber ||
prevProps.showCopyNotification !== this.props.showCopyNotification ||
prevProps.theme !== this.props.theme) {
prevProps.theme !== this.props.theme ||
prevProps.scrollPastEnd !== this.props.scrollPastEnd) {
this.applyStyle()
this.rewriteIframe()
}
}
applyStyle () {
const { fontSize, lineNumber, codeBlockTheme } = this.props
const { fontSize, lineNumber, codeBlockTheme, scrollPastEnd } = this.props
let { fontFamily, codeBlockFontFamily } = this.props
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
? fontFamily.split(',').map(fontName => fontName.trim()).concat(defaultFontFamily)
@@ -277,7 +280,7 @@ export default class MarkdownPreview extends React.Component {
: defaultCodeBlockFontFamily
this.setCodeTheme(codeBlockTheme)
this.getWindow().document.getElementById('style').innerHTML = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, lineNumber)
this.getWindow().document.getElementById('style').innerHTML = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd)
}
setCodeTheme (theme) {

View File

@@ -62,6 +62,7 @@ class MarkdownSplitEditor extends React.Component {
keyMap={config.editor.keyMap}
fontFamily={config.editor.fontFamily}
fontSize={editorFontSize}
displayLineNumbers={config.editor.displayLineNumbers}
indentType={config.editor.indentType}
indentSize={editorIndentSize}
scrollPastEnd={config.editor.scrollPastEnd}
@@ -78,6 +79,7 @@ class MarkdownSplitEditor extends React.Component {
codeBlockTheme={config.preview.codeBlockTheme}
codeBlockFontFamily={config.editor.fontFamily}
lineNumber={config.preview.lineNumber}
scrollPastEnd={config.preview.scrollPastEnd}
ref='preview'
tabInde='0'
value={value}

View File

@@ -92,7 +92,6 @@ body[data-theme="white"]
color $ui-inactive-text-color
.menu-button--active
@extend .menu-button
color #e74c3c
background-color $ui-button--active-backgroundColor
.menu-button-label
@@ -109,7 +108,6 @@ body[data-theme="white"]
color $ui-text-color
.menu-button-star--active
@extend .menu-button
color #F9BF3B
background-color $ui-button--active-backgroundColor
.menu-button-label
@@ -126,7 +124,6 @@ body[data-theme="white"]
color $ui-text-color
.menu-button-trash--active
@extend .menu-button
color #5D9E36
background-color $ui-button--active-backgroundColor
.menu-button-label

View File

@@ -1,6 +1,6 @@
.percentageBar
position absolute
top 50px
top 72px
right 0px
left 0px
background-color #DADFE1

View File

@@ -105,7 +105,6 @@ a
border-radius 5px
margin -5px
transition .1s
display inline-block
img
vertical-align sub
&:hover

View File

@@ -1,156 +0,0 @@
$search-height = 50px
$nav-width = 175px
$list-width = 250px
.root
absolute top left right bottom
.search
height $search-height
padding 10px
box-sizing border-box
border-bottom $ui-border
text-align center
.search-input
height 30px
width 100%
margin 0 auto
font-size 18px
border none
outline none
text-align center
background-color transparent
.result
absolute left right bottom
top $search-height
background-color $ui-noteDetail-backgroundColor
.result-nav
user-select none
absolute left top bottom
width $nav-width
background-color $ui-backgroundColor
.result-nav-filter
margin-bottom 10px
.result-nav-filter-option
height 25px
line-height 25px
padding 0 10px
label
cursor pointer
.result-nav-menu
navButtonColor()
height 32px
padding 0 10px
font-size 14px
width 100%
outline none
text-align left
line-height 32px
box-sizing border-box
cursor pointer
.result-nav-menu--active
@extend .result-nav-menu
background-color $ui-button--active-backgroundColor
color $ui-button--active-color
&:hover
background-color $ui-button--active-backgroundColor
.result-nav-storageList
absolute bottom left right
top 110px + 32px + 10px + 10px + 20px
overflow-y auto
.result-list
user-select none
absolute top bottom
left $nav-width
width $list-width
box-sizing border-box
overflow-y auto
box-shadow 2px 0 15px -8px #b1b1b1
z-index 1
.result-detail
absolute top bottom right
left $nav-width + $list-width
background-color $ui-noteDetail-backgroundColor
body[data-theme="dark"]
.root
background-color $ui-dark-backgroundColor
.search
border-color $ui-dark-borderColor
.search-input
color $ui-dark-text-color
.result
background-color $ui-dark-noteList-backgroundColor
.result-nav
background-color $ui-dark-backgroundColor
label
color $ui-dark-text-color
.result-nav-menu
navDarkButtonColor()
.result-nav-menu--active
background-color $ui-dark-button--active-backgroundColor
color $ui-dark-button--active-color
&:hover
background-color $ui-dark-button--active-backgroundColor
.result-list
border-color $ui-dark-borderColor
box-shadow none
top 0
.result-detail
absolute top bottom right
left $nav-width + $list-width
background-color $ui-dark-noteDetail-backgroundColor
body[data-theme="solarized-dark"]
.root
background-color $ui-solarized-dark-backgroundColor
.search
border-color $ui-solarized-dark-borderColor
.search-input
color $ui-dark-text-color
.result
background-color $ui-solarized-dark-backgroundColor
.result-nav
background-color $ui-solarized-dark-backgroundColor
label
color $ui-dark-text-color
.result-nav-menu
navDarkButtonColor()
.result-nav-menu--active
background-color $ui-solarized-dark-button-backgroundColor
color $ui-dark-button--active-color
&:hover
background-color $ui-dark-button--active-backgroundColor
.result-list
border-color $ui-solarized-dark-borderColor
box-shadow none
top 0
.result-detail
absolute top bottom right
left $nav-width + $list-width
background-color $ui-solarized-dark-backgroundColor

View File

@@ -1,211 +0,0 @@
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './NoteDetail.styl'
import MarkdownPreview from 'browser/components/MarkdownPreview'
import MarkdownEditor from 'browser/components/MarkdownEditor'
import CodeEditor from 'browser/components/CodeEditor'
import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
import { findStorage } from 'browser/lib/findStorage'
const electron = require('electron')
const { clipboard } = electron
const path = require('path')
function pass (name) {
switch (name) {
case 'ejs':
return 'Embedded Javascript'
case 'html_ruby':
return 'Embedded Ruby'
case 'objectivec':
return 'Objective C'
case 'text':
return 'Plain Text'
default:
return name
}
}
function notify (title, options) {
if (global.process.platform === 'win32') {
options.icon = path.join('file://', global.__dirname, '../../resources/app.png')
}
return new window.Notification(title, options)
}
class NoteDetail extends React.Component {
constructor (props) {
super(props)
this.state = {
snippetIndex: 0
}
}
componentWillReceiveProps (nextProps) {
if (nextProps.note !== this.props.note) {
this.setState({
snippetIndex: 0
}, () => {
if (nextProps.note.type === 'SNIPPET_NOTE') {
nextProps.note.snippets.forEach((snippet, index) => {
this.refs['code-' + index].reload()
})
}
})
}
}
selectPriorSnippet () {
const { note } = this.props
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
this.setState({
snippetIndex: (this.state.snippetIndex + note.snippets.length - 1) % note.snippets.length
})
}
}
selectNextSnippet () {
const { note } = this.props
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
this.setState({
snippetIndex: (this.state.snippetIndex + 1) % note.snippets.length
})
}
}
saveToClipboard () {
const { note } = this.props
if (note.type === 'MARKDOWN_NOTE') {
clipboard.writeText(note.content)
} else {
clipboard.writeText(note.snippets[this.state.snippetIndex].content)
}
notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!',
silent: true
})
}
handleTabButtonClick (e, index) {
this.setState({
snippetIndex: index
})
}
render () {
const { note, config } = this.props
if (note == null) {
return (
<div styleName='root' />
)
}
let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
const storage = findStorage(note.storage)
if (note.type === 'SNIPPET_NOTE') {
const tabList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
return <div styleName={isActive
? 'tabList-item--active'
: 'tabList-item'
}
key={index}
>
<button styleName='tabList-item-button'
onClick={(e) => this.handleTabButtonClick(e, index)}
>
{snippet.name.trim().length > 0
? snippet.name
: <span styleName='tabList-item-unnamed'>
Unnamed
</span>
}
</button>
</div>
})
const viewList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
let syntax = CodeMirror.findModeByName(pass(snippet.mode))
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
return <div styleName='tabView'
key={index}
style={{zIndex: isActive ? 5 : 4}}
>
{snippet.mode === 'markdown'
? <MarkdownEditor styleName='tabView-content'
config={config}
value={snippet.content}
ref={'code-' + index}
storageKey={note.storage}
/>
: <CodeEditor styleName='tabView-content'
mode={snippet.mode}
value={snippet.content}
theme={config.editor.theme}
fontFamily={config.editor.fontFamily}
fontSize={editorFontSize}
indentType={config.editor.indentType}
indentSize={editorIndentSize}
keyMap={config.editor.keyMap}
scrollPastEnd={config.editor.scrollPastEnd}
readOnly
ref={'code-' + index}
/>
}
</div>
})
return (
<div styleName='root'>
<div styleName='description'>
<textarea styleName='description-textarea'
style={{
fontFamily: config.preview.fontFamily,
fontSize: parseInt(config.preview.fontSize, 10)
}}
ref='description'
placeholder='Description...'
value={note.description}
readOnly
/>
</div>
<div styleName='tabList'>
{tabList}
</div>
{viewList}
</div>
)
}
return (
<MarkdownPreview styleName='root'
theme={config.ui.theme}
fontSize={config.preview.fontSize}
fontFamily={config.preview.fontFamily}
codeBlockTheme={config.preview.codeBlockTheme}
codeBlockFontFamily={config.editor.fontFamily}
lineNumber={config.preview.lineNumber}
indentSize={editorIndentSize}
value={note.content}
showCopyNotification={config.ui.showCopyNotification}
storagePath={storage.path}
/>
)
}
}
NoteDetail.propTypes = {
}
export default CSSModules(NoteDetail, styles)

View File

@@ -1,129 +0,0 @@
@import('../main/Detail/DetailVars.styl')
.root
absolute top bottom left right
bottom 30px
margin 0 25px
height 100%
width 365px
background-color $ui-noteDetail-backgroundColor
.description
absolute top left right
height 80px
box-sizing border-box
.description-textarea
display block
height 100%
width 100%
resize none
border none
padding 10px
line-height 1.6
box-sizing border-box
background-color $ui-noteDetail-backgroundColor
.tabList
absolute left right
top 80px
box-sizing border-box
height 30px
display flex
background-color $ui-noteDetail-backgroundColor
.tabList-item
position relative
flex 1
overflow hidden
&:hover
background-color $ui-button--hover-backgroundColorg
.tabList-item--active
@extend .tabList-item
border-bottom $ui-border
.tabList-item-button
width 100%
height 29px
overflow ellipsis
text-align left
padding-right 30px
padding-left 10px
border none
background-color transparent
transition 0.15s
&:hover
background-color $ui-button--hover-backgroundColor
.tabView
absolute left right bottom
top 130px
.tabView-content
absolute top left right bottom
box-sizing border-box
height 100%
width 100%
body[data-theme="dark"]
.root
background-color $ui-dark-noteDetail-backgroundColor
.description
border-color $ui-dark-borderColor
background-color $ui-dark-noteDetail-backgroundColor
.description-textarea
background-color $ui-dark-noteDetail-backgroundColor
color white
.tabList
background-color $ui-dark-noteDetail-backgroundColor
.tabList-item
border-color $ui-dark-borderColor
&:hover
background-color $ui-dark-button--hover-backgroundColor
.tabList-item-button
border none
color $ui-dark-text-color
background-color transparent
transition color background-color 0.15s
border-left 4px solid transparent
&:hover
color white
background-color $ui-dark-button--hover-backgroundColor
body[data-theme="solarized-dark"]
.root
background-color $ui-solarized-dark-backgroundColor
.description
border-color $ui-dark-borderColor
background-color $ui-solarized-dark-backgroundColor
.description-textarea
background-color $ui-solarized-dark-backgroundColor
color white
.tabList
background-color $ui-solarized-dark-backgroundColor
.tabList-item
border-color $ui-dark-borderColor
&:hover
background-color $ui-dark-button--hover-backgroundColor
.tabList-item-button
border none
color $ui-dark-text-color
background-color transparent
transition color background-color 0.15s
border-left 4px solid transparent
&:hover
color white
background-color $ui-dark-button--hover-backgroundColor

View File

@@ -1,90 +0,0 @@
import React from 'react'
import NoteItem from 'browser/components/NoteItem'
import moment from 'moment'
class NoteList extends React.Component {
constructor (props) {
super(props)
this.state = {
range: 0
}
}
componentWillReceiveProps (nextProps) {
if (this.props.search !== nextProps.search) {
this.resetScroll()
}
}
componentDidUpdate () {
const { index } = this.props
if (index > -1) {
const list = this.refs.root
const item = list.childNodes[index]
if (item == null) return null
const overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0
if (overflowBelow) {
list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight
}
const overflowAbove = list.scrollTop > item.offsetTop
if (overflowAbove) {
list.scrollTop = item.offsetTop
}
}
}
resetScroll () {
this.refs.root.scrollTop = 0
this.setState({
range: 0
})
}
handleScroll (e) {
const { notes } = this.props
if (e.target.offsetHeight + e.target.scrollTop > e.target.scrollHeight - 100 && notes.length > this.state.range * 10 + 10) {
this.setState({
range: this.state.range + 1
})
}
}
render () {
const { notes, index } = this.props
const notesList = notes
.slice(0, 10 + 10 * this.state.range)
.map((note, _index) => {
const isActive = (index === _index)
const key = `${note.storage}-${note.key}`
const dateDisplay = moment(note.updatedAt).fromNow()
return (
<NoteItem
isActive={isActive}
note={note}
dateDisplay={dateDisplay}
key={key}
handleNoteClick={(e) => this.props.handleNoteClick(e, _index)}
/>
)
})
return (
<div className={this.props.className}
onScroll={(e) => this.handleScroll(e)}
ref='root'
>
{notesList}
</div>
)
}
}
NoteList.propTypes = {
}
export default NoteList

View File

@@ -1,77 +0,0 @@
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './StorageSection.styl'
import StorageItem from 'browser/components/StorageItem'
class StorageSection extends React.Component {
constructor (props) {
super(props)
this.state = {
isOpen: true
}
}
handleToggleButtonClick (e) {
this.setState({
isOpen: !this.state.isOpen
})
}
handleHeaderClick (e) {
const { storage } = this.props
this.props.handleStorageButtonClick(e, storage.key)
}
handleFolderClick (e, folder) {
const { storage } = this.props
this.props.handleFolderButtonClick(e, storage.key, folder.key)
}
render () {
const { storage, filter } = this.props
const folderList = storage.folders
.map(folder => (
<StorageItem
key={folder.key}
isActive={filter.type === 'FOLDER' && filter.folder === folder.key && filter.storage === storage.key}
handleButtonClick={(e) => this.handleFolderClick(e, folder)}
folderName={folder.name}
folderColor={folder.color}
isFolded={false}
/>
))
return (
<div styleName='root'>
<div styleName='header'>
<button styleName='header-toggleButton'
onClick={(e) => this.handleToggleButtonClick(e)}
>
<i className={this.state.isOpen
? 'fa fa-caret-down'
: 'fa fa-caret-right'
}
/>
</button>
<button styleName={filter.type === 'STORAGE' && filter.storage === storage.key
? 'header-name--active'
: 'header-name'
}
onClick={(e) => this.handleHeaderClick(e)}
>{storage.name}</button>
</div>
{this.state.isOpen &&
<div styleName='folderList'>
{folderList}
</div>
}
</div>
)
}
}
StorageSection.propTypes = {
}
export default CSSModules(StorageSection, styles)

View File

@@ -1,85 +0,0 @@
.root
position relative
.header
height 26px
.header-toggleButton
absolute top left
width 25px
height 26px
navButtonColor()
border none
outline none
.header-name
display block
height 26px
navButtonColor()
padding 0 10px 0 25px
font-size 14px
width 100%
text-align left
line-height 26px
box-sizing border-box
cursor pointer
outline none
.header-name--active
@extend .header-name
background-color $ui-button--active-backgroundColor
color $ui-button--active-color
&:hover
background-color $ui-button--active-backgroundColor
.folderList-item
display block
width 100%
height 26px
navButtonColor()
padding 0 10px 0 25px
font-size 14px
width 100%
text-align left
line-height 26px
box-sizing border-box
cursor pointer
outline none
padding 0 10px
margin 2px 0
height 26px
line-height 26px
border-width 0 0 0 6px
border-style solid
border-color transparent
.folderList-item--active
@extend .folderList-item
background-color $ui-button--active-backgroundColor
color $ui-button--active-color
&:hover
background-color $ui-button--active-backgroundColor
body[data-theme="dark"]
.header-toggleButton
navDarkButtonColor()
.header-name
navDarkButtonColor()
.header-name--active
@extend .header-name
background-color $ui-button--active-backgroundColor
color $ui-button--active-color
&:hover
background-color $ui-button--active-backgroundColor
.folderList-item
navDarkButtonColor()
border-width 0 0 0 6px
border-style solid
border-color transparent
.folderList-item--active
@extend .folderList-item
background-color $ui-button--active-backgroundColor
color $ui-button--active-color
&:hover
background-color $ui-button--active-backgroundColor

View File

@@ -1,357 +0,0 @@
import PropTypes from 'prop-types'
import React from 'react'
import ReactDOM from 'react-dom'
import { connect, Provider } from 'react-redux'
import _ from 'lodash'
import store from './store'
import CSSModules from 'browser/lib/CSSModules'
import styles from './FinderMain.styl'
import StorageSection from './StorageSection'
import NoteList from './NoteList'
import NoteDetail from './NoteDetail'
import SideNavFilter from 'browser/components/SideNavFilter'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
require('!!style!css!stylus?sourceMap!../main/global.styl')
require('../lib/customMeta')
require('./ipcClient.js')
const electron = require('electron')
const { remote } = electron
const { Menu } = remote
function hideFinder () {
const finderWindow = remote.getCurrentWindow()
if (global.process.platform === 'win32') {
finderWindow.blur()
finderWindow.hide()
}
if (global.process.platform === 'darwin') {
Menu.sendActionToFirstResponder('hide:')
}
remote.getCurrentWindow().hide()
}
require('!!style!css!stylus?sourceMap!../styles/finder/index.styl')
class FinderMain extends React.Component {
constructor (props) {
super(props)
this.state = {
search: '',
index: 0,
filter: {
includeSnippet: true,
includeMarkdown: false,
type: 'ALL',
storage: null,
folder: null
}
}
this.focusHandler = (e) => this.handleWindowFocus(e)
this.blurHandler = (e) => this.handleWindowBlur(e)
}
componentDidMount () {
this.refs.search.focus()
window.addEventListener('focus', this.focusHandler)
window.addEventListener('blur', this.blurHandler)
}
componentWillUnmount () {
window.removeEventListener('focus', this.focusHandler)
window.removeEventListener('blur', this.blurHandler)
}
handleWindowFocus (e) {
this.refs.search.focus()
}
handleWindowBlur (e) {
this.setState({
search: ''
})
}
handleKeyDown (e) {
this.refs.search.focus()
if (e.keyCode === 9) {
if (e.shiftKey) {
this.refs.detail.selectPriorSnippet()
} else {
this.refs.detail.selectNextSnippet()
}
e.preventDefault()
}
if (e.keyCode === 38) {
this.selectPrevious()
e.preventDefault()
}
if (e.keyCode === 40) {
this.selectNext()
e.preventDefault()
}
if (e.keyCode === 13) {
this.refs.detail.saveToClipboard()
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('COPY_FINDER')
hideFinder()
e.preventDefault()
}
if (e.keyCode === 27) {
hideFinder()
e.preventDefault()
}
if (e.keyCode === 91 || e.metaKey) {
return
}
}
handleSearchChange (e) {
this.setState({
search: e.target.value,
index: 0
})
}
selectArticle (article) {
this.setState({currentArticle: article})
}
selectPrevious () {
if (this.state.index > 0) {
this.setState({
index: this.state.index - 1
})
}
}
selectNext () {
if (this.state.index < this.noteCount - 1) {
this.setState({
index: this.state.index + 1
})
}
}
handleOnlySnippetCheckboxChange (e) {
const { filter } = this.state
filter.includeSnippet = e.target.checked
this.setState({
filter: filter,
index: 0
}, () => {
this.refs.search.focus()
})
}
handleOnlyMarkdownCheckboxChange (e) {
const { filter } = this.state
filter.includeMarkdown = e.target.checked
this.refs.list.resetScroll()
this.setState({
filter: filter,
index: 0
}, () => {
this.refs.search.focus()
})
}
handleAllNotesButtonClick (e) {
const { filter } = this.state
filter.type = 'ALL'
this.refs.list.resetScroll()
this.setState({
filter,
index: 0
}, () => {
this.refs.search.focus()
})
}
handleStarredButtonClick (e) {
const { filter } = this.state
filter.type = 'STARRED'
this.refs.list.resetScroll()
this.setState({
filter,
index: 0
}, () => {
this.refs.search.focus()
})
}
handleStorageButtonClick (e, storage) {
const { filter } = this.state
filter.type = 'STORAGE'
filter.storage = storage
this.refs.list.resetScroll()
this.setState({
filter,
index: 0
}, () => {
this.refs.search.focus()
})
}
handleFolderButtonClick (e, storage, folder) {
const { filter } = this.state
filter.type = 'FOLDER'
filter.storage = storage
filter.folder = folder
this.refs.list.resetScroll()
this.setState({
filter,
index: 0
}, () => {
this.refs.search.focus()
})
}
handleNoteClick (e, index) {
this.setState({
index
}, () => {
this.refs.search.focus()
})
}
render () {
const { data, config } = this.props
const { filter, search } = this.state
const storageList = []
for (const key in data.storageMap) {
const storage = data.storageMap[key]
const item = (
<StorageSection
filter={filter}
storage={storage}
key={storage.key}
handleStorageButtonClick={(e, storage) => this.handleStorageButtonClick(e, storage)}
handleFolderButtonClick={(e, storage, folder) => this.handleFolderButtonClick(e, storage, folder)}
/>
)
storageList.push(item)
}
let notes = []
let noteIds
switch (filter.type) {
case 'STORAGE':
noteIds = data.storageNoteMap[filter.storage]
break
case 'FOLDER':
noteIds = data.folderNoteMap[filter.storage + '-' + filter.folder]
break
case 'STARRED':
noteIds = data.starredSet
}
if (noteIds != null) {
noteIds.forEach((id) => {
notes.push(data.noteMap[id])
})
} else {
for (const key in data.noteMap) {
notes.push(data.noteMap[key])
}
}
if (!filter.includeSnippet && filter.includeMarkdown) {
notes = notes.filter((note) => note.type === 'MARKDOWN_NOTE')
} else if (filter.includeSnippet && !filter.includeMarkdown) {
notes = notes.filter((note) => note.type === 'SNIPPET_NOTE')
}
if (search.trim().length > 0) {
const needle = new RegExp(_.escapeRegExp(search.trim()), 'i')
notes = notes.filter((note) => note.title.match(needle))
}
notes = notes
.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))
const activeNote = notes[this.state.index]
this.noteCount = notes.length
return (
<div className='Finder'
styleName='root'
ref='-1'
onKeyDown={(e) => this.handleKeyDown(e)}
>
<div styleName='search'>
<input
styleName='search-input'
ref='search'
value={search}
placeholder='Search...'
onChange={(e) => this.handleSearchChange(e)}
/>
</div>
<div styleName='result'>
<div styleName='result-nav'>
<div styleName='result-nav-filter'>
<div styleName='result-nav-filter-option'>
<label>
<input type='checkbox'
checked={filter.includeSnippet}
onChange={(e) => this.handleOnlySnippetCheckboxChange(e)}
/> Only Snippets</label>
</div>
<div styleName='result-nav-filter-option'>
<label>
<input type='checkbox'
checked={filter.includeMarkdown}
onChange={(e) => this.handleOnlyMarkdownCheckboxChange(e)}
/> Only Markdown</label>
</div>
</div>
<SideNavFilter
isHomeActive={filter.type === 'ALL'}
handleAllNotesButtonClick={(e) => this.handleAllNotesButtonClick(e)}
isStarredActive={filter.type === 'STARRED'}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
/>
<div styleName='result-nav-storageList'>
{storageList}
</div>
</div>
<NoteList styleName='result-list'
storageMap={data.storageMap}
notes={notes}
ref='list'
search={search}
index={this.state.index}
handleNoteClick={(e, _index) => this.handleNoteClick(e, _index)}
/>
<div styleName='result-detail'>
<NoteDetail
note={activeNote}
config={config}
ref='detail'
/>
</div>
</div>
</div>
)
}
}
FinderMain.propTypes = {
dispatch: PropTypes.func
}
var Finder = connect((x) => x)(CSSModules(FinderMain, styles))
function refreshData () {
// let data = dataStore.getData(true)
}
ReactDOM.render((
<Provider store={store}>
<Finder />
</Provider>
), document.getElementById('content'), function () {
refreshData()
})

View File

@@ -1,126 +0,0 @@
const nodeIpc = require('node-ipc')
const { remote, ipcRenderer } = require('electron')
const { app, Menu } = remote
const path = require('path')
const store = require('./store')
const consts = require('browser/lib/consts')
nodeIpc.config.id = 'finder'
nodeIpc.config.retry = 1500
nodeIpc.config.silent = true
function killFinder () {
const finderWindow = remote.getCurrentWindow()
finderWindow.removeAllListeners()
if (global.process.platform === 'darwin') {
// Only OSX has another app process.
nodeIpc.of.node.emit('quit-from-finder')
} else {
finderWindow.close()
}
}
function toggleFinder () {
const finderWindow = remote.getCurrentWindow()
if (global.process.platform === 'darwin') {
if (finderWindow.isVisible()) {
finderWindow.hide()
Menu.sendActionToFirstResponder('hide:')
} else {
nodeIpc.of.node.emit('request-data-from-finder')
finderWindow.show()
}
} else {
if (finderWindow.isVisible()) {
finderWindow.blur()
finderWindow.hide()
} else {
nodeIpc.of.node.emit('request-data-from-finder')
finderWindow.show()
finderWindow.focus()
}
}
}
nodeIpc.connectTo(
'node',
path.join(app.getPath('userData'), 'boostnote.service'),
function () {
nodeIpc.of.node.on('error', function (err) {
console.log(err)
})
nodeIpc.of.node.on('connect', function () {
console.log('Conncted successfully')
})
nodeIpc.of.node.on('disconnect', function () {
console.log('disconnected')
})
nodeIpc.of.node.on('open-finder', function () {
toggleFinder()
})
ipcRenderer.on('open-finder-from-tray', function () {
toggleFinder()
})
ipcRenderer.on('open-main-from-tray', function () {
nodeIpc.of.node.emit('open-main-from-finder')
})
ipcRenderer.on('quit-from-tray', function () {
nodeIpc.of.node.emit('quit-from-finder')
killFinder()
})
nodeIpc.of.node.on('throttle-data', function (payload) {
console.log('Received data from Main renderer')
store.default.dispatch({
type: 'THROTTLE_DATA',
data: payload
})
})
nodeIpc.of.node.on('config-renew', function (payload) {
const { config } = payload
if (config.ui.theme === 'dark') {
document.body.setAttribute('data-theme', 'dark')
} else if (config.ui.theme === 'white') {
document.body.setAttribute('data-theme', 'white')
} else if (config.ui.theme === 'solarized-dark') {
document.body.setAttribute('data-theme', 'solarized-dark')
} else {
document.body.setAttribute('data-theme', 'default')
}
let editorTheme = document.getElementById('editorTheme')
if (editorTheme == null) {
editorTheme = document.createElement('link')
editorTheme.setAttribute('id', 'editorTheme')
editorTheme.setAttribute('rel', 'stylesheet')
document.head.appendChild(editorTheme)
}
config.editor.theme = consts.THEMES.some((theme) => theme === config.editor.theme)
? config.editor.theme
: 'default'
if (config.editor.theme !== 'default') {
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
}
store.default.dispatch({
type: 'SET_CONFIG',
config: config
})
})
nodeIpc.of.node.on('quit-finder-app', function () {
nodeIpc.of.node.emit('quit-finder-app-confirm')
killFinder()
})
}
)
const ipc = {}
module.exports = ipc

View File

@@ -1,51 +0,0 @@
import { combineReducers, createStore } from 'redux'
import { routerReducer } from 'react-router-redux'
import { DEFAULT_CONFIG } from 'browser/main/lib/ConfigManager'
const defaultData = {
storageMap: {},
noteMap: {},
starredSet: [],
storageNoteMap: {},
folderNoteMap: {},
tagNoteMap: {}
}
function data (state = defaultData, action) {
switch (action.type) {
case 'THROTTLE_DATA':
console.log(action)
state = action.data
}
return state
}
function config (state = DEFAULT_CONFIG, action) {
switch (action.type) {
case 'INIT_CONFIG':
case 'SET_CONFIG':
return Object.assign({}, state, action.config)
case 'SET_IS_SIDENAV_FOLDED':
state.isSideNavFolded = action.isFolded
return Object.assign({}, state)
case 'SET_ZOOM':
state.zoom = action.zoom
return Object.assign({}, state)
case 'SET_LIST_WIDTH':
state.listWidth = action.listWidth
return Object.assign({}, state)
case 'SET_UI':
return Object.assign({}, state, action.config)
}
return state
}
const reducer = combineReducers({
data,
config,
routing: routerReducer
})
const store = createStore(reducer)
export default store

View File

@@ -2,7 +2,7 @@ const { remote } = require('electron')
const { Menu, MenuItem } = remote
function popup (templates) {
let menu = new Menu()
const menu = new Menu()
templates.forEach((item) => {
menu.append(new MenuItem(item))
})

View File

@@ -31,10 +31,10 @@ var md = markdownit({
return `<pre class="sequence">${str}</pre>`
}
return '<pre class="code">' +
createGutter(str) +
'<code class="' + lang + '">' +
str +
'</code></pre>'
createGutter(str) +
'<code class="' + lang + '">' +
str +
'</code></pre>'
}
})
md.use(emoji, {
@@ -57,7 +57,7 @@ md.use(math, {
blockRenderer: function (str) {
let output = ''
try {
output = katex.renderToString(str.trim(), {displayMode: true})
output = katex.renderToString(str.trim(), { displayMode: true })
} catch (err) {
output = `<div class="katex-error">${err.message}</div>`
}
@@ -76,7 +76,17 @@ md.use(require('markdown-it-named-headers'), {
}
})
md.use(require('markdown-it-kbd'))
md.use(require('markdown-it-plantuml'))
const deflate = require('markdown-it-plantuml/lib/deflate')
md.use(require('markdown-it-plantuml'), '', {
generateSource: function (umlCode) {
const s = unescape(encodeURIComponent(umlCode))
const zippedCode = deflate.encode64(
deflate.zip_deflate(`@startuml\n${s}\n@enduml`, 9)
)
return `http://www.plantuml.com/plantuml/svg/${zippedCode}`
}
})
// Override task item
md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
@@ -110,7 +120,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
state.line = nextLine
token = state.push('paragraph_open', 'p', 1)
token.map = [ startLine, state.line ]
token.map = [startLine, state.line]
if (state.parentType === 'list') {
const match = content.match(/^\[( |x)\] ?(.+)/i)
@@ -121,7 +131,7 @@ md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
token = state.push('inline', '', 0)
token.content = content
token.map = [ startLine, state.line ]
token.map = [startLine, state.line]
token.children = []
token = state.push('paragraph_close', 'p', -1)

View File

@@ -20,11 +20,13 @@
body[data-theme="dark"]
.root
background-color $ui-dark-backgroundColor
border-left 1px solid $ui-dark-borderColor
.empty-message
color $ui-dark-inactive-text-color
body[data-theme="solarized-dark"]
.root
background-color $ui-solarized-dark-noteDetail-backgroundColor
border-left 1px solid $ui-solarized-dark-borderColor
.empty-message
color $ui-solarized-dark-text-color

View File

@@ -3,20 +3,14 @@
border solid 1px transparent
vertical-align middle
border-radius 2px
height 30px
transition 0.15s
user-select none
margin-right 10px
&:hover
background-color $ui-button--hover-backgroundColor
.root--search, .root--focus
@extend .root
background-color $ui-noteDetail-backgroundColor = #fff
border-color $ui-input--focus-borderColor
width 154px
height 30px
&:hover
border-color $ui-input--focus-borderColor = #fff
.idle
position relative

View File

@@ -8,8 +8,8 @@
tooltip()
position absolute
pointer-events none
top 26px
right 0
top 50px
right 70px
z-index 200
padding 5px
line-height normal

View File

@@ -8,8 +8,8 @@
tooltip()
position absolute
pointer-events none
top 26px
right 0
top 50px
right 20px
z-index 200
padding 5px
line-height normal

View File

@@ -2,82 +2,97 @@ import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './InfoPanel.styl'
import copy from 'copy-to-clipboard'
const InfoPanel = ({
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, exportAsHtml, wordCount, letterCount, type, print
}) => (
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
<div>
<p styleName='modification-date'>{updatedAt}</p>
<p styleName='modification-date-desc'>MODIFICATION DATE</p>
</div>
class InfoPanel extends React.Component {
copyNoteLink () {
const {noteLink} = this.props
this.refs.noteLink.select()
copy(noteLink)
}
<hr />
{type === 'SNIPPET_NOTE'
? ''
: <div styleName='count-wrap'>
<div styleName='count-number'>
<p styleName='infoPanel-defaul-count'>{wordCount}</p>
<p styleName='infoPanel-sub-count'>Words</p>
render () {
const {
storageName, folderName, noteLink, updatedAt, createdAt, exportAsMd, exportAsTxt, exportAsHtml, wordCount, letterCount, type, print
} = this.props
return (
<div className='infoPanel' styleName='control-infoButton-panel' style={{display: 'none'}}>
<div>
<p styleName='modification-date'>{updatedAt}</p>
<p styleName='modification-date-desc'>MODIFICATION DATE</p>
</div>
<div styleName='count-number'>
<p styleName='infoPanel-defaul-count'>{letterCount}</p>
<p styleName='infoPanel-sub-count'>Letters</p>
<hr />
{type === 'SNIPPET_NOTE'
? ''
: <div styleName='count-wrap'>
<div styleName='count-number'>
<p styleName='infoPanel-defaul-count'>{wordCount}</p>
<p styleName='infoPanel-sub-count'>Words</p>
</div>
<div styleName='count-number'>
<p styleName='infoPanel-defaul-count'>{letterCount}</p>
<p styleName='infoPanel-sub-count'>Letters</p>
</div>
</div>
}
{type === 'SNIPPET_NOTE'
? ''
: <hr />
}
<div>
<p styleName='infoPanel-default'>{storageName}</p>
<p styleName='infoPanel-sub'>STORAGE</p>
</div>
<div>
<p styleName='infoPanel-default'>{folderName}</p>
<p styleName='infoPanel-sub'>FOLDER</p>
</div>
<div>
<p styleName='infoPanel-default'>{createdAt}</p>
<p styleName='infoPanel-sub'>CREATION DATE</p>
</div>
<div>
<input styleName='infoPanel-noteLink' ref='noteLink' value={noteLink} onClick={(e) => { e.target.select() }} />
<button onClick={() => this.copyNoteLink()} styleName='infoPanel-copyButton'>
<i className='fa fa-clipboard' />
</button>
<p styleName='infoPanel-sub'>NOTE LINK</p>
</div>
<hr />
<div id='export-wrap'>
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
<i className='fa fa-file-code-o' />
<p>.md</p>
</button>
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
<i className='fa fa-file-text-o' />
<p>.txt</p>
</button>
<button styleName='export--enable' onClick={(e) => exportAsHtml(e)}>
<i className='fa fa-html5' />
<p>.html</p>
</button>
<button styleName='export--enable' onClick={(e) => print(e)}>
<i className='fa fa-print' />
<p>Print</p>
</button>
</div>
</div>
}
{type === 'SNIPPET_NOTE'
? ''
: <hr />
}
<div>
<p styleName='infoPanel-default'>{storageName}</p>
<p styleName='infoPanel-sub'>STORAGE</p>
</div>
<div>
<p styleName='infoPanel-default'>{folderName}</p>
<p styleName='infoPanel-sub'>FOLDER</p>
</div>
<div>
<p styleName='infoPanel-default'>{createdAt}</p>
<p styleName='infoPanel-sub'>CREATION DATE</p>
</div>
<div>
<input styleName='infoPanel-noteLink' value={noteLink} onClick={(e) => { e.target.select() }} />
<p styleName='infoPanel-sub'>NOTE LINK</p>
</div>
<hr />
<div id='export-wrap'>
<button styleName='export--enable' onClick={(e) => exportAsMd(e)}>
<i className='fa fa-file-code-o' />
<p>.md</p>
</button>
<button styleName='export--enable' onClick={(e) => exportAsTxt(e)}>
<i className='fa fa-file-text-o' />
<p>.txt</p>
</button>
<button styleName='export--enable' onClick={(e) => exportAsHtml(e)}>
<i className='fa fa-html5' />
<p>.html</p>
</button>
<button styleName='export--enable' onClick={(e) => print(e)}>
<i className='fa fa-print' />
<p>Print</p>
</button>
</div>
</div>
)
)
}
}
InfoPanel.propTypes = {
storageName: PropTypes.string.isRequired,

View File

@@ -11,11 +11,10 @@
.control-infoButton-panel
z-index 200
margin-top 0px
right 0
right 25px
position absolute
padding 20px 25px 0 25px
width 300px
height 350px
overflow auto
background-color $ui-noteList-backgroundColor
box-shadow 2px 12px 15px 2px rgba(0, 0, 0, 0.1), 2px 1px 50px 2px rgba(0, 0, 0, 0.1)
@@ -70,15 +69,30 @@
color $ui-text-color
.infoPanel-sub
font-size 14px
font-size 12px
font-weight 600
color $ui-inactive-text-color
padding-bottom 8px
.infoPanel-noteLink
padding-right 5px
width 200px
width 210px
height 25px
margin-bottom 6px
margin 6px 0
.infoPanel-copyButton
outline none
font-size 16px
color #A0A0A0
background-color transparent
border none
margin 0 5px
border-radius 5px
cursor pointer
&:hover
transition 0.2s
background-color alpha($ui-button--hover-backgroundColor, 30%)
color $ui-inactive-text-color
.infoPanel-trash
color #EA4447

View File

@@ -367,10 +367,6 @@ class MarkdownNoteDetail extends React.Component {
<TodoListPercentage percentageOfTodo={getTodoPercentageOfCompleted(note.content)} />
</div>
<div styleName='info-right'>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<StarButton
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
@@ -384,6 +380,7 @@ class MarkdownNoteDetail extends React.Component {
onMouseDown={(e) => this.handleLockButtonMouseDown(e)}
>
<img styleName='iconInfo' src={imgSrc} />
{this.state.isLocked ? <span styleName='tooltip'>Unlock</span> : <span styleName='tooltip'>Lock</span>}
</button>
return (
@@ -395,6 +392,10 @@ class MarkdownNoteDetail extends React.Component {
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<InfoPanel
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}

View File

@@ -12,11 +12,27 @@
padding-bottom 3px
.control-lockButton
top 150px
topBarButtonRight()
position absolute
right 225px
&:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 35px
right -10px
width 50px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
.trashed-infopanel
top 40px
position relative
.body
@@ -25,7 +41,7 @@
right 0
top $info-height + $info-margin-under-border
bottom $statusBar-height
margin 0 45px
margin 0 30px
.body-noteEditor
absolute top bottom left right

View File

@@ -1,6 +1,6 @@
@import('DetailVars')
$info-height = 50px
$info-height = 60px
$info-margin-under-border = 30px
.info
@@ -8,11 +8,11 @@ $info-margin-under-border = 30px
left 0
right 0
height $info-height
border-bottom 1px solid #eee
background-color $ui-noteDetail-backgroundColor
width 100%
display flex
align-items center
padding 0 20px
.info-left
padding 0 10px
@@ -20,7 +20,6 @@ $info-margin-under-border = 30px
display flex
align-items center
.info-left-top-folderSelect
display flex
align-items center
@@ -45,12 +44,9 @@ $info-margin-under-border = 30px
color $ui-button--color
.info-right
position absolute
right 40px
top 60px
bottom 1px
padding-left 30px
z-index 101
display inline-flex
margin-top 3px
.undo-button
width 34px

View File

@@ -564,6 +564,7 @@ class SnippetNoteDetail extends React.Component {
fontSize={editorFontSize}
indentType={config.editor.indentType}
indentSize={editorIndentSize}
displayLineNumbers={config.editor.displayLineNumbers}
keyMap={config.editor.keyMap}
scrollPastEnd={config.editor.scrollPastEnd}
onChange={(e) => this.handleCodeChange(index)(e)}
@@ -626,10 +627,6 @@ class SnippetNoteDetail extends React.Component {
/>
</div>
<div styleName='info-right'>
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<StarButton
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
@@ -637,10 +634,16 @@ class SnippetNoteDetail extends React.Component {
<button styleName='control-fullScreenButton' title='Fullscreen'
onMouseDown={(e) => this.handleFullScreenButton(e)}>
<img styleName='iconInfo' src='../resources/icon/icon-sidebar.svg' />
<img styleName='iconInfo' src='../resources/icon/icon-full.svg' />
<span styleName='tooltip'>Fullscreen</span>
</button>
<TrashButton onClick={(e) => this.handleTrashButtonClick(e)} />
<InfoButton
onClick={(e) => this.handleInfoButtonClick(e)}
/>
<InfoPanel
storageName={currentOption.storage.name}
folderName={currentOption.folder.name}

View File

@@ -9,8 +9,7 @@
.body
absolute left right
left $snippet-note-detail-left-margin
right $snippet-note-detail-right-margin
margin 0 30px
top $info-height + $info-margin-under-border
bottom $statusBar-height
background-color $ui-noteDetail-backgroundColor
@@ -70,6 +69,21 @@
top 80px
margin-bottom 10px
topBarButtonRight()
&:hover .tooltip
opacity 1
.tooltip
tooltip()
position absolute
pointer-events none
top 50px
right 70px
z-index 200
padding 5px
line-height normal
border-radius 2px
opacity 0
transition 0.1s
body[data-theme="white"]
.root

View File

@@ -11,9 +11,9 @@
tooltip()
position absolute
pointer-events none
top 26px
right 0
width 100%
top 50px
right 115px
width 40px
z-index 200
padding 5px
line-height normal

View File

@@ -64,7 +64,8 @@ class TagSelect extends React.Component {
submitTag () {
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_TAG')
let { value } = this.props
const newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')
let newTag = this.refs.newTag.value.trim().replace(/ +/g, '_')
newTag = newTag.charAt(0) === '#' ? newTag.substring(1) : newTag
if (newTag.length <= 0) {
this.setState({

View File

@@ -6,7 +6,8 @@
width 100%
overflow-x scroll
white-space nowrap
margin-right 10px
margin-top 31px
position absolute
.root::-webkit-scrollbar
display none

View File

@@ -8,10 +8,10 @@ const ToggleModeButton = ({
}) => (
<div styleName='control-toggleModeButton'>
<div styleName={editorType === 'SPLIT' ? 'active' : 'non-active'} onClick={() => onClick('SPLIT')}>
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '../resources/icon/icon-mode-split-on.svg' : '../resources/icon/icon-mode-split-on-active.svg'} />
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '../resources/icon/icon-mode-markdown-off-active.svg' : ''} />
</div>
<div styleName={editorType === 'EDITOR_PREVIEW' ? 'active' : 'non-active'} onClick={() => onClick('EDITOR_PREVIEW')}>
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '../resources/icon/icon-mode-markdown-off-active.svg' : '../resources/icon/icon-mode-markdown-off.svg'} />
<img styleName='item-star' src={editorType === 'EDITOR_PREVIEW' ? '' : '../resources/icon/icon-mode-split-on-active.svg'} />
</div>
<span styleName='tooltip'>Toggle Mode</span>
</div>

View File

@@ -1,24 +1,28 @@
.control-toggleModeButton
border 1px solid #eee
height 34px
height 25px
border-radius 50px
background-color #F4F4F4
width 52px
display flex
align-items center
position absolute
right 165px
.active
background-color #1EC38B
width 33px
height 24px
box-shadow 2px 0px 7px #eee
z-index 1
div
width 40px
height 100%
background-color #f9f9f9
border-radius 50%
display flex
align-items center
justify-content center
cursor pointer
&:first-child
border-right 1px solid #eee
.active
background-color #fff
box-shadow 2px 0px 7px #eee
z-index 1
&:hover .tooltip
opacity 1
@@ -26,9 +30,10 @@
tooltip()
position absolute
pointer-events none
top 47px
right 11px
top 33px
left -10px
z-index 200
width 80px
padding 5px
line-height normal
border-radius 2px
@@ -40,22 +45,14 @@ body[data-theme="dark"]
topBarButtonDark()
.control-toggleModeButton
border 1px solid #444444
div
background-color $ui-dark-noteDetail-backgroundColor
&:first-child
border-right 1px solid #444444
.active
background-color #3A404C
.active
background-color #1EC38B
box-shadow 2px 0px 7px #444444
body[data-theme="solarized-dark"]
.control-toggleModeButton
border 1px solid #586E75
div
background-color $ui-solarized-dark-noteDetail-backgroundColor
&:first-child
border-right 1px solid #586E75
.active
background-color #002B36
.active
background-color #1EC38B
box-shadow 2px 0px 7px #222222

View File

@@ -8,8 +8,8 @@
tooltip()
position absolute
pointer-events none
top 26px
right 0
top 50px
right 50px
z-index 200
padding 5px
line-height normal

View File

@@ -86,7 +86,7 @@ class NewNoteButton extends React.Component {
onClick={(e) => this.handleNewNoteButtonClick(e)}>
<img styleName='iconTag' src='../resources/icon/icon-newnote.svg' />
<span styleName='control-newNoteButton-tooltip'>
Make a Note {OSX ? '⌘' : '^'} + n
Make a note {OSX ? '⌘' : 'Ctrl'} + N
</span>
</button>
</div>

View File

@@ -11,10 +11,8 @@ import NoteItem from 'browser/components/NoteItem'
import NoteItemSimple from 'browser/components/NoteItemSimple'
import searchFromNotes from 'browser/lib/search'
import fs from 'fs'
import path from 'path'
import { hashHistory } from 'react-router'
import markdown from 'browser/lib/markdownTextHelper'
import { findNoteTitle } from 'browser/lib/findNoteTitle'
import store from 'browser/main/store'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
const { remote } = require('electron')
@@ -171,9 +169,8 @@ class NoteList extends React.Component {
if (this.notes == null || this.notes.length === 0) {
return
}
let { router } = this.context
let { location } = this.props
let { selectedNoteKeys, shiftKeyDown } = this.state
let { selectedNoteKeys } = this.state
const { shiftKeyDown } = this.state
let targetIndex = this.getTargetIndex()
@@ -199,9 +196,8 @@ class NoteList extends React.Component {
if (this.notes == null || this.notes.length === 0) {
return
}
let { router } = this.context
let { location } = this.props
let { selectedNoteKeys, shiftKeyDown } = this.state
let { selectedNoteKeys } = this.state
const { shiftKeyDown } = this.state
let targetIndex = this.getTargetIndex()
const isTargetLastNote = targetIndex === this.notes.length - 1
@@ -242,7 +238,6 @@ class NoteList extends React.Component {
}
handleNoteListKeyDown (e) {
const { shiftKeyDown } = this.state
if (e.metaKey || e.ctrlKey) return true
if (e.keyCode === 65 && !e.shiftKey) {
@@ -284,7 +279,7 @@ class NoteList extends React.Component {
getNotes () {
const { data, params, location } = this.props
if (location.pathname.match(/\/home/) || location.pathname.match(/\alltags/)) {
if (location.pathname.match(/\/home/) || location.pathname.match(/alltags/)) {
const allNotes = data.noteMap.map((note) => note)
this.contextNotes = allNotes
return allNotes
@@ -355,9 +350,10 @@ class NoteList extends React.Component {
}
handleNoteClick (e, uniqueKey) {
let { router } = this.context
let { location } = this.props
let { shiftKeyDown, selectedNoteKeys } = this.state
const { router } = this.context
const { location } = this.props
let { selectedNoteKeys } = this.state
const { shiftKeyDown } = this.state
if (shiftKeyDown && selectedNoteKeys.includes(uniqueKey)) {
const newSelectedNoteKeys = selectedNoteKeys.filter((noteKey) => noteKey !== uniqueKey)
@@ -443,6 +439,7 @@ class NoteList extends React.Component {
const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top'
const deleteLabel = 'Delete Note'
const cloneNote = 'Clone Note'
const menu = new Menu()
if (!location.pathname.match(/\/home|\/starred|\/trash/)) {
@@ -455,6 +452,10 @@ class NoteList extends React.Component {
label: deleteLabel,
click: this.deleteNote
}))
menu.append(new MenuItem({
label: cloneNote,
click: this.cloneNote.bind(this)
}))
menu.popup()
}
@@ -545,6 +546,42 @@ class NoteList extends React.Component {
this.setState({ selectedNoteKeys: [] })
}
cloneNote () {
const { selectedNoteKeys } = this.state
const { dispatch, location } = this.props
const { storage, folder } = this.resolveTargetFolder()
const notes = this.notes.map((note) => Object.assign({}, note))
const selectedNotes = findNotesByKeys(notes, selectedNoteKeys)
const firstNote = selectedNotes[0]
const eventName = firstNote.type === 'MARKDOWN_NOTE' ? 'ADD_MARKDOWN' : 'ADD_SNIPPET'
AwsMobileAnalyticsConfig.recordDynamicCustomEvent(eventName)
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE')
dataApi
.createNote(storage.key, {
type: firstNote.type,
folder: folder.key,
title: firstNote.title + ' copy',
content: firstNote.content
})
.then((note) => {
const uniqueKey = note.storage + '-' + note.key
dispatch({
type: 'UPDATE_NOTE',
note: note
})
this.setState({
selectedNoteKeys: [uniqueKey]
})
hashHistory.push({
pathname: location.pathname,
query: {key: uniqueKey}
})
})
}
importFromFile () {
const options = {
filters: [
@@ -582,7 +619,7 @@ class NoteList extends React.Component {
const newNote = {
content: content,
folder: folder.key,
title: markdown.strip(findNoteTitle(content)),
title: path.basename(filepath, path.extname(filepath)),
type: 'MARKDOWN_NOTE',
createdAt: birthtime,
updatedAt: mtime
@@ -642,9 +679,10 @@ class NoteList extends React.Component {
}
render () {
let { location, notes, config, dispatch } = this.props
let { selectedNoteKeys } = this.state
let sortFunc = config.sortBy === 'CREATED_AT'
const { location, config } = this.props
let { notes } = this.props
const { selectedNoteKeys } = this.state
const sortFunc = config.sortBy === 'CREATED_AT'
? sortByCreatedAt
: config.sortBy === 'ALPHABETICAL'
? sortByAlphabetical
@@ -689,7 +727,6 @@ class NoteList extends React.Component {
config.sortBy === 'CREATED_AT'
? note.createdAt : note.updatedAt
).fromNow('D')
const key = `${note.storage}-${note.key}`
if (isDefault) {
return (

View File

@@ -8,12 +8,10 @@ import CreateFolderModal from 'browser/main/modals/CreateFolderModal'
import RenameFolderModal from 'browser/main/modals/RenameFolderModal'
import dataApi from 'browser/main/lib/dataApi'
import StorageItemChild from 'browser/components/StorageItem'
import eventEmitter from 'browser/main/lib/eventEmitter'
import _ from 'lodash'
import * as path from 'path'
const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote
const { Menu, dialog } = remote
class StorageItem extends React.Component {
constructor (props) {

View File

@@ -21,19 +21,20 @@
color white
.zoom
navButtonColor()
color rgba(0,0,0,.54)
height 20px
display flex
padding 0
align-items center
background-color transparent
&:hover
color $ui-active-color
&:active
color $ui-active-color
span
margin-left 5px
display none
// navButtonColor()
// color rgba(0,0,0,.54)
// height 20px
// display flex
// padding 0
// align-items center
// background-color transparent
// &:hover
// color $ui-active-color
// &:active
// color $ui-active-color
// span
// margin-left 5px
.update
navButtonColor()

View File

@@ -97,7 +97,7 @@ body[data-theme="dark"]
.CodeMirror
font-family inherit !important
line-height 1.4em
height 96%
height 100%
.CodeMirror > div > textarea
margin-bottom -1em
.CodeMirror-focused .CodeMirror-selected

View File

@@ -18,7 +18,6 @@ export const DEFAULT_CONFIG = {
listStyle: 'DEFAULT', // 'DEFAULT', 'SMALL'
amaEnabled: true,
hotkey: {
toggleFinder: OSX ? 'Cmd + Alt + S' : 'Super + Alt + S',
toggleMain: OSX ? 'Cmd + Alt + L' : 'Super + Alt + E'
},
ui: {
@@ -34,6 +33,7 @@ export const DEFAULT_CONFIG = {
fontFamily: win ? 'Segoe UI' : 'Monaco, Consolas',
indentType: 'space',
indentSize: '2',
displayLineNumbers: true,
switchPreview: 'BLUR', // Available value: RIGHTCLICK, BLUR
scrollPastEnd: false,
type: 'SPLIT'
@@ -46,7 +46,8 @@ export const DEFAULT_CONFIG = {
latexInlineOpen: '$',
latexInlineClose: '$',
latexBlockOpen: '$$',
latexBlockClose: '$$'
latexBlockClose: '$$',
scrollPastEnd: false
}
}

View File

@@ -24,20 +24,6 @@ nodeIpc.connectTo(
nodeIpc.of.node.on('disconnect', function () {
console.log('disconnected')
})
nodeIpc.of.node.on('request-data-from-finder', function () {
console.log('throttle')
var { data } = store.getState()
console.log(data.starredSet.toJS())
nodeIpc.of.node.emit('throttle-data', {
storageMap: data.storageMap.toJS(),
noteMap: data.noteMap.toJS(),
starredSet: data.starredSet.toJS(),
storageNoteMap: data.storageNoteMap.toJS(),
folderNoteMap: data.folderNoteMap.toJS(),
tagNoteMap: data.tagNoteMap.toJS()
})
})
}
)

View File

@@ -106,7 +106,7 @@ class NewNoteModal extends React.Component {
onKeyDown={(e) => this.handleKeyDown(e)}
>
<div styleName='header'>
<div styleName='title'>Make a Note</div>
<div styleName='title'>Make a note</div>
</div>
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
<div styleName='control'>

View File

@@ -89,9 +89,9 @@
margin-right 10px
.group-control-rightButton
position absolute
top 10px
right 20px
position fixed
top 80px
right 100px
colorPrimaryButton()
border none
border-radius 2px

View File

@@ -22,18 +22,18 @@ class Crowdfunding extends React.Component {
return (
<div styleName='root'>
<div styleName='header'>Crowdfunding</div>
<p>Dear all,</p>
<p>Dear everyone,</p>
<br />
<p>Thanks for your using!</p>
<p>Boostnote is used in about 200 countries and regions, it is a awesome developer community.</p>
<p>Thank you for using Boostnote!</p>
<p>Boostnote is used in about 200 different countries and regions by an awesome community of developers.</p>
<br />
<p>To continue supporting this growth, and to satisfy community expectations,</p>
<p>we would like to invest more time in this project.</p>
<p>we would like to invest more time and resources in this project.</p>
<br />
<p>If you like this project and see its potential, you can help!</p>
<p>If you like this project and see its potential, you can help by supporting us on OpenCollective!</p>
<br />
<p>Thanks,</p>
<p>Boostnote maintainers.</p>
<p>Boostnote maintainers</p>
<br />
<button styleName='cf-link'>
<a href='https://opencollective.com/boostnoteio' onClick={(e) => this.handleLinkClick(e)}>Support via OpenCollective</a>

View File

@@ -66,7 +66,6 @@ class HotkeyTab extends React.Component {
handleHotkeyChange (e) {
const { config } = this.state
config.hotkey = {
toggleFinder: this.refs.toggleFinder.value,
toggleMain: this.refs.toggleMain.value
}
this.setState({
@@ -103,9 +102,9 @@ class HotkeyTab extends React.Component {
return (
<div styleName='root'>
<div styleName='group'>
<div styleName='group-header'>Hotkey</div>
<div styleName='group-header'>Hotkeys</div>
<div styleName='group-section'>
<div styleName='group-section-label'>Toggle Main</div>
<div styleName='group-section-label'>Show/Hide Boostnote</div>
<div styleName='group-section-control'>
<input styleName='group-section-control-input'
onChange={(e) => this.handleHotkeyChange(e)}
@@ -115,24 +114,13 @@ class HotkeyTab extends React.Component {
/>
</div>
</div>
<div styleName='group-section'>
<div styleName='group-section-label'>Toggle Finder (Quick search)</div>
<div styleName='group-section-control'>
<input styleName='group-section-control-input'
onChange={(e) => this.handleHotkeyChange(e)}
ref='toggleFinder'
value={config.hotkey.toggleFinder}
type='text'
/>
</div>
</div>
<div styleName='group-control'>
<button styleName='group-control-leftButton'
onClick={(e) => this.handleHintToggleButtonClick(e)}
>
{this.state.isHotkeyHintOpen
? 'Hide Hint'
: 'Hint?'
? 'Hide Help'
: 'Help'
}
</button>
<button styleName='group-control-rightButton'

View File

@@ -31,7 +31,7 @@ class InfoTab extends React.Component {
}
handleSaveButtonClick (e) {
let newConfig = {
const newConfig = {
amaEnabled: this.state.config.amaEnabled
}
@@ -102,7 +102,7 @@ class InfoTab extends React.Component {
<hr />
<div styleName='header--sub'>Info</div>
<div styleName='header--sub'>About</div>
<div styleName='top'>
<div styleName='icon-space'>
@@ -137,17 +137,19 @@ class InfoTab extends React.Component {
<hr styleName='separate-line' />
<div styleName='policy'>Data collection policy</div>
<div>We collect only the number of DAU for Boostnote and **DO NOT collect** any detail information such as your note content.</div>
<div styleName='policy'>Analytics</div>
<div>Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.</div>
<div>You can see how it works on <a href='https://github.com/BoostIO/Boostnote' onClick={(e) => this.handleLinkClick(e)}>GitHub</a>.</div>
<div>This data is only used for Boostnote improvements.</div>
<br />
<div>You can choose to enable or disable this option.</div>
<input onChange={(e) => this.handleConfigChange(e)}
checked={this.state.config.amaEnabled}
ref='amaEnabled'
type='checkbox'
/>
Enable to send analytics to our servers<br />
Enable analytics to help improve Boostnote<br />
<button styleName='policy-submit' onClick={(e) => this.handleSaveButtonClick(e)}>Save</button>
<br />
{this.infoMessage()}
</div>
)

View File

@@ -84,3 +84,17 @@ body[data-theme="dark"]
top 25px
z-index 10
white-space nowrap
body[data-theme="solarized-dark"]
.header
border-color $ui-solarized-dark-button-backgroundColor
.header-label-path
color $ui-solarized-dark-text-color
.header-label-editButton
color $ui-solarized-dark-text-color
.header-control-button
border-color $ui-solarized-dark-button-backgroundColor
background-color $ui-solarized-dark-button-backgroundColor
color $ui-solarized-dark-text-color

View File

@@ -78,7 +78,7 @@ class StoragesTab extends React.Component {
<button styleName='list-control-addStorageButton'
onClick={(e) => this.handleAddStorageButton(e)}
>
<i className='fa fa-plus' /> Add Storage
<i className='fa fa-plus' /> Add Storage Location
</button>
</div>
</div>
@@ -167,7 +167,7 @@ class StoragesTab extends React.Component {
<option value='FILESYSTEM'>File System</option>
</select>
<div styleName='addStorage-body-section-type-description'>
3rd party cloud integration:
Setting up 3rd-party cloud storage integration:{' '}
<a href='https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup'
onClick={(e) => this.handleLinkClick(e)}
>Cloud-Syncing-and-Backup</a>
@@ -196,7 +196,7 @@ class StoragesTab extends React.Component {
<div styleName='addStorage-body-control'>
<button styleName='addStorage-body-control-createButton'
onClick={(e) => this.handleAddStorageCreateButton(e)}
>Create</button>
>Add</button>
<button styleName='addStorage-body-control-cancelButton'
onClick={(e) => this.handleAddStorageCancelButton(e)}
>Cancel</button>

View File

@@ -73,6 +73,7 @@ class UiTab extends React.Component {
fontFamily: this.refs.editorFontFamily.value,
indentType: this.refs.editorIndentType.value,
indentSize: this.refs.editorIndentSize.value,
displayLineNumbers: this.refs.editorDisplayLineNumbers.checked,
switchPreview: this.refs.editorSwitchPreview.value,
keyMap: this.refs.editorKeyMap.value,
scrollPastEnd: this.refs.scrollPastEnd.checked
@@ -85,7 +86,8 @@ class UiTab extends React.Component {
latexInlineOpen: this.refs.previewLatexInlineOpen.value,
latexInlineClose: this.refs.previewLatexInlineClose.value,
latexBlockOpen: this.refs.previewLatexBlockOpen.value,
latexBlockClose: this.refs.previewLatexBlockClose.value
latexBlockClose: this.refs.previewLatexBlockClose.value,
scrollPastEnd: this.refs.previewScrollPastEnd.checked
}
}
@@ -148,10 +150,10 @@ class UiTab extends React.Component {
return (
<div styleName='root'>
<div styleName='group'>
<div styleName='group-header'>UI</div>
<div styleName='group-header'>Interface</div>
<div styleName='group-section'>
Color Theme
Interface Theme
<div styleName='group-section-control'>
<select value={config.ui.theme}
onChange={(e) => this.handleUIChange(e)}
@@ -303,6 +305,17 @@ class UiTab extends React.Component {
</div>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.editor.displayLineNumbers}
ref='editorDisplayLineNumbers'
type='checkbox'
/>&nbsp;
Show line numbers in the editor
</label>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
@@ -356,6 +369,16 @@ class UiTab extends React.Component {
</select>
</div>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.preview.scrollPastEnd}
ref='previewScrollPastEnd'
type='checkbox'
/>&nbsp;
Allow preview to scroll past the last line
</label>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}

View File

@@ -1,6 +1,5 @@
import PropTypes from 'prop-types'
import React from 'react'
import ReactDOM from 'react-dom'
import { connect } from 'react-redux'
import HotkeyTab from './HotkeyTab'
import UiTab from './UiTab'
@@ -11,6 +10,7 @@ import ModalEscButton from 'browser/components/ModalEscButton'
import CSSModules from 'browser/lib/CSSModules'
import styles from './PreferencesModal.styl'
import RealtimeNotification from 'browser/components/RealtimeNotification'
import _ from 'lodash'
class Preferences extends React.Component {
constructor (props) {
@@ -94,8 +94,7 @@ class Preferences extends React.Component {
}
getContentBoundingBox () {
const node = ReactDOM.findDOMNode(this.refs.content)
return node.getBoundingClientRect()
return this.refs.content.getBoundingClientRect()
}
haveToSaveNotif (type, message) {
@@ -108,10 +107,10 @@ class Preferences extends React.Component {
const content = this.renderContent()
const tabs = [
{target: 'STORAGES', label: 'Storages'},
{target: 'HOTKEY', label: 'Hotkey', Hotkey: this.state.HotkeyAlert},
{target: 'UI', label: 'UI', UI: this.state.UIAlert},
{target: 'INFO', label: 'Community / Info'},
{target: 'STORAGES', label: 'Storage'},
{target: 'HOTKEY', label: 'Hotkeys', Hotkey: this.state.HotkeyAlert},
{target: 'UI', label: 'Interface', UI: this.state.UIAlert},
{target: 'INFO', label: 'About'},
{target: 'CROWDFUNDING', label: 'Crowdfunding'}
]

View File

@@ -355,11 +355,9 @@ function data (state = defaultDataMap(), action) {
state.storageMap.set(action.storage.key, action.storage)
return state
case 'EXPORT_FOLDER':
{
state = Object.assign({}, state)
state.storageMap = new Map(state.storageMap)
state.storageMap.set(action.storage.key, action.storage)
}
state = Object.assign({}, state)
state.storageMap = new Map(state.storageMap)
state.storageMap.set(action.storage.key, action.storage)
return state
case 'DELETE_FOLDER':
{

View File

@@ -1,129 +0,0 @@
@import '../../../node_modules/nib/lib/nib'
@import '../vars'
@import '../mixins/*'
global-reset()
@import '../shared/*'
@import '../theme/*'
iptBgColor = #E6E6E6
iptFocusBorderColor = #369DCD
DEFAULT_FONTS = 'Lato', 'MS Gothic', 'Malgun Gothic', 'Sans-serif'
body
font-family DEFAULT_FONTS
color textColor
font-size fontSize
width 100%
height 100%
overflow hidden
button, input
font-family DEFAULT_FONTS
.Finder
absolute top bottom left right
.FinderInput
padding 11px
margin 0 auto
height 55px
box-sizing border-box
border-bottom solid 1px borderColor
background-color iptBgColor
z-index 200
input
display block
width 100%
border solid 1px borderColor
padding 0 10px
font-size 1em
height 33px
border-radius 5px
box-sizing border-box
border-radius 5px
&:focus, &.focus
border-color iptFocusBorderColor
outline none
.FinderList
absolute left bottom
top 55px
border-right solid 1px borderColor
box-sizing border-box
width 250px
overflow-y auto
z-index 0
user-select none
&>ul>li
.articleItem
padding 10px
border solid 2px transparent
box-sizing border-box
cursor pointer
white-space nowrap
overflow-x hidden
text-overflow ellipsis
.divider
box-sizing border-box
border-bottom solid 1px borderColor
&.active
.articleItem
border-color brandColor
.FinderDetail
absolute right bottom
top 55px
left 250px
box-shadow 0px 0px 10px 0 #CCC
z-index 100
.header
absolute top left right
height 55px
box-sizing border-box
padding 0 10px
border-bottom solid 1px borderColor
line-height 55px
font-size 18px
white-space nowrap
text-overflow ellipsis
overflow-x hidden
clearfix()
.left
float left
.right
float right
button
border-radius 16.5px
cursor pointer
height 33px
width 33px
border none
margin-right 5px
font-size 18px
color inactiveTextColor
background-color transparent
padding 0
.tooltip
tooltip()
&.clipboardBtn .tooltip
margin-left -160px
margin-top 25px
&:hover
color textColor
.tooltip
opacity 1
.content
position absolute
top 55px
padding 10px
bottom 0
left 0
right 0
box-sizing border-box
overflow-y auto
.MarkdownPreview
marked()
&.empty
color lighten(inactiveTextColor, 10%)
user-select none
font-size 14px
.CodeEditor
absolute top bottom left right

View File

@@ -188,7 +188,6 @@ modal()
border-radius $modal-border-radius
topBarButtonRight()
position absolute
width 34px
height 34px
border-radius 17px

View File

@@ -378,52 +378,10 @@ body[data-theme="dark"]
&: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

View File

@@ -19,7 +19,7 @@ module.exports = function (grunt) {
var initConfig = {
pkg: grunt.file.readJSON('package.json'),
'create-windows-installer': {
x64: {
ia32: {
appDirectory: path.join(__dirname, 'dist', 'Boostnote-win32-x64'),
outputDirectory: path.join(__dirname, 'dist'),
authors: 'MAISIN&CO., Inc.',
@@ -109,7 +109,7 @@ module.exports = function (grunt) {
var done = this.async()
var opts = {
name: 'Boostnote',
arch: 'x64',
arch: 'ia32',
dir: __dirname,
version: grunt.config.get('pkg.config.electron-version'),
'app-version': grunt.config.get('pkg.version'),

View File

@@ -4,11 +4,6 @@ const path = require('path')
var error = null
function isFinderCalled () {
var argv = process.argv.slice(1)
return argv.some((arg) => arg.match(/--finder/))
}
function execMainApp () {
const appRootPath = path.join(process.execPath, '../..')
const updateDotExePath = path.join(appRootPath, 'Update.exe')
@@ -78,8 +73,4 @@ function execMainApp () {
require('./lib/main-app')
}
if (isFinderCalled()) {
require('./lib/finder-app')
} else {
execMainApp()
}
execMainApp()

View File

@@ -1,14 +0,0 @@
const electron = require('electron')
const app = electron.app
app.on('ready', function () {
if (process.platform === 'darwin') {
app.dock.hide()
}
/* eslint-disable */
finderWindow = require('./finder-window')
/* eslint-enable */
})
module.exports = app

View File

@@ -1,101 +0,0 @@
const electron = require('electron')
const { app } = electron
const BrowserWindow = electron.BrowserWindow
const Menu = electron.Menu
const MenuItem = electron.MenuItem
const Tray = electron.Tray
const path = require('path')
var config = {
width: 840,
height: 540,
show: false,
frame: false,
resizable: false,
zoomFactor: 1.0,
webPreferences: {
blinkFeatures: 'OverlayScrollbars'
},
skipTaskbar: true,
standardWindow: false
}
if (process.platform === 'darwin') {
config['always-on-top'] = true
}
var finderWindow = new BrowserWindow(config)
var url = path.resolve(__dirname, './finder.html')
finderWindow.loadURL('file://' + url)
finderWindow.setSkipTaskbar(true)
if (process.platform === 'darwin') {
finderWindow.setVisibleOnAllWorkspaces(true)
}
finderWindow.on('blur', function () {
hideFinder()
})
finderWindow.on('close', function (e) {
e.preventDefault()
finderWindow.hide()
})
var trayIcon = process.platform === 'darwin' || process.platform === 'win32'
? path.join(__dirname, '../resources/tray-icon-default.png')
: path.join(__dirname, '../resources/tray-icon.png')
var appIcon = new Tray(trayIcon)
appIcon.setToolTip('Boostnote')
if (process.platform === 'darwin') {
appIcon.setPressedImage(path.join(__dirname, '../resources/tray-icon-dark.png'))
}
var trayMenu = new Menu()
trayMenu.append(new MenuItem({
label: 'Open Main window',
click: function () {
finderWindow.webContents.send('open-main-from-tray')
}
}))
if (process.env.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon') {
trayMenu.append(new MenuItem({
label: 'Open Finder window',
click: function () {
finderWindow.webContents.send('open-finder-from-tray')
}
}))
}
trayMenu.append(new MenuItem({
label: 'Quit',
click: function () {
finderWindow.webContents.send('quit-from-tray')
}
}))
appIcon.setContextMenu(trayMenu)
appIcon.on('click', function (e) {
e.preventDefault()
appIcon.popUpContextMenu(trayMenu)
})
function hideFinder () {
if (process.platform === 'win32') {
finderWindow.minimize()
return
}
if (process.platform === 'darwin') {
Menu.sendActionToFirstResponder('hide:')
}
finderWindow.hide()
}
app.on('before-quit', function (e) {
finderWindow.removeAllListeners()
})
module.exports = finderWindow

View File

@@ -1,65 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<title>Boostnote Finder</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
<link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
<link rel="shortcut icon" href="favicon.ico">
<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css">
<style>
@font-face {
font-family: 'Lato';
src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
url('../resources/fonts/Lato-Regular.ttf') format('truetype');
font-style: normal;
font-weight: normal;
text-rendering: optimizeLegibility;
}
</style>
</head>
<body>
<div id="content"></div>
<script src="../node_modules/codemirror/lib/codemirror.js"></script>
<script src="../node_modules/codemirror/mode/meta.js"></script>
<script src="../node_modules/codemirror-mode-elixir/dist/elixir.js"></script>
<script src="../node_modules/codemirror/addon/mode/overlay.js"></script>
<script src="../node_modules/codemirror/addon/mode/loadmode.js"></script>
<script src="../node_modules/codemirror/keymap/sublime.js"></script>
<script src="../node_modules/codemirror/keymap/vim.js"></script>
<script src="../node_modules/codemirror/keymap/emacs.js"></script>
<script src="../node_modules/codemirror/addon/runmode/runmode.js"></script>
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
<script src="../node_modules/raphael/raphael.min.js"></script>
<script src="../node_modules/flowchart.js/release/flowchart.min.js"></script>
<script src="../node_modules/katex/dist/katex.min.js"></script>
<script src="../node_modules/react/dist/react.min.js"></script>
<script src="../node_modules/react-dom/dist/react-dom.min.js"></script>
<script src="../node_modules/redux/dist/redux.min.js"></script>
<script src="../node_modules/react-redux/dist/react-redux.min.js"></script>
<script>
window._ = require('lodash');
</script>
<script src="../node_modules/js-sequence-diagrams/fucknpm/sequence-diagram-min.js"></script>
<script>
const electron = require('electron')
electron.webFrame.setZoomLevelLimits(1, 1)
const _ = require('lodash')
var scriptUrl = _.find(electron.remote.process.argv, (a) => a === '--hot')
? 'http://localhost:8080/assets/finder.js'
: '../compiled/finder.js'
var scriptEl = document.createElement('script')
scriptEl.setAttribute('type', 'text/javascript')
scriptEl.setAttribute('src', scriptUrl)
document.body.appendChild(scriptEl)
</script>
</body>
</html>

View File

@@ -26,10 +26,6 @@ function toggleMainWindow () {
}
}
function toggleFinder () {
nodeIpc.server.broadcast('open-finder')
}
ipcMain.on('config-renew', (e, payload) => {
nodeIpc.server.broadcast('config-renew', payload)
@@ -37,11 +33,6 @@ ipcMain.on('config-renew', (e, payload) => {
var { config } = payload
var errors = []
try {
globalShortcut.register(config.hotkey.toggleFinder, toggleFinder)
} catch (err) {
errors.push('toggleFinder')
}
try {
globalShortcut.register(config.hotkey.toggleMain, toggleMainWindow)
} catch (err) {
@@ -61,12 +52,6 @@ ipcMain.on('config-renew', (e, payload) => {
nodeIpc.serve(
path.join(app.getPath('userData'), 'boostnote.service'),
function () {
nodeIpc.server.on('open-main-from-finder', toggleMainWindow)
nodeIpc.server.on('quit-from-finder', function () {
app.quit()
})
nodeIpc.server.on('connect', function (socket) {
nodeIpc.log('ipc server >> socket joinned'.rainbow)
socket.on('close', function () {
@@ -76,14 +61,6 @@ nodeIpc.serve(
nodeIpc.server.on('error', function (err) {
nodeIpc.log('Node IPC error'.rainbow, err)
})
// Todo: Direct connection between Main window renderer & Finder window renderer
nodeIpc.server.on('request-data-from-finder', function () {
nodeIpc.server.broadcast('request-data-from-finder')
})
nodeIpc.server.on('throttle-data', function (payload) {
nodeIpc.server.broadcast('throttle-data', payload)
})
}
)

View File

@@ -2,9 +2,6 @@ const electron = require('electron')
const app = electron.app
const Menu = electron.Menu
const ipc = electron.ipcMain
const path = require('path')
const ChildProcess = require('child_process')
const _ = require('lodash')
const GhReleases = require('electron-gh-releases')
// electron.crashReporter.start()
var ipcServer = null
@@ -72,17 +69,6 @@ ipc.on('update-app-confirm', function (event, msg) {
}
})
function spawnFinder () {
var finderArgv = [path.join(__dirname, 'finder-app.js'), '--finder']
if (_.find(process.argv, a => a === '--hot')) finderArgv.push('--hot')
var finderProcess = ChildProcess
.execFile(process.execPath, finderArgv)
app.on('before-quit', function () {
finderProcess.kill()
})
}
app.on('ready', function () {
mainWindow = require('./main-window')
@@ -90,15 +76,12 @@ app.on('ready', function () {
var menu = Menu.buildFromTemplate(template)
switch (process.platform) {
case 'darwin':
spawnFinder()
Menu.setApplicationMenu(menu)
break
case 'win32':
require('./finder-window')
mainWindow.setMenu(menu)
break
case 'linux':
require('./finder-window')
Menu.setApplicationMenu(menu)
mainWindow.setMenu(menu)
}
@@ -125,4 +108,3 @@ app.on('ready', function () {
})
module.exports = app

View File

@@ -4,6 +4,7 @@ const BrowserWindow = electron.BrowserWindow
const path = require('path')
const Config = require('electron-config')
const config = new Config()
const _ = require('lodash')
var showMenu = process.platform !== 'win32'
const windowSize = config.get('windowsize') || { width: 1080, height: 720 }
@@ -39,41 +40,28 @@ mainWindow.webContents.sendInputEvent({
keyCode: '\u0008'
})
if (process.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon') {
if (process.platform === 'darwin' || process.env.DESKTOP_SESSION === 'cinnamon') {
mainWindow.on('close', function (e) {
e.preventDefault()
if (process.platform === 'win32') {
quitApp()
} else {
if (mainWindow.isFullScreen()) {
mainWindow.once('leave-full-screen', function () {
mainWindow.hide()
})
mainWindow.setFullScreen(false)
} else {
if (mainWindow.isFullScreen()) {
mainWindow.once('leave-full-screen', function () {
mainWindow.hide()
}
})
mainWindow.setFullScreen(false)
} else {
mainWindow.hide()
}
})
app.on('before-quit', function (e) {
storeWindowSize()
mainWindow.removeAllListeners()
})
} else {
mainWindow.on('close', function () {
storeWindowSize()
})
app.on('window-all-closed', function () {
app.quit()
})
}
function quitApp () {
storeWindowSize()
app.quit()
}
mainWindow.on('resize', _.throttle(storeWindowSize, 500))
function storeWindowSize () {
try {

View File

@@ -1,7 +1,7 @@
{
"name": "boost",
"productName": "Boostnote",
"version": "0.8.20",
"version": "0.9.0",
"main": "index.js",
"description": "Boostnote",
"license": "GPL-3.0",
@@ -10,13 +10,13 @@
"hot": "electron ./index.js --hot",
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
"compile": "grunt compile",
"test": "PWD=$(pwd) NODE_ENV=test ava",
"test": "PWD=$(pwd) NODE_ENV=test ava --serial",
"fix": "npm run lint --fix",
"lint": "eslint .",
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\""
},
"config": {
"electron-version": "1.7.10"
"electron-version": "1.7.11"
},
"repository": {
"type": "git",
@@ -56,11 +56,12 @@
"codemirror-mode-elixir": "^1.1.1",
"electron-config": "^0.2.1",
"electron-gh-releases": "^2.0.2",
"electron-windows-installer": "^1.7.8",
"flowchart.js": "^1.6.5",
"font-awesome": "^4.3.0",
"immutable": "^3.8.1",
"js-sequence-diagrams": "^1000000.0.6",
"katex": "^0.7.1",
"katex": "^0.8.3",
"lodash": "^4.11.1",
"lodash-move": "^1.1.1",
"markdown-it": "^6.0.1",
@@ -103,7 +104,7 @@
"css-loader": "^0.19.0",
"devtron": "^1.1.0",
"dom-storage": "^2.0.2",
"electron": "1.7.10",
"electron": "1.7.11",
"electron-packager": "^6.0.0",
"eslint": "^3.13.1",
"eslint-config-standard": "^6.2.1",
@@ -113,6 +114,7 @@
"faker": "^3.1.0",
"grunt": "^0.4.5",
"grunt-electron-installer": "2.1.0",
"gulp": "^3.9.1",
"history": "^1.17.0",
"jsdom": "^9.4.2",
"json-loader": "^0.5.4",

View File

@@ -10,7 +10,6 @@
## Authors & Maintainers
- [Rokt33r](https://github.com/rokt33r)
- [Kohei TAKATA](https://github.com/kohei-takata)
- [Sosuke](https://github.com/sosukesuzuki)
- [Kazz](https://github.com/kazup01)
@@ -26,16 +25,17 @@ Boostnote is an open source project. It's an independent project with its ongoin
## Community
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
- [Twitter](https://twitter.com/boostnoteapp)
- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMjkxMzMwODYxMDI1LTgwZmRiODg0NzA5MWRmOTJjNzBjZjAwMmMyZGQ4Y2RkOGE0MDg0YjcyMjA5OGUzMmZhNmFiNTMzOTlkYWNlMTM)
- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMzAzMjI1MTIyNTQ3LTc2MjNiYWU3NTc1YjZlMTk3NzFmOWE1ZWU1MGRhMzBkMGIwMWFjOWMxMDRiM2I2NzkzYzc4OGZhNmVhZjYzZTM)
- [Blog](https://medium.com/boostnote)
- [Reddit](https://www.reddit.com/r/Boostnote/)
#### More Information
* [Website](https://boostnote.io)
* [Subscribe to the Newsletter](https://boostnote.io/#community): Get updates on Boostnote progress. No spam, ever :)
* Website: https://boostnote.io
* Newsletters: https://boostnote.io/#subscribe
* [Development](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md): Development configurations for Boostnote.
* Copyright (C) 2017 Maisin&Co.
* Copyright (C) 2016 - 2018 BoostIO, Inc.
#### License

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="14px" height="14px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="13px" height="13px" viewBox="0 0 14 14" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>icon-full</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 954 B

After

Width:  |  Height:  |  Size: 954 B

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="15px" height="15px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<title>icon-info</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="15px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>icon-mode-markdown-off</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="16px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="13px" height="13px" viewBox="0 0 16 16" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>icon-mode-split-on</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="14px" height="14px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>icon-previewoff-off</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="18px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="14px" height="14px" viewBox="0 0 18 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>icon-previewoff-on</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="18px" height="17px" viewBox="0 0 18 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="14px" height="13px" viewBox="0 0 18 17" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 48.1 (47250) - http://www.bohemiancoding.com/sketch -->
<title>icon-star</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.2 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="20px" height="19px" viewBox="0 0 20 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="15px" height="16px" viewBox="0 0 20 19" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<title>icon-starred</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="16px" height="18px" viewBox="0 0 16 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<svg width="13px" height="15px" viewBox="0 0 16 18" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<!-- Generator: Sketch 47.1 (45422) - http://www.bohemiancoding.com/sketch -->
<title>icon-trash</title>
<desc>Created with Sketch.</desc>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@@ -10,7 +10,6 @@
"theme": "monokai"
},
"hotkey": {
"toggleFinder": "Cmd + Alt + S",
"toggleMain": "Cmd + Alt + L"
},
"isSideNavFolded": false,

View File

@@ -5,7 +5,7 @@ const { parse } = require('browser/lib/RcParser')
// Unit test
test('RcParser should return a json object', t => {
const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 }
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleFinder': 'Cmd + Alt + S', 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
// [input, expected]
const validTestCases = [

View File

@@ -38,11 +38,6 @@ var config = Object.assign({}, skeleton, {
'NODE_ENV': JSON.stringify('production'),
'BABEL_ENV': JSON.stringify('production')
}
}),
new webpack.optimize.UglifyJsPlugin({
compressor: {
warnings: false
}
})
]
})

View File

@@ -4,8 +4,7 @@ const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin')
var config = {
entry: {
main: './browser/main/index.js',
finder: './browser/finder/index.js'
main: './browser/main/index.js'
},
resolve: {
extensions: ['', '.js', '.jsx', '.styl'],

1128
yarn.lock

File diff suppressed because it is too large Load Diff