You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
218 lines
6.6 KiB
218 lines
6.6 KiB
<script context="module">
|
|
import live from "$/rendered/pages/live/index.js";
|
|
let past_streams = [];
|
|
|
|
export const getPaths = async () => {
|
|
past_streams = await live.load_paths();
|
|
return past_streams;
|
|
}
|
|
|
|
export const getData = stream => ({
|
|
slug: stream.slug, stream
|
|
});
|
|
</script>
|
|
|
|
<script>
|
|
import SEOTricks from "$/client/components/SEOTricks.svelte";
|
|
import { base_host, twitter_user } from "$/client/config.js";
|
|
import HLSVideo from "$/client/components/HLSVideo.svelte";
|
|
import WTVideo from "$/client/components/WTVideo.svelte";
|
|
import Icon from "$/client/components/Icon.svelte";
|
|
import IconImage from "$/client/components/IconImage.svelte";
|
|
import Layout from '$/rendered/Layout.svelte';
|
|
import Markdown from "$/client/components/Markdown.svelte";
|
|
import parseISO from "date-fns/parseISO";
|
|
import formatDistanceToNow from "date-fns/formatDistanceToNow";
|
|
import SnapImage from "$/client/components/SnapImage.svelte";
|
|
import { Hydrate } from '@jamcart/7ty/components';
|
|
import ShareButton from "$/client/components/ShareButton.svelte";
|
|
|
|
export let stream;
|
|
export let slug;
|
|
|
|
let og = {
|
|
"title": stream.title, // title of the article
|
|
"description": stream.description, // description for inside preview
|
|
"url": `${ base_host }/live/${ stream.slug }/`, // URL to article
|
|
"type": "website", // not mentioned on linked in but needed
|
|
}
|
|
|
|
let twitter = {
|
|
"card": "summary", // must be summary, summary_large_image, app, player
|
|
"creator": twitter_user, // @username of content creator
|
|
"description": og.description, // max 200 chars
|
|
"site": "@lzsthw", // @username of site
|
|
"title": og.title,
|
|
}
|
|
|
|
const show_free_archived = (stream) => {
|
|
// NOTE: this is different from the client/pages/Live.svelte since it's public
|
|
return stream.state === "archived" && stream.is_free;
|
|
}
|
|
|
|
if(stream.poster) {
|
|
og.image = `${base_host}/${stream.image}`;
|
|
twitter.image = og.image;
|
|
}
|
|
</script>
|
|
|
|
<SEOTricks og={ og } twitter={ twitter } />
|
|
|
|
<style>
|
|
container {
|
|
padding-top: var(--fixed-header-height);
|
|
display: flex;
|
|
flex-direction: row;
|
|
width: 100%;
|
|
}
|
|
|
|
container > left {
|
|
width: 100%;
|
|
max-height: calc(100vh - var(--fixed-header-height));
|
|
overflow-y: auto;
|
|
-ms-overflow-style: none; /* IE and Edge */
|
|
scrollbar-width: none; /* Firefox */
|
|
}
|
|
|
|
/* This combined with the -ms-overflow-style and scrollbar-width is how you remove
|
|
the scrolls on the inner video/notes column.
|
|
*/
|
|
container > left::-webkit-scrollbar {
|
|
display: none;
|
|
}
|
|
|
|
container > left notes {
|
|
display: flex;
|
|
flex-direction: column;
|
|
padding-left: 1rem;
|
|
padding-right: 1rem;
|
|
}
|
|
|
|
container > waiting {
|
|
display:flex;
|
|
width: 100%;
|
|
min-height: calc(100vh - var(--fixed-header-height));
|
|
justify-content: center;
|
|
align-items: center;
|
|
}
|
|
|
|
container > right {
|
|
min-width: 400px;
|
|
max-width: 400px;
|
|
height: calc(100vh - var(--fixed-header-height));
|
|
border-left: 1px solid var(--value7);
|
|
padding-left: 0.5rem;
|
|
min-height: calc(100vh - var(--fixed-header-height));
|
|
max-height: calc(100vh - var(--fixed-header-height));
|
|
overflow-y: auto;
|
|
}
|
|
|
|
container > right card {
|
|
border: unset;
|
|
box-shadow: unset;
|
|
}
|
|
|
|
container > right card middle {
|
|
margin-bottom: 0.3rem;
|
|
}
|
|
|
|
@media only screen and (max-width: 800px) {
|
|
right {
|
|
display: none;
|
|
}
|
|
}
|
|
</style>
|
|
|
|
<Layout centered={ true } fullwidth={ true } fixed={ true } footer={ false }>
|
|
<container>
|
|
<left>
|
|
{#if stream.state === "live"}
|
|
<Hydrate component={ HLSVideo } props={ { poster: stream.poster, source: stream.source } } />
|
|
{:else if stream.state === "archived" }
|
|
{#if show_free_archived(stream)}
|
|
<Hydrate component={ WTVideo } props={ { media: stream.media } } />
|
|
{:else}
|
|
<IconImage name="film" />
|
|
{/if}
|
|
{:else if stream.state === "finished"}
|
|
<IconImage name="video-off" />
|
|
{:else if stream.state === "pending"}
|
|
<IconImage name="clock" />
|
|
{:else}
|
|
<IconImage name="video" />
|
|
{/if}
|
|
|
|
<info>
|
|
<tile>
|
|
<left>
|
|
<Icon name="user" size="48" />
|
|
</left>
|
|
<middle>
|
|
<b>Zed A. Shaw</b>
|
|
<span>{ stream.title }</span>
|
|
</middle>
|
|
<right>
|
|
<Hydrate component={ ShareButton } props={
|
|
{ url: `/live/${stream.slug}` }
|
|
} />
|
|
</right>
|
|
</tile>
|
|
</info>
|
|
|
|
<notes>
|
|
<Markdown content={ stream.description } />
|
|
<br>
|
|
{#if stream.state === "pending"}
|
|
<callout class="info">
|
|
<span>
|
|
This live stream starts at <b>{ stream.starts_on }</b>.
|
|
Come back then, and hit refresh.
|
|
</span>
|
|
</callout>
|
|
{:else if stream.state === "ready"}
|
|
<callout class="info">
|
|
<span>
|
|
The show is about to start. Your page might refresh when it does, but if the video doesn't start on its own hit refresh.
|
|
</span>
|
|
</callout>
|
|
{:else if stream.state === "finished"}
|
|
<callout class="info">
|
|
<span>
|
|
This live stream has ended. It will be posted for later viewing after editing, probably in a few days.
|
|
</span>
|
|
</callout>
|
|
{:else if !show_free_archived(stream) }
|
|
<callout class="info">
|
|
<span>
|
|
This live stream is for members only. If you want to learn JavaScript, then <a style="color: var(--value0)" href="/client/#/register">register today</a> and enjoy all livestreams plus all modules.
|
|
</span>
|
|
</callout>
|
|
{/if}
|
|
</notes>
|
|
</left>
|
|
|
|
{#if past_streams}
|
|
<right>
|
|
{#each past_streams as archived}
|
|
{#if archived.id !== stream.id}
|
|
<card>
|
|
<top>
|
|
<a href="/client/#/live/{ archived.id }/">
|
|
{#if archived.poster}
|
|
<Hydrate component={SnapImage} props={ {src: archived.poster } } />
|
|
{:else}
|
|
<IconImage name="video" />
|
|
{/if}
|
|
</a>
|
|
</top>
|
|
<middle>
|
|
<b>{ archived.title }</b>
|
|
<div>{ formatDistanceToNow(parseISO(archived.starts_on), {addSuffix: true}) }</div>
|
|
</middle>
|
|
</card>
|
|
{/if}
|
|
{/each}
|
|
</right>
|
|
{/if}
|
|
</container>
|
|
</Layout>
|
|
|