From 5d9f3cfdc3a20b23bc8e51e0603135066b13d54e Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 3 Nov 2023 17:34:05 +0900 Subject: [PATCH] :v: --- packages/frontend/src/components/MkNote.vue | 107 +--------------- .../src/components/MkNoteDetailed.vue | 69 +--------- .../frontend/src/scripts/get-note-menu.ts | 120 ++++++++++++++++++ 3 files changed, 128 insertions(+), 168 deletions(-) diff --git a/packages/frontend/src/components/MkNote.vue b/packages/frontend/src/components/MkNote.vue index 91d12683dd..30a68f38f2 100644 --- a/packages/frontend/src/components/MkNote.vue +++ b/packages/frontend/src/components/MkNote.vue @@ -159,7 +159,7 @@ import { reactionPicker } from '@/scripts/reaction-picker.js'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; -import { getAbuseNoteMenu, getCopyNoteLinkMenu, getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu.js'; +import { getAbuseNoteMenu, getCopyNoteLinkMenu, getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/scripts/get-note-menu.js'; import { useNoteCapture } from '@/scripts/use-note-capture.js'; import { deepClone } from '@/scripts/clone.js'; import { useTooltip } from '@/scripts/use-tooltip.js'; @@ -275,113 +275,14 @@ if (!props.mock) { }); } -type Visibility = 'public' | 'home' | 'followers' | 'specified'; - -// defaultStore.state.visibilityがstringなためstringも受け付けている -function smallerVisibility(a: Visibility | string, b: Visibility | string): Visibility { - if (a === 'specified' || b === 'specified') return 'specified'; - if (a === 'followers' || b === 'followers') return 'followers'; - if (a === 'home' || b === 'home') return 'home'; - // if (a === 'public' || b === 'public') - return 'public'; -} - function renote(viaKeyboard = false) { pleaseLogin(); showMovedDialog(); - const channelRenoteItems: MenuItem[] = []; - const normalRenoteItems: MenuItem[] = []; - - if (appearNote.channel) { - channelRenoteItems.push(...[{ - text: i18n.ts.inChannelRenote, - icon: 'ti ti-repeat', - action: () => { - const el = renoteButton.value as HTMLElement | null | undefined; - if (el) { - const rect = el.getBoundingClientRect(); - const x = rect.left + (el.offsetWidth / 2); - const y = rect.top + (el.offsetHeight / 2); - os.popup(MkRippleEffect, { x, y }, {}, 'end'); - } - - if (!props.mock) { - os.api('notes/create', { - renoteId: appearNote.id, - channelId: appearNote.channelId, - }).then(() => { - os.toast(i18n.ts.renoted); - }); - } - }, - }, { - text: i18n.ts.inChannelQuote, - icon: 'ti ti-quote', - action: () => { - if (!props.mock) { - os.post({ - renote: appearNote, - channel: appearNote.channel, - }); - } - }, - }]); - } - - if (!appearNote.channel || appearNote.channel?.allowRenoteToExternal) { - normalRenoteItems.push(...[{ - text: i18n.ts.renote, - icon: 'ti ti-repeat', - action: () => { - const el = renoteButton.value as HTMLElement | null | undefined; - if (el) { - const rect = el.getBoundingClientRect(); - const x = rect.left + (el.offsetWidth / 2); - const y = rect.top + (el.offsetHeight / 2); - os.popup(MkRippleEffect, { x, y }, {}, 'end'); - } - - const configuredVisibility = defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility; - const localOnly = defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly; - - let visibility = appearNote.visibility; - visibility = smallerVisibility(visibility, configuredVisibility); - if (appearNote.channel?.isSensitive) { - visibility = smallerVisibility(visibility, 'home'); - } - - if (!props.mock) { - os.api('notes/create', { - localOnly, - visibility, - renoteId: appearNote.id, - }).then(() => { - os.toast(i18n.ts.renoted); - }); - } - }, - }, (props.mock) ? undefined : { - text: i18n.ts.quote, - icon: 'ti ti-quote', - action: () => { - os.post({ - renote: appearNote, - }); - }, - }]); - } - - // nullを挟むことで区切り線を出せる - const renoteItems = [ - ...channelRenoteItems, - ...(channelRenoteItems.length > 0 && normalRenoteItems.length > 0) ? [null] : [], - ...normalRenoteItems, - ]; - - os.popupMenu(renoteItems, renoteButton.value, { + const { menu } = getRenoteMenu({ note: note, renoteButton, mock: props.mock }); + os.popupMenu(menu, renoteButton.value, { viaKeyboard, - }); + }).then(focus); } function reply(viaKeyboard = false): void { diff --git a/packages/frontend/src/components/MkNoteDetailed.vue b/packages/frontend/src/components/MkNoteDetailed.vue index d34d35a0c3..9e9b1035d7 100644 --- a/packages/frontend/src/components/MkNoteDetailed.vue +++ b/packages/frontend/src/components/MkNoteDetailed.vue @@ -206,7 +206,7 @@ import { reactionPicker } from '@/scripts/reaction-picker.js'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; import { $i } from '@/account.js'; import { i18n } from '@/i18n.js'; -import { getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu.js'; +import { getNoteClipMenu, getNoteMenu, getRenoteMenu } from '@/scripts/get-note-menu.js'; import { useNoteCapture } from '@/scripts/use-note-capture.js'; import { deepClone } from '@/scripts/clone.js'; import { useTooltip } from '@/scripts/use-tooltip.js'; @@ -325,71 +325,10 @@ function renote(viaKeyboard = false) { pleaseLogin(); showMovedDialog(); - let items = [] as MenuItem[]; - - if (appearNote.channel) { - items = items.concat([{ - text: i18n.ts.inChannelRenote, - icon: 'ti ti-repeat', - action: () => { - const el = renoteButton.value as HTMLElement | null | undefined; - if (el) { - const rect = el.getBoundingClientRect(); - const x = rect.left + (el.offsetWidth / 2); - const y = rect.top + (el.offsetHeight / 2); - os.popup(MkRippleEffect, { x, y }, {}, 'end'); - } - - os.api('notes/create', { - renoteId: appearNote.id, - channelId: appearNote.channelId, - }).then(() => { - os.toast(i18n.ts.renoted); - }); - }, - }, { - text: i18n.ts.inChannelQuote, - icon: 'ti ti-quote', - action: () => { - os.post({ - renote: appearNote, - channel: appearNote.channel, - }); - }, - }, null]); - } - - items = items.concat([{ - text: i18n.ts.renote, - icon: 'ti ti-repeat', - action: () => { - const el = renoteButton.value as HTMLElement | null | undefined; - if (el) { - const rect = el.getBoundingClientRect(); - const x = rect.left + (el.offsetWidth / 2); - const y = rect.top + (el.offsetHeight / 2); - os.popup(MkRippleEffect, { x, y }, {}, 'end'); - } - - os.api('notes/create', { - renoteId: appearNote.id, - }).then(() => { - os.toast(i18n.ts.renoted); - }); - }, - }, { - text: i18n.ts.quote, - icon: 'ti ti-quote', - action: () => { - os.post({ - renote: appearNote, - }); - }, - }]); - - os.popupMenu(items, renoteButton.value, { + const { menu } = getRenoteMenu({ note: note, renoteButton }); + os.popupMenu(menu, renoteButton.value, { viaKeyboard, - }); + }).then(focus); } function reply(viaKeyboard = false): void { diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index e399145fc9..d0753872ff 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -17,6 +17,7 @@ import { miLocalStorage } from '@/local-storage.js'; import { getUserMenu } from '@/scripts/get-user-menu.js'; import { clipsCache } from '@/cache.js'; import { MenuItem } from '@/types/menu.js'; +import MkRippleEffect from '@/components/MkRippleEffect.vue'; export async function getNoteClipMenu(props: { note: Misskey.entities.Note; @@ -418,3 +419,122 @@ export function getNoteMenu(props: { cleanup, }; } + +type Visibility = 'public' | 'home' | 'followers' | 'specified'; + +// defaultStore.state.visibilityがstringなためstringも受け付けている +function smallerVisibility(a: Visibility | string, b: Visibility | string): Visibility { + if (a === 'specified' || b === 'specified') return 'specified'; + if (a === 'followers' || b === 'followers') return 'followers'; + if (a === 'home' || b === 'home') return 'home'; + // if (a === 'public' || b === 'public') + return 'public'; +} + +export function getRenoteMenu(props: { + note: Misskey.entities.Note; + renoteButton: Ref; + mock?: boolean; +}) { + const isRenote = ( + props.note.renote != null && + props.note.text == null && + props.note.fileIds.length === 0 && + props.note.poll == null + ); + + const appearNote = isRenote ? props.note.renote as Misskey.entities.Note : props.note; + + const channelRenoteItems: MenuItem[] = []; + const normalRenoteItems: MenuItem[] = []; + + if (appearNote.channel) { + channelRenoteItems.push(...[{ + text: i18n.ts.inChannelRenote, + icon: 'ti ti-repeat', + action: () => { + const el = props.renoteButton.value as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(MkRippleEffect, { x, y }, {}, 'end'); + } + + if (!props.mock) { + os.api('notes/create', { + renoteId: appearNote.id, + channelId: appearNote.channelId, + }).then(() => { + os.toast(i18n.ts.renoted); + }); + } + }, + }, { + text: i18n.ts.inChannelQuote, + icon: 'ti ti-quote', + action: () => { + if (!props.mock) { + os.post({ + renote: appearNote, + channel: appearNote.channel, + }); + } + }, + }]); + } + + if (!appearNote.channel || appearNote.channel?.allowRenoteToExternal) { + normalRenoteItems.push(...[{ + text: i18n.ts.renote, + icon: 'ti ti-repeat', + action: () => { + const el = props.renoteButton.value as HTMLElement | null | undefined; + if (el) { + const rect = el.getBoundingClientRect(); + const x = rect.left + (el.offsetWidth / 2); + const y = rect.top + (el.offsetHeight / 2); + os.popup(MkRippleEffect, { x, y }, {}, 'end'); + } + + const configuredVisibility = defaultStore.state.rememberNoteVisibility ? defaultStore.state.visibility : defaultStore.state.defaultNoteVisibility; + const localOnly = defaultStore.state.rememberNoteVisibility ? defaultStore.state.localOnly : defaultStore.state.defaultNoteLocalOnly; + + let visibility = appearNote.visibility; + visibility = smallerVisibility(visibility, configuredVisibility); + if (appearNote.channel?.isSensitive) { + visibility = smallerVisibility(visibility, 'home'); + } + + if (!props.mock) { + os.api('notes/create', { + localOnly, + visibility, + renoteId: appearNote.id, + }).then(() => { + os.toast(i18n.ts.renoted); + }); + } + }, + }, (props.mock) ? undefined : { + text: i18n.ts.quote, + icon: 'ti ti-quote', + action: () => { + os.post({ + renote: appearNote, + }); + }, + }]); + } + + // nullを挟むことで区切り線を出せる + const renoteItems = [ + ...normalRenoteItems, + ...(channelRenoteItems.length > 0 && normalRenoteItems.length > 0) ? [null] : [], + ...channelRenoteItems, + ]; + + return { + menu: renoteItems, + }; +}