Compare commits

..

3 commits

Author SHA1 Message Date
daae1ec300
client: better error for already clipped note
Changelog: Fixed
2025-02-06 20:06:08 +01:00
f1b344c5e7
client: more actions for renotes
Also allows to perform most note actions on renotes.

Changelog: Added
2025-02-06 20:06:07 +01:00
81cf69c9bf
client: refactor getNoteMenu
Instead of re-determining `appearNote` inside `getNoteMenu`, it makes sense
to pass in the value since it has already been computed anyway.
2025-02-06 20:06:07 +01:00
2 changed files with 49 additions and 47 deletions

View file

@ -24,7 +24,7 @@
</I18n>
<div class="info">
<button ref="renoteTime" class="_button time" @click="showRenoteMenu()">
<i v-if="isMyRenote" class="fas fa-ellipsis-h dropdownIcon"></i>
<i class="fas fa-ellipsis-h dropdownIcon"></i>
<MkTime :time="note.createdAt"/>
</button>
<MkVisibility :note="note"/>
@ -154,7 +154,6 @@ const renoteButton = ref<InstanceType<typeof XRenoteButton>>();
const renoteTime = ref<HTMLElement>();
const reactButton = ref<HTMLElement>();
let appearNote = $computed(() => isRenote ? note.renote as foundkey.entities.Note : note);
const isMyRenote = $i && ($i.id === note.userId);
const showContent = ref(false);
const isLong = (appearNote.cw == null && appearNote.text != null && (
(appearNote.text.split('\n').length > 9) ||
@ -244,20 +243,18 @@ function menu(viaKeyboard = false): void {
}
function showRenoteMenu(viaKeyboard = false): void {
if (!isMyRenote) return;
os.popupMenu([{
text: i18n.ts.unrenote,
icon: 'fas fa-trash-alt',
danger: true,
action: () => {
os.api('notes/delete', {
noteId: note.id,
});
isDeleted.value = true;
},
}], renoteTime.value, {
viaKeyboard,
});
os.popupMenu(
getNoteMenu({
note,
translating,
translation,
renoteTime,
isDeleted,
currentClipPage
}),
renoteTime.value,
{ viaKeyboard },
);
}
function focus() {

View file

@ -26,7 +26,7 @@ export function getNoteMenu(props: {
if (canceled) return;
os.api('notes/delete', {
noteId: note.id,
noteId: props.note.id,
});
});
}
@ -39,16 +39,21 @@ export function getNoteMenu(props: {
if (canceled) return;
os.api('notes/delete', {
noteId: note.id,
noteId: props.note.id,
});
os.post({ initialNote: note, renote: note.renote, reply: note.reply, channel: note.channel });
os.post({
initialNote: props.note,
renote: props.note.renote,
reply: props.note.reply,
channel: props.note.channel,
});
});
}
function toggleWatch(watch: boolean): void {
os.apiWithDialog(watch ? 'notes/watching/create' : 'notes/watching/delete', {
noteId: note.id,
noteId: props.note.id,
});
}
@ -69,7 +74,7 @@ export function getNoteMenu(props: {
}
await os.apiWithDialog('notes/thread-muting/create', {
noteId: note.id,
noteId: props.note.id,
mutingNotificationTypes,
});
},
@ -78,23 +83,23 @@ export function getNoteMenu(props: {
function unmuteThread(): void {
os.apiWithDialog('notes/thread-muting/delete', {
noteId: note.id,
noteId: props.note.id,
});
}
function copyContent(): void {
copyToClipboard(note.text);
copyToClipboard(props.note.text);
os.success();
}
function copyLink(): void {
copyToClipboard(`${url}/notes/${note.id}`);
copyToClipboard(`${url}/notes/${props.note.id}`);
os.success();
}
function togglePin(pin: boolean): void {
os.apiWithDialog(pin ? 'i/pin' : 'i/unpin', {
noteId: note.id,
noteId: props.note.id,
}, undefined, null, res => {
if (res.code === 'PIN_LIMIT_EXCEEDED') {
os.alert({
@ -132,22 +137,22 @@ export function getNoteMenu(props: {
const clip = await os.apiWithDialog('clips/create', result);
os.apiWithDialog('clips/add-note', { clipId: clip.id, noteId: note.id });
os.apiWithDialog('clips/add-note', { clipId: clip.id, noteId: props.note.id });
},
}, null, ...clips.map(clip => ({
text: clip.name,
action: () => {
os.promiseDialog(
os.api('clips/add-note', { clipId: clip.id, noteId: note.id }),
os.api('clips/add-note', { clipId: clip.id, noteId: props.note.id }),
null,
async (err) => {
if (err.id === 'ALREADY_CLIPPED') {
if (err.code === 'ALREADY_CLIPPED') {
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: note.id });
os.apiWithDialog('clips/remove-note', { clipId: clip.id, noteId: props.note.id });
if (props.currentClipPage?.value.id === clip.id) props.isDeleted.value = true;
}
} else {
@ -164,15 +169,15 @@ export function getNoteMenu(props: {
}
async function unclip(): Promise<void> {
os.apiWithDialog('clips/remove-note', { clipId: props.currentClipPage.value.id, noteId: note.id });
os.apiWithDialog('clips/remove-note', { clipId: props.currentClipPage.value.id, noteId: props.note.id });
props.isDeleted.value = true;
}
function share(): void {
navigator.share({
title: i18n.t('noteOf', { user: note.user.name || note.user.username }),
text: note.text,
url: `${url}/notes/${note.id}`,
title: i18n.t('noteOf', { user: props.note.user.name || props.note.user.username }),
text: props.note.text,
url: `${url}/notes/${props.note.id}`,
});
}
@ -188,7 +193,7 @@ export function getNoteMenu(props: {
}
const res = await os.api('notes/translate', {
noteId: note.id,
noteId: props.note.id,
targetLang,
});
props.translating.value = false;
@ -198,7 +203,7 @@ export function getNoteMenu(props: {
let menu;
if ($i) {
const statePromise = os.api('notes/state', {
noteId: note.id,
noteId: props.note.id,
});
menu = [
@ -220,11 +225,11 @@ export function getNoteMenu(props: {
text: i18n.ts.copyLink,
action: copyLink,
},
(note.url || note.uri) ? {
(props.note.url || props.note.uri) ? {
icon: 'fas fa-external-link-square-alt',
text: i18n.ts.showOnRemote,
action: () => {
window.open(note.url || note.uri, '_blank');
window.open(props.note.url || props.note.uri, '_blank');
},
} : undefined,
{
@ -243,7 +248,7 @@ export function getNoteMenu(props: {
text: i18n.ts.clip,
action: () => clip(),
},
(note.userId !== $i.id) ? statePromise.then(state => state.isWatching ? {
(props.note.userId !== $i.id) ? statePromise.then(state => state.isWatching ? {
icon: 'fas fa-eye-slash',
text: i18n.ts.unwatch,
action: () => toggleWatch(false),
@ -261,7 +266,7 @@ export function getNoteMenu(props: {
text: i18n.ts.muteThread,
action: () => muteThread(),
}),
note.userId === $i.id ? ($i.pinnedNoteIds || []).includes(note.id) ? {
props.note.userId === $i.id ? ($i.pinnedNoteIds || []).includes(props.note.id) ? {
icon: 'fas fa-thumbtack',
text: i18n.ts.unpin,
action: () => togglePin(false),
@ -270,24 +275,24 @@ export function getNoteMenu(props: {
text: i18n.ts.pin,
action: () => togglePin(true),
} : undefined,
...(note.userId !== $i.id && !isPureRenote ? [
...(props.note.userId !== $i.id && !isPureRenote ? [
null,
{
icon: 'fas fa-exclamation-circle',
text: i18n.ts.reportAbuse,
action: () => {
const u = note.url || note.uri || `${url}/notes/${note.id}`;
const u = props.note.url || props.note.uri || `${url}/notes/${props.note.id}`;
os.popup(defineAsyncComponent(() => import('@/components/abuse-report-window.vue')), {
user: note.user,
user: props.note.user,
urls: [u],
}, {}, 'closed');
},
}]
: []
),
...(note.userId === $i.id || $i.isModerator || $i.isAdmin ? [
...(props.note.userId === $i.id || $i.isModerator || $i.isAdmin ? [
null,
(!isPureRenote && note.userId === $i.id) ? {
(!isPureRenote && props.note.userId === $i.id) ? {
icon: 'fas fa-edit',
text: i18n.ts.deleteAndEdit,
action: delEdit,
@ -313,11 +318,11 @@ export function getNoteMenu(props: {
text: i18n.ts.copyLink,
action: copyLink,
},
(note.url || note.uri) ? {
(props.note.url || props.note.uri) ? {
icon: 'fas fa-external-link-square-alt',
text: i18n.ts.showOnRemote,
action: () => {
window.open(note.url || note.uri, '_blank');
window.open(props.note.url || props.note.uri, '_blank');
},
} : undefined
]
@ -329,7 +334,7 @@ export function getNoteMenu(props: {
icon: 'fas fa-plug',
text: action.title,
action: () => {
action.handler(note);
action.handler(props.note);
},
}))]);
}