finish ui
This commit is contained in:
parent
36128864aa
commit
6c1ca1e8c0
4 changed files with 421 additions and 262 deletions
10
Cargo.lock
generated
10
Cargo.lock
generated
|
@ -202,7 +202,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#78e3d6b798eb32d85ab58dd8891457f7ab6f75aa"
|
source = "git+https://git.hydrar.de/jmarya/based?branch=ui#79f08fd202abcfbc52cbab09be7dccc02f4c7c01"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"chrono",
|
"chrono",
|
||||||
|
@ -313,9 +313,9 @@ checksum = "a3e368af43e418a04d52505cf3dbc23dda4e3407ae2fa99fd0e4f308ce546acc"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cc"
|
name = "cc"
|
||||||
version = "1.2.9"
|
version = "1.2.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b"
|
checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"jobserver",
|
"jobserver",
|
||||||
"libc",
|
"libc",
|
||||||
|
@ -3364,9 +3364,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "valuable"
|
name = "valuable"
|
||||||
version = "0.1.0"
|
version = "0.1.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d"
|
checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "vcpkg"
|
name = "vcpkg"
|
||||||
|
|
|
@ -2,7 +2,7 @@ use based::auth::MaybeUser;
|
||||||
use based::request::{RawResponse, RequestContext, StringResponse, respond_with};
|
use based::request::{RawResponse, RequestContext, StringResponse, respond_with};
|
||||||
use based::ui::components::Shell;
|
use based::ui::components::Shell;
|
||||||
use based::ui::{prelude::*, render_page};
|
use based::ui::{prelude::*, render_page};
|
||||||
use maud::{PreEscaped, html};
|
use maud::{PreEscaped, Render, html};
|
||||||
use pacco::pkg::mirror::MirrorRepository;
|
use pacco::pkg::mirror::MirrorRepository;
|
||||||
use rocket::http::{ContentType, Status};
|
use rocket::http::{ContentType, Status};
|
||||||
use rocket::{State, get};
|
use rocket::{State, get};
|
||||||
|
@ -24,35 +24,39 @@ pub async fn index_page(
|
||||||
) -> StringResponse {
|
) -> StringResponse {
|
||||||
let repos: Vec<String> = Repository::list();
|
let repos: Vec<String> = Repository::list();
|
||||||
|
|
||||||
let content = html!(
|
let content = Div().vanish()
|
||||||
(Flex(html! {
|
.push(
|
||||||
h1 class="text-4xl font-bold pb-6" { "Repositories" };
|
Flex(
|
||||||
@if let Some(user) = user.take_user() {
|
Div().vanish()
|
||||||
a class="text-lg" href="/account" { (user.username) };
|
.push(Padding(Text("Repositories")._4xl().bold()).bottom(ScreenValue::_6))
|
||||||
};
|
.push_some(user.take_user().as_ref(), |user: &based::auth::User| Link("/account", Text(&user.username).large()))
|
||||||
}).justify(Justify::Between))
|
).justify(Justify::Between)
|
||||||
|
).push(
|
||||||
|
html!(
|
||||||
div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6" {
|
div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-6" {
|
||||||
@for repo in repos {
|
@for repo in repos {
|
||||||
// TODO : Implement class transition
|
(Animated(
|
||||||
(Link(&format!("/{repo}"),
|
|
||||||
Rounded(
|
Rounded(
|
||||||
Padding(
|
Padding(
|
||||||
Shadow::medium(
|
Shadow::medium(
|
||||||
Flex(Hover(
|
Flex(Hover(
|
||||||
Background(Gray::_600, Nothing()),
|
Background(Gray::_600, Nothing())).on(
|
||||||
Background(Gray::_700,
|
Background(Gray::_700,
|
||||||
|
Link(
|
||||||
|
&format!("/{repo}"),
|
||||||
Div().vanish().push(Text(&repo).medium().color(&Gray::_100))
|
Div().vanish().push(Text(&repo).medium().color(&Gray::_100))
|
||||||
.push(html! {
|
.push_some(
|
||||||
@if config.is_mirrored_repo(&repo) {
|
if config.is_mirrored_repo(&repo) {
|
||||||
(Padding(Rounded(Background(Blue::_500, Text("Mirrored").white().medium().sm())).size(Size::Full)).x(ScreenValue::_3).y(ScreenValue::_1))
|
Some(&())
|
||||||
};
|
} else { None },
|
||||||
})
|
|_: &()| Context(Padding(Rounded(Background(Blue::_500, Text("Mirrored").white().medium().sm())).size(Size::Full)).x(ScreenValue::_3).y(ScreenValue::_1)))).use_htmx()
|
||||||
))).items_center().gap(4))).all(ScreenValue::_4))
|
))).items_center().gap(ScreenValue::_4)
|
||||||
|
)).all(ScreenValue::_4))
|
||||||
.size(Size::Large)))
|
.size(Size::Large)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
);
|
)
|
||||||
|
).render();
|
||||||
|
|
||||||
render(content, "Repositories", ctx).await
|
render(content, "Repositories", ctx).await
|
||||||
}
|
}
|
||||||
|
|
543
src/routes/ui.rs
543
src/routes/ui.rs
|
@ -1,5 +1,8 @@
|
||||||
use based::request::{RequestContext, StringResponse};
|
use based::request::{RequestContext, StringResponse};
|
||||||
use based::ui::prelude::*;
|
use based::ui::primitives::flex::Strategy;
|
||||||
|
use based::ui::primitives::space::SpaceBetweenWidget;
|
||||||
|
use based::ui::primitives::text::{Code, TextWidget};
|
||||||
|
use based::ui::{UIWidget, prelude::*};
|
||||||
use maud::{PreEscaped, Render, html};
|
use maud::{PreEscaped, Render, html};
|
||||||
use rocket::{State, get};
|
use rocket::{State, get};
|
||||||
|
|
||||||
|
@ -35,150 +38,212 @@ pub async fn pkg_ui(
|
||||||
let binaries = pkg.binaries();
|
let binaries = pkg.binaries();
|
||||||
let mut pkginfo = pkg.pkginfo();
|
let mut pkginfo = pkg.pkginfo();
|
||||||
|
|
||||||
let content = html! {
|
let content = Div().vanish()
|
||||||
|
.push(
|
||||||
|
Flex(
|
||||||
// Package Name
|
// Package Name
|
||||||
div class="flex flex-wrap gap-2 justify-center items-center" {
|
Div().vanish()
|
||||||
(Link(&format!("/{}", repo.name),
|
.push(
|
||||||
|
Link(&format!("/{}", repo.name),
|
||||||
Text(&repo.name).bold().color(&Gray::_100)._3xl()
|
Text(&repo.name).bold().color(&Gray::_100)._3xl()
|
||||||
).use_htmx())
|
).use_htmx()
|
||||||
|
)
|
||||||
p class="font-bold p-2 text-gray-400" { "/" };
|
.push(Padding(Text("/").bold().color(&Gray::_400)).all(ScreenValue::_2))
|
||||||
h1 class="text-3xl font-bold text-gray-800 dark:text-gray-100 pr-2" {
|
.push(
|
||||||
(pkg.name)
|
Padding(Text(&pkg.name)._3xl().bold().color(&Gray::_100)).right(ScreenValue::_2)
|
||||||
};
|
)
|
||||||
|
.push_if(pkg.is_signed(), || {
|
||||||
@if pkg.is_signed() {
|
Flex(
|
||||||
div class="flex items-center gap-2 text-slate-300 pr-4" {
|
Padding(
|
||||||
(Span("✓")._2xl().bold())
|
Div().vanish()
|
||||||
(Span("Signed").sm().medium())
|
.push(Span("✓")._2xl().bold().color(&Slate::_300))
|
||||||
|
.push(Span("Signed").sm().medium().color(&Slate::_300))
|
||||||
// TODO : Add more info: Who signed? + Public Key recv
|
// TODO : Add more info: Who signed? + Public Key recv
|
||||||
}
|
).right(ScreenValue::_4)
|
||||||
}
|
).items_center().gap(ScreenValue::_2)
|
||||||
|
})
|
||||||
@for arch in arch {
|
.push_for_each(&arch, |arch: &Architecture| {
|
||||||
(Rounded(
|
Rounded(
|
||||||
Padding(
|
Padding(
|
||||||
Background(Gray::_700,
|
Background(Gray::_700,
|
||||||
Span(&arch.to_string()).medium().sm())
|
Span(&arch.to_string()).medium().sm())
|
||||||
).x(ScreenValue::_3).y(ScreenValue::_1)
|
).x(ScreenValue::_3).y(ScreenValue::_1)
|
||||||
).size(Size::Full)
|
).size(Size::Full)
|
||||||
)
|
})
|
||||||
}
|
.push(Margin(
|
||||||
|
Flex(
|
||||||
a href=(format!("/pkg/{}/{}/{}", pkg.repo, pkg.arch.to_string(), pkg.file_name())) class="ml-4 inline-flex items-center px-2 py-2 bg-gray-200 text-black font-xs rounded-lg shadow-md hover:bg-gray-300 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-opacity-50" {
|
Padding(
|
||||||
|
Hover(Background(Gray::_300, Nothing())).on(Background(Gray::_200,
|
||||||
|
Rounded(Shadow::medium(
|
||||||
|
Link(&format!("/pkg/{}/{}/{}", pkg.repo, pkg.arch.to_string(), pkg.file_name()),
|
||||||
|
Paragraph(
|
||||||
|
html! {
|
||||||
svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" {
|
svg class="w-5 h-5" xmlns="http://www.w3.org/2000/svg" fill="none" stroke="currentColor" viewBox="0 0 24 24" stroke-width="2" {
|
||||||
path stroke-linecap="round" stroke-linejoin="round" d="M12 5v14m7-7l-7 7-7-7" {};
|
path stroke-linecap="round" stroke-linejoin="round" d="M12 5v14m7-7l-7 7-7-7" {};
|
||||||
};
|
};
|
||||||
p class="ml-2" { "Download" };
|
p class="ml-2 text-black" { "Download" };
|
||||||
};
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
div class="flex flex-wrap pt-6" {
|
|
||||||
div class="space-y-2 p-4 bg-gray-50 dark:bg-gray-800 shadow-lg rounded-lg transition flex-1 m-2 grow" {
|
|
||||||
h2 class="text-xl font-semibold text-gray-700 dark:text-gray-300 underline" { "Info" };
|
|
||||||
|
|
||||||
@if let Some(desc) = take_out(&mut pkginfo, |x| { x.0 == "pkgdesc" }).1 {
|
|
||||||
(build_info(desc.0, desc.1))
|
|
||||||
}
|
}
|
||||||
|
).black().xs()))).size(Size::Large)
|
||||||
@if let Some(desc) = take_out(&mut pkginfo, |x| { x.0 == "packager" }).1 {
|
))
|
||||||
(build_info(desc.0, desc.1))
|
).x(ScreenValue::_2).y(ScreenValue::_2)
|
||||||
}
|
).items_center()
|
||||||
|
).left(ScreenValue::_4)
|
||||||
@if let Some(desc) = take_out(&mut pkginfo, |x| { x.0 == "url" }).1 {
|
)
|
||||||
(build_info(desc.0, desc.1))
|
).wrap(Wrap::Wrap).gap(ScreenValue::_2).full_center().group()
|
||||||
}
|
)
|
||||||
|
.push(
|
||||||
@if let Some(desc) = take_out(&mut pkginfo, |x| { x.0 == "size" }).1 {
|
Padding(
|
||||||
(build_info(desc.0, desc.1))
|
Flex(
|
||||||
}
|
Div().vanish().push(
|
||||||
|
Context(
|
||||||
@for (key, val) in pkginfo {
|
FlexGrow(Strategy::Grow,
|
||||||
(build_info(key, val))
|
Animated(Background(Gray::_800, Shadow::large(Rounded(Margin(Padding(SpaceBetween(
|
||||||
};
|
Div()
|
||||||
};
|
.push(
|
||||||
|
Context(Text("Info").xl().semibold().color(&Gray::_300).underlined())
|
||||||
div class="space-y-2 p-4 bg-gray-50 dark:bg-gray-800 shadow-lg rounded-lg transition m-2 grow md:grow-0 md:shrink" {
|
)
|
||||||
h2 class="text-xl font-semibold text-gray-700 dark:text-gray-300" { "Versions" }
|
.push_some(
|
||||||
ul class="space-y-1" {
|
take_out(&mut pkginfo, |x| { x.0 == "pkgdesc" }).1,
|
||||||
@for version in versions {
|
|x: (String, String)| build_info(x.0, x.1)
|
||||||
li class="text-gray-800 dark:text-gray-100 hover:text-blue-500 dark:hover:text-blue-400 transition" {
|
)
|
||||||
(Link(&format!("/{}/{}?ver={version}", repo.name, &pkg.name),
|
.push_some(
|
||||||
|
take_out(&mut pkginfo, |x| { x.0 == "packager" }).1,
|
||||||
|
|x: (String, String)| build_info(x.0, x.1)
|
||||||
|
)
|
||||||
|
.push_some(
|
||||||
|
take_out(&mut pkginfo, |x| { x.0 == "url" }).1,
|
||||||
|
|x: (String, String)| build_info(x.0, x.1)
|
||||||
|
)
|
||||||
|
.push_some(
|
||||||
|
take_out(&mut pkginfo, |x| { x.0 == "size" }).1,
|
||||||
|
|x: (String, String)| build_info(x.0, x.1)
|
||||||
|
)
|
||||||
|
.push_for_each(&pkginfo, |(key, val)| build_info(key.clone(), val.clone()))
|
||||||
|
).y(ScreenValue::_2)).all(ScreenValue::_4)).all(ScreenValue::_2)).size(Size::Large)))))
|
||||||
|
)).push(
|
||||||
|
SpaceBetween(
|
||||||
|
Padding(
|
||||||
|
Background(Gray::_800,
|
||||||
|
Shadow::large(
|
||||||
|
Rounded(
|
||||||
|
Margin(
|
||||||
|
Screen::medium(FlexGrow(Strategy::NoGrow, Nothing())).on(
|
||||||
|
FlexGrow(Strategy::Grow,
|
||||||
|
Div().vanish()
|
||||||
|
.push(
|
||||||
|
Text("Versions").xl().semibold().color(&Gray::_300)
|
||||||
|
)
|
||||||
|
.push(
|
||||||
|
SpaceBetween(
|
||||||
|
Div().vanish()
|
||||||
|
.push_for_each(&versions, |version: &String| {
|
||||||
|
Animated(Link(&format!("/{}/{}?ver={version}", repo.name, &pkg.name),
|
||||||
if pkg.version.as_ref()
|
if pkg.version.as_ref()
|
||||||
.map(|x| *x == Package::version(&version).0).unwrap_or_default()
|
.map(|x| *x == Package::version(&version).0).unwrap_or_default()
|
||||||
{ Text(&version).color(&Blue::_500) } else { Text(&version) }
|
{ Text(&version).color(&Blue::_500).render() } else {
|
||||||
|
Hover(Text("").color(&Blue::_400)).on(
|
||||||
|
Text(&version).color(&Gray::_100)).render()
|
||||||
|
}
|
||||||
).use_htmx())
|
).use_htmx())
|
||||||
};
|
})
|
||||||
}
|
).y(ScreenValue::_1)
|
||||||
}
|
)
|
||||||
}
|
))
|
||||||
};
|
).all(ScreenValue::_2)
|
||||||
|
).size(Size::Large)
|
||||||
div class="flex flex-wrap pt-6" {
|
)
|
||||||
div class="space-y-2" {
|
)
|
||||||
h2 class="text-xl font-bold text-gray-700 dark:text-gray-300" { "Content" }
|
).all(ScreenValue::_4)
|
||||||
|
).y(ScreenValue::_2)
|
||||||
div class="flex flex-wrap" {
|
)
|
||||||
@if !systemd_units.is_empty() {
|
).wrap(Wrap::Wrap).group()
|
||||||
div class="space-y-2 p-4 bg-gray-50 dark:bg-gray-800 shadow-lg rounded-lg transition m-2 grow" {
|
).top(ScreenValue::_6)
|
||||||
h3 class="text-lg font-medium text-gray-800 dark:text-gray-100 underline" { "Systemd Units" }
|
).push(
|
||||||
ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-1" {
|
Padding(Flex(
|
||||||
@for unit in systemd_units {
|
SpaceBetween(
|
||||||
|
Div().vanish()
|
||||||
|
.push(
|
||||||
|
Text("Content").xl().bold().color(&Gray::_300)
|
||||||
|
)
|
||||||
|
.push(
|
||||||
|
Flex(
|
||||||
|
Div().vanish()
|
||||||
|
.push_if(!systemd_units.is_empty(), || {
|
||||||
|
InfoCard(
|
||||||
|
Div().vanish()
|
||||||
|
.push(
|
||||||
|
CardTitle("Systemd Units")
|
||||||
|
)
|
||||||
|
.push(
|
||||||
|
ListElements(&systemd_units)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.push_if(!pacman_hooks.is_empty(), || {
|
||||||
|
InfoCard(
|
||||||
|
Div().vanish()
|
||||||
|
.push(CardTitle("Pacman Hooks"))
|
||||||
|
.push(
|
||||||
|
Paragraph(
|
||||||
|
SpaceBetween(
|
||||||
|
Div().vanish()
|
||||||
|
.push_for_each(&pacman_hooks, |hook: &(String, String)| {
|
||||||
|
Div().vanish()
|
||||||
|
.push(
|
||||||
|
Text(&hook.0).xl().semibold().color(&Gray::_300)
|
||||||
|
)
|
||||||
|
.push(
|
||||||
|
Padding(Rounded(Background(Gray::_700, Code(&hook.1).sm().color(&Gray::_100))).size(Size::Large)).all(ScreenValue::_4)
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.push(
|
||||||
|
html! {
|
||||||
|
@for unit in &systemd_units {
|
||||||
li { (unit) }
|
li { (unit) }
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}
|
).y(ScreenValue::_1)
|
||||||
}
|
).list_style(ListStyle::Disc).color(&Gray::_300)
|
||||||
|
)
|
||||||
@if !pacman_hooks.is_empty() {
|
)
|
||||||
div class="space-y-2 p-4 bg-gray-50 dark:bg-gray-800 shadow-lg rounded-lg transition m-2 grow" {
|
})
|
||||||
h3 class="text-lg font-medium text-gray-800 dark:text-gray-100 underline" { "Pacman Hooks" }
|
.push_if(!binaries.is_empty(),
|
||||||
ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-1" {
|
|| InfoCard(
|
||||||
@for hook in pacman_hooks {
|
Div().vanish()
|
||||||
h2 class="text-xl font-semibold text-gray-700 dark:text-gray-300" { (hook.0) }
|
.push(
|
||||||
|
CardTitle("Binaries")
|
||||||
pre class="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg text-gray-800 dark:text-gray-100 overflow-x-auto text-sm" {
|
).push(
|
||||||
(hook.1)
|
ListElements(&binaries)
|
||||||
}
|
)
|
||||||
}
|
)
|
||||||
}
|
)
|
||||||
}
|
.push(
|
||||||
}
|
InfoCard(
|
||||||
|
Div().vanish().push(
|
||||||
@if !binaries.is_empty() {
|
CardTitle("Package Files")
|
||||||
div class="space-y-2 p-4 bg-gray-50 dark:bg-gray-800 shadow-lg rounded-lg transition m-2 grow" {
|
)
|
||||||
h3 class="text-lg font-medium text-gray-800 dark:text-gray-100 underline" { "Binaries" }
|
.push(
|
||||||
ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-1" {
|
ListElements(&pkg.file_list())
|
||||||
@for binary in binaries {
|
)
|
||||||
li { (binary) }
|
)
|
||||||
}
|
)
|
||||||
}
|
).group().wrap(Wrap::Wrap)
|
||||||
}
|
)
|
||||||
}
|
).y(ScreenValue::_2)
|
||||||
|
).wrap(Wrap::Wrap).group()).top(ScreenValue::_6)
|
||||||
div class="space-y-2 p-4 bg-gray-50 dark:bg-gray-800 shadow-lg rounded-lg transition m-2 grow" {
|
).push_some(install_script.as_ref(), |install_script: &String| {
|
||||||
h3 class="text-lg font-medium text-gray-800 dark:text-gray-100 underline" { "Package Files" }
|
SpaceBetween(
|
||||||
ul class="list-disc list-inside text-gray-700 dark:text-gray-300 space-y-1" {
|
Margin(
|
||||||
@for file in pkg.file_list() {
|
Div()
|
||||||
li { (file) }
|
.push(Text("Install Script")._3xl().semibold().color(&Gray::_300).indentation(ScreenValue::_2))
|
||||||
}
|
.push(Rounded(Padding(Background(Gray::_700,
|
||||||
}
|
Code(install_script.trim())
|
||||||
}
|
.color(&Gray::_100).sm()
|
||||||
}
|
.indentation(ScreenValue::_0)
|
||||||
};
|
)).all(ScreenValue::_2)).size(Size::Large))
|
||||||
};
|
).top(ScreenValue::_6)
|
||||||
|
).y(ScreenValue::_4)
|
||||||
// Install Script
|
}).render();
|
||||||
@if let Some(install_script) = install_script {
|
|
||||||
div class="space-y-4 pt-6" {
|
|
||||||
h2 class="text-3xl font-semibold text-gray-700 dark:text-gray-300" { "Install Script" }
|
|
||||||
pre class="bg-gray-100 dark:bg-gray-700 p-4 rounded-lg text-gray-800 dark:text-gray-100 overflow-x-auto text-sm" {
|
|
||||||
(install_script)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Some(render(content, pkg_name, ctx).await)
|
Some(render(content, pkg_name, ctx).await)
|
||||||
}
|
}
|
||||||
|
@ -222,21 +287,32 @@ pub async fn repo_ui(
|
||||||
repo.list_pkg()
|
repo.list_pkg()
|
||||||
};
|
};
|
||||||
|
|
||||||
let content = html! {
|
let repo_info = Margin(
|
||||||
// Repository name and architectures
|
// Repository name and architectures
|
||||||
div class="flex flex-wrap items-center justify-center mb-6" {
|
Flex(
|
||||||
h1 class="text-3xl font-bold text-gray-800 dark:text-gray-100" {
|
Div()
|
||||||
(repo.name)
|
.vanish()
|
||||||
};
|
.push(Text(&repo.name)._3xl().bold().color(&Gray::_100))
|
||||||
|
.push_if(config.is_mirrored_repo(&repo.name), || {
|
||||||
@if config.is_mirrored_repo(&repo.name) {
|
Background(
|
||||||
div class="inline-block px-3 py-1 text-sm font-medium text-white bg-blue-500 rounded-full ml-4" { "Mirrored" };
|
Blue::_500,
|
||||||
};
|
Rounded(
|
||||||
|
Margin(
|
||||||
div class="flex gap-2 mt-2 md:mt-0 ml-4" {
|
Padding(Text("Mirrored").sm().medium().white())
|
||||||
@for a in architectures {
|
.x(ScreenValue::_3)
|
||||||
|
.y(ScreenValue::_1),
|
||||||
|
)
|
||||||
|
.left(ScreenValue::_4),
|
||||||
|
)
|
||||||
|
.size(Size::Full),
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.push(
|
||||||
|
Screen::medium(Margin(Nothing()).top(ScreenValue::_0)).on(Margin(
|
||||||
|
Flex(Div().vanish().push_for_each(&architectures, |a: &String| {
|
||||||
|
html! {
|
||||||
@if let Some(arch) = arch.as_ref() {
|
@if let Some(arch) = arch.as_ref() {
|
||||||
@if arch.to_string() == a {
|
@if arch.to_string() == *a {
|
||||||
(arch_card(&a, &repo.name, true))
|
(arch_card(&a, &repo.name, true))
|
||||||
} @else {
|
} @else {
|
||||||
(arch_card(&a, &repo.name, false))
|
(arch_card(&a, &repo.name, false))
|
||||||
|
@ -245,50 +321,92 @@ pub async fn repo_ui(
|
||||||
(arch_card(&a, &repo.name, false))
|
(arch_card(&a, &repo.name, false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}))
|
||||||
};
|
.group()
|
||||||
|
.gap(ScreenValue::_2),
|
||||||
|
)
|
||||||
|
.left(ScreenValue::_4)
|
||||||
|
.top(ScreenValue::_2)),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.wrap(Wrap::Wrap)
|
||||||
|
.full_center()
|
||||||
|
.group(),
|
||||||
|
)
|
||||||
|
.bottom(ScreenValue::_6);
|
||||||
|
|
||||||
// Package list
|
let package_list = SpaceBetween(Div().vanish().push_for_each(&packages, |pkg| {
|
||||||
ul class="space-y-4" {
|
Animated(
|
||||||
@for pkg in packages {
|
Flex(
|
||||||
(
|
Padding(
|
||||||
|
Hover(Background(Gray::_600, Nothing())).on(Background(
|
||||||
|
Gray::_700,
|
||||||
|
Rounded(Shadow::medium(
|
||||||
Link(
|
Link(
|
||||||
&format!("/{}/{pkg}", repo.name),
|
&format!("/{}/{pkg}", repo.name),
|
||||||
// TODO : Implement transition class
|
Div()
|
||||||
|
.vanish()
|
||||||
|
.push(Context(Sized(
|
||||||
|
ScreenValue::_10,
|
||||||
|
ScreenValue::_10,
|
||||||
|
Rounded(Background(
|
||||||
|
Blue::_500,
|
||||||
Flex(
|
Flex(
|
||||||
|
Text(
|
||||||
|
&pkg.chars()
|
||||||
|
.next()
|
||||||
|
.unwrap_or_default()
|
||||||
|
.to_uppercase()
|
||||||
|
.to_string(),
|
||||||
|
)
|
||||||
|
.white()
|
||||||
|
.semibold(),
|
||||||
|
)
|
||||||
|
.full_center()
|
||||||
|
.group(),
|
||||||
|
))
|
||||||
|
.size(Size::Full),
|
||||||
|
)))
|
||||||
|
.push(Context(Width(
|
||||||
|
ScreenValue::fit,
|
||||||
|
Text(&pkg).medium().color(&Gray::_100),
|
||||||
|
)))
|
||||||
|
.push(Context(
|
||||||
Padding(
|
Padding(
|
||||||
Hover(
|
Flex(
|
||||||
Background(Gray::_600, Nothing()),
|
Div()
|
||||||
Background(Gray::_700,
|
.vanish()
|
||||||
Rounded(
|
|
||||||
Shadow::medium(
|
|
||||||
Div().vanish()
|
|
||||||
.push(
|
.push(
|
||||||
html! { (Sized(ScreenValue::_10, ScreenValue::_10, Rounded(
|
Span("✓")._2xl().bold().color(&Slate::_300),
|
||||||
Background(Blue::_500, Flex(Text(
|
|
||||||
&pkg.chars().next().unwrap_or_default().to_uppercase().to_string()
|
|
||||||
).white().semibold()).full_center().group()
|
|
||||||
)).size(Size::Full))) }
|
|
||||||
)
|
)
|
||||||
.push(html! { (Width(ScreenValue::fit, Text(&pkg).medium().color(&Gray::_100))) })
|
.push(
|
||||||
.push(html! {
|
Span("Signed")
|
||||||
(
|
.sm()
|
||||||
Flex(
|
.medium()
|
||||||
Padding(
|
.color(&Slate::_300),
|
||||||
Div().vanish()
|
),
|
||||||
.push(Span("✓")._2xl().bold().color(&Slate::_300))
|
|
||||||
.push(Span("Signed").sm().medium().color(&Slate::_300))
|
|
||||||
).right(ScreenValue::_4)
|
|
||||||
).items_center().gap(2).group()
|
|
||||||
)
|
)
|
||||||
})
|
.items_center()
|
||||||
|
.gap(ScreenValue::_2)
|
||||||
|
.group(),
|
||||||
)
|
)
|
||||||
).size(Size::Large)))).all(ScreenValue::_4)).items_center().gap(4)
|
.right(ScreenValue::_4),
|
||||||
).use_htmx()
|
)),
|
||||||
)
|
)
|
||||||
}
|
.use_htmx(),
|
||||||
}
|
))
|
||||||
};
|
.size(Size::Large),
|
||||||
|
)),
|
||||||
|
)
|
||||||
|
.all(ScreenValue::_4),
|
||||||
|
)
|
||||||
|
.items_center()
|
||||||
|
.gap(ScreenValue::_4),
|
||||||
|
)
|
||||||
|
}))
|
||||||
|
.y(ScreenValue::_4);
|
||||||
|
|
||||||
|
let content = Div().vanish().push(repo_info).push(package_list).render();
|
||||||
|
|
||||||
render(content, &repo.name, ctx).await
|
render(content, &repo.name, ctx).await
|
||||||
}
|
}
|
||||||
|
@ -307,12 +425,16 @@ pub fn build_info(key: String, value: String) -> PreEscaped<String> {
|
||||||
return key_value("Packager".to_string(), value);
|
return key_value("Packager".to_string(), value);
|
||||||
}
|
}
|
||||||
"url" => {
|
"url" => {
|
||||||
return html! {
|
return Flex(
|
||||||
div class="flex" {
|
Div()
|
||||||
span class="font-bold w-32" { (format!("Website: ")) };
|
.vanish()
|
||||||
a class="ml-2 text-blue-400" href=(value) { (value) };
|
.push(Width(ScreenValue::_32, Span("Website: ").bold()))
|
||||||
};
|
.push(
|
||||||
};
|
Margin(Link(&value, Span(&value).color(&Blue::_400))).left(ScreenValue::_6),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.group()
|
||||||
|
.render();
|
||||||
}
|
}
|
||||||
"builddate" => {
|
"builddate" => {
|
||||||
let date = chrono::DateTime::from_timestamp(value.parse().unwrap(), 0).unwrap();
|
let date = chrono::DateTime::from_timestamp(value.parse().unwrap(), 0).unwrap();
|
||||||
|
@ -349,7 +471,7 @@ pub fn key_value(key: String, value: String) -> PreEscaped<String> {
|
||||||
Div()
|
Div()
|
||||||
.vanish()
|
.vanish()
|
||||||
.push(Width(ScreenValue::_32, Span(&format!("{key}: ")).bold()))
|
.push(Width(ScreenValue::_32, Span(&format!("{key}: ")).bold()))
|
||||||
.push(Margin(Span(&value)).left(ScreenValue::_2)),
|
.push(Margin(Span(&value)).left(ScreenValue::_6)),
|
||||||
)
|
)
|
||||||
.items_center()
|
.items_center()
|
||||||
.group()
|
.group()
|
||||||
|
@ -384,24 +506,57 @@ pub fn find_pkg_url(pkg: &str) -> Option<String> {
|
||||||
pub fn pkg_list_info(key: &str, value: &str) -> PreEscaped<String> {
|
pub fn pkg_list_info(key: &str, value: &str) -> PreEscaped<String> {
|
||||||
let pkgs = value.split_whitespace().map(|pkg| {
|
let pkgs = value.split_whitespace().map(|pkg| {
|
||||||
if let Some(pkg_url) = find_pkg_url(pkg) {
|
if let Some(pkg_url) = find_pkg_url(pkg) {
|
||||||
html! {
|
Margin(Link(&pkg_url, Text(&pkg).color(&Blue::_400)).use_htmx()).left(ScreenValue::_6)
|
||||||
a href=(pkg_url) class="ml-2 text-blue-400" { (pkg) };
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
html! {
|
Margin(Span(&pkg)).left(ScreenValue::_6)
|
||||||
span class="ml-2" { (pkg) };
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
(Flex(html! {
|
(Flex(
|
||||||
span class="font-bold w-32" { (format!("{key}: ")) };
|
Div().vanish()
|
||||||
div class="flex flex-wrap" {
|
.push(Width(ScreenValue::_32, Span(&format!("{key}: ")).bold()))
|
||||||
|
.push(Flex(
|
||||||
|
html! {
|
||||||
@for pkg in pkgs {
|
@for pkg in pkgs {
|
||||||
(pkg)
|
(pkg)
|
||||||
};
|
|
||||||
};
|
|
||||||
}).items_center().group())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
).group().wrap(Wrap::Wrap))
|
||||||
|
).items_center().group())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn ListElements(el: &[String]) -> TextWidget {
|
||||||
|
Paragraph(
|
||||||
|
SpaceBetween(html! {
|
||||||
|
@for unit in el {
|
||||||
|
li { (unit) }
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.y(ScreenValue::_1),
|
||||||
|
)
|
||||||
|
.list_style(ListStyle::Disc)
|
||||||
|
.color(&Gray::_300)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn CardTitle(title: &str) -> PreEscaped<String> {
|
||||||
|
Context(Text(title).large().medium().color(&Gray::_100).underlined())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub fn InfoCard<T: UIWidget + 'static>(inner: T) -> SpaceBetweenWidget {
|
||||||
|
SpaceBetween(
|
||||||
|
Padding(Background(
|
||||||
|
Gray::_800,
|
||||||
|
Shadow::large(
|
||||||
|
Rounded(Margin(FlexGrow(Strategy::Grow, inner)).all(ScreenValue::_2))
|
||||||
|
.size(Size::Large),
|
||||||
|
),
|
||||||
|
))
|
||||||
|
.all(ScreenValue::_4),
|
||||||
|
)
|
||||||
|
.y(ScreenValue::_2)
|
||||||
|
}
|
||||||
|
|
|
@ -128,7 +128,7 @@ pub async fn account_page(user: User, ctx: RequestContext) -> StringResponse {
|
||||||
(Link("/passwd", Margin(
|
(Link("/passwd", Margin(
|
||||||
Rounded(Padding(
|
Rounded(Padding(
|
||||||
Hover(
|
Hover(
|
||||||
Background(Green::_600, Nothing()),
|
Background(Green::_600, Nothing())).on(
|
||||||
Background(Green::_500, Text("Change Password").white())
|
Background(Green::_500, Text("Change Password").white())
|
||||||
)
|
)
|
||||||
).x(ScreenValue::_6).y(ScreenValue::_2))
|
).x(ScreenValue::_6).y(ScreenValue::_2))
|
||||||
|
|
Loading…
Add table
Reference in a new issue