@@ -3,7 +3,7 @@ import { useDebounceFn, useEventListener, watchImmediate } from '@vueuse/core';
33import type { WalineComment , WalineCommentData , UserInfo } from ' @waline/api' ;
44import { addComment , login , updateComment } from ' @waline/api' ;
55import autosize from ' autosize' ;
6- import type { DeepReadonly } from ' vue' ;
6+ import type { DeepReadonly , CSSProperties } from ' vue' ;
77import {
88 computed ,
99 inject ,
@@ -88,6 +88,35 @@ const gifSearchRef = useTemplateRef<HTMLInputElement>('gif-search');
8888const emoji = ref <DeepReadonly <WalineEmojiConfig >>({ tabs: [], map: {} });
8989const emojiTabIndex = ref (0 );
9090const showEmoji = ref (false );
91+ const previewEmoji = ref (' ' );
92+ const previewStyle = ref <CSSProperties >({});
93+ let leaveTimer: ReturnType <typeof setTimeout >;
94+
95+ const onEmojiHover = (event : MouseEvent , key : string ): void => {
96+ clearTimeout (leaveTimer );
97+ previewEmoji .value = key ;
98+
99+ const target = event .currentTarget as HTMLElement | null ;
100+ const popup = emojiPopupRef .value ;
101+
102+ if (target && popup ) {
103+ const targetRect = target .getBoundingClientRect ();
104+ const popupRect = popup .getBoundingClientRect ();
105+
106+ previewStyle .value = {
107+ left: ` ${targetRect .left - popupRect .left + targetRect .width / 2 }px ` ,
108+ top: ` ${targetRect .top - popupRect .top }px ` ,
109+ transform: ' translate(-50%, -100%)' ,
110+ };
111+ }
112+ };
113+
114+ const onEmojiLeave = (): void => {
115+ leaveTimer = setTimeout (() => {
116+ previewEmoji .value = ' ' ;
117+ }, 50 );
118+ };
119+
91120const showGif = ref (false );
92121const showPreview = ref (false );
93122const previewText = ref (' ' );
@@ -746,13 +775,19 @@ onMounted(() => {
746775 v-for =" (emojiItem , index ) in emoji .tabs "
747776 :key =" emojiItem .name "
748777 >
749- <div v-if =" index === emojiTabIndex" class =" wl-tab-wrapper" >
778+ <div
779+ v-if =" index === emojiTabIndex"
780+ class =" wl-tab-wrapper"
781+ @scroll =" onEmojiLeave"
782+ >
750783 <button
751784 v-for =" key in emojiItem.items"
752785 :key =" key"
753786 type =" button"
754787 :title =" key"
755788 @click =" insert(`:${key}:`)"
789+ @mouseenter =" onEmojiHover($event, key)"
790+ @mouseleave =" onEmojiLeave"
756791 >
757792 <img
758793 v-if =" showEmoji"
@@ -766,6 +801,18 @@ onMounted(() => {
766801 </div >
767802 </template >
768803
804+ <div >
805+ <img
806+ v-if =" previewEmoji"
807+ class =" wl-emoji-preview"
808+ :src =" emoji.map[previewEmoji]"
809+ alt =" preview"
810+ loading =" lazy"
811+ referrerPolicy =" no-referrer"
812+ :style =" previewStyle"
813+ />
814+ </div >
815+
769816 <div v-if =" emoji.tabs.length > 1" class =" wl-tabs" >
770817 <button
771818 v-for =" (emojiItem, index) in emoji.tabs"
0 commit comments