💄 update
All checks were successful
ci/woodpecker/push/build Pipeline was successful

This commit is contained in:
JMARyA 2025-02-09 01:05:00 +01:00
parent 7aed380e21
commit 77f1c27981
Signed by: jmarya
GPG key ID: 901B2ADDF27C2263
4 changed files with 125 additions and 80 deletions

6
Cargo.lock generated
View file

@ -152,7 +152,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
[[package]]
name = "based"
version = "0.1.0"
source = "git+https://git.hydrar.de/jmarya/based?branch=ui#1e0ab7e0dcd42c304146376176d15ff34784bb34"
source = "git+https://git.hydrar.de/jmarya/based?branch=ui#cdaabccd9eb701c5f0050def9706fc167137a481"
dependencies = [
"bcrypt",
"chrono",
@ -257,9 +257,9 @@ checksum = "f61dac84819c6588b558454b194026eb1f09c293b9036ae9b159e74e73ab6cf9"
[[package]]
name = "cc"
version = "1.2.12"
version = "1.2.13"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "755717a7de9ec452bf7f3f1a3099085deabd7f2962b861dae91ecd7a365903d2"
checksum = "c7777341816418c02e033934a09f20dc0ccaf65a5201ef8a450ae0105a573fda"
dependencies = [
"shlex",
]

View file

@ -27,3 +27,7 @@ contact.email = "mail@example.com"
[project.sub.name]
name = "Sub Project"
description = "Sub Project"
[project.sub.name.sub.subname]
name = "Sub Sub Project"
description = "Sub Sub Project"

View file

@ -29,3 +29,15 @@ impl Config {
toml::from_str(&content).unwrap()
}
}
pub fn get_prj(c: &ProjectConfig, path: &str) -> Option<Project> {
let paths: Vec<_> = path.split("/").filter(|x| !x.is_empty()).collect();
let name = paths.first()?.to_string();
if paths.len() == 1 {
return c.get(&name).cloned();
} else {
let sub_prj = c.get(&name)?.sub.as_ref()?;
get_prj(sub_prj, &paths[1..].join("/"))
}
}

View file

@ -3,12 +3,12 @@ use std::path::Path;
use based::asset::AssetRoutes;
use based::page;
use based::request::{RequestContext, StringResponse};
use based::ui::components::{Shell, Tabs};
use based::ui::components::{Breadcrumb, Shell, Tabs};
use based::ui::prelude::*;
use based::ui::primitives::flex::Row;
use based::ui::primitives::Optional;
use config::{Project, ProjectConfig};
use maud::Render;
use config::{get_prj, Project, ProjectConfig};
use maud::{PreEscaped, Render};
use rocket::fs::NamedFile;
use rocket::request::FromSegments;
use rocket::{get, launch, routes, State};
@ -61,11 +61,10 @@ pub async fn project_page(
) -> Option<StringResponse> {
let mut prj = c.get(path.segments.first()?);
for p in &path.segments[1..] {
println!(" --> {p}");
prj = prj.as_ref()?.sub.as_ref()?.get(p);
}
Some(render_project(shell, ctx, prj?, path.to_str()).await)
Some(render_project(shell, ctx, prj?, c, path.to_str()).await)
}
#[get("/static/<file>")]
@ -85,100 +84,130 @@ pub async fn main_page(
let first = keys.first().unwrap();
let prj = c.get(*first).unwrap();
render_project(shell, ctx, prj, format!("{first}/")).await
render_project(shell, ctx, prj, c, format!("{first}/")).await
} else {
// TODO : root project overview
site::gen_site(c, ctx).await
}
}
pub fn info_tab(prj: &Project, root: &str) -> PreEscaped<String> {
Flex(
Div()
.vanish()
.push(Rounded(
Background(Padding(Code(&prj.description)).all(ScreenValue::_4)).color(Gray::_900),
))
.push(Optional(prj.website.as_deref(), |website| {
Link(website, Text(&format!("Website: {website}")))
}))
.push(Optional(prj.documentation.as_deref(), |docs| {
Link(docs, Text(&format!("Documentation: {docs}")))
}))
.push(Optional(prj.since.as_deref(), |since| {
Text(&format!("Since: {since}"))
}))
.push(Optional(prj.contact.as_ref(), |contact| {
Div()
.vanish()
.push(Text("Contact").large())
.push(Text(&format!(
"eMail: {}",
contact
.email
.as_ref()
.map(|x| x.as_str())
.unwrap_or_default()
)))
}))
.push(Optional(prj.sub.as_ref(), |sub| {
let mut prj_links = Vec::new();
for key in sub.keys() {
prj_links.push(key);
}
Div()
.vanish()
.push(Text("Sub projects").large())
.push_for_each(&prj_links, |link: &_| {
Width(
ScreenValue::fit,
Button(Link(
&format!("/prj/{root}{link}"),
Text(&prj.sub.as_ref().unwrap().get(*link).unwrap().name),
)),
)
})
})),
)
.gap(ScreenValue::_2)
.direction(Direction::Column)
.render()
}
fn up_to(keyword: &str, v: &[&str], separator: &str) -> String {
let index = v.iter().position(|s| *s == keyword).unwrap_or(v.len());
v[..index + 1].join(separator)
}
#[allow(non_snake_case)]
pub fn ProjectIcon(prj: &Project) -> PreEscaped<String> {
Row(vec![
Optional(prj.icon.as_ref(), |icon| Image(icon).alt("Project Icon")),
Text(&prj.name)._2xl().render(),
])
.gap(ScreenValue::_4)
.full_center()
.render()
}
pub async fn render_project(
shell: &State<Shell>,
ctx: RequestContext,
prj: &Project,
root: String,
c: &State<ProjectConfig>,
mut root: String,
) -> StringResponse {
let title = format!("{} - Umbrella ☂️", prj.name);
if !root.is_empty() && !root.ends_with('/') {
root.push_str("/");
}
let root_paths: Vec<_> = root.split("/").filter(|x| !x.is_empty()).collect();
let bc: Vec<_> = root_paths
.iter()
.map(|x| {
let prj_path = up_to(x, &root_paths, "/");
(
ProjectIcon(&get_prj(c, &prj_path).unwrap()).0,
format!("/prj/{}", prj_path),
)
})
.collect();
println!("{bc:?}");
page!(
shell,
ctx,
title,
Div()
.vanish()
.push(
Margin(
Row(vec![
Optional(prj.icon.as_ref(), |icon| Image(icon).alt("Project Icon")),
Text(&prj.name)._2xl().render()
])
.gap(ScreenValue::_4)
.full_center()
)
.top(ScreenValue::_6)
.bottom(ScreenValue::_2)
)
.push(Width(
ScreenValue::fit,
Margin(Breadcrumb(bc))
.top(ScreenValue::_6)
.bottom(ScreenValue::_2)
.x(ScreenValue::auto)
))
.push(
Padding(
Tabs()
.add_tab(
"info",
Text("📜 Info").medium(),
Flex(
Div()
.vanish()
.push(Text(&prj.description))
.push(Optional(prj.website.as_deref(), |website| Link(
website,
Text(&format!("Website: {website}"))
)))
.push(Optional(prj.documentation.as_deref(), |docs| Link(
docs,
Text(&format!("Documentation: {docs}"))
)))
.push(Optional(prj.since.as_deref(), |since| Text(&format!(
"Since: {since}"
))))
.push(Optional(prj.contact.as_ref(), |contact| {
Div().vanish().push(Text("Contact").large()).push(Text(
&format!(
"eMail: {}",
contact
.email
.as_ref()
.map(|x| x.as_str())
.unwrap_or_default()
),
))
}))
.push(Optional(prj.sub.as_ref(), |sub| {
let mut prj_links = Vec::new();
for key in sub.keys() {
prj_links.push(key);
}
Div()
.vanish()
.push(Text("Sub projects").large())
.push_for_each(&prj_links, |link: &_| {
Link(
&format!("/prj/{root}{link}"),
Text(
&prj.sub
.as_ref()
.unwrap()
.get(*link)
.unwrap()
.name,
),
)
})
}))
)
.gap(ScreenValue::_2)
.direction(Direction::Column)
)
.add_tab("info", Text("📜 Info").medium(), info_tab(prj, &root))
.add_tab(
"invest",
Text("💵 Invest").medium(),