Merge pull request #15360 from netchampfaris/marketplaces-fixes
fix(image): New Image component to consistently handle broken images
This commit is contained in:
commit
80e6cad7ac
@ -28,7 +28,7 @@
|
|||||||
<div class="row margin-bottom">
|
<div class="row margin-bottom">
|
||||||
<div class="col-md-3">
|
<div class="col-md-3">
|
||||||
<div class="hub-item-image">
|
<div class="hub-item-image">
|
||||||
<img v-img-src="image">
|
<base-image :src="image" :alt="title" />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="col-md-8">
|
<div class="col-md-8">
|
||||||
|
40
erpnext/public/js/hub/components/Image.vue
Normal file
40
erpnext/public/js/hub/components/Image.vue
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
<template>
|
||||||
|
<div class="hub-image">
|
||||||
|
<img :src="src" :alt="alt" v-show="!is_loading && !is_broken"/>
|
||||||
|
<div class="hub-image-loading" v-if="is_loading">
|
||||||
|
<span class="octicon octicon-cloud-download"></span>
|
||||||
|
</div>
|
||||||
|
<div class="hub-image-broken" v-if="is_broken">
|
||||||
|
<span class="octicon octicon-file-media"></span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
name: 'Image',
|
||||||
|
props: ['src', 'alt'],
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
is_loading: true,
|
||||||
|
is_broken: false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
created() {
|
||||||
|
this.handle_image();
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
handle_image() {
|
||||||
|
let img = new Image();
|
||||||
|
img.src = this.src;
|
||||||
|
|
||||||
|
img.onload = () => {
|
||||||
|
this.is_loading = false;
|
||||||
|
};
|
||||||
|
img.onerror = () => {
|
||||||
|
this.is_loading = false;
|
||||||
|
this.is_broken = true;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
</script>
|
@ -15,7 +15,7 @@
|
|||||||
</i>
|
</i>
|
||||||
</div>
|
</div>
|
||||||
<div class="hub-card-body">
|
<div class="hub-card-body">
|
||||||
<img class="hub-card-image" v-img-src="item.image"/>
|
<base-image class="hub-card-image" :src="item.image" :alt="title" />
|
||||||
<div class="hub-card-overlay">
|
<div class="hub-card-overlay">
|
||||||
<div v-if="is_local" class="hub-card-overlay-body">
|
<div v-if="is_local" class="hub-card-overlay-body">
|
||||||
<div class="hub-card-overlay-button">
|
<div class="hub-card-overlay-button">
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="hub-list-item" :data-route="item.route">
|
<div class="hub-list-item" :data-route="item.route">
|
||||||
<div class="hub-list-left">
|
<div class="hub-list-left">
|
||||||
<img class="hub-list-image" v-img-src="item.image">
|
<base-image class="hub-list-image" :src="item.image" />
|
||||||
<div class="hub-list-body ellipsis">
|
<div class="hub-list-body ellipsis">
|
||||||
<div class="hub-list-title">{{item.item_name}}</div>
|
<div class="hub-list-title">{{item.item_name}}</div>
|
||||||
<div class="hub-list-subtitle ellipsis">
|
<div class="hub-list-subtitle ellipsis">
|
||||||
|
@ -7,6 +7,7 @@ import SearchInput from './components/SearchInput.vue';
|
|||||||
import DetailView from './components/DetailView.vue';
|
import DetailView from './components/DetailView.vue';
|
||||||
import DetailHeaderItem from './components/DetailHeaderItem.vue';
|
import DetailHeaderItem from './components/DetailHeaderItem.vue';
|
||||||
import EmptyState from './components/EmptyState.vue';
|
import EmptyState from './components/EmptyState.vue';
|
||||||
|
import Image from './components/Image.vue';
|
||||||
|
|
||||||
Vue.prototype.__ = window.__;
|
Vue.prototype.__ = window.__;
|
||||||
Vue.prototype.frappe = window.frappe;
|
Vue.prototype.frappe = window.frappe;
|
||||||
@ -17,6 +18,7 @@ Vue.component('search-input', SearchInput);
|
|||||||
Vue.component('detail-view', DetailView);
|
Vue.component('detail-view', DetailView);
|
||||||
Vue.component('detail-header-item', DetailHeaderItem);
|
Vue.component('detail-header-item', DetailHeaderItem);
|
||||||
Vue.component('empty-state', EmptyState);
|
Vue.component('empty-state', EmptyState);
|
||||||
|
Vue.component('base-image', Image);
|
||||||
|
|
||||||
Vue.directive('route', {
|
Vue.directive('route', {
|
||||||
bind(el, binding) {
|
bind(el, binding) {
|
||||||
@ -51,16 +53,6 @@ const handleImage = (el, src) => {
|
|||||||
img.src = src;
|
img.src = src;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vue.directive('img-src', {
|
|
||||||
bind(el, binding) {
|
|
||||||
handleImage(el, binding.value);
|
|
||||||
},
|
|
||||||
update(el, binding) {
|
|
||||||
if (binding.value === binding.oldValue) return;
|
|
||||||
handleImage(el, binding.value);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
Vue.filter('striphtml', function (text) {
|
Vue.filter('striphtml', function (text) {
|
||||||
return strip_html(text || '');
|
return strip_html(text || '');
|
||||||
});
|
});
|
@ -1,4 +1,5 @@
|
|||||||
@import "../../../../frappe/frappe/public/less/variables.less";
|
@import "variables.less";
|
||||||
|
@import (reference) "desk.less";
|
||||||
|
|
||||||
body[data-route^="marketplace/"] {
|
body[data-route^="marketplace/"] {
|
||||||
.layout-side-section {
|
.layout-side-section {
|
||||||
@ -26,6 +27,22 @@ body[data-route^="marketplace/"] {
|
|||||||
font-size: @text-medium;
|
font-size: @text-medium;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.hub-image {
|
||||||
|
height: 200px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hub-image-loading, .hub-image-broken {
|
||||||
|
.img-background();
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
span {
|
||||||
|
font-size: 32px;
|
||||||
|
color: @text-extra-muted;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.progress-bar {
|
.progress-bar {
|
||||||
background-color: #89da28;
|
background-color: #89da28;
|
||||||
}
|
}
|
||||||
@ -136,6 +153,7 @@ body[data-route^="marketplace/"] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.hub-item-image {
|
.hub-item-image {
|
||||||
|
position: relative;
|
||||||
border: 1px solid @border-color;
|
border: 1px solid @border-color;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
Loading…
Reference in New Issue
Block a user