feat: textarea width/rows in px to match drawpad, and drawpad submissions/entry rendering
This commit is contained in:
parent
6322606335
commit
d26c289f66
7 changed files with 64 additions and 43 deletions
|
|
@ -78,11 +78,11 @@
|
||||||
# Label for the message field.
|
# Label for the message field.
|
||||||
# BOOK_LABEL_MESSAGE=Your message:
|
# BOOK_LABEL_MESSAGE=Your message:
|
||||||
|
|
||||||
# Number of rows for the message textarea.
|
# Message textarea width in pixels.
|
||||||
# BOOK_TEXTAREA_ROWS=8
|
# BOOK_TEXTAREA_WIDTH=400
|
||||||
|
|
||||||
# Number of columns for the message textarea.
|
# Message textarea height in pixels.
|
||||||
# BOOK_TEXTAREA_COLS=60
|
# BOOK_TEXTAREA_HEIGHT=150
|
||||||
|
|
||||||
# Custom HTML template file with {{title}}, {{form}}, {{entries}}, and {{style}} placeholders.
|
# Custom HTML template file with {{title}}, {{form}}, {{entries}}, and {{style}} placeholders.
|
||||||
# Uses built-in default if unset.
|
# Uses built-in default if unset.
|
||||||
|
|
|
||||||
26
README.md
26
README.md
|
|
@ -167,11 +167,11 @@ Running `guestbook` with no env vars will give you a working guestbook on `local
|
||||||
# Label for the message field.
|
# Label for the message field.
|
||||||
# BOOK_LABEL_MESSAGE=Your message:
|
# BOOK_LABEL_MESSAGE=Your message:
|
||||||
|
|
||||||
# Number of rows for the message textarea.
|
# Message textarea width in pixels.
|
||||||
# BOOK_TEXTAREA_ROWS=8
|
# BOOK_TEXTAREA_WIDTH=400
|
||||||
|
|
||||||
# Number of columns for the message textarea.
|
# Message textarea height in pixels.
|
||||||
# BOOK_TEXTAREA_COLS=60
|
# BOOK_TEXTAREA_HEIGHT=150
|
||||||
|
|
||||||
# Custom HTML template file with {{title}}, {{form}}, {{entries}}, and {{style}} placeholders.
|
# Custom HTML template file with {{title}}, {{form}}, {{entries}}, and {{style}} placeholders.
|
||||||
# Uses built-in default if unset.
|
# Uses built-in default if unset.
|
||||||
|
|
@ -235,8 +235,8 @@ services.guestbook = {
|
||||||
message = "Your message:";
|
message = "Your message:";
|
||||||
};
|
};
|
||||||
message = {
|
message = {
|
||||||
rows = 8;
|
width = 400;
|
||||||
cols = 60;
|
height = 150;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -286,8 +286,8 @@ The `status` field can be `pending`, `approved`, or `denied`. Only approved entr
|
||||||
title - Site title (BOOK_SITE_TITLE). Useful in <title> and headings.
|
title - Site title (BOOK_SITE_TITLE). Useful in <title> and headings.
|
||||||
form - The submission form (labels, inputs, button). Controlled by
|
form - The submission form (labels, inputs, button). Controlled by
|
||||||
BOOK_FORM_PROMPT, BOOK_LABEL_NAME, BOOK_LABEL_WEBSITE,
|
BOOK_FORM_PROMPT, BOOK_LABEL_NAME, BOOK_LABEL_WEBSITE,
|
||||||
BOOK_LABEL_MESSAGE, BOOK_BUTTON_TEXT, BOOK_TEXTAREA_ROWS,
|
BOOK_LABEL_MESSAGE, BOOK_BUTTON_TEXT, BOOK_TEXTAREA_WIDTH,
|
||||||
BOOK_TEXTAREA_COLS. Empty when BOOK_ENABLE_SUBMISSIONS=false.
|
BOOK_TEXTAREA_HEIGHT. Empty when BOOK_ENABLE_SUBMISSIONS=false.
|
||||||
entries - Approved guestbook entries, newest first. Entry separator
|
entries - Approved guestbook entries, newest first. Entry separator
|
||||||
controlled by BOOK_SEPARATOR.
|
controlled by BOOK_SEPARATOR.
|
||||||
style - Custom CSS from BOOK_STYLE or BOOK_STYLE_FILE, wrapped in
|
style - Custom CSS from BOOK_STYLE or BOOK_STYLE_FILE, wrapped in
|
||||||
|
|
@ -340,6 +340,16 @@ entries
|
||||||
.guestbook-textarea {}
|
.guestbook-textarea {}
|
||||||
.guestbook-button {}
|
.guestbook-button {}
|
||||||
|
|
||||||
|
/* Drawings */
|
||||||
|
.guestbook-canvas {
|
||||||
|
border: 1px solid #000;
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
.guestbook-canvas-reset {}
|
||||||
|
.entry-drawing {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
/* Entries */
|
/* Entries */
|
||||||
.entry-header {}
|
.entry-header {}
|
||||||
.entry-name {}
|
.entry-name {}
|
||||||
|
|
|
||||||
16
module.nix
16
module.nix
|
|
@ -203,16 +203,16 @@ in
|
||||||
};
|
};
|
||||||
|
|
||||||
message = {
|
message = {
|
||||||
rows = mkOption {
|
width = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
default = 8;
|
default = 400;
|
||||||
description = "Number of rows for the message textarea.";
|
description = "Message textarea width in pixels.";
|
||||||
};
|
};
|
||||||
|
|
||||||
cols = mkOption {
|
height = mkOption {
|
||||||
type = types.int;
|
type = types.int;
|
||||||
default = 60;
|
default = 150;
|
||||||
description = "Number of columns for the message textarea.";
|
description = "Message textarea height in pixels.";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
@ -249,8 +249,8 @@ in
|
||||||
BOOK_LABEL_NAME = cfg.styles.labels.name;
|
BOOK_LABEL_NAME = cfg.styles.labels.name;
|
||||||
BOOK_LABEL_WEBSITE = cfg.styles.labels.website;
|
BOOK_LABEL_WEBSITE = cfg.styles.labels.website;
|
||||||
BOOK_LABEL_MESSAGE = cfg.styles.labels.message;
|
BOOK_LABEL_MESSAGE = cfg.styles.labels.message;
|
||||||
BOOK_TEXTAREA_ROWS = toString cfg.styles.message.rows;
|
BOOK_TEXTAREA_WIDTH = toString cfg.styles.message.width;
|
||||||
BOOK_TEXTAREA_COLS = toString cfg.styles.message.cols;
|
BOOK_TEXTAREA_HEIGHT = toString cfg.styles.message.height;
|
||||||
} // lib.optionalAttrs (cfg.styles.cssFile != null) {
|
} // lib.optionalAttrs (cfg.styles.cssFile != null) {
|
||||||
BOOK_STYLE_FILE = cfg.styles.cssFile;
|
BOOK_STYLE_FILE = cfg.styles.cssFile;
|
||||||
} // lib.optionalAttrs (cfg.styles.templateFile != null) {
|
} // lib.optionalAttrs (cfg.styles.templateFile != null) {
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,8 @@ pub struct Config {
|
||||||
pub label_name: String,
|
pub label_name: String,
|
||||||
pub label_website: String,
|
pub label_website: String,
|
||||||
pub label_message: String,
|
pub label_message: String,
|
||||||
pub textarea_rows: u32,
|
pub textarea_width: u32,
|
||||||
pub textarea_cols: u32,
|
pub textarea_height: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Config {
|
impl Config {
|
||||||
|
|
@ -138,14 +138,14 @@ impl Config {
|
||||||
.unwrap_or_else(|_| "Your website (optional):".into()),
|
.unwrap_or_else(|_| "Your website (optional):".into()),
|
||||||
label_message: env::var("BOOK_LABEL_MESSAGE")
|
label_message: env::var("BOOK_LABEL_MESSAGE")
|
||||||
.unwrap_or_else(|_| "Your message:".into()),
|
.unwrap_or_else(|_| "Your message:".into()),
|
||||||
textarea_rows: env::var("BOOK_TEXTAREA_ROWS")
|
textarea_width: env::var("BOOK_TEXTAREA_WIDTH")
|
||||||
.unwrap_or_else(|_| "8".into())
|
.unwrap_or_else(|_| "400".into())
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| "BOOK_TEXTAREA_ROWS must be a number")?,
|
.map_err(|_| "BOOK_TEXTAREA_WIDTH must be a number")?,
|
||||||
textarea_cols: env::var("BOOK_TEXTAREA_COLS")
|
textarea_height: env::var("BOOK_TEXTAREA_HEIGHT")
|
||||||
.unwrap_or_else(|_| "60".into())
|
.unwrap_or_else(|_| "150".into())
|
||||||
.parse()
|
.parse()
|
||||||
.map_err(|_| "BOOK_TEXTAREA_COLS must be a number")?,
|
.map_err(|_| "BOOK_TEXTAREA_HEIGHT must be a number")?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -40,8 +40,7 @@ pub fn render_form(config: &Config) -> String {
|
||||||
|
|
||||||
let drawing_section = if config.enable_drawings {
|
let drawing_section = if config.enable_drawings {
|
||||||
format!(
|
format!(
|
||||||
r##"
|
r##"<label class="guestbook-label">{label}</label>
|
||||||
<label class="guestbook-label">{label}</label>
|
|
||||||
<canvas class="guestbook-canvas" width="{w}" height="{h}"></canvas>
|
<canvas class="guestbook-canvas" width="{w}" height="{h}"></canvas>
|
||||||
<a href="#" class="guestbook-canvas-reset">Reset</a>
|
<a href="#" class="guestbook-canvas-reset">Reset</a>
|
||||||
<input type="hidden" name="drawing">
|
<input type="hidden" name="drawing">
|
||||||
|
|
@ -87,7 +86,7 @@ pub fn render_form(config: &Config) -> String {
|
||||||
<input class="guestbook-input" name="name" required>
|
<input class="guestbook-input" name="name" required>
|
||||||
{website_section}
|
{website_section}
|
||||||
<label class="guestbook-label">{label_message}</label>
|
<label class="guestbook-label">{label_message}</label>
|
||||||
<textarea class="guestbook-textarea" name="message" rows="{rows}" cols="{cols}" required></textarea>
|
<textarea class="guestbook-textarea" name="message" style="width:{tw}px;height:{th}px" required></textarea>
|
||||||
{captcha_section}
|
{captcha_section}
|
||||||
{drawing_section}
|
{drawing_section}
|
||||||
<input name="url" style="display:none" tabindex="-1" autocomplete="off">
|
<input name="url" style="display:none" tabindex="-1" autocomplete="off">
|
||||||
|
|
@ -97,8 +96,8 @@ pub fn render_form(config: &Config) -> String {
|
||||||
label_name = config.label_name,
|
label_name = config.label_name,
|
||||||
website_section = website_section,
|
website_section = website_section,
|
||||||
label_message = config.label_message,
|
label_message = config.label_message,
|
||||||
rows = config.textarea_rows,
|
tw = config.textarea_width,
|
||||||
cols = config.textarea_cols,
|
th = config.textarea_height,
|
||||||
captcha_section = captcha_section,
|
captcha_section = captcha_section,
|
||||||
drawing_section = drawing_section,
|
drawing_section = drawing_section,
|
||||||
button = config.button_text,
|
button = config.button_text,
|
||||||
|
|
@ -196,8 +195,8 @@ mod tests {
|
||||||
label_name: "Your name:".into(),
|
label_name: "Your name:".into(),
|
||||||
label_website: "Your website (optional):".into(),
|
label_website: "Your website (optional):".into(),
|
||||||
label_message: "Your message:".into(),
|
label_message: "Your message:".into(),
|
||||||
textarea_rows: 8,
|
textarea_width: 400,
|
||||||
textarea_cols: 60,
|
textarea_height: 150,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -298,11 +297,11 @@ mod tests {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_render_form_custom_textarea() {
|
fn test_render_form_custom_textarea() {
|
||||||
let mut config = test_config();
|
let mut config = test_config();
|
||||||
config.textarea_rows = 12;
|
config.textarea_width = 500;
|
||||||
config.textarea_cols = 40;
|
config.textarea_height = 200;
|
||||||
let form = render_form(&config);
|
let form = render_form(&config);
|
||||||
assert!(form.contains("rows=\"12\""));
|
assert!(form.contains("width:500px"));
|
||||||
assert!(form.contains("cols=\"40\""));
|
assert!(form.contains("height:200px"));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -424,6 +423,6 @@ mod tests {
|
||||||
let entry = make_entry("alice", "2026-04-09", "Hello!");
|
let entry = make_entry("alice", "2026-04-09", "Hello!");
|
||||||
let form = render_form(&config);
|
let form = render_form(&config);
|
||||||
let html = render_page(DEFAULT_TEMPLATE, &config, &[entry], &form);
|
let html = render_page(DEFAULT_TEMPLATE, &config, &[entry], &form);
|
||||||
assert!(!html.contains("entry-drawing"));
|
assert!(!html.contains("<img class=\"entry-drawing\""));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -275,8 +275,8 @@ mod tests {
|
||||||
label_name: "Your name:".into(),
|
label_name: "Your name:".into(),
|
||||||
label_website: "Your website (optional):".into(),
|
label_website: "Your website (optional):".into(),
|
||||||
label_message: "Your message:".into(),
|
label_message: "Your message:".into(),
|
||||||
textarea_rows: 8,
|
textarea_width: 400,
|
||||||
textarea_cols: 60,
|
textarea_height: 150,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,9 +12,21 @@
|
||||||
.guestbook-form {}
|
.guestbook-form {}
|
||||||
.guestbook-label {}
|
.guestbook-label {}
|
||||||
.guestbook-input {}
|
.guestbook-input {}
|
||||||
.guestbook-textarea {}
|
.guestbook-textarea {
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
.guestbook-button {}
|
.guestbook-button {}
|
||||||
|
|
||||||
|
/* Drawings */
|
||||||
|
.guestbook-canvas {
|
||||||
|
border: 1px solid #000;
|
||||||
|
cursor: crosshair;
|
||||||
|
}
|
||||||
|
.guestbook-canvas-reset {}
|
||||||
|
.entry-drawing {
|
||||||
|
max-width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
/* Entries */
|
/* Entries */
|
||||||
.entry-header {}
|
.entry-header {}
|
||||||
.entry-name {}
|
.entry-name {}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue