diff options
Diffstat (limited to 'src/components/user_card')
| -rw-r--r-- | src/components/user_card/user_card.js | 38 | ||||
| -rw-r--r-- | src/components/user_card/user_card.vue | 429 |
2 files changed, 329 insertions, 138 deletions
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 7c6ffa89..82d3b835 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -1,12 +1,13 @@ import UserAvatar from '../user_avatar/user_avatar.vue' import RemoteFollow from '../remote_follow/remote_follow.vue' +import ProgressButton from '../progress_button/progress_button.vue' import ModerationTools from '../moderation_tools/moderation_tools.vue' import { hex2rgb } from '../../services/color_convert/color_convert.js' import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' export default { - props: [ 'user', 'switcher', 'selected', 'hideBio', 'rounded', 'bordered' ], + props: [ 'user', 'switcher', 'selected', 'hideBio', 'rounded', 'bordered', 'allowZoomingAvatar' ], data () { return { followRequestInProgress: false, @@ -23,15 +24,15 @@ export default { computed: { classes () { return [{ - 'user-card-rounded-t': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius - 'user-card-rounded': this.rounded === true, // set border-radius for all sides - 'user-card-bordered': this.bordered === true // set border for all sides + 'user-card-rounded-t': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius + 'user-card-rounded': this.rounded === true, // set border-radius for all sides + 'user-card-bordered': this.bordered === true // set border for all sides }] }, style () { const color = this.$store.state.config.customTheme.colors - ? this.$store.state.config.customTheme.colors.bg // v2 - : this.$store.state.config.colors.bg // v1 + ? this.$store.state.config.customTheme.colors.bg // v2 + : this.$store.state.config.colors.bg // v1 if (color) { const rgb = (typeof color === 'string') ? hex2rgb(color) : color @@ -73,12 +74,12 @@ export default { userHighlightType: { get () { const data = this.$store.state.config.highlight[this.user.screen_name] - return data && data.type || 'disabled' + return (data && data.type) || 'disabled' }, set (type) { const data = this.$store.state.config.highlight[this.user.screen_name] if (type !== 'disabled') { - this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: data && data.color || '#FFFFFF', type }) + this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: (data && data.color) || '#FFFFFF', type }) } else { this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined }) } @@ -104,13 +105,14 @@ export default { components: { UserAvatar, RemoteFollow, - ModerationTools + ModerationTools, + ProgressButton }, methods: { followUser () { const store = this.$store this.followRequestInProgress = true - requestFollow(this.user, store).then(({sent}) => { + requestFollow(this.user, store).then(({ sent }) => { this.followRequestInProgress = false this.followRequestSent = sent }) @@ -135,13 +137,19 @@ export default { unmuteUser () { this.$store.dispatch('unmuteUser', this.user.id) }, + subscribeUser () { + return this.$store.dispatch('subscribeUser', this.user.id) + }, + unsubscribeUser () { + return this.$store.dispatch('unsubscribeUser', this.user.id) + }, setProfileView (v) { if (this.switcher) { const store = this.$store store.commit('setProfileView', { v }) } }, - linkClicked ({target}) { + linkClicked ({ target }) { if (target.tagName === 'SPAN') { target = target.parentNode } @@ -154,6 +162,14 @@ export default { }, reportUser () { this.$store.dispatch('openUserReportingModal', this.user.id) + }, + zoomAvatar () { + const attachment = { + url: this.user.profile_image_url_original, + mimetype: 'image' + } + this.$store.dispatch('setMedia', [attachment]) + this.$store.dispatch('setCurrent', attachment) } } } diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index b4495673..fc18e240 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -1,65 +1,143 @@ <template> -<div class="user-card" :class="classes" :style="style"> - <div class="panel-heading"> - <div class='user-info'> - <div class='container'> - <router-link :to="userProfileLink(user)"> - <UserAvatar :betterShadow="betterShadow" :user="user"/> - </router-link> - <div class="user-summary"> - <div class="top-line"> - <div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div> - <div :title="user.name" class='user-name' v-else>{{user.name}}</div> - <router-link :to="{ name: 'user-settings' }" v-if="!isOtherUser"> - <i class="button-icon icon-wrench usersettings" :title="$t('tool_tip.user_settings')"></i> - </router-link> - <a :href="user.statusnet_profile_url" target="_blank" v-if="isOtherUser && !user.is_local"> - <i class="icon-link-ext usersettings"></i> - </a> + <div + class="user-card" + :class="classes" + :style="style" + > + <div class="panel-heading"> + <div class="user-info"> + <div class="container"> + <a + v-if="allowZoomingAvatar" + class="user-info-avatar-link" + @click="zoomAvatar" + > + <UserAvatar + :better-shadow="betterShadow" + :user="user" + /> + <div class="user-info-avatar-link-overlay"> + <i class="button-icon icon-zoom-in" /> + </div> + </a> + <router-link + v-else + :to="userProfileLink(user)" + > + <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" + /> + <!-- eslint-enable vue/no-v-html --> + <div + v-else + :title="user.name" + class="user-name" + > + {{ user.name }} + </div> + <router-link + v-if="!isOtherUser" + :to="{ name: 'user-settings' }" + > + <i + class="button-icon icon-wrench usersettings" + :title="$t('tool_tip.user_settings')" + /> + </router-link> + <a + v-if="isOtherUser && !user.is_local" + :href="user.statusnet_profile_url" + target="_blank" + > + <i class="icon-link-ext usersettings" /> + </a> + </div> + + <div class="bottom-line"> + <router-link + class="user-screen-name" + :to="userProfileLink(user)" + > + @{{ user.screen_name }} + </router-link> + <span + v-if="!hideBio && !!visibleRole" + class="alert staff" + >{{ visibleRole }}</span> + <span v-if="user.locked"><i class="icon icon-lock" /></span> + <span + v-if="!hideUserStatsLocal && !hideBio" + class="dailyAvg" + >{{ dailyAvg }} {{ $t('user_card.per_day') }}</span> + </div> </div> - - <div class="bottom-line"> - <router-link class="user-screen-name" :to="userProfileLink(user)">@{{user.screen_name}}</router-link> - <span class="alert staff" v-if="!hideBio && !!visibleRole">{{visibleRole}}</span> - <span v-if="user.locked"><i class="icon icon-lock"></i></span> - <span v-if="!hideUserStatsLocal && !hideBio" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> - </div> - </div> - </div> - <div class="user-meta"> - <div v-if="user.follows_you && loggedIn && isOtherUser" class="following"> - {{ $t('user_card.follows_you') }} </div> - <div class="highlighter" v-if="isOtherUser && (loggedIn || !switcher)"> - <!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to --> - <input class="userHighlightText" type="text" :id="'userHighlightColorTx'+user.id" v-if="userHighlightType !== 'disabled'" v-model="userHighlightColor"/> - <input class="userHighlightCl" type="color" :id="'userHighlightColor'+user.id" v-if="userHighlightType !== 'disabled'" v-model="userHighlightColor"/> - <label for="style-switcher" class='userHighlightSel select'> - <select class="userHighlightSel" :id="'userHighlightSel'+user.id" v-model="userHighlightType"> - <option value="disabled">No highlight</option> - <option value="solid">Solid bg</option> - <option value="striped">Striped bg</option> - <option value="side">Side stripe</option> - </select> - <i class="icon-down-open"/> - </label> + <div class="user-meta"> + <div + v-if="user.follows_you && loggedIn && isOtherUser" + 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" + > + <label + for="style-switcher" + class="userHighlightSel select" + > + <select + :id="'userHighlightSel'+user.id" + v-model="userHighlightType" + class="userHighlightSel" + > + <option value="disabled">No highlight</option> + <option value="solid">Solid bg</option> + <option value="striped">Striped bg</option> + <option value="side">Side stripe</option> + </select> + <i class="icon-down-open" /> + </label> + </div> </div> - </div> - <div v-if="isOtherUser" class="user-interactions"> - <div class="follow" v-if="loggedIn"> - <span v-if="user.following"> - <!--Following them!--> - <button @click="unfollowUser" class="pressed" :disabled="followRequestInProgress" :title="$t('user_card.follow_unfollow')"> - <template v-if="followRequestInProgress"> - {{ $t('user_card.follow_progress') }} - </template> - <template v-else> - {{ $t('user_card.following') }} - </template> - </button> - </span> - <span v-if="!user.following"> - <button @click="followUser" :disabled="followRequestInProgress" :title="followRequestSent ? $t('user_card.follow_again') : ''"> + <div + v-if="loggedIn && isOtherUser" + class="user-interactions" + > + <div v-if="!user.following"> + <button + class="btn btn-default btn-block" + :disabled="followRequestInProgress" + :title="followRequestSent ? $t('user_card.follow_again') : ''" + @click="followUser" + > <template v-if="followRequestInProgress"> {{ $t('user_card.follow_progress') }} </template> @@ -70,65 +148,148 @@ {{ $t('user_card.follow') }} </template> </button> - </span> - </div> - <div class='mute' v-if='isOtherUser && loggedIn'> - <span v-if='user.muted'> - <button @click="unmuteUser" class="pressed"> + </div> + <div v-else-if="followRequestInProgress"> + <button + class="btn btn-default btn-block pressed" + disabled + :title="$t('user_card.follow_unfollow')" + @click="unfollowUser" + > + {{ $t('user_card.follow_progress') }} + </button> + </div> + <div + v-else + class="btn-group" + > + <button + class="btn btn-default pressed" + :title="$t('user_card.follow_unfollow')" + @click="unfollowUser" + > + {{ $t('user_card.following') }} + </button> + <ProgressButton + v-if="!user.subscribed" + class="btn btn-default" + :click="subscribeUser" + :title="$t('user_card.subscribe')" + > + <i class="icon-bell-alt" /> + </ProgressButton> + <ProgressButton + v-else + class="btn btn-default pressed" + :click="unsubscribeUser" + :title="$t('user_card.unsubscribe')" + > + <i class="icon-bell-ringing-o" /> + </ProgressButton> + </div> + + <div> + <button + v-if="user.muted" + class="btn btn-default btn-block pressed" + @click="unmuteUser" + > {{ $t('user_card.muted') }} </button> - </span> - <span v-if='!user.muted'> - <button @click="muteUser"> + <button + v-else + class="btn btn-default btn-block" + @click="muteUser" + > {{ $t('user_card.mute') }} </button> - </span> - </div> - <div v-if='!loggedIn && user.is_local'> - <RemoteFollow :user="user" /> - </div> - <div class='block' v-if='isOtherUser && loggedIn'> - <span v-if='user.statusnet_blocking'> - <button @click="unblockUser" class="pressed"> + </div> + + <div> + <button + v-if="user.statusnet_blocking" + class="btn btn-default btn-block pressed" + @click="unblockUser" + > {{ $t('user_card.blocked') }} </button> - </span> - <span v-if='!user.statusnet_blocking'> - <button @click="blockUser"> + <button + v-else + class="btn btn-default btn-block" + @click="blockUser" + > {{ $t('user_card.block') }} </button> - </span> - </div> - <div class='block' v-if='isOtherUser && loggedIn'> - <span> - <button @click="reportUser"> + </div> + + <div> + <button + class="btn btn-default btn-block" + @click="reportUser" + > {{ $t('user_card.report') }} </button> - </span> + </div> + + <ModerationTools + v-if="loggedIn.role === "admin"" + :user="user" + /> + </div> + <div + v-if="!loggedIn && user.is_local" + class="user-interactions" + > + <RemoteFollow :user="user" /> </div> - <ModerationTools :user='user' v-if='loggedIn.role === "admin"'/> </div> </div> - </div> - <div class="panel-body" v-if="!hideBio"> - <div v-if="!hideUserStatsLocal && switcher" class="user-counts"> - <div class="user-count" v-on:click.prevent="setProfileView('statuses')"> - <h5>{{ $t('user_card.statuses') }}</h5> - <span>{{user.statuses_count}} <br></span> - </div> - <div class="user-count" v-on:click.prevent="setProfileView('friends')"> - <h5>{{ $t('user_card.followees') }}</h5> - <span>{{user.friends_count}}</span> - </div> - <div class="user-count" v-on:click.prevent="setProfileView('followers')"> - <h5>{{ $t('user_card.followers') }}</h5> - <span>{{user.followers_count}}</span> + <div + v-if="!hideBio" + class="panel-body" + > + <div + v-if="!hideUserStatsLocal && switcher" + 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> + <span>{{ user.friends_count }}</span> + </div> + <div + class="user-count" + @click.prevent="setProfileView('followers')" + > + <h5>{{ $t('user_card.followers') }}</h5> + <span>{{ user.followers_count }}</span> + </div> </div> + <!-- 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" + /> + <!-- eslint-enable vue/no-v-html --> + <p + v-else-if="!hideBio" + class="user-card-bio" + > + {{ user.description }} + </p> </div> - <p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="user-card-bio" v-html="user.description_html"></p> - <p v-else-if="!hideBio" class="user-card-bio">{{ user.description }}</p> </div> -</div> </template> <script src="./user_card.js"></script> @@ -138,7 +299,6 @@ .user-card { background-size: cover; - overflow: hidden; .panel-heading { padding: .5em 0; @@ -153,6 +313,8 @@ word-wrap: break-word; background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%); background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%); + border-bottom-right-radius: inherit; + border-bottom-left-radius: inherit; } p { @@ -205,6 +367,7 @@ .container { padding: 16px 0 6px; display: flex; + align-items: flex-start; max-height: 56px; .avatar { @@ -226,6 +389,35 @@ } } + &-avatar-link { + position: relative; + cursor: pointer; + + &-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; + + i { + color: #FFF; + } + } + + &:hover &-overlay { + opacity: 1; + } + } + .usersettings { color: $fallback--lightText; color: var(--lightText, $fallback--lightText); @@ -358,43 +550,26 @@ } } .user-interactions { + position: relative; display: flex; flex-flow: row wrap; justify-content: space-between; - margin-right: -.75em; - div { + > * { flex: 1 0 0; - margin-right: .75em; - margin-bottom: .6em; + margin: 0 .75em .6em 0; white-space: nowrap; } - .mute { - max-width: 220px; - min-height: 28px; - } - - .follow { - max-width: 220px; - min-height: 28px; - } - button { - width: 100%; - height: 100%; margin: 0; - } - .remote-button { - height: 28px !important; - width: 92%; - } - - .pressed { - border-bottom-color: rgba(255, 255, 255, 0.2); - border-top-color: rgba(0, 0, 0, 0.2); + &.pressed { + // TODO: This should be themed. + border-bottom-color: rgba(255, 255, 255, 0.2); + border-top-color: rgba(0, 0, 0, 0.2); + } } } } |
