diff options
Diffstat (limited to 'src/components/user_card_content')
| -rw-r--r-- | src/components/user_card_content/user_card_content.js | 79 | ||||
| -rw-r--r-- | src/components/user_card_content/user_card_content.vue | 177 |
2 files changed, 180 insertions, 76 deletions
diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index cdb1a850..75185053 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -6,21 +6,37 @@ export default { props: [ 'user', 'switcher', 'selected', 'hideBio', 'activatePanel' ], data () { return { + followRequestInProgress: false, + followRequestSent: false, hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined' ? this.$store.state.instance.hideUserStats - : this.$store.state.config.hideUserStats + : this.$store.state.config.hideUserStats, + betterShadow: this.$store.state.interface.browserSupport.cssFilter } }, computed: { headingStyle () { - const color = this.$store.state.config.colors.bg + const color = this.$store.state.config.customTheme.colors + ? this.$store.state.config.customTheme.colors.bg // v2 + : this.$store.state.config.colors.bg // v1 + if (color) { - const rgb = hex2rgb(color) + const rgb = (typeof color === 'string') ? hex2rgb(color) : color const tintColor = `rgba(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)}, .5)` + + const gradient = [ + [tintColor, this.hideBio ? '60%' : ''], + this.hideBio ? [ + color, '100%' + ] : [ + tintColor, '' + ] + ].map(_ => _.join(' ')).join(', ') + return { backgroundColor: `rgb(${Math.floor(rgb.r * 0.53)}, ${Math.floor(rgb.g * 0.56)}, ${Math.floor(rgb.b * 0.59)})`, backgroundImage: [ - `linear-gradient(to bottom, ${tintColor}, ${tintColor})`, + `linear-gradient(to bottom, ${gradient})`, `url(${this.user.cover_photo})` ].join(', ') } @@ -71,13 +87,68 @@ export default { methods: { followUser () { const store = this.$store + this.followRequestInProgress = true store.state.api.backendInteractor.followUser(this.user.id) .then((followedUser) => store.commit('addNewUsers', [followedUser])) + .then(() => { + // For locked users we just mark it that we sent the follow request + if (this.user.locked) { + this.followRequestInProgress = false + this.followRequestSent = true + return + } + + if (this.user.following) { + // If we get result immediately, just stop. + this.followRequestInProgress = false + return + } + + // But usually we don't get result immediately, so we ask server + // for updated user profile to confirm if we are following them + // Sometimes it takes several tries. Sometimes we end up not following + // user anyway, probably because they locked themselves and we + // don't know that yet. + // Recursive Promise, it will call itself up to 3 times. + const fetchUser = (attempt) => new Promise((resolve, reject) => { + setTimeout(() => { + store.state.api.backendInteractor.fetchUser({ id: this.user.id }) + .then((user) => store.commit('addNewUsers', [user])) + .then(() => resolve([this.user.following, attempt])) + .catch((e) => reject(e)) + }, 500) + }).then(([following, attempt]) => { + if (!following && attempt <= 3) { + // If we BE reports that we still not following that user - retry, + // increment attempts by one + return fetchUser(++attempt) + } else { + // If we run out of attempts, just return whatever status is. + return following + } + }) + + return fetchUser(1) + .then((following) => { + if (following) { + // We confirmed and everything its good. + this.followRequestInProgress = false + } else { + // If after all the tries, just treat it as if user is locked + this.followRequestInProgress = false + this.followRequestSent = true + } + }) + }) }, unfollowUser () { const store = this.$store + this.followRequestInProgress = true store.state.api.backendInteractor.unfollowUser(this.user.id) .then((unfollowedUser) => store.commit('addNewUsers', [unfollowedUser])) + .then(() => { + this.followRequestInProgress = false + }) }, blockUser () { const store = this.$store diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index 6e48f3f9..136bcd6a 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -2,20 +2,20 @@ <div id="heading" class="profile-panel-background" :style="headingStyle"> <div class="panel-heading text-center"> <div class='user-info'> - <router-link @click.native="activatePanel('timeline')" :to="{ name: 'user-settings' }" style="float: right; margin-top:16px;" v-if="!isOtherUser"> + <router-link @click.native="activatePanel && activatePanel('timeline')" :to="{ name: 'user-settings' }" style="float: right; margin-top:16px;" v-if="!isOtherUser"> <i class="icon-cog usersettings" :title="$t('tool_tip.user_settings')"></i> </router-link> <a :href="user.statusnet_profile_url" target="_blank" class="floater" v-if="isOtherUser"> <i class="icon-link-ext usersettings"></i> </a> <div class='container'> - <router-link :to="userProfileLink(user)"> - <StillImage class="avatar" :src="user.profile_image_url_original"/> + <router-link @click.native="activatePanel && activatePanel('timeline')" :to="userProfileLink(user)"> + <StillImage class="avatar" :class='{ "better-shadow": betterShadow }' :src="user.profile_image_url_original"/> </router-link> <div class="name-and-screen-name"> <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 class='user-screen-name' :to="userProfileLink(user)"> + <router-link @click.native="activatePanel && activatePanel('timeline')" class='user-screen-name' :to="userProfileLink(user)"> <span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span> <span v-if="!hideUserStatsLocal" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span> </router-link> @@ -41,74 +41,87 @@ </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"> + <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') }} - </button> - </span> - <span v-if="!user.following"> - <button @click="followUser"> + </template> + </button> + </span> + <span v-if="!user.following"> + <button @click="followUser" :disabled="followRequestInProgress" :title="followRequestSent ? $t('user_card.follow_again') : ''"> + <template v-if="followRequestInProgress"> + {{ $t('user_card.follow_progress') }} + </template> + <template v-else-if="followRequestSent"> + {{ $t('user_card.follow_sent') }} + </template> + <template v-else> {{ $t('user_card.follow') }} - </button> - </span> - </div> - <div class='mute' v-if='isOtherUser'> - <span v-if='user.muted'> - <button @click="toggleMute" class="pressed"> - {{ $t('user_card.muted') }} - </button> - </span> - <span v-if='!user.muted'> - <button @click="toggleMute"> - {{ $t('user_card.mute') }} - </button> - </span> - </div> - <div class="remote-follow" v-if='!loggedIn && user.is_local'> - <form method="POST" :action='subscribeUrl'> - <input type="hidden" name="nickname" :value="user.screen_name"> - <input type="hidden" name="profile" value=""> - <button click="submit" class="remote-button"> - {{ $t('user_card.remote_follow') }} - </button> - </form> - </div> - <div class='block' v-if='isOtherUser && loggedIn'> - <span v-if='user.statusnet_blocking'> - <button @click="unblockUser" class="pressed"> - {{ $t('user_card.blocked') }} - </button> - </span> - <span v-if='!user.statusnet_blocking'> - <button @click="blockUser"> - {{ $t('user_card.block') }} - </button> - </span> - </div> + </template> + </button> + </span> </div> - </div> - </div> - <div class="panel-body profile-panel-body"> - <div v-if="!hideUserStatsLocal || switcher" class="user-counts" :class="{clickable: switcher}"> - <div class="user-count" v-on:click.prevent="setProfileView('statuses')" :class="{selected: selected === 'statuses'}"> - <h5>{{ $t('user_card.statuses') }}</h5> - <span v-if="!hideUserStatsLocal">{{user.statuses_count}} <br></span> + <div class='mute' v-if='isOtherUser'> + <span v-if='user.muted'> + <button @click="toggleMute" class="pressed"> + {{ $t('user_card.muted') }} + </button> + </span> + <span v-if='!user.muted'> + <button @click="toggleMute"> + {{ $t('user_card.mute') }} + </button> + </span> </div> - <div class="user-count" v-on:click.prevent="setProfileView('friends')" :class="{selected: selected === 'friends'}"> - <h5>{{ $t('user_card.followees') }}</h5> - <span v-if="!hideUserStatsLocal">{{user.friends_count}}</span> + <div class="remote-follow" v-if='!loggedIn && user.is_local'> + <form method="POST" :action='subscribeUrl'> + <input type="hidden" name="nickname" :value="user.screen_name"> + <input type="hidden" name="profile" value=""> + <button click="submit" class="remote-button"> + {{ $t('user_card.remote_follow') }} + </button> + </form> </div> - <div class="user-count" v-on:click.prevent="setProfileView('followers')" :class="{selected: selected === 'followers'}"> - <h5>{{ $t('user_card.followers') }}</h5> - <span v-if="!hideUserStatsLocal">{{user.followers_count}}</span> + <div class='block' v-if='isOtherUser && loggedIn'> + <span v-if='user.statusnet_blocking'> + <button @click="unblockUser" class="pressed"> + {{ $t('user_card.blocked') }} + </button> + </span> + <span v-if='!user.statusnet_blocking'> + <button @click="blockUser"> + {{ $t('user_card.block') }} + </button> + </span> </div> </div> - <p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p> - <p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p> </div> </div> + <div class="panel-body profile-panel-body" v-if="!hideBio"> + <div v-if="!hideUserStatsLocal || switcher" class="user-counts" :class="{clickable: switcher}"> + <div class="user-count" v-on:click.prevent="setProfileView('statuses')" :class="{selected: selected === 'statuses'}"> + <h5>{{ $t('user_card.statuses') }}</h5> + <span v-if="!hideUserStatsLocal">{{user.statuses_count}} <br></span> + </div> + <div class="user-count" v-on:click.prevent="setProfileView('friends')" :class="{selected: selected === 'friends'}"> + <h5>{{ $t('user_card.followees') }}</h5> + <span v-if="!hideUserStatsLocal">{{user.friends_count}}</span> + </div> + <div class="user-count" v-on:click.prevent="setProfileView('followers')" :class="{selected: selected === 'followers'}"> + <h5>{{ $t('user_card.followers') }}</h5> + <span v-if="!hideUserStatsLocal">{{user.followers_count}}</span> + </div> + </div> + <p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p> + <p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p> + </div> +</div> </template> <script src="./user_card_content.js"></script> @@ -120,10 +133,15 @@ background-size: cover; border-radius: $fallback--panelRadius; border-radius: var(--panelRadius, $fallback--panelRadius); + overflow: hidden; + + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; .panel-heading { padding: 0.6em 0em; text-align: center; + box-shadow: none; } } @@ -138,15 +156,14 @@ } .user-info { - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); padding: 0 16px; .container { padding: 16px 10px 6px 10px; display: flex; max-height: 56px; - overflow: hidden; .avatar { border-radius: $fallback--avatarRadius; @@ -155,8 +172,14 @@ width: 56px; height: 56px; box-shadow: 0px 1px 8px rgba(0,0,0,0.75); + box-shadow: var(--avatarShadow); object-fit: cover; + &.better-shadow { + box-shadow: var(--avatarShadowInset); + filter: var(--avatarShadowFilter) + } + &.animated::before { display: none; } @@ -173,8 +196,8 @@ } .usersettings { - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); opacity: .8; } @@ -185,6 +208,16 @@ text-overflow: ellipsis; white-space: nowrap; flex: 1 1 0; + // 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 + } } .user-name{ @@ -193,8 +226,8 @@ } .user-screen-name { - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); display: inline-block; font-weight: light; font-size: 15px; @@ -269,8 +302,8 @@ padding: .5em 1.5em 0em 1.5em; text-align: center; justify-content: space-between; - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); &.clickable { .user-count { |
