diff --git a/src/main.rs b/src/main.rs index c0aa54a..ac3d36b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -74,6 +74,7 @@ async fn launch() -> _ { routes![ pages::assets::video_file, pages::assets::video_thumbnail, + pages::assets::fav_icon, pages::index::search, pages::index::channel_page, pages::yt::yt_tags, diff --git a/src/pages/assets.rs b/src/pages/assets.rs index 6b6c704..27dca1a 100644 --- a/src/pages/assets.rs +++ b/src/pages/assets.rs @@ -1,4 +1,9 @@ -use rocket::{fs::NamedFile, get, State}; +use rocket::{ + fs::NamedFile, + get, + http::{ContentType, Status}, + State, +}; use crate::library::Library; @@ -29,3 +34,11 @@ pub async fn video_thumbnail(v: &str, library: &State) -> Option (Status, (ContentType, &'static [u8])) { + ( + Status::Ok, + (ContentType::PNG, include_bytes!("../../src/icon.png")), + ) +} diff --git a/src/pages/components.rs b/src/pages/components.rs index 773ae03..43af141 100644 --- a/src/pages/components.rs +++ b/src/pages/components.rs @@ -28,6 +28,27 @@ impl<'r> FromRequest<'r> for HTMX { } } +pub fn htmx_link( + url: &str, + class: &str, + onclick: &str, + content: PreEscaped, +) -> PreEscaped { + html!( + a class=(class) onclick=(onclick) href=(url) hx-get=(url) hx-target="#main_content" hx-push-url="true" hx-swap="innerHTML" { + (content); + }; + ) +} + +pub fn script(script: &str) -> PreEscaped { + html!( + script { + (PreEscaped(script)) + }; + ) +} + pub fn shell(content: PreEscaped, title: &str) -> PreEscaped { html! { html { @@ -38,11 +59,25 @@ pub fn shell(content: PreEscaped, title: &str) -> PreEscaped { meta name="viewport" content="width=device-width, initial-scale=1.0"; }; body class="bg-black text-white" { + header class="bg-gray-800 text-white shadow-md py-2" { + (script(include_str!("../scripts/header.js"))); + + div class="flex justify-start px-6" { + + (htmx_link("/", "flex items-center space-x-2", "stopAllVideos()", html!( + img src="/favicon" alt="Logo" class="w-10 h-10 rounded-md"; + span class="font-semibold text-xl" { "WatchDogs" }; + ))) + + }; + + }; + }; + div id="main_content" { (content) }; - } - } + }; } } @@ -105,74 +140,63 @@ pub fn format_number(num: i32) -> String { } pub async fn video_element_wide(video: &mut Video) -> PreEscaped { - html!( - a href=(format!("/watch?v={}", video.id)) class="flex items-center w-full p-4 bg-gray-900 shadow-lg rounded-lg overflow-hidden mb-2 mt-2" { - div class="flex-shrink-0" { - img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-48 h-32 object-cover rounded-md"; - }; - - div class="flex flex-col flex-grow ml-4" { - h3 class="text-lg font-semibold truncate mb-1" { - ( video.title ) + htmx_link( + &format!("/watch?v={}", video.id), + "flex items-center w-full p-4 bg-gray-900 shadow-lg rounded-lg overflow-hidden mb-2 mt-2", + "stopAllVideos()", + html!( + div class="flex-shrink-0" { + img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-48 h-32 object-cover rounded-md"; }; - @if let Some(meta) = video.youtube_meta().await { - div class="text-sm text-gray-400 mb-2" { - span class="font-medium" { ( meta.uploader_name ) } - span { " - " } - span { ( format_date(&meta.upload_date) ) } - }; - - div class="text-sm text-gray-400" { - span { ( format_number(meta.views) ) } - span { " views" } - span { " - " } - span class="ml-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" { - (( format_seconds_to_hhmmss(video.duration) )) + div class="flex flex-col flex-grow ml-4" { + h3 class="text-lg font-semibold truncate mb-1" { + ( video.title ) }; - }; - }; - }; - }; - ) -} -pub async fn video_element(video: &mut Video) -> PreEscaped { - html!( - a href=(format!("/watch?v={}", video.id)) class="max-w-sm mx-auto p-4 max-h-60 aspect-video" { - div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" { - div class="relative" { - img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-full h-auto object-cover aspect-video"; - span class="absolute bottom-2 right-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" { - (( format_seconds_to_hhmmss(video.duration) )) + @if let Some(meta) = video.youtube_meta().await { + div class="text-sm text-gray-400 mb-2" { + span class="font-medium" { ( meta.uploader_name ) } + span { " - " } + span { ( format_date(&meta.upload_date) ) } }; - }; - div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" { - div class="p-4" { - h3 class="text-lg font-semibold truncate" { - ( video.title ) + div class="text-sm text-gray-400" { + span { ( format_number(meta.views) ) } + span { " views" } + span { " - " } + span class="ml-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" { + (( format_seconds_to_hhmmss(video.duration) )) }; }; }; }; - }; + ), ) } -pub fn header(query: &str) -> PreEscaped { - html!( - header style="padding: 10px 0; display: flex; justify-content: space-between;" { - a href="/" style="text-decoration: none; margin-left: 20px;" { - div style="margin-right: 20px;display:flex;align-items: center" { - img src="/icon" width="64" style="margin-top: -25px;margin-right: 15px;border-radius: 20%;"; - p style="font-size: 42px;" { "WatchDogs" }; +pub async fn video_element(video: &mut Video) -> PreEscaped { + htmx_link( + &format!("/watch?v={}", video.id), + "max-w-sm mx-auto p-4 max-h-60 aspect-video", + "stopAllVideos()", + html!( + div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" { + div class="relative" { + img width="480" src=(format!("/video/thumbnail?v={}", video.id)) alt="Video Thumbnail" class="w-full h-auto object-cover aspect-video"; + span class="absolute bottom-2 right-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" { + (( format_seconds_to_hhmmss(video.duration) )) + }; + }; + + div class="bg-gray-900 shadow-lg rounded-lg overflow-hidden" { + div class="p-4" { + h3 class="text-lg font-semibold truncate" { + ( video.title ) + }; + }; + }; }; - }; - div style="width: 35px;" {}; - div style="flex-grow: 1; text-align: center;" { - (search_bar(query)); - }; - }; + ), ) } diff --git a/src/pages/index.rs b/src/pages/index.rs index 19b080c..d1ddd46 100644 --- a/src/pages/index.rs +++ b/src/pages/index.rs @@ -6,7 +6,10 @@ use rocket::{ }; use serde_json::json; -use crate::{library::Library, pages::components::video_element}; +use crate::{ + library::Library, + pages::components::{htmx_link, video_element}, +}; use super::{ api_response, @@ -69,7 +72,7 @@ pub async fn index_page(htmx: HTMX, library: &State) -> (Status, (Conte h1 class="text-center text-4xl font-extrabold leading-tight mt-8" { "Directories:" }; div class="flex flex-wrap p-10" { @for dir in library.get_directories().await { - a class="px-3 py-2 m-2 bg-purple-500 text-white rounded-full cursor-pointer hover:bg-purple-600" href=(format!("/d/{dir}")) { (dir) }; + (htmx_link(&format!("/d/{dir}"), "px-3 py-2 m-2 bg-purple-500 text-white rounded-full cursor-pointer hover:bg-purple-600", "", html! { (dir) })); br; }; }; diff --git a/src/scripts/header.js b/src/scripts/header.js new file mode 100644 index 0000000..6d3d76b --- /dev/null +++ b/src/scripts/header.js @@ -0,0 +1,7 @@ +function stopAllVideos() { + const videos = document.querySelectorAll('video'); + + videos.forEach(video => { + video.pause(); + }); +} \ No newline at end of file