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,
|
||||
};
|
||||
use std::convert::Infallible;
|
||||
use std::fmt::{Display, Write as _};
|
||||
use std::fmt::Display;
|
||||
use std::str::FromStr;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
@@ -174,6 +174,7 @@ impl IntoHandlerFailure for AppError {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Hemplate)]
|
||||
pub struct Dashboard {
|
||||
csrf: CsrfToken,
|
||||
flash: String,
|
||||
@@ -203,42 +204,6 @@ pub struct ProjectRow {
|
||||
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 {
|
||||
fn from(record: ProjectRecord) -> Self {
|
||||
Self {
|
||||
|
||||
Reference in New Issue
Block a user