From 7d1da29c48f060820809fb3278613fdafdd1edde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E3=81=8B=E3=81=A3=E3=81=93=E3=81=8B=E3=82=8A?= <67428053+kakkokari-gtyih@users.noreply.github.com> Date: Sat, 8 Nov 2025 13:11:52 +0900 Subject: [PATCH] enhance(frontend): implement mute setting dialog for enhanced mute (#16763) * enhance(frontend): implement mute setting dialog for enhanced mute * remove unnecessary defs * fix description * fix lint --- locales/index.d.ts | 16 ++ locales/ja-JP.yml | 4 + .../src/components/MkMuteSettingDialog.vue | 159 ++++++++++++++++++ .../frontend/src/utility/get-user-menu.ts | 41 +++-- 4 files changed, 199 insertions(+), 21 deletions(-) create mode 100644 packages/frontend/src/components/MkMuteSettingDialog.vue diff --git a/locales/index.d.ts b/locales/index.d.ts index 0d0c1cfc53..1f6a79699e 100644 --- a/locales/index.d.ts +++ b/locales/index.d.ts @@ -594,6 +594,18 @@ export interface Locale extends ILocale { * ミュート */ "mute": string; + /** + * ミュートする範囲 + */ + "muteType": string; + /** + * ミュートを適用する範囲を設定できます。「タイムラインのみ」に設定すると、タイムラインや検索結果上からは見えなくなりますが、通知は受け取ります。 + */ + "muteTypeDescription": string; + /** + * タイムラインのみ + */ + "muteTypeTimeline": string; /** * ミュート解除 */ @@ -5637,6 +5649,10 @@ export interface Locale extends ILocale { * ゼロ埋め */ "zeroPadding": string; + /** + * ミュートしますか? + */ + "muteConfirm": string; "_imageEditing": { "_vars": { /** diff --git a/locales/ja-JP.yml b/locales/ja-JP.yml index e40c083cff..28b7fa2474 100644 --- a/locales/ja-JP.yml +++ b/locales/ja-JP.yml @@ -144,6 +144,9 @@ markAsSensitive: "センシティブとして設定" unmarkAsSensitive: "センシティブを解除する" enterFileName: "ファイル名を入力" mute: "ミュート" +muteType: "ミュートする範囲" +muteTypeDescription: "ミュートを適用する範囲を設定できます。「タイムラインのみ」に設定すると、タイムラインや検索結果上からは見えなくなりますが、通知は受け取ります。" +muteTypeTimeline: "タイムラインのみ" unmute: "ミュート解除" renoteMute: "リノートをミュート" renoteUnmute: "リノートのミュートを解除" @@ -1404,6 +1407,7 @@ youAreAdmin: "あなたは管理者です" frame: "フレーム" presets: "プリセット" zeroPadding: "ゼロ埋め" +muteConfirm: "ミュートしますか?" _imageEditing: _vars: diff --git a/packages/frontend/src/components/MkMuteSettingDialog.vue b/packages/frontend/src/components/MkMuteSettingDialog.vue new file mode 100644 index 0000000000..5efc734ae7 --- /dev/null +++ b/packages/frontend/src/components/MkMuteSettingDialog.vue @@ -0,0 +1,159 @@ + + + + + + + + + + + {{ i18n.ts.muteConfirm }} + + + + + {{ i18n.ts.mutePeriod }} + + + {{ i18n.ts.muteType }} + {{ i18n.ts.muteTypeDescription }} + + + + {{ i18n.ts.cancel }} + {{ i18n.ts.ok }} + + + + + + + + + + diff --git a/packages/frontend/src/utility/get-user-menu.ts b/packages/frontend/src/utility/get-user-menu.ts index 9b2c53360c..64d4b421a3 100644 --- a/packages/frontend/src/utility/get-user-menu.ts +++ b/packages/frontend/src/utility/get-user-menu.ts @@ -20,6 +20,18 @@ import { mainRouter } from '@/router.js'; import { genEmbedCode } from '@/utility/get-embed-code.js'; import { prefer } from '@/preferences.js'; import { getPluginHandlers } from '@/plugin.js'; +import type { MkMuteSettingDialogDoneEvent } from '@/components/MkMuteSettingDialog.vue'; + +function muteConfirm(): Promise { + return new Promise(resolve => { + const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkMuteSettingDialog.vue')), {}, { + done: result => { + resolve(result ? result : { canceled: true }); + }, + closed: () => dispose(), + }); + }); +} export function getUserMenu(user: Misskey.entities.UserDetailed, router: Router = mainRouter) { const meId = $i ? $i.id : null; @@ -34,33 +46,20 @@ export function getUserMenu(user: Misskey.entities.UserDetailed, router: Router user.isMuted = false; }); } else { - const { canceled, result: period } = await os.select({ - title: i18n.ts.mutePeriod, - items: [{ - value: 'indefinitely', label: i18n.ts.indefinitely, - }, { - value: 'tenMinutes', label: i18n.ts.tenMinutes, - }, { - value: 'oneHour', label: i18n.ts.oneHour, - }, { - value: 'oneDay', label: i18n.ts.oneDay, - }, { - value: 'oneWeek', label: i18n.ts.oneWeek, - }], - default: 'indefinitely', - }); - if (canceled) return; + const res = await muteConfirm(); + if (res.canceled) return; - const expiresAt = period === 'indefinitely' ? null - : period === 'tenMinutes' ? Date.now() + (1000 * 60 * 10) - : period === 'oneHour' ? Date.now() + (1000 * 60 * 60) - : period === 'oneDay' ? Date.now() + (1000 * 60 * 60 * 24) - : period === 'oneWeek' ? Date.now() + (1000 * 60 * 60 * 24 * 7) + const expiresAt = res.period === 'indefinitely' ? null + : res.period === 'tenMinutes' ? Date.now() + (1000 * 60 * 10) + : res.period === 'oneHour' ? Date.now() + (1000 * 60 * 60) + : res.period === 'oneDay' ? Date.now() + (1000 * 60 * 60 * 24) + : res.period === 'oneWeek' ? Date.now() + (1000 * 60 * 60 * 24 * 7) : null; os.apiWithDialog('mute/create', { userId: user.id, expiresAt, + mutingType: res.type, }).then(() => { user.isMuted = true; });