From 331afcb96a638d436f7fa925bc395ef04057a147 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 21 Jan 2022 20:17:31 +0900 Subject: [PATCH] feat(client): make possible to switch account instantly in post form --- CHANGELOG.md | 1 + packages/client/src/account.ts | 86 ++++++++++++------- packages/client/src/components/post-form.vue | 46 +++++++++- packages/client/src/components/ui/menu.vue | 2 +- .../src/ui/_common_/sidebar-for-mobile.vue | 6 +- packages/client/src/ui/_common_/sidebar.vue | 6 +- packages/client/src/ui/classic.header.vue | 6 +- packages/client/src/ui/classic.sidebar.vue | 6 +- 8 files changed, 119 insertions(+), 40 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5bdf76b79c..5228be120b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ ### Improvements - カスタム絵文字一括編集機能 - カスタム絵文字一括インポート +- 投稿フォームで一時的に投稿するアカウントを切り替えられるように ### Bugfixes diff --git a/packages/client/src/account.ts b/packages/client/src/account.ts index 76a0d2bd00..5a935e1dc7 100644 --- a/packages/client/src/account.ts +++ b/packages/client/src/account.ts @@ -129,7 +129,12 @@ export async function login(token: Account['token'], redirect?: string) { unisonReload(); } -export async function openAccountMenu(ev: MouseEvent) { +export async function openAccountMenu(opts: { + includeCurrentAccount?: boolean; + withExtraOperation: boolean; + active?: misskey.entities.UserDetailed['id']; + onChoose?: (account: misskey.entities.UserDetailed) => void; +}, ev: MouseEvent) { function showSigninDialog() { popup(import('@/components/signin-dialog.vue'), {}, { done: res => { @@ -148,7 +153,7 @@ export async function openAccountMenu(ev: MouseEvent) { }, 'closed'); } - async function switchAccount(account: any) { + async function switchAccount(account: misskey.entities.UserDetailed) { const storedAccounts = await getAccounts(); const token = storedAccounts.find(x => x.id === account.id).token; switchAccountWithToken(token); @@ -161,41 +166,58 @@ export async function openAccountMenu(ev: MouseEvent) { const storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id)); const accountsPromise = api('users/show', { userIds: storedAccounts.map(x => x.id) }); + function createItem(account: misskey.entities.UserDetailed) { + return { + type: 'user', + user: account, + active: opts.active != null ? opts.active === account.id : false, + action: () => { + if (opts.onChoose) { + opts.onChoose(account); + } else { + switchAccount(account); + } + }, + }; + } + const accountItemPromises = storedAccounts.map(a => new Promise(res => { accountsPromise.then(accounts => { const account = accounts.find(x => x.id === a.id); if (account == null) return res(null); - res({ - type: 'user', - user: account, - action: () => { switchAccount(account); } - }); + res(createItem(account)); }); })); - popupMenu([...[{ - type: 'link', - text: i18n.locale.profile, - to: `/@${ $i.username }`, - avatar: $i, - }, null, ...accountItemPromises, { - icon: 'fas fa-plus', - text: i18n.locale.addAccount, - action: () => { - popupMenu([{ - text: i18n.locale.existingAccount, - action: () => { showSigninDialog(); }, - }, { - text: i18n.locale.createAccount, - action: () => { createAccount(); }, - }], ev.currentTarget || ev.target); - }, - }, { - type: 'link', - icon: 'fas fa-users', - text: i18n.locale.manageAccounts, - to: `/settings/accounts`, - }]], ev.currentTarget || ev.target, { - align: 'left' - }); + if (opts.withExtraOperation) { + popupMenu([...[{ + type: 'link', + text: i18n.locale.profile, + to: `/@${ $i.username }`, + avatar: $i, + }, null, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, { + icon: 'fas fa-plus', + text: i18n.locale.addAccount, + action: () => { + popupMenu([{ + text: i18n.locale.existingAccount, + action: () => { showSigninDialog(); }, + }, { + text: i18n.locale.createAccount, + action: () => { createAccount(); }, + }], ev.currentTarget || ev.target); + }, + }, { + type: 'link', + icon: 'fas fa-users', + text: i18n.locale.manageAccounts, + to: `/settings/accounts`, + }]], ev.currentTarget || ev.target, { + align: 'left' + }); + } else { + popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget || ev.target, { + align: 'left' + }); + } } diff --git a/packages/client/src/components/post-form.vue b/packages/client/src/components/post-form.vue index 60b062f054..3ab8af3092 100644 --- a/packages/client/src/components/post-form.vue +++ b/packages/client/src/components/post-form.vue @@ -8,6 +8,9 @@ >
+
{{ maxTextLength - textLength }} @@ -83,7 +86,7 @@ import { throttle } from 'throttle-debounce'; import MkInfo from '@/components/ui/info.vue'; import { i18n } from '@/i18n'; import { instance } from '@/instance'; -import { $i } from '@/account'; +import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account'; const modal = inject('modal'); @@ -553,8 +556,15 @@ async function post() { } } + let token = undefined; + + if (postAccount) { + const storedAccounts = await getAccounts(); + token = storedAccounts.find(x => x.id === postAccount.id)?.token; + } + posting = true; - os.api('notes/create', data).then(() => { + os.api('notes/create', data, token).then(() => { clear(); nextTick(() => { deleteDraft(); @@ -585,7 +595,7 @@ function insertMention() { }); } -async function insertEmoji(ev) { +async function insertEmoji(ev: MouseEvent) { os.openEmojiPicker(ev.currentTarget || ev.target, {}, textareaEl); } @@ -602,6 +612,23 @@ function showActions(ev) { })), ev.currentTarget || ev.target); } +let postAccount = $ref(null); + +function openAccountMenu(ev: MouseEvent) { + openAccountMenu_({ + withExtraOperation: false, + includeCurrentAccount: true, + active: postAccount != null ? postAccount.id : $i.id, + onChoose: (account) => { + if (account.id === $i.id) { + postAccount = null; + } else { + postAccount = account; + } + }, + }, ev); +} + onMounted(() => { if (props.autofocus) { focus(); @@ -678,6 +705,19 @@ onMounted(() => { line-height: 66px; } + > .account { + height: 100%; + aspect-ratio: 1/1; + display: inline-flex; + vertical-align: bottom; + + > .avatar { + width: 28px; + height: 28px; + margin: auto; + } + } + > div { position: absolute; top: 0; diff --git a/packages/client/src/components/ui/menu.vue b/packages/client/src/components/ui/menu.vue index 6f3f277b11..41165c8d33 100644 --- a/packages/client/src/components/ui/menu.vue +++ b/packages/client/src/components/ui/menu.vue @@ -24,7 +24,7 @@ {{ item.text }} - diff --git a/packages/client/src/ui/_common_/sidebar-for-mobile.vue b/packages/client/src/ui/_common_/sidebar-for-mobile.vue index 5babdb98a8..afcc50725b 100644 --- a/packages/client/src/ui/_common_/sidebar-for-mobile.vue +++ b/packages/client/src/ui/_common_/sidebar-for-mobile.vue @@ -61,7 +61,11 @@ export default defineComponent({ otherMenuItemIndicated, post: os.post, search, - openAccountMenu, + openAccountMenu:(ev) => { + openAccountMenu({ + withExtraOperation: true, + }, ev); + }, more: () => { os.popup(import('@/components/launch-pad.vue'), {}, { }, 'closed'); diff --git a/packages/client/src/ui/_common_/sidebar.vue b/packages/client/src/ui/_common_/sidebar.vue index fa712ba45d..94baacbee9 100644 --- a/packages/client/src/ui/_common_/sidebar.vue +++ b/packages/client/src/ui/_common_/sidebar.vue @@ -76,7 +76,11 @@ export default defineComponent({ iconOnly, post: os.post, search, - openAccountMenu, + openAccountMenu:(ev) => { + openAccountMenu({ + withExtraOperation: true, + }, ev); + }, more: () => { os.popup(import('@/components/launch-pad.vue'), {}, { }, 'closed'); diff --git a/packages/client/src/ui/classic.header.vue b/packages/client/src/ui/classic.header.vue index 3563e8a888..699b992668 100644 --- a/packages/client/src/ui/classic.header.vue +++ b/packages/client/src/ui/classic.header.vue @@ -105,7 +105,11 @@ export default defineComponent({ }, 'closed'); }, - openAccountMenu, + openAccountMenu:(ev) => { + openAccountMenu({ + withExtraOperation: true, + }, ev); + }, } }); diff --git a/packages/client/src/ui/classic.sidebar.vue b/packages/client/src/ui/classic.sidebar.vue index cc9d7a9b48..afbca06c8e 100644 --- a/packages/client/src/ui/classic.sidebar.vue +++ b/packages/client/src/ui/classic.sidebar.vue @@ -125,7 +125,11 @@ export default defineComponent({ }, 'closed'); }, - openAccountMenu, + openAccountMenu:(ev) => { + openAccountMenu({ + withExtraOperation: true, + }, ev); + }, } });