start work on admin cp

This commit is contained in:
Hamcha 2025-02-09 14:13:34 +01:00
parent 2941690f0a
commit bd32c02e2c
Signed by: hamcha
GPG key ID: 1669C533B8CF6D89
6 changed files with 94 additions and 8 deletions
Dioxus.toml
assets
admin/style
renderer/style
src/inbound/renderer

View file

@ -12,7 +12,7 @@ reload_html = true
watch_path = ["src", "assets"]
[web.resource]
style = ["/assets/style/main.css"]
style = []
script = []
[web.resource.dev]

View file

@ -0,0 +1,15 @@
@import url(https://rsms.me/inter/inter.css);
:root {
background-color: #312337;
color: #fff6fe;
font-family: Inter, sans-serif;
/* fix for Chrome */
font-feature-settings: 'liga' 1, 'calt' 1;
}
a,
a:visited {
color: #f0cf96;
}

View file

@ -2,12 +2,16 @@ use dioxus::prelude::*;
mod server;
#[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Routable, Debug, PartialEq)]
#[rustfmt::skip]
enum Route {
#[layout(AdminLayout)]
#[route("/")]
Home {},
#[nest("/site")]
#[route("/:domain")]
Site { domain: String },
}
pub fn App() -> Element {
@ -16,24 +20,33 @@ pub fn App() -> Element {
}
}
#[component]
fn Home() -> Element {
rsx! {
h2 { "Hello!" }
SuspenseBoundary { fallback: |_context: SuspenseContext| rsx! { "Loading sites..." }, SiteList {} }
}
}
#[component]
fn SiteList() -> Element {
let sites = use_server_future(server::site_list)?.suspend()?;
rsx! {
h3 { "Sites" }
button { "New site" }
match &*sites.read() {
Ok(sites) => {
rsx! {
ul {
for site in sites {
li { "{site.domain} - {site.title}" }
li {
Link {
to: Route::Site {
domain: site.domain.clone(),
},
"{site.domain} - {site.title}"
}
}
}
}
}
@ -47,9 +60,35 @@ fn SiteList() -> Element {
}
}
#[component]
fn Site(domain: String) -> Element {
let site = use_server_future(move || server::get_site(domain.clone()))?.suspend()?;
let info = match &*site.read() {
Ok(site) => site.clone(),
Err(err) => {
return rsx! {
h1 { "Error: {err}" }
}
}
};
rsx! {
h1 { "{info.title}" }
}
}
static CSS: Asset = asset!("/assets/admin/style/main.css");
#[component]
fn AdminLayout() -> Element {
rsx! {
h1 { "Admin UI" }
document::Stylesheet { href: CSS }
header { "data-test-id": "admin-ui",
div {
Link { to: Route::Home {}, "Administration panel" }
}
}
SuspenseBoundary { fallback: |_context: SuspenseContext| rsx! { "..." },
main { Outlet::<Route> {} }
}
@ -69,7 +108,7 @@ mod tests {
fn site_list_shows_sites() {
let mut app = VirtualDom::new(|| {
rsx! {
SiteList {}
Router::<Route> {}
}
});

View file

@ -18,3 +18,17 @@ pub async fn site_list() -> Result<Vec<SiteInfo>, ServerFnError> {
})
.collect())
}
#[server]
pub async fn get_site(domain: String) -> Result<SiteInfo, ServerFnError> {
use crate::outbound::services::site::SiteServiceProvider;
let FromContext(SiteServiceProvider { service }) = extract().await?;
let site = service.get_site(&domain).await?;
Ok(SiteInfo {
domain: site.domain.clone(),
title: site.title.clone(),
pages: vec![],
})
}

View file

@ -15,7 +15,7 @@ mod server;
#[cfg(test)]
mod testing;
#[derive(Clone, Routable, Debug, PartialEq, serde::Serialize, serde::Deserialize)]
#[derive(Clone, Routable, Debug, PartialEq)]
#[rustfmt::skip]
enum Route {
#[layout(SiteLayout)]
@ -31,6 +31,7 @@ enum Route {
PageNotFound { route: Vec<String> },
}
#[component]
pub fn App() -> Element {
// Check for special redirects
let site_res = use_server_future(server::get_site_info)?.suspend()?;
@ -79,12 +80,15 @@ fn PageLink(page: String, title: String, current: Route) -> Element {
}
}
static CSS: Asset = asset!("/assets/renderer/style/main.css");
#[component]
fn SiteLayout() -> Element {
let site = meta::site();
let route = use_route::<Route>();
rsx! {
document::Stylesheet { href: CSS }
header { class: "site-header",
nav { class: "page-list",
ul {
@ -228,6 +232,20 @@ mod tests {
})
})
});
mock_service.expect_get_page().times(1).returning(|_, _| {
Box::pin(async {
Ok(entities::site::Page {
info: entities::site::PageInfo {
title: "Test page".to_string(),
name: "/".to_string(),
order: 0,
},
content: PageContent::Single {
content: entities::site::Post { blocks: vec![] },
},
})
})
});
server_context().insert(AppConfig {
admin_host: "admin.local".to_string(),
@ -337,6 +355,6 @@ mod tests {
app.rebuild_in_place();
let elem_str = dioxus::ssr::render(&app);
println!("elem_str: {elem_str}");
assert!(elem_str.contains("Admin UI"));
assert!(elem_str.contains("admin-ui"));
}
}