124 lines
4.6 KiB
Rust
124 lines
4.6 KiB
Rust
use crate::library::Video;
|
|
use based::{
|
|
auth::User,
|
|
format::{format_date, format_number, format_seconds_to_hhmmss},
|
|
page::script,
|
|
request::{RequestContext, StringResponse},
|
|
};
|
|
use maud::{html, PreEscaped};
|
|
|
|
pub async fn render_page(
|
|
ctx: RequestContext,
|
|
content: PreEscaped<String>,
|
|
title: &str,
|
|
user: Option<User>,
|
|
) -> StringResponse {
|
|
based::page::render_page(
|
|
content,
|
|
title,
|
|
ctx,
|
|
&based::page::Shell::new(
|
|
html! {
|
|
script src="https://cdn.tailwindcss.com" {};
|
|
script src="/assets/htmx.min.js" {};
|
|
meta name="viewport" content="width=device-width, initial-scale=1.0";
|
|
},
|
|
html! {
|
|
header class="bg-gray-800 text-white shadow-md py-2" {
|
|
(script(include_str!("../scripts/header.js")));
|
|
|
|
div class="flex justify-between px-6" {
|
|
a href="/" class="flex items-center space-x-2" {
|
|
img src="/favicon" alt="Logo" class="w-10 h-10 rounded-md";
|
|
span class="font-semibold text-xl" { "WatchDogs" };
|
|
};
|
|
|
|
@if user.is_some() {
|
|
p { (user.unwrap().username) };
|
|
};
|
|
|
|
};
|
|
|
|
};
|
|
},
|
|
Some(String::from("bg-black text-white")),
|
|
),
|
|
)
|
|
.await
|
|
}
|
|
|
|
pub fn loading_spinner() -> PreEscaped<String> {
|
|
html! {
|
|
style {
|
|
".spinner { display: flex;justify-content: center;align-items: center;height: 100vh;}
|
|
.spinner-border { border: 2px solid #007bff;border-top: 2px solid transparent;border-radius: 50%;width: 40px;height: 40px;animation: spin 1s linear infinite;}
|
|
@keyframes spin {0% { transform: rotate(0deg); }100% { transform: rotate(360deg); }}"
|
|
};
|
|
div class="spinner" {
|
|
div class="spinner-border" {};
|
|
};
|
|
}
|
|
}
|
|
|
|
pub fn search_bar(query: &str) -> PreEscaped<String> {
|
|
html! {
|
|
form hx-get="/search" action="/search" hx-push-url="true" hx-target="#main-view" hx-swap="innerHTML" {
|
|
input style="width: 100%;" value=(query) name="query" type="search" placeholder="Search...";
|
|
};
|
|
}
|
|
}
|
|
|
|
pub async fn video_element_wide(video: &Video) -> PreEscaped<String> {
|
|
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 relative" {
|
|
img width="480" src=(format!("/video/thumbnail?v={}", video.id)) class="w-48 h-32 object-cover rounded-md";
|
|
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="flex flex-col flex-grow ml-4" {
|
|
h3 class="text-lg font-semibold truncate mb-1" title=(video.title) {
|
|
( video.title )
|
|
};
|
|
|
|
@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" }
|
|
};
|
|
};
|
|
};
|
|
};
|
|
)
|
|
}
|
|
|
|
pub async fn video_element(video: &mut Video) -> PreEscaped<String> {
|
|
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)) 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" title=(video.title) {
|
|
( video.title )
|
|
};
|
|
};
|
|
};
|
|
};
|
|
};
|
|
)
|
|
}
|