unwind/unwind-ui/src/components/MovieList.vue
2021-08-05 19:18:52 +02:00

138 lines
3 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<template>
<table class="table is-fullwidth is-striped">
<thead>
<tr>
<th>title</th>
<th>year</th>
<th>type</th>
<th>rating</th>
<th>runtime</th>
</tr>
</thead>
<tbody>
<tr v-for="item in items" :key="item.id" :data-unwind-id="item.id">
<td v-if="item.original_title">
<a :href="`https://www.imdb.com/title/${item.imdb_id}/`">
<span>{{ item.original_title }}</span>
</a>
<span v-if="item.title != item.original_title"> ({{ item.title }})</span>
</td>
<td v-else>
<a :href="`https://www.imdb.com/title/${item.imdb_id}/`">
<span>{{ item.title }}</span>
</a>
</td>
<td>
<span class="year">{{ item.release_year }}</span>
</td>
<td>
<span class="mediatype">{{ item.media_type }}</span>
</td>
<td>
<span
class="score imdb-score tag is-large"
:title="`IMDb rating (1-10) / ${item.imdb_votes} votes`"
>{{ imdb_rating(item.imdb_score) }}</span
>
<span
class="score tag is-info is-large"
:title="`User rating (1-10) / ${
item.user_scores.length
} votes / σ = ${imdb_stdev(item.user_scores)}`"
>{{ avg_imdb_rating(item.user_scores) }}</span
>
</td>
<td>
<span>{{ duration(item.runtime) }}</span>
</td>
</tr>
</tbody>
</table>
<div ref="sentinel"></div>
</template>
<script lang="ts">
import { defineComponent } from "vue"
import { mean, pstdev } from "../utils.ts"
function avg_imdb_rating(scores) {
return imdb_rating(scores.length === 0 ? null : mean(scores))
}
function imdb_stdev(scores) {
return pstdev(scores.map(imdb_rating_from_score))
}
function imdb_rating_from_score(score) {
return Math.round((score * 9) / 10 + 10) / 10
}
function imdb_rating(score) {
if (score == null) {
return "-"
}
const deci = 10 * imdb_rating_from_score(score)
return `${(deci / 10) | 0}.${deci % 10}`
}
function duration(minutes_total) {
if (minutes_total == null) {
return "-"
}
const m = minutes_total % 60
const h = (minutes_total / 60) | 0
return `${h} h ${m} m`
}
export default defineComponent({
props: {
items: {
type: Array,
required: true,
},
},
emits: ["reach-bottom"],
mounted() {
const options = {
rootMargin: "500px",
}
const observer = new IntersectionObserver(([e]) => {
if (!e.isIntersecting) {
return
}
this.$emit("reach-bottom")
}, options)
observer.observe(this.$refs.sentinel)
},
methods: {
avg_imdb_rating,
imdb_rating,
imdb_stdev,
duration,
},
})
</script>
<style scoped>
.year {
color: grey;
}
.mediatype {
color: grey;
}
.score {
width: 2em;
height: 2em;
}
.score + .score {
margin-left: 1em;
}
.imdb-score {
background-color: rgb(245, 197, 24);
}
.user-score {
}
</style>