diff --git a/src/build/assets/site.css b/src/build/assets/site.css index dc40137..8d5c258 100644 --- a/src/build/assets/site.css +++ b/src/build/assets/site.css @@ -14,6 +14,7 @@ a:hover { color: var(--fg-3); } cursor: pointer; display: flex; padding: .3rem .6rem .3rem .5rem; + white-space: nowrap; } .actions a:focus-visible, .actions a:hover, @@ -62,6 +63,17 @@ button { text-underline-offset: .3rem; } .center .description a:hover { text-decoration: none; } +.context_dot { + border-radius: 50%; + display: block; + height: 1rem; + width: 1rem; +} +.context_dot:focus-visible, +.context_dot:hover { + box-shadow: 0 0 .15rem var(--mg); +} +.context_dot + .context_dot { margin-left: .3rem; } #copy-link::after { color: var(--fg-2); padding-left: .5rem; @@ -93,12 +105,13 @@ button { } .flex { display: flex; } .flex.align { align-items: center; } +.flex.align_start { align-items: flex-start; } .flex.apart { justify-content: space-between; } .flex.space { column-gap: .3rem; } +.flex.wrap { flex-wrap: wrap; } footer { align-items: center; background: var(--bg-1); - box-sizing: border-box; display: flex; font-size: .9rem; flex-wrap: wrap; @@ -191,34 +204,25 @@ img { padding: .5rem; } .medium_font { font-size: 1.2rem; } -/*.outline { +.parent_context { + display: flex; + flex-wrap: wrap; + font-size: .9rem; + gap: .3rem; + margin-bottom: .2rem; +} +.parent_context a:not(.context_dot) { + align-items: center; + column-gap: .3rem; + display: flex; +} +.parent_context > div { + align-items: flex-end; display: flex; flex-direction: column; - row-gap: 1rem; + gap: .3rem; } -.outline > a { - border: 1px solid var(--bg-2); - border-radius: .6rem; - position: relative; -} -.outline > a > img, -.outline > a > .placeholder { - border-radius: .6rem; -} -.outline > a > .placeholder { - background: var(--bg-2); - height: 12rem; -} -.outline .text { - background: var(--bg-1-85); - border-bottom-left-radius: .6rem; - border-bottom-right-radius: .6rem; - bottom: 0; - left: 0; - padding: 1rem; - position: absolute; - right: 0; -}*/ +.parent_context > div > div:nth-child(2) { display: flex; } .parents { font-size: .9rem; margin-top: .2rem; @@ -346,12 +350,7 @@ img { @media (max-aspect-ratio: 2/3) { .player_wrapper:not(:fullscreen) video { max-height: 76dvh; } } -.playlist_context { - border: 1px solid var(--bg-2); - border-radius: .5rem; - /* TODO: Shadows only in light mode or different strategy between both color schemes */ - box-shadow: 0 0 12rem #0001; -} +.playlist_context { margin-top: 6.1rem; } .playlist_context > a { display: flex; outline: none; @@ -370,7 +369,7 @@ img { .playlist_context > a:focus-visible, .playlist_context > a:hover { background: var(--bg-2); } .playlist_context > a:not(:last-child) { - border-bottom: 1px solid var(--bg-1); + margin-bottom: .5rem; } .playlist_context .current { background: var(--bg-3); } .playlist_context .description { @@ -416,15 +415,6 @@ img { height: 4rem; object-fit: contain; } -.playlist_header { - background: var(--bg-1); - padding: .8rem; -} -.playlist_header .duration { color: var(--fg-3); } -.playlist_header .title { - color: var(--fg-1); - display: block; -} .playlist_page { display: flex; flex-direction: column; @@ -667,15 +657,17 @@ svg { } .versions_ring.interacting g:not(:focus-visible):not(:hover) { opacity: .5; } video { - background: var(--d-1); + background: #000; border-radius: .5rem; display: block; height: 100%; width: 100%; } +.video_info { margin-bottom: 1.5rem; } .video_title { color: var(--fg-1); margin: 0; + margin-bottom: .2em; } .videos { column-gap: 1rem; diff --git a/src/build/collection.rs b/src/build/collection.rs index 3c0de54..bbb1069 100644 --- a/src/build/collection.rs +++ b/src/build/collection.rs @@ -134,21 +134,6 @@ pub fn collection_html( body.push_str(&rendered); } - // if traversal.steps.len() > 1 { - // let outline_items = traversal.steps - // .iter() - // .filter(|step| !step.is_collection(collection)) - // .enumerate() - // .map(|(index, step)| { - // let prefix = "../".repeat(traversal.steps.len() - 1 - index); - // step.context_for_collection(collection, &prefix, site) - // }) - // .collect::>() - // .join("\n"); - - // body.push_str(&format!(r#"
{outline_items}
"#)); - // } - if collection.platform_integration().enabled() { if let Some(collection_url) = site.absolute_url_index(&collection.site_path) { let mut meta = PlatformIntegrationMeta::new(title.to_string(), collection_url); diff --git a/src/build/outline.rs b/src/build/outline.rs index 1a1d445..9733583 100644 --- a/src/build/outline.rs +++ b/src/build/outline.rs @@ -24,8 +24,6 @@ pub struct Breadcrumb<'a> { pub step: &'a TraversalStep<'a> } -// TODO: Consider the similarity to TraversalStep here (!) This indicates -// we should really have a generic item of that sort for representing both? pub enum CurrentPage<'a> { Collection(&'a Collection), Playlist(&'a Playlist), @@ -438,6 +436,72 @@ impl TraversalStep<'_> { } } + pub fn context_with_bubbles( + &self, + prefix: &str, + site: &Site + ) -> String { + let index_suffix_file_only = site.index_suffix_file_only(); + let translations = &site.language.translations; + + match self { + TraversalStep::Collection(collection) => { + let label = collection.title_or_slug_or_generic_label(translations); + let label_escaped = html_escape_outside_attribute(label); + + let video_bubbles = collection.public_videos() + .map(|video| { + if let Some(poster_meta) = &video.poster.as_ref().and_then(|poster| poster.poster_meta.as_ref()) { + let background = poster_meta.lqip.gradient_radial(); + let video_slug = video.slug_unchecked(); + formatdoc!(r#""#) + } else { + String::new() + } + }) + .collect::>() + .join(""); + + let count = collection.public_videos().count(); + + format!(r#" +
+
{label_escaped}
+
{video_bubbles}
+
+ "#) + } + TraversalStep::Playlist(playlist) => { + let label = playlist.title_or_slug_or_generic_label(translations); + let label_escaped = html_escape_outside_attribute(label); + + let video_bubbles = playlist.public_videos() + .map(|video| { + if let Some(poster_meta) = &video.poster.as_ref().and_then(|poster| poster.poster_meta.as_ref()) { + let background = poster_meta.lqip.gradient_radial(); + let video_slug = video.slug_unchecked(); + formatdoc!(r#""#) + } else { + String::new() + } + }) + .collect::>() + .join(""); + + let count = playlist.public_videos().count(); + + format!(r#" +
+
{label_escaped}
+
{video_bubbles}
+
+ "#) + } + TraversalStep::Video(_) => unimplemented!(), + TraversalStep::Virtual { .. } => unimplemented!() + } + } + fn crumb_collection_header( collection: &Collection, prefix: &str, @@ -655,27 +719,19 @@ impl TraversalStep<'_> { site: &Site, video: Option<&Video> ) -> String { - let banner = if let Some(banner) = &playlist.banner { - banner_html(banner, prefix) - } else if let Some(video) = &playlist.public_videos() - .find(|video| video.poster.is_some()) { - let video_prefix = format!("{prefix}{}/", video.slug_unchecked()); - poster_html(video.poster.as_ref().unwrap(), &video_prefix) - } else { - String::from(r#"
"#) - }; - let label = playlist.title_or_slug_or_generic_label(&site.language.translations); - let outline_stats = OutlineStats::for_playlist(playlist).render(site); + let translations = &site.language.translations; - let header_crumb = formatdoc!(r#" - - {banner} -
-
{label}
- {outline_stats} -
-
- "#); + // let banner = if let Some(banner) = &playlist.banner { + // banner_html(banner, prefix) + // } else if let Some(video) = &playlist.public_videos() + // .find(|video| video.poster.is_some()) { + // let video_prefix = format!("{prefix}{}/", video.slug_unchecked()); + // poster_html(video.poster.as_ref().unwrap(), &video_prefix) + // } else { + // String::from(r#"
"#) + // }; + + let label = playlist.title_or_slug_or_generic_label(translations); if let Some(video) = video { let index_suffix = site.index_suffix(); @@ -686,7 +742,7 @@ impl TraversalStep<'_> { .iter() .enumerate() .map(|(index, video_iterated)| { - let label = video_iterated.title_or_slug_or_generic_label(&site.language.translations); + let label = video_iterated.title_or_slug_or_generic_label(translations); let slug = video_iterated.slug_unchecked(); let video_prefix = if video_iterated.site_path == video.site_path { @@ -725,18 +781,13 @@ impl TraversalStep<'_> { .collect::>() .join("\n"); - let videos_crumb = formatdoc!(r#" + formatdoc!(r#"
{items}
- "#); - - formatdoc!(r#" - {header_crumb} - {videos_crumb} "#) } else { - header_crumb + String::new() } } diff --git a/src/build/playlist.rs b/src/build/playlist.rs index e38b57d..b909884 100644 --- a/src/build/playlist.rs +++ b/src/build/playlist.rs @@ -120,21 +120,6 @@ pub fn playlist_html( body.push_str(&videos_rendered); } - // if !traversal.steps.is_empty() { - // let outline_items = traversal.steps - // .iter() - // .filter(|step| !step.is_playlist()) - // .enumerate() - // .map(|(index, step)| { - // let prefix = "../".repeat(traversal.steps.len() - 1 - index); - // step.context_for_playlist(playlist, &prefix, site) - // }) - // .collect::>() - // .join("\n"); - - // body.push_str(&format!(r#"
{outline_items}
"#)); - // } - if playlist.platform_integration().enabled() { if let Some(playlist_url) = site.absolute_url_index(&playlist.site_path) { let mut meta = PlatformIntegrationMeta::new(title.to_string(), playlist_url); diff --git a/src/build/video.rs b/src/build/video.rs index a83192a..164030e 100644 --- a/src/build/video.rs +++ b/src/build/video.rs @@ -85,22 +85,18 @@ pub fn video_html( } }; - // let outline_items = traversal.steps - // .iter() - // .filter(|step| !step.is_video(video)) - // .enumerate() - // .map(|(index, step)| { - // let prefix = "../".repeat(traversal.steps.len() - 1 - index); - // step.context_for_video(&prefix, site, video) - // }) - // .collect::>() - // .join("\n"); + let parent_context = if traversal.steps.len() > 1 { + let parent_step = &traversal.steps[traversal.steps.len() - 2]; + let context_with_bubbles = parent_step.context_with_bubbles("../", site); - // let outline_rendered = formatdoc!(r#" - //
- // {outline_items} - //
- // "#); + formatdoc!(r#" +
+ {context_with_bubbles} +
+ "#) + } else { + String::new() + }; let video_prefix = ""; let player_rendered = player(false, next_video, site, video, video_prefix); @@ -152,11 +148,16 @@ pub fn video_html( let video_content = formatdoc!(r#"
+
+
+

{e_title} {r_unlisted_badge}

+ {parent_context} +
+
{player_rendered}
-
+
-

{e_title} {r_unlisted_badge}

{release_date}
@@ -165,8 +166,8 @@ pub fn video_html( {r_downloads}
- {description} {links_rendered} + {description}
"#); diff --git a/src/site.rs b/src/site.rs index 0243b49..cd1afb3 100644 --- a/src/site.rs +++ b/src/site.rs @@ -532,6 +532,13 @@ impl Site { } } + pub fn index_suffix_file_only(&self) -> &str { + match self.clean_urls { + true => "", + false => "index.html" + } + } + pub fn new() -> Site { Site { base_url: None,