feat(examples): derive saas dashboard template
Replace the SaaS tutorial dashboard's hand-written Hemplate implementation with the real hemplate-derived dashboard template. This closes the tutorial skeleton shortcut and keeps the provider-light production app path on generated/derived rendering. req: examples/001 req: canonical_authoring/001 req: view/001
This commit is contained in:
@@ -7,7 +7,7 @@ use hemx_axum::{
|
|||||||
interactions, Form, HandlerErrorContext, HandlerFailure, IntoHandlerFailure, Registry, State,
|
interactions, Form, HandlerErrorContext, HandlerFailure, IntoHandlerFailure, Registry, State,
|
||||||
};
|
};
|
||||||
use std::convert::Infallible;
|
use std::convert::Infallible;
|
||||||
use std::fmt::{Display, Write as _};
|
use std::fmt::Display;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
@@ -174,6 +174,7 @@ impl IntoHandlerFailure for AppError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Hemplate)]
|
||||||
pub struct Dashboard {
|
pub struct Dashboard {
|
||||||
csrf: CsrfToken,
|
csrf: CsrfToken,
|
||||||
flash: String,
|
flash: String,
|
||||||
@@ -203,42 +204,6 @@ pub struct ProjectRow {
|
|||||||
owner: String,
|
owner: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Hemplate for Dashboard {
|
|
||||||
fn render_into(&self, buf: &mut String) -> Result<(), hemplate::error::HemplateError> {
|
|
||||||
buf.push_str("<section class=\"dashboard\" data-hemx-root=\"dashboard\" data-hemx-sse=\"/events\">\n");
|
|
||||||
buf.push_str(" <header class=\"hero\"><p class=\"eyebrow\">Production-shaped SaaS path</p><h1>Projects</h1><p class=\"lede\">Auth-gated mutations, CSRF checks, local persistence, typed forms, generated swaps, page swaps, live status, plain CSS, and one explicit island.</p></header>\n");
|
|
||||||
buf.push_str(" <nav class=\"tabs\" data-hemx-slot=\"nav\"><a href=\"/\" data-hemx-nav=\"\">Projects</a><button type=\"button\" data-hemx-handle=\"open_settings\">Settings</button></nav>\n");
|
|
||||||
buf.push_str(" <section class=\"panel\" data-hemx-slot=\"page_panel\">\n");
|
|
||||||
buf.push_str(" <form class=\"project-form\" data-hemx-handle=\"create_project\" data-hemx-form=\"new_project\" data-hemx-disable-while-pending>\n");
|
|
||||||
write!(
|
|
||||||
buf,
|
|
||||||
" <input type=\"hidden\" name=\"csrf\" value=\"{}\">\n",
|
|
||||||
hemplate::HtmlEscape(&self.csrf.to_string())
|
|
||||||
)?;
|
|
||||||
buf.push_str(" <label>Project name <input name=\"name\" required=\"required\" maxlength=\"64\" value=\"Launch checklist\"></label><button type=\"submit\">Create project</button><p class=\"field-error\" data-hemx-error-for=\"name\"></p>\n </form>\n");
|
|
||||||
write!(
|
|
||||||
buf,
|
|
||||||
" <p class=\"flash\" data-hemx-slot=\"flash\">{}</p>\n",
|
|
||||||
hemplate::HtmlEscape(&self.flash)
|
|
||||||
)?;
|
|
||||||
write!(
|
|
||||||
buf,
|
|
||||||
" <p class=\"summary\" data-hemx-slot=\"summary\">{}</p>\n",
|
|
||||||
hemplate::HtmlEscape(&self.summary)
|
|
||||||
)?;
|
|
||||||
buf.push_str(" <ul class=\"project-list\" data-hemx-slot=\"project_row\">\n");
|
|
||||||
for row in &self.rows {
|
|
||||||
buf.push_str(" ");
|
|
||||||
row.render_into(buf)?;
|
|
||||||
buf.push('\n');
|
|
||||||
}
|
|
||||||
buf.push_str(" </ul>\n </section>\n <section class=\"status-row\"><p data-hemx-slot=\"live_status\">Waiting for status…</p>");
|
|
||||||
write!(buf, "<article class=\"metrics-island\" data-hemx-island=\"metrics\" data-project-count=\"{}\"><h2>Metrics island</h2><canvas width=\"320\" height=\"140\" aria-label=\"Project metrics chart\"></canvas><p data-island-readout=\"\">Waiting for island script…</p></article>", self.project_count)?;
|
|
||||||
buf.push_str("</section>\n</section>\n");
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ProjectRecord> for ProjectRow {
|
impl From<ProjectRecord> for ProjectRow {
|
||||||
fn from(record: ProjectRecord) -> Self {
|
fn from(record: ProjectRecord) -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|||||||
Reference in New Issue
Block a user