diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index f95a329f..7d9807de 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -1,5 +1,5 @@ import Status from '../status/status.vue' -import StillImage from '../still-image/still-image.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' import UserCardContent from '../user_card_content/user_card_content.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, StillImage, UserCardContent + Status, UserAvatar, UserCardContent }, methods: { toggleUserExpanded () { diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index f91c90cc..a0a55cba 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -2,7 +2,7 @@ <status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status> <div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]"v-else> <a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded"> - <StillImage class='avatar-compact' :class="{'better-shadow': betterShadow}" :src="notification.action.user.profile_image_url_original"/> + <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"> diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 5c4ca1b9..bc81d45c 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -36,26 +36,7 @@ border-color: $fallback--border; border-color: var(--border, $fallback--border); - .avatar-compact { - width: 32px; - height: 32px; - box-shadow: var(--avatarStatusShadow); - border-radius: $fallback--avatarAltRadius; - border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); - overflow: hidden; - line-height: 0; - - &.better-shadow { - box-shadow: var(--avatarStatusShadowInset); - filter: var(--avatarStatusShadowFilter) - } - - &.animated::before { - display: none; - } - } - - &:hover .animated.avatar-compact { + &:hover .animated.avatar { canvas { display: none; } diff --git a/src/components/status/status.js b/src/components/status/status.js index c718fe9f..7bf4fa2d 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -4,7 +4,7 @@ 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 StillImage from '../still-image/still-image.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' import Gallery from '../gallery/gallery.vue' import LinkPreview from '../link-preview/link-preview.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' @@ -244,7 +244,7 @@ const Status = { DeleteButton, PostStatusForm, UserCardContent, - StillImage, + UserAvatar, Gallery, LinkPreview }, diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 3e3e82bf..7581f749 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -13,7 +13,7 @@ </template> <template v-else> <div v-if="retweet && !noHeading" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info"> - <StillImage v-if="retweet" class='avatar' :class='{ "better-shadow": betterShadow }' :src="statusoid.user.profile_image_url_original"/> + <UserAvatar v-if="retweet" :betterShadow="betterShadow" :src="statusoid.user.profile_image_url_original"/> <div class="media-body faint"> <a v-if="retweeterHtml" :href="statusoid.user.statusnet_profile_url" class="user-name" :title="'@'+statusoid.user.screen_name" v-html="retweeterHtml"></a> <a v-else :href="statusoid.user.statusnet_profile_url" class="user-name" :title="'@'+statusoid.user.screen_name">{{retweeter}}</a> @@ -25,7 +25,7 @@ <div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet }]" :style="[ userStyle ]" class="media status"> <div v-if="!noHeading" class="media-left"> <router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded"> - <StillImage class='avatar' :class="{'avatar-compact': compact, 'better-shadow': betterShadow}" :src="status.user.profile_image_url_original"/> + <UserAvatar :compact="compact" :betterShadow="betterShadow" :src="status.user.profile_image_url_original"/> </router-link> </div> <div class="status-body"> @@ -413,7 +413,7 @@ padding: 0.4em 0.6em 0 0.6em; margin: 0; - .avatar { + .avatar.still-image { border-radius: $fallback--avatarAltRadius; border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); margin-left: 28px; @@ -497,46 +497,6 @@ color: var(--cBlue, $fallback--cBlue); } -.status .avatar-compact { - width: 32px; - height: 32px; - box-shadow: var(--avatarStatusShadow); - border-radius: $fallback--avatarAltRadius; - border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); - - &.better-shadow { - box-shadow: var(--avatarStatusShadowInset); - filter: var(--avatarStatusShadowFilter) - } -} - -.avatar.still-image { - width: 48px; - height: 48px; - box-shadow: var(--avatarStatusShadow); - border-radius: $fallback--avatarRadius; - border-radius: var(--avatarRadius, $fallback--avatarRadius); - overflow: hidden; - position: relative; - - &.better-shadow { - box-shadow: var(--avatarStatusShadowInset); - filter: var(--avatarStatusShadowFilter) - } - - img { - width: 100%; - height: 100%; - } - - &.animated::before { - display: none; - } - - &.retweeted { - } -} - .status:hover .animated.avatar { canvas { display: none; @@ -594,7 +554,7 @@ a.unmute { @media all and (max-width: 800px) { .status-el { .retweet-info { - .avatar { + .avatar.still-image { margin-left: 20px; } } @@ -603,14 +563,14 @@ a.unmute { max-width: 100%; } - .status .avatar { + .status .avatar.still-image { width: 40px; height: 40px; - } - .status .avatar-compact { - width: 32px; - height: 32px; + &.avatar-compact { + width: 32px; + height: 32px; + } } } diff --git a/src/components/still-image/still-image.js b/src/components/still-image/still-image.js index 5ad06dc2..8f3a7206 100644 --- a/src/components/still-image/still-image.js +++ b/src/components/still-image/still-image.js @@ -2,7 +2,8 @@ const StillImage = { props: [ 'src', 'referrerpolicy', - 'mimetype' + 'mimetype', + 'imageLoadError' ], data () { return { diff --git a/src/components/still-image/still-image.vue b/src/components/still-image/still-image.vue index 1dcb7ce6..29c59e42 100644 --- a/src/components/still-image/still-image.vue +++ b/src/components/still-image/still-image.vue @@ -1,7 +1,7 @@ <template> <div class='still-image' :class='{ animated: animated }' > <canvas ref="canvas" v-if="animated"></canvas> - <img ref="src" :src="src" :referrerpolicy="referrerpolicy" v-on:load="onLoad"/> + <img ref="src" :src="src" :referrerpolicy="referrerpolicy" v-on:load="onLoad" @error="imageLoadError"/> </div> </template> diff --git a/src/components/user_avatar/user_avatar.js b/src/components/user_avatar/user_avatar.js new file mode 100644 index 00000000..e513b993 --- /dev/null +++ b/src/components/user_avatar/user_avatar.js @@ -0,0 +1,29 @@ +import StillImage from '../still-image/still-image.vue' + +const UserAvatar = { + props: [ + 'src', + 'betterShadow', + 'compact' + ], + data () { + return { + showPlaceholder: false + } + }, + components: { + StillImage + }, + computed: { + imgSrc () { + return this.showPlaceholder ? '/images/avi.png' : this.src + } + }, + methods: { + imageLoadError () { + this.showPlaceholder = true + } + } +} + +export default UserAvatar diff --git a/src/components/user_avatar/user_avatar.vue b/src/components/user_avatar/user_avatar.vue new file mode 100644 index 00000000..3ec25b21 --- /dev/null +++ b/src/components/user_avatar/user_avatar.vue @@ -0,0 +1,37 @@ +<template> + <StillImage class="avatar" :class="{ 'avatar-compact': compact, 'better-shadow': betterShadow }" :src="imgSrc" :imageLoadError="imageLoadError"/> +</template> + +<script src="./user_avatar.js"></script> +<style lang="scss"> +@import '../../_variables.scss'; + +.avatar.still-image { + width: 48px; + height: 48px; + box-shadow: var(--avatarStatusShadow); + border-radius: $fallback--avatarRadius; + border-radius: var(--avatarRadius, $fallback--avatarRadius); + + img { + width: 100%; + height: 100%; + } + + &.better-shadow { + box-shadow: var(--avatarStatusShadowInset); + filter: var(--avatarStatusShadowFilter) + } + + &.animated::before { + display: none; + } + + &.avatar-compact { + width: 32px; + height: 32px; + border-radius: $fallback--avatarAltRadius; + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + } +} +</style> diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 615e6487..ecc36a4d 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -1,5 +1,5 @@ import UserCardContent from '../user_card_content/user_card_content.vue' -import StillImage from '../still-image/still-image.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' const UserCard = { @@ -15,7 +15,7 @@ const UserCard = { }, components: { UserCardContent, - StillImage + UserAvatar }, computed: { currentUser () { return this.$store.state.users.currentUser } diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index cf69606d..57a44dfb 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -1,7 +1,7 @@ <template> <div class="card"> <a href="#"> - <StillImage @click.prevent="toggleUserExpanded" class="avatar" :src="user.profile_image_url"/> + <UserAvatar :compact="true" @click.prevent="toggleUserExpanded" :src="user.profile_image_url"/> </a> <div class="usercard" v-if="userExpanded"> <user-card-content :user="user" :switcher="false"></user-card-content> @@ -70,10 +70,6 @@ .avatar { margin-top: 0.2em; - width:32px; - height: 32px; - border-radius: $fallback--avatarAltRadius; - border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); } } diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index 541c73b4..6f6d04a7 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -1,4 +1,4 @@ -import StillImage from '../still-image/still-image.vue' +import UserAvatar from '../user_avatar/user_avatar.vue' import { hex2rgb } from '../../services/color_convert/color_convert.js' import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator' @@ -82,7 +82,7 @@ export default { } }, components: { - StillImage + UserAvatar }, methods: { followUser () { diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index d1034d68..ce65ec2f 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -4,7 +4,7 @@ <div class='user-info'> <div class='container'> <router-link :to="userProfileLink(user)"> - <StillImage class="avatar" :class='{ "better-shadow": betterShadow }' :src="user.profile_image_url_original"/> + <UserAvatar :betterShadow="betterShadow" :src="user.profile_image_url_original"/> </router-link> <div class="name-and-screen-name"> <div class="top-line"> @@ -169,23 +169,12 @@ max-height: 56px; .avatar { - border-radius: $fallback--avatarRadius; - border-radius: var(--avatarRadius, $fallback--avatarRadius); 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; - - &.better-shadow { - box-shadow: var(--avatarShadowInset); - filter: var(--avatarShadowFilter) - } - - &.animated::before { - display: none; - } } }