From 3e645db3245cac5ce015c23a8564898a519360c2 Mon Sep 17 00:00:00 2001 From: HarlanLuo Date: Thu, 27 Dec 2018 21:36:20 +0800 Subject: [PATCH] add feature: colored tags --- browser/components/ColorPicker.js | 63 +++++++++++++ browser/components/ColorPicker.styl | 25 ++++++ browser/components/NoteItem.js | 14 +-- browser/components/TagListItem.js | 8 +- browser/main/Detail/MarkdownNoteDetail.js | 1 + browser/main/Detail/SnippetNoteDetail.js | 1 + browser/main/Detail/TagSelect.js | 6 +- browser/main/NoteList/index.js | 1 + browser/main/SideNav/index.js | 88 +++++++++++++++++++ browser/main/lib/ConfigManager.js | 3 +- package.json | 1 + tests/components/TagListItem.snapshot.test.js | 2 +- .../TagListItem.snapshot.test.js.snap | 5 ++ 13 files changed, 205 insertions(+), 13 deletions(-) create mode 100644 browser/components/ColorPicker.js create mode 100644 browser/components/ColorPicker.styl diff --git a/browser/components/ColorPicker.js b/browser/components/ColorPicker.js new file mode 100644 index 00000000..f68aa8ec --- /dev/null +++ b/browser/components/ColorPicker.js @@ -0,0 +1,63 @@ +import React from 'react' +import PropTypes from 'prop-types' +import { SketchPicker } from 'react-color' +import CSSModules from 'browser/lib/CSSModules' +import styles from './ColorPicker.styl' + +const componentHeight = 333 + +class ColorPicker extends React.Component { + constructor (props) { + super(props) + + this.state = { + color: this.props.color || '#888888' + } + + this.onColorChange = this.onColorChange.bind(this) + this.handleConfirm = this.handleConfirm.bind(this) + } + + onColorChange (color) { + this.setState({ + color + }) + } + + handleConfirm () { + this.props.onConfirm(this.state.color) + } + + render () { + const { onReset, onCancel, targetRect } = this.props + const { color } = this.state + + const clientHeight = document.body.clientHeight + const alignX = targetRect.right + 4 + let alignY = targetRect.top + if (targetRect.top + componentHeight > clientHeight) { + alignY = targetRect.bottom - componentHeight + } + + return ( +
+ +
+ + + +
+
+ ) + } +} + +ColorPicker.propTypes = { + color: PropTypes.string, + targetRect: PropTypes.object, + onConfirm: PropTypes.func.isRequired, + onCancel: PropTypes.func.isRequired, + onReset: PropTypes.func.isRequired +} + +export default CSSModules(ColorPicker, styles) diff --git a/browser/components/ColorPicker.styl b/browser/components/ColorPicker.styl new file mode 100644 index 00000000..4c5a269c --- /dev/null +++ b/browser/components/ColorPicker.styl @@ -0,0 +1,25 @@ +.colorPicker + position fixed + z-index 10000 + display flex + flex-direction column +.footer + display flex + justify-content center + align-items center + padding 5px + & > button + button + margin-left 10px + +.btn-cancel, +.btn-confirm, +.btn-reset + height 1.6em + border 1px solid #888888 + background-color #fff + font-size 16px + border-radius 4px +.btn-confirm + background-color $ui-button-default--active-backgroundColor + + diff --git a/browser/components/NoteItem.js b/browser/components/NoteItem.js index 2fc70a39..cd97527c 100644 --- a/browser/components/NoteItem.js +++ b/browser/components/NoteItem.js @@ -15,8 +15,8 @@ import i18n from 'browser/lib/i18n' * @param {string} tagName * @return {React.Component} */ -const TagElement = ({ tagName }) => ( - +const TagElement = ({ tagName, color }) => ( + #{tagName} ) @@ -27,7 +27,7 @@ const TagElement = ({ tagName }) => ( * @param {boolean} showTagsAlphabetically * @return {React.Component} */ -const TagElementList = (tags, showTagsAlphabetically) => { +const TagElementList = (tags, showTagsAlphabetically, tagConfig) => { if (!isArray(tags)) { return [] } @@ -35,7 +35,7 @@ const TagElementList = (tags, showTagsAlphabetically) => { if (showTagsAlphabetically) { return _.sortBy(tags).map(tag => TagElement({ tagName: tag })) } else { - return tags.map(tag => TagElement({ tagName: tag })) + return tags.map(tag => TagElement({ tagName: tag, color: tagConfig[tag] })) } } @@ -59,7 +59,8 @@ const NoteItem = ({ storageName, folderName, viewType, - showTagsAlphabetically + showTagsAlphabetically, + tagConfig }) => (
{note.tags.length > 0 - ? TagElementList(note.tags, showTagsAlphabetically) + ? TagElementList(note.tags, showTagsAlphabetically, tagConfig) : ( +const TagListItem = ({name, handleClickTagListItem, handleClickNarrowToTag, handleContextMenu, isActive, isRelated, count, color}) => (
handleContextMenu(e, name)}> {isRelated ?
diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index d8b5798d..96ea0941 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -788,6 +788,7 @@ class SnippetNoteDetail extends React.Component { showTagsAlphabetically={config.ui.showTagsAlphabetically} data={data} onChange={(e) => this.handleChange(e)} + tagConfig={config.tag} />
diff --git a/browser/main/Detail/TagSelect.js b/browser/main/Detail/TagSelect.js index 6ced475b..d4411af9 100644 --- a/browser/main/Detail/TagSelect.js +++ b/browser/main/Detail/TagSelect.js @@ -179,13 +179,14 @@ class TagSelect extends React.Component { } render () { - const { value, className, showTagsAlphabetically } = this.props + const { value, className, showTagsAlphabetically, tagConfig } = this.props const tagList = _.isArray(value) ? (showTagsAlphabetically ? _.sortBy(value) : value).map((tag) => { return ( this.handleTagLabelClick(tag)}>#{tag}
{this.SideNavComponent(isFolded, storageList)} + {colorPicker} ) } diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 81165777..c70978f7 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -86,7 +86,8 @@ export const DEFAULT_CONFIG = { token: '', username: '', password: '' - } + }, + tag: {} } function validate (config) { diff --git a/package.json b/package.json index f12360a0..9b0c1d31 100644 --- a/package.json +++ b/package.json @@ -97,6 +97,7 @@ "react": "^15.5.4", "react-autosuggest": "^9.4.0", "react-codemirror": "^0.3.0", + "react-color": "^2.17.0", "react-debounce-render": "^4.0.1", "react-dom": "^15.0.2", "react-image-carousel": "^2.0.18", diff --git a/tests/components/TagListItem.snapshot.test.js b/tests/components/TagListItem.snapshot.test.js index 8bea2ccb..637844e6 100644 --- a/tests/components/TagListItem.snapshot.test.js +++ b/tests/components/TagListItem.snapshot.test.js @@ -3,7 +3,7 @@ import renderer from 'react-test-renderer' import TagListItem from 'browser/components/TagListItem' it('TagListItem renders correctly', () => { - const tagListItem = renderer.create() + const tagListItem = renderer.create() expect(tagListItem.toJSON()).toMatchSnapshot() }) diff --git a/tests/components/__snapshots__/TagListItem.snapshot.test.js.snap b/tests/components/__snapshots__/TagListItem.snapshot.test.js.snap index ad883222..d6939ec2 100644 --- a/tests/components/__snapshots__/TagListItem.snapshot.test.js.snap +++ b/tests/components/__snapshots__/TagListItem.snapshot.test.js.snap @@ -14,6 +14,11 @@ exports[`TagListItem renders correctly 1`] = ` > # Test