From e0a66b989d8f30f6475bc04064c8c36f9f876539 Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Tue, 5 Mar 2019 02:32:23 -0500
Subject: Re-do UserCardContent css

---
 src/components/notification/notification.vue | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

(limited to 'src/components/notification/notification.vue')

diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 87925cfc..6583570e 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -5,9 +5,7 @@
       <UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.action.user.profile_image_url_original"/>
     </a>
     <div class='notification-right'>
-      <div class="usercard notification-usercard" v-if="userExpanded">
-        <user-card-content :user="notification.action.user" :switcher="false"></user-card-content>
-      </div>
+      <UserCardContent :user="notification.action.user" :rounded="true" :bordered="true" v-if="userExpanded"/>
       <span class="notification-details">
         <div class="name-and-action">
           <span class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span>
-- 
cgit v1.2.3-70-g09d2


From 7bceabb5bda1f7d0737f8f51e0aa07879b7ce72e Mon Sep 17 00:00:00 2001
From: taehoon <th.dev91@gmail.com>
Date: Tue, 5 Mar 2019 14:01:49 -0500
Subject: Rename UserCardContent to UserCard

---
 src/components/basic_user_card/basic_user_card.js  |   4 +-
 src/components/basic_user_card/basic_user_card.vue |   2 +-
 src/components/notification/notification.js        |   4 +-
 src/components/notification/notification.vue       |   2 +-
 src/components/side_drawer/side_drawer.js          |   4 +-
 src/components/side_drawer/side_drawer.vue         |   2 +-
 src/components/status/status.js                    |   4 +-
 src/components/status/status.vue                   |   2 +-
 src/components/user_card/user_card.js              | 148 ++++++++
 src/components/user_card/user_card.vue             | 420 +++++++++++++++++++++
 .../user_card_content/user_card_content.js         | 148 --------
 .../user_card_content/user_card_content.vue        | 420 ---------------------
 src/components/user_panel/user_panel.js            |   4 +-
 src/components/user_panel/user_panel.vue           |   2 +-
 src/components/user_profile/user_profile.js        |   4 +-
 src/components/user_profile/user_profile.vue       |   2 +-
 16 files changed, 586 insertions(+), 586 deletions(-)
 create mode 100644 src/components/user_card/user_card.js
 create mode 100644 src/components/user_card/user_card.vue
 delete mode 100644 src/components/user_card_content/user_card_content.js
 delete mode 100644 src/components/user_card_content/user_card_content.vue

(limited to 'src/components/notification/notification.vue')

diff --git a/src/components/basic_user_card/basic_user_card.js b/src/components/basic_user_card/basic_user_card.js
index a8441446..87085a28 100644
--- a/src/components/basic_user_card/basic_user_card.js
+++ b/src/components/basic_user_card/basic_user_card.js
@@ -1,4 +1,4 @@
-import UserCardContent from '../user_card_content/user_card_content.vue'
+import UserCard from '../user_card/user_card.vue'
 import UserAvatar from '../user_avatar/user_avatar.vue'
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 
@@ -12,7 +12,7 @@ const BasicUserCard = {
     }
   },
   components: {
-    UserCardContent,
+    UserCard,
     UserAvatar
   },
   methods: {
diff --git a/src/components/basic_user_card/basic_user_card.vue b/src/components/basic_user_card/basic_user_card.vue
index f72620a3..9b80c72b 100644
--- a/src/components/basic_user_card/basic_user_card.vue
+++ b/src/components/basic_user_card/basic_user_card.vue
@@ -4,7 +4,7 @@
       <UserAvatar class="avatar" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/>
     </router-link>
     <div class="basic-user-card-expanded-content" v-if="userExpanded">
-      <UserCardContent :user="user" :rounded="true" :bordered="true"/>
+      <UserCard :user="user" :rounded="true" :bordered="true"/>
     </div>
     <div class="basic-user-card-collapsed-content" v-else>
       <div :title="user.name" class="basic-user-card-user-name">
diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js
index 7d9807de..fe5b7018 100644
--- a/src/components/notification/notification.js
+++ b/src/components/notification/notification.js
@@ -1,6 +1,6 @@
 import Status from '../status/status.vue'
 import UserAvatar from '../user_avatar/user_avatar.vue'
-import UserCardContent from '../user_card_content/user_card_content.vue'
+import UserCard from '../user_card/user_card.vue'
 import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
 import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
 
@@ -13,7 +13,7 @@ const Notification = {
   },
   props: [ 'notification' ],
   components: {
-    Status, UserAvatar, UserCardContent
+    Status, UserAvatar, UserCard
   },
   methods: {
     toggleUserExpanded () {
diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue
index 6583570e..5e9cef97 100644
--- a/src/components/notification/notification.vue
+++ b/src/components/notification/notification.vue
@@ -5,7 +5,7 @@
       <UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.action.user.profile_image_url_original"/>
     </a>
     <div class='notification-right'>
-      <UserCardContent :user="notification.action.user" :rounded="true" :bordered="true" v-if="userExpanded"/>
+      <UserCard :user="notification.action.user" :rounded="true" :bordered="true" v-if="userExpanded"/>
       <span class="notification-details">
         <div class="name-and-action">
           <span class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span>
diff --git a/src/components/side_drawer/side_drawer.js b/src/components/side_drawer/side_drawer.js
index b5c49059..ad3738d1 100644
--- a/src/components/side_drawer/side_drawer.js
+++ b/src/components/side_drawer/side_drawer.js
@@ -1,4 +1,4 @@
-import UserCardContent from '../user_card_content/user_card_content.vue'
+import UserCard from '../user_card/user_card.vue'
 import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
 
 // TODO: separate touch gesture stuff into their own utils if more components want them
@@ -12,7 +12,7 @@ const SideDrawer = {
     closed: true,
     touchCoord: [0, 0]
   }),
-  components: { UserCardContent },
+  components: { UserCard },
   computed: {
     currentUser () {
       return this.$store.state.users.currentUser
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index f346b440..b608b008 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -8,7 +8,7 @@
       @touchmove="touchMove"
     >
       <div class="side-drawer-heading" @click="toggleDrawer">
-        <UserCardContent :user="currentUser" :hideBio="true" v-if="currentUser"/>
+        <UserCard :user="currentUser" :hideBio="true" v-if="currentUser"/>
         <div class="side-drawer-logo-wrapper" v-else>
           <img :src="logo"/>
           <span>{{sitename}}</span>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index fbbca6c4..9e18fe15 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -3,7 +3,7 @@ import FavoriteButton from '../favorite_button/favorite_button.vue'
 import RetweetButton from '../retweet_button/retweet_button.vue'
 import DeleteButton from '../delete_button/delete_button.vue'
 import PostStatusForm from '../post_status_form/post_status_form.vue'
-import UserCardContent from '../user_card_content/user_card_content.vue'
+import UserCard from '../user_card/user_card.vue'
 import UserAvatar from '../user_avatar/user_avatar.vue'
 import Gallery from '../gallery/gallery.vue'
 import LinkPreview from '../link-preview/link-preview.vue'
@@ -259,7 +259,7 @@ const Status = {
     RetweetButton,
     DeleteButton,
     PostStatusForm,
-    UserCardContent,
+    UserCard,
     UserAvatar,
     Gallery,
     LinkPreview
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 0c110c90..8fda68f5 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -31,7 +31,7 @@
           </router-link>
         </div>
         <div class="status-body">
-          <UserCardContent :user="status.user" :rounded="true" :bordered="true" class="status-usercard-content" v-if="userExpanded"/>
+          <UserCard :user="status.user" :rounded="true" :bordered="true" class="status-usercard-content" v-if="userExpanded"/>
           <div v-if="!noHeading" class="media-heading">
             <div class="heading-name-row">
               <div class="name-and-account-name">
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
new file mode 100644
index 00000000..0cb616f4
--- /dev/null
+++ b/src/components/user_card/user_card.js
@@ -0,0 +1,148 @@
+import UserAvatar from '../user_avatar/user_avatar.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' ],
+  data () {
+    return {
+      followRequestInProgress: false,
+      followRequestSent: false,
+      hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined'
+        ? this.$store.state.instance.hideUserStats
+        : this.$store.state.config.hideUserStats,
+      betterShadow: this.$store.state.interface.browserSupport.cssFilter
+    }
+  },
+  computed: {
+    classes () {
+      return [{
+        'user-card-rt': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius
+        'user-card-r': this.rounded === true,   // set border-radius for all sides
+        'user-card-b': 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
+
+      if (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, ${gradient})`,
+            `url(${this.user.cover_photo})`
+          ].join(', ')
+        }
+      }
+    },
+    isOtherUser () {
+      return this.user.id !== this.$store.state.users.currentUser.id
+    },
+    subscribeUrl () {
+      // eslint-disable-next-line no-undef
+      const serverUrl = new URL(this.user.statusnet_profile_url)
+      return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
+    },
+    loggedIn () {
+      return this.$store.state.users.currentUser
+    },
+    dailyAvg () {
+      const days = Math.ceil((new Date() - new Date(this.user.created_at)) / (60 * 60 * 24 * 1000))
+      return Math.round(this.user.statuses_count / days)
+    },
+    userHighlightType: {
+      get () {
+        const data = this.$store.state.config.highlight[this.user.screen_name]
+        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 })
+        } else {
+          this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined })
+        }
+      }
+    },
+    userHighlightColor: {
+      get () {
+        const data = this.$store.state.config.highlight[this.user.screen_name]
+        return data && data.color
+      },
+      set (color) {
+        this.$store.dispatch('setHighlight', { user: this.user.screen_name, color })
+      }
+    },
+    visibleRole () {
+      const validRole = (this.user.role === 'admin' || this.user.role === 'moderator')
+      const showRole = this.isOtherUser || this.user.show_role
+
+      return validRole && showRole && this.user.role
+    }
+  },
+  components: {
+    UserAvatar
+  },
+  methods: {
+    followUser () {
+      this.followRequestInProgress = true
+      requestFollow(this.user, this.$store).then(({sent}) => {
+        this.followRequestInProgress = false
+        this.followRequestSent = sent
+      })
+    },
+    unfollowUser () {
+      this.followRequestInProgress = true
+      requestUnfollow(this.user, this.$store).then(() => {
+        this.followRequestInProgress = false
+      })
+    },
+    blockUser () {
+      const store = this.$store
+      store.state.api.backendInteractor.blockUser(this.user.id)
+        .then((blockedUser) => store.commit('addNewUsers', [blockedUser]))
+    },
+    unblockUser () {
+      const store = this.$store
+      store.state.api.backendInteractor.unblockUser(this.user.id)
+        .then((unblockedUser) => store.commit('addNewUsers', [unblockedUser]))
+    },
+    toggleMute () {
+      const store = this.$store
+      store.commit('setMuted', {user: this.user, muted: !this.user.muted})
+      store.state.api.backendInteractor.setUserMute(this.user)
+    },
+    setProfileView (v) {
+      if (this.switcher) {
+        const store = this.$store
+        store.commit('setProfileView', { v })
+      }
+    },
+    linkClicked ({target}) {
+      if (target.tagName === 'SPAN') {
+        target = target.parentNode
+      }
+      if (target.tagName === 'A') {
+        window.open(target.href, '_blank')
+      }
+    },
+    userProfileLink (user) {
+      return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
+    }
+  }
+}
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
new file mode 100644
index 00000000..b90f57a1
--- /dev/null
+++ b/src/components/user_card/user_card.vue
@@ -0,0 +1,420 @@
+<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" :src="user.profile_image_url_original"/>
+        </router-link>
+        <div class="name-and-screen-name">
+          <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-cog 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>
+
+          <router-link class='user-screen-name' :to="userProfileLink(user)">
+            <span class="handle">@{{user.screen_name}}
+              <span class="alert staff" v-if="!hideBio && !!visibleRole">{{visibleRole}}</span>
+            </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>
+          </router-link>
+        </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>
+      </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') : ''">
+              <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') }}
+              </template>
+            </button>
+          </span>
+        </div>
+        <div class='mute' v-if='isOtherUser && loggedIn'>
+          <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>
+      </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>
+    </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>
+
+<style lang="scss">
+@import '../../_variables.scss';
+
+.user-card {
+  background-size: cover;
+  overflow: hidden;
+
+  .panel-heading {
+    padding: .5em 0;
+    text-align: center;
+    box-shadow: none;
+    background: transparent;
+    flex-direction: column;
+    align-items: stretch;
+  }
+
+  .panel-body {
+    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%);
+  }
+
+  p {
+    margin-bottom: 0;
+  }
+
+  &-bio {
+    text-align: center;
+  }
+
+  //
+  // Modifiers
+
+  &-rt {
+    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);
+  }
+
+  &-r {
+    border-radius: $fallback--panelRadius;
+    border-radius: var(--panelRadius, $fallback--panelRadius);
+  }
+
+  &-b {
+    border-width: 1px;
+    border-style: solid;
+    border-color: $fallback--border;
+    border-color: var(--border, $fallback--border);
+  }
+}
+
+.user-info {
+  color: $fallback--lightText;
+  color: var(--lightText, $fallback--lightText);
+  padding: 0 26px;
+
+  .container {
+    padding: 16px 0 6px;
+    display: flex;
+    max-height: 56px;
+
+    .avatar {
+      flex: 1 0 100%;
+      width: 56px;
+      height: 56px;
+      box-shadow: 0px 1px 8px rgba(0,0,0,0.75);
+      box-shadow: var(--avatarShadow);
+      object-fit: cover;
+    }
+  }
+
+  &:hover .animated.avatar {
+    canvas {
+      display: none;
+    }
+    img {
+      visibility: visible;
+    }
+  }
+
+  .usersettings {
+    color: $fallback--lightText;
+    color: var(--lightText, $fallback--lightText);
+    opacity: .8;
+  }
+
+  .name-and-screen-name {
+    display: block;
+    margin-left: 0.6em;
+    text-align: left;
+    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
+    }
+    .top-line {
+      display: flex;
+    }
+  }
+
+  .user-name {
+    text-overflow: ellipsis;
+    overflow: hidden;
+    flex: 1 1 auto;
+    margin-right: 1em;
+    font-size: 15px;
+
+    img {
+      object-fit: contain;
+      height: 16px;
+      width: 16px;
+      vertical-align: middle;
+    }
+  }
+
+  .user-screen-name {
+    color: $fallback--lightText;
+    color: var(--lightText, $fallback--lightText);
+    display: inline-block;
+    font-weight: light;
+    font-size: 15px;
+    padding-right: 0.1em;
+    width: 100%;
+    display: flex;
+
+    .dailyAvg {
+      min-width: 1px;
+      flex: 0 0 auto;
+      margin-left: 1em;
+      font-size: 0.7em;
+      color: $fallback--text;
+      color: var(--text, $fallback--text);
+    }
+
+    .handle {
+      min-width: 1px;
+      flex: 0 1 auto;
+      text-overflow: ellipsis;
+      overflow: hidden;
+    }
+
+    // TODO use proper colors
+    .staff {
+      text-transform: capitalize;
+      color: $fallback--text;
+      color: var(--btnText, $fallback--text);
+      background-color: $fallback--fg;
+      background-color: var(--btn, $fallback--fg);
+    }
+  }
+
+  .user-meta {
+    margin-bottom: .15em;
+    display: flex;
+    align-items: baseline;
+    font-size: 14px;
+    line-height: 22px;
+    flex-wrap: wrap;
+
+    .following {
+      flex: 1 0 auto;
+      margin: 0;
+      margin-bottom: .25em;
+      text-align: left;
+    }
+
+    .highlighter {
+      flex: 0 1 auto;
+      display: flex;
+      flex-wrap: wrap;
+      margin-right: -.5em;
+      align-self: start;
+
+      .userHighlightCl {
+        padding: 2px 10px;
+        flex: 1 0 auto;
+      }
+
+      .userHighlightSel,
+      .userHighlightSel.select {
+        padding-top: 0;
+        padding-bottom: 0;
+        flex: 1 0 auto;
+      }
+      .userHighlightSel.select i {
+        line-height: 22px;
+      }
+
+      .userHighlightText {
+        width: 70px;
+        flex: 1 0 auto;
+      }
+
+      .userHighlightCl,
+      .userHighlightText,
+      .userHighlightSel,
+      .userHighlightSel.select {
+        height: 22px;
+        vertical-align: top;
+        margin-right: .5em;
+        margin-bottom: .25em;
+      }
+    }
+  }
+  .user-interactions {
+    display: flex;
+    flex-flow: row wrap;
+    justify-content: space-between;
+
+    margin-right: -.75em;
+
+    div {
+      flex: 1 0 0;
+      margin-right: .75em;
+      margin-bottom: .6em;
+      white-space: nowrap;
+    }
+
+    .mute {
+      max-width: 220px;
+      min-height: 28px;
+    }
+
+    .remote-follow {
+      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);
+    }
+  }
+}
+
+.user-counts {
+  display: flex;
+  line-height:16px;
+  padding: .5em 1.5em 0em 1.5em;
+  text-align: center;
+  justify-content: space-between;
+  color: $fallback--lightText;
+  color: var(--lightText, $fallback--lightText);
+  flex-wrap: wrap;
+}
+
+.user-count {
+  flex: 1 0 auto;
+  padding: .5em 0 .5em 0;
+  margin: 0 .5em;
+
+  h5 {
+    font-size:1em;
+    font-weight: bolder;
+    margin: 0 0 0.25em;
+  }
+  a {
+    text-decoration: none;
+  }
+}
+</style>
diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js
deleted file mode 100644
index 96c6036c..00000000
--- a/src/components/user_card_content/user_card_content.js
+++ /dev/null
@@ -1,148 +0,0 @@
-import UserAvatar from '../user_avatar/user_avatar.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' ],
-  data () {
-    return {
-      followRequestInProgress: false,
-      followRequestSent: false,
-      hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined'
-        ? this.$store.state.instance.hideUserStats
-        : this.$store.state.config.hideUserStats,
-      betterShadow: this.$store.state.interface.browserSupport.cssFilter
-    }
-  },
-  computed: {
-    classes () {
-      return [{
-        'user-card-content-rt': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius
-        'user-card-content-r': this.rounded === true,   // set border-radius for all sides
-        'user-card-content-b': 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
-
-      if (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, ${gradient})`,
-            `url(${this.user.cover_photo})`
-          ].join(', ')
-        }
-      }
-    },
-    isOtherUser () {
-      return this.user.id !== this.$store.state.users.currentUser.id
-    },
-    subscribeUrl () {
-      // eslint-disable-next-line no-undef
-      const serverUrl = new URL(this.user.statusnet_profile_url)
-      return `${serverUrl.protocol}//${serverUrl.host}/main/ostatus`
-    },
-    loggedIn () {
-      return this.$store.state.users.currentUser
-    },
-    dailyAvg () {
-      const days = Math.ceil((new Date() - new Date(this.user.created_at)) / (60 * 60 * 24 * 1000))
-      return Math.round(this.user.statuses_count / days)
-    },
-    userHighlightType: {
-      get () {
-        const data = this.$store.state.config.highlight[this.user.screen_name]
-        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 })
-        } else {
-          this.$store.dispatch('setHighlight', { user: this.user.screen_name, color: undefined })
-        }
-      }
-    },
-    userHighlightColor: {
-      get () {
-        const data = this.$store.state.config.highlight[this.user.screen_name]
-        return data && data.color
-      },
-      set (color) {
-        this.$store.dispatch('setHighlight', { user: this.user.screen_name, color })
-      }
-    },
-    visibleRole () {
-      const validRole = (this.user.role === 'admin' || this.user.role === 'moderator')
-      const showRole = this.isOtherUser || this.user.show_role
-
-      return validRole && showRole && this.user.role
-    }
-  },
-  components: {
-    UserAvatar
-  },
-  methods: {
-    followUser () {
-      this.followRequestInProgress = true
-      requestFollow(this.user, this.$store).then(({sent}) => {
-        this.followRequestInProgress = false
-        this.followRequestSent = sent
-      })
-    },
-    unfollowUser () {
-      this.followRequestInProgress = true
-      requestUnfollow(this.user, this.$store).then(() => {
-        this.followRequestInProgress = false
-      })
-    },
-    blockUser () {
-      const store = this.$store
-      store.state.api.backendInteractor.blockUser(this.user.id)
-        .then((blockedUser) => store.commit('addNewUsers', [blockedUser]))
-    },
-    unblockUser () {
-      const store = this.$store
-      store.state.api.backendInteractor.unblockUser(this.user.id)
-        .then((unblockedUser) => store.commit('addNewUsers', [unblockedUser]))
-    },
-    toggleMute () {
-      const store = this.$store
-      store.commit('setMuted', {user: this.user, muted: !this.user.muted})
-      store.state.api.backendInteractor.setUserMute(this.user)
-    },
-    setProfileView (v) {
-      if (this.switcher) {
-        const store = this.$store
-        store.commit('setProfileView', { v })
-      }
-    },
-    linkClicked ({target}) {
-      if (target.tagName === 'SPAN') {
-        target = target.parentNode
-      }
-      if (target.tagName === 'A') {
-        window.open(target.href, '_blank')
-      }
-    },
-    userProfileLink (user) {
-      return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
-    }
-  }
-}
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
deleted file mode 100644
index e003e850..00000000
--- a/src/components/user_card_content/user_card_content.vue
+++ /dev/null
@@ -1,420 +0,0 @@
-<template>
-<div class="user-card-content" :class="classes" :style="style">
-  <div class="panel-heading">
-    <div class='user-info'>
-      <div class='container'>
-        <router-link :to="userProfileLink(user)">
-          <UserAvatar :betterShadow="betterShadow" :src="user.profile_image_url_original"/>
-        </router-link>
-        <div class="name-and-screen-name">
-          <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-cog 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>
-
-          <router-link class='user-screen-name' :to="userProfileLink(user)">
-            <span class="handle">@{{user.screen_name}}
-              <span class="alert staff" v-if="!hideBio && !!visibleRole">{{visibleRole}}</span>
-            </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>
-          </router-link>
-        </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>
-      </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') : ''">
-              <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') }}
-              </template>
-            </button>
-          </span>
-        </div>
-        <div class='mute' v-if='isOtherUser && loggedIn'>
-          <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>
-      </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>
-    </div>
-    <p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="user-card-content-bio" v-html="user.description_html"></p>
-    <p v-else-if="!hideBio" class="user-card-content-bio">{{ user.description }}</p>
-  </div>
-</div>
-</template>
-
-<script src="./user_card_content.js"></script>
-
-<style lang="scss">
-@import '../../_variables.scss';
-
-.user-card-content {
-  background-size: cover;
-  overflow: hidden;
-
-  .panel-heading {
-    padding: .5em 0;
-    text-align: center;
-    box-shadow: none;
-    background: transparent;
-    flex-direction: column;
-    align-items: stretch;
-  }
-
-  .panel-body {
-    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%);
-  }
-
-  p {
-    margin-bottom: 0;
-  }
-
-  &-bio {
-    text-align: center;
-  }
-
-  //
-  // Modifiers
-
-  &-rt {
-    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);
-  }
-
-  &-r {
-    border-radius: $fallback--panelRadius;
-    border-radius: var(--panelRadius, $fallback--panelRadius);
-  }
-
-  &-b {
-    border-width: 1px;
-    border-style: solid;
-    border-color: $fallback--border;
-    border-color: var(--border, $fallback--border);
-  }
-}
-
-.user-info {
-  color: $fallback--lightText;
-  color: var(--lightText, $fallback--lightText);
-  padding: 0 26px;
-
-  .container {
-    padding: 16px 0 6px;
-    display: flex;
-    max-height: 56px;
-
-    .avatar {
-      flex: 1 0 100%;
-      width: 56px;
-      height: 56px;
-      box-shadow: 0px 1px 8px rgba(0,0,0,0.75);
-      box-shadow: var(--avatarShadow);
-      object-fit: cover;
-    }
-  }
-
-  &:hover .animated.avatar {
-    canvas {
-      display: none;
-    }
-    img {
-      visibility: visible;
-    }
-  }
-
-  .usersettings {
-    color: $fallback--lightText;
-    color: var(--lightText, $fallback--lightText);
-    opacity: .8;
-  }
-
-  .name-and-screen-name {
-    display: block;
-    margin-left: 0.6em;
-    text-align: left;
-    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
-    }
-    .top-line {
-      display: flex;
-    }
-  }
-
-  .user-name {
-    text-overflow: ellipsis;
-    overflow: hidden;
-    flex: 1 1 auto;
-    margin-right: 1em;
-    font-size: 15px;
-
-    img {
-      object-fit: contain;
-      height: 16px;
-      width: 16px;
-      vertical-align: middle;
-    }
-  }
-
-  .user-screen-name {
-    color: $fallback--lightText;
-    color: var(--lightText, $fallback--lightText);
-    display: inline-block;
-    font-weight: light;
-    font-size: 15px;
-    padding-right: 0.1em;
-    width: 100%;
-    display: flex;
-
-    .dailyAvg {
-      min-width: 1px;
-      flex: 0 0 auto;
-      margin-left: 1em;
-      font-size: 0.7em;
-      color: $fallback--text;
-      color: var(--text, $fallback--text);
-    }
-
-    .handle {
-      min-width: 1px;
-      flex: 0 1 auto;
-      text-overflow: ellipsis;
-      overflow: hidden;
-    }
-
-    // TODO use proper colors
-    .staff {
-      text-transform: capitalize;
-      color: $fallback--text;
-      color: var(--btnText, $fallback--text);
-      background-color: $fallback--fg;
-      background-color: var(--btn, $fallback--fg);
-    }
-  }
-
-  .user-meta {
-    margin-bottom: .15em;
-    display: flex;
-    align-items: baseline;
-    font-size: 14px;
-    line-height: 22px;
-    flex-wrap: wrap;
-
-    .following {
-      flex: 1 0 auto;
-      margin: 0;
-      margin-bottom: .25em;
-      text-align: left;
-    }
-
-    .highlighter {
-      flex: 0 1 auto;
-      display: flex;
-      flex-wrap: wrap;
-      margin-right: -.5em;
-      align-self: start;
-
-      .userHighlightCl {
-        padding: 2px 10px;
-        flex: 1 0 auto;
-      }
-
-      .userHighlightSel,
-      .userHighlightSel.select {
-        padding-top: 0;
-        padding-bottom: 0;
-        flex: 1 0 auto;
-      }
-      .userHighlightSel.select i {
-        line-height: 22px;
-      }
-
-      .userHighlightText {
-        width: 70px;
-        flex: 1 0 auto;
-      }
-
-      .userHighlightCl,
-      .userHighlightText,
-      .userHighlightSel,
-      .userHighlightSel.select {
-        height: 22px;
-        vertical-align: top;
-        margin-right: .5em;
-        margin-bottom: .25em;
-      }
-    }
-  }
-  .user-interactions {
-    display: flex;
-    flex-flow: row wrap;
-    justify-content: space-between;
-
-    margin-right: -.75em;
-
-    div {
-      flex: 1 0 0;
-      margin-right: .75em;
-      margin-bottom: .6em;
-      white-space: nowrap;
-    }
-
-    .mute {
-      max-width: 220px;
-      min-height: 28px;
-    }
-
-    .remote-follow {
-      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);
-    }
-  }
-}
-
-.user-counts {
-  display: flex;
-  line-height:16px;
-  padding: .5em 1.5em 0em 1.5em;
-  text-align: center;
-  justify-content: space-between;
-  color: $fallback--lightText;
-  color: var(--lightText, $fallback--lightText);
-  flex-wrap: wrap;
-}
-
-.user-count {
-  flex: 1 0 auto;
-  padding: .5em 0 .5em 0;
-  margin: 0 .5em;
-
-  h5 {
-    font-size:1em;
-    font-weight: bolder;
-    margin: 0 0 0.25em;
-  }
-  a {
-    text-decoration: none;
-  }
-}
-</style>
diff --git a/src/components/user_panel/user_panel.js b/src/components/user_panel/user_panel.js
index 15804b88..d4478290 100644
--- a/src/components/user_panel/user_panel.js
+++ b/src/components/user_panel/user_panel.js
@@ -1,6 +1,6 @@
 import LoginForm from '../login_form/login_form.vue'
 import PostStatusForm from '../post_status_form/post_status_form.vue'
-import UserCardContent from '../user_card_content/user_card_content.vue'
+import UserCard from '../user_card/user_card.vue'
 
 const UserPanel = {
   computed: {
@@ -9,7 +9,7 @@ const UserPanel = {
   components: {
     LoginForm,
     PostStatusForm,
-    UserCardContent
+    UserCard
   }
 }
 
diff --git a/src/components/user_panel/user_panel.vue b/src/components/user_panel/user_panel.vue
index 4b3d8971..8310f30e 100644
--- a/src/components/user_panel/user_panel.vue
+++ b/src/components/user_panel/user_panel.vue
@@ -1,7 +1,7 @@
 <template>
   <div class="user-panel">
     <div v-if='user' class="panel panel-default" style="overflow: visible;">
-      <UserCardContent :user="user" :hideBio="true" rounded="top"/>
+      <UserCard :user="user" :hideBio="true" rounded="top"/>
       <div class="panel-footer">
         <post-status-form v-if='user'></post-status-form>
       </div>
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index cdf1cee9..54126514 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -1,6 +1,6 @@
 import { compose } from 'vue-compose'
 import get from 'lodash/get'
-import UserCardContent from '../user_card_content/user_card_content.vue'
+import UserCard from '../user_card/user_card.vue'
 import FollowCard from '../follow_card/follow_card.vue'
 import Timeline from '../timeline/timeline.vue'
 import withLoadMore from '../../hocs/with_load_more/with_load_more'
@@ -147,7 +147,7 @@ const UserProfile = {
     }
   },
   components: {
-    UserCardContent,
+    UserCard,
     Timeline,
     FollowerList,
     FriendList
diff --git a/src/components/user_profile/user_profile.vue b/src/components/user_profile/user_profile.vue
index c57d3409..7d4a8b1f 100644
--- a/src/components/user_profile/user_profile.vue
+++ b/src/components/user_profile/user_profile.vue
@@ -1,7 +1,7 @@
 <template>
 <div>
   <div v-if="user.id" class="user-profile panel panel-default">
-    <UserCardContent :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/>
+    <UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/>
     <tab-switcher :renderOnlyFocused="true" ref="tabSwitcher">
       <Timeline
         :label="$t('user_card.statuses')"
-- 
cgit v1.2.3-70-g09d2

