Fix emoji picker

This commit is contained in:
N-Pex 2025-05-12 17:15:11 +02:00
parent bde99dc242
commit d766f9a0e3
7 changed files with 124 additions and 45 deletions

View file

@ -1,9 +1,19 @@
#EmojiPicker {
.v3-emoji-picker {
width: 100%;
background-color: #ffffff;
margin-top: 15px;
box-shadow: none;
height: 100%;
flex: 1 1 100%;
.container-emoji {
height: 60vh;
.v3-emojis button {
@media #{map-get($display-breakpoints, 'sm')} {
flex-basis: 10% !important;
max-width: 10% !important;
}
@media #{map-get($display-breakpoints, 'md-and-up')} {
flex-basis: 6.25% !important;
max-width: 6.25% !important;
}
}
}

View file

@ -0,0 +1,34 @@
<svg width="13" height="13" viewBox="0 0 13 13" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
d="M1.08333 5.77777H0.361111C0.161778 5.77777 0 5.93955 0 6.13888C0 6.33822 0.161778 6.49999 0.361111 6.49999H1.08333C1.28267 6.49999 1.44444 6.33822 1.44444 6.13888C1.44444 5.93955 1.28267 5.77777 1.08333 5.77777Z"
fill="black"
/>
<path
d="M1.08333 5.77777H0.361111C0.161778 5.77777 0 5.93955 0 6.13888C0 6.33822 0.161778 6.49999 0.361111 6.49999H1.08333C1.28267 6.49999 1.44444 6.33822 1.44444 6.13888C1.44444 5.93955 1.28267 5.77777 1.08333 5.77777Z"
fill="black"
/>
<path
d="M1.08333 8.66669H0.361111C0.161778 8.66669 0 8.82846 0 9.0278C0 9.22713 0.161778 9.38891 0.361111 9.38891H1.08333C1.28267 9.38891 1.44444 9.22713 1.44444 9.0278C1.44444 8.82846 1.28267 8.66669 1.08333 8.66669Z"
fill="black"
/>
<path
d="M1.08333 8.66669H0.361111C0.161778 8.66669 0 8.82846 0 9.0278C0 9.22713 0.161778 9.38891 0.361111 9.38891H1.08333C1.28267 9.38891 1.44444 9.22713 1.44444 9.0278C1.44444 8.82846 1.28267 8.66669 1.08333 8.66669Z"
fill="black"
/>
<path
d="M11.6553 4.02206L12.1724 3.50494C12.3132 3.36411 12.3132 3.13517 12.1724 2.99433C12.0316 2.8535 11.8026 2.8535 11.6618 2.99433L11.1447 3.51144C10.2766 2.75239 9.1658 2.26633 7.94453 2.18472V0.722222H9.02786C9.22719 0.722222 9.38897 0.560444 9.38897 0.361111C9.38897 0.161778 9.22719 0 9.02786 0H6.13897C5.93964 0 5.77786 0.161778 5.77786 0.361111C5.77786 0.560444 5.93964 0.722222 6.13897 0.722222H7.2223V2.18472C4.40419 2.37178 2.16675 4.71828 2.16675 7.58333C2.16675 10.5704 4.5963 13 7.58341 13C10.5705 13 13.0001 10.5704 13.0001 7.58333C13.0001 6.21978 12.4895 4.97611 11.6553 4.02206ZM7.58341 12.2778C4.99497 12.2778 2.88897 10.1718 2.88897 7.58333C2.88897 4.99489 4.99497 2.88889 7.58341 2.88889C10.1719 2.88889 12.2779 4.99489 12.2779 7.58333C12.2779 10.1718 10.1719 12.2778 7.58341 12.2778Z"
fill="black"
/>
<path
d="M11.6553 4.02206L12.1724 3.50494C12.3132 3.36411 12.3132 3.13517 12.1724 2.99433C12.0316 2.8535 11.8026 2.8535 11.6618 2.99433L11.1447 3.51144C10.2766 2.75239 9.1658 2.26633 7.94453 2.18472V0.722222H9.02786C9.22719 0.722222 9.38897 0.560444 9.38897 0.361111C9.38897 0.161778 9.22719 0 9.02786 0H6.13897C5.93964 0 5.77786 0.161778 5.77786 0.361111C5.77786 0.560444 5.93964 0.722222 6.13897 0.722222H7.2223V2.18472C4.40419 2.37178 2.16675 4.71828 2.16675 7.58333C2.16675 10.5704 4.5963 13 7.58341 13C10.5705 13 13.0001 10.5704 13.0001 7.58333C13.0001 6.21978 12.4895 4.97611 11.6553 4.02206ZM7.58341 12.2778C4.99497 12.2778 2.88897 10.1718 2.88897 7.58333C2.88897 4.99489 4.99497 2.88889 7.58341 2.88889C10.1719 2.88889 12.2779 4.99489 12.2779 7.58333C12.2779 10.1718 10.1719 12.2778 7.58341 12.2778Z"
fill="black"
/>
<path
d="M7.58328 4.33331C7.38395 4.33331 7.22217 4.49509 7.22217 4.69442V7.58331C7.22217 7.78265 7.38395 7.94442 7.58328 7.94442C7.78261 7.94442 7.94439 7.78265 7.94439 7.58331V4.69442C7.94439 4.49509 7.78261 4.33331 7.58328 4.33331Z"
fill="black"
/>
<path
d="M7.58328 4.33331C7.38395 4.33331 7.22217 4.49509 7.22217 4.69442V7.58331C7.22217 7.78265 7.38395 7.94442 7.58328 7.94442C7.78261 7.94442 7.94439 7.78265 7.94439 7.58331V4.69442C7.94439 4.49509 7.78261 4.33331 7.58328 4.33331Z"
fill="black"
/>
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

View file

@ -305,7 +305,14 @@
</div>
<MessageOperationsBottomSheet ref="messageOperationsSheet">
<EmojiPicker ref="emojiPicker" @select="emojiSelected" :i18n="i18nEmoji"/>
<EmojiPicker ref="emojiPicker"
@select="emojiSelected"
:additional-groups="additionalEmojiGroups"
:group-names="emojiGroupNames"
:group-icons="additionalEmojiGroupIcons"
:group-order="['recently_used']"
disable-skin-tones
:static-texts="{ placeholder: $t('emoji.search')}"/>
</MessageOperationsBottomSheet>
<StickerPickerBottomSheet ref="stickerPickerSheet" v-on:selectSticker="sendSticker" />
@ -358,6 +365,7 @@
<script>
import { TimelineWindow, EventTimeline } from "matrix-js-sdk";
import { toRaw } from "vue";
import util, { ROOM_TYPE_VOICE_MODE, ROOM_TYPE_FILE_MODE, ROOM_TYPE_CHANNEL } from "../plugins/utils";
import MessageOperations from "./messages/MessageOperations.vue";
import ChatHeader from "./ChatHeader";
@ -388,8 +396,10 @@ import { imageSize } from "image-size";
import prettyBytes from "pretty-bytes";
import RoomExport from "./RoomExport.vue";
import EmojiPicker from 'vue3-emoji-picker';
import 'vue3-emoji-picker/css';
import emitter from 'tiny-emitter/instance';
import { markRaw } from "vue";
import timerIcon from '@/assets/icons/ic_timer.svg';
const READ_RECEIPT_TIMEOUT = 5000; /* How long a message must have been visible before the read marker is updated */
const WINDOW_BUFFER_SIZE = 0.3; /** Relative window height of when we start paginating. Always keep this much loaded before and after our scroll position! */
@ -512,19 +522,16 @@ export default {
opStyle: "",
isEmojiQuickReaction: true,
i18nEmoji: {
search: this.$t("emoji.search"),
categories: {
Activity: this.$t("emoji.categories.activity"),
Flags: this.$t("emoji.categories.flags"),
Foods: this.$t("emoji.categories.foods"),
Frequently: this.$t("emoji.categories.frequently"),
Objects: this.$t("emoji.categories.objects"),
Nature: this.$t("emoji.categories.nature"),
Peoples: this.$t("emoji.categories.peoples"),
Symbols: this.$t("emoji.categories.symbols"),
Places: this.$t("emoji.categories.places")
}
emojiGroupNames: {
"smileys_people": this.$t("emoji.categories.peoples"),
"animals_nature": this.$t("emoji.categories.nature"),
"food_drink": this.$t("emoji.categories.foods"),
"activities": this.$t("emoji.categories.activity"),
"travel_places": this.$t("emoji.categories.places"),
"objects": this.$t("emoji.categories.objects"),
"symbols": this.$t("emoji.categories.symbols"),
"flags": this.$t("emoji.categories.flags"),
"recently_used": this.$t("emoji.categories.frequently"),
},
/**
@ -570,6 +577,12 @@ export default {
},
computed: {
additionalEmojiGroups() {
return { 'recently_used': this.recentEmojis }
},
additionalEmojiGroupIcons() {
return { 'recently_used': timerIcon }
},
latestReply() {
const contents = this.replyToEvent ? this.replyToEvent.getContent().body : "";
const contentArr = contents.split("\n").reverse();
@ -1229,7 +1242,6 @@ export default {
* Triggered when our "long tap" timer hits.
*/
touchTimerElapsed() {
this.updateRecentEmojis();
this.showContextMenu = true;
},
@ -1817,14 +1829,25 @@ export default {
if (this.selectedEvent) {
const event = this.selectedEvent;
this.selectedEvent = null;
this.sendQuickReaction({ reaction: e.data, event: event });
this.sendQuickReaction({ reaction: e.i, event: event });
}
} else {
// When text input emoji picker is clicked
this.currentInput = `${this.currentInput} ${e.data}`;
this.currentInput = `${this.currentInput} ${e.i}`;
this.$refs.messageInput.focus();
}
let emojis = this.recentEmojis;
const existingIdx = emojis.findIndex(emoji => emoji.u == e.u);
if (existingIdx >= 0) {
emojis.splice(existingIdx, 1);
}
emojis.splice(0, 0, markRaw(e));
if (emojis.length > 5) {
emojis.splice(5, emojis.length - 5);
}
this.recentEmojis = emojis;
this.showEmojiPicker = false;
this.$refs.messageOperationsSheet.close();
},
@ -1895,7 +1918,6 @@ export default {
this.showContextMenu = false;
this.$nextTick(() => {
this.selectedEvent = event;
this.updateRecentEmojis();
this.showContextMenuAnchor = e.anchor;
this.showContextMenu = true;
})
@ -2033,20 +2055,6 @@ export default {
});
},
updateRecentEmojis() {
if (this.$refs.emojiPicker) {
this.recentEmojis = this.$refs.emojiPicker.mapEmojis["Frequently"];
if (this.recentEmojis.length < 20) {
let peoples = this.$refs.emojiPicker.mapEmojis["Peoples"];
for (var p of peoples) {
this.recentEmojis.push(p);
}
}
return;
}
this.recentEmojis = [];
},
formatBytes(bytes) {
return prettyBytes(bytes);
},

View file

@ -111,6 +111,8 @@ export default {
}
.card {
padding: 0px !important;
display: flex;
flex-direction: column;
&[data-state="half"] {
top: 100px !important;

View file

@ -58,7 +58,7 @@ import ReadMarker from "./messages/ReadMarker.vue";
import roomDisplayOptionsMixin from "./roomDisplayOptionsMixin";
import roomTypeMixin from "./roomTypeMixin";
export const ROOM_READ_MARKER_EVENT_PLACEHOLDER = { getId: () => "ROOM_READ_MARKER" };
export const ROOM_READ_MARKER_EVENT_PLACEHOLDER = { getId: () => "ROOM_READ_MARKER", getTs: () => Date.now() };
export default {
mixins: [ roomDisplayOptionsMixin, roomTypeMixin ],

View file

@ -1,8 +1,8 @@
<template>
<div :class="{'message-operations':true,'incoming':incoming,'outgoing':!incoming}">
<template v-for="(item,index) in getEmojis" :key="item.data">
<v-btn v-if="userCanSendReactionAndAnswerPoll && index < maxRecents" id="btn-quick-reaction" icon @click.stop="addQuickReaction(item.data)" class="ma-0 pa-0" density="compact">
<span class="recent-emoji">{{ item.data }}</span>
<template v-for="(item,index) in getEmojis" :key="item.i">
<v-btn v-if="userCanSendReactionAndAnswerPoll && index < maxRecents" id="btn-quick-reaction" icon @click.stop="addQuickReaction(item.i)" class="ma-0 pa-0" density="compact">
<span class="recent-emoji">{{ item.i }}</span>
</v-btn>
</template>
<v-btn v-if="userCanSendReactionAndAnswerPoll" id="btn-more" icon @click.stop="more" class="ma-0 pa-0">

View file

@ -12,6 +12,12 @@ import aesjs from "aes-js";
import localizedFormat from "dayjs/plugin/localizedFormat";
import duration from "dayjs/plugin/duration";
import i18n from "./lang";
import {
toRaw,
isRef,
isReactive,
isProxy,
} from 'vue';
export const STATE_EVENT_ROOM_DELETION_NOTICE = "im.keanu.room_deletion_notice";
export const STATE_EVENT_ROOM_DELETED = "im.keanu.room_deleted";
@ -782,10 +788,10 @@ class Util {
getDefaultAvatars() {
var images = [];
const modules = import.meta.glob("@/assets/avatars/*.{jpeg,jpg,png}", {
query: '?url',
import: 'default',
eager: true
const modules = import.meta.glob("@/assets/avatars/*.{jpeg,jpg,png}", {
query: "?url",
import: "default",
eager: true,
});
Object.keys(modules).map((path) => {
var name = path.split("_")[1];
@ -1180,7 +1186,7 @@ class Util {
* Possibly convert numerals to local representation (currently only for "bo" locale)
* @param str String in which to convert numerals [0-9]
* @returns converted string
*/
*/
toLocalNumbers = (str) => {
if (i18n.locale == "my") {
// Translate to burmese numerals
@ -1210,5 +1216,24 @@ class Util {
return str;
};
}
deepToRaw(sourceObj) {
const objectIterator = (input) => {
if (Array.isArray(input)) {
return input.map((item) => objectIterator(item));
}
if (isRef(input) || isReactive(input) || isProxy(input)) {
return objectIterator(toRaw(input));
}
if (input && typeof input === "object") {
return Object.keys(input).reduce((acc, key) => {
acc[key] = objectIterator(input[key]);
return acc;
}, {});
}
return input;
};
return objectIterator(sourceObj);
}
};
export default new Util();