From 4ef5e2a4f866c3315a0310a142ae69add70cbaad Mon Sep 17 00:00:00 2001 From: sokumon Date: Sun, 9 Nov 2025 20:05:57 +0530 Subject: [PATCH] feat: emoji picker --- .eslintrc | 1 + frappe/public/js/frappe/form/controls/icon.js | 1 + .../js/frappe/icon_picker/icon_picker.js | 70 ++++++++++++++++++- frappe/public/js/frappe/utils/utils.js | 7 ++ frappe/public/js/libs.bundle.js | 2 + frappe/public/scss/common/icon_picker.scss | 10 ++- package.json | 1 + yarn.lock | 5 ++ 8 files changed, 95 insertions(+), 2 deletions(-) diff --git a/.eslintrc b/.eslintrc index c5e7d6831a..36c82c3048 100644 --- a/.eslintrc +++ b/.eslintrc @@ -96,6 +96,7 @@ "hljs": true, "Awesomplete": true, "Sortable": true, + "gemoji": true, "Showdown": true, "Taggle": true, "Gantt": true, diff --git a/frappe/public/js/frappe/form/controls/icon.js b/frappe/public/js/frappe/form/controls/icon.js index f3386ed813..a964153d2b 100644 --- a/frappe/public/js/frappe/form/controls/icon.js +++ b/frappe/public/js/frappe/form/controls/icon.js @@ -21,6 +21,7 @@ frappe.ui.form.ControlIcon = class ControlIcon extends frappe.ui.form.ControlDat parent: picker_wrapper, icon: this.get_icon(), icons: frappe.symbols, + include_emoji: this.df.options == "Emojis", }); this.$wrapper diff --git a/frappe/public/js/frappe/icon_picker/icon_picker.js b/frappe/public/js/frappe/icon_picker/icon_picker.js index 8d8cccd748..85c5582ca7 100644 --- a/frappe/public/js/frappe/icon_picker/icon_picker.js +++ b/frappe/public/js/frappe/icon_picker/icon_picker.js @@ -5,6 +5,7 @@ class Picker { this.height = opts.height; this.set_icon(opts.icon); this.icons = opts.icons; + this.include_emoji = opts.include_emoji; this.setup_picker(); } @@ -19,7 +20,7 @@ class Picker { ${frappe.utils.icon("search", "sm")} -
+
@@ -29,8 +30,75 @@ class Picker { this.search_input = this.icon_picker_wrapper.find(".search-icons > input"); this.refresh(); this.setup_icons(); + if (this.include_emoji) { + this.setup_emojis(); + } } + setup_emojis() { + console.log("Making emojis"); + // setup tab + this.setup_tab(); + // setup emoji container + this.setup_emoji_container(); + // emojis + this.emoji_wrapper = this.icon_picker_wrapper.find(".emojis"); + gemoji.forEach((emoji, i) => { + let $icon = $( + `
${gemoji[i].emoji}
` + ); + this.emoji_wrapper.append($icon); + const set_values = () => { + this.set_icon(gemoji[i].emoji); + this.update_icon_selected(); + }; + $icon.on("click", () => { + set_values(); + }); + // $icon.keydown((e) => { + // const key_code = e.keyCode; + // if ([13, 32].includes(key_code)) { + // e.preventDefault(); + // set_values(); + // } + // }); + }); + } + setup_emoji_container() { + this.icon_picker_wrapper.find(".icon-section") + .after(``); + } + setup_tab() { + this.icon_picker_wrapper.find(".search-icons").after(`
+ +
`); + let icon_types = ["icon", "emoji"]; + const me = this; + this.icon_picker_wrapper.find(".nav-item").on("click", function (e) { + let container_name = $(this).text().trim().toLowerCase(); + + icon_types.forEach((type) => { + if (type === container_name) { + me.icon_picker_wrapper.find(`.${type}-section`).removeClass("hidden"); + } else { + me.icon_picker_wrapper.find(`.${type}-section`).addClass("hidden"); + } + }); + }); + } setup_icons() { this.icons.forEach((icon) => { let $icon = $( diff --git a/frappe/public/js/frappe/utils/utils.js b/frappe/public/js/frappe/utils/utils.js index 2fc3fc64ac..bab0516b7b 100644 --- a/frappe/public/js/frappe/utils/utils.js +++ b/frappe/public/js/frappe/utils/utils.js @@ -1245,6 +1245,9 @@ Object.assign(frappe.utils, { current_color = false, stroke_color = null ) { + if (frappe.utils.is_emoji(icon_name)) { + return `${icon_name}`; + } let size_class = ""; let is_espresso = icon_name.startsWith("es-"); @@ -1276,6 +1279,10 @@ Object.assign(frappe.utils, { flag(country_code) { return ``; }, + is_emoji(emoji_name) { + let emojiList = gemoji.map((emoji) => emoji.emoji); + return emojiList.includes(emoji_name); + }, make_chart(wrapper, custom_options = {}) { let chart_args = { diff --git a/frappe/public/js/libs.bundle.js b/frappe/public/js/libs.bundle.js index 77704bb173..0e1d5df2ef 100644 --- a/frappe/public/js/libs.bundle.js +++ b/frappe/public/js/libs.bundle.js @@ -5,9 +5,11 @@ import "../js/lib/leaflet_easy_button/easy-button.js"; import "../js/lib/leaflet_draw/leaflet.draw.js"; import "../js/lib/leaflet_control_locate/L.Control.Locate.js"; import Sortable from "sortablejs"; +import { gemoji } from "gemoji"; window.SetVueGlobals = (app) => { app.config.globalProperties.__ = window.__; app.config.globalProperties.frappe = window.frappe; }; window.Sortable = Sortable; +window.gemoji = gemoji; diff --git a/frappe/public/scss/common/icon_picker.scss b/frappe/public/scss/common/icon_picker.scss index 76270994e5..185eac366b 100644 --- a/frappe/public/scss/common/icon_picker.scss +++ b/frappe/public/scss/common/icon_picker.scss @@ -3,7 +3,8 @@ color: var(--text-muted); --icon-picker-width: 240px; width: var(--icon-picker-width); - .icons { + .icons, + .emojis { margin-top: 10px; display: flex; flex-wrap: wrap; @@ -27,6 +28,13 @@ text-align: center; align-items: center; } + .emoji-wrapper { + font-size: 20px; + width: 30px; + height: 30px; + text-align: center; + align-items: center; + } } .search-icons { diff --git a/package.json b/package.json index a7fdc106f5..8e75cc962e 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "frappe-datatable": "1.19.0", "frappe-gantt": "^0.6.0", "frappe-quill-image-resize": "^3.0.9", + "gemoji": "^8.1.0", "highlight.js": "^10.4.1", "html5-qrcode": "^2.3.8", "jquery": "3.7.0", diff --git a/yarn.lock b/yarn.lock index f52fc1a4ac..303baa1f56 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1489,6 +1489,11 @@ functions-have-names@^1.2.3: resolved "https://registry.yarnpkg.com/functions-have-names/-/functions-have-names-1.2.3.tgz#0404fe4ee2ba2f607f0e0ec3c80bae994133b834" integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== +gemoji@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/gemoji/-/gemoji-8.1.0.tgz#3d47a26e569c51efa95198822a6f483d7a7ae600" + integrity sha512-HA4Gx59dw2+tn+UAa7XEV4ufUKI4fH1KgcbenVA9YKSj1QJTT0xh5Mwv5HMFNN3l2OtUe3ZIfuRwSyZS5pLIWw== + generic-names@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/generic-names/-/generic-names-1.0.3.tgz#2d786a121aee508876796939e8e3bff836c20917"