pleroma-fe/src/components/user_card/user_card.vue

619 lines
15 KiB
Vue
Raw Normal View History

2016-11-30 22:27:19 +01:00
<template>
2019-07-11 02:59:10 +02:00
<div
class="user-card"
:class="classes"
>
2019-09-25 19:23:55 +02:00
<div
:class="{ 'hide-bio': hideBio }"
:style="style"
class="background-image"
/>
2019-07-11 02:59:10 +02:00
<div class="panel-heading">
<div class="user-info">
<div class="container">
2019-07-22 22:58:20 +02:00
<a
v-if="allowZoomingAvatar"
2019-07-22 22:58:20 +02:00
class="user-info-avatar-link"
@click="zoomAvatar"
2019-07-22 22:58:20 +02:00
>
<UserAvatar
:better-shadow="betterShadow"
:user="user"
/>
2019-07-25 21:49:02 +02:00
<div class="user-info-avatar-link-overlay">
2020-10-20 23:31:16 +02:00
<FAIcon
class="fa-scale-110 fa-old-padding"
2020-10-20 23:31:16 +02:00
icon="search-plus"
/>
2019-07-25 21:49:02 +02:00
</div>
2019-07-22 22:58:20 +02:00
</a>
<router-link
v-else
:to="userProfileLink(user)"
>
2019-07-11 02:59:10 +02:00
<UserAvatar
:better-shadow="betterShadow"
:user="user"
/>
</router-link>
<div class="user-summary">
<div class="top-line">
<!-- eslint-disable vue/no-v-html -->
<div
v-if="user.name_html"
:title="user.name"
class="user-name"
v-html="user.name_html"
/>
2019-07-12 21:11:54 +02:00
<!-- eslint-enable vue/no-v-html -->
2019-07-11 02:59:10 +02:00
<div
v-else
:title="user.name"
class="user-name"
>
{{ user.name }}
</div>
2021-06-17 21:29:58 +02:00
<button
v-if="!isOtherUser && user.is_local"
class="button-unstyled edit-profile-button"
@click.stop="openProfileTab"
>
<FAIcon
fixed-width
class="icon"
icon="edit"
:title="$t('user_card.edit_profile')"
/>
</button>
2021-04-07 21:42:34 +02:00
<button
2019-07-11 02:59:10 +02:00
v-if="isOtherUser && !user.is_local"
:href="user.statusnet_profile_url"
target="_blank"
2021-04-07 21:42:34 +02:00
class="button-unstyled external-link-button"
2019-07-11 02:59:10 +02:00
>
2020-10-20 23:31:16 +02:00
<FAIcon
class="icon"
icon="external-link-alt"
/>
2021-04-07 21:42:34 +02:00
</button>
2019-10-11 15:52:26 +02:00
<AccountActions
v-if="isOtherUser && loggedIn"
:user="user"
2020-04-21 22:27:51 +02:00
:relationship="relationship"
2019-10-11 15:52:26 +02:00
/>
2019-07-11 02:59:10 +02:00
</div>
<div class="bottom-line">
<router-link
class="user-screen-name"
:title="user.screen_name_ui"
2019-07-11 02:59:10 +02:00
:to="userProfileLink(user)"
>
@{{ user.screen_name_ui }}
2019-07-11 02:59:10 +02:00
</router-link>
<template v-if="!hideBio">
<span
v-if="!!visibleRole"
class="alert user-role"
>
{{ $t(`general.role.${visibleRole}`) }}
</span>
<span
v-if="user.bot"
class="alert user-role"
>
2021-02-12 10:01:16 +01:00
{{ $t('user_card.bot') }}
</span>
</template>
<span v-if="user.locked">
2020-10-20 23:31:16 +02:00
<FAIcon
class="lock-icon"
icon="lock"
size="sm"
/>
</span>
2019-07-11 02:59:10 +02:00
<span
v-if="!mergedConfig.hideUserStats && !hideBio"
2019-07-11 02:59:10 +02:00
class="dailyAvg"
>{{ dailyAvg }} {{ $t('user_card.per_day') }}</span>
</div>
2019-05-16 04:01:04 +02:00
</div>
2018-06-19 16:14:33 +02:00
</div>
2019-07-11 02:59:10 +02:00
<div class="user-meta">
<div
2020-04-21 22:27:51 +02:00
v-if="relationship.followed_by && loggedIn && isOtherUser"
2019-07-11 02:59:10 +02:00
class="following"
>
{{ $t('user_card.follows_you') }}
</div>
<div
v-if="isOtherUser && (loggedIn || !switcher)"
class="highlighter"
>
<!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to -->
<input
v-if="userHighlightType !== 'disabled'"
:id="'userHighlightColorTx'+user.id"
v-model="userHighlightColor"
class="userHighlightText"
type="text"
>
<input
v-if="userHighlightType !== 'disabled'"
:id="'userHighlightColor'+user.id"
v-model="userHighlightColor"
class="userHighlightCl"
type="color"
>
<Select
:id="'userHighlightSel'+user.id"
v-model="userHighlightType"
class="userHighlightSel"
2019-07-11 02:59:10 +02:00
>
2021-05-31 13:02:36 +02:00
<option value="disabled">
{{ $t('user_card.highlight.disabled') }}
</option>
<option value="solid">
{{ $t('user_card.highlight.solid') }}
</option>
<option value="striped">
{{ $t('user_card.highlight.striped') }}
</option>
<option value="side">
{{ $t('user_card.highlight.side') }}
</option>
</Select>
2019-07-11 02:59:10 +02:00
</div>
2018-06-18 10:36:58 +02:00
</div>
2019-07-11 02:59:10 +02:00
<div
v-if="loggedIn && isOtherUser"
class="user-interactions"
>
2019-10-08 09:21:48 +02:00
<div class="btn-group">
2020-04-21 22:27:51 +02:00
<FollowButton :relationship="relationship" />
<template v-if="relationship.following">
2019-10-08 09:21:48 +02:00
<ProgressButton
2020-04-21 22:27:51 +02:00
v-if="!relationship.subscribing"
class="btn button-default"
2019-10-08 09:21:48 +02:00
:click="subscribeUser"
:title="$t('user_card.subscribe')"
>
<FAIcon icon="bell" />
2019-10-08 09:21:48 +02:00
</ProgressButton>
<ProgressButton
v-else
class="btn button-default toggled"
2019-10-08 09:21:48 +02:00
:click="unsubscribeUser"
:title="$t('user_card.unsubscribe')"
>
<FALayers>
2020-10-20 23:31:16 +02:00
<FAIcon
icon="rss"
transform="left-5 shrink-6 up-3 rotate-20"
flip="horizontal"
/>
<FAIcon
icon="rss"
transform="right-5 shrink-6 up-3 rotate-20"
/>
<FAIcon icon="bell" />
</FALayers>
2019-10-08 09:21:48 +02:00
</ProgressButton>
</template>
2019-09-17 21:59:17 +02:00
</div>
2019-07-11 02:59:10 +02:00
<div>
<button
2020-04-21 22:27:51 +02:00
v-if="relationship.muting"
class="btn button-default btn-block toggled"
2019-07-11 02:59:10 +02:00
@click="unmuteUser"
>
{{ $t('user_card.muted') }}
</button>
<button
v-else
class="btn button-default btn-block"
2019-07-11 02:59:10 +02:00
@click="muteUser"
>
{{ $t('user_card.mute') }}
</button>
</div>
<div>
<button
class="btn button-default btn-block"
@click="mentionUser"
>
{{ $t('user_card.mention') }}
</button>
</div>
2019-07-11 02:59:10 +02:00
<ModerationTools
v-if="loggedIn.role === &quot;admin&quot;"
:user="user"
/>
</div>
<div
v-if="!loggedIn && user.is_local"
class="user-interactions"
>
<RemoteFollow :user="user" />
</div>
2019-04-16 16:13:26 +02:00
</div>
</div>
2019-07-11 02:59:10 +02:00
<div
v-if="!hideBio"
class="panel-body"
>
<div
v-if="!mergedConfig.hideUserStats && switcher"
2019-07-11 02:59:10 +02:00
class="user-counts"
>
<div
class="user-count"
@click.prevent="setProfileView('statuses')"
>
<h5>{{ $t('user_card.statuses') }}</h5>
<span>{{ user.statuses_count }} <br></span>
</div>
<div
class="user-count"
@click.prevent="setProfileView('friends')"
>
<h5>{{ $t('user_card.followees') }}</h5>
2019-11-12 19:31:30 +01:00
<span>{{ hideFollowsCount ? $t('user_card.hidden') : user.friends_count }}</span>
2019-07-11 02:59:10 +02:00
</div>
<div
class="user-count"
@click.prevent="setProfileView('followers')"
>
<h5>{{ $t('user_card.followers') }}</h5>
2019-11-12 19:31:30 +01:00
<span>{{ hideFollowersCount ? $t('user_card.hidden') : user.followers_count }}</span>
2019-07-11 02:59:10 +02:00
</div>
2018-11-25 15:24:58 +01:00
</div>
2019-07-11 02:59:10 +02:00
<!-- eslint-disable vue/no-v-html -->
<p
v-if="!hideBio && user.description_html"
class="user-card-bio"
@click.prevent="linkClicked"
v-html="user.description_html"
/>
2019-07-12 21:11:54 +02:00
<!-- eslint-enable vue/no-v-html -->
2019-07-11 02:59:10 +02:00
<p
v-else-if="!hideBio"
class="user-card-bio"
>
{{ user.description }}
</p>
2018-11-25 15:24:58 +01:00
</div>
</div>
2016-11-30 22:27:19 +01:00
</template>
2019-03-05 20:01:49 +01:00
<script src="./user_card.js"></script>
<style lang="scss">
2017-08-21 19:25:01 +02:00
@import '../../_variables.scss';
2019-03-05 20:01:49 +01:00
.user-card {
position: relative;
2020-10-29 20:39:36 +01:00
&:hover .Avatar {
--_still-image-img-visibility: visible;
--_still-image-canvas-visibility: hidden;
}
2018-04-07 18:30:27 +02:00
.panel-heading {
2019-01-09 14:31:53 +01:00
padding: .5em 0;
2018-04-07 18:30:27 +02:00
text-align: center;
box-shadow: none;
2019-03-05 08:32:23 +01:00
background: transparent;
flex-direction: column;
align-items: stretch;
// create new stacking context
position: relative;
2018-04-07 18:30:27 +02:00
}
2019-03-05 08:32:23 +01:00
.panel-body {
word-wrap: break-word;
border-bottom-right-radius: inherit;
border-bottom-left-radius: inherit;
// create new stacking context
position: relative;
}
.background-image {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
mask: linear-gradient(to top, white, transparent) bottom no-repeat,
linear-gradient(to top, white, white);
// Autoprefixed seem to ignore this one, and also syntax is different
-webkit-mask-composite: xor;
mask-composite: exclude;
background-size: cover;
mask-size: 100% 60%;
border-top-left-radius: calc(var(--panelRadius) - 1px);
border-top-right-radius: calc(var(--panelRadius) - 1px);
background-color: var(--profileBg);
&.hide-bio {
mask-size: 100% 40px;
}
2019-03-05 08:32:23 +01:00
}
2018-08-21 20:16:03 +02:00
2019-03-05 08:32:23 +01:00
p {
margin-bottom: 0;
}
&-bio {
2018-08-21 20:16:03 +02:00
text-align: center;
a {
color: $fallback--link;
color: var(--postLink, $fallback--link);
}
img {
object-fit: contain;
vertical-align: middle;
max-width: 100%;
max-height: 400px;
&.emoji {
width: 32px;
height: 32px;
}
}
2018-08-21 20:16:03 +02:00
}
2019-03-05 08:32:23 +01:00
// Modifiers
2019-03-06 03:52:04 +01:00
&-rounded-t {
2019-03-05 19:25:31 +01:00
border-top-left-radius: $fallback--panelRadius;
border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
border-top-right-radius: $fallback--panelRadius;
border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
2019-03-05 08:32:23 +01:00
}
2019-03-06 03:52:04 +01:00
&-rounded {
2019-03-05 08:32:23 +01:00
border-radius: $fallback--panelRadius;
border-radius: var(--panelRadius, $fallback--panelRadius);
}
2019-03-06 03:52:04 +01:00
&-bordered {
2019-03-05 08:32:23 +01:00
border-width: 1px;
border-style: solid;
border-color: $fallback--border;
border-color: var(--border, $fallback--border);
}
}
.user-info {
2018-10-07 18:59:22 +02:00
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
2018-12-26 10:19:25 +01:00
padding: 0 26px;
2018-04-07 18:30:27 +02:00
.container {
2018-12-26 10:19:25 +01:00
padding: 16px 0 6px;
2018-04-07 18:30:27 +02:00
display: flex;
2019-07-25 21:49:02 +02:00
align-items: flex-start;
2018-04-07 18:30:27 +02:00
max-height: 56px;
2018-04-07 15:48:49 +02:00
.Avatar {
--_avatarShadowBox: var(--avatarShadow);
--_avatarShadowFilter: var(--avatarShadowFilter);
--_avatarShadowInset: var(--avatarShadowInset);
flex: 1 0 100%;
width: 56px;
height: 56px;
object-fit: cover;
2018-04-07 15:48:49 +02:00
}
2018-04-07 18:30:27 +02:00
}
2018-04-07 15:48:49 +02:00
2019-07-22 22:58:20 +02:00
&-avatar-link {
2019-07-25 21:49:02 +02:00
position: relative;
2019-07-22 22:58:20 +02:00
cursor: pointer;
2019-07-25 21:49:02 +02:00
&-overlay {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, 0.3);
display: flex;
justify-content: center;
align-items: center;
border-radius: $fallback--avatarRadius;
border-radius: var(--avatarRadius, $fallback--avatarRadius);
opacity: 0;
transition: opacity .2s ease;
svg {
2019-07-25 21:49:02 +02:00
color: #FFF;
}
}
&:hover &-overlay {
opacity: 1;
}
2019-07-22 22:58:20 +02:00
}
2021-06-17 21:29:58 +02:00
.external-link-button, .edit-profile-button {
cursor: pointer;
width: 2.5em;
text-align: center;
margin: -0.5em 0;
padding: 0.5em 0;
&:not(:hover) .icon {
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
}
}
2019-05-16 04:01:04 +02:00
.user-summary {
2018-04-07 18:30:27 +02:00
display: block;
margin-left: 0.6em;
text-align: left;
text-overflow: ellipsis;
white-space: nowrap;
flex: 1 1 0;
2018-11-25 15:42:41 +01:00
// This is so that text doesn't get overlapped by avatar's shadow if it has
// big one
z-index: 1;
img {
width: 26px;
height: 26px;
vertical-align: middle;
object-fit: contain
}
2019-05-16 04:01:04 +02:00
2018-12-26 10:19:25 +01:00
.top-line {
display: flex;
}
2018-04-07 18:30:27 +02:00
}
.user-name {
text-overflow: ellipsis;
overflow: hidden;
flex: 1 1 auto;
margin-right: 1em;
font-size: 15px;
2019-02-26 13:13:09 +01:00
img {
object-fit: contain;
height: 16px;
width: 16px;
vertical-align: middle;
}
2018-04-07 18:30:27 +02:00
}
2019-05-16 04:01:04 +02:00
.bottom-line {
display: flex;
font-weight: light;
2018-04-07 18:30:27 +02:00
font-size: 15px;
2018-12-26 10:19:25 +01:00
.lock-icon {
margin-left: 0.5em;
}
2019-05-19 20:25:02 +02:00
.user-screen-name {
2019-05-16 04:01:31 +02:00
min-width: 1px;
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
}
2019-05-16 04:01:31 +02:00
.dailyAvg {
min-width: 1px;
flex: 0 0 auto;
margin-left: 1em;
font-size: 0.7em;
color: $fallback--text;
color: var(--text, $fallback--text);
}
2019-05-16 04:01:04 +02:00
.user-role {
2019-05-19 20:25:02 +02:00
flex: none;
2019-05-16 04:01:31 +02:00
color: $fallback--text;
2020-01-28 01:03:21 +01:00
color: var(--alertNeutralText, $fallback--text);
2019-05-16 04:01:31 +02:00
background-color: $fallback--fg;
2020-01-28 01:03:21 +01:00
background-color: var(--alertNeutral, $fallback--fg);
2019-05-16 04:01:31 +02:00
}
2018-04-07 18:30:27 +02:00
}
2018-06-19 16:14:33 +02:00
.user-meta {
2018-12-26 10:19:25 +01:00
margin-bottom: .15em;
display: flex;
align-items: baseline;
font-size: 14px;
line-height: 22px;
flex-wrap: wrap;
2018-06-19 16:14:33 +02:00
.following {
2018-12-26 10:19:25 +01:00
flex: 1 0 auto;
2018-06-19 16:14:33 +02:00
margin: 0;
2018-12-26 10:19:25 +01:00
margin-bottom: .25em;
2018-06-19 16:14:33 +02:00
text-align: left;
}
2018-12-26 10:19:25 +01:00
.highlighter {
flex: 0 1 auto;
display: flex;
flex-wrap: wrap;
margin-right: -.5em;
align-self: start;
.userHighlightCl {
padding: 2px 10px;
flex: 1 0 auto;
}
2021-03-11 15:31:15 +01:00
.userHighlightSel {
2018-12-26 10:19:25 +01:00
padding-top: 0;
padding-bottom: 0;
flex: 1 0 auto;
}
.userHighlightText {
width: 70px;
flex: 1 0 auto;
}
.userHighlightCl,
.userHighlightText,
2021-03-11 15:31:15 +01:00
.userHighlightSel {
2018-12-26 10:19:25 +01:00
vertical-align: top;
margin-right: .5em;
margin-bottom: .25em;
}
2018-06-19 16:14:33 +02:00
}
}
2018-04-07 18:30:27 +02:00
.user-interactions {
2019-07-11 17:01:12 +02:00
position: relative;
2018-04-07 18:30:27 +02:00
display: flex;
flex-flow: row wrap;
2018-12-26 10:19:25 +01:00
margin-right: -.75em;
2019-04-26 06:39:43 +02:00
> * {
margin: 0 .75em .6em 0;
2018-12-26 10:19:25 +01:00
white-space: nowrap;
2019-10-09 08:04:18 +02:00
min-width: 95px;
2018-04-07 18:30:27 +02:00
}
2019-04-26 09:33:25 +02:00
button {
2019-04-26 06:39:43 +02:00
margin: 0;
}
2018-04-07 18:30:27 +02:00
}
}
.user-counts {
2018-04-07 18:30:27 +02:00
display: flex;
line-height:16px;
padding: .5em 1.5em 0em 1.5em;
2018-04-07 18:30:27 +02:00
text-align: center;
justify-content: space-between;
2018-10-07 18:59:22 +02:00
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
2018-12-26 10:19:25 +01:00
flex-wrap: wrap;
}
.user-count {
2018-12-26 10:19:25 +01:00
flex: 1 0 auto;
padding: .5em 0 .5em 0;
margin: 0 .5em;
2018-04-07 18:30:27 +02:00
h5 {
font-size:1em;
font-weight: bolder;
margin: 0 0 0.25em;
}
a {
text-decoration: none;
}
}
</style>