mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 10:16:26 +00:00
Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7fbe456e79 | ||
|
|
9d8daac4cf | ||
|
|
ce199374d5 | ||
|
|
4af8615624 | ||
|
|
b6bb438507 | ||
|
|
49acd8a4f3 | ||
|
|
3e699a99d5 | ||
|
|
e4238f9283 | ||
|
|
9cd6d6d4c1 | ||
|
|
49a4b5feb4 | ||
|
|
c6eff157de | ||
|
|
80d16233e7 | ||
|
|
65e1a39027 | ||
|
|
d73b567bd4 | ||
|
|
787bb0a9e6 |
@@ -219,6 +219,12 @@ export default class CodeEditor extends React.Component {
|
||||
session.on('change', this.changeHandler)
|
||||
}
|
||||
|
||||
setValue (value) {
|
||||
let session = this.editor.getSession()
|
||||
session.setValue(value)
|
||||
this.value = value
|
||||
}
|
||||
|
||||
render () {
|
||||
let { className, fontFamily } = this.props
|
||||
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
|
||||
|
||||
@@ -73,6 +73,29 @@ class MarkdownEditor extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleCheckboxClick (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
let idMatch = /checkbox-([0-9]+)/
|
||||
let checkedMatch = /\[x\]/i
|
||||
let uncheckedMatch = /\[ \]/
|
||||
if (idMatch.test(e.target.getAttribute('id'))) {
|
||||
let lineIndex = parseInt(e.target.getAttribute('id').match(idMatch)[1], 10) - 1
|
||||
let lines = this.refs.code.value
|
||||
.split('\n')
|
||||
|
||||
let targetLine = lines[lineIndex]
|
||||
|
||||
if (targetLine.match(checkedMatch)) {
|
||||
lines[lineIndex] = targetLine.replace(checkedMatch, '[ ]')
|
||||
}
|
||||
if (targetLine.match(uncheckedMatch)) {
|
||||
lines[lineIndex] = targetLine.replace(uncheckedMatch, '[x]')
|
||||
}
|
||||
this.refs.code.setValue(lines.join('\n'))
|
||||
}
|
||||
}
|
||||
|
||||
focus () {
|
||||
if (this.state.status === 'PREVIEW') {
|
||||
this.setState({
|
||||
@@ -135,6 +158,7 @@ class MarkdownEditor extends React.Component {
|
||||
value={value}
|
||||
onMouseUp={(e) => this.handlePreviewMouseUp(e)}
|
||||
onMouseDown={(e) => this.handlePreviewMouseDown(e)}
|
||||
onCheckboxClick={(e) => this.handleCheckboxClick(e)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
@@ -5,11 +5,6 @@ import hljsTheme from 'browser/lib/hljsThemes'
|
||||
|
||||
const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1]
|
||||
const { shell } = require('electron')
|
||||
const goExternal = function (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
shell.openExternal(e.target.href)
|
||||
}
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
|
||||
@@ -27,6 +22,27 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.contextMenuHandler = (e) => this.handleContextMenu(e)
|
||||
this.mouseDownHandler = (e) => this.handleMouseDown(e)
|
||||
this.mouseUpHandler = (e) => this.handleMouseUp(e)
|
||||
this.anchorClickHandler = (e) => this.handlePreviewAnchorClick(e)
|
||||
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e)
|
||||
}
|
||||
|
||||
handlePreviewAnchorClick (e) {
|
||||
e.preventDefault()
|
||||
e.stopPropagation()
|
||||
|
||||
let href = e.target.getAttribute('href')
|
||||
if (_.isString(href) && href.match(/^#/)) {
|
||||
let targetElement = this.refs.root.contentWindow.document.getElementById(href.substring(1, href.length))
|
||||
if (targetElement != null) {
|
||||
this.getWindow().scrollTo(0, targetElement.offsetTop)
|
||||
}
|
||||
} else {
|
||||
shell.openExternal(e.target.href)
|
||||
}
|
||||
}
|
||||
|
||||
handleCheckboxClick (e) {
|
||||
this.props.onCheckboxClick(e)
|
||||
}
|
||||
|
||||
handleContextMenu (e) {
|
||||
@@ -34,10 +50,20 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
handleMouseDown (e) {
|
||||
if (e.target != null) {
|
||||
switch (e.target.tagName) {
|
||||
case 'A':
|
||||
case 'INPUT':
|
||||
return null
|
||||
}
|
||||
}
|
||||
if (this.props.onMouseDown != null) this.props.onMouseDown(e)
|
||||
}
|
||||
|
||||
handleMouseUp (e) {
|
||||
if (e.target != null && e.target.tagName === 'A') {
|
||||
return null
|
||||
}
|
||||
if (this.props.onMouseUp != null) this.props.onMouseUp(e)
|
||||
}
|
||||
|
||||
@@ -68,7 +94,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
|
||||
rewriteIframe () {
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||
el.removeEventListener('click', goExternal)
|
||||
el.removeEventListener('click', this.anchorClickHandler)
|
||||
})
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
|
||||
el.removeEventListener('click', this.checkboxClickHandler)
|
||||
})
|
||||
|
||||
let { value, fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme } = this.props
|
||||
@@ -111,7 +140,10 @@ export default class MarkdownPreview extends React.Component {
|
||||
this.refs.root.contentWindow.document.body.innerHTML = markdown(value)
|
||||
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||
el.addEventListener('mousedown', goExternal)
|
||||
el.addEventListener('click', this.anchorClickHandler)
|
||||
})
|
||||
Array.prototype.forEach.call(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
|
||||
el.addEventListener('click', this.checkboxClickHandler)
|
||||
})
|
||||
}
|
||||
|
||||
@@ -124,14 +156,14 @@ export default class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
scrollTo (targetRow) {
|
||||
let lineAnchors = this.getWindow().document.querySelectorAll('a.lineAnchor')
|
||||
let blocks = this.getWindow().document.querySelectorAll('body>[data-line]')
|
||||
|
||||
for (let index = 0; index < lineAnchors.length; index++) {
|
||||
let lineAnchor = lineAnchors[index]
|
||||
let row = parseInt(lineAnchor.getAttribute('data-key'))
|
||||
if (row > targetRow) {
|
||||
let targetAnchor = lineAnchors[index - 1]
|
||||
this.getWindow().scrollTo(0, targetAnchor.offsetTop)
|
||||
for (let index = 0; index < blocks.length; index++) {
|
||||
let block = blocks[index]
|
||||
let row = parseInt(block.getAttribute('data-line'))
|
||||
if (row > targetRow || index === blocks.length - 1) {
|
||||
block = blocks[index - 1]
|
||||
block != null && this.getWindow().scrollTo(0, block.offsetTop)
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,6 +68,10 @@ body
|
||||
padding 5px
|
||||
margin -5px
|
||||
border-radius 5px
|
||||
li
|
||||
label.taskListItem
|
||||
margin-left -2em
|
||||
background-color white
|
||||
div.math-rendered
|
||||
text-align center
|
||||
.math-failed
|
||||
@@ -102,12 +106,6 @@ a
|
||||
background-color alpha(#FFC95C, 0.3)
|
||||
&:visited
|
||||
color brandColor
|
||||
&.lineAnchor
|
||||
padding 0
|
||||
margin 0
|
||||
display block
|
||||
font-size 0
|
||||
height 0
|
||||
hr
|
||||
border-top none
|
||||
border-bottom solid 1px borderColor
|
||||
@@ -147,9 +145,6 @@ h6
|
||||
line-height 1.4em
|
||||
margin 1em 0 1em
|
||||
color #777
|
||||
|
||||
*:not(a.lineAnchor) + p, *:not(a.lineAnchor) + blockquote, *:not(a.lineAnchor) + ul, *:not(a.lineAnchor) + ol, *:not(a.lineAnchor) + pre
|
||||
margin-top 1em
|
||||
p
|
||||
line-height 1.6em
|
||||
margin 0 0 1em
|
||||
@@ -195,8 +190,6 @@ code
|
||||
font-size 0.85em
|
||||
text-decoration none
|
||||
margin-right 2px
|
||||
*:not(a.lineAnchor) + code
|
||||
margin-left 2px
|
||||
pre
|
||||
padding 0.5em !important
|
||||
border solid 1px alpha(borderColor, 0.5)
|
||||
|
||||
@@ -2,6 +2,7 @@ import markdownit from 'markdown-it'
|
||||
import emoji from 'markdown-it-emoji'
|
||||
import math from '@rokt33r/markdown-it-math'
|
||||
import hljs from 'highlight.js'
|
||||
import _ from 'lodash'
|
||||
|
||||
const katex = window.katex
|
||||
|
||||
@@ -59,21 +60,77 @@ md.use(math, {
|
||||
return output
|
||||
}
|
||||
})
|
||||
md.use(require('markdown-it-checkbox'))
|
||||
md.use(require('markdown-it-footnote'))
|
||||
// Override task item
|
||||
md.block.ruler.at('paragraph', function (state, startLine/*, endLine*/) {
|
||||
let content, terminate, i, l, token
|
||||
let nextLine = startLine + 1
|
||||
let terminatorRules = state.md.block.ruler.getRules('paragraph')
|
||||
let endLine = state.lineMax
|
||||
|
||||
let originalRenderToken = md.renderer.renderToken
|
||||
md.renderer.renderToken = function renderToken (tokens, idx, options) {
|
||||
let token = tokens[idx]
|
||||
// jump line-by-line until empty one or EOF
|
||||
for (; nextLine < endLine && !state.isEmpty(nextLine); nextLine++) {
|
||||
// this would be a code block normally, but after paragraph
|
||||
// it's considered a lazy continuation regardless of what's there
|
||||
if (state.sCount[nextLine] - state.blkIndent > 3) { continue }
|
||||
|
||||
let result = originalRenderToken.call(md.renderer, tokens, idx, options)
|
||||
if (token.map != null) {
|
||||
return result + '<a class=\'lineAnchor\' data-key=\'' + token.map[0] + '\'></a>'
|
||||
// quirk for blockquotes, this line should already be checked by that rule
|
||||
if (state.sCount[nextLine] < 0) { continue }
|
||||
|
||||
// Some tags can terminate paragraph without empty line.
|
||||
terminate = false
|
||||
for (i = 0, l = terminatorRules.length; i < l; i++) {
|
||||
if (terminatorRules[i](state, nextLine, endLine, true)) {
|
||||
terminate = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (terminate) { break }
|
||||
}
|
||||
|
||||
content = state.getLines(startLine, nextLine, state.blkIndent, false).trim()
|
||||
|
||||
state.line = nextLine
|
||||
|
||||
token = state.push('paragraph_open', 'p', 1)
|
||||
token.map = [ startLine, state.line ]
|
||||
|
||||
if (state.parentType === 'list') {
|
||||
let match = content.match(/^\[( |x)\] ?(.+)/i)
|
||||
if (match) {
|
||||
content = `<label class='taskListItem' for='checkbox-${startLine + 1}'><input type='checkbox'${match[1] !== ' ' ? ' checked' : ''} id='checkbox-${startLine + 1}'/> ${content.substring(4, content.length)}</label>`
|
||||
}
|
||||
}
|
||||
|
||||
token = state.push('inline', '', 0)
|
||||
token.content = content
|
||||
token.map = [ startLine, state.line ]
|
||||
token.children = []
|
||||
|
||||
token = state.push('paragraph_close', 'p', -1)
|
||||
|
||||
return true
|
||||
})
|
||||
|
||||
// Add line number attribute for scrolling
|
||||
let originalRender = md.renderer.render
|
||||
md.renderer.render = function render (tokens, options, env) {
|
||||
tokens.forEach((token) => {
|
||||
switch (token.type) {
|
||||
case 'heading_open':
|
||||
case 'paragraph_open':
|
||||
case 'blockquote_open':
|
||||
case 'table_open':
|
||||
token.attrPush(['data-line', token.map[0]])
|
||||
}
|
||||
})
|
||||
let result = originalRender.call(md.renderer, tokens, options, env)
|
||||
return result
|
||||
}
|
||||
window.md = md
|
||||
|
||||
export default function markdown (content) {
|
||||
if (content == null) content = ''
|
||||
if (!_.isString(content)) content = ''
|
||||
|
||||
return md.render(content.toString())
|
||||
return md.render(content)
|
||||
}
|
||||
|
||||
@@ -89,8 +89,9 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
save () {
|
||||
clearTimeout(this.saveQueue)
|
||||
this.saveQueue = setTimeout(() => {
|
||||
let { note, dispatch } = this.props
|
||||
|
||||
dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: this.state.note
|
||||
@@ -98,6 +99,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
dataApi
|
||||
.updateNote(note.storage, note.folder, note.key, this.state.note)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
handleFolderChange (e) {
|
||||
@@ -175,6 +177,8 @@ class MarkdownNoteDetail extends React.Component {
|
||||
handleDeleteMenuClick (e) {
|
||||
this.setState({
|
||||
isDeleting: true
|
||||
}, () => {
|
||||
this.refs.deleteConfirmButton.focus()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -191,6 +195,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
}
|
||||
ee.once('list:moved', dispatchHandler)
|
||||
ee.emit('list:next')
|
||||
ee.emit('list:focus')
|
||||
})
|
||||
}
|
||||
|
||||
@@ -200,6 +205,10 @@ class MarkdownNoteDetail extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
handleDeleteKeyDown (e) {
|
||||
if (e.keyCode === 27) this.handleDeleteCancelButtonClick(e)
|
||||
}
|
||||
|
||||
render () {
|
||||
let { storages, config } = this.props
|
||||
let { note } = this.state
|
||||
@@ -211,7 +220,10 @@ class MarkdownNoteDetail extends React.Component {
|
||||
>
|
||||
{this.state.isDeleting
|
||||
? <div styleName='info'>
|
||||
<div styleName='info-delete'>
|
||||
<div styleName='info-delete'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleDeleteKeyDown(e)}
|
||||
>
|
||||
|
||||
<span styleName='info-delete-message'>
|
||||
Are you sure to delete this note?
|
||||
@@ -221,6 +233,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
>Cancel</button>
|
||||
<button styleName='info-delete-confirmButton'
|
||||
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
|
||||
ref='deleteConfirmButton'
|
||||
>Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -250,13 +263,20 @@ class MarkdownNoteDetail extends React.Component {
|
||||
/>
|
||||
<button styleName='info-right-button'
|
||||
onClick={(e) => this.handleShareButtonClick(e)}
|
||||
disabled
|
||||
>
|
||||
<i className='fa fa-share-alt fa-fw'/>
|
||||
<span styleName='info-right-button-tooltip'
|
||||
style={{right: 20}}
|
||||
>Share Note</span>
|
||||
</button>
|
||||
<button styleName='info-right-button'
|
||||
onClick={(e) => this.handleContextButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-ellipsis-v'/>
|
||||
<span styleName='info-right-button-tooltip'
|
||||
style={{right: 5}}
|
||||
>More Options</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -77,11 +77,18 @@ $info-height = 75px
|
||||
padding 0
|
||||
&:active
|
||||
border-color $ui-button--focus-borderColor
|
||||
&:hover .left-control-newPostButton-tooltip
|
||||
display block
|
||||
&:hover .info-right-button-tooltip
|
||||
opacity 1
|
||||
&:focus
|
||||
border-color $ui-button--focus-borderColor
|
||||
|
||||
.info-right-button-tooltip
|
||||
tooltip()
|
||||
position fixed
|
||||
top 45px
|
||||
padding 5px
|
||||
opacity 0
|
||||
|
||||
.body
|
||||
absolute bottom left right
|
||||
top $info-height
|
||||
|
||||
@@ -99,8 +99,9 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
|
||||
save () {
|
||||
clearTimeout(this.saveQueue)
|
||||
this.saveQueue = setTimeout(() => {
|
||||
let { note, dispatch } = this.props
|
||||
|
||||
dispatch({
|
||||
type: 'UPDATE_NOTE',
|
||||
note: this.state.note
|
||||
@@ -108,6 +109,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
|
||||
dataApi
|
||||
.updateNote(note.storage, note.folder, note.key, this.state.note)
|
||||
}, 1000)
|
||||
}
|
||||
|
||||
handleFolderChange (e) {
|
||||
@@ -186,6 +188,8 @@ class SnippetNoteDetail extends React.Component {
|
||||
handleDeleteMenuClick (e) {
|
||||
this.setState({
|
||||
isDeleting: true
|
||||
}, () => {
|
||||
this.refs.deleteConfirmButton.focus()
|
||||
})
|
||||
}
|
||||
|
||||
@@ -300,6 +304,10 @@ class SnippetNoteDetail extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
handleDeleteKeyDown (e) {
|
||||
if (e.keyCode === 27) this.handleDeleteCancelButtonClick(e)
|
||||
}
|
||||
|
||||
render () {
|
||||
let { storages, config } = this.props
|
||||
let { note } = this.state
|
||||
@@ -383,7 +391,10 @@ class SnippetNoteDetail extends React.Component {
|
||||
>
|
||||
{this.state.isDeleting
|
||||
? <div styleName='info'>
|
||||
<div styleName='info-delete'>
|
||||
<div styleName='info-delete'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleDeleteKeyDown(e)}
|
||||
>
|
||||
|
||||
<span styleName='info-delete-message'>
|
||||
Are you sure to delete this note?
|
||||
@@ -393,6 +404,7 @@ class SnippetNoteDetail extends React.Component {
|
||||
>Cancel</button>
|
||||
<button styleName='info-delete-confirmButton'
|
||||
onClick={(e) => this.handleDeleteConfirmButtonClick(e)}
|
||||
ref='deleteConfirmButton'
|
||||
>Confirm</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -422,13 +434,20 @@ class SnippetNoteDetail extends React.Component {
|
||||
/>
|
||||
<button styleName='info-right-button'
|
||||
onClick={(e) => this.handleShareButtonClick(e)}
|
||||
disabled
|
||||
>
|
||||
<i className='fa fa-share-alt fa-fw'/>
|
||||
<span styleName='info-right-button-tooltip'
|
||||
style={{right: 20}}
|
||||
>Share Note</span>
|
||||
</button>
|
||||
<button styleName='info-right-button'
|
||||
onClick={(e) => this.handleContextButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-ellipsis-v'/>
|
||||
<span styleName='info-right-button-tooltip'
|
||||
style={{right: 5}}
|
||||
>More Options</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -77,10 +77,16 @@ $info-height = 75px
|
||||
padding 0
|
||||
&:active
|
||||
border-color $ui-button--focus-borderColor
|
||||
&:hover .left-control-newPostButton-tooltip
|
||||
display block
|
||||
&:hover .info-right-button-tooltip
|
||||
opacity 1
|
||||
&:focus
|
||||
border-color $ui-button--focus-borderColor
|
||||
.info-right-button-tooltip
|
||||
tooltip()
|
||||
position fixed
|
||||
top 45px
|
||||
padding 5px
|
||||
opacity 0
|
||||
|
||||
.body
|
||||
absolute bottom left right
|
||||
|
||||
@@ -47,11 +47,13 @@ class StarButton extends React.Component {
|
||||
onMouseLeave={(e) => this.handleMouseLeave(e)}
|
||||
onClick={this.props.onClick}
|
||||
>
|
||||
<i className={this.state.isActive || this.props.isActive
|
||||
<i styleName='icon'
|
||||
className={this.state.isActive || this.props.isActive
|
||||
? 'fa fa-star'
|
||||
: 'fa fa-star-o'
|
||||
}
|
||||
/>
|
||||
<span styleName='tooltip'>Star Note</span>
|
||||
</button>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,25 @@
|
||||
.root
|
||||
position relative
|
||||
padding 0
|
||||
transition transform 0.15s
|
||||
&:hover
|
||||
.icon
|
||||
transform rotate(-72deg)
|
||||
.tooltip
|
||||
opacity 1
|
||||
|
||||
|
||||
.root--active
|
||||
@extend .root
|
||||
color $ui-active-color
|
||||
.icon
|
||||
transform rotate(-72deg)
|
||||
.icon
|
||||
transition transform 0.15s
|
||||
|
||||
.tooltip
|
||||
tooltip()
|
||||
position fixed
|
||||
top 45px
|
||||
right 65px
|
||||
padding 5px
|
||||
opacity 0
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
margin 0
|
||||
padding 0
|
||||
border-style solid
|
||||
border-color $ui-borderColor
|
||||
border-color $ui-button--focus-borderColor
|
||||
border-width 0 0 0 3px
|
||||
line-height 18px
|
||||
background-color transparent
|
||||
|
||||
@@ -83,7 +83,7 @@
|
||||
border-radius 3px
|
||||
vertical-align middle
|
||||
border-style solid
|
||||
border-color $ui-borderColor
|
||||
border-color $ui-button--focus-borderColor
|
||||
border-width 0 0 0 3px
|
||||
background-color $ui-backgroundColor
|
||||
|
||||
|
||||
@@ -16,12 +16,16 @@ class NoteList extends React.Component {
|
||||
this.selectPriorNoteHandler = () => {
|
||||
this.selectPriorNote()
|
||||
}
|
||||
this.focusHandler = () => {
|
||||
this.refs.root.focus()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.refreshTimer = setInterval(() => this.forceUpdate(), 60 * 1000)
|
||||
ee.on('list:next', this.selectNextNoteHandler)
|
||||
ee.on('list:prior', this.selectPriorNoteHandler)
|
||||
ee.on('lost:focus', this.focusHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
@@ -29,6 +33,7 @@ class NoteList extends React.Component {
|
||||
|
||||
ee.off('list:next', this.selectNextNoteHandler)
|
||||
ee.off('list:prior', this.selectPriorNoteHandler)
|
||||
ee.off('lost:focus', this.focusHandler)
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
@@ -120,34 +125,20 @@ class NoteList extends React.Component {
|
||||
handleNoteListKeyDown (e) {
|
||||
if (e.metaKey || e.ctrlKey) return true
|
||||
|
||||
// if (e.keyCode === 65 && !e.shiftKey) {
|
||||
// e.preventDefault()
|
||||
// remote.getCurrentWebContents().send('top-new-post')
|
||||
// }
|
||||
if (e.keyCode === 65 && !e.shiftKey) {
|
||||
e.preventDefault()
|
||||
ee.emit('top:new-note')
|
||||
}
|
||||
|
||||
// if (e.keyCode === 65 && e.shiftKey) {
|
||||
// e.preventDefault()
|
||||
// remote.getCurrentWebContents().send('nav-new-folder')
|
||||
// }
|
||||
if (e.keyCode === 68) {
|
||||
e.preventDefault()
|
||||
ee.emit('detail:delete')
|
||||
}
|
||||
|
||||
// if (e.keyCode === 68) {
|
||||
// e.preventDefault()
|
||||
// remote.getCurrentWebContents().send('detail-delete')
|
||||
// }
|
||||
|
||||
// if (e.keyCode === 84) {
|
||||
// e.preventDefault()
|
||||
// remote.getCurrentWebContents().send('detail-title')
|
||||
// }
|
||||
|
||||
// if (e.keyCode === 69) {
|
||||
// e.preventDefault()
|
||||
// }
|
||||
|
||||
// if (e.keyCode === 83) {
|
||||
// e.preventDefault()
|
||||
// remote.getCurrentWebContents().send('detail-save')
|
||||
// }
|
||||
if (e.keyCode === 69) {
|
||||
e.preventDefault()
|
||||
ee.emit('detail:focus')
|
||||
}
|
||||
|
||||
if (e.keyCode === 38) {
|
||||
e.preventDefault()
|
||||
@@ -275,7 +266,7 @@ class NoteList extends React.Component {
|
||||
<div className='NoteList'
|
||||
styleName='root'
|
||||
ref='root'
|
||||
tabIndex='0'
|
||||
tabIndex='-1'
|
||||
onKeyDown={(e) => this.handleNoteListKeyDown(e)}
|
||||
style={this.props.style}
|
||||
>
|
||||
|
||||
@@ -88,19 +88,17 @@ $control-height = 34px
|
||||
padding 0
|
||||
&:active
|
||||
border-color $ui-button--active-backgroundColor
|
||||
&:hover .left-control-newPostButton-tooltip
|
||||
display block
|
||||
&:hover .control-newPostButton-tooltip
|
||||
opacity 1
|
||||
|
||||
.control-newPostButton-tooltip
|
||||
tooltip()
|
||||
position fixed
|
||||
line-height 1.4
|
||||
background-color $ui-tooltip-backgroundColor
|
||||
color $ui-tooltip-text-color
|
||||
font-size 10px
|
||||
margin-left -25px
|
||||
margin-top 5px
|
||||
padding 5px
|
||||
z-index 1
|
||||
border-radius 5px
|
||||
display none
|
||||
pointer-events none
|
||||
top 45px
|
||||
left 385px
|
||||
z-index 10
|
||||
padding 5px
|
||||
line-height normal
|
||||
opacity 0
|
||||
transition 0.1s
|
||||
|
||||
@@ -63,19 +63,21 @@ class TopBar extends React.Component {
|
||||
searchBlocks.forEach((block) => {
|
||||
if (block.match(/^#.+/)) {
|
||||
let tag = block.match(/#(.+)/)[1]
|
||||
let regExp = new RegExp(_.escapeRegExp(tag), 'i')
|
||||
notes = notes
|
||||
.filter((note) => {
|
||||
if (!_.isArray(note.tags)) return false
|
||||
return note.tags.some((_tag) => {
|
||||
return _tag === tag
|
||||
return _tag.match(regExp)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
let regExp = new RegExp(_.escapeRegExp(block), 'i')
|
||||
notes = notes.filter((note) => {
|
||||
if (note.type === 'SNIPPET_NOTE') {
|
||||
return note.description.match(block)
|
||||
return note.description.match(regExp)
|
||||
} else if (note.type === 'MARKDOWN_NOTE') {
|
||||
return note.content.match(block)
|
||||
return note.content.match(regExp)
|
||||
}
|
||||
return false
|
||||
})
|
||||
|
||||
@@ -313,16 +313,25 @@ class StorageItem extends React.Component {
|
||||
onClick={(e) => this.handleNewFolderButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-plus'/>
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -20}}
|
||||
>Add Folder</span>
|
||||
</button>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleExternalButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-external-link'/>
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -50}}
|
||||
>Open Storage folder</span>
|
||||
</button>
|
||||
<button styleName='header-control-button'
|
||||
onClick={(e) => this.handleUnlinkButtonClick(e)}
|
||||
>
|
||||
<i className='fa fa-unlink'/>
|
||||
<span styleName='header-control-button-tooltip'
|
||||
style={{left: -10}}
|
||||
>Unlink</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -47,8 +47,21 @@
|
||||
border-radius 2px
|
||||
border $ui-border
|
||||
margin-right 5px
|
||||
position relative
|
||||
&:last-child
|
||||
margin-right 0
|
||||
&:hover
|
||||
.header-control-button-tooltip
|
||||
opacity 1
|
||||
|
||||
.header-control-button-tooltip
|
||||
tooltip()
|
||||
position absolute
|
||||
opacity 0
|
||||
padding 5px
|
||||
top 25px
|
||||
z-index 10
|
||||
white-space nowrap
|
||||
|
||||
.folderList-item
|
||||
height 35px
|
||||
|
||||
@@ -29,6 +29,15 @@ $ui-tooltip-text-color = white
|
||||
$ui-tooltip-backgroundColor = alpha(#444, 70%)
|
||||
$ui-tooltip-button-backgroundColor = #D1D1D1
|
||||
$ui-tooltip-button--hover-backgroundColor = lighten(#D1D1D1, 30%)
|
||||
$ui-tooltip-font-size = 12px
|
||||
|
||||
tooltip()
|
||||
background-color $ui-tooltip-backgroundColor = alpha(#444, 70%)
|
||||
color $ui-tooltip-text-color = white
|
||||
font-size $ui-tooltip-font-size
|
||||
pointer-events none
|
||||
transition 0.1s
|
||||
|
||||
|
||||
// UI Input
|
||||
$ui-input--focus-borderColor = #369DCD
|
||||
|
||||
@@ -271,7 +271,7 @@ app.on('ready', function () {
|
||||
mainWindow.setMenu(menu)
|
||||
}
|
||||
mainWindow.on('close', function (e) {
|
||||
if (appQuit) {
|
||||
if (appQuit || process.platform != 'darwin') {
|
||||
app.quit()
|
||||
} else {
|
||||
mainWindow.hide()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "boost",
|
||||
"version": "0.6.1",
|
||||
"version": "0.6.2",
|
||||
"description": "Boostnote",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
@@ -48,6 +48,7 @@
|
||||
"markdown-it": "^6.0.1",
|
||||
"markdown-it-checkbox": "^1.1.0",
|
||||
"markdown-it-emoji": "^1.1.1",
|
||||
"markdown-it-footnote": "^3.0.0",
|
||||
"md5": "^2.0.0",
|
||||
"moment": "^2.10.3",
|
||||
"sander": "^0.5.1",
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
- Evernote
|
||||
- GitKraken
|
||||
- GitBook
|
||||
- Gist
|
||||
- Gistbox
|
||||
- Snippets Lab
|
||||
|
||||
|
||||
## Using stack
|
||||
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
- Evernote
|
||||
- GitKraken
|
||||
- GitBook
|
||||
- Gist
|
||||
- Gistbox
|
||||
- Snippets Lab
|
||||
|
||||
## Using stack
|
||||
|
||||
|
||||
15
readme.md
15
readme.md
@@ -2,7 +2,6 @@
|
||||
|
||||
Simple opensource note app for developer.
|
||||
|
||||
<<<<<<< HEAD
|
||||
- [日本語](./readme-ja.md)
|
||||
- [한국어](./readme-ko.md)
|
||||
|
||||
@@ -13,17 +12,6 @@ We just want you to enjoying writing anything. :grinning:
|
||||
- Target OS : OSX, Windows, Linux(also mobile somewhen!)
|
||||
- Cloud : Google drive, Dropbox, One drive, iCloud...
|
||||
- Remaining opensource forever!
|
||||
=======
|
||||
## !!v0.6.0 is Underconstruction!!
|
||||
|
||||
Check the links below for further information.
|
||||
|
||||
Progress summary
|
||||
https://github.com/BoostIO/Boostnote/issues/3
|
||||
|
||||
v0.6.0 Branch
|
||||
https://github.com/BoostIO/Boostnote/tree/0.6.0
|
||||
>>>>>>> no_submodules
|
||||
|
||||
## Inspired by
|
||||
|
||||
@@ -32,6 +20,9 @@ https://github.com/BoostIO/Boostnote/tree/0.6.0
|
||||
- Evernote
|
||||
- GitKraken
|
||||
- GitBook
|
||||
- Gist
|
||||
- Gistbox
|
||||
- Snippets Lab
|
||||
|
||||
## Using stack
|
||||
|
||||
|
||||
Reference in New Issue
Block a user