1
0
mirror of https://github.com/misskey-dev/misskey.git synced 2026-05-21 20:25:36 +02:00

feat(frontend): 絵文字をミュート可能にする機能 (#15966)

* wip ( 絵文字ミュートの基礎実装, PoC )

* refactor: 絵文字のmute/unmute処理の共通化

* SPDX

* リアクションからも絵文字ミュート可能に

* emojiMute/emojiUnmute

* replace resource of emojiMute

* add vitest preferstate for mutedEmojis

* add vitest to preferReactive

* 混入削除

* Fix typo (mutedEmojis -> mutingEmojis)

* reactiveやめる

* add時の判定ミスを修正

* Add CHANGELOG

* Revert "reactiveやめる"

This reverts commit 442742c371.

* Update Changelog
This commit is contained in:
taichan
2025-05-12 10:00:06 +09:00
committed by GitHub
parent b18d6b4cef
commit 5bc52b6743
13 changed files with 409 additions and 36 deletions

View File

@@ -0,0 +1,105 @@
<!--
SPDX-FileCopyrightText: syuilo and misskey-project
SPDX-License-Identifier: AGPL-3.0-only
-->
<template>
<div :class="$style.emojis">
<div v-for="emoji in emojis" :key="`emojiMute-${emoji}`" :class="$style.emoji" @click="onEmojiClick($event, emoji)">
<MkCustomEmoji
v-if="emoji.startsWith(':')"
:name="customEmojiName(emoji)"
:host="customEmojiHost(emoji)"
:normal="true"
:menu="false"
:menuReaction="false"
:ignoreMuted="true"
/>
<MkEmoji
v-else
:emoji="emoji"
:menu="false"
:menuReaction="false"
:ignoreMuted="true"
></MkEmoji>
</div>
</div>
<MkButton primary inline @click="add"><i class="ti ti-plus"></i> {{ i18n.ts.add }}</MkButton>
</template>
<script lang="ts" setup>
import type { MenuItem } from '@/types/menu';
import MkButton from '@/components/MkButton.vue';
import * as os from '@/os.js';
import { i18n } from '@/i18n.js';
import { prefer } from '@/preferences.js';
import {
mute as muteEmoji,
unmute as unmuteEmoji,
extractCustomEmojiName as customEmojiName,
extractCustomEmojiHost as customEmojiHost,
} from '@/utility/emoji-mute.js';
const emojis = prefer.model('mutingEmojis');
function getHTMLElement(ev: MouseEvent): HTMLElement {
const target = ev.currentTarget ?? ev.target;
return target as HTMLElement;
}
function add(ev: MouseEvent) {
os.pickEmoji(getHTMLElement(ev), { showPinned: false }).then((emoji) => {
if (emoji) {
muteEmoji(emoji);
}
});
}
function onEmojiClick(ev: MouseEvent, emoji: string) {
const menuItems : MenuItem[] = [{
type: 'label',
text: emoji,
}, {
text: i18n.ts.emojiUnmute,
icon: 'ti ti-mood-off',
action: () => unmute(emoji),
}];
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
}
function unmute(emoji: string) {
os.confirm({
type: 'question',
title: i18n.tsx.unmuteX({ x: emoji }),
}).then(({ canceled }) => {
if (canceled) {
return;
}
unmuteEmoji(emoji);
});
}
</script>
<style module>
.emojis {
display: flex;
flex-wrap: wrap;
align-items: center;
gap: 4px;
&:empty {
display: none;
}
}
.emoji {
display: inline-flex;
height: 42px;
padding: 0 6px;
font-size: 1.5em;
border-radius: 6px;
align-items: center;
justify-content: center;
background: var(--MI_THEME-buttonBg);
}
</style>

View File

@@ -49,6 +49,20 @@ SPDX-License-Identifier: AGPL-3.0-only
</MkFolder>
</SearchMarker>
<SearchMarker
:label="i18n.ts.emojiMute"
:keywords="['emoji', 'mute', 'hide']"
>
<MkFolder>
<template #icon><i class="ti ti-mood-off"></i></template>
<template #label>{{ i18n.ts.emojiMute }}</template>
<div class="_gaps_m">
<XEmojiMute/>
</div>
</mkfolder>
</SearchMarker>
<SearchMarker
:label="i18n.ts.instanceMute"
:keywords="['note', 'server', 'instance', 'host', 'federation', 'mute', 'hide']"
@@ -163,6 +177,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<script lang="ts" setup>
import { ref, computed, watch } from 'vue';
import XEmojiMute from './mute-block.emoji-mute.vue';
import XInstanceMute from './mute-block.instance-mute.vue';
import XWordMute from './mute-block.word-mute.vue';
import MkPagination from '@/components/MkPagination.vue';