From a6af1c09cddd2f8d973fde67a30686a65e5e3987 Mon Sep 17 00:00:00 2001 From: Jorik Kraaikamp Date: Fri, 10 Jun 2022 17:16:20 +0200 Subject: [PATCH 1/3] Made a start on a custom emoji picker --- package-lock.json | 5 + package.json | 1 + .../components/Messages/Messages.html | 7 +- .../js/components/emoji-button/index.js | 99 ++++++++----------- src/open_inwoner/js/components/index.js | 2 +- .../scss/components/Emoji/Emoji.scss | 32 ++++++ .../components/MessageFile/MessageFile.scss | 5 + src/open_inwoner/scss/components/_index.scss | 1 + .../utils/widgets/message_file_input.html | 2 +- 9 files changed, 92 insertions(+), 62 deletions(-) create mode 100644 src/open_inwoner/scss/components/Emoji/Emoji.scss diff --git a/package-lock.json b/package-lock.json index 1a598a1d10..54d13f6018 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4965,6 +4965,11 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "emojibase-data": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/emojibase-data/-/emojibase-data-7.0.1.tgz", + "integrity": "sha512-BLZpOdwyFpZ7lzBWyDtnxmKVm/SJMYgAfp1if3o6n1TVUMSXAf0nikONXl90LZuJ/m3XWPBkkubgCet2BsCGGQ==" + }, "emojis-list": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", diff --git a/package.json b/package.json index e7ce7e9651..90fb9eb412 100644 --- a/package.json +++ b/package.json @@ -44,6 +44,7 @@ "@joeattardi/emoji-button": "^4.6.4", "@tarekraafat/autocomplete.js": "^10.2.6", "bem.js": "^1.0.10", + "emojibase-data": "^7.0.1", "flatpickr": "^4.6.9", "gumshoejs": "^5.1.2", "html-minifier": "^4.0.0", diff --git a/src/open_inwoner/components/templates/components/Messages/Messages.html b/src/open_inwoner/components/templates/components/Messages/Messages.html index 4a32399b6c..3d7cb431ea 100644 --- a/src/open_inwoner/components/templates/components/Messages/Messages.html +++ b/src/open_inwoner/components/templates/components/Messages/Messages.html @@ -45,7 +45,12 @@

{{ day.text }}

{% textarea form.content %}
{% input form.file icon="attach_file" no_label=True no_help=True extra_classes="message-file" %} - {% button class="emoji-button" icon="tag_faces" text=_('Selecteer emoji') hide_text=True type="button" %} +
+ {% button class="emoji__button" icon="tag_faces" text=_('Selecteer emoji') hide_text=True type="button" %} +
+ +
+
{% form_actions primary_text=_("Verzenden") primary_icon='arrow_forward' %} diff --git a/src/open_inwoner/js/components/emoji-button/index.js b/src/open_inwoner/js/components/emoji-button/index.js index e85bc77c8d..86c493559c 100644 --- a/src/open_inwoner/js/components/emoji-button/index.js +++ b/src/open_inwoner/js/components/emoji-button/index.js @@ -1,68 +1,49 @@ -import { EmojiButton } from '@joeattardi/emoji-button' +import emojis from 'emojibase-data/nl/data.json' -/** @type {NodeList} All the emoji buttons. */ -const EMOJI_BUTTONS = document.querySelectorAll('.emoji-button') +const emojiElements = document.querySelectorAll('.emoji') -/** - * Allows selecting emojis. - */ -class EmojiButtonSelector { - /** - * Constructor method. - * @param {HTMLElement} node - */ +class Emoji { constructor(node) { - /** @type {HTMLElement} */ this.node = node - - /** @type {EmojiButton} */ - this.picker = this.getPicker() - - this.bindEvents() - } - - /** - * Binds events to callbacks. - */ - bindEvents() { - this.node.addEventListener('click', () => - this.getPicker().togglePicker(this.node) - ) - this.getPicker().on('emoji', this.onEmoji.bind(this)) - } - - /** - * Returns the input to add emoji's to. - * @return {HTMLElement} - */ - getInput() { - return this.node.parentElement?.parentElement?.querySelector( - 'input, textarea' - ) - } - - /** - * Returns/instantiates the picker instances. - * @return {EmojiButton} - */ - getPicker() { - if (!this.picker) { - this.picker = new EmojiButton() - } - - return this.picker + this.content = document.getElementById('id_content') + this.search = node.querySelector('.emoji__search') + this.button = node.querySelector('.emoji__button') + this.popup = node.querySelector('.emoji__popup') + this.populatePopup() + this.button.addEventListener('click', (event) => { + event.preventDefault() + this.popup.classList.toggle('emoji__popup--open') + }) + document.addEventListener('keyup', (event) => { + if (event.key === 'Escape') { + this.popup.classList.remove('emoji__popup--open') + } + }) + this.search.addEventListener('keydown', (event) => { + const searchValue = event.currentTarget.value + document.querySelectorAll('.emoji__emoji-button').forEach((button) => { + if (button.dataset.label.includes(searchValue)) { + button.classList.remove('emoji__emoji-button--hidden') + } else { + button.classList.add('emoji__emoji-button--hidden') + } + }) + }) } - /** - * Gets called when an emoji is selected. - * @param {Object} selection - */ - onEmoji(selection) { - const input = this.getInput() - const emoji = selection.emoji - input.value += emoji + populatePopup() { + emojis.forEach((emoji) => { + const emojiButton = document.createElement('div') + emojiButton.classList.add('emoji__emoji-button') + emojiButton.append(emoji.emoji) + emojiButton.title = emoji.label + emojiButton.setAttribute('data-label', emoji.label) + emojiButton.addEventListener('click', (event) => { + this.content.append(emoji.emoji) + }) + this.popup.append(emojiButton) + }) } } -// Start1 -;[...EMOJI_BUTTONS].forEach((node) => new EmojiButtonSelector(node)) +;[...emojiElements].forEach((emojiElement) => new Emoji(emojiElement)) diff --git a/src/open_inwoner/js/components/index.js b/src/open_inwoner/js/components/index.js index b523a8d217..d30bab5107 100644 --- a/src/open_inwoner/js/components/index.js +++ b/src/open_inwoner/js/components/index.js @@ -9,7 +9,7 @@ import './confirmation' import './datepicker' import './dropdown' import './dropdown' -// import './emoji-button' +import './emoji-button' import './header' import './map' import './message-file' diff --git a/src/open_inwoner/scss/components/Emoji/Emoji.scss b/src/open_inwoner/scss/components/Emoji/Emoji.scss new file mode 100644 index 0000000000..ffea79e64b --- /dev/null +++ b/src/open_inwoner/scss/components/Emoji/Emoji.scss @@ -0,0 +1,32 @@ +.emoji { + &__button { + } + + &__search { + grid-column: 1 / span 8; + } + + &__emoji-button { + cursor: pointer; + + &--hidden { + display: none; + } + } + + &__popup { + display: none; + grid-template-columns: repeat(8, 1fr); + position: absolute; + max-height: 200px; + overflow: auto; + background-color: #fff; + padding: var(--spacing-medium); + border: 1px solid #000; + gap: var(--spacing-medium); + + &--open { + display: grid; + } + } +} diff --git a/src/open_inwoner/scss/components/MessageFile/MessageFile.scss b/src/open_inwoner/scss/components/MessageFile/MessageFile.scss index 7b5b515974..ad6dd15265 100644 --- a/src/open_inwoner/scss/components/MessageFile/MessageFile.scss +++ b/src/open_inwoner/scss/components/MessageFile/MessageFile.scss @@ -16,6 +16,10 @@ padding: var(--spacing-small); } + &__init { + display: none; + } + &__delete { cursor: pointer; } @@ -34,6 +38,7 @@ .label { cursor: pointer; + flex-direction: row; *[class*='icon'] { top: var(--spacing-tiny); diff --git a/src/open_inwoner/scss/components/_index.scss b/src/open_inwoner/scss/components/_index.scss index e7c5d54671..820c09b6ce 100644 --- a/src/open_inwoner/scss/components/_index.scss +++ b/src/open_inwoner/scss/components/_index.scss @@ -80,3 +80,4 @@ @import './Typography/LinkList.scss'; @import './Typography/P.scss'; @import './modal/modal'; +@import './Emoji/Emoji.scss'; diff --git a/src/open_inwoner/templates/utils/widgets/message_file_input.html b/src/open_inwoner/templates/utils/widgets/message_file_input.html index 7dd6cc2d93..e2f37c7559 100644 --- a/src/open_inwoner/templates/utils/widgets/message_file_input.html +++ b/src/open_inwoner/templates/utils/widgets/message_file_input.html @@ -1,5 +1,5 @@ From f58922db7aa13bae45b760e1a39fb30b768ce9b0 Mon Sep 17 00:00:00 2001 From: Jorik Kraaikamp Date: Fri, 10 Jun 2022 17:21:42 +0200 Subject: [PATCH 2/3] Fixed case sensitive search --- src/open_inwoner/js/components/emoji-button/index.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/open_inwoner/js/components/emoji-button/index.js b/src/open_inwoner/js/components/emoji-button/index.js index 86c493559c..629644b96a 100644 --- a/src/open_inwoner/js/components/emoji-button/index.js +++ b/src/open_inwoner/js/components/emoji-button/index.js @@ -19,10 +19,11 @@ class Emoji { this.popup.classList.remove('emoji__popup--open') } }) - this.search.addEventListener('keydown', (event) => { - const searchValue = event.currentTarget.value + this.search.addEventListener('keyup', (event) => { + const searchValue = event.currentTarget.value.toUpperCase() document.querySelectorAll('.emoji__emoji-button').forEach((button) => { - if (button.dataset.label.includes(searchValue)) { + const label = button.dataset.label.toUpperCase() + if (label.includes(searchValue)) { button.classList.remove('emoji__emoji-button--hidden') } else { button.classList.add('emoji__emoji-button--hidden') From 29459bbf5cb0c420685d5372838d9fed4c03b928 Mon Sep 17 00:00:00 2001 From: Jorik Kraaikamp Date: Mon, 13 Jun 2022 14:06:03 +0200 Subject: [PATCH 3/3] Made the emoji picker function better --- .../components/Messages/Messages.html | 8 +++-- .../js/components/emoji-button/index.js | 33 ++++++++++++------- .../scss/components/Emoji/Emoji.scss | 32 +++++++++++++----- .../scss/components/Form/Input.scss | 4 +++ .../scss/components/Messages/_Messages.scss | 6 +++- 5 files changed, 61 insertions(+), 22 deletions(-) diff --git a/src/open_inwoner/components/templates/components/Messages/Messages.html b/src/open_inwoner/components/templates/components/Messages/Messages.html index 3d7cb431ea..03b99ab18a 100644 --- a/src/open_inwoner/components/templates/components/Messages/Messages.html +++ b/src/open_inwoner/components/templates/components/Messages/Messages.html @@ -1,4 +1,4 @@ -{% load i18n button_tags form_tags messages_tags %} +{% load i18n button_tags form_tags messages_tags icon_tags %}
@@ -48,7 +48,11 @@

{{ day.text }}

{% button class="emoji__button" icon="tag_faces" text=_('Selecteer emoji') hide_text=True type="button" %}
- +
+ + {% icon icon="close" %} +
+
diff --git a/src/open_inwoner/js/components/emoji-button/index.js b/src/open_inwoner/js/components/emoji-button/index.js index 629644b96a..89205c45e8 100644 --- a/src/open_inwoner/js/components/emoji-button/index.js +++ b/src/open_inwoner/js/components/emoji-button/index.js @@ -9,7 +9,13 @@ class Emoji { this.search = node.querySelector('.emoji__search') this.button = node.querySelector('.emoji__button') this.popup = node.querySelector('.emoji__popup') + this.container = node.querySelector('.emoji__emojis') + this.close = this.popup.querySelector('.material-icons') this.populatePopup() + this.addListeners() + } + + addListeners() { this.button.addEventListener('click', (event) => { event.preventDefault() this.popup.classList.toggle('emoji__popup--open') @@ -19,16 +25,21 @@ class Emoji { this.popup.classList.remove('emoji__popup--open') } }) - this.search.addEventListener('keyup', (event) => { - const searchValue = event.currentTarget.value.toUpperCase() - document.querySelectorAll('.emoji__emoji-button').forEach((button) => { - const label = button.dataset.label.toUpperCase() - if (label.includes(searchValue)) { - button.classList.remove('emoji__emoji-button--hidden') - } else { - button.classList.add('emoji__emoji-button--hidden') - } - }) + this.close.addEventListener('click', (event) => { + this.popup.classList.remove('emoji__popup--open') + }) + this.search.addEventListener('keyup', this.searchEmoji.bind(this)) + } + + searchEmoji(event) { + const searchValue = event.currentTarget.value.toUpperCase() + document.querySelectorAll('.emoji__emoji-button').forEach((button) => { + const label = button.dataset.label.toUpperCase() + if (label.includes(searchValue)) { + button.classList.remove('emoji__emoji-button--hidden') + } else { + button.classList.add('emoji__emoji-button--hidden') + } }) } @@ -42,7 +53,7 @@ class Emoji { emojiButton.addEventListener('click', (event) => { this.content.append(emoji.emoji) }) - this.popup.append(emojiButton) + this.container.append(emojiButton) }) } } diff --git a/src/open_inwoner/scss/components/Emoji/Emoji.scss b/src/open_inwoner/scss/components/Emoji/Emoji.scss index ffea79e64b..aa5b075837 100644 --- a/src/open_inwoner/scss/components/Emoji/Emoji.scss +++ b/src/open_inwoner/scss/components/Emoji/Emoji.scss @@ -1,9 +1,19 @@ .emoji { - &__button { + &__header { + display: grid; + grid-template-columns: 1fr 25px; + align-items: center; + padding: 8px 0 0 8px; + gap: 8px; } &__search { - grid-column: 1 / span 8; + // grid-column: 1 / span 8; + min-width: 0; + } + + .material-icons { + cursor: pointer; } &__emoji-button { @@ -16,17 +26,23 @@ &__popup { display: none; - grid-template-columns: repeat(8, 1fr); position: absolute; - max-height: 200px; - overflow: auto; background-color: #fff; - padding: var(--spacing-medium); border: 1px solid #000; - gap: var(--spacing-medium); + width: 260px; &--open { - display: grid; + display: block; } } + + &__emojis { + display: grid; + gap: var(--spacing-medium); + grid-template-columns: repeat(8, 1fr); + padding: var(--spacing-medium); + max-height: 200px; + overflow: auto; + text-align: center; + } } diff --git a/src/open_inwoner/scss/components/Form/Input.scss b/src/open_inwoner/scss/components/Form/Input.scss index efb50bf235..cb99533e81 100644 --- a/src/open_inwoner/scss/components/Form/Input.scss +++ b/src/open_inwoner/scss/components/Form/Input.scss @@ -20,6 +20,10 @@ font-family: var(--font-family-body); font-size: var(--font-size-body); background-color: var(--color-white); + + &.input--bordered { + border: 1px solid var(--color-mute); + } } textarea.input { diff --git a/src/open_inwoner/scss/components/Messages/_Messages.scss b/src/open_inwoner/scss/components/Messages/_Messages.scss index de91d84e2f..8d8293357e 100644 --- a/src/open_inwoner/scss/components/Messages/_Messages.scss +++ b/src/open_inwoner/scss/components/Messages/_Messages.scss @@ -70,8 +70,12 @@ } .message { - max-width: 50%; + max-width: 85%; align-self: baseline; + + @media (min-width: 768px) { + max-width: 50%; + } } .message--ours {