1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 17:56:25 +00:00

snippet note

This commit is contained in:
Dick Choi
2016-07-21 01:17:53 +09:00
parent 69d11b5cd0
commit b6d34472fe
13 changed files with 890 additions and 96 deletions

View File

@@ -71,7 +71,6 @@ export default class MarkdownPreview extends React.Component {
el.removeEventListener('click', goExternal) el.removeEventListener('click', goExternal)
}) })
let { value, fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme } = this.props let { value, fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme } = this.props
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0 fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
? [fontFamily].concat(defaultFontFamily) ? [fontFamily].concat(defaultFontFamily)

View File

@@ -1,90 +1,9 @@
const modes = [ const modes = [
// Major
{ {
name: 'text', name: 'text',
label: 'Plain text', label: 'Plain text',
mode: 'text' mode: 'text'
}, },
{
name: 'markdown',
label: 'Markdown',
alias: ['md'],
mode: 'markdown'
},
{
name: 'javascript',
label: 'JavaScript',
alias: ['js', 'jscript', 'babel', 'es'],
mode: 'javascript'
},
{
name: 'html',
label: 'HTML',
alias: [],
mode: 'html'
},
{
name: 'css',
label: 'CSS',
alias: ['cascade', 'stylesheet'],
mode: 'css'
},
{
name: 'php',
label: 'PHP',
alias: [],
mode: 'php'
},
{
name: 'python',
label: 'Python',
alias: ['py'],
mode: 'python'
},
{
name: 'ruby',
label: 'Ruby',
alias: ['rb'],
mode: 'ruby'
},
{
name: 'java',
label: 'Java',
alias: [],
mode: 'java'
},
{
name: 'c',
label: 'C',
alias: ['c', 'h', 'clang', 'clang'],
mode: 'c_cpp'
},
{
name: 'cpp',
label: 'C++',
alias: ['cc', 'cpp', 'cxx', 'hh', 'c++', 'cplusplus'],
mode: 'c_cpp'
},
{
name: 'csharp',
label: 'C#',
alias: ['cs', 'c#'],
mode: 'csharp'
},
{
name: 'swift',
label: 'Swift',
alias: [],
mode: 'swift'
},
{
name: 'golang',
label: 'Go',
alias: ['go'],
mode: 'golang'
},
// Minor
{ {
name: 'abap', name: 'abap',
label: 'ABAP', label: 'ABAP',
@@ -145,6 +64,12 @@ const modes = [
alias: ['dos', 'windows', 'bat', 'cmd', 'btm'], alias: ['dos', 'windows', 'bat', 'cmd', 'btm'],
mode: 'batchfile' mode: 'batchfile'
}, },
{
name: 'c',
label: 'C',
alias: ['c', 'h', 'clang', 'clang'],
mode: 'c_cpp'
},
{ {
name: 'cirru', name: 'cirru',
label: 'Cirru', label: 'Cirru',
@@ -175,6 +100,24 @@ const modes = [
alias: ['cfm', 'cfc'], alias: ['cfm', 'cfc'],
mode: 'coldfusion' mode: 'coldfusion'
}, },
{
name: 'cpp',
label: 'C++',
alias: ['cc', 'cpp', 'cxx', 'hh', 'c++', 'cplusplus'],
mode: 'c_cpp'
},
{
name: 'csharp',
label: 'C#',
alias: ['cs', 'c#'],
mode: 'csharp'
},
{
name: 'css',
label: 'CSS',
alias: ['cascade', 'stylesheet'],
mode: 'css'
},
{ {
name: 'curly', name: 'curly',
label: 'Curly', label: 'Curly',
@@ -283,6 +226,12 @@ const modes = [
alias: ['opengl', 'shading'], alias: ['opengl', 'shading'],
mode: 'glsl' mode: 'glsl'
}, },
{
name: 'golang',
label: 'Go',
alias: ['go'],
mode: 'golang'
},
{ {
name: 'groovy', name: 'groovy',
label: 'Groovy', label: 'Groovy',
@@ -313,6 +262,12 @@ const modes = [
alias: ['hx', 'hxml'], alias: ['hx', 'hxml'],
mode: 'haxe' mode: 'haxe'
}, },
{
name: 'html',
label: 'HTML',
alias: [],
mode: 'html'
},
{ {
name: 'html_ruby', name: 'html_ruby',
label: 'HTML (Ruby)', label: 'HTML (Ruby)',
@@ -355,6 +310,18 @@ const modes = [
alias: [], alias: [],
mode: 'jade' mode: 'jade'
}, },
{
name: 'java',
label: 'Java',
alias: [],
mode: 'java'
},
{
name: 'javascript',
label: 'JavaScript',
alias: ['js', 'jscript', 'babel', 'es'],
mode: 'javascript'
},
{ {
name: 'json', name: 'json',
label: 'JSON', label: 'JSON',
@@ -451,6 +418,12 @@ const modes = [
alias: [], alias: [],
mode: 'makefile' mode: 'makefile'
}, },
{
name: 'markdown',
label: 'Markdown',
alias: ['md'],
mode: 'markdown'
},
{ {
name: 'mask', name: 'mask',
label: 'Mask', label: 'Mask',
@@ -529,6 +502,12 @@ const modes = [
alias: ['postgres'], alias: ['postgres'],
mode: 'pgsql' mode: 'pgsql'
}, },
{
name: 'php',
label: 'PHP',
alias: [],
mode: 'php'
},
{ {
name: 'powershell', name: 'powershell',
label: 'PowerShell', label: 'PowerShell',
@@ -559,6 +538,12 @@ const modes = [
alias: ['protocol', 'buffers'], alias: ['protocol', 'buffers'],
mode: 'protobuf' mode: 'protobuf'
}, },
{
name: 'python',
label: 'Python',
alias: ['py'],
mode: 'python'
},
{ {
name: 'r', name: 'r',
label: 'R', label: 'R',
@@ -571,6 +556,12 @@ const modes = [
alias: [], alias: [],
mode: 'rdoc' mode: 'rdoc'
}, },
{
name: 'ruby',
label: 'Ruby',
alias: ['rb'],
mode: 'ruby'
},
{ {
name: 'rust', name: 'rust',
label: 'Rust', label: 'Rust',
@@ -667,6 +658,12 @@ const modes = [
alias: [], alias: [],
mode: 'svg' mode: 'svg'
}, },
{
name: 'swift',
label: 'Swift',
alias: [],
mode: 'swift'
},
{ {
name: 'swig', name: 'swig',
label: 'SWIG', label: 'SWIG',

View File

@@ -1,6 +1,6 @@
import React, { PropTypes } from 'react' import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './NoteDetail.styl' import styles from './MarkdownNoteDetail.styl'
import MarkdownEditor from 'browser/components/MarkdownEditor' import MarkdownEditor from 'browser/components/MarkdownEditor'
import StarButton from './StarButton' import StarButton from './StarButton'
import TagSelect from './TagSelect' import TagSelect from './TagSelect'
@@ -13,7 +13,7 @@ const { remote } = electron
const Menu = remote.Menu const Menu = remote.Menu
const MenuItem = remote.MenuItem const MenuItem = remote.MenuItem
class NoteDetail extends React.Component { class MarkdownNoteDetail extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
@@ -217,7 +217,7 @@ class NoteDetail extends React.Component {
} }
} }
NoteDetail.propTypes = { MarkdownNoteDetail.propTypes = {
dispatch: PropTypes.func, dispatch: PropTypes.func,
repositories: PropTypes.array, repositories: PropTypes.array,
note: PropTypes.shape({ note: PropTypes.shape({
@@ -229,4 +229,4 @@ NoteDetail.propTypes = {
ignorePreviewPointerEvents: PropTypes.bool ignorePreviewPointerEvents: PropTypes.bool
} }
export default CSSModules(NoteDetail, styles) export default CSSModules(MarkdownNoteDetail, styles)

View File

@@ -2,7 +2,7 @@ $info-height = 75px
.root .root
absolute top bottom right absolute top bottom right
border-width 1px 0 border-width 0 0 1px
border-style solid border-style solid
border-color $ui-borderColor border-color $ui-borderColor

View File

@@ -0,0 +1,410 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './SnippetNoteDetail.styl'
import CodeEditor from 'browser/components/CodeEditor'
import StarButton from './StarButton'
import TagSelect from './TagSelect'
import FolderSelect from './FolderSelect'
import Commander from 'browser/main/lib/Commander'
import dataApi from 'browser/main/lib/dataApi'
import modes from 'browser/lib/modes'
const electron = require('electron')
const { remote } = electron
const Menu = remote.Menu
const MenuItem = remote.MenuItem
class SnippetNoteDetail extends React.Component {
constructor (props) {
super(props)
this.state = {
snippetIndex: 0,
note: Object.assign({
description: ''
}, props.note, {
snippets: props.note.snippets.map((snippet) => Object.assign({}, snippet))
})
}
}
componentDidMount () {
Commander.bind('note-detail', this)
}
componentWillUnmount () {
Commander.release(this)
}
fire (command) {
switch (command) {
case 'focus':
this.refs.description.focus()
}
}
componentWillReceiveProps (nextProps) {
if (nextProps.note.key !== this.props.note.key) {
this.setState({
snippetIndex: 0,
note: Object.assign({
description: ''
}, nextProps.note, {
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
})
}, () => {
let { snippets } = this.state.note
snippets.forEach((snippet, index) => {
this.refs['code-' + index].reload()
})
this.refs.tags.reset()
})
}
}
findTitle (value) {
let splitted = value.split('\n')
let title = null
for (let i = 0; i < splitted.length; i++) {
let trimmedLine = splitted[i].trim()
if (trimmedLine.match(/^# .+/)) {
title = trimmedLine.substring(1, trimmedLine.length).trim()
break
}
}
if (title == null) {
for (let i = 0; i < splitted.length; i++) {
let trimmedLine = splitted[i].trim()
if (trimmedLine.length > 0) {
title = trimmedLine
break
}
}
if (title == null) {
title = ''
}
}
return title
}
handleChange (e) {
let { note } = this.state
note.tags = this.refs.tags.value
note.description = this.refs.description.value
note.updatedAt = new Date()
note.title = this.findTitle(note.description)
this.setState({
note
}, () => {
this.save()
})
}
save () {
let { note, dispatch } = this.props
dispatch({
type: 'UPDATE_NOTE',
note: this.state.note
})
dataApi
.updateNote(note.storage, note.folder, note.key, this.state.note)
}
handleFolderChange (e) {
}
handleStarButtonClick (e) {
let { note } = this.state
note.isStarred = !note.isStarred
this.setState({
note
}, () => {
this.save()
})
}
exportAsFile () {
}
handleShareButtonClick (e) {
let menu = new Menu()
menu.append(new MenuItem({
label: 'Export as a File',
click: (e) => this.handlePreferencesButtonClick(e)
}))
menu.append(new MenuItem({
label: 'Export to Web',
disabled: true,
click: (e) => this.handlePreferencesButtonClick(e)
}))
menu.popup(remote.getCurrentWindow())
}
handleContextButtonClick (e) {
let menu = new Menu()
menu.append(new MenuItem({
label: 'Delete',
click: (e) => this.handlePreferencesButtonClick(e)
}))
menu.popup(remote.getCurrentWindow())
}
handleTabPlusButtonClick (e) {
let { note } = this.state
note.snippets = note.snippets.concat([{
name: '',
mode: 'text',
content: ''
}])
this.setState({
note
})
}
handleTabButtonClick (index) {
return (e) => {
this.setState({
snippetIndex: index
})
}
}
handleTabDeleteButtonClick (index) {
return (e) => {
if (this.state.note.snippets.length > 1) {
let snippets = this.state.note.snippets.slice()
snippets.splice(index, 1)
this.state.note.snippets = snippets
this.setState({
note: this.state.note
})
}
}
}
handleNameInputChange (index) {
return (e) => {
let snippets = this.state.note.snippets.slice()
snippets[index].name = e.target.value
this.state.note.snippets = snippets
this.setState({
note: this.state.note
}, () => {
this.save()
})
}
}
handleModeButtonClick (index) {
return (e) => {
let menu = new Menu()
modes.forEach((mode) => {
menu.append(new MenuItem({
label: mode.label,
click: (e) => this.handleModeOptionClick(index, mode.name)(e)
}))
})
menu.popup(remote.getCurrentWindow())
}
}
handleModeOptionClick (index, name) {
return (e) => {
let snippets = this.state.note.snippets.slice()
snippets[index].mode = name
this.state.note.snippets = snippets
this.setState({
note: this.state.note
}, () => {
this.save()
})
}
}
handleCodeChange (index) {
return (e) => {
let snippets = this.state.note.snippets.slice()
snippets[index].content = this.refs['code-' + index].value
this.state.note.snippets = snippets
this.setState({
note: this.state.note
}, () => {
this.save()
})
}
}
render () {
let { storages, config } = this.props
let { note } = this.state
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
let tabList = note.snippets.map((snippet, index) => {
let 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(index)(e)}
>
{snippet.name.trim().length > 0
? snippet.name
: <span styleName='tabList-item-unnamed'>
Unnamed
</span>
}
</button>
{note.snippets.length > 1 &&
<button styleName='tabList-item-deleteButton'
onClick={(e) => this.handleTabDeleteButtonClick(index)(e)}
>
<i className='fa fa-times'/>
</button>
}
</div>
})
let viewList = note.snippets.map((snippet, index) => {
let isActive = this.state.snippetIndex === index
let mode = snippet.mode === 'text'
? null
: modes.filter((mode) => mode.name === snippet.mode)[0]
return <div styleName='tabView'
key={index}
style={{zIndex: isActive ? 5 : 4}}
>
<div styleName='tabView-top'>
<input styleName='tabView-top-name'
placeholder='Filename including extensions...'
value={snippet.name}
onChange={(e) => this.handleNameInputChange(index)(e)}
/>
<button styleName='tabView-top-mode'
onClick={(e) => this.handleModeButtonClick(index)(e)}
>
{mode == null
? 'Select Syntax...'
: mode.label
}&nbsp;
<i className='fa fa-caret-down'/>
</button>
</div>
<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}
onChange={(e) => this.handleCodeChange(index)(e)}
ref={'code-' + index}
/>
</div>
})
return (
<div className='NoteDetail'
style={this.props.style}
styleName='root'
>
<div styleName='info'>
<div styleName='info-left'>
<div styleName='info-left-top'>
<FolderSelect styleName='info-left-top-folderSelect'
value={this.state.note.storage + '-' + this.state.note.folder}
ref='folder'
storages={storages}
onChange={(e) => this.handleFolderChange(e)}
/>
</div>
<div styleName='info-left-bottom'>
<TagSelect
styleName='info-left-bottom-tagSelect'
ref='tags'
value={this.state.note.tags}
onChange={(e) => this.handleChange(e)}
/>
</div>
</div>
<div styleName='info-right'>
<StarButton styleName='info-right-button'
onClick={(e) => this.handleStarButtonClick(e)}
isActive={note.isStarred}
/>
<button styleName='info-right-button'
onClick={(e) => this.handleShareButtonClick(e)}
>
<i className='fa fa-share-alt fa-fw'/>
</button>
<button styleName='info-right-button'
onClick={(e) => this.handleContextButtonClick(e)}
>
<i className='fa fa-ellipsis-v'/>
</button>
</div>
</div>
<div styleName='body'>
<div styleName='body-description'>
<textarea styleName='body-description-textarea'
style={{
fontFamily: config.preview.fontFamily,
fontSize: parseInt(config.preview.fontSize, 10)
}}
ref='description'
placeholder='Description...'
value={this.state.note.description}
onChange={(e) => this.handleChange(e)}
/>
</div>
<div styleName='tabList'>
{tabList}
<button styleName='tabList-plusButton'
onClick={(e) => this.handleTabPlusButtonClick(e)}
>
<i className='fa fa-plus'/>
</button>
</div>
{viewList}
</div>
</div>
)
}
}
SnippetNoteDetail.propTypes = {
dispatch: PropTypes.func,
repositories: PropTypes.array,
note: PropTypes.shape({
}),
style: PropTypes.shape({
left: PropTypes.number
}),
ignorePreviewPointerEvents: PropTypes.bool
}
export default CSSModules(SnippetNoteDetail, styles)

View File

@@ -0,0 +1,139 @@
$info-height = 75px
.root
absolute top bottom right
border-width 0 0 1px
border-style solid
border-color $ui-borderColor
.info
absolute top left right
height $info-height
border-bottom $ui-border
background-color $ui-backgroundColor
.info-left
float left
padding 0 5px
.info-left-top
height 40px
line-height 40px
.info-left-top-folderSelect
display inline-block
height 34px
width 200px
vertical-align middle
.info-left-bottom
height 30px
.info-left-bottom-tagSelect
height 30px
line-height 30px
.info-right
float right
.info-right-button
width 34px
height 34px
border-radius 17px
navButtonColor()
border $ui-border
font-size 14px
margin 8px 2px
padding 0
&:active
border-color $ui-button--focus-borderColor
&:hover .left-control-newPostButton-tooltip
display block
&:focus
border-color $ui-button--focus-borderColor
.body
absolute bottom left right
top $info-height
.body-description
absolute top left right
height 80px
border-bottom $ui-border
.body-description-textarea
display block
height 100%
width 100%
resize none
border none
padding 10px
.tabList
absolute left right
top 80px
height 30px
border-bottom $ui-border
display flex
background-color $ui-backgroundColor
.tabList-item
position relative
flex 1
border-right $ui-border
&:hover
.tabList-item-deleteButton
color $ui-inactive-text-color
&:hover
background-color darken($ui-backgroundColor, 15%)
&:active
color white
background-color $ui-active-color
.tabList-item--active
@extend .tabList-item
.tabList-item-button
border-color $brand-color
.tabList-item-button
width 100%
height 100%
navButtonColor()
border-left 4px solid transparent
.tabList-item-deleteButton
position absolute
top 5px
height 20px
right 5px
width 20px
text-align center
border none
padding 0
color transparent
background-color transparent
border-radius 2px
.tabList-plusButton
navButtonColor()
width 30px
.tabView
absolute left right bottom
top 110px
.tabView-top
absolute top left right
height 30px
border-bottom $ui-border
display flex
.tabView-top-name
flex 1
border none
padding 0 10px
font-size 14px
.tabView-top-mode
width 110px
padding 0
border none
border-left $ui-border
colorDefaultButton()
color $ui-inactive-text-color
&:hover
color $ui-text-color
.tabView-content
absolute left right bottom
top 30px

View File

@@ -2,7 +2,8 @@ import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
import styles from './Detail.styl' import styles from './Detail.styl'
import _ from 'lodash' import _ from 'lodash'
import NoteDetail from './NoteDetail' import MarkdownNoteDetail from './MarkdownNoteDetail'
import SnippetNoteDetail from './SnippetNoteDetail'
const electron = require('electron') const electron = require('electron')
@@ -13,7 +14,7 @@ class Detail extends React.Component {
} }
render () { render () {
let { storages, location, notes, config } = this.props let { location, notes, config } = this.props
let note = null let note = null
if (location.query.key != null) { if (location.query.key != null) {
let splitted = location.query.key.split('-') let splitted = location.query.key.split('-')
@@ -41,8 +42,23 @@ class Detail extends React.Component {
) )
} }
if (note.type === 'SNIPPET_NOTE') {
return ( return (
<NoteDetail <SnippetNoteDetail
note={note}
config={config}
{..._.pick(this.props, [
'dispatch',
'storages',
'style',
'ignorePreviewPointerEvents'
])}
/>
)
}
return (
<MarkdownNoteDetail
note={note} note={note}
config={config} config={config}
{..._.pick(this.props, [ {..._.pick(this.props, [

View File

@@ -54,9 +54,17 @@
.item-title .item-title
height 20px height 20px
line-height 20px line-height 20px
padding 0 5px padding 0 5px 0 0
font-weight bold font-weight bold
overflow ellipsis overflow ellipsis
color $ui-text-color
.item-title-icon
font-size 12px
color $ui-inactive-text-color
padding-right 3px
.item-title-empty
font-weight normal
color $ui-inactive-text-color
.item-tagList .item-tagList
height 30px height 30px

View File

@@ -236,7 +236,16 @@ class NoteList extends React.Component {
</div> </div>
<div styleName='item-title'>{note.title}</div> <div styleName='item-title'>
{note.type === 'SNIPPET_NOTE'
? <i styleName='item-title-icon' className='fa fa-fw fa-code'/>
: <i styleName='item-title-icon' className='fa fa-fw fa-file-text-o'/>
}
{note.title.trim().length > 0
? note.title
: <span styleName='item-title-empty'>Empty</span>
}
</div>
<div styleName='item-tagList'> <div styleName='item-tagList'>
<i styleName='item-tagList-icon' <i styleName='item-tagList-icon'

View File

@@ -8,7 +8,7 @@ class StorageItem extends React.Component {
super(props) super(props)
this.state = { this.state = {
isOpen: false isOpen: true
} }
} }

View File

@@ -322,18 +322,49 @@ function removeFolder (storageKey, folderKey) {
.then((storage) => storage.toJSON()) .then((storage) => storage.toJSON())
} }
function createNote (storageKey, folderKey, input) { function createMarkdownNote (storageKey, folderKey, input) {
let key = keygen() let key = keygen()
while (notes.some((note) => note.storage === storageKey && note.folder === folderKey && note.key === key)) { while (notes.some((note) => note.storage === storageKey && note.folder === folderKey && note.key === key)) {
key = keygen() key = keygen()
} }
let newNote = new Note(Object.assign({ let newNote = new Note(Object.assign({
type: 'MARKDOWN_NOTE',
tags: [], tags: [],
title: '', title: '',
content: '' content: ''
}, input, { }, input, {
type: 'MARKDOWN_NOTE',
storage: storageKey,
folder: folderKey,
key: key,
isStarred: false,
createdAt: new Date(),
updatedAt: new Date()
}))
notes.push(newNote)
return newNote
.save()
.then(() => newNote.toJSON())
}
function createSnippetNote (storageKey, folderKey, input) {
let key = keygen()
while (notes.some((note) => note.storage === storageKey && note.folder === folderKey && note.key === key)) {
key = keygen()
}
let newNote = new Note(Object.assign({
tags: [],
title: '',
description: '',
snippets: [{
name: '',
mode: 'text',
content: ''
}]
}, input, {
type: 'SNIPPET_NOTE',
storage: storageKey, storage: storageKey,
folder: folderKey, folder: folderKey,
key: key, key: key,
@@ -374,7 +405,8 @@ export default {
createFolder, createFolder,
updateFolder, updateFolder,
removeFolder, removeFolder,
createNote, createMarkdownNote,
createSnippetNote,
updateNote, updateNote,
removeNote removeNote
} }

View File

@@ -0,0 +1,128 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './NewNoteModal.styl'
import dataApi from 'browser/main/lib/dataApi'
import { hashHistory } from 'react-router'
class NewNoteModal extends React.Component {
constructor (props) {
super(props)
this.state = {
}
}
componentDidMount () {
this.refs.markdownButton.focus()
}
handleCloseButtonClick (e) {
this.props.close()
}
handleMarkdownNoteButtonClick (e) {
let { storage, folder, dispatch, location } = this.props
dataApi
.createMarkdownNote(storage, folder, {
title: '',
content: ''
})
.then((note) => {
dispatch({
type: 'CREATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: {key: note.uniqueKey}
})
this.props.close()
})
}
handleMarkdownNoteButtonKeyDown (e) {
if (e.keyCode === 9) {
e.preventDefault()
this.refs.snippetButton.focus()
}
}
handleSnippetNoteButtonClick (e) {
let { storage, folder, dispatch, location } = this.props
dataApi
.createSnippetNote(storage, folder, {
title: '',
description: '',
snippets: [{
name: '',
mode: 'text',
content: ''
}]
})
.then((note) => {
dispatch({
type: 'CREATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: {key: note.uniqueKey}
})
this.props.close()
})
}
handleSnippetNoteButtonKeyDown (e) {
if (e.keyCode === 9) {
e.preventDefault()
this.refs.markdownButton.focus()
}
}
render () {
return (
<div styleName='root'>
<div styleName='header'>
<div styleName='title'>New Note</div>
</div>
<button styleName='closeButton'
onClick={(e) => this.handleCloseButtonClick(e)}
>Close</button>
<div styleName='control'>
<button styleName='control-button'
onClick={(e) => this.handleMarkdownNoteButtonClick(e)}
onKeyDown={(e) => this.handleMarkdownNoteButtonKeyDown(e)}
ref='markdownButton'
>
<i styleName='control-button-icon'
className='fa fa-file-text-o'
/><br/>
<span styleName='control-button-label'>Markdown Note</span><br/>
<span styleName='control-button-description'>It is good for any type of documents. Check List, Code block and Latex block are available.</span>
</button>
<button styleName='control-button'
onClick={(e) => this.handleSnippetNoteButtonClick(e)}
onKeyDown={(e) => this.handleSnippetNoteButtonKeyDown(e)}
ref='snippetButton'
>
<i styleName='control-button-icon'
className='fa fa-code'
/><br/>
<span styleName='control-button-label'>Snippet Note</span><br/>
<span styleName='control-button-description'>This format is specialized on managing snippets like Gist. Multiple snippets can be grouped as a note.
</span>
</button>
</div>
<div styleName='description'><i className='fa fa-arrows-h'/> Tab to switch format</div>
</div>
)
}
}
NewNoteModal.propTypes = {
}
export default CSSModules(NewNoteModal, styles)

View File

@@ -0,0 +1,56 @@
.root
modal()
max-width 540px
overflow hidden
position relative
.header
height 50px
font-size 18px
line-height 50px
padding 0 15px
background-color $ui-backgroundColor
border-bottom solid 1px $ui-borderColor
color $ui-text-color
.closeButton
position absolute
top 10px
right 10px
height 30px
width 0 25px
border $ui-border
border-radius 2px
color $ui-text-color
colorDefaultButton()
.control
padding 25px 15px 15px
text-align center
.control-button
width 220px
height 220px
margin 0 15px
border $ui-border
border-radius 5px
color $ui-text-color
colorDefaultButton()
padding 10px
&:focus
colorPrimaryButton()
.control-button-icon
font-size 50px
margin-bottom 15px
.control-button-label
font-size 18px
line-height 32px
.control-button-description
font-size 12px
.description
color $ui-inactive-text-color
text-align center
margin-bottom 25px