Added image loaders
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
<script lang="ts">
|
||||
import { onMount } from 'svelte';
|
||||
import type { Video, VideoBase } from './Api/model';
|
||||
import { truncate } from './misc';
|
||||
|
||||
@@ -11,6 +12,24 @@
|
||||
|
||||
return `${hours}:${minutes}:${seconds}`;
|
||||
}
|
||||
|
||||
let loading = true;
|
||||
let loaded = false;
|
||||
let failed = false;
|
||||
|
||||
onMount(() => {
|
||||
const img = new Image();
|
||||
img.src = video.videoThumbnails[3].url;
|
||||
|
||||
img.onload = () => {
|
||||
loading = false;
|
||||
loaded = true;
|
||||
};
|
||||
img.onerror = () => {
|
||||
loading = false;
|
||||
failed = true;
|
||||
};
|
||||
});
|
||||
</script>
|
||||
|
||||
<article class="no-padding transparent">
|
||||
@@ -18,12 +37,19 @@
|
||||
class="wave"
|
||||
style="width: 100%; height: 155px; overflow: hidden;"
|
||||
href={`/watch/${video.videoId}`}
|
||||
><img
|
||||
class="responsive"
|
||||
style="object-fit: crop;"
|
||||
src={video.videoThumbnails[3].url}
|
||||
alt="Thumbnail for video"
|
||||
/>
|
||||
>
|
||||
{#if loading}
|
||||
<progress class="circle"></progress>
|
||||
{:else if loaded}
|
||||
<img
|
||||
class="responsive"
|
||||
style="object-fit: crop;"
|
||||
src={video.videoThumbnails[3].url}
|
||||
alt="Thumbnail for video"
|
||||
/>
|
||||
{:else}
|
||||
<p>Failed to load image</p>
|
||||
{/if}
|
||||
{#if !('liveVideo' in video) || !video.liveVideo}
|
||||
<div class="absolute right bottom small-margin black white-text small-text">
|
||||
{videoLength(video.lengthSeconds)}
|
||||
@@ -40,7 +66,7 @@
|
||||
<div class="small-padding">
|
||||
<nav>
|
||||
<div class="max">
|
||||
<div class="bold">{truncate(video.title)}</div>
|
||||
<a href={`/watch/${video.videoId}`}><div class="bold">{truncate(video.title)}</div></a>
|
||||
<div>
|
||||
{video.author}{#if !('publishedText' in video)}
|
||||
• {video.viewCountText}{/if}
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
export function truncate(value: string, maxLength: number = 50): string {
|
||||
return value.length > maxLength ? `${value.substring(0, maxLength)}...` : value;
|
||||
}
|
||||
|
||||
export function numberWithCommas(number: number) {
|
||||
return number.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
export const ssr = false;
|
||||
@@ -1,7 +1,5 @@
|
||||
<script lang="ts">
|
||||
import Logo from '$lib/Logo.svelte';
|
||||
import 'beercss';
|
||||
import 'material-dynamic-colors';
|
||||
|
||||
const pages = [
|
||||
{
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
import 'beercss/dist/cdn/beer.min.css';
|
||||
import 'material-dynamic-colors';
|
||||
|
||||
@@ -1,22 +1,15 @@
|
||||
<script lang="ts">
|
||||
import { getTrending } from '$lib/Api';
|
||||
import type { Video } from '$lib/Api/model';
|
||||
import PageLoading from '$lib/PageLoading.svelte';
|
||||
import Thumbnail from '$lib/Thumbnail.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
|
||||
let trending: Video[];
|
||||
|
||||
onMount(async () => {
|
||||
trending = await getTrending();
|
||||
});
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
{#if trending}
|
||||
{#if data.trending}
|
||||
<div class="page right active">
|
||||
<div class="space"></div>
|
||||
<div class="grid">
|
||||
{#each trending as video}
|
||||
{#each data.trending as video}
|
||||
<div class="s12 m6 l2">
|
||||
<Thumbnail {video} />
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { getTrending } from '$lib/Api/index.js';
|
||||
|
||||
export async function load({ params }) {
|
||||
return { trending: await getTrending() };
|
||||
}
|
||||
@@ -1,30 +1,21 @@
|
||||
<script lang="ts">
|
||||
import { page } from '$app/stores';
|
||||
import { getVideo } from '$lib/Api';
|
||||
import type { VideoPlay } from '$lib/Api/model';
|
||||
import PageLoading from '$lib/PageLoading.svelte';
|
||||
import Thumbnail from '$lib/Thumbnail.svelte';
|
||||
import { onMount } from 'svelte';
|
||||
import { numberWithCommas } from '$lib/misc.js';
|
||||
|
||||
let video: VideoPlay;
|
||||
|
||||
onMount(async () => {
|
||||
video = await getVideo($page.params.slug);
|
||||
});
|
||||
export let data;
|
||||
</script>
|
||||
|
||||
{#if video}
|
||||
<div class="grid large-margin">
|
||||
<div class="s12 m10 l10">
|
||||
<h5>{video.title}</h5>
|
||||
<p style="white-space: pre-line">{video.description}</p>
|
||||
</div>
|
||||
<div class="m4 l2">
|
||||
{#each video.recommendedVideos as recommendedVideo}
|
||||
<Thumbnail video={recommendedVideo} />
|
||||
{/each}
|
||||
</div>
|
||||
<div class="grid large-margin">
|
||||
<div class="s12 m10 l10">
|
||||
<h5>{data.video.title}</h5>
|
||||
<article>
|
||||
<p>{numberWithCommas(data.video.viewCount)} views • {data.video.publishedText}</p>
|
||||
<p style="white-space: pre-line">{data.video.description}</p>
|
||||
</article>
|
||||
</div>
|
||||
{:else}
|
||||
<PageLoading />
|
||||
{/if}
|
||||
<div class="m4 l2">
|
||||
{#each data.video.recommendedVideos as recommendedVideo}
|
||||
<Thumbnail video={recommendedVideo} />
|
||||
{/each}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { getVideo } from '$lib/Api/index.js';
|
||||
|
||||
export async function load({ params }) {
|
||||
return { video: await getVideo(params.slug) };
|
||||
};
|
||||
Reference in New Issue
Block a user