1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-17 19:51:42 +00:00

Merge pull request #922 from sosukesuzuki/feature-tag-area

Feature tag area
This commit is contained in:
Sota Sugiura
2017-10-14 16:58:28 +09:00
committed by GitHub
10 changed files with 271 additions and 63 deletions

View File

@@ -0,0 +1,29 @@
/**
* @fileoverview Micro component for toggle SideNav
*/
import React, { PropTypes } from 'react'
import styles from './NavToggleButton.styl'
import CSSModules from 'browser/lib/CSSModules'
/**
* @param {boolean} isFolded
* @param {Function} handleToggleButtonClick
*/
const NavToggleButton = ({isFolded, handleToggleButtonClick}) => (
<button styleName='navToggle'
onClick={(e) => handleToggleButtonClick(e)}
>
{isFolded
? <i className='fa fa-angle-double-right' />
: <i className='fa fa-angle-double-left' />
}
</button>
)
NavToggleButton.propTypes = {
isFolded: PropTypes.bool.isRequired,
handleToggleButtonClick: PropTypes.func.isRequired
}
export default CSSModules(NavToggleButton, styles)

View File

@@ -0,0 +1,19 @@
.navToggle
navButtonColor()
display block
position absolute
right 5px
bottom 5px
border-radius 16.5px
height 34px
width 34px
line-height 32px
padding 0
body[data-theme="dark"]
.navToggle
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
transition 0.15s
color $ui-dark-text-color

View File

@@ -0,0 +1,23 @@
/**
* @fileoverview Micro component for showing StorageList
*/
import React, { PropTypes } from 'react'
import styles from './StorgaeList.styl'
import CSSModules from 'browser/lib/CSSModules'
/**
* @param {Array} storgaeList
*/
const StorageList = ({storageList}) => (
<div styleName='storageList'>
{storageList.length > 0 ? storageList : (
<div styleName='storgaeList-empty'>No storage mount.</div>
)}
</div>
)
StorageList.propTypes = {
storgaeList: PropTypes.arrayOf(PropTypes.element).isRequired
}
export default CSSModules(StorageList, styles)

View File

@@ -0,0 +1,20 @@
.storageList
absolute left right
bottom 37px
top 160px
overflow-y auto
.storageList-empty
padding 0 10px
margin-top 15px
line-height 24px
color $ui-inactive-text-color
body[data-theme="dark"]
.storageList-empty
color $ui-dark-inactive-text-color
.root-folded
.storageList-empty
white-space nowrap
transform rotate(90deg)

View File

@@ -0,0 +1,27 @@
/**
* @fileoverview Micro component for showing TagList.
*/
import React, { PropTypes } from 'react'
import styles from './TagListItem.styl'
import CSSModules from 'browser/lib/CSSModules'
/**
* @param {string} name
* @param {Function} handleClickTagListItem
* @param {bool} isActive
*/
const TagListItem = ({name, handleClickTagListItem, isActive}) => (
<button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}>
<span styleName='tagList-item-name'>
{`# ${name}`}
</span>
</button>
)
TagListItem.propTypes = {
name: PropTypes.string.isRequired,
handleClickTagListItem: PropTypes.func.isRequired
}
export default CSSModules(TagListItem, styles)

View File

@@ -0,0 +1,45 @@
.tagList-item
display flex
width 100%
height 26px
background-color transparent
color $ui-inactive-text-color
padding 0
margin-bottom 5px
text-align left
border none
overflow ellipsis
font-size 12px
&:first-child
margin-top 0
&:hover
color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%)
transition background-color 0.15s
&:active
color $ui-text-color
background-color $ui-button--active-backgroundColor
.tagList-item-active
background-color $ui-button--active-backgroundColor
display flex
width 100%
height 26px
padding 0
margin-bottom 5px
text-align left
border none
overflow ellipsis
font-size 12px
.tagList-item-name
display block
flex 1
padding 0 25px
height 26px
line-height 26px
border-width 0 0 0 2px
border-style solid
border-color transparent
overflow hidden
text-overflow ellipsis

View File

@@ -229,7 +229,7 @@ class NoteList extends React.Component {
let { data, params, location } = this.props let { data, params, location } = this.props
let { router } = this.context let { router } = this.context
if (location.pathname.match(/\/home/)) { if (location.pathname.match(/\/home/) || location.pathname.match(/\alltags/)) {
const allNotes = data.noteMap.map((note) => note) const allNotes = data.noteMap.map((note) => note)
this.contextNotes = allNotes this.contextNotes = allNotes
return allNotes return allNotes
@@ -255,6 +255,14 @@ class NoteList extends React.Component {
return trashedNotes return trashedNotes
} }
if (location.pathname.match(/\/tags/)) {
return data.noteMap.map(note => {
return note
}).filter(note => {
return note.tags.includes(params.tagname)
})
}
return this.getContextNotes() return this.getContextNotes()
} }

View File

@@ -13,48 +13,33 @@
height $topBar-height height $topBar-height
padding 0 15px padding 0 15px
font-size 12px font-size 12px
width 100% width 33%
text-align left text-align center
&:hover &:hover
color $ui-text-color color $ui-text-color
&:active, &:active:hover &:active, &:active:hover
color $ui-text-color color $ui-text-color
background-color alpha($ui-button--active-backgroundColor, 20%) background-color alpha($ui-button--active-backgroundColor, 20%)
.active-button
background-color $ui-button--active-color
.non-active-button
background-color $ui-button-color
.top-menu-label .top-menu-label
margin-left 5px margin-left 5px
overflow ellipsis overflow ellipsis
.storageList .tagList
absolute left right absolute left right
bottom 37px bottom 37px
top 160px top 80px
overflow-y auto overflow-y auto
.storageList-empty
padding 0 10px
margin-top 15px
line-height 24px
color $ui-inactive-text-color
.navToggle
navButtonColor()
display block
position absolute
right 5px
bottom 5px
border-radius 16.5px
height 34px
width 34px
line-height 32px
padding 0
.root--folded .root--folded
@extend .root @extend .root
width 44px width 44px
.storageList-empty
white-space nowrap
transform rotate(90deg)
.top-menu .top-menu
width 44px - 1 width 44px - 1
text-align center text-align center
@@ -119,12 +104,3 @@ body[data-theme="dark"]
background-color alpha($ui-dark-button--active-backgroundColor, 20%) background-color alpha($ui-dark-button--active-backgroundColor, 20%)
&:hover &:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%) background-color alpha($ui-dark-button--active-backgroundColor, 20%)
.storageList-empty
color $ui-dark-inactive-text-color
.navToggle
&:hover
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
transition 0.15s
color $ui-dark-text-color

View File

@@ -5,7 +5,10 @@ import { openModal } from 'browser/main/lib/modal'
import PreferencesModal from '../modals/PreferencesModal' import PreferencesModal from '../modals/PreferencesModal'
import ConfigManager from 'browser/main/lib/ConfigManager' import ConfigManager from 'browser/main/lib/ConfigManager'
import StorageItem from './StorageItem' import StorageItem from './StorageItem'
import TagListItem from 'browser/components/TagListItem'
import SideNavFilter from 'browser/components/SideNavFilter' import SideNavFilter from 'browser/components/SideNavFilter'
import StorageList from 'browser/components/StorageList'
import NavToggleButton from 'browser/components/NavToggleButton'
class SideNav extends React.Component { class SideNav extends React.Component {
// TODO: should not use electron stuff v0.7 // TODO: should not use electron stuff v0.7
@@ -38,13 +41,85 @@ class SideNav extends React.Component {
router.push('/trashed') router.push('/trashed')
} }
handleSwitchFoldersButtonClick () {
const { router } = this.context
router.push('/home')
}
handleSwitchTagsButtonClick () {
const { router } = this.context
router.push('/alltags')
}
SideNavComponent (isFolded, storageList) {
let { location, data } = this.props
const isHomeActive = !!location.pathname.match(/^\/home$/)
const isStarredActive = !!location.pathname.match(/^\/starred$/)
const isTrashedActive = !!location.pathname.match(/^\/trashed$/)
let component
// TagsMode is not selected
if (!location.pathname.match('/tags') && !location.pathname.match('/alltags')) {
component = (
<div>
<SideNavFilter
isFolded={isFolded}
isHomeActive={isHomeActive}
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
isStarredActive={isStarredActive}
isTrashedActive={isTrashedActive}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
/>
<StorageList storageList={storageList} />
<NavToggleButton isFolded={isFolded} handleToggleButtonClick={this.handleToggleButtonClick.bind(this)} />
</div>
)
} else {
component = (
<div>
<div styleName='tag-title'>
<p>Tags</p>
</div>
<div styleName='tagList'>
{this.tagListComponent(data)}
</div>
</div>
)
}
return component
}
tagListComponent () {
const { data, location } = this.props
let tagList = data.tagNoteMap.map((tag, key) => {
return key
})
return (
tagList.map(tag => (
<TagListItem
name={tag}
handleClickTagListItem={this.handleClickTagListItem.bind(this)}
isActive={!!location.pathname.match(tag)}
key={tag}
/>
))
)
}
handleClickTagListItem (name) {
const { router } = this.context
router.push(`/tags/${name}`)
}
render () { render () {
let { data, location, config, dispatch } = this.props let { data, location, config, dispatch } = this.props
let isFolded = config.isSideNavFolded let isFolded = config.isSideNavFolded
let isHomeActive = !!location.pathname.match(/^\/home$/)
let isStarredActive = !!location.pathname.match(/^\/starred$/)
let isTrashedActive = !!location.pathname.match(/^\/trashed$/)
let storageList = data.storageMap.map((storage, key) => { let storageList = data.storageMap.map((storage, key) => {
return <StorageItem return <StorageItem
@@ -58,6 +133,7 @@ class SideNav extends React.Component {
}) })
let style = {} let style = {}
if (!isFolded) style.width = this.props.width if (!isFolded) style.width = this.props.width
const isTagActive = location.pathname.match(/tag/)
return ( return (
<div className='SideNav' <div className='SideNav'
styleName={isFolded ? 'root--folded' : 'root'} styleName={isFolded ? 'root--folded' : 'root'}
@@ -65,37 +141,17 @@ class SideNav extends React.Component {
style={style} style={style}
> >
<div styleName='top'> <div styleName='top'>
<div styleName='switch-buttons'>
<button styleName={isTagActive ? 'non-active-button' : 'active-button'} onClick={this.handleSwitchFoldersButtonClick.bind(this)}>Folders</button>
<button styleName={isTagActive ? 'active-button' : 'non-active-button'} onClick={this.handleSwitchTagsButtonClick.bind(this)}>Tags</button>
</div>
<button styleName='top-menu' <button styleName='top-menu'
onClick={(e) => this.handleMenuButtonClick(e)} onClick={(e) => this.handleMenuButtonClick(e)}
> >
<i className='fa fa-wrench fa-fw' /> <i className='fa fa-wrench fa-fw' />
<span styleName='top-menu-label'>Preferences</span>
</button> </button>
</div> </div>
{this.SideNavComponent(isFolded, storageList)}
<SideNavFilter
isFolded={isFolded}
isHomeActive={isHomeActive}
handleAllNotesButtonClick={(e) => this.handleHomeButtonClick(e)}
isStarredActive={isStarredActive}
isTrashedActive={isTrashedActive}
handleStarredButtonClick={(e) => this.handleStarredButtonClick(e)}
handleTrashedButtonClick={(e) => this.handleTrashedButtonClick(e)}
/>
<div styleName='storageList'>
{storageList.length > 0 ? storageList : (
<div styleName='storageList-empty'>No storage mount.</div>
)}
</div>
<button styleName='navToggle'
onClick={(e) => this.handleToggleButtonClick(e)}
>
{isFolded
? <i className='fa fa-angle-double-right' />
: <i className='fa fa-angle-double-left' />
}
</button>
</div> </div>
) )
} }

View File

@@ -65,6 +65,11 @@ ReactDOM.render((
<Route path='starred' /> <Route path='starred' />
<Route path='searched' /> <Route path='searched' />
<Route path='trashed' /> <Route path='trashed' />
<Route path='alltags' />
<Route path='tags'>
<IndexRedirect to='/alltags' />
<Route path=':tagname' />
</Route>
<Route path='storages'> <Route path='storages'>
<IndexRedirect to='/home' /> <IndexRedirect to='/home' />
<Route path=':storageKey'> <Route path=':storageKey'>