Replace v-progress loaders with skeletons

This commit is contained in:
Georges-Antoine Assi
2025-08-22 09:56:38 -04:00
parent 66e2ea417d
commit eee8cc120f
5 changed files with 40 additions and 71 deletions

View File

@@ -20,40 +20,40 @@ const unmatchedCoverImage = computed(() =>
<template>
<v-card
id="background-header"
elevation="0"
rounded="0"
class="w-100"
:key="currentRom.updated_at"
v-if="currentRom"
>
<v-img
id="background-image"
:src="currentRom?.path_cover_large || unmatchedCoverImage"
class="background-image"
:src="currentRom?.path_cover_small || unmatchedCoverImage"
cover
>
<template #error>
<v-img :src="missingCoverImage" />
</template>
<template #placeholder>
<div class="d-flex align-center justify-center fill-height">
<v-progress-circular
:width="2"
:size="40"
color="primary"
indeterminate
/>
</div>
<v-skeleton-loader class="background-skeleton" type="image" />
</template>
</v-img>
</v-card>
</template>
<style scoped>
#background-header {
width: 100%;
}
#background-image {
<style scoped>
.background-image {
height: 18rem;
filter: blur(30px);
}
.background-skeleton {
height: 18rem;
}
</style>
<style>
.background-skeleton .v-skeleton-loader__image {
height: 100%;
}
</style>

View File

@@ -2,12 +2,13 @@
import type { SearchRomSchema } from "@/__generated__";
import GameCard from "@/components/common/Game/Card/Base.vue";
import RDialog from "@/components/common/RDialog.vue";
import romApi from "@/services/api/rom";
import Skeleton from "@/components/common/Game/Card/Skeleton.vue";
import EmptyManualMatch from "@/components/common/EmptyStates/EmptyManualMatch.vue";
import storeGalleryView from "@/stores/galleryView";
import storeHeartbeat from "@/stores/heartbeat";
import storeRoms, { type SimpleRom } from "@/stores/roms";
import storePlatforms from "@/stores/platforms";
import romApi from "@/services/api/rom";
import type { Events } from "@/types/emitter";
import type { Emitter } from "mitt";
import { computed, inject, onBeforeUnmount, ref } from "vue";
@@ -490,15 +491,10 @@ onBeforeUnmount(() => {
cover
>
<template #placeholder>
<div
class="d-flex align-center justify-center fill-height"
>
<v-progress-circular
color="primary"
:width="2"
indeterminate
/>
</div>
<skeleton
:aspectRatio="computedAspectRatio"
type="image"
/>
</template>
<v-row no-gutters class="text-white pa-1">
<v-avatar class="mr-1" size="30" rounded="1">
@@ -580,19 +576,18 @@ onBeforeUnmount(() => {
<template #footer>
<v-row no-gutters class="text-center">
<v-col>
<v-chip label class="pr-0" size="small"
>{{ t("rom.results-found") }}:<v-chip
color="primary"
class="ml-2 px-2"
label
>{{ !searching ? matchedRoms.length : ""
}}<v-progress-circular
<v-chip label class="pr-0" size="small">
{{ t("rom.results-found") }}:
<v-chip color="primary" class="ml-2 px-2" label>
{{ !searching ? matchedRoms.length : "" }}
<v-progress-circular
v-if="searching"
:width="1"
:size="10"
color="primary"
indeterminate
/></v-chip>
/>
</v-chip>
</v-chip>
</v-col>
</v-row>

View File

@@ -132,9 +132,9 @@ onBeforeUnmount(() => {
:size="20"
indeterminate
/>
<v-icon v-else :color="$route.name == 'scan' ? 'primary' : ''"
>mdi-magnify-scan</v-icon
>
<v-icon v-else :color="$route.name == 'scan' ? 'primary' : ''">
mdi-magnify-scan
</v-icon>
<v-expand-transition>
<span
v-if="withTag"

View File

@@ -2,26 +2,24 @@
import type { SearchCoverSchema } from "@/__generated__";
import RDialog from "@/components/common/RDialog.vue";
import sgdbApi from "@/services/api/sgdb";
import Skeleton from "@/components/common/Game/Card/Skeleton.vue";
import storeGalleryView from "@/stores/galleryView";
import storePlatforms from "@/stores/platforms";
import type { Events } from "@/types/emitter";
import type { Emitter } from "mitt";
import { inject, onBeforeUnmount, ref } from "vue";
import { useDisplay } from "vuetify";
const { lgAndUp } = useDisplay();
const galleryViewStore = storeGalleryView();
const show = ref(false);
const searching = ref(false);
const searchText = ref("");
const coverType = ref("all");
const covers = ref<SearchCoverSchema[]>([]);
const filteredCovers = ref<SearchCoverSchema[]>();
const galleryViewStore = storeGalleryView();
const panels = ref([0]);
const emitter = inject<Emitter<Events>>("emitter");
const coverAspectRatio = ref(
parseFloat(galleryViewStore.defaultAspectRatioCover.toString()),
);
emitter?.on("showSearchCoverDialog", ({ term, aspectRatio = null }) => {
searchText.value = term;
show.value = true;
@@ -30,6 +28,10 @@ emitter?.on("showSearchCoverDialog", ({ term, aspectRatio = null }) => {
if (searchText.value) searchCovers();
});
const coverAspectRatio = ref(
parseFloat(galleryViewStore.defaultAspectRatioCover.toString()),
);
async function searchCovers() {
covers.value = [];
@@ -199,16 +201,7 @@ onBeforeUnmount(() => {
></v-img>
</template>
<template #placeholder>
<div
class="d-flex align-center justify-center fill-height"
>
<v-progress-circular
:width="2"
:size="40"
color="primary"
indeterminate
/>
</div>
<skeleton :aspectRatio="coverAspectRatio" type="image" />
</template>
</v-img>
</v-hover>

View File

@@ -1,19 +0,0 @@
<script setup lang="ts">
import type { Events } from "@/types/emitter";
import type { Emitter } from "mitt";
import { inject, ref } from "vue";
const show = ref(false);
const scrim = ref(false);
const emitter = inject<Emitter<Events>>("emitter");
emitter?.on("showLoadingDialog", (args) => {
show.value = args.loading;
scrim.value = args.scrim;
});
</script>
<template>
<v-dialog :model-value="show" scroll-strategy="none" width="auto" persistent>
<v-progress-circular :width="3" :size="70" color="primary" indeterminate />
</v-dialog>
</template>