diff --git a/webapp/i18n/en.json b/webapp/i18n/en.json index 035ffb517..24efc34e2 100644 --- a/webapp/i18n/en.json +++ b/webapp/i18n/en.json @@ -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" diff --git a/webapp/i18n/es.json b/webapp/i18n/es.json index 0ceec5472..96cd46f5a 100644 --- a/webapp/i18n/es.json +++ b/webapp/i18n/es.json @@ -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" diff --git a/webapp/package-lock.json b/webapp/package-lock.json index 22c74db08..2183359e8 100644 --- a/webapp/package-lock.json +++ b/webapp/package-lock.json @@ -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", diff --git a/webapp/package.json b/webapp/package.json index cd03f9eb7..7c89511e4 100644 --- a/webapp/package.json +++ b/webapp/package.json @@ -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", diff --git a/webapp/src/components/cardDetail.tsx b/webapp/src/components/cardDetail.tsx index e8116ba6c..7b32dd7e8 100644 --- a/webapp/src/components/cardDetail.tsx +++ b/webapp/src/components/cardDetail.tsx @@ -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 { } } + 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 { name={intl.formatMessage({id: 'CardDetail.random-icon', defaultMessage: 'Random'})} onClick={() => mutator.changeIcon(card, BlockIcons.shared.randomIcon())} /> + + + { { { 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 { name={intl.formatMessage({id: 'ViewTitle.random-icon', defaultMessage: 'Random'})} onClick={() => mutator.changeIcon(board, BlockIcons.shared.randomIcon())} /> + + + void +} + +const EmojiPicker: FC = (props: Props): JSX.Element => ( +
e.stopPropagation()} + > + props.onSelect(emoji.native)} + /> +
+) + +export default EmojiPicker diff --git a/webapp/src/widgets/menu/subMenuOption.scss b/webapp/src/widgets/menu/subMenuOption.scss index f6b62198e..327d13c46 100644 --- a/webapp/src/widgets/menu/subMenuOption.scss +++ b/webapp/src/widgets/menu/subMenuOption.scss @@ -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 { diff --git a/webapp/src/widgets/menu/subMenuOption.tsx b/webapp/src/widgets/menu/subMenuOption.tsx index 39632491d..e1b6f912f 100644 --- a/webapp/src/widgets/menu/subMenuOption.tsx +++ b/webapp/src/widgets/menu/subMenuOption.tsx @@ -9,7 +9,7 @@ import {MenuOptionProps} from './menuItem' import './subMenuOption.scss' type SubMenuOptionProps = MenuOptionProps & { - position?: 'bottom | top' + position?: 'bottom' | 'top' } type SubMenuState = { diff --git a/webapp/webpack.common.js b/webapp/webpack.common.js index f066a38dc..0b40767b7 100644 --- a/webapp/webpack.common.js +++ b/webapp/webpack.common.js @@ -47,6 +47,13 @@ function makeCommonConfig() { 'sass-loader', ], }, + { + test: /\.css$/i, + use: [ + 'style-loader', + 'css-loader', + ], + }, { test: /\.(tsx?|js|jsx|html)$/, use: [