summaryrefslogtreecommitdiff
path: root/packages/frontend/src/components/MkUserSelectDialog.vue
diff options
context:
space:
mode:
authorsyuilo <Syuilotan@yahoo.co.jp>2022-12-27 14:36:33 +0900
committersyuilo <Syuilotan@yahoo.co.jp>2022-12-27 14:36:33 +0900
commit9384f5399da39e53855beb8e7f8ded1aa56bf72e (patch)
treece5959571a981b9c4047da3c7b3fd080aa44222c /packages/frontend/src/components/MkUserSelectDialog.vue
parentwip: retention for dashboard (diff)
downloadsharkey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.tar.gz
sharkey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.tar.bz2
sharkey-9384f5399da39e53855beb8e7f8ded1aa56bf72e.zip
rename: client -> frontend
Diffstat (limited to 'packages/frontend/src/components/MkUserSelectDialog.vue')
-rw-r--r--packages/frontend/src/components/MkUserSelectDialog.vue190
1 files changed, 190 insertions, 0 deletions
diff --git a/packages/frontend/src/components/MkUserSelectDialog.vue b/packages/frontend/src/components/MkUserSelectDialog.vue
new file mode 100644
index 0000000000..1d31769c30
--- /dev/null
+++ b/packages/frontend/src/components/MkUserSelectDialog.vue
@@ -0,0 +1,190 @@
+<template>
+<XModalWindow
+ ref="dialogEl"
+ :with-ok-button="true"
+ :ok-button-disabled="selected == null"
+ @click="cancel()"
+ @close="cancel()"
+ @ok="ok()"
+ @closed="$emit('closed')"
+>
+ <template #header>{{ i18n.ts.selectUser }}</template>
+ <div class="tbhwbxda">
+ <div class="form">
+ <FormSplit :min-width="170">
+ <MkInput v-model="username" :autofocus="true" @update:model-value="search">
+ <template #label>{{ i18n.ts.username }}</template>
+ <template #prefix>@</template>
+ </MkInput>
+ <MkInput v-model="host" @update:model-value="search">
+ <template #label>{{ i18n.ts.host }}</template>
+ <template #prefix>@</template>
+ </MkInput>
+ </FormSplit>
+ </div>
+ <div v-if="username != '' || host != ''" class="result" :class="{ hit: users.length > 0 }">
+ <div v-if="users.length > 0" class="users">
+ <div v-for="user in users" :key="user.id" class="user" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
+ <MkAvatar :user="user" class="avatar" :show-indicator="true"/>
+ <div class="body">
+ <MkUserName :user="user" class="name"/>
+ <MkAcct :user="user" class="acct"/>
+ </div>
+ </div>
+ </div>
+ <div v-else class="empty">
+ <span>{{ i18n.ts.noUsers }}</span>
+ </div>
+ </div>
+ <div v-if="username == '' && host == ''" class="recent">
+ <div class="users">
+ <div v-for="user in recentUsers" :key="user.id" class="user" :class="{ selected: selected && selected.id === user.id }" @click="selected = user" @dblclick="ok()">
+ <MkAvatar :user="user" class="avatar" :show-indicator="true"/>
+ <div class="body">
+ <MkUserName :user="user" class="name"/>
+ <MkAcct :user="user" class="acct"/>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+</XModalWindow>
+</template>
+
+<script lang="ts" setup>
+import { nextTick, onMounted } from 'vue';
+import * as misskey from 'misskey-js';
+import MkInput from '@/components/form/input.vue';
+import FormSplit from '@/components/form/split.vue';
+import XModalWindow from '@/components/MkModalWindow.vue';
+import * as os from '@/os';
+import { defaultStore } from '@/store';
+import { i18n } from '@/i18n';
+
+const emit = defineEmits<{
+ (ev: 'ok', selected: misskey.entities.UserDetailed): void;
+ (ev: 'cancel'): void;
+ (ev: 'closed'): void;
+}>();
+
+let username = $ref('');
+let host = $ref('');
+let users: misskey.entities.UserDetailed[] = $ref([]);
+let recentUsers: misskey.entities.UserDetailed[] = $ref([]);
+let selected: misskey.entities.UserDetailed | null = $ref(null);
+let dialogEl = $ref();
+
+const search = () => {
+ if (username === '' && host === '') {
+ users = [];
+ return;
+ }
+ os.api('users/search-by-username-and-host', {
+ username: username,
+ host: host,
+ limit: 10,
+ detail: false,
+ }).then(_users => {
+ users = _users;
+ });
+};
+
+const ok = () => {
+ if (selected == null) return;
+ emit('ok', selected);
+ dialogEl.close();
+
+ // 最近使ったユーザー更新
+ let recents = defaultStore.state.recentlyUsedUsers;
+ recents = recents.filter(x => x !== selected.id);
+ recents.unshift(selected.id);
+ defaultStore.set('recentlyUsedUsers', recents.splice(0, 16));
+};
+
+const cancel = () => {
+ emit('cancel');
+ dialogEl.close();
+};
+
+onMounted(() => {
+ os.api('users/show', {
+ userIds: defaultStore.state.recentlyUsedUsers,
+ }).then(users => {
+ recentUsers = users;
+ });
+});
+</script>
+
+<style lang="scss" scoped>
+.tbhwbxda {
+ > .form {
+ padding: 0 var(--root-margin);
+ }
+
+ > .result, > .recent {
+ display: flex;
+ flex-direction: column;
+ overflow: auto;
+ height: 100%;
+
+ &.result.hit {
+ padding: 0;
+ }
+
+ &.recent {
+ padding: 0;
+ }
+
+ > .users {
+ flex: 1;
+ overflow: auto;
+ padding: 8px 0;
+
+ > .user {
+ display: flex;
+ align-items: center;
+ padding: 8px var(--root-margin);
+ font-size: 14px;
+
+ &:hover {
+ background: var(--X7);
+ }
+
+ &.selected {
+ background: var(--accent);
+ color: #fff;
+ }
+
+ > * {
+ pointer-events: none;
+ user-select: none;
+ }
+
+ > .avatar {
+ width: 45px;
+ height: 45px;
+ }
+
+ > .body {
+ padding: 0 8px;
+ min-width: 0;
+
+ > .name {
+ display: block;
+ font-weight: bold;
+ }
+
+ > .acct {
+ opacity: 0.5;
+ }
+ }
+ }
+ }
+
+ > .empty {
+ opacity: 0.7;
+ text-align: center;
+ }
+ }
+}
+</style>