This is the template project that's checked out and configured when you run the bando-up command from ljsthw-bandolier. This is where the code really lives.
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.
bandolier-template/rendered/pages/live/[slug]/index.svelte

219 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>