diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 00dc1f6d..29c3748b 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -7,6 +7,7 @@ import path from 'path' import copyImage from 'browser/main/lib/dataApi/copyImage' import { findStorage } from 'browser/lib/findStorage' import fs from 'fs' +import eventEmitter from 'browser/main/lib/eventEmitter' CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js' @@ -47,6 +48,40 @@ export default class CodeEditor extends React.Component { this.loadStyleHandler = (e) => { this.editor.refresh() } + this.searchHandler = (e, msg) => this.handleSearch(msg) + this.searchState = null + } + + handleSearch (msg) { + const cm = this.editor + const component = this + + if (component.searchState) cm.removeOverlay(component.searchState) + if (msg.length < 3) return + + cm.operation(function () { + component.searchState = makeOverlay(msg, 'searching') + cm.addOverlay(component.searchState) + + function makeOverlay (query, style) { + query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'), 'gi') + return { + token: function (stream) { + query.lastIndex = stream.pos + var match = query.exec(stream.string) + if (match && match.index === stream.pos) { + stream.pos += match[0].length || 1 + return style + } else if (match) { + stream.pos = match.index + } else { + stream.skipToEnd() + } + } + } + } + }) + this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {leading: false, trailing: true}) } componentDidMount () { @@ -107,6 +142,10 @@ export default class CodeEditor extends React.Component { this.editor.on('blur', this.blurHandler) this.editor.on('change', this.changeHandler) this.editor.on('paste', this.pasteHandler) + eventEmitter.on('top:search', this.searchHandler) + + eventEmitter.emit('code:init') + this.editor.on('scroll', this.scrollHandler) const editorTheme = document.getElementById('editorTheme') editorTheme.addEventListener('load', this.loadStyleHandler) @@ -126,6 +165,8 @@ export default class CodeEditor extends React.Component { this.editor.off('blur', this.blurHandler) this.editor.off('change', this.changeHandler) this.editor.off('paste', this.pasteHandler) + eventEmitter.off('top:search', this.searchHandler) + this.editor.off('scroll', this.scrollHandler) const editorTheme = document.getElementById('editorTheme') editorTheme.removeEventListener('load', this.loadStyleHandler) } @@ -231,27 +272,67 @@ export default class CodeEditor extends React.Component { } handlePaste (editor, e) { - const dataTransferItem = e.clipboardData.items[0] - if (!dataTransferItem.type.match('image')) return - - const blob = dataTransferItem.getAsFile() - const reader = new window.FileReader() - let base64data - - reader.readAsDataURL(blob) - reader.onloadend = () => { - base64data = reader.result.replace(/^data:image\/png;base64,/, '') - base64data += base64data.replace('+', ' ') - const binaryData = new Buffer(base64data, 'base64').toString('binary') - const imageName = Math.random().toString(36).slice(-16) - const storagePath = findStorage(this.props.storageKey).path - const imageDir = path.join(storagePath, 'images') - if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir) - const imagePath = path.join(imageDir, `${imageName}.png`) - fs.writeFile(imagePath, binaryData, 'binary') - const imageMd = `![${imageName}](${path.join('/:storage', `${imageName}.png`)})` - this.insertImageMd(imageMd) + const clipboardData = e.clipboardData + const dataTransferItem = clipboardData.items[0] + const pastedTxt = clipboardData.getData('text') + const isURL = (str) => { + const matcher = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/ + return matcher.test(str) } + if (dataTransferItem.type.match('image')) { + const blob = dataTransferItem.getAsFile() + const reader = new FileReader() + let base64data + + reader.readAsDataURL(blob) + reader.onloadend = () => { + base64data = reader.result.replace(/^data:image\/png;base64,/, '') + base64data += base64data.replace('+', ' ') + const binaryData = new Buffer(base64data, 'base64').toString('binary') + const imageName = Math.random().toString(36).slice(-16) + const storagePath = findStorage(this.props.storageKey).path + const imageDir = path.join(storagePath, 'images') + if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir) + const imagePath = path.join(imageDir, `${imageName}.png`) + fs.writeFile(imagePath, binaryData, 'binary') + const imageMd = `![${imageName}](${path.join('/:storage', `${imageName}.png`)})` + this.insertImageMd(imageMd) + } + } else if (this.props.fetchUrlTitle && isURL(pastedTxt)) { + this.handlePasteUrl(e, editor, pastedTxt) + } + } + + handleScroll (e) { + if (this.props.onScroll) { + this.props.onScroll(e) + } + } + + handlePasteUrl (e, editor, pastedTxt) { + e.preventDefault() + const taggedUrl = `<${pastedTxt}>` + editor.replaceSelection(taggedUrl) + + fetch(pastedTxt, { + method: 'get' + }).then((response) => { + return (response.text()) + }).then((response) => { + const parsedResponse = (new window.DOMParser()).parseFromString(response, 'text/html') + const value = editor.getValue() + const cursor = editor.getCursor() + const LinkWithTitle = `[${parsedResponse.title}](${pastedTxt})` + const newValue = value.replace(taggedUrl, LinkWithTitle) + editor.setValue(newValue) + editor.setCursor(cursor) + }).catch((e) => { + const value = editor.getValue() + const newValue = value.replace(taggedUrl, pastedTxt) + const cursor = editor.getCursor() + editor.setValue(newValue) + editor.setCursor(cursor) + }) } render () { diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index 52ab2873..f02a146a 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -5,7 +5,7 @@ import styles from './MarkdownEditor.styl' import CodeEditor from 'browser/components/CodeEditor' import MarkdownPreview from 'browser/components/MarkdownPreview' import eventEmitter from 'browser/main/lib/eventEmitter' -import { findStorage } from 'browser/lib/findStorage' +import {findStorage} from 'browser/lib/findStorage' class MarkdownEditor extends React.Component { constructor (props) { @@ -92,7 +92,9 @@ class MarkdownEditor extends React.Component { if (this.state.isLocked) return this.setState({ keyPressed: new Set() }) const { config } = this.props - if (config.editor.switchPreview === 'BLUR') { + if (config.editor.switchPreview === 'BLUR' || + (config.editor.switchPreview === 'DBL_CLICK' && this.state.status === 'CODE') + ) { const cursorPosition = this.refs.code.editor.getCursor() this.setState({ status: 'PREVIEW' @@ -104,6 +106,20 @@ class MarkdownEditor extends React.Component { } } + handleDoubleClick (e) { + if (this.state.isLocked) return + this.setState({keyPressed: new Set()}) + const { config } = this.props + if (config.editor.switchPreview === 'DBL_CLICK') { + this.setState({ + status: 'CODE' + }, () => { + this.refs.code.focus() + eventEmitter.emit('topbar:togglelockbutton', this.state.status) + }) + } + } + handlePreviewMouseDown (e) { this.previewMouseDownedAt = new Date() } @@ -245,6 +261,7 @@ class MarkdownEditor extends React.Component { displayLineNumbers={config.editor.displayLineNumbers} scrollPastEnd={config.editor.scrollPastEnd} storageKey={storageKey} + fetchUrlTitle={config.editor.fetchUrlTitle} onChange={(e) => this.handleChange(e)} onBlur={(e) => this.handleBlur(e)} /> @@ -264,6 +281,7 @@ class MarkdownEditor extends React.Component { scrollPastEnd={config.preview.scrollPastEnd} ref='preview' onContextMenu={(e) => this.handleContextMenu(e)} + onDoubleClick={(e) => this.handleDoubleClick(e)} tabIndex='0' value={this.state.renderValue} onMouseUp={(e) => this.handlePreviewMouseUp(e)} diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index ecaff1b8..c5b0355d 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -120,6 +120,8 @@ 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.DoubleClickHandler = (e) => this.handleDoubleClick(e) + this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {leading: false, trailing: true}) this.anchorClickHandler = (e) => this.handlePreviewAnchorClick(e) this.checkboxClickHandler = (e) => this.handleCheckboxClick(e) this.saveAsTextHandler = () => this.handleSaveAsText() @@ -150,10 +152,20 @@ export default class MarkdownPreview extends React.Component { this.props.onCheckboxClick(e) } + handleScroll (e) { + if (this.props.onScroll) { + this.props.onScroll(e) + } + } + handleContextMenu (e) { this.props.onContextMenu(e) } + handleDoubleClick (e) { + if (this.props.onDoubleClick != null) this.props.onDoubleClick(e) + } + handleMouseDown (e) { if (e.target != null) { switch (e.target.tagName) { @@ -271,8 +283,10 @@ export default class MarkdownPreview extends React.Component { this.refs.root.contentWindow.document.addEventListener('mousedown', this.mouseDownHandler) this.refs.root.contentWindow.document.addEventListener('mouseup', this.mouseUpHandler) + this.refs.root.contentWindow.document.addEventListener('dblclick', this.DoubleClickHandler) this.refs.root.contentWindow.document.addEventListener('drop', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler) + this.refs.root.contentWindow.document.addEventListener('scroll', this.scrollHandler) eventEmitter.on('export:save-text', this.saveAsTextHandler) eventEmitter.on('export:save-md', this.saveAsMdHandler) eventEmitter.on('export:save-html', this.saveAsHtmlHandler) @@ -283,8 +297,10 @@ export default class MarkdownPreview extends React.Component { this.refs.root.contentWindow.document.body.removeEventListener('contextmenu', this.contextMenuHandler) this.refs.root.contentWindow.document.removeEventListener('mousedown', this.mouseDownHandler) this.refs.root.contentWindow.document.removeEventListener('mouseup', this.mouseUpHandler) + this.refs.root.contentWindow.document.removeEventListener('dblclick', this.DoubleClickHandler) this.refs.root.contentWindow.document.removeEventListener('drop', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler) + this.refs.root.contentWindow.document.removeEventListener('scroll', this.scrollHandler) eventEmitter.off('export:save-text', this.saveAsTextHandler) eventEmitter.off('export:save-md', this.saveAsMdHandler) eventEmitter.off('export:save-html', this.saveAsHtmlHandler) diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index 2cf8e322..505fbaf4 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -2,6 +2,7 @@ import React from 'react' import CodeEditor from 'browser/components/CodeEditor' import MarkdownPreview from 'browser/components/MarkdownPreview' import { findStorage } from 'browser/lib/findStorage' +import _ from 'lodash' import styles from './MarkdownSplitEditor.styl' import CSSModules from 'browser/lib/CSSModules' @@ -12,6 +13,7 @@ class MarkdownSplitEditor extends React.Component { this.value = props.value this.focus = () => this.refs.code.focus() this.reload = () => this.refs.code.reload() + this.userScroll = true } handleOnChange () { @@ -19,6 +21,49 @@ class MarkdownSplitEditor extends React.Component { this.props.onChange() } + handleScroll (e) { + const previewDoc = _.get(this, 'refs.preview.refs.root.contentWindow.document') + const codeDoc = _.get(this, 'refs.code.editor.doc') + let srcTop, srcHeight, targetTop, targetHeight + + if (this.userScroll) { + if (e.doc) { + srcTop = _.get(e, 'doc.scrollTop') + srcHeight = _.get(e, 'doc.height') + targetTop = _.get(previewDoc, 'body.scrollTop') + targetHeight = _.get(previewDoc, 'body.scrollHeight') + } else { + srcTop = _.get(previewDoc, 'body.scrollTop') + srcHeight = _.get(previewDoc, 'body.scrollHeight') + targetTop = _.get(codeDoc, 'scrollTop') + targetHeight = _.get(codeDoc, 'height') + } + + const distance = (targetHeight * srcTop / srcHeight) - targetTop + const framerate = 1000 / 60 + const frames = 20 + const refractory = frames * framerate + + this.userScroll = false + + let frame = 0 + let scrollPos, time + const timer = setInterval(() => { + time = frame / frames + scrollPos = time < 0.5 + ? 2 * time * time // ease in + : -1 + (4 - 2 * time) * time // ease out + if (e.doc) _.set(previewDoc, 'body.scrollTop', targetTop + scrollPos * distance) + else _.get(this, 'refs.code.editor').scrollTo(0, targetTop + scrollPos * distance) + if (frame >= frames) { + clearInterval(timer) + setTimeout(() => { this.userScroll = true }, refractory) + } + frame++ + }, framerate) + } + } + handleCheckboxClick (e) { e.preventDefault() e.stopPropagation() @@ -66,8 +111,10 @@ class MarkdownSplitEditor extends React.Component { indentType={config.editor.indentType} indentSize={editorIndentSize} scrollPastEnd={config.editor.scrollPastEnd} + fetchUrlTitle={config.editor.fetchUrlTitle} storageKey={storageKey} onChange={this.handleOnChange.bind(this)} + onScroll={this.handleScroll.bind(this)} /> this.handleCheckboxClick(e)} + onScroll={this.handleScroll.bind(this)} showCopyNotification={config.ui.showCopyNotification} storagePath={storage.path} /> diff --git a/browser/components/NoteItem.js b/browser/components/NoteItem.js index 31769abf..2c93dc18 100644 --- a/browser/components/NoteItem.js +++ b/browser/components/NoteItem.js @@ -46,11 +46,22 @@ const TagElementList = (tags) => { * @param {Function} handleDragStart * @param {string} dateDisplay */ -const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteContextMenu, handleDragStart, pathname }) => ( +const NoteItem = ({ + isActive, + note, + dateDisplay, + handleNoteClick, + handleNoteContextMenu, + handleDragStart, + pathname, + storageName, + folderName, + viewType +}) => (
handleNoteClick(e, `${note.storage}-${note.key}`)} onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)} @@ -68,23 +79,33 @@ const NoteItem = ({ isActive, note, dateDisplay, handleNoteClick, handleNoteCont : Empty }
+ {['ALL', 'STORAGE'].includes(viewType) &&
+
{dateDisplay}
+
+
+ {viewType === 'ALL' && storageName} + {viewType === 'STORAGE' && folderName} +
+
+
} -
{dateDisplay}
- {note.isStarred - ? : '' - } - {note.isPinned && !pathname.match(/\/starred|\/trash/) - ? : '' - } - {note.type === 'MARKDOWN_NOTE' - ? - : '' - }
{note.tags.length > 0 ? TagElementList(note.tags) - : + : No tags + } +
+
+ {note.isStarred + ? : '' + } + {note.isPinned && !pathname.match(/\/home|\/starred|\/trash/) + ? : '' + } + {note.type === 'MARKDOWN_NOTE' + ? + : '' }
diff --git a/browser/components/NoteItem.styl b/browser/components/NoteItem.styl index c57908b0..f213348a 100644 --- a/browser/components/NoteItem.styl +++ b/browser/components/NoteItem.styl @@ -90,6 +90,26 @@ $control-height = 30px font-weight normal color $ui-inactive-text-color +.item-middle + font-size 13px + padding-left 2px + padding-bottom 2px + +.item-middle-time + color $ui-inactive-text-color + display inline-block + +.item-middle-app-meta + float right + .item-middle-app-meta-label + opacity 0.4 + color $ui-inactive-text-color + padding 0 3px + white-space nowrap + text-overflow ellipsis + overflow hidden + max-width 200px + .item-bottom position relative bottom 0px @@ -124,9 +144,7 @@ $control-height = 30px padding-bottom 2px .item-star - position absolute - right -6px - bottom 23px + position relative width 16px height 16px color alpha($ui-favorite-star-button-color, 60%) @@ -135,9 +153,7 @@ $control-height = 30px border-radius 17px .item-pin - position absolute - right 0px - bottom 2px + position relative width 34px height 34px color #E54D42 @@ -192,7 +208,7 @@ body[data-theme="dark"] .item-bottom-tagList-item transition 0.15s background-color alpha(white, 10%) - color $ui-dark-text-color + color $ui-dark-text-color .item-wrapper border-color alpha($ui-dark-button--active-backgroundColor, 60%) @@ -266,7 +282,7 @@ body[data-theme="solarized-dark"] .item-bottom-tagList-item transition 0.15s background-color alpha($ui-solarized-dark-noteList-backgroundColor, 10%) - color $ui-solarized-dark-text-color + color $ui-solarized-dark-text-color .item-wrapper border-color alpha($ui-solarized-dark-button--active-backgroundColor, 60%) @@ -304,4 +320,4 @@ body[data-theme="solarized-dark"] .item-bottom-tagList-empty color $ui-inactive-text-color - vertical-align middle \ No newline at end of file + vertical-align middle diff --git a/browser/components/NoteItemSimple.js b/browser/components/NoteItemSimple.js index 6b0dd4e0..0d2465e9 100644 --- a/browser/components/NoteItemSimple.js +++ b/browser/components/NoteItemSimple.js @@ -14,11 +14,20 @@ import styles from './NoteItemSimple.styl' * @param {Function} handleNoteContextMenu * @param {Function} handleDragStart */ -const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenu, handleDragStart, pathname }) => ( +const NoteItemSimple = ({ + isActive, + isAllNotesView, + note, + handleNoteClick, + handleNoteContextMenu, + handleDragStart, + pathname, + storage +}) => (
handleNoteClick(e, `${note.storage}-${note.key}`)} onContextMenu={e => handleNoteContextMenu(e, `${note.storage}-${note.key}`)} @@ -38,6 +47,11 @@ const NoteItemSimple = ({ isActive, note, handleNoteClick, handleNoteContextMenu ? note.title : Empty } + {isAllNotesView &&
+ + {storage.name} + +
}
) diff --git a/browser/components/NoteItemSimple.styl b/browser/components/NoteItemSimple.styl index fdf0c2e3..3097b82c 100644 --- a/browser/components/NoteItemSimple.styl +++ b/browser/components/NoteItemSimple.styl @@ -124,7 +124,7 @@ body[data-theme="dark"] .item-simple-bottom-tagList-item transition 0.15s background-color alpha(white, 10%) - color $ui-dark-text-color + color $ui-dark-text-color .item-simple--active border-color $ui-dark-borderColor @@ -188,7 +188,7 @@ body[data-theme="solarized-dark"] .item-simple-bottom-tagList-item transition 0.15s background-color alpha(white, 10%) - color $ui-solarized-dark-text-color + color $ui-solarized-dark-text-color .item-simple--active border-color $ui-solarized-dark-borderColor @@ -206,4 +206,9 @@ body[data-theme="solarized-dark"] // background-color alpha($ui-dark-button--active-backgroundColor, 60%) color #c0392b .item-simple-bottom-tagList-item - background-color alpha(#fff, 20%) \ No newline at end of file + background-color alpha(#fff, 20%) +.item-simple-right + float right + .item-simple-right-storageName + padding-left 4px + opacity 0.4 diff --git a/browser/components/SideNavFilter.js b/browser/components/SideNavFilter.js index dba26f92..2f839a84 100644 --- a/browser/components/SideNavFilter.js +++ b/browser/components/SideNavFilter.js @@ -17,7 +17,7 @@ import styles from './SideNavFilter.styl' const SideNavFilter = ({ isFolded, isHomeActive, handleAllNotesButtonClick, isStarredActive, handleStarredButtonClick, isTrashedActive, handleTrashedButtonClick, counterDelNote, - counterTotalNote, counterStarredNote + counterTotalNote, counterStarredNote, handleFilterButtonContextMenu }) => (
@@ -26,9 +26,9 @@ const SideNavFilter = ({ >
All Notes @@ -40,9 +40,9 @@ const SideNavFilter = ({ >
Starred @@ -54,12 +54,12 @@ const SideNavFilter = ({ >
- Trash + Trash {counterDelNote} diff --git a/browser/components/TagListItem.js b/browser/components/TagListItem.js index 2625412a..ebef7df4 100644 --- a/browser/components/TagListItem.js +++ b/browser/components/TagListItem.js @@ -12,10 +12,11 @@ import CSSModules from 'browser/lib/CSSModules' * @param {bool} isActive */ -const TagListItem = ({name, handleClickTagListItem, isActive}) => ( +const TagListItem = ({name, handleClickTagListItem, isActive, count}) => ( ) diff --git a/browser/components/TagListItem.styl b/browser/components/TagListItem.styl index cd3a5387..b35b30cf 100644 --- a/browser/components/TagListItem.styl +++ b/browser/components/TagListItem.styl @@ -48,6 +48,9 @@ overflow hidden text-overflow ellipsis +.tagList-item-count + padding 0 3px + body[data-theme="white"] .tagList-item color $ui-inactive-text-color @@ -63,6 +66,8 @@ body[data-theme="white"] color $ui-text-color &:hover background-color alpha($ui-button--active-backgroundColor, 60%) + .tagList-item-count + color $ui-text-color body[data-theme="dark"] .tagList-item @@ -81,4 +86,6 @@ body[data-theme="dark"] background-color alpha($ui-dark-button--active-backgroundColor, 50%) &:hover color $ui-dark-text-color - background-color alpha($ui-dark-button--active-backgroundColor, 50%) \ No newline at end of file + background-color alpha($ui-dark-button--active-backgroundColor, 50%) + .tagList-item-count + color $ui-dark-button--active-color diff --git a/browser/components/markdown.styl b/browser/components/markdown.styl index d1d306e9..b64af56c 100644 --- a/browser/components/markdown.styl +++ b/browser/components/markdown.styl @@ -220,6 +220,7 @@ pre background-color white &.CodeMirror height initial + flex-wrap wrap &>code flex 1 overflow-x auto @@ -229,6 +230,13 @@ pre padding 0 border none border-radius 0 + &>span.filename + width 100% + border-radius: 5px 0px 0px 0px + margin -8px 100% 8px -8px + padding 0px 6px + background-color #777; + color white &>span.lineNumber display none font-size 1em diff --git a/browser/finder/NoteDetail.js b/browser/finder/NoteDetail.js new file mode 100644 index 00000000..e69de29b diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js index c3510f89..d0801a1b 100644 --- a/browser/lib/markdown.js +++ b/browser/lib/markdown.js @@ -9,10 +9,11 @@ import {lastFindInArray} from './utils' const katex = window.katex const config = ConfigManager.get() -function createGutter (str) { - const lc = (str.match(/\n/g) || []).length +function createGutter (str, firstLineNumber) { + if (Number.isNaN(firstLineNumber)) firstLineNumber = 1 + const lastLineNumber = (str.match(/\n/g) || []).length + firstLineNumber - 1 const lines = [] - for (let i = 1; i <= lc; i++) { + for (let i = firstLineNumber; i <= lastLineNumber; i++) { lines.push('' + i + '') } return '' + lines.join('') + '' @@ -25,15 +26,22 @@ var md = markdownit({ xhtmlOut: true, breaks: true, highlight: function (str, lang) { - if (lang === 'flowchart') { + const delimiter = ':' + const langInfo = lang.split(delimiter) + const langType = langInfo[0] + const fileName = langInfo[1] || '' + const firstLineNumber = parseInt(langInfo[2], 10) + + if (langType === 'flowchart') { return `
${str}
` } - if (lang === 'sequence') { + if (langType === 'sequence') { return `
${str}
` } return '
' +
-      createGutter(str) +
-      '' +
+      '' + fileName + '' +
+      createGutter(str, firstLineNumber) +
+      '' +
       str +
       '
' } diff --git a/browser/main/Detail/MarkdownNoteDetail.js b/browser/main/Detail/MarkdownNoteDetail.js index bb76b8f3..a543a5aa 100755 --- a/browser/main/Detail/MarkdownNoteDetail.js +++ b/browser/main/Detail/MarkdownNoteDetail.js @@ -19,6 +19,7 @@ import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import ConfigManager from 'browser/main/lib/ConfigManager' import TrashButton from './TrashButton' import FullscreenButton from './FullscreenButton' +import RestoreButton from './RestoreButton' import PermanentDeleteButton from './PermanentDeleteButton' import InfoButton from './InfoButton' import ToggleModeButton from './ToggleModeButton' @@ -68,11 +69,8 @@ class MarkdownNoteDetail extends React.Component { } componentWillUnmount () { - if (this.saveQueue != null) this.saveNow() - } - - componentDidUnmount () { ee.off('topbar:togglelockbutton', this.toggleLockButton) + if (this.saveQueue != null) this.saveNow() } handleUpdateTag () { @@ -324,10 +322,7 @@ class MarkdownNoteDetail extends React.Component { const trashTopBar =
- this.handleUndoButtonClick(e)} - /> + this.handleUndoButtonClick(e)} />
this.handleTrashButtonClick(e)} /> @@ -362,12 +357,10 @@ class MarkdownNoteDetail extends React.Component { value={this.state.note.tags} onChange={this.handleUpdateTag.bind(this)} /> - - this.handleSwitchMode(e)} editorType={editorType} /> -
+ this.handleSwitchMode(e)} editorType={editorType} /> this.handleStarButtonClick(e)} isActive={note.isStarred} diff --git a/browser/main/Detail/MarkdownNoteDetail.styl b/browser/main/Detail/MarkdownNoteDetail.styl index 652532c7..ad20f0f2 100644 --- a/browser/main/Detail/MarkdownNoteDetail.styl +++ b/browser/main/Detail/MarkdownNoteDetail.styl @@ -7,6 +7,7 @@ background-color $ui-noteDetail-backgroundColor box-shadow none padding 20px 40px + overflow hidden .lock-button padding-bottom 3px @@ -44,7 +45,7 @@ margin 0 30px .body-noteEditor absolute top bottom left right - + body[data-theme="white"] .root box-shadow $note-detail-box-shadow diff --git a/browser/main/Detail/RestoreButton.js b/browser/main/Detail/RestoreButton.js new file mode 100644 index 00000000..0f9c992e --- /dev/null +++ b/browser/main/Detail/RestoreButton.js @@ -0,0 +1,21 @@ +import PropTypes from 'prop-types' +import React from 'react' +import CSSModules from 'browser/lib/CSSModules' +import styles from './RestoreButton.styl' + +const RestoreButton = ({ + onClick +}) => ( + +) + +RestoreButton.propTypes = { + onClick: PropTypes.func.isRequired +} + +export default CSSModules(RestoreButton, styles) diff --git a/browser/main/Detail/RestoreButton.styl b/browser/main/Detail/RestoreButton.styl new file mode 100644 index 00000000..58ce745d --- /dev/null +++ b/browser/main/Detail/RestoreButton.styl @@ -0,0 +1,22 @@ +.control-restoreButton + top 115px + topBarButtonRight() + &:hover .tooltip + opacity 1 + +.tooltip + tooltip() + position absolute + pointer-events none + top 50px + left 25px + z-index 200 + padding 5px + line-height normal + border-radius 2px + opacity 0 + transition 0.1s + +body[data-theme="dark"] + .control-restoreButton + topBarButtonDark() diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index c93611d4..aa9f2c79 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -20,6 +20,7 @@ import _ from 'lodash' import {findNoteTitle} from 'browser/lib/findNoteTitle' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import TrashButton from './TrashButton' +import RestoreButton from './RestoreButton' import PermanentDeleteButton from './PermanentDeleteButton' import InfoButton from './InfoButton' import InfoPanel from './InfoPanel' @@ -648,6 +649,7 @@ class SnippetNoteDetail extends React.Component { displayLineNumbers={config.editor.displayLineNumbers} keyMap={config.editor.keyMap} scrollPastEnd={config.editor.scrollPastEnd} + fetchUrlTitle={config.editor.fetchUrlTitle} onChange={(e) => this.handleCodeChange(index)(e)} ref={'code-' + index} /> @@ -668,10 +670,7 @@ class SnippetNoteDetail extends React.Component { const trashTopBar =
- this.handleUndoButtonClick(e)} - /> + this.handleUndoButtonClick(e)} />
this.handleTrashButtonClick(e)} /> diff --git a/browser/main/Detail/ToggleModeButton.styl b/browser/main/Detail/ToggleModeButton.styl index c69401f8..185a780c 100644 --- a/browser/main/Detail/ToggleModeButton.styl +++ b/browser/main/Detail/ToggleModeButton.styl @@ -5,8 +5,8 @@ width 52px display flex align-items center - position absolute - right 165px + position: relative + top 2px .active background-color #1EC38B width 33px @@ -55,4 +55,4 @@ body[data-theme="solarized-dark"] background-color #002B36 .active background-color #1EC38B - box-shadow 2px 0px 7px #222222 \ No newline at end of file + box-shadow 2px 0px 7px #222222 diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js index 7dd28340..8c3e8790 100644 --- a/browser/main/NoteList/index.js +++ b/browser/main/NoteList/index.js @@ -66,6 +66,10 @@ class NoteList extends React.Component { this.deleteNote = this.deleteNote.bind(this) this.focusNote = this.focusNote.bind(this) this.pinToTop = this.pinToTop.bind(this) + this.getNoteStorage = this.getNoteStorage.bind(this) + this.getNoteFolder = this.getNoteFolder.bind(this) + this.getViewType = this.getViewType.bind(this) + this.restoreNote = this.restoreNote.bind(this) // TODO: not Selected noteKeys but SelectedNote(for reusing) this.state = { @@ -109,14 +113,27 @@ class NoteList extends React.Component { componentDidUpdate (prevProps) { const { location } = this.props + const { selectedNoteKeys } = this.state + const visibleNoteKeys = this.notes.map(note => `${note.storage}-${note.key}`) + const note = this.notes[0] + const prevKey = prevProps.location.query.key + const noteKey = visibleNoteKeys.includes(prevKey) ? prevKey : note && `${note.storage}-${note.key}` - if (this.notes.length > 0 && location.query.key == null) { + if (note && location.query.key == null) { const { router } = this.context if (!location.pathname.match(/\/searched/)) this.contextNotes = this.getContextNotes() + + // A visible note is an active note + if (!selectedNoteKeys.includes(noteKey)) { + if (selectedNoteKeys.length === 1) selectedNoteKeys.pop() + selectedNoteKeys.push(noteKey) + ee.emit('list:moved') + } + router.replace({ pathname: location.pathname, query: { - key: this.notes[0].storage + '-' + this.notes[0].key + key: noteKey } }) return @@ -440,6 +457,7 @@ class NoteList extends React.Component { const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top' const deleteLabel = 'Delete Note' const cloneNote = 'Clone Note' + const restoreNote = 'Restore Note' const menu = new Menu() if (!location.pathname.match(/\/starred|\/trash/)) { @@ -448,6 +466,14 @@ class NoteList extends React.Component { click: this.pinToTop })) } + + if (location.pathname.match(/\/trash/)) { + menu.append(new MenuItem({ + label: restoreNote, + click: this.restoreNote + })) + } + menu.append(new MenuItem({ label: deleteLabel, click: this.deleteNote @@ -459,28 +485,50 @@ class NoteList extends React.Component { menu.popup() } - pinToTop () { + updateSelectedNotes (updateFunc, cleanSelection = true) { const { selectedNoteKeys } = this.state const { dispatch } = this.props const notes = this.notes.map((note) => Object.assign({}, note)) const selectedNotes = findNotesByKeys(notes, selectedNoteKeys) + if (!_.isFunction(updateFunc)) { + console.warn('Update function is not defined. No update will happen') + updateFunc = (note) => { return note } + } + Promise.all( - selectedNotes.map((note) => { - note.isPinned = !note.isPinned - return dataApi - .updateNote(note.storage, note.key, note) - }) - ) - .then((updatedNotes) => { - updatedNotes.forEach((note) => { - dispatch({ - type: 'UPDATE_NOTE', - note + selectedNotes.map((note) => { + note = updateFunc(note) + return dataApi + .updateNote(note.storage, note.key, note) }) - }) + ) + .then((updatedNotes) => { + updatedNotes.forEach((note) => { + dispatch({ + type: 'UPDATE_NOTE', + note + }) + }) + }) + + if (cleanSelection) { + this.selectNextNote() + } + } + + pinToTop () { + this.updateSelectedNotes((note) => { + note.isPinned = !note.isPinned + return note + }) + } + + restoreNote () { + this.updateSelectedNotes((note) => { + note.isTrashed = false + return note }) - this.setState({ selectedNoteKeys: [] }) } deleteNote () { @@ -678,6 +726,24 @@ class NoteList extends React.Component { }) } + getNoteStorage (note) { // note.storage = storage key + return this.props.data.storageMap.toJS()[note.storage] + } + + getNoteFolder (note) { // note.folder = folder key + return _.find(this.getNoteStorage(note).folders, ({ key }) => key === note.folder) + } + + getViewType () { + const { pathname } = this.props.location + const folder = /\/folders\/[a-zA-Z0-9]+/.test(pathname) + const storage = /\/storages\/[a-zA-Z0-9]+/.test(pathname) && !folder + const allNotes = pathname === '/home' + if (allNotes) return 'ALL' + if (folder) return 'FOLDER' + if (storage) return 'STORAGE' + } + render () { const { location, config } = this.props let { notes } = this.props @@ -714,6 +780,8 @@ class NoteList extends React.Component { } }) + const viewType = this.getViewType() + const noteList = notes .map(note => { if (note == null) { @@ -739,6 +807,9 @@ class NoteList extends React.Component { handleNoteClick={this.handleNoteClick.bind(this)} handleDragStart={this.handleDragStart.bind(this)} pathname={location.pathname} + folderName={this.getNoteFolder(note).name} + storageName={this.getNoteStorage(note).name} + viewType={viewType} /> ) } @@ -752,6 +823,9 @@ class NoteList extends React.Component { handleNoteClick={this.handleNoteClick.bind(this)} handleDragStart={this.handleDragStart.bind(this)} pathname={location.pathname} + folderName={this.getNoteFolder(note).name} + storageName={this.getNoteStorage(note).name} + viewType={viewType} /> ) }) diff --git a/browser/main/SideNav/index.js b/browser/main/SideNav/index.js index 9b95ae3e..6d05e37b 100644 --- a/browser/main/SideNav/index.js +++ b/browser/main/SideNav/index.js @@ -1,6 +1,9 @@ import PropTypes from 'prop-types' import React from 'react' import CSSModules from 'browser/lib/CSSModules' +const { remote } = require('electron') +const { Menu } = remote +import dataApi from 'browser/main/lib/dataApi' import styles from './SideNav.styl' import { openModal } from 'browser/main/lib/modal' import PreferencesModal from '../modals/PreferencesModal' @@ -89,6 +92,7 @@ class SideNav extends React.Component { counterTotalNote={data.noteMap._map.size - data.trashedSet._set.size} counterStarredNote={data.starredSet._set.size} counterDelNote={data.trashedSet._set.size} + handleFilterButtonContextMenu={this.handleFilterButtonContextMenu.bind(this)} /> @@ -113,18 +117,21 @@ class SideNav extends React.Component { tagListComponent () { const { data, location } = this.props - const tagList = data.tagNoteMap.map((tag, key) => { - return key + const tagList = data.tagNoteMap.map((tag, name) => { + return { name, size: tag.size } }) return ( - tagList.map(tag => ( - - )) + tagList.map(tag => { + return ( + + ) + }) ) } @@ -139,6 +146,34 @@ class SideNav extends React.Component { router.push(`/tags/${name}`) } + emptyTrash (entries) { + const { dispatch } = this.props + const deletionPromises = entries.map((storageAndNoteKey) => { + const storageKey = storageAndNoteKey.split('-')[0] + const noteKey = storageAndNoteKey.split('-')[1] + return dataApi.deleteNote(storageKey, noteKey) + }) + Promise.all(deletionPromises) + .then((arrayOfStorageAndNoteKeys) => { + arrayOfStorageAndNoteKeys.forEach(({ storageKey, noteKey }) => { + dispatch({ type: 'DELETE_NOTE', storageKey, noteKey }) + }) + }) + .catch((err) => { + console.error('Cannot Delete note: ' + err) + }) + console.log('Trash emptied') + } + + handleFilterButtonContextMenu (event) { + const { data } = this.props + const entries = data.trashedSet.toJS() + const menu = Menu.buildFromTemplate([ + { label: 'Empty Trash', click: () => this.emptyTrash(entries) } + ]) + menu.popup() + } + render () { const { data, location, config, dispatch } = this.props diff --git a/browser/main/TopBar/index.js b/browser/main/TopBar/index.js index 11d31abd..6b4a118e 100644 --- a/browser/main/TopBar/index.js +++ b/browser/main/TopBar/index.js @@ -22,14 +22,18 @@ class TopBar extends React.Component { this.focusSearchHandler = () => { this.handleOnSearchFocus() } + + this.codeInitHandler = this.handleCodeInit.bind(this) } componentDidMount () { ee.on('top:focus-search', this.focusSearchHandler) + ee.on('code:init', this.codeInitHandler) } componentWillUnmount () { ee.off('top:focus-search', this.focusSearchHandler) + ee.off('code:init', this.codeInitHandler) } handleKeyDown (e) { @@ -73,14 +77,16 @@ class TopBar extends React.Component { handleSearchChange (e) { const { router } = this.context + const keyword = this.refs.searchInput.value if (this.state.isAlphabet || this.state.isConfirmTranslation) { router.push('/searched') } else { e.preventDefault() } this.setState({ - search: this.refs.searchInput.value + search: keyword }) + ee.emit('top:search', keyword) } handleSearchFocus (e) { @@ -115,6 +121,10 @@ class TopBar extends React.Component { } } + handleCodeInit () { + ee.emit('top:search', this.refs.searchInput.value) + } + render () { const { config, style, location } = this.props return ( diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index fde7dafd..0c8d6ee9 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -36,7 +36,8 @@ export const DEFAULT_CONFIG = { displayLineNumbers: true, switchPreview: 'BLUR', // Available value: RIGHTCLICK, BLUR scrollPastEnd: false, - type: 'SPLIT' + type: 'SPLIT', + fetchUrlTitle: true }, preview: { fontSize: '14', diff --git a/browser/main/modals/NewNoteModal.js b/browser/main/modals/NewNoteModal.js index 24b150cb..8322d99f 100644 --- a/browser/main/modals/NewNoteModal.js +++ b/browser/main/modals/NewNoteModal.js @@ -35,14 +35,16 @@ class NewNoteModal extends React.Component { content: '' }) .then((note) => { + const noteHash = `${note.storage}-${note.key}` dispatch({ type: 'UPDATE_NOTE', note: note }) hashHistory.push({ pathname: location.pathname, - query: {key: note.storage + '-' + note.key} + query: {key: noteHash} }) + ee.emit('list:jump', noteHash) ee.emit('detail:focus') this.props.close() }) @@ -73,14 +75,16 @@ class NewNoteModal extends React.Component { }] }) .then((note) => { + const noteHash = `${note.storage}-${note.key}` dispatch({ type: 'UPDATE_NOTE', note: note }) hashHistory.push({ pathname: location.pathname, - query: {key: note.storage + '-' + note.key} + query: {key: noteHash} }) + ee.emit('list:jump', noteHash) ee.emit('detail:focus') this.props.close() }) diff --git a/browser/main/modals/PreferencesModal/InfoTab.js b/browser/main/modals/PreferencesModal/InfoTab.js index 892b6ee2..25c0b255 100644 --- a/browser/main/modals/PreferencesModal/InfoTab.js +++ b/browser/main/modals/PreferencesModal/InfoTab.js @@ -83,7 +83,7 @@ class InfoTab extends React.Component { >GitHub
  • - this.handleLinkClick(e)} >Blog
  • diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index df35e260..50e13f6c 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -76,7 +76,8 @@ class UiTab extends React.Component { displayLineNumbers: this.refs.editorDisplayLineNumbers.checked, switchPreview: this.refs.editorSwitchPreview.value, keyMap: this.refs.editorKeyMap.value, - scrollPastEnd: this.refs.scrollPastEnd.checked + scrollPastEnd: this.refs.scrollPastEnd.checked, + fetchUrlTitle: this.refs.editorFetchUrlTitle.checked }, preview: { fontSize: this.refs.previewFontSize.value, @@ -283,6 +284,7 @@ class UiTab extends React.Component { onChange={(e) => this.handleUIChange(e)} > +
    @@ -327,6 +329,17 @@ class UiTab extends React.Component {
    +
    + +
    +
    Preview
    diff --git a/docs/de/build.md b/docs/de/build.md index 44b744ca..3c7c8ac6 100644 --- a/docs/de/build.md +++ b/docs/de/build.md @@ -1,5 +1,5 @@ # Build -Diese Seite ist auch verfügbar in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md). +Diese Seite ist auch verfügbar in [Japanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Koreanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Vereinfachtem Chinesisch](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [Französisch](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) und [Deutsch](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md). ## Umgebungen * npm: 4.x diff --git a/docs/de/debug.md b/docs/de/debug.md index ee1a734c..6c3de3dc 100644 --- a/docs/de/debug.md +++ b/docs/de/debug.md @@ -1,25 +1,31 @@ # How to debug Boostnote (Electron app) -Diese Seite ist auch verfügbar in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) and [German](https://github.com/BoostIO/Boostnote/blob/add-german-documents/docs/de/debug.md). -Boostnote is eine Electron app, somit basiert sie auf Chromium; Entwickler können die `Developer Tools` verwenden, wie Google Chrome. +Diese Seite ist auch verfügbar in [Japanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Koreanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Vereinfachtem Chinesisch](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [Französisch](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) und [Deutsch](https://github.com/BoostIO/Boostnote/blob/master/docs/de/debug.md). + + +Boostnote ist eine Electron App und basiert auf Chromium. + +Zum Entwicklen verwendest du am Besten die `Developer Tools` von Google Chrome verwenden. Diese kannst du ganz einfach im unter dem Menüpunkt `View` mit `Toggle Developer Tools` aktivieren: -Du kannst die `Developer Tools` so einschalten: ![how_to_toggle_devTools](https://cloud.githubusercontent.com/assets/11307908/24343585/162187e2-127c-11e7-9c01-23578db03ecf.png) -Die `Developer Tools` schauen dann ungefähr so aus: +Die Anzeige der `Developer Tools` sieht in etwa so aus: + ![Developer_Tools](https://cloud.githubusercontent.com/assets/11307908/24343545/eff9f3a6-127b-11e7-94cf-cb67bfda634a.png) -Wenn Fehler vorkommen, werden die Fehlermeldungen in der `console` ausgegeben. ## Debugging -Zum Beispiel kannst du mit dem `debugger` Haltepunkte im Code setzen wie hier veranschaulicht: + +Fehlermeldungen werden in der Regel in der `console` ausgegeben, die du über den gleichnamigen Reiter der `Developer Tools` anzeigen lassen kannst. Zum Debuggen kannst du beispielsweise über den `debugger` Haltepunkte im Code setzen. + ![debugger](https://cloud.githubusercontent.com/assets/11307908/24343879/9459efea-127d-11e7-9943-f60bf7f66d4a.png) -Das ist ledigtlich ein Beispiel, du kannst die Art von Debugging verwenden die für dich am besten ist. +Du kannst aber natürlich auch die Art von Debugging verwenden mit der du am besten zurecht kommst. ## Referenz + * [Official document of Google Chrome about debugging](https://developer.chrome.com/devtools) --- -Special thanks: Translated by [gino909](https://github.com/gino909) +Special thanks: Translated by [gino909](https://github.com/gino909), [mdeuerlein](https://github.com/mdeuerlein) diff --git a/docs/debug.md b/docs/debug.md index 30c217a4..78a71137 100644 --- a/docs/debug.md +++ b/docs/debug.md @@ -1,5 +1,5 @@ # How to debug Boostnote (Electron app) -This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) and [German](https://github.com/BoostIO/Boostnote/blob/add-german-documents/docs/de/debug.md). +This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/debug.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/debug.md). Boostnote is an Electron app so it's based on Chromium; developers can use `Developer Tools` just like Google Chrome. diff --git a/docs/fr/build.md b/docs/fr/build.md index 0d718742..7003de84 100644 --- a/docs/fr/build.md +++ b/docs/fr/build.md @@ -1,5 +1,5 @@ # Build -Cette page est également disponible en [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), et en [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md). +Cette page est également disponible en [Angalis](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md), [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md) et en [Allemand](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md) ## Environnements * npm: 4.x diff --git a/docs/fr/debug.md b/docs/fr/debug.md index 9395e4f9..f0b1be4b 100644 --- a/docs/fr/debug.md +++ b/docs/fr/debug.md @@ -1,5 +1,5 @@ # Comment débugger Boostnote (Application Electron) -Cette page est également disponible en [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), et en [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md) +Cette page est également disponible en [Angalis](https://github.com/BoostIO/Boostnote/blob/master/docs/debug.md), [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/debug.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/debug.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/debug.md), [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/debug.md) et en [Allemand](https://github.com/BoostIO/Boostnote/blob/master/docs/de/debug.md) Boostnote est une application Electron donc basée sur Chromium. Il est possible d'utiliser les `Developer Tools` comme dans Google Chrome. @@ -19,4 +19,4 @@ Par exemple, vous pouvez utiliser le `debugger` pour placer un point d'arrêt da C'est une façon comme une autre de faire, vous pouvez trouver une façon de débugger que vous trouverez plus adaptée. ## Références -* [Documentation officiel de Google Chrome sur le debugging](https://developer.chrome.com/devtools) \ No newline at end of file +* [Documentation officiel de Google Chrome sur le debugging](https://developer.chrome.com/devtools) diff --git a/package.json b/package.json index e61ea055..db2a9733 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "boost", "productName": "Boostnote", - "version": "0.9.0", + "version": "0.10.0", "main": "index.js", "description": "Boostnote", "license": "GPL-3.0", diff --git a/readme.md b/readme.md index 40012652..67a5689d 100644 --- a/readme.md +++ b/readme.md @@ -26,7 +26,7 @@ Boostnote is an open source project. It's an independent project with its ongoin - [Facebook Group](https://www.facebook.com/groups/boostnote/) - [Twitter](https://twitter.com/boostnoteapp) - [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMzAzMjI1MTIyNTQ3LTc2MjNiYWU3NTc1YjZlMTk3NzFmOWE1ZWU1MGRhMzBkMGIwMWFjOWMxMDRiM2I2NzkzYzc4OGZhNmVhZjYzZTM) -- [Blog](https://medium.com/boostnote) +- [Blog](https://boostlog.io/@junp1234) - [Reddit](https://www.reddit.com/r/Boostnote/)