1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

add Folder

This commit is contained in:
Rokt33r
2016-05-03 22:38:54 +09:00
parent df51e6d429
commit dcf773fd88
7 changed files with 197 additions and 40 deletions

View File

@@ -3,6 +3,7 @@ const fs = require('fs')
const path = require('path')
const CSON = require('season')
const _ = require('lodash')
const consts = require('browser/lib/consts')
let repositories = []
@@ -19,10 +20,10 @@ let repositories = []
* .then(() => repo.load())
*
* // Update Cached
* repo.updateCache({name: 'renamed'})
* repo.saveCache({name: 'renamed'})
*
* // Update JSON
* repo.updateJSON({author: 'Other user'})
* repo.saveJSON({author: 'Other user'})
*
* // Remove repository
* repo.unmount()
@@ -142,6 +143,7 @@ class Repository {
return Promise.all([resolveDataDirectory, resolveBoostrepoJSON])
.then((data) => {
this.json = data[1]
return true
})
}
@@ -167,6 +169,7 @@ class Repository {
return Promise.all(notes)
.then((notes) => {
this.notes = notes
return true
})
}
@@ -178,10 +181,11 @@ class Repository {
return this.getData()
})
.catch(function handleError (err) {
.catch((err) => {
this.status = 'ERROR'
this.error = err
return err
console.error(err)
return this
})
}
@@ -253,14 +257,23 @@ class Repository {
* @return {Promise} all data of a repository
*/
getData () {
if (this.status !== 'READY') {
function carbonCopy (obj) {
return JSON.parse(JSON.stringify(obj))
}
if (this.status === 'IDLE') {
return this.load()
}
return Promise.resolve(Object.assign({}, this.json, this.cached, {
if (this.status === 'ERROR') {
return Promise.resolve(carbonCopy(Object.assign({}, this.json, this.cached, {
status: this.status
})))
}
return Promise.resolve(carbonCopy(Object.assign({}, this.json, this.cached, {
status: this.status,
notes: this.notes
}))
})))
}
/**
@@ -287,11 +300,13 @@ class Repository {
*/
saveJSON (newJSON) {
let jsonPath = path.join(this.cached.path, 'boostrepo.json')
Object.assign(this.json, newJSON)
if (_.isObject(newJSON)) {
Object.assign(this.json, newJSON)
}
return new Promise(function (resolve, reject) {
return new Promise((resolve, reject) => {
CSON
.writeFile(jsonPath, this.json, function (err) {
.writeFile(jsonPath, this.json, (err) => {
if (err != null) return reject(err)
resolve(this.json)
})
@@ -316,9 +331,9 @@ class Repository {
newFolder = _.pick(newFolder, ['color', 'name'])
if (!_.isString(newFolder.name) || newFolder.name.trim().length === 0) newFolder.name = 'unnamed'
else newFolder.name = newFolder.trim()
else newFolder.name = newFolder.name.trim()
if (!_.isString(newFolder.color)) newFolder.color = ''
if (!_.isString(newFolder.color)) newFolder.color = this.constructor.randomColor()
newFolder.key = keygen()
while (_.findIndex(folders, {key: newFolder.key}) > -1) {
@@ -327,7 +342,7 @@ class Repository {
folders.push(newFolder)
return this.updateJSON(this.json)
return this.saveJSON(this.json)
.then(() => newFolder)
}
@@ -451,6 +466,10 @@ class Repository {
return Promise.resolve(this.notes)
}
/**
* Static Methods
*/
static generateDefaultJSON (override) {
return Object.assign({
name: 'unnamed',
@@ -458,7 +477,7 @@ class Repository {
folders: [{
key: keygen(),
name: 'general',
color: 'green'
color: this.randomColor()
}]
}, override)
}
@@ -474,21 +493,28 @@ class Repository {
* @return {Promise} resolving parsed data
*/
static resolveJSON (targetPath, defaultOverrides) {
return new Promise(function checkIfExists (resolve, reject) {
// If JSON doesn't exist, make a new one.
if (CSON.resolve(targetPath) == null) {
let newRepoJSON = this.constructor.generateDefaultJSON(defaultOverrides)
CSON.writeFile(targetPath, newRepoJSON, function (err) {
return (new Promise((resolve, reject) => {
let writeNew = () => {
let newRepoJSON = this.generateDefaultJSON(defaultOverrides)
CSON.writeFile(targetPath, newRepoJSON, (err) => {
if (err != null) return reject(err)
resolve(newRepoJSON)
})
}
// If JSON doesn't exist, make a new one.
if (CSON.resolve(targetPath) == null) {
writeNew()
} else {
CSON.readFile(targetPath, function (err, obj) {
CSON.readFile(targetPath, (err, obj) => {
if (err != null) return reject(err)
resolve(obj)
if (obj == null) {
writeNew()
} else {
resolve(obj)
}
})
}
})
}))
}
/**
@@ -553,7 +579,6 @@ class Repository {
throw new Error('Data is corrupted. it must be an array.')
}
} catch (err) {
console.log(err)
data = []
this.saveAllCached(data)
}
@@ -582,6 +607,10 @@ class Repository {
let repository = _.find(repositories, {cached: {key: repoKey}})
return Promise.resolve(repository)
}
static randomColor () {
return consts.FOLDER_COLORS[Math.floor(Math.random() * consts.FOLDER_COLORS.length)]
}
}
export default Repository

14
browser/lib/consts.js Normal file
View File

@@ -0,0 +1,14 @@
const consts = {
FOLDER_COLORS: [
'#3460C7',
'#2BA5F7',
'#FF8E00',
'#E8D252',
'#3FD941',
'#1FAD85',
'#E10051',
'#B013A4'
]
}
module.exports = consts

View File

@@ -9,10 +9,28 @@ const Menu = remote.Menu
const MenuItem = remote.MenuItem
class RepositorySection extends React.Component {
constructor (props) {
super(props)
this.state = {
isOpen: true,
isCreatingFolder: false,
isSaving: false,
newFolder: {
name: ''
}
}
}
getRepository () {
let { repository } = this.props
return Repository.find(repository.key)
}
handleUnlinkButtonClick () {
let { dispatch, repository } = this.props
Repository.find(repository.key)
this.getRepository()
.then((repositoryInstance) => {
return repositoryInstance.unmount()
})
@@ -25,16 +43,16 @@ class RepositorySection extends React.Component {
}
handleToggleButtonClick (e) {
this.setState({
isOpen: !this.state.isOpen
})
}
handleContextButtonClick (e) {
var menu = new Menu()
menu.append(new MenuItem({
label: 'New Note'
}))
menu.append(new MenuItem({
label: 'New Folder'
label: 'New Folder',
click: () => this.handleNewFolderButtonClick()
}))
menu.append(new MenuItem({ type: 'separator' }))
menu.append(new MenuItem({
@@ -45,17 +63,62 @@ class RepositorySection extends React.Component {
menu.popup(remote.getCurrentWindow())
}
handleNewFolderButtonClick (e) {
this.setState({
isCreatingFolder: true,
newFolder: {
name: 'New Folder'
}
}, () => {
this.refs.nameInput.select()
this.refs.nameInput.focus()
})
}
handleNewFolderFormChange (e) {
let newFolder = this.state.newFolder
newFolder.name = this.refs.nameInput.value
this.setState({
newFolder
})
}
handleNameInputBlur (e) {
let { dispatch, repository } = this.props
this.getRepository()
.then((repositoryInstance) => {
return repositoryInstance.addFolder({
name: this.state.newFolder.name
})
})
.then((folder) => {
console.log(folder)
dispatch({
type: 'ADD_FOLDER',
key: repository.key,
folder: folder
})
this.setState({
isCreatingFolder: false,
isSaving: false
})
})
}
render () {
let { repository } = this.props
let folderElements = repository.folders.map((folder) => {
return (
<div
key={folder.name}
key={folder.key}
styleName='folder'
>
<div styleName='folder-label'>
<i className='fa fa-cube'/> {folder.name}
<i className='fa fa-cube' style={{color: folder.color}}/> {folder.name}
</div>
<div styleName='folder-control'>
<button styleName='folder-control-button'>
@@ -66,6 +129,10 @@ class RepositorySection extends React.Component {
)
})
let toggleButtonIconClassName = this.state.isOpen
? 'fa fa-minus'
: 'fa fa-plus'
return (
<div
className='RepositorySection'
@@ -85,17 +152,29 @@ class RepositorySection extends React.Component {
<button styleName='header-control-button'
onClick={(e) => this.handleToggleButtonClick(e)}
>
<i className='fa fa-angle-down'/>
<i className={toggleButtonIconClassName}/>
</button>
</div>
</div>
{this.state.isOpen && <div>
{folderElements}
{folderElements}
<button styleName='newFolderButton'
>
<i className='fa fa-plus'/> New Folder
</button>
{this.state.isCreatingFolder
? <div styleName='newFolderForm'>
<input styleName='newFolderForm-nameInput'
ref='nameInput'
value={this.state.newFolder.name}
onChange={(e) => this.handleNewFolderFormChange(e)}
onBlur={(e) => this.handleNameInputBlur(e)}
/>
</div>
: <button styleName='newFolderButton'
onClick={(e) => this.handleNewFolderButtonClick(e)}
>
<i className='fa fa-plus'/> New Folder
</button>
}
</div>}
</div>
)
}

View File

@@ -83,6 +83,21 @@
color white
background-color $brand-color
.newFolderForm
width 100%
padding 0 15px
height 33px
.newFolderForm-nameInput
width 100%
height 33px
padding 0 10px
border-radius 5px
border solid 1px $nav-border-color
outline none
&:focus
border-color $focus-border-color
.newFolderButton
height 33px
width 100%

View File

@@ -1,9 +1,8 @@
import React, { PropTypes } from 'react'
import CSSModules from 'browser/lib/CSSModules'
import styles from './SideNav.styl'
import { openModal, isModalOpen } from 'browser/lib/modal'
import { openModal } from 'browser/lib/modal'
import Preferences from '../../modal/Preferences'
import CreateNewFolder from '../../modal/CreateNewFolder'
import RepositorySection from './RepositorySection'
import NewRepositoryModal from '../../modal/NewRepositoryModal'

View File

@@ -35,16 +35,36 @@ function repositories (state = initialRepositories, action) {
case 'ADD_REPOSITORY':
{
let repos = state.slice()
repos.push(action.repository)
return repos
}
case 'REMOVE_REPOSITORY':
{
let repos = state.slice()
let targetIndex = _.findIndex(repos, {key: action.key})
if (targetIndex > -1) {
repos.splice(targetIndex, 1)
}
return repos
}
case 'ADD_FOLDER':
{
let repos = state.slice()
let targetRepo = _.find(repos, {key: action.key})
if (targetRepo == null) return state
let targetFolderIndex = _.findIndex(targetRepo.folders, {key: action.folder.key})
if (targetFolderIndex < 0) {
targetRepo.folders.push(action.folder)
} else {
targetRepo.folders.splice(targetFolderIndex, 1, action.folder)
}
return repos
}
}

View File

@@ -9,6 +9,7 @@ $danger-lighten-color = #FFE5E6
*/
$border-color = #D0D0D0
$active-border-color = #369DCD
$focus-border-color = #369DCD
$default-border = solid 1px $border-color
$active-border = solid 1px $active-border-color