watchdogs/src/pages/components.rs
JMARyA a0e7c5d3c1
Some checks failed
ci/woodpecker/push/build Pipeline failed
history feature
2024-12-22 20:19:52 +01:00

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 )
};
};
};
};
};
)
}