diff options
Diffstat (limited to 'src/client/components/user-preview.vue')
| -rw-r--r-- | src/client/components/user-preview.vue | 207 |
1 files changed, 109 insertions, 98 deletions
diff --git a/src/client/components/user-preview.vue b/src/client/components/user-preview.vue index 410de6b488..d1a11dc790 100644 --- a/src/client/components/user-preview.vue +++ b/src/client/components/user-preview.vue @@ -1,44 +1,55 @@ <template> -<transition name="popup" appear @after-leave="() => { $emit('closed'); destroyDom(); }"> - <div v-if="show" class="fxxzrfni _panel _shadow" ref="content" :style="{ top: top + 'px', left: left + 'px' }" @mouseover="() => { $emit('mouseover'); }" @mouseleave="() => { $emit('mouseleave'); }"> - <div class="banner" :style="u.bannerUrl ? `background-image: url(${u.bannerUrl})` : ''"></div> - <mk-avatar class="avatar" :user="u" :disable-preview="true"/> - <div class="title"> - <router-link class="name" :to="u | userPage"><mk-user-name :user="u" :nowrap="false"/></router-link> - <p class="username"><mk-acct :user="u"/></p> - </div> - <div class="description"> - <mfm v-if="u.description" :text="u.description" :author="u" :i="$store.state.i" :custom-emojis="u.emojis"/> - </div> - <div class="status"> - <div> - <p>{{ $t('notes') }}</p><span>{{ u.notesCount }}</span> +<transition name="popup" appear @after-leave="$emit('closed')"> + <div v-if="showing" class="fxxzrfni _popup _shadow" :style="{ top: top + 'px', left: left + 'px' }" @mouseover="() => { $emit('mouseover'); }" @mouseleave="() => { $emit('mouseleave'); }"> + <div v-if="fetched" class="info"> + <div class="banner" :style="user.bannerUrl ? `background-image: url(${user.bannerUrl})` : ''"></div> + <MkAvatar class="avatar" :user="user" :disable-preview="true"/> + <div class="title"> + <router-link class="name" :to="userPage(user)"><MkUserName :user="user" :nowrap="false"/></router-link> + <p class="username"><MkAcct :user="user"/></p> </div> - <div> - <p>{{ $t('following') }}</p><span>{{ u.followingCount }}</span> + <div class="description"> + <Mfm v-if="user.description" :text="user.description" :author="user" :i="$store.state.i" :custom-emojis="user.emojis"/> </div> - <div> - <p>{{ $t('followers') }}</p><span>{{ u.followersCount }}</span> + <div class="status"> + <div> + <p>{{ $t('notes') }}</p><span>{{ user.notesCount }}</span> + </div> + <div> + <p>{{ $t('following') }}</p><span>{{ user.followingCount }}</span> + </div> + <div> + <p>{{ $t('followers') }}</p><span>{{ user.followersCount }}</span> + </div> </div> + <MkFollowButton class="koudoku-button" v-if="$store.getters.isSignedIn && user.id != $store.state.i.id" :user="user" mini/> + </div> + <div v-else> + <MkLoading/> </div> - <mk-follow-button class="koudoku-button" v-if="$store.getters.isSignedIn && u.id != $store.state.i.id" :user="u" mini/> </div> </transition> </template> <script lang="ts"> -import Vue from 'vue'; +import { defineComponent } from 'vue'; import parseAcct from '../../misc/acct/parse'; import MkFollowButton from './follow-button.vue'; +import { userPage } from '../filters/user'; +import * as os from '@/os'; -export default Vue.extend({ +export default defineComponent({ components: { MkFollowButton }, props: { - user: { - type: [Object, String], + showing: { + type: Boolean, + required: true + }, + q: { + type: String, required: true }, source: { @@ -46,29 +57,30 @@ export default Vue.extend({ } }, + emits: ['closed', 'mouseover', 'mouseleave'], + data() { return { - u: null, - show: false, - closed: false, + user: null, + fetched: false, top: 0, left: 0, }; }, mounted() { - if (typeof this.user == 'object') { - this.u = this.user; - this.show = true; + if (typeof this.q == 'object') { + this.user = this.q; + this.fetched = true; } else { - const query = this.user.startsWith('@') ? - parseAcct(this.user.substr(1)) : - { userId: this.user }; + const query = this.q.startsWith('@') ? + parseAcct(this.q.substr(1)) : + { userId: this.q }; - this.$root.api('users/show', query).then(user => { - if (this.closed) return; - this.u = user; - this.show = true; + os.api('users/show', query).then(user => { + if (!this.showing) return; + this.user = user; + this.fetched = true; }); } @@ -81,11 +93,7 @@ export default Vue.extend({ }, methods: { - close() { - this.closed = true; - this.show = false; - if (this.$refs.content) (this.$refs.content as any).style.pointerEvents = 'none'; - } + userPage } }); </script> @@ -94,7 +102,7 @@ export default Vue.extend({ .popup-enter-active, .popup-leave-active { transition: opacity 0.3s, transform 0.3s !important; } -.popup-enter, .popup-leave-to { +.popup-enter-from, .popup-leave-to { opacity: 0; transform: scale(0.9); } @@ -104,78 +112,81 @@ export default Vue.extend({ z-index: 11000; width: 300px; overflow: hidden; + transform-origin: center top; - > .banner { - height: 84px; - background-color: rgba(0, 0, 0, 0.1); - background-size: cover; - background-position: center; - } + > .info { + > .banner { + height: 84px; + background-color: rgba(0, 0, 0, 0.1); + background-size: cover; + background-position: center; + } - > .avatar { - display: block; - position: absolute; - top: 62px; - left: 13px; - z-index: 2; - width: 58px; - height: 58px; - border: solid 3px var(--face); - border-radius: 8px; - } + > .avatar { + display: block; + position: absolute; + top: 62px; + left: 13px; + z-index: 2; + width: 58px; + height: 58px; + border: solid 3px var(--face); + border-radius: 8px; + } + + > .title { + display: block; + padding: 8px 0 8px 82px; - > .title { - display: block; - padding: 8px 0 8px 82px; + > .name { + display: inline-block; + margin: 0; + font-weight: bold; + line-height: 16px; + word-break: break-all; + } - > .name { - display: inline-block; - margin: 0; - font-weight: bold; - line-height: 16px; - word-break: break-all; + > .username { + display: block; + margin: 0; + line-height: 16px; + font-size: 0.8em; + color: var(--text); + opacity: 0.7; + } } - > .username { - display: block; - margin: 0; - line-height: 16px; + > .description { + padding: 0 16px; font-size: 0.8em; color: var(--text); - opacity: 0.7; } - } - > .description { - padding: 0 16px; - font-size: 0.8em; - color: var(--text); - } + > .status { + padding: 8px 16px; - > .status { - padding: 8px 16px; + > div { + display: inline-block; + width: 33%; - > div { - display: inline-block; - width: 33%; + > p { + margin: 0; + font-size: 0.7em; + color: var(--text); + } - > p { - margin: 0; - font-size: 0.7em; - color: var(--text); - } - - > span { - font-size: 1em; - color: var(--accent); + > span { + font-size: 1em; + color: var(--accent); + } } } - } - > .koudoku-button { - position: absolute; - top: 8px; - right: 8px; + > .koudoku-button { + position: absolute; + top: 8px; + right: 8px; + } } } </style> |