add Vue UI [wip]
This commit is contained in:
parent
3d5656392e
commit
b47dfc579b
22 changed files with 2242 additions and 6 deletions
114
unwind-ui/src/components/MovieList.vue
Normal file
114
unwind-ui/src/components/MovieList.vue
Normal file
|
|
@ -0,0 +1,114 @@
|
|||
<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" :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)">{{ imdb_rating(item.imdb_score) }}</span>
|
||||
<span class="score tag is-info is-large" title="User rating (1-10)">{{ imdb_rating(item.user_score) }}</span>
|
||||
</td>
|
||||
<td>
|
||||
<span>{{ duration(item.runtime) }}</span>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<div ref="sentinel"></div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue"
|
||||
|
||||
function imdb_rating(score) {
|
||||
if (score == null) {
|
||||
return "-"
|
||||
}
|
||||
|
||||
const deci = Math.round((score * 9) / 10 + 10)
|
||||
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: {
|
||||
imdb_rating,
|
||||
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>
|
||||
73
unwind-ui/src/components/UserLogin.vue
Normal file
73
unwind-ui/src/components/UserLogin.vue
Normal file
|
|
@ -0,0 +1,73 @@
|
|||
<template>
|
||||
<div class="field is-grouped">
|
||||
<p class="control has-icons-left">
|
||||
<input
|
||||
class="input is-small"
|
||||
type="text"
|
||||
placeholder="User ID"
|
||||
v-model="user_id"
|
||||
@change="active = true"
|
||||
/>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-user"></i>
|
||||
</span>
|
||||
</p>
|
||||
<p class="control has-icons-left">
|
||||
<input
|
||||
class="input is-small"
|
||||
type="password"
|
||||
placeholder="Secret"
|
||||
v-model="secret"
|
||||
@change="active = true"
|
||||
/>
|
||||
<span class="icon is-small is-left">
|
||||
<i class="fas fa-lock"></i>
|
||||
</span>
|
||||
</p>
|
||||
<p class="control">
|
||||
<button
|
||||
class="button is-primary is-small"
|
||||
:disabled="!active"
|
||||
@click="login"
|
||||
>
|
||||
Login
|
||||
</button>
|
||||
</p>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from "vue"
|
||||
|
||||
export default defineComponent({
|
||||
data: () => ({
|
||||
user_id: window.localStorage.user_id || "",
|
||||
secret: window.localStorage.secret || "",
|
||||
active: true,
|
||||
}),
|
||||
emits: ["login"],
|
||||
mounted() {
|
||||
const { user_id, secret } = this
|
||||
if (user_id && secret) {
|
||||
this.login()
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
login() {
|
||||
const { user_id, secret } = this
|
||||
this.$emit("login", { user_id, secret })
|
||||
this.active = false
|
||||
},
|
||||
},
|
||||
watch: {
|
||||
user_id(newval) {
|
||||
window.localStorage.user_id = newval
|
||||
},
|
||||
secret(newval) {
|
||||
window.localStorage.secret = newval
|
||||
},
|
||||
},
|
||||
})
|
||||
</script>
|
||||
|
||||
<style scoped></style>
|
||||
Loading…
Add table
Add a link
Reference in a new issue