feat: emoji picker

This commit is contained in:
sokumon 2025-11-09 20:05:57 +05:30
parent 526ae1608f
commit 4ef5e2a4f8
8 changed files with 95 additions and 2 deletions

View file

@ -96,6 +96,7 @@
"hljs": true,
"Awesomplete": true,
"Sortable": true,
"gemoji": true,
"Showdown": true,
"Taggle": true,
"Gantt": true,

View file

@ -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

View file

@ -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 {
<input type="search" placeholder="${__("Search for icons...")}" class="form-control">
<span class="search-icon">${frappe.utils.icon("search", "sm")}</span>
</div>
<div class="icon-section">
<div class="icon-section" id='icon-section'>
<div class="icons"></div>
</div>
</div>
@ -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 = $(
`<div id="${gemoji[i].emoji}" class="emoji-wrapper">${gemoji[i].emoji}</div>`
);
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(`<div class="emoji-section hidden" id='emoji-section'>
<div class="emojis"></div>
</div>`);
}
setup_tab() {
this.icon_picker_wrapper.find(".search-icons").after(`<div class="form-tabs-list">
<ul class="nav form-tabs" id="form-tabs" role="tablist">
<li class="nav-item show">
<button class="nav-link active" data-toggle="tab" role="tab" aria-selected="true">
Icon
</button>
</li>
<li class="nav-item show">
<button class="nav-link" data-toggle="tab" role="tab" aria-selected="true">
Emoji
</button>
</li>
</ul>
</div>`);
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 = $(

View file

@ -1245,6 +1245,9 @@ Object.assign(frappe.utils, {
current_color = false,
stroke_color = null
) {
if (frappe.utils.is_emoji(icon_name)) {
return `<span>${icon_name}</span>`;
}
let size_class = "";
let is_espresso = icon_name.startsWith("es-");
@ -1276,6 +1279,10 @@ Object.assign(frappe.utils, {
flag(country_code) {
return `<img loading="lazy" src="https://flagcdn.com/${country_code}.svg" width="20" height="15">`;
},
is_emoji(emoji_name) {
let emojiList = gemoji.map((emoji) => emoji.emoji);
return emojiList.includes(emoji_name);
},
make_chart(wrapper, custom_options = {}) {
let chart_args = {

View file

@ -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;

View file

@ -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 {

View file

@ -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",

View file

@ -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"