Adding emoji picker
This commit is contained in:
parent
8afac6781d
commit
ec93778293
12 changed files with 113 additions and 1 deletions
|
@ -16,6 +16,7 @@
|
|||
"CardDetail.add-property": "+ Add a property",
|
||||
"CardDetail.image": "Image",
|
||||
"CardDetail.new-comment-placeholder": "Add a comment...",
|
||||
"CardDetail.pick-icon": "Pick Icon",
|
||||
"CardDetail.random-icon": "Random",
|
||||
"CardDetail.remove-icon": "Remove Icon",
|
||||
"CardDetail.text": "Text",
|
||||
|
@ -66,6 +67,7 @@
|
|||
"ViewHeader.test-add-100-cards": "TEST: Add 100 cards",
|
||||
"ViewHeader.test-add-1000-cards": "TEST: Add 1,000 cards",
|
||||
"ViewHeader.test-randomize-icons": "TEST: Randomize icons",
|
||||
"ViewTitle.pick-icon": "Pick Icon",
|
||||
"ViewTitle.random-icon": "Random",
|
||||
"ViewTitle.remove-icon": "Remove Icon",
|
||||
"ViewTitle.untitled-board": "Untitled Board"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
"CardDetail.add-property": "+ Añadir propiedad",
|
||||
"CardDetail.image": "Imagen",
|
||||
"CardDetail.new-comment-placeholder": "Añadir un comentario...",
|
||||
"CardDetail.pick-icon": "Escoger Icono",
|
||||
"CardDetail.random-icon": "Aleatorio",
|
||||
"CardDetail.remove-icon": "Quitar icono",
|
||||
"CardDetail.text": "Texto",
|
||||
|
@ -66,6 +67,7 @@
|
|||
"ViewHeader.test-add-100-cards": "TEST: Añadir 100 tarjetas",
|
||||
"ViewHeader.test-add-1000-cards": "TEST: Añadir 1,000 tarjetas",
|
||||
"ViewHeader.test-randomize-icons": "TEST: Iconos aleatorios",
|
||||
"ViewTitle.pick-icon": "Escoger Icono",
|
||||
"ViewTitle.random-icon": "Aleatorio",
|
||||
"ViewTitle.remove-icon": "Quitar Icono",
|
||||
"ViewTitle.untitled-board": "Panel sin título"
|
||||
|
|
18
webapp/package-lock.json
generated
18
webapp/package-lock.json
generated
|
@ -1314,6 +1314,15 @@
|
|||
"@types/tern": "*"
|
||||
}
|
||||
},
|
||||
"@types/emoji-mart": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/emoji-mart/-/emoji-mart-3.0.3.tgz",
|
||||
"integrity": "sha512-IAfTNRA6OoM7f/GZpuvdM47ktLGcHsnUuR+dQlwEEXSRbS0Z9iFoPA3WgBim6RBL4i7EVLtoRpREn5BgL3aMXA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/react": "*"
|
||||
}
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "0.0.45",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-0.0.45.tgz",
|
||||
|
@ -3627,6 +3636,15 @@
|
|||
"integrity": "sha512-d34LN4L6h18Bzz9xpoku2nPwKxCPlPMr3EEKTkoEBi+1/+b0lcRkRJ1UVyyZaKNeqGR3swcGl6s390DNO4YVgQ==",
|
||||
"dev": true
|
||||
},
|
||||
"emoji-mart": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-mart/-/emoji-mart-3.0.0.tgz",
|
||||
"integrity": "sha512-r5DXyzOLJttdwRYfJmPq/XL3W5tiAE/VsRnS0Hqyn27SqPA/GOYwVUSx50px/dXdJyDSnvmoPbuJ/zzhwSaU4A==",
|
||||
"requires": {
|
||||
"@babel/runtime": "^7.0.0",
|
||||
"prop-types": "^15.6.0"
|
||||
}
|
||||
},
|
||||
"emoji-regex": {
|
||||
"version": "8.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"i18n-extract": "formatjs extract src/**/*.tsx src/**/*.ts --out-file i18n/tmp.json; formatjs compile i18n/tmp.json --out-file i18n/en.json; rm i18n/tmp.json"
|
||||
},
|
||||
"dependencies": {
|
||||
"emoji-mart": "^3.0.0",
|
||||
"marked": "^1.1.1",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
@ -30,6 +31,7 @@
|
|||
"@formatjs/ts-transformer": "^2.11.3",
|
||||
"@testing-library/jest-dom": "^5.11.4",
|
||||
"@testing-library/react": "^11.0.4",
|
||||
"@types/emoji-mart": "^3.0.3",
|
||||
"@types/jest": "^26.0.14",
|
||||
"@types/marked": "^1.1.0",
|
||||
"@types/react": "^16.9.49",
|
||||
|
|
|
@ -14,6 +14,7 @@ import {Utils} from '../utils'
|
|||
import MenuWrapper from '../widgets/menuWrapper'
|
||||
import Menu from '../widgets/menu'
|
||||
import Editable from '../widgets/editable'
|
||||
import EmojiPicker from '../widgets/emojiPicker'
|
||||
import Button from '../widgets/buttons/button'
|
||||
|
||||
import {MarkdownEditor} from './markdownEditor'
|
||||
|
@ -50,6 +51,13 @@ class CardDetail extends React.Component<Props, State> {
|
|||
}
|
||||
}
|
||||
|
||||
onSelectEmoji = (emoji: string) => {
|
||||
mutator.changeIcon(this.state.cardTree.card, emoji)
|
||||
|
||||
// Close the menu
|
||||
document.body.click()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.cardListener = new OctoListener()
|
||||
this.cardListener.open([this.props.cardId], async (blockId) => {
|
||||
|
@ -128,6 +136,12 @@ class CardDetail extends React.Component<Props, State> {
|
|||
name={intl.formatMessage({id: 'CardDetail.random-icon', defaultMessage: 'Random'})}
|
||||
onClick={() => mutator.changeIcon(card, BlockIcons.shared.randomIcon())}
|
||||
/>
|
||||
<Menu.SubMenu
|
||||
id='pick'
|
||||
name={intl.formatMessage({id: 'CardDetail.pick-icon', defaultMessage: 'Pick Icon'})}
|
||||
>
|
||||
<EmojiPicker onSelect={this.onSelectEmoji}/>
|
||||
</Menu.SubMenu>
|
||||
<Menu.Text
|
||||
id='remove'
|
||||
name={intl.formatMessage({id: 'CardDetail.remove-icon', defaultMessage: 'Remove Icon'})}
|
||||
|
|
|
@ -203,6 +203,7 @@ class Sidebar extends React.Component<Props, State> {
|
|||
<Menu.SubMenu
|
||||
id='lang'
|
||||
name={intl.formatMessage({id: 'Sidebar.set-language', defaultMessage: 'Set Language'})}
|
||||
position='top'
|
||||
>
|
||||
<Menu.Text
|
||||
id='english-lang'
|
||||
|
@ -218,6 +219,7 @@ class Sidebar extends React.Component<Props, State> {
|
|||
<Menu.SubMenu
|
||||
id='theme'
|
||||
name={intl.formatMessage({id: 'Sidebar.set-theme', defaultMessage: 'Set Theme'})}
|
||||
position='top'
|
||||
>
|
||||
<Menu.Text
|
||||
id='dark-theme'
|
||||
|
|
|
@ -9,6 +9,7 @@ import mutator from '../mutator'
|
|||
import Menu from '../widgets/menu'
|
||||
import MenuWrapper from '../widgets/menuWrapper'
|
||||
import Editable from '../widgets/editable'
|
||||
import EmojiPicker from '../widgets/emojiPicker'
|
||||
import Button from '../widgets/buttons/button'
|
||||
|
||||
import './viewTitle.scss'
|
||||
|
@ -33,6 +34,13 @@ class ViewTitle extends React.Component<Props, State> {
|
|||
this.state = {title: props.board.title}
|
||||
}
|
||||
|
||||
onSelectEmoji = (emoji: string) => {
|
||||
mutator.changeIcon(this.props.board, emoji)
|
||||
|
||||
// Close the menu
|
||||
document.body.click()
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
const {board, intl} = this.props
|
||||
|
||||
|
@ -62,6 +70,12 @@ class ViewTitle extends React.Component<Props, State> {
|
|||
name={intl.formatMessage({id: 'ViewTitle.random-icon', defaultMessage: 'Random'})}
|
||||
onClick={() => mutator.changeIcon(board, BlockIcons.shared.randomIcon())}
|
||||
/>
|
||||
<Menu.SubMenu
|
||||
id='pick'
|
||||
name={intl.formatMessage({id: 'ViewTitle.pick-icon', defaultMessage: 'Pick Icon'})}
|
||||
>
|
||||
<EmojiPicker onSelect={this.onSelectEmoji}/>
|
||||
</Menu.SubMenu>
|
||||
<Menu.Text
|
||||
id='remove'
|
||||
name={intl.formatMessage({id: 'ViewTitle.remove-icon', defaultMessage: 'Remove Icon'})}
|
||||
|
|
20
webapp/src/widgets/emojiPicker.scss
Normal file
20
webapp/src/widgets/emojiPicker.scss
Normal file
|
@ -0,0 +1,20 @@
|
|||
.EmojiPicker {
|
||||
.emoji-mart {
|
||||
color: rgb(var(--main-fg));
|
||||
background: rgb(var(--main-bg));
|
||||
border-color: rgba(var(--main-fg), 0.16);
|
||||
.emoji-mart-bar {
|
||||
border: 0 solid rgba(var(--main-fg), 0.16);
|
||||
border-bottom-width: 1px
|
||||
}
|
||||
.emoji-mart-search input {
|
||||
border: 1px solid rgba(var(--main-fg), 0.16);
|
||||
}
|
||||
.emoji-mart-category-label span {
|
||||
background: rgb(var(--main-bg));
|
||||
}
|
||||
.emoji-mart-search-icon svg {
|
||||
fill: rgb(var(--main-fg));
|
||||
}
|
||||
}
|
||||
}
|
25
webapp/src/widgets/emojiPicker.tsx
Normal file
25
webapp/src/widgets/emojiPicker.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React, {FC} from 'react'
|
||||
|
||||
import 'emoji-mart/css/emoji-mart.css'
|
||||
import {Picker, BaseEmoji} from 'emoji-mart'
|
||||
|
||||
import './emojiPicker.scss'
|
||||
|
||||
type Props = {
|
||||
onSelect: (emoji: string) => void
|
||||
}
|
||||
|
||||
const EmojiPicker: FC<Props> = (props: Props): JSX.Element => (
|
||||
<div
|
||||
className='EmojiPicker'
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<Picker
|
||||
onSelect={(emoji: BaseEmoji) => props.onSelect(emoji.native)}
|
||||
/>
|
||||
</div>
|
||||
)
|
||||
|
||||
export default EmojiPicker
|
|
@ -11,6 +11,12 @@
|
|||
border-radius: 3px;
|
||||
box-shadow: rgba(var(--main-fg), 0.05) 0px 0px 0px 1px, rgba(var(--main-fg), 0.1) 0px 3px 6px, rgba(var(--main-fg), 0.2) 0px 9px 24px;
|
||||
left: 100%;
|
||||
&.top {
|
||||
bottom: 0;
|
||||
}
|
||||
&.bottom {
|
||||
top: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.SubmenuTriangleIcon {
|
||||
|
|
|
@ -9,7 +9,7 @@ import {MenuOptionProps} from './menuItem'
|
|||
import './subMenuOption.scss'
|
||||
|
||||
type SubMenuOptionProps = MenuOptionProps & {
|
||||
position?: 'bottom | top'
|
||||
position?: 'bottom' | 'top'
|
||||
}
|
||||
|
||||
type SubMenuState = {
|
||||
|
|
|
@ -47,6 +47,13 @@ function makeCommonConfig() {
|
|||
'sass-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.css$/i,
|
||||
use: [
|
||||
'style-loader',
|
||||
'css-loader',
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(tsx?|js|jsx|html)$/,
|
||||
use: [
|
||||
|
|
Loading…
Reference in a new issue