diff --git a/browser/lib/Repository.js b/browser/lib/Repository.js index 3a72ec0c..9c583b4b 100644 --- a/browser/lib/Repository.js +++ b/browser/lib/Repository.js @@ -362,7 +362,7 @@ class Repository { if (_.isString(override.name) && override.name.trim().length > 0) targetFolder.name = override.name.trim() if (_.isString(override.color)) targetFolder.color = override.color - return this.updateJSON(this.json) + return this.saveJSON(this.json) .then(() => targetFolder) } @@ -380,7 +380,7 @@ class Repository { targetFolder = folders.splice(targetIndex, 1)[0] } - return this.updateJSON(null) + return this.saveJSON(null) .then(() => targetFolder) } diff --git a/browser/lib/consts.js b/browser/lib/consts.js index de75eaf1..400ffb78 100644 --- a/browser/lib/consts.js +++ b/browser/lib/consts.js @@ -8,6 +8,16 @@ const consts = { '#1FAD85', '#E10051', '#B013A4' + ], + FOLDER_COLOR_NAMES: [ + 'Cerulean Blue', + 'Dodger Blue', + 'Pizazz', + 'Confetti', + 'Emerald', + 'Mountain Meadow', + 'Razzmatazz', + 'Violet Eggplant' ] } diff --git a/browser/main/HomePage/SideNav/FolderItem.js b/browser/main/HomePage/SideNav/FolderItem.js new file mode 100644 index 00000000..c9164225 --- /dev/null +++ b/browser/main/HomePage/SideNav/FolderItem.js @@ -0,0 +1,212 @@ +import React, { PropTypes } from 'react' +import CSSModules from 'browser/lib/CSSModules' +import styles from './FolderItem.styl' +import store from 'browser/main/store' +import Repository from 'browser/lib/Repository' +import consts from 'browser/lib/consts' + +const electron = require('electron') +const { remote } = electron +const { Menu, MenuItem } = remote + +class FolderItem extends React.Component { + constructor (props) { + super(props) + + this.state = { + isEditing: false, + isUpdating: false, + name: props.folder.name + } + } + + handleColorButtonClick (color) { + return (e) => { + let { repository, folder } = this.props + this.setState({ + isUpdating: true + }, () => { + Repository.find(repository.key) + .then((repository) => { + console.log(repository) + return repository.updateFolder(folder.key, {color: color}) + }) + .then((folder) => { + store.dispatch({ + type: 'EDIT_FOLDER', + key: repository.key, + folder: folder + }) + this.setState({ + isEditing: false, + isUpdating: false + }) + }) + .catch((err) => { + console.error(err) + this.setState({ + isEditing: false, + isUpdating: false + }) + }) + }) + } + } + + handleContextButtonClick (e) { + if (this.state.isUpdating) { + return + } + + var menu = new Menu() + menu.append(new MenuItem({ + label: 'Rename', + click: () => this.handleRenameButtonClick(e) + })) + var colorMenu = new Menu() + consts.FOLDER_COLORS.forEach((color, index) => { + colorMenu.append(new MenuItem({ + label: consts.FOLDER_COLOR_NAMES[index], + click: (e) => this.handleColorButtonClick(color)(e) + })) + }) + menu.append(new MenuItem({ + label: 'Recolor', + submenu: colorMenu + })) + menu.append(new MenuItem({ type: 'separator' })) + menu.append(new MenuItem({ + label: 'Delete', + click: () => this.handleDeleteButtonClick(e) + })) + + menu.popup(remote.getCurrentWindow()) + } + + handleRenameButtonClick (e) { + this.setState({ + isEditing: true, + name: this.props.folder.name + }, () => { + this.refs.nameInput.focus() + }) + } + + handleDeleteButtonClick (e) { + let { repository, folder } = this.props + + this.setState({ + isUpdating: true + }, () => { + Repository.find(repository.key) + .then((repository) => { + console.log(repository) + return repository.removeFolder(folder.key) + }) + .then(() => { + store.dispatch({ + type: 'REMOVE_FOLDER', + repository: repository.key, + folder: folder.key + }) + }) + .catch((err) => { + console.error(err) + this.setState({ + isUpdating: false + }) + }) + }) + } + + renderIdle () { + let { folder } = this.props + + return ( +
+
+ {folder.name} +
+
+ +
+
+ ) + } + + handleNameInputChange (e) { + this.setState({ + name: e.target.value + }) + } + + handleNameInputBlur (e) { + let { folder, repository } = this.props + + this.setState({ + isUpdating: true + }, () => { + Repository.find(repository.key) + .then((repository) => { + console.log(repository) + return repository.updateFolder(folder.key, {name: this.state.name}) + }) + .then((folder) => { + store.dispatch({ + type: 'EDIT_FOLDER', + key: repository.key, + folder: folder + }) + this.setState({ + isEditing: false, + isUpdating: false + }) + }) + .catch((err) => { + console.error(err) + this.setState({ + isEditing: false, + isUpdating: false + }) + }) + }) + } + + renderEdit () { + return ( +
this.handleContextButtonClick(e)} + > + this.handleNameInputChange(e)} + onBlur={(e) => this.handleNameInputBlur(e)} + disabled={this.state.isUpdating} + /> +
+ ) + } + + render () { + return this.state.isEditing ? this.renderEdit() : this.renderIdle() + } +} + +FolderItem.propTypes = { + folder: PropTypes.shape({ + name: PropTypes.string, + color: PropTypes.string + }), + repository: PropTypes.shape({ + key: PropTypes.string + }) +} + +export default CSSModules(FolderItem, styles) diff --git a/browser/main/HomePage/SideNav/FolderItem.styl b/browser/main/HomePage/SideNav/FolderItem.styl new file mode 100644 index 00000000..817b975e --- /dev/null +++ b/browser/main/HomePage/SideNav/FolderItem.styl @@ -0,0 +1,56 @@ +.root + height 33px + width 100% + position relative + cursor pointer + &:hover + background-color alpha(white, 0.1) + .control + opacity 1 + +.label + position absolute + left 0 + top 0 + bottom 0 + right 48px + padding-left 20px + line-height 33px + color white + +.control + opacity 0 + position absolute + top 0 + bottom 0 + right 5px + width 24px + +.control-button + width 24px + height 24px + margin-top 4.5px + border none + border-radius 5px + background-color transparent + color $nav-inactive-color + &:hover + color white + background-color alpha(white, 0.1) + &:active + color white + background-color $brand-color + +.nameInput + absolute top bottom + left 10px + right 10px + height 33px + padding 0 10px + border-radius 5px + border solid 1px $nav-border-color + outline none + &:focus + border-color $focus-border-color + &:disabled + background-color $disabled-input-background diff --git a/browser/main/HomePage/SideNav/RepositorySection.js b/browser/main/HomePage/SideNav/RepositorySection.js index 6ace6531..294e2a99 100644 --- a/browser/main/HomePage/SideNav/RepositorySection.js +++ b/browser/main/HomePage/SideNav/RepositorySection.js @@ -2,11 +2,11 @@ import React, { PropTypes } from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './RepositorySection.styl' import Repository from 'browser/lib/Repository' +import FolderItem from './FolderItem' const electron = require('electron') const { remote } = electron -const Menu = remote.Menu -const MenuItem = remote.MenuItem +const { Menu, MenuItem } = remote class RepositorySection extends React.Component { constructor (props) { @@ -124,19 +124,11 @@ class RepositorySection extends React.Component { let folderElements = repository.folders.map((folder) => { return ( -
-
- {folder.name} -
-
- -
-
+ folder={folder} + repository={repository} + /> ) }) diff --git a/browser/main/HomePage/SideNav/RepositorySection.styl b/browser/main/HomePage/SideNav/RepositorySection.styl index 9bc95ca4..8230fc3e 100644 --- a/browser/main/HomePage/SideNav/RepositorySection.styl +++ b/browser/main/HomePage/SideNav/RepositorySection.styl @@ -50,49 +50,6 @@ @extend .header-control-button opacity 1 -.folder - height 33px - width 100% - position relative - cursor pointer - &:hover - background-color alpha(white, 0.1) - .folder-control - opacity 1 - -.folder-label - position absolute - left 0 - top 0 - bottom 0 - right 48px - padding-left 20px - line-height 33px - color white - -.folder-control - opacity 0 - position absolute - top 0 - bottom 0 - right 5px - width 24px - -.folder-control-button - width 24px - height 24px - margin-top 4.5px - border none - border-radius 5px - background-color transparent - color $nav-inactive-color - &:hover - color white - background-color alpha(white, 0.1) - &:active - color white - background-color $brand-color - .newFolderForm width 100% padding 0 15px diff --git a/browser/main/HomePage/SideNav/SideNav.styl b/browser/main/HomePage/SideNav/SideNav.styl index 1b67b6e8..65bb6b37 100644 --- a/browser/main/HomePage/SideNav/SideNav.styl +++ b/browser/main/HomePage/SideNav/SideNav.styl @@ -47,8 +47,8 @@ .repositoryList-empty padding 0 10px - height 44px - line-height 44px + margin-top 15px + line-height 24px color $nav-inactive-color .navToggle diff --git a/browser/main/HomePage/SideNav/index.js b/browser/main/HomePage/SideNav/index.js index 171b1f0b..4d76847c 100644 --- a/browser/main/HomePage/SideNav/index.js +++ b/browser/main/HomePage/SideNav/index.js @@ -72,7 +72,7 @@ class SideNav extends React.Component {
{repositories.length > 0 ? repositorieElements : ( -
No repository mount
+
No repository mount.
)}
diff --git a/browser/main/store.js b/browser/main/store.js index adabd37a..109d2dfd 100644 --- a/browser/main/store.js +++ b/browser/main/store.js @@ -65,6 +65,44 @@ function repositories (state = initialRepositories, action) { targetRepo.folders.splice(targetFolderIndex, 1, action.folder) } + return repos + } + case 'EDIT_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 + } + /** + * Remove a folder from the repository + * { + * type: 'REMOVE_FOLDER', + * repository: repositoryKey, + * folder: folderKey + * } + */ + case 'REMOVE_FOLDER': + { + let repos = state.slice() + let targetRepo = _.find(repos, {key: action.repository}) + + if (targetRepo == null) return state + + let targetFolderIndex = _.findIndex(targetRepo.folders, {key: action.folder}) + if (targetFolderIndex > -1) { + targetRepo.folders.splice(targetFolderIndex, 1) + } + return repos } } diff --git a/browser/styles/main/modal/Preferences.styl b/browser/styles/main/modal/Preferences.styl index 0bb32d97..9239f571 100644 --- a/browser/styles/main/modal/Preferences.styl +++ b/browser/styles/main/modal/Preferences.styl @@ -31,8 +31,6 @@ iptFocusBorderColor = #369DCD margin-right 15px border none border-radius 5px - &:hover - background-color lighten(closeBtnBgColor, 10%) &>.nav absolute left bottom top 50px @@ -158,8 +156,6 @@ iptFocusBorderColor = #369DCD height 33px padding 0 15px font-size 14px - &:hover - background-color lighten(brandColor, 10%) .alert float right width 250px @@ -188,441 +184,3 @@ iptFocusBorderColor = #369DCD &.AppSettingTab .description marked() - &.TeamSettingTab - .header - border-bottom 1px solid borderColor - padding 10px - font-size 18px - color brandColor - line-height 33px - .teamSelect - border 1px solid borderColor - height 33px - width 200px - margin 0 10px - outline none - font-size 14px - &:focus - border-color iptFocusBorderColor - .teamDeleteConfirm - - label - line-height 33px - font-size 14px - .teamDelete - label - line-height 33px - font-size 18px - color brandColor - .teamDelete, .teamDeleteConfirm - padding 15px 20px 15px 15px - button - background-color white - height 33px - font-size 14px - padding 0 15px - border 1px solid borderColor - float right - margin 0 5px - border-radius 5px - &:hover - background-color darken(white, 10%) - button.deleteBtn - background-color brandColor - border none - color white - &:hover - background-color lighten(brandColor, 10%) - &.MemberSettingTab - &>.header - border-bottom 1px solid borderColor - padding 10px - font-size 18px - color brandColor - line-height 33px - .teamSelect - border 1px solid borderColor - height 33px - width 200px - margin 0 10px - outline none - font-size 14px - &:focus - border-color iptFocusBorderColor - .membersTableSection - .addMember - clearfix() - padding 10px - .addMemberLabel - font-size 14px - line-height 33px - float left - .addMemberControl - width 330px - float left - margin-left 25px - .Select - display block - margin 0 - float left - width 280px - height 33px - font-size 14px - border none - line-height 33px - background-color transparent - outline none - &.is-focus - .Select-control - border-color iptFocusBorderColor - .Select-control - height 33px - line-height 33px - padding 0 0 0 15px - border-radius 5px 0 0 5px - border 1px solid borderColor - border-right none - .Select-placeholder - padding 0 0 0 15px - .Seleect-arrow - top 21px - .Select-clear - padding 0 10px - .Select-noresults, .Select-option - line-height 33px - padding 0 0 0 15px - button - font-weight 400 - height 33px - cursor pointer - margin 0 - padding 0 - width 50px - float right - border none - background-color brandColor - border-top-right-radius 5px - border-bottom-right-radius 5px - color white - font-size 14px - .memberList - &>.header - clearfix() - &>.userName - float left - &>.role - float left - &>.control - float right - &>li - &.edit - .colDescription - font-size 14px - line-height 33px - padding-left 15px - float left - strong - font-size 16px - color brandColor - .colDeleteConfirm - float right - margin-right 15px - button - border none - height 30px - width 60px - margin-top 1.5px - font-size 14px - background-color transparent - color stripBtnColor - &:hover - color stripHoverBtnColor - &:disabled - color lighten(stripBtnColor, 10%) - cursor not-allowed - &.primary - color brandColor - &:hover - color lighten(brandColor, 10%) - - border-bottom 1px solid borderColor - height 44px - padding 0 25px - width 420px - margin 0 auto - clearfix() - &:nth-last-child(1) - border-bottom-color transparent - .colUserName - float left - width 250px - clearfix() - .userPhoto - width 30px - height 30px - float left - margin-top 7px - margin-right 15px - border-radius 15px - .userInfo - float left - margin-top 7px - width 205px - .userName - font-size 16px - margin-bottom 2px - overflow ellipsis - .userEmail - font-size 12px - overflow ellipsis - .colRole - float left - width 75px - .userRole - height 30px - background-color transparent - border 1px solid transparent - margin-top 7px - margin-right 35px - outline none - cursor pointer - &:hover - border-color borderColor - &:focus - border-color iptFocusBorderColor - &:disabled - border-color transparent - cursor not-allowed - .colDelete - width 45px - float right - text-align center - button.deleteButton - border none - height 30px - width 30px - margin-top 7px - background-color transparent - color stripBtnColor - &:hover - color stripHoverBtnColor - &:disabled - color lighten(stripBtnColor, 10%) - cursor not-allowed - &.header - .colRole, .colDelete - text-align center - .colUserName, .colRole, .colDelete - line-height 44px - &.FolderSettingTab - &>.header - border-bottom 1px solid borderColor - padding 10px - font-size 18px - color brandColor - line-height 33px - .teamSelect - border 1px solid borderColor - height 33px - width 200px - margin 0 10px - outline none - font-size 14px - &:focus - border-color iptFocusBorderColor - .section - .folderTable - width 420px - margin 15px auto - &>div - border-bottom 1px solid borderColor - clearfix() - height 43px - line-height 33px - padding 5px 0 - &:last-child - border-color transparent - .folderColor - float left - margin-left 10px - text-align center - width 44px - .folderName - float left - width 175px - overflow ellipsis - .folderControl - float right - width 125px - text-align center - &.folderHeader - .folderName - padding-left 25px - &.newFolder - .alert - display block - color infoTextColor - background-color infoBackgroundColor - font-size 14px - padding 15px 15px - width 330px - border-radius 5px - margin 0 auto - &.error - color errorTextColor - background-color errorBackgroundColor - .folderName input - height 33px - border 1px solid transparent - border-radius 5px - padding 0 10px - font-size 14px - outline none - width 150px - overflow ellipsis - &:hover - border-color borderColor - &:focus - border-color iptFocusBorderColor - .folderPublic select - height 33px - border 1px solid transparent - background-color white - outline none - display block - margin 0 auto - font-size 14px - &:hover - border-color borderColor - &:focus - border-color iptFocusBorderColor - .folderControl - button - border none - height 30px - margin-top 1.5px - font-size 14px - background-color transparent - color brandColor - &:hover - color lighten(brandColor, 10%) - &.FolderRow - .sortBtns - float left - display block - height 30px - width 30px - margin-top 1.5px - position absolute - button - absolute left - background-color transparent - border none - height 15px - padding 0 - margin 0 - color stripBtnColor - &:first-child - top 0 - &:last-child - top 15px - &:hover - color stripHoverBtnColor - &:disabled - color lighten(stripBtnColor, 10%) - cursor not-allowed - .folderName input - height 33px - border 1px solid borderColor - border-radius 5px - padding 0 10px - font-size 14px - outline none - width 150px - &:focus - border-color iptFocusBorderColor - .folderColor - .select - height 33px - width 33px - border 1px solid borderColor - background-color white - outline none - display block - margin 0 auto - font-size 14px - border-radius 5px - &:focus - border-color iptFocusBorderColor - .options - position absolute - background-color white - text-align left - border 1px solid borderColor - border-radius 5px - padding 0 5px 5px - margin-left 5px - margin-top -34px - clearfix() - .label - margin-left 5px - line-height 22px - font-size 12px - button - float left - border none - width 33px - height 33px - margin-right 5px - border 1px solid transparent - line-height 29px - overflow hidden - border-radius 5px - background-color transparent - outline none - transition 0.1s - &:hover - border-color borderColor - &.active - border-color iptFocusBorderColor - .FolderMark - transform scale(1.4) - .folderControl - button - border none - height 30px - width 30px - margin-top 1.5px - font-size 14px - background-color transparent - color stripBtnColor - &:hover - color stripHoverBtnColor - &:disabled - color lighten(stripBtnColor, 10%) - cursor not-allowed - &.edit - .folderControl - button - width 60px - &.primary - color brandColor - &:hover - color lighten(brandColor, 10%) - &.delete - .folderDeleteLabel - float left - height 33px - width 250px - padding-left 15px - overflow ellipsis - strong - font-size 16px - color brandColor - .folderControl - button - width 60px - &.primary - color brandColor - &:hover - color lighten(brandColor, 10%)