diff options
Diffstat (limited to 'server')
-rw-r--r-- | server/src/routes/ui/node.rs | 24 | ||||
-rw-r--r-- | server/src/routes/ui/style/layout.css | 132 |
2 files changed, 126 insertions, 30 deletions
diff --git a/server/src/routes/ui/node.rs b/server/src/routes/ui/node.rs index 9162982..855da45 100644 --- a/server/src/routes/ui/node.rs +++ b/server/src/routes/ui/node.rs @@ -7,7 +7,7 @@ use crate::{ }; use anyhow::{anyhow, Context}; use log::info; -use rocket::{get, uri, State}; +use rocket::{get, http::ContentType, uri, State}; use std::{ops::Deref, path::PathBuf, sync::Arc}; use tokio::fs::File; @@ -54,8 +54,11 @@ markup::define! { } ItemCard(item: Arc<Item>) { div.card.item { - a[href=&uri!(r_library_node(&item.lib_path)).to_string()] { - img[src=uri!(r_item_assets(&item.lib_path)).to_string()]; + div.banner { + a[href=&uri!(r_library_node(&item.lib_path)).to_string()] { + img[src=uri!(r_item_assets(&item.lib_path)).to_string()]; + } + div.hover { a[href=&player_uri(&item.lib_path)] { "▶" } } } a[href=&uri!(r_library_node(&item.lib_path)).to_string()] { p.title { @item.info.title } @@ -63,17 +66,15 @@ markup::define! { } } ItemPage(item: Arc<Item>) { + // TODO different image here + img.backdrop[src=uri!(r_item_assets(&item.lib_path)).to_string()]; div.page.item { - div.backdrop { - // TODO different image here - img[src=uri!(r_item_assets(&item.lib_path)).to_string()]; - } div.banner { img[src=uri!(r_item_assets(&item.lib_path)).to_string()]; } div.title { h1 { @item.info.title } - a[href=&player_uri(&item.lib_path)] { "Watch now" } + a.play[href=&player_uri(&item.lib_path)] { "Watch now" } } div.details { h3 { "Lorem Ipsum!" } @@ -84,7 +85,10 @@ markup::define! { } #[get("/item_assets/<path..>")] -pub async fn r_item_assets(path: PathBuf, state: &State<AppState>) -> Result<File, MyError> { +pub async fn r_item_assets( + path: PathBuf, + state: &State<AppState>, +) -> Result<(ContentType, File), MyError> { let node = state .library .nested_path(&path) @@ -98,5 +102,5 @@ pub async fn r_item_assets(path: PathBuf, state: &State<AppState>) -> Result<Fil .ok_or(anyhow!("no banner available"))?, ); info!("loading asset from {path:?}"); - Ok(File::open(path).await?) + Ok((ContentType::WEBP, File::open(path).await?)) } diff --git a/server/src/routes/ui/style/layout.css b/server/src/routes/ui/style/layout.css index 6a63ccc..913bd77 100644 --- a/server/src/routes/ui/style/layout.css +++ b/server/src/routes/ui/style/layout.css @@ -5,37 +5,57 @@ :root { --card-size: 12em; + --bar-height: 5em; + --banner-aspect: 1.41; + --accent-light: rgb(255, 163, 87); + --accent-dark: rgb(199, 90, 0); + --backdrop-height: 18em; + --background-dark: #070707; + --background-light: #1c1c1c; +} + +::selection { + background-color: var(--accent-dark); } * { color: rgb(218, 218, 218); font-family: "Cantarell", sans-serif; font-weight: 500; + + scrollbar-width: thin; + scrollbar-color: var(--background-light) #0000; } body { - background-color: #070707; + background-color: var(--background-dark); width: 100vw; margin: 0px; padding: 0px; } -img { - width: 100%; - height: 100%; - object-fit: cover; -} - nav { - position: absolute; + z-index: 90; + position: fixed; top: 0px; left: 0px; padding: 1em; width: calc(100vw - 2em); height: 2em; + backdrop-filter: blur(6px); background-color: #1c1c1c9a; } +nav a { + border: 0px solid transparent; + border-radius: 5px; + padding: 0.5em; + text-decoration: none; +} +nav a:hover { + background-color: #ffffff10; +} + nav h1 { margin: 0px; font-size: 1.5em; @@ -44,6 +64,8 @@ nav h1 { } #main { + display: block; + margin-top: var(--bar-height); } .error { @@ -62,7 +84,6 @@ option { } .page.dir { - margin-top: 5em; padding: 1em; padding-left: 3em; padding-right: 3em; @@ -78,16 +99,12 @@ option { .card.item { width: var(--card-size); - height: calc(var(--card-size) * 1.41); + height: calc(var(--card-size) * var(--banner-aspect)); padding: 1em; } .card.dir { width: calc(var(--card-size) * 2); - height: calc(var(--card-size) * 1.41); -} -.card a { - width: 100%; - height: 100%; + height: calc(var(--card-size) * var(--banner-aspect)); } .card.item .title { @@ -95,15 +112,90 @@ option { text-align: center; text-overflow: ellipsis; } - -.page.item .backdrop { +.card.item .banner { + display: grid; +} +.card.item .banner a { + grid-area: 1 / 1; +} +.card.item .banner a img { width: 100%; - margin-bottom: calc(-100% * 1.41 + 18em); + height: 100%; + object-fit: cover; + object-position: center; } -.page.item .backdrop img { +.card.item .banner .hover { + pointer-events: none; + grid-area: 1 / 1; + transition: opacity 0.3s, backdrop-filter 0.3s; + opacity: 0; + display: flex; + justify-content: center; + align-items: center; +} +.card.item .banner:hover .hover { + opacity: 1; + background-color: #0004; + backdrop-filter: blur(3px); +} +.card.item .banner .hover a { + text-decoration: none; + font-stretch: 200%; + width: 1em; + height: 1em; + line-height: 1; + margin: auto; + padding: 0.4em 0.3em 0.4em 0.5em; + border-radius: 50%; + font-size: 2.2em; + pointer-events: all; + background-color: #0005; + transition: background-color 0.2s, font-size 0.2s; +} +.card.item .banner .hover a:hover { + background-color: #0008; + font-size: 3em; +} + +.backdrop { + width: 100%; + height: calc(var(--backdrop-height) + 5em); + margin-top: calc(-1 * var(--bar-height)); + margin-bottom: -5em; + mask-image: linear-gradient( + rgba(0, 0, 0, 1), + transparent calc(var(--backdrop-height) + 5em) + ); mask-mode: alpha; - mask-image: linear-gradient(rgba(0, 0, 0, 1), transparent 30%); + pointer-events: none; + object-fit: cover; + object-position: center; +} +.page.item { + position: relative; + width: 100%; } .page.item .banner { width: max(8em, 20%); + float: left; + margin: 3em; + margin-top: -1em; +} +.page.item .banner img { + width: 100%; + height: 100%; + object-fit: cover; + object-position: center; +} + +.page.item .title h1 { + display: inline; + margin-right: 1em; +} +.page.item .title .play { + display: inline; + font-stretch: 200%; +} +.page.item .title .play::before { + content: "▶ "; } |