mirror of
https://github.com/YunoHost/yunohost-admin.git
synced 2024-09-03 20:06:15 +02:00
add LazyRenderer component & update AppCatalog
This commit is contained in:
parent
9b3ac1fcaf
commit
c7d8f5fb68
2 changed files with 124 additions and 44 deletions
59
app/src/components/LazyRenderer.vue
Normal file
59
app/src/components/LazyRenderer.vue
Normal file
|
@ -0,0 +1,59 @@
|
|||
<template>
|
||||
<div class="lazy-renderer" :style="`min-height: ${fixedMinHeight}px`">
|
||||
<slot v-if="render" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: 'LazyRenderer',
|
||||
|
||||
props: {
|
||||
unrender: { type: Boolean, default: true },
|
||||
minHeight: { type: Number, default: 0 },
|
||||
renderDelay: { type: Number, default: 100 },
|
||||
unrenderDelay: { type: Number, default: 2000 },
|
||||
rootMargin: { type: String, default: '300px' }
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
observer: null,
|
||||
render: false,
|
||||
fixedMinHeight: this.minHeight
|
||||
}
|
||||
},
|
||||
|
||||
mounted () {
|
||||
let unrenderTimer
|
||||
let renderTimer
|
||||
this.observer = new IntersectionObserver(entries => {
|
||||
if (entries[0].isIntersecting) {
|
||||
clearTimeout(unrenderTimer)
|
||||
// Show the component after a delay (to avoid rendering while scrolling fast)
|
||||
renderTimer = setTimeout(() => {
|
||||
this.render = true
|
||||
}, this.unrender ? this.renderDelay : 0)
|
||||
|
||||
if (!this.unrender) {
|
||||
// Stop listening to intersections after first appearance if unrendering is not activated
|
||||
this.observer.disconnect()
|
||||
}
|
||||
} else if (this.unrender) {
|
||||
clearTimeout(renderTimer)
|
||||
// Hide the component after a delay if it's no longer in the viewport
|
||||
unrenderTimer = setTimeout(() => {
|
||||
this.fixedMinHeight = this.$el.clientHeight
|
||||
this.render = false
|
||||
}, this.unrenderDelay)
|
||||
}
|
||||
}, { rootMargin: this.rootMargin })
|
||||
|
||||
this.observer.observe(this.$el)
|
||||
},
|
||||
|
||||
beforeDestroy () {
|
||||
this.observer.disconnect()
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -64,52 +64,56 @@
|
|||
|
||||
<!-- APPS CARDS -->
|
||||
<b-card-group v-else deck>
|
||||
<b-card no-body v-for="app in filteredApps" :key="app.id">
|
||||
<b-card-body class="d-flex flex-column">
|
||||
<b-card-title class="d-flex mb-2">
|
||||
{{ app.manifest.name }}
|
||||
<small v-if="app.state !== 'working'" class="d-flex align-items-center ml-2">
|
||||
<b-badge
|
||||
v-if="app.state !== 'highquality'"
|
||||
:variant="(app.color === 'danger' && app.state === 'lowquality') ? 'warning' : app.color"
|
||||
v-b-popover.hover.bottom="$t(`app_state_${app.state}_explanation`)"
|
||||
>
|
||||
{{ $t('app_state_' + app.state) }}
|
||||
</b-badge>
|
||||
<icon
|
||||
v-else iname="star" class="star"
|
||||
v-b-popover.hover.bottom="$t(`app_state_${app.state}_explanation`)"
|
||||
/>
|
||||
</small>
|
||||
</b-card-title>
|
||||
<lazy-renderer v-for="app in filteredApps" :key="app.id" :min-height="120">
|
||||
<b-card no-body>
|
||||
<b-card-body class="d-flex flex-column">
|
||||
<b-card-title class="d-flex mb-2">
|
||||
{{ app.manifest.name }}
|
||||
|
||||
<b-card-text>{{ app.manifest.description }}</b-card-text>
|
||||
<small v-if="app.state !== 'working'" class="d-flex align-items-center ml-2">
|
||||
<b-badge
|
||||
v-if="app.state !== 'highquality'"
|
||||
:variant="(app.color === 'danger' && app.state === 'lowquality') ? 'warning' : app.color"
|
||||
v-b-popover.hover.bottom="$t(`app_state_${app.state}_explanation`)"
|
||||
>
|
||||
{{ $t('app_state_' + app.state) }}
|
||||
</b-badge>
|
||||
|
||||
<b-card-text v-if="app.maintained === 'orphaned'" class="align-self-end mt-auto">
|
||||
<span class="alert-warning p-1" v-b-popover.hover.top="$t('orphaned_details')">
|
||||
<icon iname="warning" /> {{ $t(app.maintained) }}
|
||||
</span>
|
||||
</b-card-text>
|
||||
</b-card-body>
|
||||
<icon
|
||||
v-else iname="star" class="star"
|
||||
v-b-popover.hover.bottom="$t(`app_state_${app.state}_explanation`)"
|
||||
/>
|
||||
</small>
|
||||
</b-card-title>
|
||||
|
||||
<!-- APP BUTTONS -->
|
||||
<b-button-group>
|
||||
<b-button :href="app.git.url" variant="outline-dark" target="_blank">
|
||||
<icon iname="code" /> {{ $t('code') }}
|
||||
</b-button>
|
||||
<b-card-text>{{ app.manifest.description }}</b-card-text>
|
||||
|
||||
<b-button :href="app.git.url + '/blob/master/README.md'" variant="outline-dark" target="_blank">
|
||||
<icon iname="book" /> {{ $t('readme') }}
|
||||
</b-button>
|
||||
<b-card-text v-if="app.maintained === 'orphaned'" class="align-self-end mt-auto">
|
||||
<span class="alert-warning p-1" v-b-popover.hover.top="$t('orphaned_details')">
|
||||
<icon iname="warning" /> {{ $t(app.maintained) }}
|
||||
</span>
|
||||
</b-card-text>
|
||||
</b-card-body>
|
||||
|
||||
<b-button v-if="app.isInstallable" :variant="app.color" @click="onInstallClick(app)">
|
||||
<icon iname="plus" /> {{ $t('install') }} <icon v-if="app.color === 'danger'" class="ml-1" iname="warning" />
|
||||
</b-button>
|
||||
<b-button v-else :variant="app.color" disabled>
|
||||
{{ $t('installed') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
</b-card>
|
||||
<!-- APP BUTTONS -->
|
||||
<b-button-group>
|
||||
<b-button :href="app.git.url" variant="outline-dark" target="_blank">
|
||||
<icon iname="code" /> {{ $t('code') }}
|
||||
</b-button>
|
||||
|
||||
<b-button :href="app.git.url + '/blob/master/README.md'" variant="outline-dark" target="_blank">
|
||||
<icon iname="book" /> {{ $t('readme') }}
|
||||
</b-button>
|
||||
|
||||
<b-button v-if="app.isInstallable" :variant="app.color" @click="onInstallClick(app)">
|
||||
<icon iname="plus" /> {{ $t('install') }} <icon v-if="app.color === 'danger'" class="ml-1" iname="warning" />
|
||||
</b-button>
|
||||
<b-button v-else :variant="app.color" disabled>
|
||||
{{ $t('installed') }}
|
||||
</b-button>
|
||||
</b-button-group>
|
||||
</b-card>
|
||||
</lazy-renderer>
|
||||
</b-card-group>
|
||||
|
||||
<template #bot>
|
||||
|
@ -155,12 +159,17 @@
|
|||
<script>
|
||||
import { validationMixin } from 'vuelidate'
|
||||
|
||||
import LazyRenderer from '@/components/LazyRenderer'
|
||||
import { required, githubLink } from '@/helpers/validators'
|
||||
import { randint } from '@/helpers/commons'
|
||||
|
||||
export default {
|
||||
name: 'AppCatalog',
|
||||
|
||||
components: {
|
||||
LazyRenderer
|
||||
},
|
||||
|
||||
data () {
|
||||
return {
|
||||
queries: [
|
||||
|
@ -375,10 +384,11 @@ export default {
|
|||
}
|
||||
|
||||
.card-deck {
|
||||
.card {
|
||||
border-color: $gray-400;
|
||||
> * {
|
||||
margin-left: 15px;
|
||||
margin-right: 15px;
|
||||
margin-bottom: 2rem;
|
||||
flex-basis: 90%;
|
||||
flex-basis: 100%;
|
||||
@include media-breakpoint-up(md) {
|
||||
flex-basis: 50%;
|
||||
max-width: calc(50% - 30px);
|
||||
|
@ -388,6 +398,15 @@ export default {
|
|||
max-width: calc(33.3% - 30px);
|
||||
}
|
||||
|
||||
.card {
|
||||
margin: 0;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
.card {
|
||||
border-color: $gray-400;
|
||||
|
||||
// not maintained info
|
||||
.alert-warning {
|
||||
font-size: .75em;
|
||||
|
@ -402,6 +421,8 @@ export default {
|
|||
@include media-breakpoint-up(sm) {
|
||||
min-height: 10rem;
|
||||
}
|
||||
|
||||
flex-basis: 90%;
|
||||
border: 0;
|
||||
|
||||
.btn {
|
||||
|
|
Loading…
Add table
Reference in a new issue