diff --git a/.editorconfig b/.editorconfig index a4730cbf..8c5bd614 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# EditorConfig is awesome: http://EditorConfig.org +# EditorConfig is awesome: https://EditorConfig.org # top-most EditorConfig file root = true diff --git a/.vscode/launch.json b/.vscode/launch.json index a742a59e..9d1cc4ec 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -17,7 +17,7 @@ "${workspaceFolder}/index.js" ], "windows": { - "runtimeExecutable": "${workspaceFolder}/node_modeules/.bin/electron.cmd" + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" } }, { diff --git a/Backers.md b/Backers.md deleted file mode 100644 index 18d221bf..00000000 --- a/Backers.md +++ /dev/null @@ -1,72 +0,0 @@ -
+ ${token.fileName} +` + }, mermaid: token => { return `${content}+
${token.fileName}
diff --git a/browser/lib/newNote.js b/browser/lib/newNote.js
index 0b64d0e1..d8ef196f 100644
--- a/browser/lib/newNote.js
+++ b/browser/lib/newNote.js
@@ -18,7 +18,8 @@ export function createMarkdownNote (storage, folder, dispatch, location, params,
folder: folder,
title: '',
tags,
- content: ''
+ content: '',
+ linesHighlighted: []
})
.then(note => {
const noteHash = note.key
@@ -45,6 +46,8 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
tags = params.tagname.split(' ')
}
+ const defaultLanguage = config.editor.snippetDefaultLanguage === 'Auto Detect' ? null : config.editor.snippetDefaultLanguage
+
return dataApi
.createNote(storage, {
type: 'SNIPPET_NOTE',
@@ -55,8 +58,9 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
snippets: [
{
name: '',
- mode: config.editor.snippetDefaultLanguage || 'text',
- content: ''
+ mode: defaultLanguage,
+ content: '',
+ linesHighlighted: []
}
]
})
diff --git a/browser/lib/slugify.js b/browser/lib/slugify.js
new file mode 100644
index 00000000..a3447a90
--- /dev/null
+++ b/browser/lib/slugify.js
@@ -0,0 +1,17 @@
+import diacritics from 'diacritics-map'
+
+function replaceDiacritics (str) {
+ return str.replace(/[À-ž]/g, function (ch) {
+ return diacritics[ch] || ch
+ })
+}
+
+module.exports = function slugify (title) {
+ let slug = title.trim()
+
+ slug = replaceDiacritics(slug)
+
+ slug = slug.replace(/[^\w\s-]/g, '').replace(/\s+/g, '-')
+
+ return encodeURI(slug).replace(/\-+$/, '')
+}
diff --git a/browser/main/Detail/MarkdownNoteDetail.js b/browser/main/Detail/MarkdownNoteDetail.js
index b4e7a5b3..bc6cd499 100755
--- a/browser/main/Detail/MarkdownNoteDetail.js
+++ b/browser/main/Detail/MarkdownNoteDetail.js
@@ -39,12 +39,14 @@ class MarkdownNoteDetail extends React.Component {
isMovingNote: false,
note: Object.assign({
title: '',
- content: ''
+ content: '',
+ linesHighlighted: []
}, props.note),
isLockButtonShown: false,
isLocked: false,
editorType: props.config.editor.type
}
+
this.dispatchTimer = null
this.toggleLockButton = this.handleToggleLockButton.bind(this)
@@ -71,7 +73,7 @@ class MarkdownNoteDetail extends React.Component {
if (!this.state.isMovingNote && (isNewNote || hasDeletedTags)) {
if (this.saveQueue != null) this.saveNow()
this.setState({
- note: Object.assign({}, nextProps.note)
+ note: Object.assign({linesHighlighted: []}, nextProps.note)
}, () => {
this.refs.content.reload()
if (this.refs.tags) this.refs.tags.reset()
@@ -361,6 +363,7 @@ class MarkdownNoteDetail extends React.Component {
value={note.content}
storageKey={note.storage}
noteKey={note.key}
+ linesHighlighted={note.linesHighlighted}
onChange={this.handleUpdateContent.bind(this)}
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
/>
@@ -371,6 +374,7 @@ class MarkdownNoteDetail extends React.Component {
value={note.content}
storageKey={note.storage}
noteKey={note.key}
+ linesHighlighted={note.linesHighlighted}
onChange={this.handleUpdateContent.bind(this)}
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
/>
diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js
index 887e5237..e9b0ee37 100644
--- a/browser/main/Detail/SnippetNoteDetail.js
+++ b/browser/main/Detail/SnippetNoteDetail.js
@@ -48,7 +48,7 @@ class SnippetNoteDetail extends React.Component {
note: Object.assign({
description: ''
}, props.note, {
- snippets: props.note.snippets.map((snippet) => Object.assign({}, snippet))
+ snippets: props.note.snippets.map((snippet) => Object.assign({linesHighlighted: []}, snippet))
})
}
@@ -76,8 +76,9 @@ class SnippetNoteDetail extends React.Component {
const nextNote = Object.assign({
description: ''
}, nextProps.note, {
- snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
+ snippets: nextProps.note.snippets.map((snippet) => Object.assign({linesHighlighted: []}, snippet))
})
+
this.setState({
snippetIndex: 0,
note: nextNote
@@ -410,6 +411,8 @@ class SnippetNoteDetail extends React.Component {
return (e) => {
const snippets = this.state.note.snippets.slice()
snippets[index].content = this.refs['code-' + index].value
+ snippets[index].linesHighlighted = e.options.linesHighlighted
+
this.setState(state => ({note: Object.assign(state.note, {snippets: snippets})}))
this.setState(state => ({
note: state.note
@@ -596,13 +599,16 @@ class SnippetNoteDetail extends React.Component {
}
addSnippet () {
- const { config } = this.props
+ const { config: { editor: { snippetDefaultLanguage } } } = this.props
const { note } = this.state
+ const defaultLanguage = snippetDefaultLanguage === 'Auto Detect' ? null : snippetDefaultLanguage
+
note.snippets = note.snippets.concat([{
name: '',
- mode: config.editor.snippetDefaultLanguage || 'text',
- content: ''
+ mode: defaultLanguage,
+ content: '',
+ linesHighlighted: []
}])
const snippetIndex = note.snippets.length - 1
@@ -668,6 +674,8 @@ class SnippetNoteDetail extends React.Component {
const storageKey = note.storage
const folderKey = note.folder
+ const autoDetect = config.editor.snippetDefaultLanguage === 'Auto Detect'
+
let editorFontSize = parseInt(config.editor.fontSize, 10)
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
let editorIndentSize = parseInt(config.editor.indentSize, 10)
@@ -692,10 +700,6 @@ class SnippetNoteDetail extends React.Component {
const viewList = note.snippets.map((snippet, index) => {
const isActive = this.state.snippetIndex === index
-
- let syntax = CodeMirror.findModeByName(convertModeName(snippet.mode))
- if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
-
return this.handleCodeChange(index)(e)}
ref={'code-' + index}
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
storageKey={storageKey}
/>
:
}
diff --git a/browser/main/Detail/SnippetNoteDetail.styl b/browser/main/Detail/SnippetNoteDetail.styl
index e3bb31c6..1af93645 100644
--- a/browser/main/Detail/SnippetNoteDetail.styl
+++ b/browser/main/Detail/SnippetNoteDetail.styl
@@ -31,7 +31,7 @@
.tabList
absolute left right
- top 55px
+ top 70px
height 30px
display flex
background-color $ui-noteDetail-backgroundColor
@@ -57,6 +57,9 @@
.tabList .tabButton
navWhiteButtonColor()
width 30px
+ border-left 1px solid $ui-borderColor
+ border-top 1px solid $ui-borderColor
+ border-right 1px solid $ui-borderColor
.tabView
absolute left right bottom
@@ -98,17 +101,34 @@
opacity 0
transition 0.1s
-body[data-theme="white"]
+body[data-theme="white"], body[data-theme="default"]
.root
box-shadow $note-detail-box-shadow
border none
+ .tabButton
+ &:hover
+ background-color alpha($ui-button--active-backgroundColor, 20%)
+ color $ui-text-color
+ transition 0.15s
+
body[data-theme="dark"]
.root
border-left 1px solid $ui-dark-borderColor
background-color $ui-dark-noteDetail-backgroundColor
box-shadow none
+ .tabList .tabButton
+ border-color $ui-dark-borderColor
+ &:hover
+ background-color alpha($ui-dark-button--active-backgroundColor, 20%)
+
+ .tabButton
+ &:hover
+ background-color alpha($ui-dark-button--active-backgroundColor, 20%)
+ color $ui-dark-text-color
+ transition 0.15s
+
.body
background-color $ui-dark-noteDetail-backgroundColor
@@ -118,7 +138,6 @@ body[data-theme="dark"]
border 1px solid $ui-dark-borderColor
.tabList
- background-color $ui-button--active-backgroundColor
background-color $ui-dark-noteDetail-backgroundColor
.tabList .list
@@ -150,6 +169,15 @@ body[data-theme="solarized-dark"]
color $ui-solarized-dark-text-color
border 1px solid $ui-solarized-dark-borderColor
+ .tabList .tabButton
+ border-color $ui-solarized-dark-borderColor
+
+ .tabButton
+ &:hover
+ color $ui-solarized-dark-button--active-color
+ background-color $ui-solarized-dark-noteDetail-backgroundColor
+ transition 0.15s
+
.tabList
background-color $ui-solarized-dark-noteDetail-backgroundColor
color $ui-solarized-dark-text-color
@@ -167,6 +195,14 @@ body[data-theme="monokai"]
color $ui-monokai-text-color
border 1px solid $ui-monokai-borderColor
+ .tabList .tabButton
+ border-color $ui-monokai-borderColor
+
+ .tabButton
+ &:hover
+ color $ui-monokai-text-color
+ background-color $ui-monokai-noteDetail-backgroundColor
+
.tabList
background-color $ui-monokai-noteDetail-backgroundColor
color $ui-monokai-text-color
@@ -184,6 +220,14 @@ body[data-theme="dracula"]
color $ui-dracula-text-color
border 1px solid $ui-dracula-borderColor
+ .tabList .tabButton
+ border-color $ui-dracula-borderColor
+
+ .tabButton
+ &:hover
+ color $ui-dracula-text-color
+ background-color $ui-dracula-noteDetail-backgroundColor
+
.tabList
background-color $ui-dracula-noteDetail-backgroundColor
color $ui-dracula-text-color
\ No newline at end of file
diff --git a/browser/main/Detail/TagSelect.js b/browser/main/Detail/TagSelect.js
index 6ced475b..c5221f66 100644
--- a/browser/main/Detail/TagSelect.js
+++ b/browser/main/Detail/TagSelect.js
@@ -45,8 +45,14 @@ class TagSelect extends React.Component {
value = _.isArray(value)
? value.slice()
: []
- value.push(newTag)
- value = _.uniq(value)
+
+ if (!_.includes(value, newTag)) {
+ value.push(newTag)
+ }
+
+ if (this.props.saveTagsAlphabetically) {
+ value = _.sortBy(value)
+ }
this.setState({
newTag: ''
diff --git a/browser/main/Main.js b/browser/main/Main.js
index c426f2bd..556c5daf 100644
--- a/browser/main/Main.js
+++ b/browser/main/Main.js
@@ -96,12 +96,14 @@ class Main extends React.Component {
{
name: 'example.html',
mode: 'html',
- content: "\n\nEnjoy Boostnote!
\n\n"
+ content: "\n\nEnjoy Boostnote!
\n\n",
+ linesHighlighted: []
},
{
name: 'example.js',
mode: 'javascript',
- content: "var boostnote = document.getElementById('enjoy').innerHTML\n\nconsole.log(boostnote)"
+ content: "var boostnote = document.getElementById('enjoy').innerHTML\n\nconsole.log(boostnote)",
+ linesHighlighted: []
}
]
})
@@ -234,8 +236,8 @@ class Main extends React.Component {
if (this.state.isRightSliderFocused) {
const offset = this.refs.body.getBoundingClientRect().left
let newListWidth = e.pageX - offset
- if (newListWidth < 10) {
- newListWidth = 10
+ if (newListWidth < 180) {
+ newListWidth = 180
} else if (newListWidth > 600) {
newListWidth = 600
}
diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js
index d1c8d14a..dbc9cfd3 100644
--- a/browser/main/NoteList/index.js
+++ b/browser/main/NoteList/index.js
@@ -2,7 +2,6 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
-import debounceRender from 'react-debounce-render'
import styles from './NoteList.styl'
import moment from 'moment'
import _ from 'lodash'
@@ -711,7 +710,8 @@ class NoteList extends React.Component {
type: firstNote.type,
folder: folder.key,
title: firstNote.title + ' ' + i18n.__('copy'),
- content: firstNote.content
+ content: firstNote.content,
+ linesHighlighted: firstNote.linesHighlighted
})
.then((note) => {
attachmentManagement.cloneAttachments(firstNote, note)
@@ -1129,4 +1129,4 @@ NoteList.propTypes = {
})
}
-export default debounceRender(CSSModules(NoteList, styles))
+export default CSSModules(NoteList, styles)
diff --git a/browser/main/TopBar/index.js b/browser/main/TopBar/index.js
index a5687ecb..91256daf 100644
--- a/browser/main/TopBar/index.js
+++ b/browser/main/TopBar/index.js
@@ -6,6 +6,7 @@ import _ from 'lodash'
import ee from 'browser/main/lib/eventEmitter'
import NewNoteButton from 'browser/main/NewNoteButton'
import i18n from 'browser/lib/i18n'
+import debounce from 'lodash/debounce'
class TopBar extends React.Component {
constructor (props) {
@@ -25,6 +26,10 @@ class TopBar extends React.Component {
}
this.codeInitHandler = this.handleCodeInit.bind(this)
+
+ this.updateKeyword = debounce(this.updateKeyword, 1000 / 60, {
+ maxWait: 1000 / 8
+ })
}
componentDidMount () {
@@ -94,7 +99,6 @@ class TopBar extends React.Component {
}
handleKeyUp (e) {
- const { router } = this.context
// reset states
this.setState({
isConfirmTranslation: false
@@ -106,21 +110,21 @@ class TopBar extends React.Component {
isConfirmTranslation: true
})
const keyword = this.refs.searchInput.value
- router.push(`/searched/${encodeURIComponent(keyword)}`)
- this.setState({
- search: keyword
- })
+ this.updateKeyword(keyword)
}
}
handleSearchChange (e) {
- const { router } = this.context
- const keyword = this.refs.searchInput.value
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
- router.push(`/searched/${encodeURIComponent(keyword)}`)
+ const keyword = this.refs.searchInput.value
+ this.updateKeyword(keyword)
} else {
e.preventDefault()
}
+ }
+
+ updateKeyword (keyword) {
+ this.context.router.push(`/searched/${encodeURIComponent(keyword)}`)
this.setState({
search: keyword
})
diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js
index c2ff9f7a..81165777 100644
--- a/browser/main/lib/ConfigManager.js
+++ b/browser/main/lib/ConfigManager.js
@@ -45,6 +45,9 @@ export const DEFAULT_CONFIG = {
enableRulers: false,
rulers: [80, 120],
displayLineNumbers: true,
+ matchingPairs: '()[]{}\'\'""$$**``',
+ matchingTriples: '```"""\'\'\'',
+ explodingPairs: '[]{}``$$',
switchPreview: 'BLUR', // 'BLUR', 'DBL_CLICK', 'RIGHTCLICK'
delfaultStatus: 'PREVIEW', // 'PREVIEW', 'CODE'
scrollPastEnd: false,
diff --git a/browser/main/lib/dataApi/attachmentManagement.js b/browser/main/lib/dataApi/attachmentManagement.js
index 373efddc..6a0315f7 100644
--- a/browser/main/lib/dataApi/attachmentManagement.js
+++ b/browser/main/lib/dataApi/attachmentManagement.js
@@ -227,7 +227,15 @@ function migrateAttachments (markdownContent, storagePath, noteKey) {
* @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
*/
function fixLocalURLS (renderedHTML, storagePath) {
- return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?"', 'g'), function (match) {
+ /*
+ A :storage reference is like `:storage/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`.
+
+ - `STORAGE_FOLDER_PLACEHOLDER` will match `:storage`
+ - `(?:(?:\\\/|%5C)[\\w.]+)+` will match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`
+ - `(?:\\\/|%5C)[\\w.]+` will either match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564` or `/f939b2c3.jpg`
+ - `(?:\\\/|%5C)` match the path seperator. `\\\/` for posix systems and `%5C` for windows.
+ */
+ return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:(?:\\\/|%5C)[\\w.]+)+', 'g'), function (match) {
var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
})
diff --git a/browser/main/lib/dataApi/createNote.js b/browser/main/lib/dataApi/createNote.js
index e5d44489..5bfa2457 100644
--- a/browser/main/lib/dataApi/createNote.js
+++ b/browser/main/lib/dataApi/createNote.js
@@ -16,6 +16,7 @@ function validateInput (input) {
switch (input.type) {
case 'MARKDOWN_NOTE':
if (!_.isString(input.content)) input.content = ''
+ if (!_.isArray(input.linesHighlighted)) input.linesHighlighted = []
break
case 'SNIPPET_NOTE':
if (!_.isString(input.description)) input.description = ''
@@ -23,7 +24,8 @@ function validateInput (input) {
input.snippets = [{
name: '',
mode: 'text',
- content: ''
+ content: '',
+ linesHighlighted: []
}]
}
break
diff --git a/browser/main/lib/dataApi/createSnippet.js b/browser/main/lib/dataApi/createSnippet.js
index 5d189217..2e585c9f 100644
--- a/browser/main/lib/dataApi/createSnippet.js
+++ b/browser/main/lib/dataApi/createSnippet.js
@@ -9,7 +9,8 @@ function createSnippet (snippetFile) {
id: crypto.randomBytes(16).toString('hex'),
name: 'Unnamed snippet',
prefix: [],
- content: ''
+ content: '',
+ linesHighlighted: []
}
fetchSnippet(null, snippetFile).then((snippets) => {
snippets.push(newSnippet)
diff --git a/browser/main/lib/dataApi/migrateFromV5Storage.js b/browser/main/lib/dataApi/migrateFromV5Storage.js
index b11e66e9..78d78746 100644
--- a/browser/main/lib/dataApi/migrateFromV5Storage.js
+++ b/browser/main/lib/dataApi/migrateFromV5Storage.js
@@ -69,7 +69,8 @@ function importAll (storage, data) {
isStarred: false,
title: article.title,
content: '# ' + article.title + '\n\n' + article.content,
- key: noteKey
+ key: noteKey,
+ linesHighlighted: article.linesHighlighted
}
notes.push(newNote)
} else {
@@ -87,7 +88,8 @@ function importAll (storage, data) {
snippets: [{
name: article.mode,
mode: article.mode,
- content: article.content
+ content: article.content,
+ linesHighlighted: article.linesHighlighted
}]
}
notes.push(newNote)
diff --git a/browser/main/lib/dataApi/updateNote.js b/browser/main/lib/dataApi/updateNote.js
index 147fbc06..ce9fabcf 100644
--- a/browser/main/lib/dataApi/updateNote.js
+++ b/browser/main/lib/dataApi/updateNote.js
@@ -39,6 +39,9 @@ function validateInput (input) {
if (input.content != null) {
if (!_.isString(input.content)) validatedInput.content = ''
else validatedInput.content = input.content
+
+ if (!_.isArray(input.linesHighlighted)) validatedInput.linesHighlighted = []
+ else validatedInput.linesHighlighted = input.linesHighlighted
}
return validatedInput
case 'SNIPPET_NOTE':
@@ -51,7 +54,8 @@ function validateInput (input) {
validatedInput.snippets = [{
name: '',
mode: 'text',
- content: ''
+ content: '',
+ linesHighlighted: []
}]
} else {
validatedInput.snippets = input.snippets
@@ -96,12 +100,14 @@ function updateNote (storageKey, noteKey, input) {
snippets: [{
name: '',
mode: 'text',
- content: ''
+ content: '',
+ linesHighlighted: []
}]
}
: {
type: 'MARKDOWN_NOTE',
- content: ''
+ content: '',
+ linesHighlighted: []
}
noteData.title = ''
if (storage.folders.length === 0) throw new Error('Failed to restore note: No folder exists.')
diff --git a/browser/main/lib/dataApi/updateSnippet.js b/browser/main/lib/dataApi/updateSnippet.js
index f2310b8e..f132d83f 100644
--- a/browser/main/lib/dataApi/updateSnippet.js
+++ b/browser/main/lib/dataApi/updateSnippet.js
@@ -12,7 +12,8 @@ function updateSnippet (snippet, snippetFile) {
if (
currentSnippet.name === snippet.name &&
currentSnippet.prefix === snippet.prefix &&
- currentSnippet.content === snippet.content
+ currentSnippet.content === snippet.content &&
+ currentSnippet.linesHighlighted === snippet.linesHighlighted
) {
// if everything is the same then don't write to disk
resolve(snippets)
@@ -20,6 +21,7 @@ function updateSnippet (snippet, snippetFile) {
currentSnippet.name = snippet.name
currentSnippet.prefix = snippet.prefix
currentSnippet.content = snippet.content
+ currentSnippet.linesHighlighted = (snippet.linesHighlighted)
fs.writeFile(snippetFile || consts.SNIPPET_FILE, JSON.stringify(snippets, null, 4), (err) => {
if (err) reject(err)
resolve(snippets)
diff --git a/browser/main/modals/PreferencesModal/HotkeyTab.js b/browser/main/modals/PreferencesModal/HotkeyTab.js
index a0f6a739..25098faa 100644
--- a/browser/main/modals/PreferencesModal/HotkeyTab.js
+++ b/browser/main/modals/PreferencesModal/HotkeyTab.js
@@ -151,7 +151,7 @@ class HotkeyTab extends React.Component {
- {i18n.__('Paste Smartly')}
+ {i18n.__('Paste HTML')}
this.handleHotkeyChange(e)}
diff --git a/browser/main/modals/PreferencesModal/InfoTab.js b/browser/main/modals/PreferencesModal/InfoTab.js
index a6acc963..d618fa22 100644
--- a/browser/main/modals/PreferencesModal/InfoTab.js
+++ b/browser/main/modals/PreferencesModal/InfoTab.js
@@ -73,6 +73,11 @@ class InfoTab extends React.Component {
{i18n.__('Community')}
+ -
+ this.handleLinkClick(e)}
+ >{i18n.__('Bounty on IssueHunt')}
+
-
this.handleLinkClick(e)}
diff --git a/browser/main/modals/PreferencesModal/SnippetEditor.js b/browser/main/modals/PreferencesModal/SnippetEditor.js
index 4ce5dc34..071f265f 100644
--- a/browser/main/modals/PreferencesModal/SnippetEditor.js
+++ b/browser/main/modals/PreferencesModal/SnippetEditor.js
@@ -28,9 +28,9 @@ class SnippetEditor extends React.Component {
foldGutter: true,
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
autoCloseBrackets: {
- pairs: '()[]{}\'\'""$$**``',
- triples: '```"""\'\'\'',
- explode: '[]{}``$$',
+ pairs: this.props.matchingPairs,
+ triples: this.props.matchingTriples,
+ explode: this.props.explodingPairs,
override: true
},
mode: 'null'
diff --git a/browser/main/modals/PreferencesModal/SnippetTab.js b/browser/main/modals/PreferencesModal/SnippetTab.js
index b83fa205..5f5b0aac 100644
--- a/browser/main/modals/PreferencesModal/SnippetTab.js
+++ b/browser/main/modals/PreferencesModal/SnippetTab.js
@@ -136,6 +136,9 @@ class SnippetTab extends React.Component {
enableRulers={config.editor.enableRulers}
rulers={config.editor.rulers}
displayLineNumbers={config.editor.displayLineNumbers}
+ matchingPairs={config.editor.matchingPairs}
+ matchingTriples={config.editor.matchingTriples}
+ explodingPairs={config.editor.explodingPairs}
scrollPastEnd={config.editor.scrollPastEnd}
onRef={ref => { this.snippetEditor = ref }} />
diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js
index becd4f54..c8646c39 100644
--- a/browser/main/modals/PreferencesModal/UiTab.js
+++ b/browser/main/modals/PreferencesModal/UiTab.js
@@ -96,6 +96,9 @@ class UiTab extends React.Component {
enableTableEditor: this.refs.enableTableEditor.checked,
enableFrontMatterTitle: this.refs.enableFrontMatterTitle.checked,
frontMatterTitleField: this.refs.frontMatterTitleField.value,
+ matchingPairs: this.refs.matchingPairs.value,
+ matchingTriples: this.refs.matchingTriples.value,
+ explodingPairs: this.refs.explodingPairs.value,
spellcheck: this.refs.spellcheck.checked,
enableSmartPaste: this.refs.enableSmartPaste.checked
},
@@ -478,6 +481,7 @@ class UiTab extends React.Component {
ref='editorSnippetDefaultLanguage'
onChange={(e) => this.handleUIChange(e)}
>
+
{
_.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => ())
}
@@ -561,7 +565,7 @@ class UiTab extends React.Component {
ref='enableSmartPaste'
type='checkbox'
/>
- {i18n.__('Enable smart paste')}
+ {i18n.__('Enable HTML paste')}
@@ -576,6 +580,48 @@ class UiTab extends React.Component {
+
+
+ {i18n.__('Matching character pairs')}
+
+
+ this.handleUIChange(e)}
+ type='text'
+ />
+
+
+
+
+
+ {i18n.__('Matching character triples')}
+
+
+ this.handleUIChange(e)}
+ type='text'
+ />
+
+
+
+
+
+ {i18n.__('Exploding character pairs')}
+
+
+ this.handleUIChange(e)}
+ type='text'
+ />
+
+
+
{i18n.__('Preview')}
@@ -603,6 +649,7 @@ class UiTab extends React.Component {
/>
+
{i18n.__('Code Block Theme')}
diff --git a/browser/styles/index.styl b/browser/styles/index.styl
index 56cb0eab..b9f9c41e 100644
--- a/browser/styles/index.styl
+++ b/browser/styles/index.styl
@@ -240,10 +240,8 @@ navWhiteButtonColor()
&:hover
background-color alpha($ui-button--active-backgroundColor, 20%)
transition 0.15s
- color $ui-text-color
&:active, &:active:hover
background-color $ui-button--active-backgroundColor
- color $ui-text-color
transition 0.15s
// UI Button
diff --git a/package.json b/package.json
index 128a21af..578e2c7b 100644
--- a/package.json
+++ b/package.json
@@ -1,7 +1,7 @@
{
"name": "boost",
"productName": "Boostnote",
- "version": "0.11.11",
+ "version": "0.11.12",
"main": "index.js",
"description": "Boostnote",
"license": "GPL-3.0",
@@ -66,6 +66,7 @@
"flowchart.js": "^1.6.5",
"font-awesome": "^4.3.0",
"fs-extra": "^5.0.0",
+ "highlight.js": "^9.13.1",
"i18n-2": "^0.7.2",
"iconv-lite": "^0.4.19",
"immutable": "^3.8.1",
@@ -99,8 +100,10 @@
"react-codemirror": "^0.3.0",
"react-debounce-render": "^4.0.1",
"react-dom": "^15.0.2",
+ "react-image-carousel": "^2.0.18",
"react-redux": "^4.4.5",
"react-sortable-hoc": "^0.6.7",
+ "react-transition-group": "^2.5.0",
"redux": "^3.5.2",
"sander": "^0.5.1",
"sanitize-html": "^1.18.2",
@@ -142,6 +145,7 @@
"grunt": "^0.4.5",
"grunt-electron-installer": "2.1.0",
"history": "^1.17.0",
+ "husky": "^1.1.0",
"identity-obj-proxy": "^3.0.0",
"jest": "^22.4.3",
"jest-localstorage-mock": "^2.2.0",
@@ -189,5 +193,10 @@
"/tests/jest.js",
"jest-localstorage-mock"
]
+ },
+ "husky": {
+ "hooks": {
+ "pre-commit": "npm run lint"
+ }
}
}
diff --git a/readme.md b/readme.md
index ef90dfcc..aba9b92a 100644
--- a/readme.md
+++ b/readme.md
@@ -27,7 +27,7 @@ Boostnote is an open source project. It's an independent project with its ongoin
Issues on Boostnote can be funded by anyone and the money will be distributed to contributors and maintainers. If you use Boostnote please consider becoming a backer:
-[](https://issuehunt.io/repos/53266139)
+[](https://issuehunt.io/repos/53266139)
## Community
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
diff --git a/tests/dataApi/createNote-test.js b/tests/dataApi/createNote-test.js
index 47446aab..3606dfd4 100644
--- a/tests/dataApi/createNote-test.js
+++ b/tests/dataApi/createNote-test.js
@@ -25,13 +25,16 @@ test.serial('Create a note', (t) => {
const storageKey = t.context.storage.cache.key
const folderKey = t.context.storage.json.folders[0].key
+ const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10))
+
const input1 = {
type: 'SNIPPET_NOTE',
description: faker.lorem.lines(),
snippets: [{
name: faker.system.fileName(),
mode: 'text',
- content: faker.lorem.lines()
+ content: faker.lorem.lines(),
+ linesHighlighted: randLinesHighlightedArray
}],
tags: faker.lorem.words().split(' '),
folder: folderKey
@@ -42,7 +45,8 @@ test.serial('Create a note', (t) => {
type: 'MARKDOWN_NOTE',
content: faker.lorem.lines(),
tags: faker.lorem.words().split(' '),
- folder: folderKey
+ folder: folderKey,
+ linesHighlighted: randLinesHighlightedArray
}
input2.title = input2.content.split('\n').shift()
@@ -59,6 +63,7 @@ test.serial('Create a note', (t) => {
t.is(storageKey, data1.storage)
const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
+
t.is(input1.title, data1.title)
t.is(input1.title, jsonData1.title)
t.is(input1.description, data1.description)
@@ -71,6 +76,8 @@ test.serial('Create a note', (t) => {
t.is(input1.snippets[0].content, jsonData1.snippets[0].content)
t.is(input1.snippets[0].name, data1.snippets[0].name)
t.is(input1.snippets[0].name, jsonData1.snippets[0].name)
+ t.deepEqual(input1.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted)
+ t.deepEqual(input1.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted)
t.is(storageKey, data2.storage)
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
@@ -80,6 +87,8 @@ test.serial('Create a note', (t) => {
t.is(input2.content, jsonData2.content)
t.is(input2.tags.length, data2.tags.length)
t.is(input2.tags.length, jsonData2.tags.length)
+ t.deepEqual(input2.linesHighlighted, data2.linesHighlighted)
+ t.deepEqual(input2.linesHighlighted, jsonData2.linesHighlighted)
})
})
diff --git a/tests/dataApi/createSnippet-test.js b/tests/dataApi/createSnippet-test.js
index f06cf861..638b76ca 100644
--- a/tests/dataApi/createSnippet-test.js
+++ b/tests/dataApi/createSnippet-test.js
@@ -26,6 +26,7 @@ test.serial('Create a snippet', (t) => {
t.is(snippet.name, data.name)
t.deepEqual(snippet.prefix, data.prefix)
t.is(snippet.content, data.content)
+ t.deepEqual(snippet.linesHighlighted, data.linesHighlighted)
})
})
diff --git a/tests/dataApi/updateNote-test.js b/tests/dataApi/updateNote-test.js
index 6043ee1e..da47c30c 100644
--- a/tests/dataApi/updateNote-test.js
+++ b/tests/dataApi/updateNote-test.js
@@ -26,13 +26,17 @@ test.serial('Update a note', (t) => {
const storageKey = t.context.storage.cache.key
const folderKey = t.context.storage.json.folders[0].key
+ const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10))
+ const randLinesHighlightedArray2 = new Array(15).fill().map(() => Math.round(Math.random() * 15))
+
const input1 = {
type: 'SNIPPET_NOTE',
description: faker.lorem.lines(),
snippets: [{
name: faker.system.fileName(),
mode: 'text',
- content: faker.lorem.lines()
+ content: faker.lorem.lines(),
+ linesHighlighted: randLinesHighlightedArray
}],
tags: faker.lorem.words().split(' '),
folder: folderKey
@@ -43,7 +47,8 @@ test.serial('Update a note', (t) => {
type: 'MARKDOWN_NOTE',
content: faker.lorem.lines(),
tags: faker.lorem.words().split(' '),
- folder: folderKey
+ folder: folderKey,
+ linesHighlighted: randLinesHighlightedArray
}
input2.title = input2.content.split('\n').shift()
@@ -53,7 +58,8 @@ test.serial('Update a note', (t) => {
snippets: [{
name: faker.system.fileName(),
mode: 'text',
- content: faker.lorem.lines()
+ content: faker.lorem.lines(),
+ linesHighlighted: randLinesHighlightedArray2
}],
tags: faker.lorem.words().split(' ')
}
@@ -62,7 +68,8 @@ test.serial('Update a note', (t) => {
const input4 = {
type: 'MARKDOWN_NOTE',
content: faker.lorem.lines(),
- tags: faker.lorem.words().split(' ')
+ tags: faker.lorem.words().split(' '),
+ linesHighlighted: randLinesHighlightedArray2
}
input4.title = input4.content.split('\n').shift()
@@ -99,6 +106,8 @@ test.serial('Update a note', (t) => {
t.is(input3.snippets[0].content, jsonData1.snippets[0].content)
t.is(input3.snippets[0].name, data1.snippets[0].name)
t.is(input3.snippets[0].name, jsonData1.snippets[0].name)
+ t.deepEqual(input3.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted)
+ t.deepEqual(input3.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted)
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
t.is(input4.title, data2.title)
@@ -107,6 +116,8 @@ test.serial('Update a note', (t) => {
t.is(input4.content, jsonData2.content)
t.is(input4.tags.length, data2.tags.length)
t.is(input4.tags.length, jsonData2.tags.length)
+ t.deepEqual(input4.linesHighlighted, data2.linesHighlighted)
+ t.deepEqual(input4.linesHighlighted, jsonData2.linesHighlighted)
})
})
diff --git a/yarn.lock b/yarn.lock
index 48dd9056..604880e5 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -61,7 +61,6 @@
"@enyaxu/markdown-it-anchor@^5.0.2":
version "5.0.2"
resolved "https://registry.yarnpkg.com/@enyaxu/markdown-it-anchor/-/markdown-it-anchor-5.0.2.tgz#d173f7b60b492aabc17dfba864c4d071f5595f72"
- integrity sha512-HBQ+by3IFHh2i5nw8fzn9qrdA+6uwzre68EzHpBX/WrwgnKrfvckPzdi7MphKp2C617edfpeibucslHDNPYkvQ==
"@ladjs/time-require@^0.1.4":
version "0.1.4"
@@ -1690,6 +1689,10 @@ ci-info@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2"
+ci-info@^1.5.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
+
circular-json@^0.3.1:
version "0.3.3"
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
@@ -2107,6 +2110,14 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
+cosmiconfig@^5.0.6:
+ version "5.0.6"
+ resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.6.tgz#dca6cf680a0bd03589aff684700858c81abeeb39"
+ dependencies:
+ is-directory "^0.3.1"
+ js-yaml "^3.9.0"
+ parse-json "^4.0.0"
+
create-error-class@^3.0.0, create-error-class@^3.0.1:
version "3.0.2"
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
@@ -2749,6 +2760,10 @@ doctrine@^2.0.0, doctrine@^2.0.2:
dependencies:
esutils "^2.0.2"
+dom-helpers@^3.3.1:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
+
dom-serializer@0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
@@ -3364,6 +3379,18 @@ execa@^0.7.0:
signal-exit "^3.0.0"
strip-eof "^1.0.0"
+execa@^0.9.0:
+ version "0.9.0"
+ resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01"
+ dependencies:
+ cross-spawn "^5.0.1"
+ get-stream "^3.0.0"
+ is-stream "^1.1.0"
+ npm-run-path "^2.0.0"
+ p-finally "^1.0.0"
+ signal-exit "^3.0.0"
+ strip-eof "^1.0.0"
+
exit-hook@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
@@ -3670,6 +3697,12 @@ find-up@^2.0.0, find-up@^2.1.0:
dependencies:
locate-path "^2.0.0"
+find-up@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+ dependencies:
+ locate-path "^3.0.0"
+
findup-sync@~0.1.2:
version "0.1.3"
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.1.3.tgz#7f3e7a97b82392c653bf06589bd85190e93c3683"
@@ -3915,6 +3948,10 @@ get-stdin@^5.0.1:
version "5.0.1"
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
+get-stdin@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
+
get-stream@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
@@ -4452,6 +4489,21 @@ humanize-plus@^1.8.1:
version "1.8.2"
resolved "https://registry.yarnpkg.com/humanize-plus/-/humanize-plus-1.8.2.tgz#a65b34459ad6367adbb3707a82a3c9f916167030"
+husky@^1.1.0:
+ version "1.1.0"
+ resolved "https://registry.yarnpkg.com/husky/-/husky-1.1.0.tgz#7271e85f5d98b54349788839b720c9a60cd95dba"
+ dependencies:
+ cosmiconfig "^5.0.6"
+ execa "^0.9.0"
+ find-up "^3.0.0"
+ get-stdin "^6.0.0"
+ is-ci "^1.2.1"
+ pkg-dir "^3.0.0"
+ please-upgrade-node "^3.1.1"
+ read-pkg "^4.0.1"
+ run-node "^1.0.0"
+ slash "^2.0.0"
+
i18n-2@^0.7.2:
version "0.7.2"
resolved "https://registry.yarnpkg.com/i18n-2/-/i18n-2-0.7.2.tgz#7efb1a7adc67869adea0688951577464aa793aaf"
@@ -4662,6 +4714,12 @@ is-ci@^1.0.10, is-ci@^1.0.7:
dependencies:
ci-info "^1.0.0"
+is-ci@^1.2.1:
+ version "1.2.1"
+ resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
+ dependencies:
+ ci-info "^1.5.0"
+
is-data-descriptor@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
@@ -4694,6 +4752,10 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2:
is-data-descriptor "^1.0.0"
kind-of "^6.0.2"
+is-directory@^0.3.1:
+ version "0.3.1"
+ resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
+
is-dotfile@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
@@ -5324,6 +5386,10 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
+"js-tokens@^3.0.0 || ^4.0.0":
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+
js-yaml@^3.10.0, js-yaml@^3.5.1, js-yaml@^3.7.0:
version "3.11.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef"
@@ -5331,7 +5397,7 @@ js-yaml@^3.10.0, js-yaml@^3.5.1, js-yaml@^3.7.0:
argparse "^1.0.7"
esprima "^4.0.0"
-js-yaml@^3.12.0, js-yaml@^3.8.1:
+js-yaml@^3.12.0, js-yaml@^3.8.1, js-yaml@^3.9.0:
version "3.12.0"
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
dependencies:
@@ -5688,6 +5754,13 @@ locate-path@^2.0.0:
p-locate "^2.0.0"
path-exists "^3.0.0"
+locate-path@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+ dependencies:
+ p-locate "^3.0.0"
+ path-exists "^3.0.0"
+
lodash-es@^4.2.1:
version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.10.tgz#62cd7104cdf5dd87f235a837f0ede0e8e5117e05"
@@ -5805,6 +5878,12 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3
dependencies:
js-tokens "^3.0.0"
+loose-envify@^1.4.0:
+ version "1.4.0"
+ resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+ dependencies:
+ js-tokens "^3.0.0 || ^4.0.0"
+
loud-rejection@^1.0.0, loud-rejection@^1.2.0:
version "1.6.0"
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
@@ -6681,16 +6760,32 @@ p-limit@^1.1.0:
dependencies:
p-try "^1.0.0"
+p-limit@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec"
+ dependencies:
+ p-try "^2.0.0"
+
p-locate@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
dependencies:
p-limit "^1.1.0"
+p-locate@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+ dependencies:
+ p-limit "^2.0.0"
+
p-try@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
+p-try@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
+
package-hash@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-1.2.0.tgz#003e56cd57b736a6ed6114cc2b81542672770e44"
@@ -6886,12 +6981,24 @@ pkg-dir@^2.0.0:
dependencies:
find-up "^2.1.0"
+pkg-dir@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
+ dependencies:
+ find-up "^3.0.0"
+
pkg-up@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
dependencies:
find-up "^2.1.0"
+please-upgrade-node@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz#ed320051dfcc5024fae696712c8288993595e8ac"
+ dependencies:
+ semver-compare "^1.0.0"
+
plist@^2.0.0, plist@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
@@ -7241,6 +7348,13 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8,
loose-envify "^1.3.1"
object-assign "^4.1.1"
+prop-types@^15.6.2:
+ version "15.6.2"
+ resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
+ dependencies:
+ loose-envify "^1.3.1"
+ object-assign "^4.1.1"
+
proxy-addr@~2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
@@ -7420,6 +7534,10 @@ react-dom@^15.0.2:
object-assign "^4.1.0"
prop-types "^15.5.10"
+react-image-carousel@^2.0.18:
+ version "2.0.18"
+ resolved "https://registry.yarnpkg.com/react-image-carousel/-/react-image-carousel-2.0.18.tgz#5868ea09bd9cca09c4467d3d02695cd4e7792f28"
+
react-input-autosize@^1.1.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-1.2.0.tgz#87241071159f742123897691da6796ec33b57d05"
@@ -7427,6 +7545,10 @@ react-input-autosize@^1.1.0:
create-react-class "^15.5.2"
prop-types "^15.5.8"
+react-lifecycles-compat@^3.0.4:
+ version "3.0.4"
+ resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
+
react-proxy@^1.1.7:
version "1.1.8"
resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a"
@@ -7492,6 +7614,15 @@ react-transform-hmr@^1.0.3:
global "^4.3.0"
react-proxy "^1.1.7"
+react-transition-group@^2.5.0:
+ version "2.5.0"
+ resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.5.0.tgz#70bca0e3546102c4dc5cf3f5f57f73447cce6874"
+ dependencies:
+ dom-helpers "^3.3.1"
+ loose-envify "^1.4.0"
+ prop-types "^15.6.2"
+ react-lifecycles-compat "^3.0.4"
+
react@^15.5.4:
version "15.6.2"
resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"
@@ -7545,6 +7676,14 @@ read-pkg@^2.0.0:
normalize-package-data "^2.3.2"
path-type "^2.0.0"
+read-pkg@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
+ dependencies:
+ normalize-package-data "^2.3.2"
+ parse-json "^4.0.0"
+ pify "^3.0.0"
+
readable-stream@^1.1.8, readable-stream@~1.1.9:
version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@@ -7895,6 +8034,10 @@ run-async@^0.1.0:
dependencies:
once "^1.3.0"
+run-node@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e"
+
run-parallel@^1.1.2:
version "1.1.9"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
@@ -7994,6 +8137,10 @@ section-iterator@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a"
+semver-compare@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
+
semver-diff@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
@@ -8153,6 +8300,10 @@ slash@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
+slash@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
+
slice-ansi@0.0.4:
version "0.0.4"
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"