mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-11 08:46:20 +00:00
Discard finder (#1497)
* Discard finder * Upgrade electron * Discard anything related with finder * Fix lint errors * Run test serial * Test on v6 * Test on v6 only
This commit is contained in:
committed by
GitHub
parent
922570bb5c
commit
51a8c47afd
@@ -10,7 +10,6 @@
|
||||
"theme": "monokai"
|
||||
},
|
||||
"hotkey": {
|
||||
"toggleFinder": "Cmd + Alt + S",
|
||||
"toggleMain": "Cmd + Alt + L"
|
||||
},
|
||||
"isSideNavFolded": false,
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- stable
|
||||
- lts/*
|
||||
- 6
|
||||
script:
|
||||
- npm run lint && npm run test
|
||||
- 'if [[ ${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH} = "master" ]]; then npm install -g grunt npm@5.2 && grunt pre-build; fi'
|
||||
|
||||
@@ -1,156 +0,0 @@
|
||||
$search-height = 50px
|
||||
$nav-width = 175px
|
||||
$list-width = 250px
|
||||
|
||||
.root
|
||||
absolute top left right bottom
|
||||
|
||||
.search
|
||||
height $search-height
|
||||
padding 10px
|
||||
box-sizing border-box
|
||||
border-bottom $ui-border
|
||||
text-align center
|
||||
|
||||
.search-input
|
||||
height 30px
|
||||
width 100%
|
||||
margin 0 auto
|
||||
font-size 18px
|
||||
border none
|
||||
outline none
|
||||
text-align center
|
||||
background-color transparent
|
||||
|
||||
.result
|
||||
absolute left right bottom
|
||||
top $search-height
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
|
||||
.result-nav
|
||||
user-select none
|
||||
absolute left top bottom
|
||||
width $nav-width
|
||||
background-color $ui-backgroundColor
|
||||
|
||||
.result-nav-filter
|
||||
margin-bottom 10px
|
||||
|
||||
.result-nav-filter-option
|
||||
height 25px
|
||||
line-height 25px
|
||||
padding 0 10px
|
||||
label
|
||||
cursor pointer
|
||||
|
||||
.result-nav-menu
|
||||
navButtonColor()
|
||||
height 32px
|
||||
padding 0 10px
|
||||
font-size 14px
|
||||
width 100%
|
||||
outline none
|
||||
text-align left
|
||||
line-height 32px
|
||||
box-sizing border-box
|
||||
cursor pointer
|
||||
|
||||
.result-nav-menu--active
|
||||
@extend .result-nav-menu
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-button--active-color
|
||||
&:hover
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.result-nav-storageList
|
||||
absolute bottom left right
|
||||
top 110px + 32px + 10px + 10px + 20px
|
||||
overflow-y auto
|
||||
|
||||
.result-list
|
||||
user-select none
|
||||
absolute top bottom
|
||||
left $nav-width
|
||||
width $list-width
|
||||
box-sizing border-box
|
||||
overflow-y auto
|
||||
box-shadow 2px 0 15px -8px #b1b1b1
|
||||
z-index 1
|
||||
|
||||
.result-detail
|
||||
absolute top bottom right
|
||||
left $nav-width + $list-width
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
background-color $ui-dark-backgroundColor
|
||||
.search
|
||||
border-color $ui-dark-borderColor
|
||||
.search-input
|
||||
color $ui-dark-text-color
|
||||
|
||||
.result
|
||||
background-color $ui-dark-noteList-backgroundColor
|
||||
|
||||
.result-nav
|
||||
background-color $ui-dark-backgroundColor
|
||||
label
|
||||
color $ui-dark-text-color
|
||||
|
||||
.result-nav-menu
|
||||
navDarkButtonColor()
|
||||
|
||||
.result-nav-menu--active
|
||||
background-color $ui-dark-button--active-backgroundColor
|
||||
color $ui-dark-button--active-color
|
||||
&:hover
|
||||
background-color $ui-dark-button--active-backgroundColor
|
||||
|
||||
.result-list
|
||||
border-color $ui-dark-borderColor
|
||||
box-shadow none
|
||||
top 0
|
||||
|
||||
.result-detail
|
||||
absolute top bottom right
|
||||
left $nav-width + $list-width
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
|
||||
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.root
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
.search
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
.search-input
|
||||
color $ui-dark-text-color
|
||||
|
||||
.result
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
|
||||
.result-nav
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
label
|
||||
color $ui-dark-text-color
|
||||
|
||||
.result-nav-menu
|
||||
navDarkButtonColor()
|
||||
|
||||
.result-nav-menu--active
|
||||
background-color $ui-solarized-dark-button-backgroundColor
|
||||
color $ui-dark-button--active-color
|
||||
&:hover
|
||||
background-color $ui-dark-button--active-backgroundColor
|
||||
|
||||
.result-list
|
||||
border-color $ui-solarized-dark-borderColor
|
||||
box-shadow none
|
||||
top 0
|
||||
|
||||
.result-detail
|
||||
absolute top bottom right
|
||||
left $nav-width + $list-width
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
|
||||
@@ -1,211 +0,0 @@
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './NoteDetail.styl'
|
||||
import MarkdownPreview from 'browser/components/MarkdownPreview'
|
||||
import MarkdownEditor from 'browser/components/MarkdownEditor'
|
||||
import CodeEditor from 'browser/components/CodeEditor'
|
||||
import CodeMirror from 'codemirror'
|
||||
import 'codemirror-mode-elixir'
|
||||
import { findStorage } from 'browser/lib/findStorage'
|
||||
|
||||
const electron = require('electron')
|
||||
const { clipboard } = electron
|
||||
const path = require('path')
|
||||
|
||||
function pass (name) {
|
||||
switch (name) {
|
||||
case 'ejs':
|
||||
return 'Embedded Javascript'
|
||||
case 'html_ruby':
|
||||
return 'Embedded Ruby'
|
||||
case 'objectivec':
|
||||
return 'Objective C'
|
||||
case 'text':
|
||||
return 'Plain Text'
|
||||
default:
|
||||
return name
|
||||
}
|
||||
}
|
||||
function notify (title, options) {
|
||||
if (global.process.platform === 'win32') {
|
||||
options.icon = path.join('file://', global.__dirname, '../../resources/app.png')
|
||||
}
|
||||
return new window.Notification(title, options)
|
||||
}
|
||||
|
||||
class NoteDetail extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
snippetIndex: 0
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (nextProps.note !== this.props.note) {
|
||||
this.setState({
|
||||
snippetIndex: 0
|
||||
}, () => {
|
||||
if (nextProps.note.type === 'SNIPPET_NOTE') {
|
||||
nextProps.note.snippets.forEach((snippet, index) => {
|
||||
this.refs['code-' + index].reload()
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
selectPriorSnippet () {
|
||||
const { note } = this.props
|
||||
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
|
||||
this.setState({
|
||||
snippetIndex: (this.state.snippetIndex + note.snippets.length - 1) % note.snippets.length
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
selectNextSnippet () {
|
||||
const { note } = this.props
|
||||
if (note.type === 'SNIPPET_NOTE' && note.snippets.length > 1) {
|
||||
this.setState({
|
||||
snippetIndex: (this.state.snippetIndex + 1) % note.snippets.length
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
saveToClipboard () {
|
||||
const { note } = this.props
|
||||
|
||||
if (note.type === 'MARKDOWN_NOTE') {
|
||||
clipboard.writeText(note.content)
|
||||
} else {
|
||||
clipboard.writeText(note.snippets[this.state.snippetIndex].content)
|
||||
}
|
||||
|
||||
notify('Saved to Clipboard!', {
|
||||
body: 'Paste it wherever you want!',
|
||||
silent: true
|
||||
})
|
||||
}
|
||||
|
||||
handleTabButtonClick (e, index) {
|
||||
this.setState({
|
||||
snippetIndex: index
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const { note, config } = this.props
|
||||
if (note == null) {
|
||||
return (
|
||||
<div styleName='root' />
|
||||
)
|
||||
}
|
||||
|
||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
||||
if (!(editorFontSize > 0 && editorFontSize < 132)) editorIndentSize = 4
|
||||
|
||||
const storage = findStorage(note.storage)
|
||||
|
||||
if (note.type === 'SNIPPET_NOTE') {
|
||||
const tabList = note.snippets.map((snippet, index) => {
|
||||
const isActive = this.state.snippetIndex === index
|
||||
return <div styleName={isActive
|
||||
? 'tabList-item--active'
|
||||
: 'tabList-item'
|
||||
}
|
||||
key={index}
|
||||
>
|
||||
<button styleName='tabList-item-button'
|
||||
onClick={(e) => this.handleTabButtonClick(e, index)}
|
||||
>
|
||||
{snippet.name.trim().length > 0
|
||||
? snippet.name
|
||||
: <span styleName='tabList-item-unnamed'>
|
||||
Unnamed
|
||||
</span>
|
||||
}
|
||||
</button>
|
||||
</div>
|
||||
})
|
||||
|
||||
const viewList = note.snippets.map((snippet, index) => {
|
||||
const isActive = this.state.snippetIndex === index
|
||||
|
||||
let syntax = CodeMirror.findModeByName(pass(snippet.mode))
|
||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||
|
||||
return <div styleName='tabView'
|
||||
key={index}
|
||||
style={{zIndex: isActive ? 5 : 4}}
|
||||
>
|
||||
{snippet.mode === 'markdown'
|
||||
? <MarkdownEditor styleName='tabView-content'
|
||||
config={config}
|
||||
value={snippet.content}
|
||||
ref={'code-' + index}
|
||||
storageKey={note.storage}
|
||||
/>
|
||||
: <CodeEditor styleName='tabView-content'
|
||||
mode={snippet.mode}
|
||||
value={snippet.content}
|
||||
theme={config.editor.theme}
|
||||
fontFamily={config.editor.fontFamily}
|
||||
fontSize={editorFontSize}
|
||||
indentType={config.editor.indentType}
|
||||
indentSize={editorIndentSize}
|
||||
keyMap={config.editor.keyMap}
|
||||
scrollPastEnd={config.editor.scrollPastEnd}
|
||||
readOnly
|
||||
ref={'code-' + index}
|
||||
/>
|
||||
}
|
||||
</div>
|
||||
})
|
||||
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='description'>
|
||||
<textarea styleName='description-textarea'
|
||||
style={{
|
||||
fontFamily: config.preview.fontFamily,
|
||||
fontSize: parseInt(config.preview.fontSize, 10)
|
||||
}}
|
||||
ref='description'
|
||||
placeholder='Description...'
|
||||
value={note.description}
|
||||
readOnly
|
||||
/>
|
||||
</div>
|
||||
<div styleName='tabList'>
|
||||
{tabList}
|
||||
</div>
|
||||
{viewList}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
return (
|
||||
<MarkdownPreview styleName='root'
|
||||
theme={config.ui.theme}
|
||||
fontSize={config.preview.fontSize}
|
||||
fontFamily={config.preview.fontFamily}
|
||||
codeBlockTheme={config.preview.codeBlockTheme}
|
||||
codeBlockFontFamily={config.editor.fontFamily}
|
||||
lineNumber={config.preview.lineNumber}
|
||||
indentSize={editorIndentSize}
|
||||
value={note.content}
|
||||
showCopyNotification={config.ui.showCopyNotification}
|
||||
storagePath={storage.path}
|
||||
/>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NoteDetail.propTypes = {
|
||||
}
|
||||
|
||||
export default CSSModules(NoteDetail, styles)
|
||||
@@ -1,129 +0,0 @@
|
||||
@import('../main/Detail/DetailVars.styl')
|
||||
|
||||
.root
|
||||
absolute top bottom left right
|
||||
bottom 30px
|
||||
margin 0 25px
|
||||
height 100%
|
||||
width 365px
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
|
||||
.description
|
||||
absolute top left right
|
||||
height 80px
|
||||
box-sizing border-box
|
||||
|
||||
.description-textarea
|
||||
display block
|
||||
height 100%
|
||||
width 100%
|
||||
resize none
|
||||
border none
|
||||
padding 10px
|
||||
line-height 1.6
|
||||
box-sizing border-box
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
|
||||
.tabList
|
||||
absolute left right
|
||||
top 80px
|
||||
box-sizing border-box
|
||||
height 30px
|
||||
display flex
|
||||
background-color $ui-noteDetail-backgroundColor
|
||||
|
||||
.tabList-item
|
||||
position relative
|
||||
flex 1
|
||||
overflow hidden
|
||||
&:hover
|
||||
background-color $ui-button--hover-backgroundColorg
|
||||
|
||||
.tabList-item--active
|
||||
@extend .tabList-item
|
||||
border-bottom $ui-border
|
||||
|
||||
.tabList-item-button
|
||||
width 100%
|
||||
height 29px
|
||||
overflow ellipsis
|
||||
text-align left
|
||||
padding-right 30px
|
||||
padding-left 10px
|
||||
border none
|
||||
background-color transparent
|
||||
transition 0.15s
|
||||
&:hover
|
||||
background-color $ui-button--hover-backgroundColor
|
||||
|
||||
.tabView
|
||||
absolute left right bottom
|
||||
top 130px
|
||||
|
||||
.tabView-content
|
||||
absolute top left right bottom
|
||||
box-sizing border-box
|
||||
height 100%
|
||||
width 100%
|
||||
|
||||
body[data-theme="dark"]
|
||||
.root
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
|
||||
.description
|
||||
border-color $ui-dark-borderColor
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
|
||||
.description-textarea
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
color white
|
||||
|
||||
.tabList
|
||||
background-color $ui-dark-noteDetail-backgroundColor
|
||||
|
||||
.tabList-item
|
||||
border-color $ui-dark-borderColor
|
||||
&:hover
|
||||
background-color $ui-dark-button--hover-backgroundColor
|
||||
|
||||
.tabList-item-button
|
||||
border none
|
||||
color $ui-dark-text-color
|
||||
background-color transparent
|
||||
transition color background-color 0.15s
|
||||
border-left 4px solid transparent
|
||||
&:hover
|
||||
color white
|
||||
background-color $ui-dark-button--hover-backgroundColor
|
||||
|
||||
|
||||
body[data-theme="solarized-dark"]
|
||||
.root
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
|
||||
.description
|
||||
border-color $ui-dark-borderColor
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
|
||||
.description-textarea
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
color white
|
||||
|
||||
.tabList
|
||||
background-color $ui-solarized-dark-backgroundColor
|
||||
|
||||
.tabList-item
|
||||
border-color $ui-dark-borderColor
|
||||
&:hover
|
||||
background-color $ui-dark-button--hover-backgroundColor
|
||||
|
||||
.tabList-item-button
|
||||
border none
|
||||
color $ui-dark-text-color
|
||||
background-color transparent
|
||||
transition color background-color 0.15s
|
||||
border-left 4px solid transparent
|
||||
&:hover
|
||||
color white
|
||||
background-color $ui-dark-button--hover-backgroundColor
|
||||
|
||||
@@ -1,90 +0,0 @@
|
||||
import React from 'react'
|
||||
import NoteItem from 'browser/components/NoteItem'
|
||||
import moment from 'moment'
|
||||
|
||||
class NoteList extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
range: 0
|
||||
}
|
||||
}
|
||||
|
||||
componentWillReceiveProps (nextProps) {
|
||||
if (this.props.search !== nextProps.search) {
|
||||
this.resetScroll()
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate () {
|
||||
const { index } = this.props
|
||||
|
||||
if (index > -1) {
|
||||
const list = this.refs.root
|
||||
const item = list.childNodes[index]
|
||||
if (item == null) return null
|
||||
|
||||
const overflowBelow = item.offsetTop + item.clientHeight - list.clientHeight - list.scrollTop > 0
|
||||
if (overflowBelow) {
|
||||
list.scrollTop = item.offsetTop + item.clientHeight - list.clientHeight
|
||||
}
|
||||
const overflowAbove = list.scrollTop > item.offsetTop
|
||||
if (overflowAbove) {
|
||||
list.scrollTop = item.offsetTop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
resetScroll () {
|
||||
this.refs.root.scrollTop = 0
|
||||
this.setState({
|
||||
range: 0
|
||||
})
|
||||
}
|
||||
|
||||
handleScroll (e) {
|
||||
const { notes } = this.props
|
||||
|
||||
if (e.target.offsetHeight + e.target.scrollTop > e.target.scrollHeight - 100 && notes.length > this.state.range * 10 + 10) {
|
||||
this.setState({
|
||||
range: this.state.range + 1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render () {
|
||||
const { notes, index } = this.props
|
||||
|
||||
const notesList = notes
|
||||
.slice(0, 10 + 10 * this.state.range)
|
||||
.map((note, _index) => {
|
||||
const isActive = (index === _index)
|
||||
const key = `${note.storage}-${note.key}`
|
||||
const dateDisplay = moment(note.updatedAt).fromNow()
|
||||
|
||||
return (
|
||||
<NoteItem
|
||||
isActive={isActive}
|
||||
note={note}
|
||||
dateDisplay={dateDisplay}
|
||||
key={key}
|
||||
handleNoteClick={(e) => this.props.handleNoteClick(e, _index)}
|
||||
/>
|
||||
)
|
||||
})
|
||||
return (
|
||||
<div className={this.props.className}
|
||||
onScroll={(e) => this.handleScroll(e)}
|
||||
ref='root'
|
||||
>
|
||||
{notesList}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
NoteList.propTypes = {
|
||||
}
|
||||
|
||||
export default NoteList
|
||||
@@ -1,77 +0,0 @@
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './StorageSection.styl'
|
||||
import StorageItem from 'browser/components/StorageItem'
|
||||
|
||||
class StorageSection extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
isOpen: true
|
||||
}
|
||||
}
|
||||
|
||||
handleToggleButtonClick (e) {
|
||||
this.setState({
|
||||
isOpen: !this.state.isOpen
|
||||
})
|
||||
}
|
||||
|
||||
handleHeaderClick (e) {
|
||||
const { storage } = this.props
|
||||
this.props.handleStorageButtonClick(e, storage.key)
|
||||
}
|
||||
|
||||
handleFolderClick (e, folder) {
|
||||
const { storage } = this.props
|
||||
this.props.handleFolderButtonClick(e, storage.key, folder.key)
|
||||
}
|
||||
|
||||
render () {
|
||||
const { storage, filter } = this.props
|
||||
const folderList = storage.folders
|
||||
.map(folder => (
|
||||
<StorageItem
|
||||
key={folder.key}
|
||||
isActive={filter.type === 'FOLDER' && filter.folder === folder.key && filter.storage === storage.key}
|
||||
handleButtonClick={(e) => this.handleFolderClick(e, folder)}
|
||||
folderName={folder.name}
|
||||
folderColor={folder.color}
|
||||
isFolded={false}
|
||||
/>
|
||||
))
|
||||
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='header'>
|
||||
<button styleName='header-toggleButton'
|
||||
onClick={(e) => this.handleToggleButtonClick(e)}
|
||||
>
|
||||
<i className={this.state.isOpen
|
||||
? 'fa fa-caret-down'
|
||||
: 'fa fa-caret-right'
|
||||
}
|
||||
/>
|
||||
</button>
|
||||
<button styleName={filter.type === 'STORAGE' && filter.storage === storage.key
|
||||
? 'header-name--active'
|
||||
: 'header-name'
|
||||
}
|
||||
onClick={(e) => this.handleHeaderClick(e)}
|
||||
>{storage.name}</button>
|
||||
</div>
|
||||
{this.state.isOpen &&
|
||||
<div styleName='folderList'>
|
||||
{folderList}
|
||||
</div>
|
||||
}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
StorageSection.propTypes = {
|
||||
}
|
||||
|
||||
export default CSSModules(StorageSection, styles)
|
||||
@@ -1,85 +0,0 @@
|
||||
.root
|
||||
position relative
|
||||
|
||||
.header
|
||||
height 26px
|
||||
.header-toggleButton
|
||||
absolute top left
|
||||
width 25px
|
||||
height 26px
|
||||
navButtonColor()
|
||||
border none
|
||||
outline none
|
||||
.header-name
|
||||
display block
|
||||
height 26px
|
||||
navButtonColor()
|
||||
padding 0 10px 0 25px
|
||||
font-size 14px
|
||||
width 100%
|
||||
text-align left
|
||||
line-height 26px
|
||||
box-sizing border-box
|
||||
cursor pointer
|
||||
outline none
|
||||
|
||||
.header-name--active
|
||||
@extend .header-name
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-button--active-color
|
||||
&:hover
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.folderList-item
|
||||
display block
|
||||
width 100%
|
||||
height 26px
|
||||
navButtonColor()
|
||||
padding 0 10px 0 25px
|
||||
font-size 14px
|
||||
width 100%
|
||||
text-align left
|
||||
line-height 26px
|
||||
box-sizing border-box
|
||||
cursor pointer
|
||||
outline none
|
||||
padding 0 10px
|
||||
margin 2px 0
|
||||
height 26px
|
||||
line-height 26px
|
||||
border-width 0 0 0 6px
|
||||
border-style solid
|
||||
border-color transparent
|
||||
|
||||
.folderList-item--active
|
||||
@extend .folderList-item
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-button--active-color
|
||||
&:hover
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
body[data-theme="dark"]
|
||||
.header-toggleButton
|
||||
navDarkButtonColor()
|
||||
.header-name
|
||||
navDarkButtonColor()
|
||||
|
||||
.header-name--active
|
||||
@extend .header-name
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-button--active-color
|
||||
&:hover
|
||||
background-color $ui-button--active-backgroundColor
|
||||
|
||||
.folderList-item
|
||||
navDarkButtonColor()
|
||||
border-width 0 0 0 6px
|
||||
border-style solid
|
||||
border-color transparent
|
||||
|
||||
.folderList-item--active
|
||||
@extend .folderList-item
|
||||
background-color $ui-button--active-backgroundColor
|
||||
color $ui-button--active-color
|
||||
&:hover
|
||||
background-color $ui-button--active-backgroundColor
|
||||
@@ -1,357 +0,0 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { connect, Provider } from 'react-redux'
|
||||
import _ from 'lodash'
|
||||
import store from './store'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './FinderMain.styl'
|
||||
import StorageSection from './StorageSection'
|
||||
import NoteList from './NoteList'
|
||||
import NoteDetail from './NoteDetail'
|
||||
import SideNavFilter from 'browser/components/SideNavFilter'
|
||||
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
||||
require('!!style!css!stylus?sourceMap!../main/global.styl')
|
||||
require('../lib/customMeta')
|
||||
require('./ipcClient.js')
|
||||
|
||||
const electron = require('electron')
|
||||
const { remote } = electron
|
||||
const { Menu } = remote
|
||||
|
||||
function hideFinder () {
|
||||
const finderWindow = remote.getCurrentWindow()
|
||||
if (global.process.platform === 'win32') {
|
||||
finderWindow.blur()
|
||||
finderWindow.hide()
|
||||
}
|
||||
if (global.process.platform === 'darwin') {
|
||||
Menu.sendActionToFirstResponder('hide:')
|
||||
}
|
||||
remote.getCurrentWindow().hide()
|
||||
}
|
||||
|
||||
require('!!style!css!stylus?sourceMap!../styles/finder/index.styl')
|
||||
|
||||
class FinderMain extends React.Component {
|
||||
constructor (props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
search: '',
|
||||
index: 0,
|
||||
filter: {
|
||||
includeSnippet: true,
|
||||
includeMarkdown: false,
|
||||
type: 'ALL',
|
||||
storage: null,
|
||||
folder: null
|
||||
}
|
||||
}
|
||||
|
||||
this.focusHandler = (e) => this.handleWindowFocus(e)
|
||||
this.blurHandler = (e) => this.handleWindowBlur(e)
|
||||
}
|
||||
|
||||
componentDidMount () {
|
||||
this.refs.search.focus()
|
||||
window.addEventListener('focus', this.focusHandler)
|
||||
window.addEventListener('blur', this.blurHandler)
|
||||
}
|
||||
|
||||
componentWillUnmount () {
|
||||
window.removeEventListener('focus', this.focusHandler)
|
||||
window.removeEventListener('blur', this.blurHandler)
|
||||
}
|
||||
|
||||
handleWindowFocus (e) {
|
||||
this.refs.search.focus()
|
||||
}
|
||||
|
||||
handleWindowBlur (e) {
|
||||
this.setState({
|
||||
search: ''
|
||||
})
|
||||
}
|
||||
|
||||
handleKeyDown (e) {
|
||||
this.refs.search.focus()
|
||||
if (e.keyCode === 9) {
|
||||
if (e.shiftKey) {
|
||||
this.refs.detail.selectPriorSnippet()
|
||||
} else {
|
||||
this.refs.detail.selectNextSnippet()
|
||||
}
|
||||
e.preventDefault()
|
||||
}
|
||||
if (e.keyCode === 38) {
|
||||
this.selectPrevious()
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
if (e.keyCode === 40) {
|
||||
this.selectNext()
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
if (e.keyCode === 13) {
|
||||
this.refs.detail.saveToClipboard()
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('COPY_FINDER')
|
||||
hideFinder()
|
||||
e.preventDefault()
|
||||
}
|
||||
if (e.keyCode === 27) {
|
||||
hideFinder()
|
||||
e.preventDefault()
|
||||
}
|
||||
if (e.keyCode === 91) {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
handleSearchChange (e) {
|
||||
this.setState({
|
||||
search: e.target.value,
|
||||
index: 0
|
||||
})
|
||||
}
|
||||
|
||||
selectArticle (article) {
|
||||
this.setState({currentArticle: article})
|
||||
}
|
||||
|
||||
selectPrevious () {
|
||||
if (this.state.index > 0) {
|
||||
this.setState({
|
||||
index: this.state.index - 1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
selectNext () {
|
||||
if (this.state.index < this.noteCount - 1) {
|
||||
this.setState({
|
||||
index: this.state.index + 1
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
handleOnlySnippetCheckboxChange (e) {
|
||||
const { filter } = this.state
|
||||
filter.includeSnippet = e.target.checked
|
||||
this.setState({
|
||||
filter: filter,
|
||||
index: 0
|
||||
}, () => {
|
||||
this.refs.search.focus()
|
||||
})
|
||||
}
|
||||
|
||||
handleOnlyMarkdownCheckboxChange (e) {
|
||||
const { filter } = this.state
|
||||
filter.includeMarkdown = e.target.checked
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
filter: filter,
|
||||
index: 0
|
||||
}, () => {
|
||||
this.refs.search.focus()
|
||||
})
|
||||
}
|
||||
|
||||
handleAllNotesButtonClick (e) {
|
||||
const { filter } = this.state
|
||||
filter.type = 'ALL'
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
filter,
|
||||
index: 0
|
||||
}, () => {
|
||||
this.refs.search.focus()
|
||||
})
|
||||
}
|
||||
|
||||
handleStarredButtonClick (e) {
|
||||
const { filter } = this.state
|
||||
filter.type = 'STARRED'
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
filter,
|
||||
index: 0
|
||||
}, () => {
|
||||
this.refs.search.focus()
|
||||
})
|
||||
}
|
||||
|
||||
handleStorageButtonClick (e, storage) {
|
||||
const { filter } = this.state
|
||||
filter.type = 'STORAGE'
|
||||
filter.storage = storage
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
filter,
|
||||
index: 0
|
||||
}, () => {
|
||||
this.refs.search.focus()
|
||||
})
|
||||
}
|
||||
|
||||
handleFolderButtonClick (e, storage, folder) {
|
||||
const { filter } = this.state
|
||||
filter.type = 'FOLDER'
|
||||
filter.storage = storage
|
||||
filter.folder = folder
|
||||
this.refs.list.resetScroll()
|
||||
this.setState({
|
||||
filter,
|
||||
index: 0
|
||||
}, () => {
|
||||
this.refs.search.focus()
|
||||
})
|
||||
}
|
||||
|
||||
handleNoteClick (e, index) {
|
||||
this.setState({
|
||||
index
|
||||
}, () => {
|
||||
this.refs.search.focus()
|
||||
})
|
||||
}
|
||||
|
||||
render () {
|
||||
const { data, config } = this.props
|
||||
const { filter, search } = this.state
|
||||
const storageList = []
|
||||
for (const key in data.storageMap) {
|
||||
const storage = data.storageMap[key]
|
||||
const item = (
|
||||
<StorageSection
|
||||
filter={filter}
|
||||
storage={storage}
|
||||
key={storage.key}
|
||||
handleStorageButtonClick={(e, storage) => this.handleStorageButtonClick(e, storage)}
|
||||
handleFolderButtonClick={(e, storage, folder) => this.handleFolderButtonClick(e, storage, folder)}
|
||||
/>
|
||||
)
|
||||
storageList.push(item)
|
||||
}
|
||||
let notes = []
|
||||
let noteIds
|
||||
|
||||
switch (filter.type) {
|
||||
case 'STORAGE':
|
||||
noteIds = data.storageNoteMap[filter.storage]
|
||||
break
|
||||
case 'FOLDER':
|
||||
noteIds = data.folderNoteMap[filter.storage + '-' + filter.folder]
|
||||
break
|
||||
case 'STARRED':
|
||||
noteIds = data.starredSet
|
||||
}
|
||||
if (noteIds != null) {
|
||||
noteIds.forEach((id) => {
|
||||
notes.push(data.noteMap[id])
|
||||
})
|
||||
} else {
|
||||
for (const key in data.noteMap) {
|
||||
notes.push(data.noteMap[key])
|
||||
}
|
||||
}
|
||||
|
||||
if (!filter.includeSnippet && filter.includeMarkdown) {
|
||||
notes = notes.filter((note) => note.type === 'MARKDOWN_NOTE')
|
||||
} else if (filter.includeSnippet && !filter.includeMarkdown) {
|
||||
notes = notes.filter((note) => note.type === 'SNIPPET_NOTE')
|
||||
}
|
||||
|
||||
if (search.trim().length > 0) {
|
||||
const needle = new RegExp(_.escapeRegExp(search.trim()), 'i')
|
||||
notes = notes.filter((note) => note.title.match(needle))
|
||||
}
|
||||
notes = notes
|
||||
.sort((a, b) => new Date(b.updatedAt) - new Date(a.updatedAt))
|
||||
|
||||
const activeNote = notes[this.state.index]
|
||||
this.noteCount = notes.length
|
||||
|
||||
return (
|
||||
<div className='Finder'
|
||||
styleName='root'
|
||||
ref='-1'
|
||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
||||
>
|
||||
<div styleName='search'>
|
||||
<input
|
||||
styleName='search-input'
|
||||
ref='search'
|
||||
value={search}
|
||||
placeholder='Search...'
|
||||
onChange={(e) => this.handleSearchChange(e)}
|
||||
/>
|
||||
</div>
|
||||
<div styleName='result'>
|
||||
<div styleName='result-nav'>
|
||||
<div styleName='result-nav-filter'>
|
||||
<div styleName='result-nav-filter-option'>
|
||||
<label>
|
||||
<input type='checkbox'
|
||||
checked={filter.includeSnippet}
|
||||
onChange={(e) => this.handleOnlySnippetCheckboxChange(e)}
|
||||
/> Only Snippets</label>
|
||||
</div>
|
||||
<div styleName='result-nav-filter-option'>
|
||||
<label>
|
||||
<input type='checkbox'
|
||||
checked={filter.includeMarkdown}
|
||||
onChange={(e) => this.handleOnlyMarkdownCheckboxChange(e)}
|
||||
/> Only Markdown</label>
|
||||
</div>
|
||||
</div>
|
||||
<SideNavFilter
|
||||
isHomeActive={filter.type === 'ALL'}
|
||||
handleAllNotesButtonClick={(e) => this.handleAllNotesButtonClick(e)}
|
||||
isStarredActive={filter.type === 'STARRED'}
|
||||
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
|
||||
/>
|
||||
<div styleName='result-nav-storageList'>
|
||||
{storageList}
|
||||
</div>
|
||||
</div>
|
||||
<NoteList styleName='result-list'
|
||||
storageMap={data.storageMap}
|
||||
notes={notes}
|
||||
ref='list'
|
||||
search={search}
|
||||
index={this.state.index}
|
||||
handleNoteClick={(e, _index) => this.handleNoteClick(e, _index)}
|
||||
/>
|
||||
<div styleName='result-detail'>
|
||||
<NoteDetail
|
||||
note={activeNote}
|
||||
config={config}
|
||||
ref='detail'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
FinderMain.propTypes = {
|
||||
dispatch: PropTypes.func
|
||||
}
|
||||
|
||||
var Finder = connect((x) => x)(CSSModules(FinderMain, styles))
|
||||
|
||||
function refreshData () {
|
||||
// let data = dataStore.getData(true)
|
||||
}
|
||||
|
||||
ReactDOM.render((
|
||||
<Provider store={store}>
|
||||
<Finder />
|
||||
</Provider>
|
||||
), document.getElementById('content'), function () {
|
||||
refreshData()
|
||||
})
|
||||
@@ -1,126 +0,0 @@
|
||||
const nodeIpc = require('node-ipc')
|
||||
const { remote, ipcRenderer } = require('electron')
|
||||
const { app, Menu } = remote
|
||||
const path = require('path')
|
||||
const store = require('./store')
|
||||
const consts = require('browser/lib/consts')
|
||||
|
||||
nodeIpc.config.id = 'finder'
|
||||
nodeIpc.config.retry = 1500
|
||||
nodeIpc.config.silent = true
|
||||
|
||||
function killFinder () {
|
||||
const finderWindow = remote.getCurrentWindow()
|
||||
finderWindow.removeAllListeners()
|
||||
if (global.process.platform === 'darwin') {
|
||||
// Only OSX has another app process.
|
||||
nodeIpc.of.node.emit('quit-from-finder')
|
||||
} else {
|
||||
finderWindow.close()
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFinder () {
|
||||
const finderWindow = remote.getCurrentWindow()
|
||||
if (global.process.platform === 'darwin') {
|
||||
if (finderWindow.isVisible()) {
|
||||
finderWindow.hide()
|
||||
Menu.sendActionToFirstResponder('hide:')
|
||||
} else {
|
||||
nodeIpc.of.node.emit('request-data-from-finder')
|
||||
finderWindow.show()
|
||||
}
|
||||
} else {
|
||||
if (finderWindow.isVisible()) {
|
||||
finderWindow.blur()
|
||||
finderWindow.hide()
|
||||
} else {
|
||||
nodeIpc.of.node.emit('request-data-from-finder')
|
||||
finderWindow.show()
|
||||
finderWindow.focus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
nodeIpc.connectTo(
|
||||
'node',
|
||||
path.join(app.getPath('userData'), 'boostnote.service'),
|
||||
function () {
|
||||
nodeIpc.of.node.on('error', function (err) {
|
||||
console.log(err)
|
||||
})
|
||||
nodeIpc.of.node.on('connect', function () {
|
||||
console.log('Conncted successfully')
|
||||
})
|
||||
nodeIpc.of.node.on('disconnect', function () {
|
||||
console.log('disconnected')
|
||||
})
|
||||
|
||||
nodeIpc.of.node.on('open-finder', function () {
|
||||
toggleFinder()
|
||||
})
|
||||
|
||||
ipcRenderer.on('open-finder-from-tray', function () {
|
||||
toggleFinder()
|
||||
})
|
||||
ipcRenderer.on('open-main-from-tray', function () {
|
||||
nodeIpc.of.node.emit('open-main-from-finder')
|
||||
})
|
||||
|
||||
ipcRenderer.on('quit-from-tray', function () {
|
||||
nodeIpc.of.node.emit('quit-from-finder')
|
||||
killFinder()
|
||||
})
|
||||
|
||||
nodeIpc.of.node.on('throttle-data', function (payload) {
|
||||
console.log('Received data from Main renderer')
|
||||
store.default.dispatch({
|
||||
type: 'THROTTLE_DATA',
|
||||
data: payload
|
||||
})
|
||||
})
|
||||
|
||||
nodeIpc.of.node.on('config-renew', function (payload) {
|
||||
const { config } = payload
|
||||
if (config.ui.theme === 'dark') {
|
||||
document.body.setAttribute('data-theme', 'dark')
|
||||
} else if (config.ui.theme === 'white') {
|
||||
document.body.setAttribute('data-theme', 'white')
|
||||
} else if (config.ui.theme === 'solarized-dark') {
|
||||
document.body.setAttribute('data-theme', 'solarized-dark')
|
||||
} else {
|
||||
document.body.setAttribute('data-theme', 'default')
|
||||
}
|
||||
|
||||
let editorTheme = document.getElementById('editorTheme')
|
||||
if (editorTheme == null) {
|
||||
editorTheme = document.createElement('link')
|
||||
editorTheme.setAttribute('id', 'editorTheme')
|
||||
editorTheme.setAttribute('rel', 'stylesheet')
|
||||
document.head.appendChild(editorTheme)
|
||||
}
|
||||
|
||||
config.editor.theme = consts.THEMES.some((theme) => theme === config.editor.theme)
|
||||
? config.editor.theme
|
||||
: 'default'
|
||||
|
||||
if (config.editor.theme !== 'default') {
|
||||
editorTheme.setAttribute('href', '../node_modules/codemirror/theme/' + config.editor.theme + '.css')
|
||||
}
|
||||
|
||||
store.default.dispatch({
|
||||
type: 'SET_CONFIG',
|
||||
config: config
|
||||
})
|
||||
})
|
||||
|
||||
nodeIpc.of.node.on('quit-finder-app', function () {
|
||||
nodeIpc.of.node.emit('quit-finder-app-confirm')
|
||||
killFinder()
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
const ipc = {}
|
||||
|
||||
module.exports = ipc
|
||||
@@ -1,51 +0,0 @@
|
||||
import { combineReducers, createStore } from 'redux'
|
||||
import { routerReducer } from 'react-router-redux'
|
||||
import { DEFAULT_CONFIG } from 'browser/main/lib/ConfigManager'
|
||||
|
||||
const defaultData = {
|
||||
storageMap: {},
|
||||
noteMap: {},
|
||||
starredSet: [],
|
||||
storageNoteMap: {},
|
||||
folderNoteMap: {},
|
||||
tagNoteMap: {}
|
||||
}
|
||||
|
||||
function data (state = defaultData, action) {
|
||||
switch (action.type) {
|
||||
case 'THROTTLE_DATA':
|
||||
console.log(action)
|
||||
state = action.data
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
function config (state = DEFAULT_CONFIG, action) {
|
||||
switch (action.type) {
|
||||
case 'INIT_CONFIG':
|
||||
case 'SET_CONFIG':
|
||||
return Object.assign({}, state, action.config)
|
||||
case 'SET_IS_SIDENAV_FOLDED':
|
||||
state.isSideNavFolded = action.isFolded
|
||||
return Object.assign({}, state)
|
||||
case 'SET_ZOOM':
|
||||
state.zoom = action.zoom
|
||||
return Object.assign({}, state)
|
||||
case 'SET_LIST_WIDTH':
|
||||
state.listWidth = action.listWidth
|
||||
return Object.assign({}, state)
|
||||
case 'SET_UI':
|
||||
return Object.assign({}, state, action.config)
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
const reducer = combineReducers({
|
||||
data,
|
||||
config,
|
||||
routing: routerReducer
|
||||
})
|
||||
|
||||
const store = createStore(reducer)
|
||||
|
||||
export default store
|
||||
@@ -18,7 +18,6 @@ export const DEFAULT_CONFIG = {
|
||||
listStyle: 'DEFAULT', // 'DEFAULT', 'SMALL'
|
||||
amaEnabled: true,
|
||||
hotkey: {
|
||||
toggleFinder: OSX ? 'Cmd + Alt + S' : 'Super + Alt + S',
|
||||
toggleMain: OSX ? 'Cmd + Alt + L' : 'Super + Alt + E'
|
||||
},
|
||||
ui: {
|
||||
|
||||
@@ -24,20 +24,6 @@ nodeIpc.connectTo(
|
||||
nodeIpc.of.node.on('disconnect', function () {
|
||||
console.log('disconnected')
|
||||
})
|
||||
|
||||
nodeIpc.of.node.on('request-data-from-finder', function () {
|
||||
console.log('throttle')
|
||||
var { data } = store.getState()
|
||||
console.log(data.starredSet.toJS())
|
||||
nodeIpc.of.node.emit('throttle-data', {
|
||||
storageMap: data.storageMap.toJS(),
|
||||
noteMap: data.noteMap.toJS(),
|
||||
starredSet: data.starredSet.toJS(),
|
||||
storageNoteMap: data.storageNoteMap.toJS(),
|
||||
folderNoteMap: data.folderNoteMap.toJS(),
|
||||
tagNoteMap: data.tagNoteMap.toJS()
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -66,7 +66,6 @@ class HotkeyTab extends React.Component {
|
||||
handleHotkeyChange (e) {
|
||||
const { config } = this.state
|
||||
config.hotkey = {
|
||||
toggleFinder: this.refs.toggleFinder.value,
|
||||
toggleMain: this.refs.toggleMain.value
|
||||
}
|
||||
this.setState({
|
||||
@@ -115,17 +114,6 @@ class HotkeyTab extends React.Component {
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>Toggle Finder (Quick search)</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input styleName='group-section-control-input'
|
||||
onChange={(e) => this.handleHotkeyChange(e)}
|
||||
ref='toggleFinder'
|
||||
value={config.hotkey.toggleFinder}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div styleName='group-control'>
|
||||
<button styleName='group-control-leftButton'
|
||||
onClick={(e) => this.handleHintToggleButtonClick(e)}
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
@import '../../../node_modules/nib/lib/nib'
|
||||
@import '../vars'
|
||||
@import '../mixins/*'
|
||||
global-reset()
|
||||
@import '../shared/*'
|
||||
@import '../theme/*'
|
||||
|
||||
iptBgColor = #E6E6E6
|
||||
iptFocusBorderColor = #369DCD
|
||||
|
||||
DEFAULT_FONTS = 'Lato', 'MS Gothic', 'Malgun Gothic', 'Sans-serif'
|
||||
|
||||
body
|
||||
font-family DEFAULT_FONTS
|
||||
color textColor
|
||||
font-size fontSize
|
||||
width 100%
|
||||
height 100%
|
||||
overflow hidden
|
||||
button, input
|
||||
font-family DEFAULT_FONTS
|
||||
|
||||
.Finder
|
||||
absolute top bottom left right
|
||||
.FinderInput
|
||||
padding 11px
|
||||
margin 0 auto
|
||||
height 55px
|
||||
box-sizing border-box
|
||||
border-bottom solid 1px borderColor
|
||||
background-color iptBgColor
|
||||
z-index 200
|
||||
input
|
||||
display block
|
||||
width 100%
|
||||
border solid 1px borderColor
|
||||
padding 0 10px
|
||||
font-size 1em
|
||||
height 33px
|
||||
border-radius 5px
|
||||
box-sizing border-box
|
||||
border-radius 5px
|
||||
&:focus, &.focus
|
||||
border-color iptFocusBorderColor
|
||||
outline none
|
||||
.FinderList
|
||||
absolute left bottom
|
||||
top 55px
|
||||
border-right solid 1px borderColor
|
||||
box-sizing border-box
|
||||
width 250px
|
||||
overflow-y auto
|
||||
z-index 0
|
||||
user-select none
|
||||
&>ul>li
|
||||
.articleItem
|
||||
padding 10px
|
||||
border solid 2px transparent
|
||||
box-sizing border-box
|
||||
cursor pointer
|
||||
white-space nowrap
|
||||
overflow-x hidden
|
||||
text-overflow ellipsis
|
||||
.divider
|
||||
box-sizing border-box
|
||||
border-bottom solid 1px borderColor
|
||||
&.active
|
||||
.articleItem
|
||||
border-color brandColor
|
||||
|
||||
.FinderDetail
|
||||
absolute right bottom
|
||||
top 55px
|
||||
left 250px
|
||||
box-shadow 0px 0px 10px 0 #CCC
|
||||
z-index 100
|
||||
.header
|
||||
absolute top left right
|
||||
height 55px
|
||||
box-sizing border-box
|
||||
padding 0 10px
|
||||
border-bottom solid 1px borderColor
|
||||
line-height 55px
|
||||
font-size 18px
|
||||
white-space nowrap
|
||||
text-overflow ellipsis
|
||||
overflow-x hidden
|
||||
clearfix()
|
||||
.left
|
||||
float left
|
||||
.right
|
||||
float right
|
||||
button
|
||||
border-radius 16.5px
|
||||
cursor pointer
|
||||
height 33px
|
||||
width 33px
|
||||
border none
|
||||
margin-right 5px
|
||||
font-size 18px
|
||||
color inactiveTextColor
|
||||
background-color transparent
|
||||
padding 0
|
||||
.tooltip
|
||||
tooltip()
|
||||
&.clipboardBtn .tooltip
|
||||
margin-left -160px
|
||||
margin-top 25px
|
||||
&:hover
|
||||
color textColor
|
||||
.tooltip
|
||||
opacity 1
|
||||
.content
|
||||
position absolute
|
||||
top 55px
|
||||
padding 10px
|
||||
bottom 0
|
||||
left 0
|
||||
right 0
|
||||
box-sizing border-box
|
||||
overflow-y auto
|
||||
.MarkdownPreview
|
||||
marked()
|
||||
&.empty
|
||||
color lighten(inactiveTextColor, 10%)
|
||||
user-select none
|
||||
font-size 14px
|
||||
.CodeEditor
|
||||
absolute top bottom left right
|
||||
@@ -378,52 +378,10 @@ body[data-theme="dark"]
|
||||
&:hover
|
||||
color themeDarkFocusButton
|
||||
|
||||
.Finder
|
||||
.FinderInput
|
||||
color themeDarkText
|
||||
border-color themeDarkBorder
|
||||
background-color themeDarkBackground
|
||||
|
||||
input
|
||||
color themeDarkText
|
||||
border-color lighten(themeDarkBackground, 10%)
|
||||
background-color lighten(themeDarkBackground, 10%)
|
||||
|
||||
&:focus
|
||||
border-color themeDarkTopicColor
|
||||
|
||||
.FinderList
|
||||
color themeDarkText
|
||||
border-color themeDarkBorder
|
||||
background-color themeDarkList
|
||||
|
||||
.divider
|
||||
border-color themeDarkBorder
|
||||
|
||||
.FinderDetail
|
||||
color themeDarkText
|
||||
border-color themeDarkBorder
|
||||
background-color themeDarkPreview
|
||||
box-shadow 0px 0px 10px 0 darken(themeDarkBorder, 20%);
|
||||
|
||||
.header
|
||||
border-color themeDarkBorder
|
||||
|
||||
.right
|
||||
.clipboardBtn
|
||||
transition 0.1s
|
||||
|
||||
&:hover
|
||||
color themeDarkFocusButton
|
||||
|
||||
.tooltip
|
||||
background-color themeDarkTooltip
|
||||
|
||||
.ArticleDetail-panel
|
||||
border-radius 0
|
||||
|
||||
// Markdown Preview
|
||||
.Finder .FinderDetail .content,
|
||||
.ArticleDetail .ArticleDetail-panel .ArticleEditor
|
||||
.MarkdownPreview
|
||||
color themeDarkText
|
||||
|
||||
11
index.js
11
index.js
@@ -4,11 +4,6 @@ const path = require('path')
|
||||
|
||||
var error = null
|
||||
|
||||
function isFinderCalled () {
|
||||
var argv = process.argv.slice(1)
|
||||
return argv.some((arg) => arg.match(/--finder/))
|
||||
}
|
||||
|
||||
function execMainApp () {
|
||||
const appRootPath = path.join(process.execPath, '../..')
|
||||
const updateDotExePath = path.join(appRootPath, 'Update.exe')
|
||||
@@ -78,8 +73,4 @@ function execMainApp () {
|
||||
require('./lib/main-app')
|
||||
}
|
||||
|
||||
if (isFinderCalled()) {
|
||||
require('./lib/finder-app')
|
||||
} else {
|
||||
execMainApp()
|
||||
}
|
||||
execMainApp()
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
const electron = require('electron')
|
||||
const app = electron.app
|
||||
|
||||
app.on('ready', function () {
|
||||
if (process.platform === 'darwin') {
|
||||
app.dock.hide()
|
||||
}
|
||||
|
||||
/* eslint-disable */
|
||||
finderWindow = require('./finder-window')
|
||||
/* eslint-enable */
|
||||
})
|
||||
|
||||
module.exports = app
|
||||
@@ -1,101 +0,0 @@
|
||||
const electron = require('electron')
|
||||
const { app } = electron
|
||||
const BrowserWindow = electron.BrowserWindow
|
||||
const Menu = electron.Menu
|
||||
const MenuItem = electron.MenuItem
|
||||
const Tray = electron.Tray
|
||||
const path = require('path')
|
||||
|
||||
var config = {
|
||||
width: 840,
|
||||
height: 540,
|
||||
show: false,
|
||||
frame: false,
|
||||
resizable: false,
|
||||
zoomFactor: 1.0,
|
||||
webPreferences: {
|
||||
blinkFeatures: 'OverlayScrollbars'
|
||||
},
|
||||
skipTaskbar: true,
|
||||
standardWindow: false
|
||||
}
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
config['always-on-top'] = true
|
||||
}
|
||||
|
||||
var finderWindow = new BrowserWindow(config)
|
||||
|
||||
var url = path.resolve(__dirname, './finder.html')
|
||||
|
||||
finderWindow.loadURL('file://' + url)
|
||||
finderWindow.setSkipTaskbar(true)
|
||||
|
||||
if (process.platform === 'darwin') {
|
||||
finderWindow.setVisibleOnAllWorkspaces(true)
|
||||
}
|
||||
|
||||
finderWindow.on('blur', function () {
|
||||
hideFinder()
|
||||
})
|
||||
|
||||
finderWindow.on('close', function (e) {
|
||||
e.preventDefault()
|
||||
finderWindow.hide()
|
||||
})
|
||||
|
||||
var trayIcon = process.platform === 'darwin' || process.platform === 'win32'
|
||||
? path.join(__dirname, '../resources/tray-icon-default.png')
|
||||
: path.join(__dirname, '../resources/tray-icon.png')
|
||||
var appIcon = new Tray(trayIcon)
|
||||
appIcon.setToolTip('Boostnote')
|
||||
if (process.platform === 'darwin') {
|
||||
appIcon.setPressedImage(path.join(__dirname, '../resources/tray-icon-dark.png'))
|
||||
}
|
||||
|
||||
var trayMenu = new Menu()
|
||||
trayMenu.append(new MenuItem({
|
||||
label: 'Open Main window',
|
||||
click: function () {
|
||||
finderWindow.webContents.send('open-main-from-tray')
|
||||
}
|
||||
}))
|
||||
|
||||
if (process.env.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon') {
|
||||
trayMenu.append(new MenuItem({
|
||||
label: 'Open Finder window',
|
||||
click: function () {
|
||||
finderWindow.webContents.send('open-finder-from-tray')
|
||||
}
|
||||
}))
|
||||
}
|
||||
|
||||
trayMenu.append(new MenuItem({
|
||||
label: 'Quit',
|
||||
click: function () {
|
||||
finderWindow.webContents.send('quit-from-tray')
|
||||
}
|
||||
}))
|
||||
|
||||
appIcon.setContextMenu(trayMenu)
|
||||
appIcon.on('click', function (e) {
|
||||
e.preventDefault()
|
||||
appIcon.popUpContextMenu(trayMenu)
|
||||
})
|
||||
|
||||
function hideFinder () {
|
||||
if (process.platform === 'win32') {
|
||||
finderWindow.minimize()
|
||||
return
|
||||
}
|
||||
if (process.platform === 'darwin') {
|
||||
Menu.sendActionToFirstResponder('hide:')
|
||||
}
|
||||
finderWindow.hide()
|
||||
}
|
||||
|
||||
app.on('before-quit', function (e) {
|
||||
finderWindow.removeAllListeners()
|
||||
})
|
||||
|
||||
module.exports = finderWindow
|
||||
@@ -1,65 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
|
||||
<title>Boostnote Finder</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/>
|
||||
|
||||
|
||||
<link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css">
|
||||
|
||||
<style>
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('../resources/fonts/Lato-Regular.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="content"></div>
|
||||
|
||||
<script src="../node_modules/codemirror/lib/codemirror.js"></script>
|
||||
<script src="../node_modules/codemirror/mode/meta.js"></script>
|
||||
<script src="../node_modules/codemirror-mode-elixir/dist/elixir.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/mode/overlay.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/mode/loadmode.js"></script>
|
||||
<script src="../node_modules/codemirror/keymap/sublime.js"></script>
|
||||
<script src="../node_modules/codemirror/keymap/vim.js"></script>
|
||||
<script src="../node_modules/codemirror/keymap/emacs.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/runmode/runmode.js"></script>
|
||||
<script src="../node_modules/codemirror/addon/edit/closebrackets.js"></script>
|
||||
|
||||
<script src="../node_modules/raphael/raphael.min.js"></script>
|
||||
<script src="../node_modules/flowchart.js/release/flowchart.min.js"></script>
|
||||
|
||||
<script src="../node_modules/katex/dist/katex.min.js"></script>
|
||||
<script src="../node_modules/react/dist/react.min.js"></script>
|
||||
<script src="../node_modules/react-dom/dist/react-dom.min.js"></script>
|
||||
<script src="../node_modules/redux/dist/redux.min.js"></script>
|
||||
<script src="../node_modules/react-redux/dist/react-redux.min.js"></script>
|
||||
<script>
|
||||
window._ = require('lodash');
|
||||
</script>
|
||||
<script src="../node_modules/js-sequence-diagrams/fucknpm/sequence-diagram-min.js"></script>
|
||||
<script>
|
||||
const electron = require('electron')
|
||||
electron.webFrame.setZoomLevelLimits(1, 1)
|
||||
const _ = require('lodash')
|
||||
var scriptUrl = _.find(electron.remote.process.argv, (a) => a === '--hot')
|
||||
? 'http://localhost:8080/assets/finder.js'
|
||||
: '../compiled/finder.js'
|
||||
var scriptEl = document.createElement('script')
|
||||
scriptEl.setAttribute('type', 'text/javascript')
|
||||
scriptEl.setAttribute('src', scriptUrl)
|
||||
document.body.appendChild(scriptEl)
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -26,10 +26,6 @@ function toggleMainWindow () {
|
||||
}
|
||||
}
|
||||
|
||||
function toggleFinder () {
|
||||
nodeIpc.server.broadcast('open-finder')
|
||||
}
|
||||
|
||||
ipcMain.on('config-renew', (e, payload) => {
|
||||
nodeIpc.server.broadcast('config-renew', payload)
|
||||
|
||||
@@ -37,11 +33,6 @@ ipcMain.on('config-renew', (e, payload) => {
|
||||
var { config } = payload
|
||||
|
||||
var errors = []
|
||||
try {
|
||||
globalShortcut.register(config.hotkey.toggleFinder, toggleFinder)
|
||||
} catch (err) {
|
||||
errors.push('toggleFinder')
|
||||
}
|
||||
try {
|
||||
globalShortcut.register(config.hotkey.toggleMain, toggleMainWindow)
|
||||
} catch (err) {
|
||||
@@ -61,12 +52,6 @@ ipcMain.on('config-renew', (e, payload) => {
|
||||
nodeIpc.serve(
|
||||
path.join(app.getPath('userData'), 'boostnote.service'),
|
||||
function () {
|
||||
nodeIpc.server.on('open-main-from-finder', toggleMainWindow)
|
||||
|
||||
nodeIpc.server.on('quit-from-finder', function () {
|
||||
app.quit()
|
||||
})
|
||||
|
||||
nodeIpc.server.on('connect', function (socket) {
|
||||
nodeIpc.log('ipc server >> socket joinned'.rainbow)
|
||||
socket.on('close', function () {
|
||||
@@ -76,14 +61,6 @@ nodeIpc.serve(
|
||||
nodeIpc.server.on('error', function (err) {
|
||||
nodeIpc.log('Node IPC error'.rainbow, err)
|
||||
})
|
||||
|
||||
// Todo: Direct connection between Main window renderer & Finder window renderer
|
||||
nodeIpc.server.on('request-data-from-finder', function () {
|
||||
nodeIpc.server.broadcast('request-data-from-finder')
|
||||
})
|
||||
nodeIpc.server.on('throttle-data', function (payload) {
|
||||
nodeIpc.server.broadcast('throttle-data', payload)
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@ const electron = require('electron')
|
||||
const app = electron.app
|
||||
const Menu = electron.Menu
|
||||
const ipc = electron.ipcMain
|
||||
const path = require('path')
|
||||
const ChildProcess = require('child_process')
|
||||
const _ = require('lodash')
|
||||
const GhReleases = require('electron-gh-releases')
|
||||
// electron.crashReporter.start()
|
||||
var ipcServer = null
|
||||
@@ -72,17 +69,6 @@ ipc.on('update-app-confirm', function (event, msg) {
|
||||
}
|
||||
})
|
||||
|
||||
function spawnFinder () {
|
||||
var finderArgv = [path.join(__dirname, 'finder-app.js'), '--finder']
|
||||
if (_.find(process.argv, a => a === '--hot')) finderArgv.push('--hot')
|
||||
var finderProcess = ChildProcess
|
||||
.execFile(process.execPath, finderArgv)
|
||||
|
||||
app.on('before-quit', function () {
|
||||
finderProcess.kill()
|
||||
})
|
||||
}
|
||||
|
||||
app.on('ready', function () {
|
||||
mainWindow = require('./main-window')
|
||||
|
||||
@@ -90,15 +76,12 @@ app.on('ready', function () {
|
||||
var menu = Menu.buildFromTemplate(template)
|
||||
switch (process.platform) {
|
||||
case 'darwin':
|
||||
spawnFinder()
|
||||
Menu.setApplicationMenu(menu)
|
||||
break
|
||||
case 'win32':
|
||||
require('./finder-window')
|
||||
mainWindow.setMenu(menu)
|
||||
break
|
||||
case 'linux':
|
||||
require('./finder-window')
|
||||
Menu.setApplicationMenu(menu)
|
||||
mainWindow.setMenu(menu)
|
||||
}
|
||||
@@ -125,4 +108,3 @@ app.on('ready', function () {
|
||||
})
|
||||
|
||||
module.exports = app
|
||||
|
||||
|
||||
@@ -4,10 +4,11 @@ const BrowserWindow = electron.BrowserWindow
|
||||
const path = require('path')
|
||||
const Config = require('electron-config')
|
||||
const config = new Config()
|
||||
const _ = require('lodash')
|
||||
|
||||
var showMenu = process.platform !== 'win32'
|
||||
const windowSize = config.get('windowsize') || { width: 1080, height: 720 }
|
||||
|
||||
console.log(windowSize)
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: windowSize.width,
|
||||
height: windowSize.height,
|
||||
@@ -57,26 +58,21 @@ if (process.platform !== 'linux' || process.env.DESKTOP_SESSION === 'cinnamon')
|
||||
})
|
||||
|
||||
app.on('before-quit', function (e) {
|
||||
storeWindowSize()
|
||||
mainWindow.removeAllListeners()
|
||||
})
|
||||
} else {
|
||||
mainWindow.on('close', function () {
|
||||
storeWindowSize()
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function () {
|
||||
app.quit()
|
||||
})
|
||||
}
|
||||
|
||||
mainWindow.on('resize', _.throttle(storeWindowSize, 500))
|
||||
function quitApp () {
|
||||
storeWindowSize()
|
||||
app.quit()
|
||||
}
|
||||
|
||||
function storeWindowSize () {
|
||||
try {
|
||||
console.log(mainWindow.getBounds())
|
||||
config.set('windowsize', mainWindow.getBounds())
|
||||
} catch (e) {
|
||||
// ignore any errors because an error occurs only on update
|
||||
|
||||
@@ -10,13 +10,13 @@
|
||||
"hot": "electron ./index.js --hot",
|
||||
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
|
||||
"compile": "grunt compile",
|
||||
"test": "PWD=$(pwd) NODE_ENV=test ava",
|
||||
"test": "PWD=$(pwd) NODE_ENV=test ava --serial",
|
||||
"fix": "npm run lint --fix",
|
||||
"lint": "eslint .",
|
||||
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\""
|
||||
},
|
||||
"config": {
|
||||
"electron-version": "1.7.10"
|
||||
"electron-version": "1.7.11"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -103,7 +103,7 @@
|
||||
"css-loader": "^0.19.0",
|
||||
"devtron": "^1.1.0",
|
||||
"dom-storage": "^2.0.2",
|
||||
"electron": "1.7.10",
|
||||
"electron": "1.7.11",
|
||||
"electron-packager": "^6.0.0",
|
||||
"eslint": "^3.13.1",
|
||||
"eslint-config-standard": "^6.2.1",
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
"theme": "monokai"
|
||||
},
|
||||
"hotkey": {
|
||||
"toggleFinder": "Cmd + Alt + S",
|
||||
"toggleMain": "Cmd + Alt + L"
|
||||
},
|
||||
"isSideNavFolded": false,
|
||||
|
||||
@@ -5,7 +5,7 @@ const { parse } = require('browser/lib/RcParser')
|
||||
// Unit test
|
||||
test('RcParser should return a json object', t => {
|
||||
const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 }
|
||||
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleFinder': 'Cmd + Alt + S', 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
|
||||
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
|
||||
|
||||
// [input, expected]
|
||||
const validTestCases = [
|
||||
|
||||
@@ -4,8 +4,7 @@ const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin')
|
||||
|
||||
var config = {
|
||||
entry: {
|
||||
main: './browser/main/index.js',
|
||||
finder: './browser/finder/index.js'
|
||||
main: './browser/main/index.js'
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['', '.js', '.jsx', '.styl'],
|
||||
|
||||
@@ -2212,9 +2212,9 @@ electron-winstaller@^2.2.0:
|
||||
lodash.template "^4.2.2"
|
||||
temp "^0.8.3"
|
||||
|
||||
electron@1.7.10:
|
||||
version "1.7.10"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.10.tgz#3a3e83d965fd7fafe473be8ddf8f472561b6253d"
|
||||
electron@1.7.11:
|
||||
version "1.7.11"
|
||||
resolved "https://registry.yarnpkg.com/electron/-/electron-1.7.11.tgz#993b6aa79e0e79a7cfcc369f4c813fbd9a0b08d9"
|
||||
dependencies:
|
||||
"@types/node" "^7.0.18"
|
||||
electron-download "^3.0.1"
|
||||
|
||||
Reference in New Issue
Block a user