hippofish/packages/client/src/scripts/get-note-menu.ts

519 lines
12 KiB
TypeScript
Raw Normal View History

2023-09-02 01:27:33 +02:00
import type { Ref } from "vue";
import { defineAsyncComponent, inject } from "vue";
import type * as misskey from "firefish-js";
2023-01-13 05:40:33 +01:00
import { $i } from "@/account";
import { i18n } from "@/i18n";
import { instance } from "@/instance";
import * as os from "@/os";
import copyToClipboard from "@/scripts/copy-to-clipboard";
import { url } from "@/config";
import { noteActions } from "@/store";
import { shareAvailable } from "@/scripts/share-available";
2023-06-13 01:44:30 +02:00
import { getUserMenu } from "@/scripts/get-user-menu";
export function getNoteMenu(props: {
note: misskey.entities.Note;
2023-05-07 12:48:55 +02:00
menuButton: Ref<HTMLElement | undefined>;
translation: Ref<any>;
translating: Ref<boolean>;
isDeleted: Ref<boolean>;
2022-06-18 11:27:47 +02:00
currentClipPage?: Ref<misskey.entities.Clip>;
}) {
2023-01-13 05:40:33 +01:00
const isRenote =
props.note.renote != null &&
props.note.text == null &&
props.note.fileIds.length === 0 &&
2023-01-13 05:40:33 +01:00
props.note.poll == null;
2023-01-13 05:40:33 +01:00
const appearNote = isRenote
? (props.note.renote as misskey.entities.Note)
: props.note;
function del(): void {
os.confirm({
2023-01-13 05:40:33 +01:00
type: "warning",
text: i18n.ts.noteDeleteConfirm,
}).then(({ canceled }) => {
if (canceled) return;
2023-01-13 05:40:33 +01:00
os.api("notes/delete", {
2022-06-30 03:53:40 +02:00
noteId: appearNote.id,
});
});
}
function delEdit(): void {
os.confirm({
2023-01-13 05:40:33 +01:00
type: "warning",
text: i18n.ts.deleteAndEditConfirm,
}).then(({ canceled }) => {
if (canceled) return;
2023-01-13 05:40:33 +01:00
os.api("notes/delete", {
2022-06-30 03:53:40 +02:00
noteId: appearNote.id,
});
2023-01-13 05:40:33 +01:00
os.post({
initialNote: appearNote,
renote: appearNote.renote,
reply: appearNote.reply,
channel: appearNote.channel,
});
});
}
2023-05-07 12:48:55 +02:00
function edit(): void {
2023-05-07 14:07:40 +02:00
os.post({
initialNote: appearNote,
renote: appearNote.renote,
reply: appearNote.reply,
channel: appearNote.channel,
editId: appearNote.id,
2023-05-07 12:48:55 +02:00
});
}
function toggleFavorite(favorite: boolean): void {
2023-01-13 05:40:33 +01:00
os.apiWithDialog(
favorite ? "notes/favorites/create" : "notes/favorites/delete",
{
noteId: appearNote.id,
},
);
}
function toggleWatch(watch: boolean): void {
2023-01-13 05:40:33 +01:00
os.apiWithDialog(
watch ? "notes/watching/create" : "notes/watching/delete",
{
noteId: appearNote.id,
},
);
}
function toggleThreadMute(mute: boolean): void {
2023-01-13 05:40:33 +01:00
os.apiWithDialog(
mute ? "notes/thread-muting/create" : "notes/thread-muting/delete",
{
noteId: appearNote.id,
},
);
}
function copyContent(): void {
copyToClipboard(appearNote.text);
os.success();
}
function copyLink(): void {
copyToClipboard(`${url}/notes/${appearNote.id}`);
os.success();
}
2023-06-19 22:50:51 +02:00
function copyOriginal(): void {
copyToClipboard(appearNote.url ?? appearNote.uri);
os.success();
}
function togglePin(pin: boolean): void {
2023-01-13 05:40:33 +01:00
os.apiWithDialog(
pin ? "i/pin" : "i/unpin",
{
noteId: appearNote.id,
},
undefined,
2023-04-30 18:29:50 +02:00
).catch((res) => {
if (res.id === "72dab508-c64d-498f-8740-a8eec1ba385a") {
os.alert({
type: "error",
text: i18n.ts.pinLimitExceeded,
});
}
});
}
async function clip(): Promise<void> {
2023-01-13 05:40:33 +01:00
const clips = await os.api("clips/list");
os.popupMenu(
[
{
2023-03-11 22:01:04 +01:00
icon: "ph-plus ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.createNew,
action: async () => {
const { canceled, result } = await os.form(i18n.ts.createNewClip, {
name: {
type: "string",
label: i18n.ts.name,
},
description: {
type: "string",
required: false,
multiline: true,
label: i18n.ts.description,
},
isPublic: {
type: "boolean",
label: i18n.ts.public,
default: false,
},
});
if (canceled) return;
2023-01-13 05:40:33 +01:00
const clip = await os.apiWithDialog("clips/create", result);
2023-01-13 05:40:33 +01:00
os.apiWithDialog("clips/add-note", {
clipId: clip.id,
noteId: appearNote.id,
});
2022-06-30 03:53:40 +02:00
},
2023-01-13 05:40:33 +01:00
},
null,
...clips.map((clip) => ({
text: clip.name,
action: () => {
os.promiseDialog(
os.api("clips/add-note", {
clipId: clip.id,
noteId: appearNote.id,
}),
null,
async (err) => {
if (err.id === "734806c4-542c-463a-9311-15c512803965") {
const confirm = await os.confirm({
type: "warning",
text: i18n.t("confirmToUnclipAlreadyClippedNote", {
name: clip.name,
}),
});
if (!confirm.canceled) {
os.apiWithDialog("clips/remove-note", {
clipId: clip.id,
noteId: appearNote.id,
});
if (props.currentClipPage?.value.id === clip.id)
props.isDeleted.value = true;
}
} else {
os.alert({
type: "error",
text: err.message + "\n" + err.id,
});
}
},
);
},
})),
],
props.menuButton.value,
{},
).then(focus);
}
async function unclip(): Promise<void> {
2023-01-13 05:40:33 +01:00
os.apiWithDialog("clips/remove-note", {
clipId: props.currentClipPage.value.id,
noteId: appearNote.id,
});
props.isDeleted.value = true;
}
async function promote(): Promise<void> {
const { canceled, result: days } = await os.inputNumber({
title: i18n.ts.numberOfDays,
});
if (canceled) return;
2023-01-13 05:40:33 +01:00
os.apiWithDialog("admin/promo/create", {
noteId: appearNote.id,
2023-01-13 05:40:33 +01:00
expiresAt: Date.now() + 86400000 * days,
});
}
function share(): void {
navigator.share({
2023-01-13 05:40:33 +01:00
title: i18n.t("noteOf", { user: appearNote.user.name }),
text: appearNote.text,
url: `${url}/notes/${appearNote.id}`,
});
}
async function translate_(noteId: number, targetLang: string) {
return await os.api("notes/translate", {
noteId: noteId,
targetLang: targetLang,
});
}
async function translate(): Promise<void> {
const translateLang = localStorage.getItem("translateLang");
const lang = localStorage.getItem("lang");
if (props.translation.value != null) return;
props.translating.value = true;
props.translation.value = await translate_(
appearNote.id,
translateLang || lang || navigator.language,
);
// use UI language as the second translation target
if (
translateLang != null &&
lang != null &&
translateLang !== lang &&
(!props.translation.value ||
props.translation.value.sourceLang.toLowerCase() ===
translateLang.slice(0, 2))
)
props.translation.value = await translate_(appearNote.id, lang);
props.translating.value = false;
}
let menu;
if ($i) {
2023-01-13 05:40:33 +01:00
const statePromise = os.api("notes/state", {
2022-06-30 03:53:40 +02:00
noteId: appearNote.id,
});
2023-05-07 12:48:55 +02:00
const isAppearAuthor = appearNote.userId === $i.id;
const isModerator = $i.isAdmin || $i.isModerator;
menu = [
2023-01-13 05:40:33 +01:00
...(props.currentClipPage?.value.userId === $i.id
? [
{
2023-03-11 22:01:04 +01:00
icon: "ph-minus-circle ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.unclip,
danger: true,
action: unclip,
},
null,
]
: []),
statePromise.then((state) =>
state?.isFavorited
? {
2023-03-11 22:01:04 +01:00
icon: "ph-bookmark-simple ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.unfavorite,
action: () => toggleFavorite(false),
}
: {
2023-03-11 22:01:04 +01:00
icon: "ph-bookmark-simple ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.favorite,
action: () => toggleFavorite(true),
},
),
2022-06-30 03:53:40 +02:00
{
2023-03-11 22:01:04 +01:00
icon: "ph-paperclip ph-bold ph-lg",
2022-06-30 03:53:40 +02:00
text: i18n.ts.clip,
action: () => clip(),
},
2023-05-07 12:48:55 +02:00
!isAppearAuthor
2023-01-13 05:40:33 +01:00
? statePromise.then((state) =>
state.isWatching
? {
2023-03-11 22:01:04 +01:00
icon: "ph-eye-slash ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.unwatch,
action: () => toggleWatch(false),
}
: {
2023-03-11 22:01:04 +01:00
icon: "ph-eye ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.watch,
action: () => toggleWatch(true),
},
)
: undefined,
statePromise.then((state) =>
state.isMutedThread
? {
2023-03-11 22:01:04 +01:00
icon: "ph-speaker-x ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.unmuteThread,
action: () => toggleThreadMute(false),
}
: {
2023-03-11 22:01:04 +01:00
icon: "ph-speaker-x ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.muteThread,
action: () => toggleThreadMute(true),
},
),
2023-05-07 12:48:55 +02:00
isAppearAuthor
2023-01-13 05:40:33 +01:00
? ($i.pinnedNoteIds || []).includes(appearNote.id)
? {
2023-03-11 22:01:04 +01:00
icon: "ph-push-pin ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.unpin,
action: () => togglePin(false),
}
: {
2023-03-11 22:01:04 +01:00
icon: "ph-push-pin ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.pin,
action: () => togglePin(true),
}
: undefined,
instance.translatorAvailable
? {
icon: "ph-translate ph-bold ph-lg",
text: i18n.ts.translate,
action: translate,
}
: undefined,
2023-06-19 22:50:51 +02:00
appearNote.url || appearNote.uri
? {
icon: "ph-arrow-square-out ph-bold ph-lg",
text: i18n.ts.showOnRemote,
action: () => {
window.open(appearNote.url || appearNote.uri, "_blank");
},
2023-06-24 06:22:44 +02:00
}
2023-06-19 22:50:51 +02:00
: undefined,
{
type: "parent",
icon: "ph-share-network ph-bold ph-lg",
text: i18n.ts.share,
children: [
{
icon: "ph-clipboard-text ph-bold ph-lg",
text: i18n.ts.copyContent,
action: copyContent,
},
{
icon: "ph-link-simple ph-bold ph-lg",
text: i18n.ts.copyLink,
action: copyLink,
},
2023-06-24 06:22:44 +02:00
appearNote.url || appearNote.uri
? {
icon: "ph-link-simple ph-bold ph-lg",
text: `${i18n.ts.copyLink} (${i18n.ts.origin})`,
2023-06-24 06:22:44 +02:00
action: copyOriginal,
}
: undefined,
2023-06-19 22:50:51 +02:00
shareAvailable()
2023-06-24 06:22:44 +02:00
? {
icon: "ph-share-network ph-bold ph-lg",
text: i18n.ts.share,
action: share,
}
: undefined,
],
2023-06-19 22:50:51 +02:00
},
2022-06-30 03:53:40 +02:00
/*
...($i.isModerator || $i.isAdmin ? [
null,
{
2023-03-11 22:01:04 +01:00
icon: 'ph-megaphone-simple ph-bold ph-lg',
text: i18n.ts.promote,
action: promote
}]
: []
2023-09-02 01:27:33 +02:00
), */
2023-06-08 12:02:50 +02:00
null,
!isAppearAuthor
? {
icon: "ph-warning-circle ph-bold ph-lg",
text: i18n.ts.reportAbuse,
action: () => {
const u =
appearNote.url ||
appearNote.uri ||
`${url}/notes/${appearNote.id}`;
os.popup(
defineAsyncComponent(
() => import("@/components/MkAbuseReportWindow.vue"),
),
{
user: appearNote.user,
initialComment: `Note: ${u}\n-----\n`,
},
{},
"closed",
);
2023-01-13 05:40:33 +01:00
},
2023-06-24 06:22:44 +02:00
}
2023-06-08 12:02:50 +02:00
: undefined,
isAppearAuthor
2023-05-07 12:48:55 +02:00
? {
2023-06-08 12:02:50 +02:00
icon: "ph-pencil-line ph-bold ph-lg",
text: i18n.ts.edit,
2023-06-08 19:47:21 +02:00
accent: true,
2023-06-08 12:02:50 +02:00
action: edit,
2023-05-07 12:48:55 +02:00
}
: undefined,
isAppearAuthor
? {
icon: "ph-eraser ph-bold ph-lg",
text: i18n.ts.deleteAndEdit,
danger: true,
2023-05-07 12:48:55 +02:00
action: delEdit,
}
: undefined,
2023-06-08 12:02:50 +02:00
isAppearAuthor || isModerator
? {
icon: "ph-trash ph-bold ph-lg",
text: i18n.ts.delete,
danger: true,
action: del,
}
: undefined,
2023-06-13 01:44:30 +02:00
!isAppearAuthor ? null : undefined,
!isAppearAuthor
? {
2023-06-24 06:22:44 +02:00
type: "parent",
icon: "ph-user ph-bold ph-lg",
text: i18n.ts.user,
children: getUserMenu(appearNote.user),
}
: undefined,
2023-01-13 05:40:33 +01:00
].filter((x) => x !== undefined);
} else {
2023-01-13 05:40:33 +01:00
menu = [
2023-06-19 22:50:51 +02:00
appearNote.url || appearNote.uri
? {
icon: "ph-arrow-square-out ph-bold ph-lg",
text: i18n.ts.showOnRemote,
action: () => {
window.open(appearNote.url || appearNote.uri, "_blank");
},
}
: undefined,
2023-01-13 05:40:33 +01:00
{
2023-03-11 22:01:04 +01:00
icon: "ph-clipboard-text ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.copyContent,
action: copyContent,
2022-06-30 03:53:40 +02:00
},
2023-01-13 05:40:33 +01:00
{
2023-03-11 22:01:04 +01:00
icon: "ph-link-simple ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: i18n.ts.copyLink,
action: copyLink,
},
2023-06-24 06:22:44 +02:00
appearNote.url || appearNote.uri
? {
icon: "ph-link-simple ph-bold ph-lg",
text: `${i18n.ts.copyLink} (${i18n.ts.origin})`,
2023-06-24 06:22:44 +02:00
action: copyOriginal,
}
: undefined,
2023-06-19 22:50:51 +02:00
shareAvailable()
2023-06-24 06:22:44 +02:00
? {
icon: "ph-share-network ph-bold ph-lg",
text: i18n.ts.share,
action: share,
}
: undefined,
2023-01-13 05:40:33 +01:00
].filter((x) => x !== undefined);
}
if (noteActions.length > 0) {
2023-01-13 05:40:33 +01:00
menu = menu.concat([
null,
...noteActions.map((action) => ({
2023-03-11 22:01:04 +01:00
icon: "ph-plug ph-bold ph-lg",
2023-01-13 05:40:33 +01:00
text: action.title,
action: () => {
action.handler(appearNote);
},
})),
]);
}
return menu;
}