enhance(client): show Unicode emoji tooltip with its name (#9399)
* enhance(client): show Unicode emoji tooltip with its name * Update CHANGELOG.md * Update CHANGELOG.md Co-authored-by: tamaina <tamaina@hotmail.co.jp> Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
		
							parent
							
								
									ef1224118c
								
							
						
					
					
						commit
						decde50c86
					
				
					 3 changed files with 30 additions and 8 deletions
				
			
		|  | @ -3,7 +3,7 @@ | ||||||
| 	<div class="bqxuuuey"> | 	<div class="bqxuuuey"> | ||||||
| 		<div class="reaction"> | 		<div class="reaction"> | ||||||
| 			<XReactionIcon :reaction="reaction" :custom-emojis="emojis" class="icon" :no-style="true"/> | 			<XReactionIcon :reaction="reaction" :custom-emojis="emojis" class="icon" :no-style="true"/> | ||||||
| 			<div class="name">{{ reaction.replace('@.', '') }}</div> | 			<div class="name">{{ getReactionName(reaction) }}</div> | ||||||
| 		</div> | 		</div> | ||||||
| 		<div class="users"> | 		<div class="users"> | ||||||
| 			<div v-for="u in users" :key="u.id" class="user"> | 			<div v-for="u in users" :key="u.id" class="user"> | ||||||
|  | @ -20,6 +20,7 @@ | ||||||
| import { } from 'vue'; | import { } from 'vue'; | ||||||
| import MkTooltip from './MkTooltip.vue'; | import MkTooltip from './MkTooltip.vue'; | ||||||
| import XReactionIcon from '@/components/MkReactionIcon.vue'; | import XReactionIcon from '@/components/MkReactionIcon.vue'; | ||||||
|  | import { getEmojiName } from '@/scripts/emojilist'; | ||||||
| 
 | 
 | ||||||
| defineProps<{ | defineProps<{ | ||||||
| 	showing: boolean; | 	showing: boolean; | ||||||
|  | @ -33,6 +34,14 @@ defineProps<{ | ||||||
| const emit = defineEmits<{ | const emit = defineEmits<{ | ||||||
| 	(ev: 'closed'): void; | 	(ev: 'closed'): void; | ||||||
| }>(); | }>(); | ||||||
|  | 
 | ||||||
|  | function getReactionName(reaction: string): string { | ||||||
|  | 	const trimLocal = reaction.replace('@.', ''); | ||||||
|  | 	if (trimLocal.startsWith(':')) { | ||||||
|  | 		return trimLocal; | ||||||
|  | 	} | ||||||
|  | 	return getEmojiName(reaction) ?? reaction; | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|  |  | ||||||
|  | @ -1,17 +1,18 @@ | ||||||
| <template> | <template> | ||||||
| <img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/> | <img v-if="customEmoji" class="mk-emoji custom" :class="{ normal, noStyle }" :src="url" :alt="alt" :title="alt" decoding="async"/> | ||||||
| <img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" :alt="alt" :title="alt" decoding="async"/> | <img v-else-if="char && !useOsNativeEmojis" class="mk-emoji" :src="url" decoding="async" @pointerenter="computeTitle"/> | ||||||
| <span v-else-if="char && useOsNativeEmojis">{{ char }}</span> | <span v-else-if="char && useOsNativeEmojis" :alt="alt" @pointerenter="computeTitle">{{ char }}</span> | ||||||
| <span v-else>{{ emoji }}</span> | <span v-else>{{ emoji }}</span> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts" setup> | <script lang="ts" setup> | ||||||
| import { computed, ref, watch } from 'vue'; | import { computed } from 'vue'; | ||||||
| import { CustomEmoji } from 'misskey-js/built/entities'; | import { CustomEmoji } from 'misskey-js/built/entities'; | ||||||
| import { getStaticImageUrl } from '@/scripts/get-static-image-url'; | import { getStaticImageUrl } from '@/scripts/get-static-image-url'; | ||||||
| import { char2filePath } from '@/scripts/twemoji-base'; | import { char2filePath } from '@/scripts/twemoji-base'; | ||||||
| import { defaultStore } from '@/store'; | import { defaultStore } from '@/store'; | ||||||
| import { instance } from '@/instance'; | import { instance } from '@/instance'; | ||||||
|  | import { getEmojiName } from '@/scripts/emojilist'; | ||||||
| 
 | 
 | ||||||
| const props = defineProps<{ | const props = defineProps<{ | ||||||
| 	emoji: string; | 	emoji: string; | ||||||
|  | @ -22,20 +23,28 @@ const props = defineProps<{ | ||||||
| }>(); | }>(); | ||||||
| 
 | 
 | ||||||
| const isCustom = computed(() => props.emoji.startsWith(':')); | const isCustom = computed(() => props.emoji.startsWith(':')); | ||||||
| const char = computed(() => isCustom.value ? null : props.emoji); | const char = computed(() => isCustom.value ? undefined : props.emoji); | ||||||
| const useOsNativeEmojis = computed(() => defaultStore.state.useOsNativeEmojis && !props.isReaction); | const useOsNativeEmojis = computed(() => defaultStore.state.useOsNativeEmojis && !props.isReaction); | ||||||
| const ce = computed(() => props.customEmojis ?? instance.emojis ?? []); | const ce = computed(() => props.customEmojis ?? instance.emojis ?? []); | ||||||
| const customEmoji = computed(() => isCustom.value ? ce.value.find(x => x.name === props.emoji.substr(1, props.emoji.length - 2)) : null); | const customEmoji = computed(() => isCustom.value ? ce.value.find(x => x.name === props.emoji.substr(1, props.emoji.length - 2)) : undefined); | ||||||
| const url = computed(() => { | const url = computed(() => { | ||||||
| 	if (char.value) { | 	if (char.value) { | ||||||
| 		return char2filePath(char.value); | 		return char2filePath(char.value); | ||||||
| 	} else { | 	} else { | ||||||
|  | 		const rawUrl = (customEmoji.value as CustomEmoji).url; | ||||||
| 		return defaultStore.state.disableShowingAnimatedImages | 		return defaultStore.state.disableShowingAnimatedImages | ||||||
| 			? getStaticImageUrl(customEmoji.value.url) | 			? getStaticImageUrl(rawUrl) | ||||||
| 			: customEmoji.value.url; | 			: rawUrl; | ||||||
| 	} | 	} | ||||||
| }); | }); | ||||||
| const alt = computed(() => customEmoji.value ? `:${customEmoji.value.name}:` : char.value); | const alt = computed(() => customEmoji.value ? `:${customEmoji.value.name}:` : char.value); | ||||||
|  | 
 | ||||||
|  | function computeTitle(event: PointerEvent): void { | ||||||
|  | 	const title = customEmoji.value | ||||||
|  | 		? `:${customEmoji.value.name}:` | ||||||
|  | 		: (getEmojiName(char.value as string) ?? char.value as string); | ||||||
|  | 	(event.target as HTMLElement).title = title; | ||||||
|  | } | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|  |  | ||||||
|  | @ -11,3 +11,7 @@ export type UnicodeEmojiDef = { | ||||||
| import _emojilist from '../emojilist.json'; | import _emojilist from '../emojilist.json'; | ||||||
| 
 | 
 | ||||||
| export const emojilist = _emojilist as UnicodeEmojiDef[]; | export const emojilist = _emojilist as UnicodeEmojiDef[]; | ||||||
|  | 
 | ||||||
|  | export function getEmojiName(char: string): string | undefined { | ||||||
|  | 	return emojilist.find(emo => emo.char === char)?.name; | ||||||
|  | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue