123 lines
3.1 KiB
Vue
123 lines
3.1 KiB
Vue
<template>
|
|
<div class="grid-x large-up-6">
|
|
<div v-for="video in Videos" :key="video.ID" class="cell">
|
|
<div class="card ytcard">
|
|
<a :href="video.URL"><img :src="video.Thumbnail"></a>
|
|
<div class="card-section description">
|
|
<div class="descriptiontitle">{{ video.Title }}</div>
|
|
<div class="descriptionchannel">{{ video.Channel }}</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div >
|
|
</template>
|
|
|
|
<script lang="ts">
|
|
import Vue from "vue";
|
|
import Axios from "axios";
|
|
|
|
// Wrapper for videos returned from our server.
|
|
class Video {
|
|
// Title of the video according to youtube.
|
|
public Title: string;
|
|
|
|
// Description of video according to youtube.
|
|
public Description: string;
|
|
|
|
// Youtube ID
|
|
public ID: string;
|
|
|
|
// Thumbnail
|
|
public Thumbnail: string;
|
|
|
|
// What channel made this video.
|
|
public Channel: string;
|
|
|
|
// Duration of the video in seconds.
|
|
public Seconds: number;
|
|
|
|
// Tags relevant to the video.
|
|
public Tags: Array<string>;
|
|
|
|
// Youtube URL of the video.
|
|
public URL: string;
|
|
|
|
// Popuplate this using data from our server.
|
|
constructor(v: any){
|
|
this.Title = v.title;
|
|
this.Description = v.description;
|
|
this.ID = v.id;
|
|
this.Thumbnail = v.thumbnail;
|
|
this.Channel = v.channel;
|
|
this.Seconds = v.seconds;
|
|
this.Tags = v.tags;
|
|
this.URL = "https://www.youtube.com/watch?v=" + v.id;
|
|
}
|
|
}
|
|
|
|
async function get_videos(): Promise<Array<Video>> {
|
|
// How many chars at most for the description.
|
|
const maxcharsdescriptionfield = 100;
|
|
|
|
// Temporary holder for videos.
|
|
let Videos : Array<Video> = [];
|
|
|
|
// Ask server for videos.
|
|
let resp = await Axios.get('http://localhost:62214/api/Videos').catch(e => console.log(e));
|
|
|
|
// Handle all our nulls.
|
|
if (resp == null || resp.data == null)
|
|
console.log("server /api/videos return is null");
|
|
else {
|
|
// Parse our videos.
|
|
resp.data.forEach((v: any) => {
|
|
// Trim description if needed.
|
|
if (v.description.length > maxcharsdescriptionfield) {
|
|
v.description = v.description.substring(0, maxcharsdescriptionfield) + " ...";
|
|
}
|
|
|
|
// Add it to our array
|
|
Videos.push(new Video(v));
|
|
});
|
|
}
|
|
|
|
// Send back the resulting videos.
|
|
return Promise.resolve(Videos);
|
|
}
|
|
|
|
// Vue class for keeping state of the videos.
|
|
export default Vue.extend({
|
|
data() {
|
|
return {
|
|
Videos: Array<Video>()
|
|
}
|
|
},
|
|
|
|
// Ugh, vue doesn't have async support for computed, wow ...
|
|
mounted() { get_videos().then(e => this.Videos = e ) }
|
|
});
|
|
</script>
|
|
|
|
<style scoped>
|
|
.ytcard {
|
|
border-bottom-left-radius: 10px;
|
|
border-bottom-right-radius: 10px;
|
|
background-color:#ddd9d4;
|
|
margin: 6px 2px 6px;
|
|
}
|
|
|
|
.description {
|
|
padding: 7px 5px 7px;
|
|
}
|
|
|
|
.descriptiontitle {
|
|
font-size: 14px;
|
|
padding-bottom:10px;
|
|
}
|
|
|
|
.descriptionchannel {
|
|
font-size: 10px;
|
|
text-align: right;
|
|
}
|
|
</style>
|