enhance(frontend): 下書き/予約投稿一覧は投稿フォームのアカウントメニュー内に移動し、下書き保存は「...」メニュー内に移動
This commit is contained in:
parent
5b5a1f08e1
commit
3c97c12e7f
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
### Client
|
### Client
|
||||||
- Enhance: デッキのメインカラムのヘッダをクリックしてページ上部/下部にスクロールできるように
|
- Enhance: デッキのメインカラムのヘッダをクリックしてページ上部/下部にスクロールできるように
|
||||||
|
- Enhance: 下書き/予約投稿一覧は投稿フォームのアカウントメニュー内に移動し、下書き保存は「...」メニュー内に移動されました
|
||||||
- Fix: カスタム絵文字画面(beta)のaliasesで使用される区切り文字が一致していないのを修正 #15614
|
- Fix: カスタム絵文字画面(beta)のaliasesで使用される区切り文字が一致していないのを修正 #15614
|
||||||
- Fix: バナー画像の幅が表示領域と一致していない問題を修正
|
- Fix: バナー画像の幅が表示領域と一致していない問題を修正
|
||||||
- Fix: 一部のブラウザでバナー画像が上下中央に表示されない問題を修正
|
- Fix: 一部のブラウザでバナー画像が上下中央に表示されない問題を修正
|
||||||
|
|
|
||||||
|
|
@ -211,13 +211,13 @@ export async function switchAccount(host: string, id: string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function openAccountMenu(opts: {
|
export async function getAccountMenu(opts: {
|
||||||
includeCurrentAccount?: boolean;
|
includeCurrentAccount?: boolean;
|
||||||
withExtraOperation: boolean;
|
withExtraOperation: boolean;
|
||||||
active?: Misskey.entities.User['id'];
|
active?: Misskey.entities.User['id'];
|
||||||
onChoose?: (account: Misskey.entities.MeDetailed) => void;
|
onChoose?: (account: Misskey.entities.MeDetailed) => void;
|
||||||
}, ev: MouseEvent) {
|
}) {
|
||||||
if (!$i) return;
|
if ($i == null) throw new Error('No current account');
|
||||||
const me = $i;
|
const me = $i;
|
||||||
|
|
||||||
const callback = opts.onChoose;
|
const callback = opts.onChoose;
|
||||||
|
|
@ -338,9 +338,7 @@ export async function openAccountMenu(opts: {
|
||||||
menuItems.push(...accountItems);
|
menuItems.push(...accountItems);
|
||||||
}
|
}
|
||||||
|
|
||||||
popupMenu(menuItems, ev.currentTarget ?? ev.target, {
|
return menuItems;
|
||||||
align: 'left',
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getAccountWithSigninDialog(): Promise<{ id: string, token: string } | null> {
|
export function getAccountWithSigninDialog(): Promise<{ id: string, token: string } | null> {
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,6 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
<button v-click-anime v-tooltip="i18n.ts.switchAccount" :class="$style.account" class="_button" @click="openAccountMenu">
|
<button v-click-anime v-tooltip="i18n.ts.switchAccount" :class="$style.account" class="_button" @click="openAccountMenu">
|
||||||
<img :class="$style.avatar" :src="(postAccount ?? $i).avatarUrl" style="border-radius: 100%;"/>
|
<img :class="$style.avatar" :src="(postAccount ?? $i).avatarUrl" style="border-radius: 100%;"/>
|
||||||
</button>
|
</button>
|
||||||
<button v-if="$i.policies.noteDraftLimit > 0" v-tooltip="(postAccount != null && postAccount.id !== $i.id) ? null : i18n.ts.draftsAndScheduledNotes" class="_button" :class="$style.draftButton" :disabled="postAccount != null && postAccount.id !== $i.id" @click="showDraftMenu"><i class="ti ti-list"></i></button>
|
|
||||||
</div>
|
</div>
|
||||||
<div :class="$style.headerRight">
|
<div :class="$style.headerRight">
|
||||||
<template v-if="!(targetChannel != null && fixed)">
|
<template v-if="!(targetChannel != null && fixed)">
|
||||||
|
|
@ -141,7 +140,7 @@ import MkInfo from '@/components/MkInfo.vue';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { ensureSignin, notesCount, incNotesCount } from '@/i.js';
|
import { ensureSignin, notesCount, incNotesCount } from '@/i.js';
|
||||||
import { getAccounts, openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
import { getAccounts, getAccountMenu } from '@/accounts.js';
|
||||||
import { deepClone } from '@/utility/clone.js';
|
import { deepClone } from '@/utility/clone.js';
|
||||||
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
import MkRippleEffect from '@/components/MkRippleEffect.vue';
|
||||||
import { miLocalStorage } from '@/local-storage.js';
|
import { miLocalStorage } from '@/local-storage.js';
|
||||||
|
|
@ -620,6 +619,19 @@ function showOtherSettings() {
|
||||||
action: () => {
|
action: () => {
|
||||||
toggleReactionAcceptance();
|
toggleReactionAcceptance();
|
||||||
},
|
},
|
||||||
|
}, { type: 'divider' }, {
|
||||||
|
type: 'button',
|
||||||
|
text: i18n.ts._drafts.saveToDraft,
|
||||||
|
icon: 'ti ti-cloud-upload',
|
||||||
|
action: async () => {
|
||||||
|
if (!canSaveAsServerDraft.value) {
|
||||||
|
return os.alert({
|
||||||
|
type: 'error',
|
||||||
|
text: i18n.ts._drafts.cannotCreateDraft,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
saveServerDraft();
|
||||||
|
},
|
||||||
}, ...($i.policies.scheduledNoteLimit > 0 ? [{
|
}, ...($i.policies.scheduledNoteLimit > 0 ? [{
|
||||||
icon: 'ti ti-calendar-time',
|
icon: 'ti ti-calendar-time',
|
||||||
text: i18n.ts.schedulePost + '...',
|
text: i18n.ts.schedulePost + '...',
|
||||||
|
|
@ -1159,34 +1171,9 @@ function showActions(ev: MouseEvent) {
|
||||||
|
|
||||||
const postAccount = ref<Misskey.entities.UserDetailed | null>(null);
|
const postAccount = ref<Misskey.entities.UserDetailed | null>(null);
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
async function openAccountMenu(ev: MouseEvent) {
|
||||||
if (props.mock) return;
|
if (props.mock) return;
|
||||||
|
|
||||||
openAccountMenu_({
|
|
||||||
withExtraOperation: false,
|
|
||||||
includeCurrentAccount: true,
|
|
||||||
active: postAccount.value != null ? postAccount.value.id : $i.id,
|
|
||||||
onChoose: (account) => {
|
|
||||||
if (account.id === $i.id) {
|
|
||||||
postAccount.value = null;
|
|
||||||
} else {
|
|
||||||
postAccount.value = account;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}, ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPerUploadItemMenu(item: UploaderItem, ev: MouseEvent) {
|
|
||||||
const menu = uploader.getMenu(item);
|
|
||||||
os.popupMenu(menu, ev.currentTarget ?? ev.target);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showPerUploadItemMenuViaContextmenu(item: UploaderItem, ev: MouseEvent) {
|
|
||||||
const menu = uploader.getMenu(item);
|
|
||||||
os.contextMenu(menu, ev);
|
|
||||||
}
|
|
||||||
|
|
||||||
function showDraftMenu(ev: MouseEvent) {
|
|
||||||
function showDraftsDialog(scheduled: boolean) {
|
function showDraftsDialog(scheduled: boolean) {
|
||||||
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNoteDraftsDialog.vue')), {
|
const { dispose } = os.popup(defineAsyncComponent(() => import('@/components/MkNoteDraftsDialog.vue')), {
|
||||||
scheduled,
|
scheduled,
|
||||||
|
|
@ -1244,34 +1231,44 @@ function showDraftMenu(ev: MouseEvent) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
os.popupMenu([{
|
const items = await getAccountMenu({
|
||||||
type: 'button',
|
withExtraOperation: false,
|
||||||
text: i18n.ts._drafts.saveToDraft,
|
includeCurrentAccount: true,
|
||||||
icon: 'ti ti-cloud-upload',
|
active: postAccount.value != null ? postAccount.value.id : $i.id,
|
||||||
action: async () => {
|
onChoose: (account) => {
|
||||||
if (!canSaveAsServerDraft.value) {
|
if (account.id === $i.id) {
|
||||||
return os.alert({
|
postAccount.value = null;
|
||||||
type: 'error',
|
} else {
|
||||||
text: i18n.ts._drafts.cannotCreateDraft,
|
postAccount.value = account;
|
||||||
});
|
|
||||||
}
|
}
|
||||||
saveServerDraft();
|
|
||||||
},
|
},
|
||||||
}, {
|
});
|
||||||
|
|
||||||
|
os.popupMenu([{
|
||||||
type: 'button',
|
type: 'button',
|
||||||
text: i18n.ts._drafts.listDrafts,
|
text: i18n.ts._drafts.listDrafts,
|
||||||
icon: 'ti ti-cloud-download',
|
icon: 'ti ti-cloud-download',
|
||||||
action: () => {
|
action: () => {
|
||||||
showDraftsDialog(false);
|
showDraftsDialog(false);
|
||||||
},
|
},
|
||||||
}, { type: 'divider' }, {
|
}, {
|
||||||
type: 'button',
|
type: 'button',
|
||||||
text: i18n.ts._drafts.listScheduledNotes,
|
text: i18n.ts._drafts.listScheduledNotes,
|
||||||
icon: 'ti ti-clock-down',
|
icon: 'ti ti-clock-down',
|
||||||
action: () => {
|
action: () => {
|
||||||
showDraftsDialog(true);
|
showDraftsDialog(true);
|
||||||
},
|
},
|
||||||
}], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
|
}, { type: 'divider' }, ...items], (ev.currentTarget ?? ev.target ?? undefined) as HTMLElement | undefined);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPerUploadItemMenu(item: UploaderItem, ev: MouseEvent) {
|
||||||
|
const menu = uploader.getMenu(item);
|
||||||
|
os.popupMenu(menu, ev.currentTarget ?? ev.target);
|
||||||
|
}
|
||||||
|
|
||||||
|
function showPerUploadItemMenuViaContextmenu(item: UploaderItem, ev: MouseEvent) {
|
||||||
|
const menu = uploader.getMenu(item);
|
||||||
|
os.contextMenu(menu, ev);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function schedule() {
|
async function schedule() {
|
||||||
|
|
@ -1422,20 +1419,6 @@ defineExpose({
|
||||||
margin: auto;
|
margin: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.draftButton {
|
|
||||||
padding: 8px;
|
|
||||||
font-size: 90%;
|
|
||||||
border-radius: 6px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: light-dark(rgba(0, 0, 0, 0.05), rgba(255, 255, 255, 0.05));
|
|
||||||
}
|
|
||||||
|
|
||||||
&:disabled {
|
|
||||||
background: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.headerRight {
|
.headerRight {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-height: 48px;
|
min-height: 48px;
|
||||||
|
|
|
||||||
|
|
@ -62,9 +62,10 @@ import { onMounted, onUnmounted, ref, inject, useTemplateRef, computed } from 'v
|
||||||
import { scrollToTop } from '@@/js/scroll.js';
|
import { scrollToTop } from '@@/js/scroll.js';
|
||||||
import XTabs from './MkPageHeader.tabs.vue';
|
import XTabs from './MkPageHeader.tabs.vue';
|
||||||
import { globalEvents } from '@/events.js';
|
import { globalEvents } from '@/events.js';
|
||||||
import { openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
import { getAccountMenu } from '@/accounts.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { DI } from '@/di.js';
|
import { DI } from '@/di.js';
|
||||||
|
import * as os from '@/os.js';
|
||||||
|
|
||||||
const props = withDefaults(defineProps<PageHeaderProps>(), {
|
const props = withDefaults(defineProps<PageHeaderProps>(), {
|
||||||
tabs: () => ([] as Tab[]),
|
tabs: () => ([] as Tab[]),
|
||||||
|
|
@ -99,10 +100,12 @@ const top = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
async function openAccountMenu(ev: MouseEvent) {
|
||||||
openAccountMenu_({
|
const menuItems = await getAccountMenu({
|
||||||
withExtraOperation: true,
|
withExtraOperation: true,
|
||||||
}, ev);
|
});
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTabClick(): void {
|
function onTabClick(): void {
|
||||||
|
|
|
||||||
|
|
@ -55,7 +55,7 @@ import MkButton from '@/components/MkButton.vue';
|
||||||
import { instance } from '@/instance.js';
|
import { instance } from '@/instance.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
import { getAccountMenu } from '@/accounts.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
import { getHTMLElementOrNull } from '@/utility/get-dom-node-or-null.js';
|
import { getHTMLElementOrNull } from '@/utility/get-dom-node-or-null.js';
|
||||||
|
|
||||||
|
|
@ -84,10 +84,12 @@ async function more(ev: MouseEvent) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
async function openAccountMenu(ev: MouseEvent) {
|
||||||
openAccountMenu_({
|
const menuItems = await getAccountMenu({
|
||||||
withExtraOperation: true,
|
withExtraOperation: true,
|
||||||
}, ev);
|
});
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
|
|
|
||||||
|
|
@ -109,7 +109,7 @@ import { instance } from '@/instance.js';
|
||||||
import { getHTMLElementOrNull } from '@/utility/get-dom-node-or-null.js';
|
import { getHTMLElementOrNull } from '@/utility/get-dom-node-or-null.js';
|
||||||
import { useRouter } from '@/router.js';
|
import { useRouter } from '@/router.js';
|
||||||
import { prefer } from '@/preferences.js';
|
import { prefer } from '@/preferences.js';
|
||||||
import { openAccountMenu as openAccountMenu_ } from '@/accounts.js';
|
import { getAccountMenu } from '@/accounts.js';
|
||||||
import { $i } from '@/i.js';
|
import { $i } from '@/i.js';
|
||||||
|
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
@ -170,10 +170,12 @@ function toggleRealtimeMode(ev: MouseEvent) {
|
||||||
}], ev.currentTarget ?? ev.target);
|
}], ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
function openAccountMenu(ev: MouseEvent) {
|
async function openAccountMenu(ev: MouseEvent) {
|
||||||
openAccountMenu_({
|
const menuItems = await getAccountMenu({
|
||||||
withExtraOperation: true,
|
withExtraOperation: true,
|
||||||
}, ev);
|
});
|
||||||
|
|
||||||
|
os.popupMenu(menuItems, ev.currentTarget ?? ev.target);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function more(ev: MouseEvent) {
|
async function more(ev: MouseEvent) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue