♻️ refactor
This commit is contained in:
parent
2567b2a0ab
commit
0301b04ba2
7 changed files with 229 additions and 138 deletions
12
Cargo.lock
generated
12
Cargo.lock
generated
|
@ -146,7 +146,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "based"
|
name = "based"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
source = "git+https://git.hydrar.de/jmarya/based?branch=ui#e02def6bc16dfe61937816d669514c9d4300ae1a"
|
source = "git+https://git.hydrar.de/jmarya/based?branch=ui#5ef37275ec504dc2e406d8feadca2e388e8d7fc9"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -1163,13 +1163,13 @@ checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "is-terminal"
|
name = "is-terminal"
|
||||||
version = "0.4.13"
|
version = "0.4.15"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b"
|
checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"hermit-abi 0.4.0",
|
"hermit-abi 0.4.0",
|
||||||
"libc",
|
"libc",
|
||||||
"windows-sys 0.52.0",
|
"windows-sys 0.59.0",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -1989,9 +1989,9 @@ checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "0.38.43"
|
version = "0.38.44"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a78891ee6bf2340288408954ac787aa063d8e8817e9f53abb37c695c6d834ef6"
|
checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.8.0",
|
"bitflags 2.8.0",
|
||||||
"errno",
|
"errno",
|
||||||
|
|
|
@ -24,4 +24,4 @@ maud = "0.26.0"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
data-encoding = "2.6.0"
|
data-encoding = "2.6.0"
|
||||||
bcrypt = "0.16.0"
|
bcrypt = "0.16.0"
|
||||||
based = { git = "https://git.hydrar.de/jmarya/based", features = ["cache", "htmx"], branch = "ui" }
|
based = { git = "https://git.hydrar.de/jmarya/based", features = ["cache"], branch = "ui" }
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use based::{auth::User, get_pg};
|
use based::{asset::AssetRoutes, auth::User, get_pg};
|
||||||
use rocket::{http::Method, routes};
|
use rocket::{http::Method, routes};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
mod library;
|
mod library;
|
||||||
|
@ -51,15 +51,15 @@ async fn launch() -> _ {
|
||||||
.expect("error creating CORS options");
|
.expect("error creating CORS options");
|
||||||
|
|
||||||
rocket::build()
|
rocket::build()
|
||||||
|
.mount_assets()
|
||||||
.mount(
|
.mount(
|
||||||
"/",
|
"/",
|
||||||
routes![
|
routes![
|
||||||
based::htmx::htmx_script_route,
|
|
||||||
pages::assets::video_file,
|
pages::assets::video_file,
|
||||||
pages::assets::video_thumbnail,
|
pages::assets::video_thumbnail,
|
||||||
pages::assets::fav_icon,
|
pages::assets::fav_icon,
|
||||||
pages::index::search,
|
pages::index::search,
|
||||||
pages::index::channel_page,
|
pages::index::dir_page,
|
||||||
pages::yt::yt_tags,
|
pages::yt::yt_tags,
|
||||||
pages::yt::yt_tag_page,
|
pages::yt::yt_tag_page,
|
||||||
pages::yt::yt_channel_page,
|
pages::yt::yt_channel_page,
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::library::Video;
|
use crate::library::Video;
|
||||||
use based::ui::components::AppBar;
|
use based::ui::components::{AppBar, Shell};
|
||||||
use based::ui::wrapper::HoverWrapper;
|
use based::ui::wrapper::HoverWrapper;
|
||||||
use based::ui::{prelude::*, UIWidget};
|
use based::ui::{prelude::*, UIWidget};
|
||||||
use based::{
|
use based::{
|
||||||
|
@ -15,84 +15,164 @@ pub async fn render_page(
|
||||||
title: &str,
|
title: &str,
|
||||||
user: Option<User>,
|
user: Option<User>,
|
||||||
) -> StringResponse {
|
) -> StringResponse {
|
||||||
based::ui::render_page(
|
Shell::new(
|
||||||
content,
|
Nothing(),
|
||||||
title,
|
Div()
|
||||||
ctx,
|
.vanish()
|
||||||
&based::ui::components::Shell::new(
|
.push(script(include_str!("../scripts/header.js")))
|
||||||
html! {
|
.push(AppBar("WatchDogs", user)),
|
||||||
script src="https://cdn.tailwindcss.com" {};
|
Background(Text("").white()).color(Colors::Black),
|
||||||
script src="/assets/htmx.min.js" {};
|
|
||||||
meta name="viewport" content="width=device-width, initial-scale=1.0";
|
|
||||||
},
|
|
||||||
html! {
|
|
||||||
(script(include_str!("../scripts/header.js")));
|
|
||||||
(AppBar("WatchDogs", user))
|
|
||||||
},
|
|
||||||
Some(String::from("bg-black text-white")),
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
.use_ui()
|
||||||
|
.render_page(content, title, ctx)
|
||||||
.await
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn HoverScaleAnimation<T: UIWidget + 'static>(inner: T) -> HoverWrapper {
|
pub fn HoverScaleAnimation<T: UIWidget + 'static>(inner: T) -> HoverWrapper {
|
||||||
Hover(Animated(ZIndex::five(Scale(1.02, Nothing()))).scope(Scope::All)).on(inner)
|
Hover(Animated(ZIndex::Five(Scale(1.02, Nothing()))).scope(Scope::All)).on(inner)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn Title<T: UIWidget + 'static>(title: T) -> PreEscaped<String> {
|
||||||
|
Margin(
|
||||||
|
Paragraph(title)
|
||||||
|
.align(TextAlignment::Center)
|
||||||
|
._4xl()
|
||||||
|
.extrabold()
|
||||||
|
.line_height(LineHeight::Tight),
|
||||||
|
)
|
||||||
|
.top(ScreenValue::_6)
|
||||||
|
.bottom(ScreenValue::_2)
|
||||||
|
.render()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn VerticalVideoGrid<T: UIWidget + 'static>(inner: T) -> PreEscaped<String> {
|
||||||
|
Screen::large(Grid(Nothing()).columns(GridAmount::_3).gap(ScreenValue::_6))
|
||||||
|
.on(Padding(Margin(inner).bottom(ScreenValue::_4)).all(ScreenValue::_6))
|
||||||
|
.render()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn video_element_wide(video: &Video) -> PreEscaped<String> {
|
pub async fn video_element_wide(video: &Video) -> PreEscaped<String> {
|
||||||
html!(
|
let yt_meta = video.youtube_meta().await;
|
||||||
a href=(format!("/watch?v={}", video.id)) class="flex items-center w-full my-4 bg-gray-900 hover:bg-gray-800 shadow-lg rounded-lg overflow-hidden" {
|
Flex(Margin(Width(ScreenValue::full,
|
||||||
div class="flex-shrink-0 relative" {
|
Hover(Background(Nothing()).color(Gray::_800)).on(
|
||||||
|
Background(
|
||||||
|
Rounded(
|
||||||
|
Shadow::large(
|
||||||
|
Link(&format!("/watch?v={}", video.id),
|
||||||
|
Div().vanish().push(
|
||||||
|
FlexGrow(Strategy::NoShrink,
|
||||||
|
Position(PositionKind::Relative,
|
||||||
|
Div().vanish().push(
|
||||||
|
html! {
|
||||||
img width="480" src=(format!("/video/thumbnail?v={}", video.id)) class="aspect-video h-32 w-48 rounded-l-md object-cover";
|
img width="480" src=(format!("/video/thumbnail?v={}", video.id)) class="aspect-video h-32 w-48 rounded-l-md object-cover";
|
||||||
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-2 max-h-32" {
|
|
||||||
(Margin(Text(&video.title).large().semibold().max_lines(LineClamp::_3).title(&video.title).align(TextAlignment::Start)
|
|
||||||
).bottom(ScreenValue::_1)
|
|
||||||
)
|
|
||||||
|
|
||||||
div class="flex flex-col flex-grow ml-2 py-1" {
|
|
||||||
@if let Some(meta) = video.youtube_meta().await {
|
|
||||||
div class="text-sm text-gray-400 mb-2 text-start" {
|
|
||||||
(Span(&meta.uploader_name).medium())
|
|
||||||
(Span(" - "))
|
|
||||||
(Span(&format_date(&meta.upload_date)))
|
|
||||||
};
|
|
||||||
|
|
||||||
div class="text-sm text-gray-400 text-start" {
|
|
||||||
(Span(&format_number(meta.views)))
|
|
||||||
(Span(" views"))
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
).push(
|
||||||
};
|
Position(PositionKind::Absolute,
|
||||||
|
Background(
|
||||||
|
Rounded(
|
||||||
|
Opacity(0.90,
|
||||||
|
Padding(
|
||||||
|
Span(
|
||||||
|
&format_seconds_to_hhmmss(video.duration)
|
||||||
|
).white().xs()
|
||||||
|
).x(ScreenValue::_2).y(ScreenValue::_1)
|
||||||
)
|
)
|
||||||
|
).size(Size::Small)
|
||||||
|
).color(Colors::Black)
|
||||||
|
).bottom(8).right(8)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
).push(
|
||||||
|
Flex(
|
||||||
|
FlexGrow(Strategy::Grow,
|
||||||
|
Margin(
|
||||||
|
MaxHeight(ScreenValue::_32,
|
||||||
|
Div().vanish().push(
|
||||||
|
Margin(Text(&video.title).large().semibold().max_lines(LineClamp::_3).title(&video.title).align(TextAlignment::Start)
|
||||||
|
).bottom(ScreenValue::_1)
|
||||||
|
).push_some(yt_meta, |meta| {
|
||||||
|
Flex(
|
||||||
|
FlexGrow(Strategy::Grow,
|
||||||
|
Margin(
|
||||||
|
Padding(
|
||||||
|
Div().vanish().push(
|
||||||
|
Paragraph(
|
||||||
|
Margin(
|
||||||
|
Div().vanish().push(
|
||||||
|
Span(&meta.uploader_name).medium()
|
||||||
|
).push(
|
||||||
|
Span(" - ")
|
||||||
|
).push(
|
||||||
|
Span(&format_date(&meta.upload_date))
|
||||||
|
)
|
||||||
|
).bottom(ScreenValue::_2)
|
||||||
|
).sm().color(&Gray::_400).align(TextAlignment::Start)
|
||||||
|
).push(
|
||||||
|
Paragraph(
|
||||||
|
Div().vanish().push(
|
||||||
|
Span(&format_number(meta.views))
|
||||||
|
).push(
|
||||||
|
Span(" views")
|
||||||
|
)
|
||||||
|
).sm().color(&Gray::_400).align(TextAlignment::Start)
|
||||||
|
)
|
||||||
|
).y(ScreenValue::_1)
|
||||||
|
).left(ScreenValue::_2)
|
||||||
|
)
|
||||||
|
).direction(Direction::Column)
|
||||||
|
})
|
||||||
|
)
|
||||||
|
).left(ScreenValue::_2)
|
||||||
|
)
|
||||||
|
).direction(Direction::Column)
|
||||||
|
)
|
||||||
|
|
||||||
|
))).size(Size::Large)).color(Gray::_900))
|
||||||
|
|
||||||
|
|
||||||
|
)).y(ScreenValue::_4)).items_center().render()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn video_thumbnail_with_time(video: &Video) -> PreEscaped<String> {
|
pub fn video_thumbnail_with_time(video: &Video) -> PreEscaped<String> {
|
||||||
html! {
|
Position(
|
||||||
div class="relative" {
|
PositionKind::Relative,
|
||||||
(
|
Div()
|
||||||
Width(ScreenValue::full,
|
.push(Context(Width(
|
||||||
Height(ScreenValue::auto,
|
ScreenValue::full,
|
||||||
Aspect::video(
|
Height(
|
||||||
Rounded(
|
ScreenValue::auto,
|
||||||
Image(&format!("/video/thumbnail?v={}", video.id))
|
Aspect::Video(
|
||||||
).size(Size::Large).side(Side::Top)
|
Rounded(Image(&format!("/video/thumbnail?v={}", video.id)))
|
||||||
|
.size(Size::Large)
|
||||||
|
.side(Side::Top),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
)))
|
||||||
|
.push(Context(
|
||||||
|
Position(
|
||||||
|
PositionKind::Absolute,
|
||||||
|
Background(
|
||||||
|
Padding(
|
||||||
|
Rounded(Opacity(
|
||||||
|
0.90,
|
||||||
|
Span(&format_seconds_to_hhmmss(video.duration)).white().xs(),
|
||||||
|
))
|
||||||
|
.size(Size::Small),
|
||||||
)
|
)
|
||||||
|
.x(ScreenValue::_2)
|
||||||
|
.y(ScreenValue::_1),
|
||||||
)
|
)
|
||||||
|
.color(Colors::Black),
|
||||||
)
|
)
|
||||||
|
.bottom(8)
|
||||||
|
.right(8),
|
||||||
|
)),
|
||||||
)
|
)
|
||||||
span class="absolute bottom-2 right-2 bg-black text-white text-xs px-2 py-1 rounded-sm opacity-90" {
|
.render()
|
||||||
(( format_seconds_to_hhmmss(video.duration) ))
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn video_element(video: &mut Video) -> PreEscaped<String> {
|
pub async fn video_element(video: &mut Video) -> PreEscaped<String> {
|
||||||
|
@ -101,7 +181,7 @@ pub async fn video_element(video: &mut Video) -> PreEscaped<String> {
|
||||||
ScreenValue::_90,
|
ScreenValue::_90,
|
||||||
MaxHeight(
|
MaxHeight(
|
||||||
ScreenValue::_60,
|
ScreenValue::_60,
|
||||||
Aspect::video(Link(
|
Aspect::Video(Link(
|
||||||
&format!("/watch?v={}", video.id),
|
&format!("/watch?v={}", video.id),
|
||||||
Context(
|
Context(
|
||||||
Hover(Background(Nothing()).color(Gray::_800)).on(Background(
|
Hover(Background(Nothing()).color(Gray::_800)).on(Background(
|
||||||
|
|
|
@ -7,10 +7,11 @@ use based::{
|
||||||
RequestContext, StringResponse,
|
RequestContext, StringResponse,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
use maud::html;
|
use maud::{html, Render};
|
||||||
use rocket::{get, State};
|
use rocket::{get, State};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
use crate::pages::components::{Title, VerticalVideoGrid};
|
||||||
use crate::{library::Library, pages::components::video_element};
|
use crate::{library::Library, pages::components::video_element};
|
||||||
|
|
||||||
use super::{
|
use super::{
|
||||||
|
@ -48,21 +49,23 @@ pub async fn latest_page(
|
||||||
user: MaybeUser,
|
user: MaybeUser,
|
||||||
) -> StringResponse {
|
) -> StringResponse {
|
||||||
let videos = library.get_newly_added(20).await;
|
let videos = library.get_newly_added(20).await;
|
||||||
|
let video_elements = html! {
|
||||||
let content = html!(
|
|
||||||
h1 class="text-center text-4xl font-extrabold leading-tight mt-6 mb-2" { "Recent videos" };
|
|
||||||
div class="p-6" {
|
|
||||||
@for mut vid in videos {
|
@for mut vid in videos {
|
||||||
( video_element_wide(&mut vid).await );
|
( video_element_wide(&mut vid).await );
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
);
|
|
||||||
|
let content = Div()
|
||||||
|
.vanish()
|
||||||
|
.push(Title("Recent videos"))
|
||||||
|
.push(Padding(video_elements).all(ScreenValue::_6))
|
||||||
|
.render();
|
||||||
|
|
||||||
render_page(ctx, content, "Recent videos", user.into()).await
|
render_page(ctx, content, "Recent videos", user.into()).await
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/d/<dir>")]
|
#[get("/d/<dir>")]
|
||||||
pub async fn channel_page(
|
pub async fn dir_page(
|
||||||
ctx: RequestContext,
|
ctx: RequestContext,
|
||||||
dir: &str,
|
dir: &str,
|
||||||
library: &State<Library>,
|
library: &State<Library>,
|
||||||
|
@ -76,15 +79,17 @@ pub async fn channel_page(
|
||||||
}
|
}
|
||||||
|
|
||||||
let dir_videos = library.get_directory_videos(dir).await;
|
let dir_videos = library.get_directory_videos(dir).await;
|
||||||
|
let video_elements = html! {
|
||||||
let content = html!(
|
|
||||||
h1 class="text-center text-4xl font-extrabold leading-tight mt-4 mb-2" { (dir) };
|
|
||||||
div class="p-6" {
|
|
||||||
@for mut vid in dir_videos {
|
@for mut vid in dir_videos {
|
||||||
( video_element_wide(&mut vid).await );
|
( video_element_wide(&mut vid).await );
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
);
|
|
||||||
|
let content = Div()
|
||||||
|
.vanish()
|
||||||
|
.push(Title(dir.to_string()))
|
||||||
|
.push(Padding(video_elements).all(ScreenValue::_6))
|
||||||
|
.render();
|
||||||
|
|
||||||
render_page(ctx, content, dir, user.into()).await
|
render_page(ctx, content, dir, user.into()).await
|
||||||
}
|
}
|
||||||
|
@ -95,42 +100,49 @@ pub async fn index_page(
|
||||||
library: &State<Library>,
|
library: &State<Library>,
|
||||||
user: MaybeUser,
|
user: MaybeUser,
|
||||||
) -> StringResponse {
|
) -> StringResponse {
|
||||||
let content = html!(
|
let random_video_elements = html! {
|
||||||
h1 class="text-center text-4xl font-extrabold leading-tight mt-8" { "Random Videos" };
|
|
||||||
div class="lg:grid grid-cols-3 gap-6 p-6 mb-4" {
|
|
||||||
@for mut vid in library.get_random_videos(3).await {
|
@for mut vid in library.get_random_videos(3).await {
|
||||||
( video_element(&mut vid).await );
|
( video_element(&mut vid).await );
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
let newly_added_elements = html! {
|
||||||
h1 class="text-center text-4xl font-extrabold leading-tight mt-16" { a href="/latest" { "Latest Videos" };};
|
|
||||||
div class="lg:grid grid-cols-3 gap-6 p-6 mb-4" {
|
|
||||||
@for mut vid in library.get_newly_added(3).await {
|
@for mut vid in library.get_newly_added(3).await {
|
||||||
( video_element(&mut vid).await );
|
( video_element(&mut vid).await );
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
let directories = library.get_directories().await;
|
||||||
|
|
||||||
h1 class="text-center text-4xl font-extrabold leading-tight mt-8" { "Directories:" };
|
let content = Div()
|
||||||
div class="flex flex-wrap p-10" {
|
.vanish()
|
||||||
@for dir in library.get_directories().await {
|
.push(Title("Random Videos"))
|
||||||
|
.push(VerticalVideoGrid(random_video_elements))
|
||||||
|
.push(Title(Link("/latest", "Latest Videos").use_htmx()))
|
||||||
(Margin(
|
.push(VerticalVideoGrid(newly_added_elements))
|
||||||
|
.push(Title("Directories:"))
|
||||||
|
.push(
|
||||||
Padding(
|
Padding(
|
||||||
Hover(Background(Cursor::Pointer.on(Nothing())).color(Purple::_600)).on(
|
Flex(Div().vanish().push_for_each(&directories, |dir: &_| {
|
||||||
Background(
|
Margin(
|
||||||
|
Padding(
|
||||||
|
Hover(Background(Cursor::Pointer.on(Nothing())).color(Purple::_600))
|
||||||
|
.on(Background(
|
||||||
Rounded(
|
Rounded(
|
||||||
Link(
|
Link(&format!("/d/{dir}"), Text(&dir).white()).use_htmx(),
|
||||||
&format!("/d/{dir}"),
|
)
|
||||||
Text(&dir).white()
|
.size(Size::Full),
|
||||||
).use_htmx()
|
)
|
||||||
).size(Size::Full)
|
.color(Purple::_500)),
|
||||||
).color(Purple::_500))
|
)
|
||||||
).x(ScreenValue::_3).y(ScreenValue::_2)).all(ScreenValue::_2))
|
.x(ScreenValue::_3)
|
||||||
br;
|
.y(ScreenValue::_2),
|
||||||
};
|
)
|
||||||
};
|
.all(ScreenValue::_2)
|
||||||
);
|
}))
|
||||||
|
.wrap(Wrap::Wrap),
|
||||||
|
)
|
||||||
|
.all(ScreenValue::_10),
|
||||||
|
)
|
||||||
|
.render();
|
||||||
|
|
||||||
render_page(ctx, content, "WatchDogs", user.into()).await
|
render_page(ctx, content, "WatchDogs", user.into()).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,12 +2,12 @@ use based::auth::{Sessions, User};
|
||||||
use based::request::StringResponse;
|
use based::request::StringResponse;
|
||||||
use based::ui::prelude::*;
|
use based::ui::prelude::*;
|
||||||
use based::{auth::MaybeUser, request::RequestContext};
|
use based::{auth::MaybeUser, request::RequestContext};
|
||||||
use maud::html;
|
use maud::{html, Render};
|
||||||
use rocket::http::CookieJar;
|
use rocket::http::CookieJar;
|
||||||
use rocket::{form::Form, get, http::Cookie, post, response::Redirect, FromForm};
|
use rocket::{form::Form, get, http::Cookie, post, response::Redirect, FromForm};
|
||||||
|
|
||||||
use crate::library::history::VideoHistory;
|
use crate::library::history::VideoHistory;
|
||||||
use crate::pages::components::video_element_wide;
|
use crate::pages::components::{video_element_wide, Title};
|
||||||
|
|
||||||
use super::components::render_page;
|
use super::components::render_page;
|
||||||
|
|
||||||
|
@ -50,14 +50,17 @@ pub async fn login_post(login_form: Form<LoginForm>, cookies: &CookieJar<'_>) ->
|
||||||
|
|
||||||
#[get("/history")]
|
#[get("/history")]
|
||||||
pub async fn history_page(ctx: RequestContext, user: User) -> StringResponse {
|
pub async fn history_page(ctx: RequestContext, user: User) -> StringResponse {
|
||||||
let content = html! {
|
let video_elements = html! {
|
||||||
h1 class="text-center text-4xl font-extrabold leading-tight mt-4 mb-2" { "History" };
|
|
||||||
(Padding(html! {
|
|
||||||
@for mut vid in user.history_of(10).await {
|
@for mut vid in user.history_of(10).await {
|
||||||
( video_element_wide(&mut vid).await );
|
( video_element_wide(&mut vid).await );
|
||||||
};
|
};
|
||||||
}).all(ScreenValue::_6))
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let content = Div()
|
||||||
|
.vanish()
|
||||||
|
.push(Title("History"))
|
||||||
|
.push(Padding(video_elements).all(ScreenValue::_6))
|
||||||
|
.render();
|
||||||
|
|
||||||
render_page(ctx, content, "History", Some(user)).await
|
render_page(ctx, content, "History", Some(user)).await
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ use maud::{html, PreEscaped, Render};
|
||||||
use rocket::{get, State};
|
use rocket::{get, State};
|
||||||
|
|
||||||
use crate::library::Video;
|
use crate::library::Video;
|
||||||
use crate::yt_meta::YouTubeMeta;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
library::{history::VideoHistory, Library},
|
library::{history::VideoHistory, Library},
|
||||||
pages::components::video_element_wide,
|
pages::components::video_element_wide,
|
||||||
|
@ -44,22 +43,20 @@ pub async fn watch_page(
|
||||||
Flex(
|
Flex(
|
||||||
Div().vanish()
|
Div().vanish()
|
||||||
.push(
|
.push(
|
||||||
Margin(
|
|
||||||
Screen::large(Width(Fraction::_10on12, Nothing())).on(
|
Screen::large(Width(Fraction::_10on12, Nothing())).on(
|
||||||
Div().push(
|
Div().push(
|
||||||
Context(Aspect::video(
|
Context(Aspect::Video(
|
||||||
Background(
|
Background(
|
||||||
Rounded(
|
Rounded(
|
||||||
html! {
|
Width(ScreenValue::full,
|
||||||
video
|
Height(ScreenValue::full,
|
||||||
controls
|
Rounded(
|
||||||
autoplay
|
Video().controls().autoplay().add_src(
|
||||||
class="w-full h-full rounded-lg" {
|
Source(&format!("/video/raw?v={}", video.id), Some("video/mp4".to_string()))
|
||||||
source src=(format!("/video/raw?v={}", video.id)) type="video/mp4" {
|
)
|
||||||
"Your browser does not support the video"
|
).size(Size::Large)
|
||||||
};
|
)
|
||||||
};
|
)
|
||||||
}
|
|
||||||
).size(Size::Large)
|
).size(Size::Large)
|
||||||
).color(Colors::Black)
|
).color(Colors::Black)
|
||||||
))
|
))
|
||||||
|
@ -94,15 +91,14 @@ pub async fn watch_page(
|
||||||
)
|
)
|
||||||
)).size(Size::Large)
|
)).size(Size::Large)
|
||||||
).color(Stone::_900)
|
).color(Stone::_900)
|
||||||
).all(ScreenValue::_4)).top(ScreenValue::_8))
|
).all(ScreenValue::_4)).top(ScreenValue::_4))
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
).top(ScreenValue::_10)
|
|
||||||
).push(
|
).push(
|
||||||
rec
|
rec
|
||||||
)
|
)
|
||||||
).direction(Direction::Column).gap(ScreenValue::_6))
|
).direction(Direction::Column).gap(ScreenValue::_6))
|
||||||
).x(ScreenValue::auto).top(ScreenValue::_6)
|
).x(ScreenValue::_10).top(ScreenValue::_6)
|
||||||
).render();
|
).render();
|
||||||
|
|
||||||
render_page(
|
render_page(
|
||||||
|
|
Loading…
Add table
Reference in a new issue