Skip to content

Commit c296dca

Browse files
committed
feat(ratings): adds score & review options
1 parent 061153d commit c296dca

18 files changed

+427
-34
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@
5454
"@dvcol/base-http-client": "^1.10.0",
5555
"@dvcol/common-utils": "^1.4.0",
5656
"@dvcol/tmdb-http-client": "^1.2.3",
57-
"@dvcol/trakt-http-client": "^1.4.3",
57+
"@dvcol/trakt-http-client": "^1.4.5",
5858
"@dvcol/tvdb-http-client": "^1.1.3",
5959
"@dvcol/web-extension-utils": "^3.0.1",
6060
"@vue/devtools": "^7.0.15",

pnpm-lock.yaml

+5-5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/components/common/typography/TextField.vue

+18-3
Original file line numberDiff line numberDiff line change
@@ -62,10 +62,15 @@ defineProps({
6262
default: 'baseline',
6363
},
6464
size: {
65-
type: String,
65+
type: String as PropType<'small' | 'medium' | 'large'>,
6666
required: false,
6767
default: 'medium',
6868
},
69+
disabled: {
70+
type: Boolean,
71+
required: false,
72+
default: false,
73+
},
6974
});
7075
7176
const { openTab } = useLinksStore();
@@ -74,14 +79,16 @@ const { openTab } = useLinksStore();
7479
<template>
7580
<NFlex
7681
class="detail"
77-
:class="{ grow, array }"
82+
:class="{ grow, array, disabled }"
7883
:style="{ '--prefix-min-width': labelWidth, '--text-flex': flex }"
7984
:align="align"
8085
:wrap="wrap"
8186
:vertical="vertical"
8287
:size="size"
8388
>
84-
<span class="prefix">{{ label }}</span>
89+
<slot name="label">
90+
<span class="prefix">{{ label }}</span>
91+
</slot>
8592
<slot>
8693
<NFlex v-if="array" class="value">
8794
<template v-if="values !== undefined">
@@ -109,6 +116,7 @@ const { openTab } = useLinksStore();
109116
<style lang="scss" scoped>
110117
.prefix {
111118
flex: 0 0 auto;
119+
align-self: center;
112120
min-width: var(--prefix-min-width);
113121
color: var(--white-50);
114122
font-weight: 600;
@@ -117,9 +125,16 @@ const { openTab } = useLinksStore();
117125
118126
.value {
119127
flex: 1 1 auto;
128+
align-self: center;
120129
min-width: max-content;
121130
}
122131
132+
.disabled {
133+
.value {
134+
color: var(--text-color-disabled);
135+
}
136+
}
137+
123138
.detail {
124139
flex: var(--text-flex);
125140
align-items: baseline;

src/components/views/panel/MoviePanel.vue

+19-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<script setup lang="ts">
22
import { deCapitalise } from '@dvcol/common-utils/common/string';
3+
4+
import { TraktRatingType } from '@dvcol/trakt-http-client/models';
35
import { NFlex, NSkeleton } from 'naive-ui';
46
import { computed, onMounted, toRefs, watch } from 'vue';
57
@@ -26,6 +28,7 @@ import {
2628
useListStore,
2729
} from '~/stores/data/list.store';
2830
import { useMovieStore, useMovieStoreRefs } from '~/stores/data/movie.store';
31+
import { useRatingsStore } from '~/stores/data/ratings.store';
2932
import { useWatchingStore, useWatchingStoreRefs } from '~/stores/data/watching.store';
3033
import { useExtensionSettingsStoreRefs } from '~/stores/settings/extension.store';
3134
import { useLinksStore } from '~/stores/settings/links.store';
@@ -94,7 +97,7 @@ const {
9497
fetchAll,
9598
} = useListStore();
9699
97-
const { loadLists, loadListsPageSize } = useExtensionSettingsStoreRefs();
100+
const { loadLists, loadListsPageSize, enableRatings } = useExtensionSettingsStoreRefs();
98101
99102
const shouldFetchLists = computed(() => {
100103
if (!myLists.value?.length) return false;
@@ -248,11 +251,19 @@ const onCheckin = async (cancel: boolean) => {
248251
249252
const { openTab } = useLinksStore();
250253
254+
const { loadRatings, getRatings } = useRatingsStore();
255+
256+
const score = computed(() => {
257+
if (!movieId.value) return;
258+
return getRatings(TraktRatingType.Movies, movieId.value);
259+
});
260+
251261
onMounted(() => {
252262
watch(
253263
movieId,
254264
id => {
255265
fetchMovie(id);
266+
if (enableRatings.value) loadRatings(TraktRatingType.Movies, id);
256267
},
257268
{ immediate: true },
258269
);
@@ -290,9 +301,10 @@ onMounted(() => {
290301
round
291302
/>
292303

293-
<NFlex>
304+
<NFlex class="rating-row" justify="space-around">
305+
<PanelRatings v-if="enableRatings" :votes="movie?.votes" :rating="movie?.rating" />
294306
<PanelPoster :tmdb="movie?.ids.tmdb" mode="movie" />
295-
<PanelRatings :votes="movie?.votes" :rating="movie?.rating" />
307+
<PanelRatings v-if="enableRatings" :score="score?.rating" mode="score" />
296308
</NFlex>
297309

298310
<MoviePanelDetails
@@ -323,6 +335,10 @@ onMounted(() => {
323335
</template>
324336

325337
<style lang="scss" scoped>
338+
.rating-row {
339+
width: 100%;
340+
}
341+
326342
.show-title-skeleton {
327343
height: 1.5rem;
328344
margin-top: 0.625rem;

src/components/views/panel/PanelRatings.vue

+81-13
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,29 @@
11
<script lang="ts" setup>
22
import { NFlex, NNumberAnimation, NProgress, NStatistic } from 'naive-ui';
3-
import { computed, onMounted, ref, toRefs, watch } from 'vue';
3+
import { computed, onMounted, type PropType, ref, toRefs, watch } from 'vue';
44
55
import TextField from '~/components/common/typography/TextField.vue';
6+
import { RatingLabel } from '~/models/rating.model';
7+
import { logger } from '~/stores/settings/log.store';
68
import { useI18n } from '~/utils/i18n.utils';
79
810
const props = defineProps({
11+
mode: {
12+
type: String as PropType<'rating' | 'score'>,
13+
required: false,
14+
default: 'rating',
15+
},
916
rating: {
1017
type: Number,
1118
required: false,
12-
default: 0,
1319
},
1420
votes: {
1521
type: Number,
1622
required: false,
17-
default: 0,
1823
},
1924
score: {
2025
type: Number,
2126
required: false,
22-
default: 0,
2327
},
2428
duration: {
2529
type: Number,
@@ -38,6 +42,7 @@ const i18n = useI18n('panel', 'ratings');
3842
const { votes, rating, score } = toRefs(props);
3943
4044
const votesUnit = computed(() => {
45+
if (votes?.value === undefined) return null;
4146
if (votes?.value >= 10000) return 'k';
4247
if (votes?.value >= 1000000) return 'm';
4348
if (votes?.value >= 1000000000) return 'b';
@@ -57,6 +62,16 @@ const _ratingProgress = ref(0);
5762
const _score = computed(() => (score?.value ?? 0) * 10);
5863
const _scoreProgress = ref(0);
5964
65+
const _scoreLabel = computed(() => {
66+
if (!score?.value) return 'not_rated';
67+
try {
68+
return RatingLabel[score.value];
69+
} catch (e) {
70+
logger.error('RatingLabel', e);
71+
return 'not_rated';
72+
}
73+
});
74+
6075
onMounted(() => {
6176
watch(
6277
_rating,
@@ -76,9 +91,17 @@ onMounted(() => {
7691
</script>
7792

7893
<template>
79-
<NFlex class="rating-container" align="center" justify="center" vertical>
80-
<TextField :label="i18n('label_votes')" vertical size="small" flex="0 1 auto">
81-
<NStatistic class="statistics" tabular-nums>
94+
<NFlex class="rating-container" align="center" justify="center" vertical size="large">
95+
<!-- Vote count -->
96+
<TextField
97+
v-if="mode === 'rating'"
98+
:label="i18n('label_votes')"
99+
:disabled="!votes"
100+
vertical
101+
size="small"
102+
flex="0 1 auto"
103+
>
104+
<NStatistic class="statistics" :class="{ disabled: !votes }" tabular-nums>
82105
<NNumberAnimation
83106
:from="0"
84107
:to="_votes"
@@ -88,14 +111,21 @@ onMounted(() => {
88111
<span v-if="votesUnit" class="unit">{{ votesUnit }}</span>
89112
</NStatistic>
90113
</TextField>
91-
<TextField :label="i18n('label_rating')" vertical flex="0 1 auto">
114+
115+
<!-- Rating progress -->
116+
<TextField
117+
v-if="mode === 'rating'"
118+
:label="i18n('label_rating')"
119+
vertical
120+
flex="0 1 auto"
121+
>
92122
<NProgress
93123
class="progress"
94124
type="circle"
95125
:percentage="_ratingProgress"
96126
:style="{ '--duration': `${duration}ms` }"
97127
>
98-
<NStatistic class="statistics" tabular-nums>
128+
<NStatistic class="statistics" :class="{ disabled: !rating }" tabular-nums>
99129
<NNumberAnimation
100130
:from="0"
101131
:to="_rating"
@@ -105,17 +135,38 @@ onMounted(() => {
105135
</NStatistic>
106136
</NProgress>
107137
</TextField>
108-
<TextField :label="i18n('label_score')" vertical flex="0 1 auto">
138+
139+
<!-- Review -->
140+
<TextField
141+
v-if="mode === 'score'"
142+
:label="i18n('label_review')"
143+
:disabled="!score"
144+
vertical
145+
size="small"
146+
flex="0 1 auto"
147+
>
148+
<span class="score-label" :class="{ disabled: !score }">
149+
{{ i18n(_scoreLabel, 'common', 'rating') }}
150+
</span>
151+
</TextField>
152+
153+
<!-- Score -->
154+
<TextField
155+
v-if="mode === 'score'"
156+
:label="i18n('label_score')"
157+
vertical
158+
flex="0 1 auto"
159+
>
109160
<NProgress
110161
class="progress"
111162
type="circle"
112163
:percentage="_scoreProgress"
113164
:style="{ '--duration': `${duration}ms` }"
114165
>
115-
<NStatistic class="statistics" tabular-nums>
166+
<NStatistic class="statistics" :class="{ disabled: !score }" tabular-nums>
116167
<NNumberAnimation
117168
:from="0"
118-
:to="_pStores"
169+
:to="_score"
119170
:duration="duration"
120171
:precision="precision"
121172
/>
@@ -130,7 +181,7 @@ onMounted(() => {
130181
--duration: 1000ms;
131182
132183
gap: 1rem;
133-
padding: 1rem;
184+
padding: 0.5rem;
134185
135186
.progress {
136187
width: 3rem;
@@ -153,6 +204,23 @@ onMounted(() => {
153204
padding-left: 0.125rem;
154205
color: var(--white-50);
155206
}
207+
208+
&.disabled {
209+
--n-value-text-color: var(--text-color-disabled) !important;
210+
}
211+
}
212+
213+
.score-label {
214+
align-self: center;
215+
padding: 0.25rem 0;
216+
217+
&.disabled {
218+
color: var(--text-color-disabled);
219+
}
220+
}
221+
222+
@media (width <= 640px) {
223+
padding: 0.5rem 25%;
156224
}
157225
}
158226
</style>

0 commit comments

Comments
 (0)