From 4807104eb175551d0c337f833a5eb80ca495fcb1 Mon Sep 17 00:00:00 2001 From: lew Date: Fri, 10 Apr 2026 16:04:42 +0100 Subject: [PATCH] feat: extracts {{prompt}} out from {{form}} as a separate element --- .env.example | 2 +- Cargo.lock | 2 +- README.md | 12 ++++++++---- src/render.rs | 16 ++++++++++++---- templates/default.html | 10 +++++++--- 5 files changed, 29 insertions(+), 13 deletions(-) diff --git a/.env.example b/.env.example index 9028c4d..b7d1a1f 100644 --- a/.env.example +++ b/.env.example @@ -84,7 +84,7 @@ # Message textarea height in pixels. # BOOK_TEXTAREA_HEIGHT=150 -# Custom HTML template file with {{title}}, {{form}}, {{entries}}, and {{style}} placeholders. +# Custom HTML template file with {{title}}, {{prompt}}, {{form}}, {{entries}}, and {{style}} placeholders. # Uses built-in default if unset. # BOOK_TEMPLATE=./templates/default.html diff --git a/Cargo.lock b/Cargo.lock index 2f13a71..897e6f4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -458,7 +458,7 @@ dependencies = [ [[package]] name = "guestbook" -version = "0.2.4" +version = "0.2.5" dependencies = [ "axum", "base64 0.22.1", diff --git a/README.md b/README.md index 4a1810f..e00f2bf 100644 --- a/README.md +++ b/README.md @@ -175,7 +175,7 @@ Running `guestbook` with no env vars will give you a working guestbook on `local # Message textarea height in pixels. # BOOK_TEXTAREA_HEIGHT=150 -# Custom HTML template file with {{title}}, {{form}}, {{entries}}, and {{style}} placeholders. +# Custom HTML template file with {{title}}, {{prompt}}, {{form}}, {{entries}}, and {{style}} placeholders. # Uses built-in default if unset. # BOOK_TEMPLATE=./templates/default.html @@ -344,10 +344,13 @@ The `status` field can be `pending`, `approved`, or `denied`. Only approved entr Available placeholders: title - Site title (BOOK_SITE_TITLE). Useful in and headings. + prompt - The form prompt text (BOOK_FORM_PROMPT), wrapped in a + <span class="guestbook-prompt">. Empty when submissions + are disabled. Place anywhere relative to the form. form - The submission form (labels, inputs, button). Controlled by - BOOK_FORM_PROMPT, BOOK_LABEL_NAME, BOOK_LABEL_WEBSITE, - BOOK_LABEL_MESSAGE, BOOK_BUTTON_TEXT, BOOK_TEXTAREA_WIDTH, - BOOK_TEXTAREA_HEIGHT. Empty when BOOK_ENABLE_SUBMISSIONS=false. + BOOK_LABEL_NAME, BOOK_LABEL_WEBSITE, BOOK_LABEL_MESSAGE, + BOOK_BUTTON_TEXT, BOOK_TEXTAREA_WIDTH, BOOK_TEXTAREA_HEIGHT. + Empty when BOOK_ENABLE_SUBMISSIONS=false. entries - Approved guestbook entries, newest first. Entry separator controlled by BOOK_SEPARATOR. style - Custom CSS from BOOK_STYLE or BOOK_STYLE_FILE, wrapped in @@ -370,6 +373,7 @@ The `status` field can be `pending`, `approved`, or `denied`. Only approved entr guestbook ========= +{{prompt}} {{form}} entries diff --git a/src/render.rs b/src/render.rs index b72b9f9..abb6c3e 100644 --- a/src/render.rs +++ b/src/render.rs @@ -13,8 +13,17 @@ pub fn render_page(template: &str, config: &Config, entries: &[Entry], form_html &config.style }; let style = format!("<style>\n{css}\n </style>"); + let prompt = if config.enable_submissions { + format!( + "<span class=\"guestbook-prompt\">{}</span>", + config.form_prompt + ) + } else { + String::new() + }; template .replace("{{title}}", &config.site_title) + .replace("{{prompt}}", &prompt) .replace("{{form}}", form_html) .replace("{{entries}}", &entries_html) .replace("{{style}}", &style) @@ -174,8 +183,7 @@ pub fn render_form(config: &Config) -> String { }; format!( - r#"<span class="guestbook-prompt">{prompt}</span> -<form class="guestbook-form" method="post" action="/submit" accept-charset="UTF-8"> + r#"<form class="guestbook-form" method="post" action="/submit" accept-charset="UTF-8"> <label class="guestbook-label" for="name">{label_name}</label> <input class="guestbook-input" id="name" name="name" required> {website_section} @@ -184,7 +192,6 @@ pub fn render_form(config: &Config) -> String { {captcha_section} {drawing_section}{voice_note_section}<input name="url" aria-hidden="true" style="position:absolute;width:1px;height:1px;overflow:hidden;clip:rect(0,0,0,0)" tabindex="-1" autocomplete="off"><button class="guestbook-button" type="submit">{button}</button> </form>"#, - prompt = config.form_prompt, label_name = config.label_name, website_section = website_section, label_message = config.label_message, @@ -437,7 +444,8 @@ mod tests { config.button_text = "submit".into(); config.label_name = "Name:".into(); let form = render_form(&config); - assert!(form.contains("Leave a note!")); + let html = render_page(DEFAULT_TEMPLATE, &config, &[], &form); + assert!(html.contains("Leave a note!")); assert!(form.contains("submit")); assert!(form.contains("Name:")); } diff --git a/templates/default.html b/templates/default.html index cac844c..4ed31b8 100644 --- a/templates/default.html +++ b/templates/default.html @@ -7,10 +7,13 @@ Available placeholders: title - Site title (BOOK_SITE_TITLE). Useful in <title> and headings. + prompt - The form prompt text (BOOK_FORM_PROMPT), wrapped in a + <span class="guestbook-prompt">. Empty when submissions + are disabled. Place anywhere relative to the form. form - The submission form (labels, inputs, button). Controlled by - BOOK_FORM_PROMPT, BOOK_LABEL_NAME, BOOK_LABEL_WEBSITE, - BOOK_LABEL_MESSAGE, BOOK_BUTTON_TEXT, BOOK_TEXTAREA_WIDTH, - BOOK_TEXTAREA_HEIGHT. Empty when BOOK_ENABLE_SUBMISSIONS=false. + BOOK_LABEL_NAME, BOOK_LABEL_WEBSITE, BOOK_LABEL_MESSAGE, + BOOK_BUTTON_TEXT, BOOK_TEXTAREA_WIDTH, BOOK_TEXTAREA_HEIGHT. + Empty when BOOK_ENABLE_SUBMISSIONS=false. entries - Approved guestbook entries, newest first. Entry separator controlled by BOOK_SEPARATOR. style - Custom CSS from BOOK_STYLE or BOOK_STYLE_FILE, wrapped in @@ -33,6 +36,7 @@ guestbook ========= +{{prompt}} {{form}} entries