feat(client): make possible to switch account instantly in post form
This commit is contained in:
		
							parent
							
								
									b388b78892
								
							
						
					
					
						commit
						331afcb96a
					
				
					 8 changed files with 119 additions and 40 deletions
				
			
		|  | @ -21,6 +21,7 @@ | |||
| ### Improvements | ||||
| - カスタム絵文字一括編集機能 | ||||
| - カスタム絵文字一括インポート | ||||
| - 投稿フォームで一時的に投稿するアカウントを切り替えられるように | ||||
| 
 | ||||
| ### Bugfixes | ||||
| 
 | ||||
|  |  | |||
|  | @ -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' | ||||
| 		}); | ||||
| 	} | ||||
| } | ||||
|  |  | |||
|  | @ -8,6 +8,9 @@ | |||
| > | ||||
| 	<header> | ||||
| 		<button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button> | ||||
| 		<button v-click-anime class="account _button" @click="openAccountMenu"> | ||||
| 			<MkAvatar :user="postAccount ?? $i" class="avatar"/> | ||||
| 		</button> | ||||
| 		<div> | ||||
| 			<span class="text-count" :class="{ over: textLength > maxTextLength }">{{ maxTextLength - textLength }}</span> | ||||
| 			<span v-if="localOnly" class="local-only"><i class="fas fa-biohazard"></i></span> | ||||
|  | @ -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<misskey.entities.UserDetailed | null>(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; | ||||
|  |  | |||
|  | @ -24,7 +24,7 @@ | |||
| 			<span>{{ item.text }}</span> | ||||
| 			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span> | ||||
| 		</a> | ||||
| 		<button v-else-if="item.type === 'user'" :tabindex="i" class="_button item" @click="clicked(item.action, $event)"> | ||||
| 		<button v-else-if="item.type === 'user'" :tabindex="i" class="_button item" :class="{ active: item.active }" :disabled="item.active" @click="clicked(item.action, $event)"> | ||||
| 			<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/> | ||||
| 			<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span> | ||||
| 		</button> | ||||
|  |  | |||
|  | @ -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'); | ||||
|  |  | |||
|  | @ -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'); | ||||
|  |  | |||
|  | @ -105,7 +105,11 @@ export default defineComponent({ | |||
| 			}, 'closed'); | ||||
| 		}, | ||||
| 
 | ||||
| 		openAccountMenu, | ||||
| 		openAccountMenu:(ev) => { | ||||
| 			openAccountMenu({ | ||||
| 				withExtraOperation: true, | ||||
| 			}, ev); | ||||
| 		}, | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  |  | |||
|  | @ -125,7 +125,11 @@ export default defineComponent({ | |||
| 			}, 'closed'); | ||||
| 		}, | ||||
| 
 | ||||
| 		openAccountMenu, | ||||
| 		openAccountMenu:(ev) => { | ||||
| 			openAccountMenu({ | ||||
| 				withExtraOperation: true, | ||||
| 			}, ev); | ||||
| 		}, | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue