diff --git a/.env.example b/.env.example
index 670640c..0d05b58 100644
--- a/.env.example
+++ b/.env.example
@@ -69,23 +69,23 @@
# .entry-name, .entry-website, .entry-body
# BOOK_STYLE=
-# Text shown above the form.
+# Text shown above the form. Empty by default.
# BOOK_FORM_PROMPT=Thanks for visiting. Sign the guestbook!
# Submit button text.
# BOOK_BUTTON_TEXT=sign
# Label for the name field.
-# BOOK_LABEL_NAME=Your name:
+# BOOK_LABEL_NAME=name
# Label for the website field.
-# BOOK_LABEL_WEBSITE=Your website (optional):
+# BOOK_LABEL_WEBSITE=website (optional)
# Label for the message field.
-# BOOK_LABEL_MESSAGE=Your message:
+# BOOK_LABEL_MESSAGE=message
# Message textarea width in pixels.
-# BOOK_TEXTAREA_WIDTH=400
+# BOOK_TEXTAREA_WIDTH=320
# Message textarea height in pixels.
# BOOK_TEXTAREA_HEIGHT=150
@@ -103,7 +103,7 @@
# BOOK_ENABLE_DRAWINGS=false
# Drawing canvas width in pixels.
-# BOOK_CANVAS_WIDTH=400
+# BOOK_CANVAS_WIDTH=320
# Drawing canvas height in pixels.
# BOOK_CANVAS_HEIGHT=200
diff --git a/README.md b/README.md
index cee5552..ed5afe4 100644
--- a/README.md
+++ b/README.md
@@ -156,27 +156,28 @@ Running `guestbook` with no env vars will give you a working guestbook on `local
# Custom CSS injected into a style tag.
# Classes: .guestbook-form, .guestbook-prompt, .guestbook-label, .guestbook-input,
-# .guestbook-textarea, .guestbook-button, .entry, .entry-header, .entry-date,
-# .entry-name, .entry-website, .entry-body
+# .guestbook-textarea, .guestbook-button, .entries, .entry-header, .entry-date,
+# .entry-name, .entry-website, .entry-body, .entry-drawing-wrap, .entry-drawing,
+# .entry-voice-note-wrap
# BOOK_STYLE=
-# Text shown above the form.
+# Text shown above the form. Empty by default.
# BOOK_FORM_PROMPT=Thanks for visiting. Sign the guestbook!
# Submit button text.
# BOOK_BUTTON_TEXT=sign
# Label for the name field.
-# BOOK_LABEL_NAME=Your name:
+# BOOK_LABEL_NAME=name
# Label for the website field.
-# BOOK_LABEL_WEBSITE=Your website (optional):
+# BOOK_LABEL_WEBSITE=website (optional)
# Label for the message field.
-# BOOK_LABEL_MESSAGE=Your message:
+# BOOK_LABEL_MESSAGE=message
# Message textarea width in pixels.
-# BOOK_TEXTAREA_WIDTH=400
+# BOOK_TEXTAREA_WIDTH=320
# Message textarea height in pixels.
# BOOK_TEXTAREA_HEIGHT=150
@@ -194,7 +195,7 @@ Running `guestbook` with no env vars will give you a working guestbook on `local
# BOOK_ENABLE_DRAWINGS=false
# Drawing canvas width in pixels.
-# BOOK_CANVAS_WIDTH=400
+# BOOK_CANVAS_WIDTH=320
# Drawing canvas height in pixels.
# BOOK_CANVAS_HEIGHT=200
@@ -234,7 +235,7 @@ services.guestbook = {
websites.enable = true;
drawing = {
enable = false;
- canvasWidth = 400;
+ canvasWidth = 320;
canvasHeight = 200;
};
voiceNote = {
@@ -275,15 +276,15 @@ services.guestbook = {
cssFile = null;
templateFile = null;
successTemplateFile = null;
- greeting = "Thanks for visiting. Sign the guestbook!";
+ greeting = "";
labels = {
submit = "sign";
- name = "Your name:";
- website = "Your website (optional):";
- message = "Your message:";
+ name = "name";
+ website = "website (optional)";
+ message = "message";
};
message = {
- width = 400;
+ width = 320;
height = 150;
};
};
@@ -412,14 +413,12 @@ entered into the 'message' field.
-{{title}}
-=========
+
{{title}}
{{prompt}}
{{form}}
-entries
-=======
+entries
{{entries}}
@@ -462,9 +461,12 @@ entries
```css
/* Page container */
+body {
+ margin: 0;
+ line-height: 1.5;
+}
.page-container {
max-width: 70ch;
- margin: 0 auto;
padding: 1rem;
word-wrap: break-word;
}
@@ -472,37 +474,37 @@ entries
/* Form */
.guestbook-prompt { display: block; margin-bottom: 1em; }
.guestbook-form {}
-.guestbook-label { display: block; }
-.guestbook-input { display: block; margin-bottom: 0.5em; }
-.guestbook-textarea { display: block; box-sizing: border-box; max-width: 100%; margin-bottom: 0.5em; }
-.guestbook-button { display: block; margin-top: 1em; margin-bottom: 1.5em; }
+.guestbook-label { position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0; }
+.guestbook-input { display: block; margin-bottom: 0.2em; }
+.guestbook-textarea { display: block; box-sizing: border-box; max-width: 100%; margin-bottom: 0.2em; }
+.guestbook-button { display: block; }
/* Drawings */
.guestbook-canvas { border: 1px solid #000; cursor: crosshair; display: block; max-width: 100%; height: auto; }
.guestbook-canvas-tools { display: block; }
.guestbook-canvas-tools a { cursor: pointer; }
-.guestbook-drawing-wrap { display: block; margin-bottom: 0.5em; }
+.guestbook-drawing-wrap { display: block; }
.guestbook-drawing-inline a { cursor: pointer; }
.guestbook-drawing-content:empty { display: none; }
-.guestbook-drawing-content { display: block; margin-bottom: 0.5em; }
+.guestbook-drawing-content { display: block; }
.guestbook-swatch { display: inline-block; width: 0.85em; height: 0.85em; border: 1px solid #000; cursor: pointer; vertical-align: middle; box-sizing: border-box; margin: 0 1px; }
.guestbook-swatch.active { border: 1px solid #000; outline: 1px solid #000; }
.guestbook-size-slider { width: 4em; vertical-align: middle; }
.entry-drawing { max-width: 100%; }
/* Voice notes */
-.guestbook-voice-wrap { display: block; margin-bottom: 0.5em; }
+.guestbook-voice-wrap { display: block; }
.guestbook-voice-record.recording { color: red; }
.guestbook-voice-timer { font-variant-numeric: tabular-nums; }
.guestbook-voice-playback:empty { display: none; }
.guestbook-voice-playback { display: block; white-space: normal; }
-audio { display: block; margin-bottom: 0.3em; height: 2em; }
+audio { display: block; height: 2em; }
/* Entries */
-.entry { margin: 0.5em 0; }
-.entry-header { margin-bottom: 0.2em; }
+.entries { margin: 0; line-height: 1; }
+.entries dt:not(:first-child) { margin-top: 0.5rem; }
.entry-date {}
-.entry-name {}
+.entry-name { font-weight: bold; }
.entry-website {}
.entry-body { white-space: pre-wrap; }
```
diff --git a/module.nix b/module.nix
index 7d54bb7..5e24e52 100644
--- a/module.nix
+++ b/module.nix
@@ -98,7 +98,7 @@ in
canvasWidth = mkOption {
type = types.int;
- default = 400;
+ default = 320;
description = "Drawing canvas width in pixels.";
};
@@ -251,7 +251,7 @@ in
greeting = mkOption {
type = types.str;
- default = "Thanks for visiting. Sign the guestbook!";
+ default = "";
description = "Text shown above the form.";
};
@@ -264,27 +264,27 @@ in
name = mkOption {
type = types.str;
- default = "Your name:";
- description = "Label for the name field.";
+ default = "name";
+ description = "Label for the name field (used as both screen-reader label and placeholder).";
};
website = mkOption {
type = types.str;
- default = "Your website (optional):";
- description = "Label for the website field.";
+ default = "website (optional)";
+ description = "Label for the website field (used as both screen-reader label and placeholder).";
};
message = mkOption {
type = types.str;
- default = "Your message:";
- description = "Label for the message field.";
+ default = "message";
+ description = "Label for the message field (used as both screen-reader label and placeholder).";
};
};
message = {
width = mkOption {
type = types.int;
- default = 400;
+ default = 320;
description = "Message textarea width in pixels.";
};
diff --git a/src/config.rs b/src/config.rs
index 35752bc..f9b23c5 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -137,7 +137,7 @@ impl Config {
.map(|v| v != "false")
.unwrap_or(false),
canvas_width: env::var("BOOK_CANVAS_WIDTH")
- .unwrap_or_else(|_| "400".into())
+ .unwrap_or_else(|_| "320".into())
.parse()
.map_err(|_| "BOOK_CANVAS_WIDTH must be a number")?,
canvas_height: env::var("BOOK_CANVAS_HEIGHT")
@@ -167,18 +167,16 @@ impl Config {
})
.or_else(|| env::var("BOOK_STYLE").ok())
.unwrap_or_default(),
- form_prompt: env::var("BOOK_FORM_PROMPT")
- .unwrap_or_else(|_| "Thanks for visiting. Sign the guestbook!".into()),
+ form_prompt: env::var("BOOK_FORM_PROMPT").unwrap_or_default(),
button_text: env::var("BOOK_BUTTON_TEXT")
.unwrap_or_else(|_| "sign".into()),
- label_name: env::var("BOOK_LABEL_NAME")
- .unwrap_or_else(|_| "Your name:".into()),
+ label_name: env::var("BOOK_LABEL_NAME").unwrap_or_else(|_| "name".into()),
label_website: env::var("BOOK_LABEL_WEBSITE")
- .unwrap_or_else(|_| "Your website (optional):".into()),
+ .unwrap_or_else(|_| "website (optional)".into()),
label_message: env::var("BOOK_LABEL_MESSAGE")
- .unwrap_or_else(|_| "Your message:".into()),
+ .unwrap_or_else(|_| "message".into()),
textarea_width: env::var("BOOK_TEXTAREA_WIDTH")
- .unwrap_or_else(|_| "400".into())
+ .unwrap_or_else(|_| "320".into())
.parse()
.map_err(|_| "BOOK_TEXTAREA_WIDTH must be a number")?,
textarea_height: env::var("BOOK_TEXTAREA_HEIGHT")
@@ -318,9 +316,9 @@ mod tests {
let config = Config::from_env().unwrap();
assert!(!config.enable_drawings);
- assert_eq!(config.canvas_width, 400);
+ assert_eq!(config.canvas_width, 320);
assert_eq!(config.canvas_height, 200);
- assert_eq!(config.max_drawing_bytes(), 400 * 200 * 4);
+ assert_eq!(config.max_drawing_bytes(), 320 * 200 * 4);
}
#[test]
diff --git a/src/render.rs b/src/render.rs
index 6de00f8..8c00226 100644
--- a/src/render.rs
+++ b/src/render.rs
@@ -32,8 +32,8 @@ pub fn render_page(template: &str, config: &Config, entries: &[Entry], form_html
pub fn render_form(config: &Config) -> String {
let website_section = if config.enable_website_links {
format!(
- "\n\n\n",
- config.label_website
+ "\n\n\n",
+ label = config.label_website
)
} else {
String::new()
@@ -41,8 +41,8 @@ pub fn render_form(config: &Config) -> String {
let captcha_section = if config.enable_captcha {
format!(
- "\n\n\n",
- config.captcha_question
+ "\n\n\n",
+ label = config.captcha_question
)
} else {
String::new()
@@ -186,10 +186,10 @@ pub fn render_form(config: &Config) -> String {
format!(
r#""#,
@@ -256,13 +256,14 @@ fn escape_html(s: &str) -> String {
}
fn render_entries(entries: &[Entry], config: &Config) -> String {
- let mut html = String::new();
- for (i, entry) in entries.iter().enumerate() {
- if i > 0 {
- html.push_str("
");
- }
+ if entries.is_empty() {
+ return String::new();
+ }
+ let mut html = String::from("");
+ for entry in entries {
html.push_str(&render_entry(entry, config));
}
+ html.push_str("
");
html
}
@@ -272,18 +273,15 @@ fn render_entry(entry: &Entry, config: &Config) -> String {
} else {
escape_html(&entry.meta.name)
};
- let mut header = format!(
- "");
+ let name_html = if config.enable_website_links && !entry.meta.website.is_empty() {
+ format!(
+ "{}",
+ escape_html(&entry.meta.website),
+ name
+ )
+ } else {
+ name
+ };
let body = if config.enable_html_injection {
entry.body.clone()
} else {
@@ -291,7 +289,7 @@ fn render_entry(entry: &Entry, config: &Config) -> String {
};
let drawing_html = if !entry.meta.drawing.is_empty() {
format!(
- "
",
+ "
",
escape_html(&entry.meta.drawing),
escape_html(&entry.meta.name)
)
@@ -300,15 +298,21 @@ fn render_entry(entry: &Entry, config: &Config) -> String {
};
let voice_note_html = if !entry.meta.voice_note.is_empty() {
format!(
- "",
+ "",
escape_html(&entry.meta.voice_note)
)
} else {
String::new()
};
+ let body_html = if body.is_empty() {
+ String::new()
+ } else {
+ format!("{body}")
+ };
+ let date = &entry.meta.date[..10];
format!(
- "{header}{drawing_html}{voice_note_html}{body}
",
- id = escape_html(&entry.id)
+ "{body_html}{drawing_html}{voice_note_html}",
+ id = escape_html(&entry.id),
)
}
@@ -404,7 +408,8 @@ mod tests {
assert!(html.contains("entry-header"));
assert!(html.contains("entry-name"));
assert!(html.contains("entry-body"));
- assert!(html.contains(""));
+ assert!(html.contains("id=\"test\""));
+ assert!(html.contains(""));
}
#[test]
diff --git a/templates/default.css b/templates/default.css
index 4a5542b..5e6004c 100644
--- a/templates/default.css
+++ b/templates/default.css
@@ -1,7 +1,10 @@
/* Page container */
+body {
+ margin: 0;
+ line-height: 1.5;
+}
.page-container {
max-width: 70ch;
- margin: 0 auto;
padding: 1rem;
word-wrap: break-word;
}
@@ -13,22 +16,28 @@
}
.guestbook-form {}
.guestbook-label {
- display: block;
+ position: absolute;
+ width: 1px;
+ height: 1px;
+ padding: 0;
+ margin: -1px;
+ overflow: hidden;
+ clip: rect(0, 0, 0, 0);
+ white-space: nowrap;
+ border: 0;
}
.guestbook-input {
display: block;
- margin-bottom: 0.5em;
+ margin-bottom: 0.2em;
}
.guestbook-textarea {
display: block;
box-sizing: border-box;
max-width: 100%;
- margin-bottom: 0.5em;
+ margin-bottom: 0.2em;
}
.guestbook-button {
display: block;
- margin-top: 1em;
- margin-bottom: 1.5em;
}
/* Drawings */
@@ -47,7 +56,6 @@
}
.guestbook-drawing-wrap {
display: block;
- margin-bottom: 0.5em;
}
.guestbook-drawing-inline a {
cursor: pointer;
@@ -57,7 +65,6 @@
}
.guestbook-drawing-content {
display: block;
- margin-bottom: 0.5em;
}
.guestbook-swatch {
display: inline-block;
@@ -84,7 +91,6 @@
/* Voice notes */
.guestbook-voice-wrap {
display: block;
- margin-bottom: 0.5em;
}
.guestbook-voice-record.recording {
color: red;
@@ -101,19 +107,21 @@
}
audio {
display: block;
- margin-bottom: 0.3em;
height: 2em;
}
/* Entries */
-.entry {
- margin: 0.5em 0;
+.entries {
+ margin: 0;
+ line-height: 1;
}
-.entry-header {
- margin-bottom: 0.2em;
+.entries dt:not(:first-child) {
+ margin-top: 0.5rem;
}
.entry-date {}
-.entry-name {}
+.entry-name {
+ font-weight: bold;
+}
.entry-website {}
.entry-body {
white-space: pre-wrap;
diff --git a/templates/default.html b/templates/default.html
index a517a98..870ddc1 100644
--- a/templates/default.html
+++ b/templates/default.html
@@ -30,14 +30,12 @@
-{{title}}
-=========
+
{{title}}
{{prompt}}
{{form}}
-entries
-=======
+entries
{{entries}}