mirror of
https://github.com/misskey-dev/misskey.git
synced 2024-12-27 06:00:21 +01:00
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
|
### Improvements
|
||||||
- カスタム絵文字一括編集機能
|
- カスタム絵文字一括編集機能
|
||||||
- カスタム絵文字一括インポート
|
- カスタム絵文字一括インポート
|
||||||
|
- 投稿フォームで一時的に投稿するアカウントを切り替えられるように
|
||||||
|
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
|
|
||||||
|
|
|
@ -129,7 +129,12 @@ export async function login(token: Account['token'], redirect?: string) {
|
||||||
unisonReload();
|
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() {
|
function showSigninDialog() {
|
||||||
popup(import('@/components/signin-dialog.vue'), {}, {
|
popup(import('@/components/signin-dialog.vue'), {}, {
|
||||||
done: res => {
|
done: res => {
|
||||||
|
@ -148,7 +153,7 @@ export async function openAccountMenu(ev: MouseEvent) {
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
}
|
}
|
||||||
|
|
||||||
async function switchAccount(account: any) {
|
async function switchAccount(account: misskey.entities.UserDetailed) {
|
||||||
const storedAccounts = await getAccounts();
|
const storedAccounts = await getAccounts();
|
||||||
const token = storedAccounts.find(x => x.id === account.id).token;
|
const token = storedAccounts.find(x => x.id === account.id).token;
|
||||||
switchAccountWithToken(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 storedAccounts = await getAccounts().then(accounts => accounts.filter(x => x.id !== $i.id));
|
||||||
const accountsPromise = api('users/show', { userIds: storedAccounts.map(x => x.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 => {
|
const accountItemPromises = storedAccounts.map(a => new Promise(res => {
|
||||||
accountsPromise.then(accounts => {
|
accountsPromise.then(accounts => {
|
||||||
const account = accounts.find(x => x.id === a.id);
|
const account = accounts.find(x => x.id === a.id);
|
||||||
if (account == null) return res(null);
|
if (account == null) return res(null);
|
||||||
res({
|
res(createItem(account));
|
||||||
type: 'user',
|
|
||||||
user: account,
|
|
||||||
action: () => { switchAccount(account); }
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
popupMenu([...[{
|
if (opts.withExtraOperation) {
|
||||||
type: 'link',
|
popupMenu([...[{
|
||||||
text: i18n.locale.profile,
|
type: 'link',
|
||||||
to: `/@${ $i.username }`,
|
text: i18n.locale.profile,
|
||||||
avatar: $i,
|
to: `/@${ $i.username }`,
|
||||||
}, null, ...accountItemPromises, {
|
avatar: $i,
|
||||||
icon: 'fas fa-plus',
|
}, null, ...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises, {
|
||||||
text: i18n.locale.addAccount,
|
icon: 'fas fa-plus',
|
||||||
action: () => {
|
text: i18n.locale.addAccount,
|
||||||
popupMenu([{
|
action: () => {
|
||||||
text: i18n.locale.existingAccount,
|
popupMenu([{
|
||||||
action: () => { showSigninDialog(); },
|
text: i18n.locale.existingAccount,
|
||||||
}, {
|
action: () => { showSigninDialog(); },
|
||||||
text: i18n.locale.createAccount,
|
}, {
|
||||||
action: () => { createAccount(); },
|
text: i18n.locale.createAccount,
|
||||||
}], ev.currentTarget || ev.target);
|
action: () => { createAccount(); },
|
||||||
},
|
}], ev.currentTarget || ev.target);
|
||||||
}, {
|
},
|
||||||
type: 'link',
|
}, {
|
||||||
icon: 'fas fa-users',
|
type: 'link',
|
||||||
text: i18n.locale.manageAccounts,
|
icon: 'fas fa-users',
|
||||||
to: `/settings/accounts`,
|
text: i18n.locale.manageAccounts,
|
||||||
}]], ev.currentTarget || ev.target, {
|
to: `/settings/accounts`,
|
||||||
align: 'left'
|
}]], ev.currentTarget || ev.target, {
|
||||||
});
|
align: 'left'
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
popupMenu([...(opts.includeCurrentAccount ? [createItem($i)] : []), ...accountItemPromises], ev.currentTarget || ev.target, {
|
||||||
|
align: 'left'
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,9 @@
|
||||||
>
|
>
|
||||||
<header>
|
<header>
|
||||||
<button v-if="!fixed" class="cancel _button" @click="cancel"><i class="fas fa-times"></i></button>
|
<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>
|
<div>
|
||||||
<span class="text-count" :class="{ over: textLength > maxTextLength }">{{ maxTextLength - textLength }}</span>
|
<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>
|
<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 MkInfo from '@/components/ui/info.vue';
|
||||||
import { i18n } from '@/i18n';
|
import { i18n } from '@/i18n';
|
||||||
import { instance } from '@/instance';
|
import { instance } from '@/instance';
|
||||||
import { $i } from '@/account';
|
import { $i, getAccounts, openAccountMenu as openAccountMenu_ } from '@/account';
|
||||||
|
|
||||||
const modal = inject('modal');
|
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;
|
posting = true;
|
||||||
os.api('notes/create', data).then(() => {
|
os.api('notes/create', data, token).then(() => {
|
||||||
clear();
|
clear();
|
||||||
nextTick(() => {
|
nextTick(() => {
|
||||||
deleteDraft();
|
deleteDraft();
|
||||||
|
@ -585,7 +595,7 @@ function insertMention() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function insertEmoji(ev) {
|
async function insertEmoji(ev: MouseEvent) {
|
||||||
os.openEmojiPicker(ev.currentTarget || ev.target, {}, textareaEl);
|
os.openEmojiPicker(ev.currentTarget || ev.target, {}, textareaEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -602,6 +612,23 @@ function showActions(ev) {
|
||||||
})), ev.currentTarget || ev.target);
|
})), 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(() => {
|
onMounted(() => {
|
||||||
if (props.autofocus) {
|
if (props.autofocus) {
|
||||||
focus();
|
focus();
|
||||||
|
@ -678,6 +705,19 @@ onMounted(() => {
|
||||||
line-height: 66px;
|
line-height: 66px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
> .account {
|
||||||
|
height: 100%;
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
display: inline-flex;
|
||||||
|
vertical-align: bottom;
|
||||||
|
|
||||||
|
> .avatar {
|
||||||
|
width: 28px;
|
||||||
|
height: 28px;
|
||||||
|
margin: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
> div {
|
> div {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 0;
|
top: 0;
|
||||||
|
|
|
@ -24,7 +24,7 @@
|
||||||
<span>{{ item.text }}</span>
|
<span>{{ item.text }}</span>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
|
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
|
||||||
</a>
|
</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"/>
|
<MkAvatar :user="item.user" class="avatar"/><MkUserName :user="item.user"/>
|
||||||
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
|
<span v-if="item.indicate" class="indicator"><i class="fas fa-circle"></i></span>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -61,7 +61,11 @@ export default defineComponent({
|
||||||
otherMenuItemIndicated,
|
otherMenuItemIndicated,
|
||||||
post: os.post,
|
post: os.post,
|
||||||
search,
|
search,
|
||||||
openAccountMenu,
|
openAccountMenu:(ev) => {
|
||||||
|
openAccountMenu({
|
||||||
|
withExtraOperation: true,
|
||||||
|
}, ev);
|
||||||
|
},
|
||||||
more: () => {
|
more: () => {
|
||||||
os.popup(import('@/components/launch-pad.vue'), {}, {
|
os.popup(import('@/components/launch-pad.vue'), {}, {
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
|
|
|
@ -76,7 +76,11 @@ export default defineComponent({
|
||||||
iconOnly,
|
iconOnly,
|
||||||
post: os.post,
|
post: os.post,
|
||||||
search,
|
search,
|
||||||
openAccountMenu,
|
openAccountMenu:(ev) => {
|
||||||
|
openAccountMenu({
|
||||||
|
withExtraOperation: true,
|
||||||
|
}, ev);
|
||||||
|
},
|
||||||
more: () => {
|
more: () => {
|
||||||
os.popup(import('@/components/launch-pad.vue'), {}, {
|
os.popup(import('@/components/launch-pad.vue'), {}, {
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
|
|
|
@ -105,7 +105,11 @@ export default defineComponent({
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
openAccountMenu,
|
openAccountMenu:(ev) => {
|
||||||
|
openAccountMenu({
|
||||||
|
withExtraOperation: true,
|
||||||
|
}, ev);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
|
@ -125,7 +125,11 @@ export default defineComponent({
|
||||||
}, 'closed');
|
}, 'closed');
|
||||||
},
|
},
|
||||||
|
|
||||||
openAccountMenu,
|
openAccountMenu:(ev) => {
|
||||||
|
openAccountMenu({
|
||||||
|
withExtraOperation: true,
|
||||||
|
}, ev);
|
||||||
|
},
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
|
|
Loading…
Reference in a new issue