Draft playlist pane on video pages, ensure stable height for playlist thumbs

This commit is contained in:
Simon Repp
2024-03-30 14:40:06 +01:00
parent c7ae38ef78
commit a3907e8a7c
5 changed files with 107 additions and 22 deletions
+5 -4
View File
@@ -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);
}
+21 -7
View File
@@ -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;
}
}
+10 -8
View File
@@ -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#"
<a href="{slug}{index_suffix}">
{video_thumbnail}
<div>{title}</div>
</a>
<div>
<div>{video_thumbnail}</div>
<div>{number} <a href="{slug}{index_suffix}">{label}</a></div>
</div>
"#)
})
.collect::<Vec<String>>()
@@ -74,7 +76,7 @@ pub fn playlist_html(
let videos_rendered = formatdoc!(r#"
<h2>Videos</h2>
<div>
<div class="playlist">
{videos}
</div>
"#);
+1 -1
View File
@@ -62,7 +62,7 @@ pub fn layout(
"#),
ThemeKind::Static(_) => String::new()
};
let body = formatdoc!(r##"
<body>
<div class="center">
+70 -2
View File
@@ -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<Breadcrumb>
) {
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#"
<div class="{current}">
<div>{thumbnail_rendered}</div>
<div>{number} <a href="{href}">{label}</a></div>
</div>
"#);
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#"
<h1>{title}</h1>
{player_rendered}
<p>
{description}
</p>
<div class="playlist context">
{playlist_context}
</div>
<div>
<a href="TODO">Share</a>
</div>