copy from MkNoteDetailed to SkNoteDetailed

plus some extra fixes in MkNoteDetailed
This commit is contained in:
dakkar 2024-08-02 13:01:12 +01:00
parent 3434092a10
commit b4624ce035
2 changed files with 131 additions and 63 deletions

View file

@ -458,12 +458,14 @@ useTooltip(quoteButton, async (showing) => {
if (users.length < 1) return; if (users.length < 1) return;
os.popup(MkUsersTooltip, { const { dispose } = os.popup(MkUsersTooltip, {
showing, showing,
users, users,
count: appearNote.value.renoteCount, count: appearNote.value.renoteCount,
targetElement: quoteButton.value, targetElement: quoteButton.value,
}, {}, 'closed'); }, {
closed: () => dispose(),
});
}); });
function boostVisibility() { function boostVisibility() {
@ -512,7 +514,9 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
misskeyApi('notes/create', { misskeyApi('notes/create', {
@ -528,7 +532,9 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
misskeyApi('notes/create', { misskeyApi('notes/create', {
@ -543,7 +549,7 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
} }
function quote() { function quote() {
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog(); showMovedDialog();
if (appearNote.value.channel) { if (appearNote.value.channel) {
@ -563,7 +569,9 @@ function quote() {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
os.toast(i18n.ts.quoted); os.toast(i18n.ts.quoted);
@ -585,7 +593,9 @@ function quote() {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
os.toast(i18n.ts.quoted); os.toast(i18n.ts.quoted);
@ -643,7 +653,7 @@ function react(): void {
} }
function like(): void { function like(): void {
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog(); showMovedDialog();
sound.playMisskeySfx('reaction'); sound.playMisskeySfx('reaction');
misskeyApi('notes/like', { misskeyApi('notes/like', {
@ -655,7 +665,9 @@ function like(): void {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
} }
@ -680,7 +692,9 @@ function undoRenote() : void {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
} }
@ -718,11 +732,9 @@ function showMenu(): void {
os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup); os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
} }
async function menuVersions(viaKeyboard = false): Promise<void> { async function menuVersions(): Promise<void> {
const { menu, cleanup } = await getNoteVersionsMenu({ note: note.value, menuVersionsButton }); const { menu, cleanup } = await getNoteVersionsMenu({ note: note.value, menuVersionsButton });
os.popupMenu(menu, menuVersionsButton.value, { os.popupMenu(menu, menuVersionsButton.value).then(focus).finally(cleanup);
viaKeyboard,
}).then(focus).finally(cleanup);
} }
async function clip(): Promise<void> { async function clip(): Promise<void> {

View file

@ -10,6 +10,7 @@ SPDX-License-Identifier: AGPL-3.0-only
ref="rootEl" ref="rootEl"
v-hotkey="keymap" v-hotkey="keymap"
:class="$style.root" :class="$style.root"
:tabindex="isDeleted ? '-1' : '0'"
> >
<div v-if="appearNote.reply && appearNote.reply.replyId && !conversationLoaded" style="padding: 16px"> <div v-if="appearNote.reply && appearNote.reply.replyId && !conversationLoaded" style="padding: 16px">
<MkButton style="margin: 0 auto;" primary rounded @click="loadConversation">{{ i18n.ts.loadConversation }}</MkButton> <MkButton style="margin: 0 auto;" primary rounded @click="loadConversation">{{ i18n.ts.loadConversation }}</MkButton>
@ -27,7 +28,7 @@ SPDX-License-Identifier: AGPL-3.0-only
</I18n> </I18n>
</span> </span>
<div :class="$style.renoteInfo"> <div :class="$style.renoteInfo">
<button ref="renoteTime" class="_button" :class="$style.renoteTime" @click="showRenoteMenu()"> <button ref="renoteTime" class="_button" :class="$style.renoteTime" @mousedown.prevent="showRenoteMenu()">
<i v-if="isMyRenote" class="ti ti-dots" style="margin-right: 4px;"></i> <i v-if="isMyRenote" class="ti ti-dots" style="margin-right: 4px;"></i>
<MkTime :time="note.createdAt"/> <MkTime :time="note.createdAt"/>
</button> </button>
@ -105,7 +106,7 @@ SPDX-License-Identifier: AGPL-3.0-only
<MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton> <MkButton v-if="!allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-play ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.play }}</MkButton>
<MkButton v-else-if="!defaultStore.state.animatedMfm && allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-stop ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.stop }}</MkButton> <MkButton v-else-if="!defaultStore.state.animatedMfm && allowAnim && animated" :class="$style.playMFMButton" :small="true" @click="animatedMFM()" @click.stop><i class="ph-stop ph-bold ph-lg "></i> {{ i18n.ts._animatedMFM.stop }}</MkButton>
<div v-if="appearNote.files && appearNote.files.length > 0"> <div v-if="appearNote.files && appearNote.files.length > 0">
<MkMediaList :mediaList="appearNote.files"/> <MkMediaList ref="galleryEl" :mediaList="appearNote.files"/>
</div> </div>
<MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/> <MkPoll v-if="appearNote.poll" ref="pollViewer" :noteId="appearNote.id" :poll="appearNote.poll" :class="$style.poll"/>
<div v-if="isEnabledUrlPreview"> <div v-if="isEnabledUrlPreview">
@ -135,7 +136,7 @@ SPDX-License-Identifier: AGPL-3.0-only
class="_button" class="_button"
:class="$style.noteFooterButton" :class="$style.noteFooterButton"
:style="renoted ? 'color: var(--accent) !important;' : ''" :style="renoted ? 'color: var(--accent) !important;' : ''"
@mousedown="renoted ? undoRenote() : boostVisibility()" @mousedown.prevent="renoted ? undoRenote() : boostVisibility()"
> >
<i class="ti ti-repeat"></i> <i class="ti ti-repeat"></i>
<p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p> <p v-if="appearNote.renoteCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.renoteCount) }}</p>
@ -162,10 +163,10 @@ SPDX-License-Identifier: AGPL-3.0-only
<i v-else class="ph-smiley ph-bold ph-lg"></i> <i v-else class="ph-smiley ph-bold ph-lg"></i>
<p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p> <p v-if="(appearNote.reactionAcceptance === 'likeOnly' || defaultStore.state.showReactionsCount) && appearNote.reactionCount > 0" :class="$style.noteFooterButtonCount">{{ number(appearNote.reactionCount) }}</p>
</button> </button>
<button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown="clip()"> <button v-if="defaultStore.state.showClipButtonInNoteFooter" ref="clipButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="clip()">
<i class="ti ti-paperclip"></i> <i class="ti ti-paperclip"></i>
</button> </button>
<button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown="showMenu()"> <button ref="menuButton" class="_button" :class="$style.noteFooterButton" @mousedown.prevent="showMenu()">
<i class="ti ti-dots"></i> <i class="ti ti-dots"></i>
</button> </button>
</footer> </footer>
@ -244,7 +245,7 @@ import MkPoll from '@/components/MkPoll.vue';
import MkUsersTooltip from '@/components/MkUsersTooltip.vue'; import MkUsersTooltip from '@/components/MkUsersTooltip.vue';
import MkUrlPreview from '@/components/MkUrlPreview.vue'; import MkUrlPreview from '@/components/MkUrlPreview.vue';
import SkInstanceTicker from '@/components/SkInstanceTicker.vue'; import SkInstanceTicker from '@/components/SkInstanceTicker.vue';
import { pleaseLogin } from '@/scripts/please-login.js'; import { pleaseLogin, type OpenOnRemoteOptions } from '@/scripts/please-login.js';
import { checkWordMute } from '@/scripts/check-word-mute.js'; import { checkWordMute } from '@/scripts/check-word-mute.js';
import { userPage } from '@/filters/user.js'; import { userPage } from '@/filters/user.js';
import number from '@/filters/number.js'; import number from '@/filters/number.js';
@ -257,6 +258,7 @@ import { reactionPicker } from '@/scripts/reaction-picker.js';
import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js'; import { extractUrlFromMfm } from '@/scripts/extract-url-from-mfm.js';
import { $i } from '@/account.js'; import { $i } from '@/account.js';
import { i18n } from '@/i18n.js'; import { i18n } from '@/i18n.js';
import { host } from '@/config.js';
import { getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu.js'; import { getNoteClipMenu, getNoteMenu } from '@/scripts/get-note-menu.js';
import { getNoteVersionsMenu } from '@/scripts/get-note-versions-menu.js'; import { getNoteVersionsMenu } from '@/scripts/get-note-versions-menu.js';
import { useNoteCapture } from '@/scripts/use-note-capture.js'; import { useNoteCapture } from '@/scripts/use-note-capture.js';
@ -272,6 +274,7 @@ import MkReactionIcon from '@/components/MkReactionIcon.vue';
import MkButton from '@/components/MkButton.vue'; import MkButton from '@/components/MkButton.vue';
import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js'; import { boostMenuItems, type Visibility } from '@/scripts/boost-quote.js';
import { isEnabledUrlPreview } from '@/instance.js'; import { isEnabledUrlPreview } from '@/instance.js';
import { type Keymap } from '@/scripts/hotkey.js';
const props = withDefaults(defineProps<{ const props = withDefaults(defineProps<{
note: Misskey.entities.Note; note: Misskey.entities.Note;
@ -324,6 +327,7 @@ const quoteButton = shallowRef<HTMLElement>();
const clipButton = shallowRef<HTMLElement>(); const clipButton = shallowRef<HTMLElement>();
const likeButton = shallowRef<HTMLElement>(); const likeButton = shallowRef<HTMLElement>();
const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value); const appearNote = computed(() => isRenote ? note.value.renote as Misskey.entities.Note : note.value);
const galleryEl = shallowRef<InstanceType<typeof MkMediaList>>();
const isMyRenote = $i && ($i.id === note.value.userId); const isMyRenote = $i && ($i.id === note.value.userId);
const showContent = ref(defaultStore.state.uncollapseCW); const showContent = ref(defaultStore.state.uncollapseCW);
const isDeleted = ref(false); const isDeleted = ref(false);
@ -358,14 +362,31 @@ if ($i) {
let renoting = false; let renoting = false;
const pleaseLoginContext = computed<OpenOnRemoteOptions>(() => ({
type: 'lookup',
url: `https://${host}/notes/${appearNote.value.id}`,
}));
const keymap = { const keymap = {
'r': () => reply(true), 'r': () => reply(),
'e|a|plus': () => react(true), 'e|a|plus': () => react(),
'(q)': () => { if (canRenote.value && !renoted.value && !renoting) renote(defaultStore.state.visibilityOnBoost); }, 'q': () => { if (canRenote.value && !renoted.value && !renoting) renote(defaultStore.state.visibilityOnBoost); },
'esc': blur, 'm': () => showMenu(),
'm|o': () => showMenu(true), 'c': () => {
's': () => showContent.value !== showContent.value, if (!defaultStore.state.showClipButtonInNoteFooter) return;
}; clip();
},
'o': () => galleryEl.value?.openGallery(),
'v|enter': () => {
if (appearNote.value.cw != null) {
showContent.value = !showContent.value;
}
},
'esc': {
allowRepeat: true,
callback: () => blur(),
},
} as const satisfies Keymap;
provide('react', (reaction: string) => { provide('react', (reaction: string) => {
misskeyApi('notes/reactions/create', { misskeyApi('notes/reactions/create', {
@ -425,12 +446,14 @@ useTooltip(renoteButton, async (showing) => {
if (users.length < 1) return; if (users.length < 1) return;
os.popup(MkUsersTooltip, { const { dispose } = os.popup(MkUsersTooltip, {
showing, showing,
users, users,
count: appearNote.value.renoteCount, count: appearNote.value.renoteCount,
targetElement: renoteButton.value, targetElement: renoteButton.value,
}, {}, 'closed'); }, {
closed: () => dispose(),
});
}); });
useTooltip(quoteButton, async (showing) => { useTooltip(quoteButton, async (showing) => {
@ -444,12 +467,14 @@ useTooltip(quoteButton, async (showing) => {
if (users.length < 1) return; if (users.length < 1) return;
os.popup(MkUsersTooltip, { const { dispose } = os.popup(MkUsersTooltip, {
showing, showing,
users, users,
count: appearNote.value.renoteCount, count: appearNote.value.renoteCount,
targetElement: quoteButton.value, targetElement: quoteButton.value,
}, {}, 'closed'); }, {
closed: () => dispose(),
});
}); });
function boostVisibility() { function boostVisibility() {
@ -474,18 +499,20 @@ if (appearNote.value.reactionAcceptance === 'likeOnly') {
if (users.length < 1) return; if (users.length < 1) return;
os.popup(MkReactionsViewerDetails, { const { dispose } = os.popup(MkReactionsViewerDetails, {
showing, showing,
reaction: '❤️', reaction: '❤️',
users, users,
count: appearNote.value.reactionCount, count: appearNote.value.reactionCount,
targetElement: reactButton.value!, targetElement: reactButton.value!,
}, {}, 'closed'); }, {
closed: () => dispose(),
});
}); });
} }
function renote(visibility: Visibility, localOnly: boolean = false) { function renote(visibility: Visibility, localOnly: boolean = false) {
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog(); showMovedDialog();
renoting = true; renoting = true;
@ -496,7 +523,9 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
misskeyApi('notes/create', { misskeyApi('notes/create', {
@ -512,7 +541,9 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
misskeyApi('notes/create', { misskeyApi('notes/create', {
@ -527,7 +558,7 @@ function renote(visibility: Visibility, localOnly: boolean = false) {
} }
function quote() { function quote() {
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog(); showMovedDialog();
if (appearNote.value.channel) { if (appearNote.value.channel) {
@ -547,7 +578,9 @@ function quote() {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
os.toast(i18n.ts.quoted); os.toast(i18n.ts.quoted);
@ -569,7 +602,9 @@ function quote() {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
os.toast(i18n.ts.quoted); os.toast(i18n.ts.quoted);
@ -578,20 +613,19 @@ function quote() {
} }
} }
function reply(viaKeyboard = false): void { function reply(): void {
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog(); showMovedDialog();
os.post({ os.post({
reply: appearNote.value, reply: appearNote.value,
channel: appearNote.value.channel, channel: appearNote.value.channel,
animation: !viaKeyboard,
}).then(() => { }).then(() => {
focus(); focus();
}); });
} }
function react(viaKeyboard = false): void { function react(): void {
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog(); showMovedDialog();
if (appearNote.value.reactionAcceptance === 'likeOnly') { if (appearNote.value.reactionAcceptance === 'likeOnly') {
sound.playMisskeySfx('reaction'); sound.playMisskeySfx('reaction');
@ -600,12 +634,14 @@ function react(viaKeyboard = false): void {
noteId: appearNote.value.id, noteId: appearNote.value.id,
override: defaultLike.value, override: defaultLike.value,
}); });
const el = reactButton.value as HTMLElement | null | undefined; const el = reactButton.value;
if (el) { if (el) {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
} else { } else {
blur(); blur();
@ -626,7 +662,7 @@ function react(viaKeyboard = false): void {
} }
function like(): void { function like(): void {
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
showMovedDialog(); showMovedDialog();
sound.playMisskeySfx('reaction'); sound.playMisskeySfx('reaction');
misskeyApi('notes/like', { misskeyApi('notes/like', {
@ -638,7 +674,9 @@ function like(): void {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
} }
@ -663,7 +701,9 @@ function undoRenote() : void {
const rect = el.getBoundingClientRect(); const rect = el.getBoundingClientRect();
const x = rect.left + (el.offsetWidth / 2); const x = rect.left + (el.offsetWidth / 2);
const y = rect.top + (el.offsetHeight / 2); const y = rect.top + (el.offsetHeight / 2);
os.popup(MkRippleEffect, { x, y }, {}, 'end'); const { dispose } = os.popup(MkRippleEffect, { x, y }, {
end: () => dispose(),
});
} }
} }
@ -696,27 +736,23 @@ function onContextmenu(ev: MouseEvent): void {
} }
} }
function showMenu(viaKeyboard = false): void { function showMenu(): void {
const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted }); const { menu, cleanup } = getNoteMenu({ note: note.value, translating, translation, isDeleted });
os.popupMenu(menu, menuButton.value, { os.popupMenu(menu, menuButton.value).then(focus).finally(cleanup);
viaKeyboard,
}).then(focus).finally(cleanup);
} }
async function menuVersions(viaKeyboard = false): Promise<void> { async function menuVersions(): Promise<void> {
const { menu, cleanup } = await getNoteVersionsMenu({ note: note.value, menuVersionsButton }); const { menu, cleanup } = await getNoteVersionsMenu({ note: note.value, menuVersionsButton });
os.popupMenu(menu, menuVersionsButton.value, { os.popupMenu(menu, menuVersionsButton.value).then(focus).finally(cleanup);
viaKeyboard,
}).then(focus).finally(cleanup);
} }
async function clip() { async function clip(): Promise<void> {
os.popupMenu(await getNoteClipMenu({ note: note.value, isDeleted }), clipButton.value).then(focus); os.popupMenu(await getNoteClipMenu({ note: note.value, isDeleted }), clipButton.value).then(focus);
} }
function showRenoteMenu(viaKeyboard = false): void { function showRenoteMenu(): void {
if (!isMyRenote) return; if (!isMyRenote) return;
pleaseLogin(); pleaseLogin(undefined, pleaseLoginContext.value);
os.popupMenu([{ os.popupMenu([{
text: i18n.ts.unrenote, text: i18n.ts.unrenote,
icon: 'ti ti-trash', icon: 'ti ti-trash',
@ -727,9 +763,7 @@ function showRenoteMenu(viaKeyboard = false): void {
}); });
isDeleted.value = true; isDeleted.value = true;
}, },
}], renoteTime.value, { }], renoteTime.value);
viaKeyboard: viaKeyboard,
});
} }
function focus() { function focus() {
@ -829,6 +863,28 @@ onUnmounted(() => {
transition: box-shadow 0.1s ease; transition: box-shadow 0.1s ease;
overflow: clip; overflow: clip;
contain: content; contain: content;
&:focus-visible {
outline: none;
&::after {
content: "";
pointer-events: none;
display: block;
position: absolute;
z-index: 10;
top: 0;
left: 0;
right: 0;
bottom: 0;
margin: auto;
width: calc(100% - 8px);
height: calc(100% - 8px);
border: dashed 2px var(--focus);
border-radius: var(--radius);
box-sizing: border-box;
}
}
} }
.footer { .footer {