diff --git a/src/build.rs b/src/build.rs index d639101..11da48d 100644 --- a/src/build.rs +++ b/src/build.rs @@ -50,7 +50,7 @@ pub fn perform_build(context: &Context) { match &site.content { SiteContent::Collection(collection) => build_collection(context, collection, &site, &breadcrumbs), SiteContent::Playlist(playlist) => build_playlist(context, playlist, &site, &breadcrumbs), - SiteContent::Video(video) => build_video(context, video, &site, &breadcrumbs), + SiteContent::Video(video) => build_video(context, None, video, &site, &breadcrumbs), SiteContent::Empty => (), SiteContent::Invalid => todo!() } @@ -78,7 +78,7 @@ fn build_collection( } for video in &collection.videos { - build_video(context, video, site, &breadcrumbs_extended); + build_video(context, None, video, site, &breadcrumbs_extended); } collection_html(context, collection, site, &breadcrumbs_extended); @@ -116,12 +116,13 @@ fn build_playlist( playlist_html(context, playlist, site, &breadcrumbs_extended); for video in &playlist.videos { - build_video(context, video, site, &breadcrumbs_extended); + build_video(context, Some(playlist), video, site, &breadcrumbs_extended); } } fn build_video( context: &Context, + playlist: Option<&Playlist>, video: &Video, site: &Site, breadcrumbs: &[Breadcrumb] @@ -177,5 +178,5 @@ fn build_video( } } - video_html(context, video, site, &breadcrumbs_extended); + video_html(context, playlist, video, site, &breadcrumbs_extended); } diff --git a/src/build/assets/styles.css b/src/build/assets/styles.css index c4396ee..8777136 100644 --- a/src/build/assets/styles.css +++ b/src/build/assets/styles.css @@ -20,6 +20,7 @@ video { width: 100%; } .center { margin: 0 auto; max-width: 33rem; + position: relative; } .chart { align-items: center; @@ -48,6 +49,9 @@ video { width: 100%; } left: 50%; transform: translateX(-50%); } +.current { + background-color: var(--c-bg-3); +} .duration { background-color: hsla(0, 0%, 0%, .9); border-radius: .2rem; @@ -78,6 +82,11 @@ img { max-width: 100%; } font-weight: 500; padding: .5rem; } +.playlist > div { + column-gap: 1rem; + display: flex; +} +.playlist.context .thumbnail { height: 5rem; } .savings .bar { background-color: var(--c-green); } .savings_percent { color: var(--c-green); @@ -110,15 +119,11 @@ svg { background-color: var(--c-letterbox); border-radius: 0.4rem; flex-shrink: 0; + height: 9rem; object-fit: contain; - width: 16rem; -} -.thumbnail_wrapper { - position: relative; -} -.thumbnail_wrapper:hover .duration { - opacity: 1; } +.thumbnail_wrapper { position: relative; } +.thumbnail_wrapper:hover .duration { opacity: 1; } .video { color: var(--c-fg-2); display: flex; @@ -134,4 +139,13 @@ svg { display: grid; grid-gap: 1rem; grid-template-columns: 16rem auto; +} + +@media (min-width: 80rem) { + .playlist.context { + left: calc(100% + 2rem); + position: absolute; + top: 6rem; + width: 24rem; + } } \ No newline at end of file diff --git a/src/build/playlist.rs b/src/build/playlist.rs index 3793e48..dfa0c80 100644 --- a/src/build/playlist.rs +++ b/src/build/playlist.rs @@ -55,17 +55,19 @@ pub fn playlist_html( if !playlist.videos.is_empty() { let videos = playlist.videos .iter() - .map(|video| { - let slug = &video.slug(); - let title = video.title.as_deref().unwrap_or_else(|| video.slug()); + .enumerate() + .map(|(index, video)| { + let number = index + 1; + let slug = video.slug(); + let label = video.label(); let video_prefix = format!("{slug}/"); let video_thumbnail = thumbnail(video, &video_prefix); formatdoc!(r#" - - {video_thumbnail} -
{title}
-
+
+
{video_thumbnail}
+
{number} {label}
+
"#) }) .collect::>() @@ -74,7 +76,7 @@ pub fn playlist_html( let videos_rendered = formatdoc!(r#"

Videos

-
+
{videos}
"#); diff --git a/src/build/render.rs b/src/build/render.rs index d4d5e7d..44bcb89 100644 --- a/src/build/render.rs +++ b/src/build/render.rs @@ -62,7 +62,7 @@ pub fn layout( "#), ThemeKind::Static(_) => String::new() }; - + let body = formatdoc!(r##"
diff --git a/src/build/video.rs b/src/build/video.rs index 7ef2412..fc77ffa 100644 --- a/src/build/video.rs +++ b/src/build/video.rs @@ -1,25 +1,93 @@ use std::fs; -use crate::{Context, Site, Video}; +use indoc::formatdoc; + +use crate::{Context, Playlist, Site, Video}; use crate::build::Breadcrumb; -use crate::build::render::{layout, player}; +use crate::build::render::{layout, player, thumbnail}; pub fn video_html( context: &Context, + playlist: Option<&Playlist>, video: &Video, site: &Site, breadcrumbs: &Vec ) { + let index_suffix = context.index_suffix(); let description = if let Some(description) = &video.description { description } else { "" }; let title = video.title.as_deref().unwrap_or(video.slug()); let player_rendered = player(video, ""); + let playlist_context = match playlist { + Some(playlist) => { + let position = playlist.videos + .iter() + .position(|video_iterated| video_iterated.path == video.path) + .unwrap(); + + let mut out = String::new(); + + let adjacent_shown: usize = 2; + + // TODO: Below a certain threshold just show all videos (at least 6 or so) + // TODO: Make the display a bit more compact too so that more videos can fit + // (but also need to determine what to do with different aspect ratios as that changes the visual proportions) + + let previous_videos = position; + if previous_videos > adjacent_shown { + out.push_str(&format!("{} previous videos", previous_videos - adjacent_shown)); + } + + for (index, video_iterated) in playlist.videos.iter().enumerate() { + if (index as i16) < (position as i16) - (adjacent_shown as i16) || index > position + adjacent_shown { continue; } + + let label = video_iterated.label(); + let slug = video_iterated.slug(); + + let video_prefix = if index == position { + String::new() + } else { + format!("../{slug}/") + }; + + let thumbnail_rendered = thumbnail(video_iterated, &video_prefix); + + let number = index + 1; + let (current, href) = if index == position { + ("current", String::new()) + } else { + ("", format!("../{slug}{index_suffix}")) + }; + + let line = formatdoc!(r#" +
+
{thumbnail_rendered}
+
{number} {label}
+
+ "#); + + out.push_str(&line); + } + + let remaining_videos = playlist.videos.len() - position - 1; + if remaining_videos > adjacent_shown { + out.push_str(&format!("{} more videos", remaining_videos - adjacent_shown)); + } + + out + } + None => String::new() + }; + let body = format!(r#"

{title}

{player_rendered}

{description}

+
+ {playlist_context} +
Share