mirror of
https://github.com/misskey-dev/misskey.git
synced 2026-05-22 15:14:16 +02:00
enhance(frontend): チャンネル指定リノートでリノート先のチャンネルに移動できるように (#17280)
* enhance(frontend): チャンネル指定リノートでリノート先のチャンネルに移動できるように * Update Changelog * fix condition * refactor
This commit is contained in:
@@ -4,7 +4,7 @@
|
|||||||
-
|
-
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
-
|
- Enhance: チャンネル指定リノートでリノート先のチャンネルに移動できるように
|
||||||
|
|
||||||
### Server
|
### Server
|
||||||
- Fix: `/api-doc` にアクセスできない問題を修正
|
- Fix: `/api-doc` にアクセスできない問題を修正
|
||||||
|
|||||||
@@ -1408,6 +1408,7 @@ frame: "フレーム"
|
|||||||
presets: "プリセット"
|
presets: "プリセット"
|
||||||
zeroPadding: "ゼロ埋め"
|
zeroPadding: "ゼロ埋め"
|
||||||
nothingToConfigure: "設定項目はありません"
|
nothingToConfigure: "設定項目はありません"
|
||||||
|
viewRenotedChannel: "リノート先のチャンネルを見る"
|
||||||
|
|
||||||
_imageEditing:
|
_imageEditing:
|
||||||
_vars:
|
_vars:
|
||||||
|
|||||||
@@ -263,7 +263,7 @@ const emit = defineEmits<{
|
|||||||
|
|
||||||
const inTimeline = inject<boolean>('inTimeline', false);
|
const inTimeline = inject<boolean>('inTimeline', false);
|
||||||
const tl_withSensitive = inject<Ref<boolean>>('tl_withSensitive', ref(true));
|
const tl_withSensitive = inject<Ref<boolean>>('tl_withSensitive', ref(true));
|
||||||
const inChannel = inject('inChannel', null);
|
const inChannel = inject(DI.inChannel, null);
|
||||||
const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', null);
|
const currentClip = inject<Ref<Misskey.entities.Clip> | null>('currentClip', null);
|
||||||
|
|
||||||
let note = deepClone(props.note);
|
let note = deepClone(props.note);
|
||||||
@@ -650,23 +650,35 @@ async function showRenoteMenu() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
const renoteDetailsMenu: MenuItem = {
|
const renoteDetailsMenu: MenuItem[] = [{
|
||||||
type: 'link',
|
type: 'link',
|
||||||
text: i18n.ts.renoteDetails,
|
text: i18n.ts.renoteDetails,
|
||||||
icon: 'ti ti-info-circle',
|
icon: 'ti ti-info-circle',
|
||||||
to: notePage(note),
|
to: notePage(note),
|
||||||
};
|
}];
|
||||||
|
|
||||||
|
if (
|
||||||
|
props.note.channelId != null &&
|
||||||
|
(inChannel == null || props.note.channelId !== inChannel.value)
|
||||||
|
) {
|
||||||
|
renoteDetailsMenu.push({
|
||||||
|
type: 'link',
|
||||||
|
text: i18n.ts.viewRenotedChannel,
|
||||||
|
icon: 'ti ti-device-tv',
|
||||||
|
to: `/channels/${props.note.channelId}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (isMyRenote) {
|
if (isMyRenote) {
|
||||||
os.popupMenu([
|
os.popupMenu([
|
||||||
renoteDetailsMenu,
|
...renoteDetailsMenu,
|
||||||
getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote),
|
getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote),
|
||||||
{ type: 'divider' },
|
{ type: 'divider' },
|
||||||
getUnrenote(),
|
getUnrenote(),
|
||||||
], renoteTime.value);
|
], renoteTime.value);
|
||||||
} else {
|
} else {
|
||||||
os.popupMenu([
|
os.popupMenu([
|
||||||
renoteDetailsMenu,
|
...renoteDetailsMenu,
|
||||||
getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote),
|
getCopyNoteLinkMenu(note, i18n.ts.copyLinkRenote),
|
||||||
{ type: 'divider' },
|
{ type: 'divider' },
|
||||||
getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote),
|
getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote),
|
||||||
|
|||||||
@@ -238,6 +238,7 @@ import { isLink } from '@@/js/is-link.js';
|
|||||||
import { host } from '@@/js/config.js';
|
import { host } from '@@/js/config.js';
|
||||||
import type { OpenOnRemoteOptions } from '@/utility/please-login.js';
|
import type { OpenOnRemoteOptions } from '@/utility/please-login.js';
|
||||||
import type { Keymap } from '@/utility/hotkey.js';
|
import type { Keymap } from '@/utility/hotkey.js';
|
||||||
|
import type { MenuItem } from '@/types/menu.js';
|
||||||
import MkNoteSub from '@/components/MkNoteSub.vue';
|
import MkNoteSub from '@/components/MkNoteSub.vue';
|
||||||
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
import MkNoteSimple from '@/components/MkNoteSimple.vue';
|
||||||
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
import MkReactionsViewer from '@/components/MkReactionsViewer.vue';
|
||||||
@@ -286,7 +287,7 @@ const props = withDefaults(defineProps<{
|
|||||||
initialTab: 'replies',
|
initialTab: 'replies',
|
||||||
});
|
});
|
||||||
|
|
||||||
const inChannel = inject('inChannel', null);
|
const inChannel = inject(DI.inChannel, null);
|
||||||
|
|
||||||
let note = deepClone(props.note);
|
let note = deepClone(props.note);
|
||||||
|
|
||||||
@@ -581,18 +582,36 @@ async function showRenoteMenu() {
|
|||||||
const isLoggedIn = await pleaseLogin({ openOnRemote: pleaseLoginContext.value });
|
const isLoggedIn = await pleaseLogin({ openOnRemote: pleaseLoginContext.value });
|
||||||
if (!isLoggedIn) return;
|
if (!isLoggedIn) return;
|
||||||
|
|
||||||
os.popupMenu([{
|
const menu: MenuItem[] = [];
|
||||||
text: i18n.ts.unrenote,
|
|
||||||
icon: 'ti ti-trash',
|
if (isMyRenote) {
|
||||||
danger: true,
|
menu.push({
|
||||||
action: () => {
|
text: i18n.ts.unrenote,
|
||||||
misskeyApi('notes/delete', {
|
icon: 'ti ti-trash',
|
||||||
noteId: note.id,
|
danger: true,
|
||||||
}).then(() => {
|
action: () => {
|
||||||
globalEvents.emit('noteDeleted', note.id);
|
misskeyApi('notes/delete', {
|
||||||
});
|
noteId: note.id,
|
||||||
},
|
}).then(() => {
|
||||||
}], renoteTime.value);
|
globalEvents.emit('noteDeleted', note.id);
|
||||||
|
});
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
props.note.channelId != null &&
|
||||||
|
(inChannel == null || props.note.channelId !== inChannel.value)
|
||||||
|
) {
|
||||||
|
menu.push({
|
||||||
|
type: 'link',
|
||||||
|
text: i18n.ts.viewRenotedChannel,
|
||||||
|
icon: 'ti ti-device-tv',
|
||||||
|
to: `/channels/${props.note.channelId}`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
os.popupMenu(menu, renoteTime.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
function focus() {
|
function focus() {
|
||||||
|
|||||||
@@ -74,6 +74,7 @@ import { store } from '@/store.js';
|
|||||||
import MkNote from '@/components/MkNote.vue';
|
import MkNote from '@/components/MkNote.vue';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
import { DI } from '@/di.js';
|
||||||
import { globalEvents, useGlobalEvent } from '@/events.js';
|
import { globalEvents, useGlobalEvent } from '@/events.js';
|
||||||
import { isSeparatorNeeded, getSeparatorInfo } from '@/utility/timeline-date-separate.js';
|
import { isSeparatorNeeded, getSeparatorInfo } from '@/utility/timeline-date-separate.js';
|
||||||
import { Paginator } from '@/utility/paginator.js';
|
import { Paginator } from '@/utility/paginator.js';
|
||||||
@@ -101,7 +102,7 @@ const props = withDefaults(defineProps<{
|
|||||||
|
|
||||||
provide('inTimeline', true);
|
provide('inTimeline', true);
|
||||||
provide('tl_withSensitive', computed(() => props.withSensitive));
|
provide('tl_withSensitive', computed(() => props.withSensitive));
|
||||||
provide('inChannel', computed(() => props.src === 'channel'));
|
provide(DI.inChannel, computed(() => props.src === 'channel' ? props.channel ?? null : null));
|
||||||
|
|
||||||
let paginator: IPaginator<Misskey.entities.Note>;
|
let paginator: IPaginator<Misskey.entities.Note>;
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import type { InjectionKey, Ref } from 'vue';
|
import type { InjectionKey, Ref, ComputedRef } from 'vue';
|
||||||
import type { PageMetadata } from '@/page.js';
|
import type { PageMetadata } from '@/page.js';
|
||||||
import type { Router } from '@/router.js';
|
import type { Router } from '@/router.js';
|
||||||
|
|
||||||
@@ -18,4 +18,5 @@ export const DI = {
|
|||||||
mfmEmojiReactCallback: Symbol() as InjectionKey<(emoji: string) => void>,
|
mfmEmojiReactCallback: Symbol() as InjectionKey<(emoji: string) => void>,
|
||||||
inModal: Symbol() as InjectionKey<boolean>,
|
inModal: Symbol() as InjectionKey<boolean>,
|
||||||
inAppSearchMarkerId: Symbol() as InjectionKey<Ref<string | null>>,
|
inAppSearchMarkerId: Symbol() as InjectionKey<Ref<string | null>>,
|
||||||
|
inChannel: Symbol() as InjectionKey<ComputedRef<string | null> | null>, // 現在開いているチャンネルのID
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -5647,6 +5647,10 @@ export interface Locale extends ILocale {
|
|||||||
* 設定項目はありません
|
* 設定項目はありません
|
||||||
*/
|
*/
|
||||||
"nothingToConfigure": string;
|
"nothingToConfigure": string;
|
||||||
|
/**
|
||||||
|
* リノート先のチャンネルを見る
|
||||||
|
*/
|
||||||
|
"viewRenotedChannel": string;
|
||||||
"_imageEditing": {
|
"_imageEditing": {
|
||||||
"_vars": {
|
"_vars": {
|
||||||
/**
|
/**
|
||||||
|
|||||||
Reference in New Issue
Block a user