Skip to content

Commit af8f122

Browse files
committed
fix(image): adds image size selector & fix placeholder
1 parent d3cee27 commit af8f122

File tree

5 files changed

+68
-21
lines changed

5 files changed

+68
-21
lines changed

src/components/common/list/ListItem.vue

+18-3
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,14 @@ const resolvedPoster = computed(() => item?.value?.poster?.value || poster.value
137137
lazy
138138
preview-disabled
139139
:src="resolvedPoster"
140-
:preview-src="resolvedPoster"
140+
:fallback-src="PosterPlaceholder"
141+
/>
142+
<NImage
143+
alt="poster-image-fallback"
144+
class="poster fallback"
145+
lazy
146+
preview-disabled
147+
:src="PosterPlaceholder"
141148
:fallback-src="PosterPlaceholder"
142149
/>
143150
<ListItemPanel :item="item" :loading="loading">
@@ -234,9 +241,17 @@ const resolvedPoster = computed(() => item?.value?.poster?.value || poster.value
234241
235242
.poster {
236243
justify-content: center;
237-
min-width: 5.5rem;
244+
min-width: 5.75rem;
238245
height: 8rem;
239-
background-color: #111;
246+
247+
&.fallback {
248+
position: absolute;
249+
background-color: #111;
250+
}
251+
252+
&:not(.fallback) {
253+
z-index: layers.$in-front;
254+
}
240255
}
241256
}
242257
</style>

src/components/common/list/ListScroll.vue

+1-1
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,7 @@ const onHover = ({ item, hover }: { item: ListScrollItem; hover: boolean }) => {
103103
:item-size="listOptions?.itemSize ?? 145"
104104
:items="items"
105105
:item-resizable="false"
106-
:ignore-item-resize="true"
106+
ignore-item-resize
107107
:visible-items-tag="listOptions?.visibleItemsTag ?? NTimeline"
108108
:visible-items-props="{
109109
size: 'large',

src/components/views/history/HistoryComponent.vue

+23-14
Original file line numberDiff line numberDiff line change
@@ -11,9 +11,10 @@ import type {
1111
import FloatingButton from '~/components/common/buttons/FloatingButton.vue';
1212
import ListScroll from '~/components/common/list/ListScroll.vue';
1313
import { useHistoryStore, useHistoryStoreRefs } from '~/stores/data/history.store';
14-
import { useImageStore } from '~/stores/data/image.store';
14+
import { useImageStore, useImageStoreRefs } from '~/stores/data/image.store';
1515
import { useUserSettingsStoreRefs } from '~/stores/settings/user.store';
1616
import { useI18n } from '~/utils';
17+
import { findClosestMatch } from '~/utils/math.utils';
1718
1819
const { filteredHistory, pagination, loading, pageSize, belowThreshold } =
1920
useHistoryStoreRefs();
@@ -36,15 +37,19 @@ onDeactivated(() => {
3637
3738
onMounted(() => {
3839
watch(user, () => {
39-
if (active.value) {
40-
fetchHistory();
41-
} else {
42-
clearState();
43-
}
40+
if (active.value) fetchHistory();
41+
else clearState();
4442
});
4543
});
4644
4745
const { getImageUrl } = useImageStore();
46+
const { imageSizes } = useImageStoreRefs();
47+
48+
const size = computed(() =>
49+
imageSizes.value?.poster?.length
50+
? findClosestMatch(200, imageSizes.value.poster)
51+
: 'original',
52+
);
4853
4954
const history = computed<ListScrollItem[]>(() => {
5055
const array = filteredHistory.value;
@@ -57,18 +62,22 @@ const history = computed<ListScrollItem[]>(() => {
5762
else if ('season' in _item) _item.type = 'season';
5863
else if ('show' in _item) _item.type = 'show';
5964
60-
if (!_item?.poster && _item.type) {
61-
if (_item?.movie?.ids?.tmdb) {
62-
_item.poster = getImageUrl({
65+
if (!_item?.poster && _item.type && _item?.movie?.ids?.tmdb) {
66+
_item.poster = getImageUrl(
67+
{
6368
id: _item.movie.ids.tmdb,
6469
type: _item.type,
65-
});
66-
} else if (_item?.show?.ids?.tmdb) {
67-
_item.poster = getImageUrl({
70+
},
71+
size.value,
72+
);
73+
} else if (!_item?.poster && _item.type && _item?.show?.ids?.tmdb) {
74+
_item.poster = getImageUrl(
75+
{
6876
id: _item.show.ids.tmdb,
6977
type: 'show',
70-
});
71-
}
78+
},
79+
size.value,
80+
);
7281
}
7382
7483
if (!item.watched_at) return _item;

src/stores/data/image.store.ts

+9-3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,11 @@ export const useImageStore = defineStore('data.image', () => {
3636
episode: {},
3737
});
3838

39+
const imageSizes = computed(() => ({
40+
poster: tmdbConfig.value?.images?.poster_sizes,
41+
still: tmdbConfig.value?.images?.still_sizes,
42+
}));
43+
3944
const syncSaveImageStore = debounce((_images = images) => storage.sync.set(`data.image-store`, _images), 1000);
4045

4146
const syncRestoreImageStore = async (seed?: Partial<ImageStore>) => {
@@ -76,19 +81,20 @@ export const useImageStore = defineStore('data.image', () => {
7681
await syncSaveImageStore();
7782
};
7883

79-
const getImageUrl = ({ id, season, episode, type }: ImageQuery) => {
84+
const getImageUrl = ({ id, season, episode, type }: ImageQuery, size: string = 'original') => {
8085
if (!tmdbConfig.value) throw new Error('TmdbConfiguration not initialized');
8186
const key = [id, season, episode].filter(Boolean).join('-');
8287
const imageRef = ref<string>(images[type][key]);
8388
if (!imageRef.value) fetchImageUrl(key, { id, season, episode, type }).catch(console.error);
89+
8490
return computed(() => {
8591
if (!imageRef.value) return;
8692
if (!tmdbConfig.value?.images?.secure_base_url) return;
87-
return `${tmdbConfig.value.images.secure_base_url}original${imageRef.value}`;
93+
return `${tmdbConfig.value.images.secure_base_url}${size}${imageRef.value}`;
8894
});
8995
};
9096

91-
return { initImageStore, getImageUrl };
97+
return { initImageStore, getImageUrl, imageSizes };
9298
});
9399

94100
export const useImageStoreRefs = () => storeToRefs(useImageStore());

src/utils/math.utils.ts

+17
Original file line numberDiff line numberDiff line change
@@ -12,3 +12,20 @@ export const arrayMax = <T>(array: Array<T>, prop: keyof T, filter?: (item: T) =
1212
}
1313
return prev;
1414
});
15+
16+
export const findClosestMatch = (value: number, array: string[]) => {
17+
let closestMatch = array[0];
18+
let minDifference = Math.abs(value - parseInt(array[0].substring(1), 10));
19+
20+
for (let i = 1; i < array.length; i += 1) {
21+
const currentValue = parseInt(array[i].substring(1), 10);
22+
const difference = Math.abs(value - currentValue);
23+
24+
if (difference < minDifference) {
25+
minDifference = difference;
26+
closestMatch = array[i];
27+
}
28+
}
29+
30+
return closestMatch;
31+
};

0 commit comments

Comments
 (0)