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