feat(frontend): Renote自体を通報できるように

This commit is contained in:
NoriDev 2023-08-08 17:30:37 +09:00
commit f8d88a471c
8 changed files with 87 additions and 57 deletions

View file

@ -29,6 +29,7 @@
- 스크롤 시 요소 표시(헤더, 플로팅 버튼, 탐색 모음)를 사용자화 할 수 있는 옵션 추가 - 스크롤 시 요소 표시(헤더, 플로팅 버튼, 탐색 모음)를 사용자화 할 수 있는 옵션 추가
- 노트 작성 폼의 "노트" 버튼을 "냥!"으로 변경할 수 있는 옵션 추가 - 노트 작성 폼의 "노트" 버튼을 "냥!"으로 변경할 수 있는 옵션 추가
- 노트의 리액션을 삭제하지 않고도 리액션 버튼을 눌러 리액션을 변경할 수 있도록 (misskey-dev/misskey#11157) - 노트의 리액션을 삭제하지 않고도 리액션 버튼을 눌러 리액션을 변경할 수 있도록 (misskey-dev/misskey#11157)
- 리노트를 신고할 수 있도록 (misskey-dev/misskey#11466)
### Client ### Client
- 이모티콘 피커의 검색 건수를 100개로 증가 (misskey-dev/misskey#11371) - 이모티콘 피커의 검색 건수를 100개로 증가 (misskey-dev/misskey#11371)

View file

@ -705,6 +705,7 @@ behavior: "Behavior"
sample: "Sample" sample: "Sample"
abuseReports: "Reports" abuseReports: "Reports"
reportAbuse: "Report" reportAbuse: "Report"
reportAbuseRenote: "Report Renote"
reportAbuseOf: "Report {name}" reportAbuseOf: "Report {name}"
fillAbuseReportDescription: "Please fill in details regarding this report. If it is about a specific note, please include its URL." fillAbuseReportDescription: "Please fill in details regarding this report. If it is about a specific note, please include its URL."
abuseReported: "Your report has been sent. Thank you very much." abuseReported: "Your report has been sent. Thank you very much."

1
locales/index.d.ts vendored
View file

@ -709,6 +709,7 @@ export interface Locale {
"sample": string; "sample": string;
"abuseReports": string; "abuseReports": string;
"reportAbuse": string; "reportAbuse": string;
"reportAbuseRenote": string;
"reportAbuseOf": string; "reportAbuseOf": string;
"fillAbuseReportDescription": string; "fillAbuseReportDescription": string;
"abuseReported": string; "abuseReported": string;

View file

@ -706,6 +706,7 @@ behavior: "動作"
sample: "サンプル" sample: "サンプル"
abuseReports: "通報" abuseReports: "通報"
reportAbuse: "通報" reportAbuse: "通報"
reportAbuseRenote: "Renoteを通報"
reportAbuseOf: "{name}を通報する" reportAbuseOf: "{name}を通報する"
fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のートがある場合はそのURLも記入してください。" fillAbuseReportDescription: "通報理由の詳細を記入してください。対象のートがある場合はそのURLも記入してください。"
abuseReported: "内容が送信されました。ご報告ありがとうございました。" abuseReported: "内容が送信されました。ご報告ありがとうございました。"

View file

@ -706,6 +706,7 @@ behavior: "동작"
sample: "예시" sample: "예시"
abuseReports: "신고" abuseReports: "신고"
reportAbuse: "신고" reportAbuse: "신고"
reportAbuseRenote: "리노트를 신고"
reportAbuseOf: "{name} 님을 신고하기" reportAbuseOf: "{name} 님을 신고하기"
fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요." fillAbuseReportDescription: "신고하려는 이유를 자세히 알려주세요. 특정 게시물을 신고할 때에는 게시물의 URL도 포함해 주세요."
abuseReported: "신고를 보냈어요! 신고해 주셔서 감사합니다." abuseReported: "신고를 보냈어요! 신고해 주셔서 감사합니다."

View file

@ -40,11 +40,15 @@ SPDX-License-Identifier: AGPL-3.0-only
</span> </span>
<span v-if="note.localOnly" style="margin-right: 0.5em;"><i v-tooltip="i18n.ts._visibility['disableFederation']" class="ti ti-rocket-off"></i></span> <span v-if="note.localOnly" style="margin-right: 0.5em;"><i v-tooltip="i18n.ts._visibility['disableFederation']" class="ti ti-rocket-off"></i></span>
<span v-if="note.channel" style="margin-right: 0.5em;"><i v-tooltip="note.channel.name" class="ti ti-device-tv"></i></span> <span v-if="note.channel" style="margin-right: 0.5em;"><i v-tooltip="note.channel.name" class="ti ti-device-tv"></i></span>
<button ref="renoteTime" :class="$style.renoteTime" class="_button" @click="showRenoteMenu()"> <span :class="$style.renoteTime">
<i v-if="isMyRenote" class="ti ti-dots" :class="$style.renoteMenu"></i> <button ref="renoteTime" class="_button">
<MkTime v-if="defaultStore.state.enableAbsoluteTime" :time="note.createdAt" mode="absolute"/> <i class="ti ti-dots" :class="$style.renoteMenu" @click="showRenoteMenu()"></i>
<MkTime v-else-if="!defaultStore.state.enableAbsoluteTime" :time="note.createdAt" mode="relative"/>
</button> </button>
<MkA :to="notePage(note)">
<MkTime v-if="defaultStore.state.enableAbsoluteTime" :time="note.createdAt" mode="absolute"/>
<MkTime v-else :time="note.createdAt" mode="relative"/>
</MkA>
</span>
</div> </div>
</div> </div>
<MkNoteSub v-if="appearNote.reply && !renoteCollapsed" :note="appearNote.reply" :class="$style.replyTo"/> <MkNoteSub v-if="appearNote.reply && !renoteCollapsed" :note="appearNote.reply" :class="$style.replyTo"/>
@ -189,7 +193,7 @@ import { reactionPicker } from '@/scripts/reaction-picker';
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm';
import { $i } from '@/account'; import { $i } from '@/account';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu'; import { getAbuseNoteMenu, getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu';
import { useNoteCapture } from '@/scripts/use-note-capture'; import { useNoteCapture } from '@/scripts/use-note-capture';
import { deepClone } from '@/scripts/clone'; import { deepClone } from '@/scripts/clone';
import { useTooltip } from '@/scripts/use-tooltip'; import { useTooltip } from '@/scripts/use-tooltip';
@ -509,7 +513,7 @@ async function translate(): Promise<void> {
} }
function showRenoteMenu(viaKeyboard = false): void { function showRenoteMenu(viaKeyboard = false): void {
if (!isMyRenote) return; if (isMyRenote) {
pleaseLogin(); pleaseLogin();
os.popupMenu([{ os.popupMenu([{
text: i18n.ts.unrenote, text: i18n.ts.unrenote,
@ -524,6 +528,11 @@ function showRenoteMenu(viaKeyboard = false): void {
}], renoteTime.value, { }], renoteTime.value, {
viaKeyboard: viaKeyboard, viaKeyboard: viaKeyboard,
}); });
} else {
os.popupMenu([getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote)], renoteTime.value, {
viaKeyboard: viaKeyboard,
});
}
} }
function focus() { function focus() {

View file

@ -35,11 +35,13 @@ SPDX-License-Identifier: AGPL-3.0-only
<i v-else-if="note.reactionAcceptance === 'likeOnly'" v-tooltip="i18n.ts.likeOnly" class="ti ti-heart"></i> <i v-else-if="note.reactionAcceptance === 'likeOnly'" v-tooltip="i18n.ts.likeOnly" class="ti ti-heart"></i>
</span> </span>
<span v-if="note.localOnly" style="margin-right: 0.5em;"><i v-tooltip="i18n.ts._visibility['disableFederation']" class="ti ti-rocket-off"></i></span> <span v-if="note.localOnly" style="margin-right: 0.5em;"><i v-tooltip="i18n.ts._visibility['disableFederation']" class="ti ti-rocket-off"></i></span>
<button ref="renoteTime" class="_button" :class="$style.renoteTime" @click="showRenoteMenu()"> <span :class="$style.renoteTime">
<i v-if="isMyRenote" class="ti ti-dots" style="margin-right: 4px;"></i> <button ref="renoteTime" class="_button">
<MkTime v-if="defaultStore.state.enableAbsoluteTime" :time="note.createdAt" mode="absolute"/> <i class="ti ti-dots" :class="$style.renoteMenu" @click="showRenoteMenu()"></i>
<MkTime v-else-if="!defaultStore.state.enableAbsoluteTime" :time="note.createdAt" mode="relative"/>
</button> </button>
<MkTime v-if="defaultStore.state.enableAbsoluteTime" :time="note.createdAt" mode="absolute"/>
<MkTime v-else :time="note.createdAt" mode="relative"/>
</span>
</div> </div>
</div> </div>
<MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/> <MkNoteSub v-for="note in conversation" :key="note.id" :class="$style.replyToMore" :note="note"/>
@ -198,12 +200,11 @@ import { reactionPicker } from '@/scripts/reaction-picker';
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm';
import { $i } from '@/account'; import { $i } from '@/account';
import { i18n } from '@/i18n'; import { i18n } from '@/i18n';
import { getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu'; import { getAbuseNoteMenu, getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu';
import { useNoteCapture } from '@/scripts/use-note-capture'; import { useNoteCapture } from '@/scripts/use-note-capture';
import { deepClone } from '@/scripts/clone'; import { deepClone } from '@/scripts/clone';
import { useTooltip } from '@/scripts/use-tooltip'; import { useTooltip } from '@/scripts/use-tooltip';
import { claimAchievement } from '@/scripts/achievements'; import { claimAchievement } from '@/scripts/achievements';
import { MenuItem } from '@/types/menu';
import MkRippleEffect from '@/components/MkRippleEffect.vue'; import MkRippleEffect from '@/components/MkRippleEffect.vue';
import { showMovedDialog } from '@/scripts/show-moved-dialog'; import { showMovedDialog } from '@/scripts/show-moved-dialog';
import { miLocalStorage } from '@/local-storage'; import { miLocalStorage } from '@/local-storage';
@ -485,7 +486,7 @@ async function clip() {
} }
function showRenoteMenu(viaKeyboard = false): void { function showRenoteMenu(viaKeyboard = false): void {
if (!isMyRenote) return; if (isMyRenote) {
pleaseLogin(); pleaseLogin();
os.popupMenu([{ os.popupMenu([{
text: i18n.ts.unrenote, text: i18n.ts.unrenote,
@ -500,6 +501,11 @@ function showRenoteMenu(viaKeyboard = false): void {
}], renoteTime.value, { }], renoteTime.value, {
viaKeyboard: viaKeyboard, viaKeyboard: viaKeyboard,
}); });
} else {
os.popupMenu([getAbuseNoteMenu(note, i18n.ts.reportAbuseRenote)], renoteTime.value, {
viaKeyboard: viaKeyboard,
});
}
} }
function focus() { function focus() {
@ -589,6 +595,10 @@ if (appearNote.replyId) {
color: inherit; color: inherit;
} }
.renoteMenu {
margin-right: 4px;
}
.renote + .note { .renote + .note {
padding-top: 8px; padding-top: 8px;
} }

View file

@ -92,6 +92,22 @@ export async function getNoteClipMenu(props: {
}]; }];
} }
export function getAbuseNoteMenu(note: misskey.entities.Note, text: string): MenuItem {
return {
icon: 'ti ti-exclamation-circle',
text,
action: (): void => {
const u = note.url ?? note.uri ?? `${url}/notes/${note.id}`;
const username = '@' + note.user.username;
const host = note.user.host ? '@' + note.user.host : '';
os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
user: note.user,
initialComment: `Note: ${u}\nUser: ${username + host}\n-----\n`,
}, {}, 'closed');
},
};
}
export function getNoteMenu(props: { export function getNoteMenu(props: {
note: misskey.entities.Note; note: misskey.entities.Note;
menuButton: Ref<HTMLElement>; menuButton: Ref<HTMLElement>;
@ -358,21 +374,11 @@ export function getNoteMenu(props: {
}] }]
: [] : []
),*/ ),*/
...(appearNote.userId !== $i.id ? [ ...(appearNote.userId !== $i.id || (isRenote && props.note.userId !== $i.id) ? [
null, null,
{ appearNote.userId !== $i.id ? getAbuseNoteMenu(appearNote, i18n.ts.reportAbuse) : undefined,
icon: 'ti ti-exclamation-circle', isRenote && props.note.userId !== $i.id ? getAbuseNoteMenu(props.note, i18n.ts.reportAbuseRenote) : undefined,
text: i18n.ts.reportAbuse, ]
action: () => {
const u = appearNote.url ?? appearNote.uri ?? `${url}/notes/${appearNote.id}`;
const username = '@' + props.note.user.username;
const host = props.note.user.host ? '@' + props.note.user.host : '';
os.popup(defineAsyncComponent(() => import('@/components/MkAbuseReportWindow.vue')), {
user: appearNote.user,
initialComment: `Note: ${u}\nUser: ${username + host}\n-----\n`,
}, {}, 'closed');
},
}]
: [] : []
), ),
...(appearNote.userId === $i.id || $i.isModerator || $i.isAdmin ? [ ...(appearNote.userId === $i.id || $i.isModerator || $i.isAdmin ? [