diff --git a/packages/frontend/src/scripts/get-note-menu.ts b/packages/frontend/src/scripts/get-note-menu.ts index 9112daf49f..d113915147 100644 --- a/packages/frontend/src/scripts/get-note-menu.ts +++ b/packages/frontend/src/scripts/get-note-menu.ts @@ -3,7 +3,7 @@ * SPDX-License-Identifier: AGPL-3.0-only */ -import { defineAsyncComponent, Ref, ShallowRef } from 'vue'; +import { defineAsyncComponent, Ref, ShallowRef, shallowRef, ref } from 'vue'; import * as Misskey from 'misskey-js'; import { url } from '@@/js/config.js'; import { claimAchievement } from './achievements.js'; @@ -22,6 +22,7 @@ import MkRippleEffect from '@/components/MkRippleEffect.vue'; import { isSupportShare } from '@/scripts/navigator.js'; import { getAppearNote } from '@/scripts/get-appear-note.js'; import { genEmbedCode } from '@/scripts/get-embed-code.js'; +import { Visibility, boostMenuItems } from '@/scripts/boost-quote.js'; export async function getNoteClipMenu(props: { note: Misskey.entities.Note; @@ -159,7 +160,7 @@ export function getCopyNoteLinkMenu(note: Misskey.entities.Note, text: string): }; } -export function getCopyNoteOriginLinkMenu(note: misskey.entities.Note, text: string): MenuItem { +export function getCopyNoteOriginLinkMenu(note: Misskey.entities.Note, text: string): MenuItem { return { icon: 'ph-link ph-bold ph-lg', text, @@ -377,6 +378,20 @@ export function getNoteMenu(props: { menuItems.push({ type: 'divider' }); + menuItems.push({ + type: 'parent', + icon: 'ti ti-repeat', + text: i18n.ts.renote, + children: () => getNewRenoteMenu(appearNote), + }) + + menuItems.push({ + type: 'parent', + icon: 'ti ti-paperclip', + text: i18n.ts.clip, + children: () => getNoteClipMenu(props), + }); + menuItems.push(statePromise.then(state => state.isFavorited ? { icon: 'ti ti-star-off', text: i18n.ts.unfavorite, @@ -387,13 +402,6 @@ export function getNoteMenu(props: { action: () => toggleFavorite(true), })); - menuItems.push({ - type: 'parent', - icon: 'ti ti-paperclip', - text: i18n.ts.clip, - children: () => getNoteClipMenu(props), - }); - menuItems.push(statePromise.then(state => state.isMutedThread ? { icon: 'ti ti-message-off', text: i18n.ts.unmuteThread, @@ -574,6 +582,83 @@ function smallerVisibility(a: Visibility, b: Visibility): Visibility { return 'public'; } +export async function getNewRenoteMenu(appearNote: Misskey.entities.Note): Promise { + const renoteItems: MenuItem[] = []; + + const renoteFunc = (visibility?: Visibility, localOnly?: boolean, channel?) => { + misskeyApi('notes/create', { + localOnly, + visibility, + channelId: channel?.id, + renoteId: appearNote.id, + }).then(() => { + os.toast(channel ? i18n.tsx.renotedToX({name: channel.name}) : i18n.ts.renoted); + }); + }; + + // If the note is from a channel, it can be renoted within that channel. + if (appearNote.channel) { + renoteItems.push({ + type: 'button', + icon: 'ti ti-device-tv', + text: appearNote.channel.name, + action: () => {renoteFunc(undefined, undefined, appearNote.channel);}, + }); + } + + // Notes from channels might not allow renoting outside the channel. + if (!appearNote.channel || appearNote.channel.allowRenoteToExternal) { + if (renoteItems.length > 0) renoteItems.push({type: 'divider'}); + renoteItems.push(...boostMenuItems(ref(appearNote), (v, l) => renoteFunc(v, l, undefined))); + // Local-only notes should have the switch visibly forced on. + if (appearNote.localOnly) { + for (const item of renoteItems) { + if (item && item['type'] == "switch" && item['text'] == i18n.ts._timelines.local) { + item['ref'] = ref(true); + item['disabled'] = true; + break; + } + } + } + + const channels = await favoritedChannelsCache.fetch(); + const otherChannelItems: MenuItem[] = channels.filter((channel) => { + if (!appearNote.channelId) return true; + return channel.id !== appearNote.channelId; + }).map((channel) => ({ + type: 'button', + icon: 'ti ti-device-tv', + text: channel.name, + action: () => {renoteFunc(undefined, undefined, channel);}, + })); + if (otherChannelItems.length > 0) { + renoteItems.push( + {type: 'divider'}, + {type: 'label', text: appearNote.channel ? i18n.ts.renoteToOtherChannel : i18n.ts.renoteToChannel}, + ...otherChannelItems + ); + } + const channelQuoteItems: MenuItem[] = channels.map((channel) => ({ + type: 'button', + text: channel.name, + action: () => {os.post({renote: appearNote, channel: channel});}, + })); + if (channelQuoteItems.length > 0) { + renoteItems.push( + {type: 'divider'}, + { + type: 'parent', + text: i18n.ts.inChannelQuote, + icon: 'ti ti-quote', + children: () => channelQuoteItems, + } + ); + } + } + + return renoteItems; +} + export function getRenoteMenu(props: { note: Misskey.entities.Note; renoteButton: ShallowRef;