ui: update to defaults, less assumptions about layout
This commit is contained in:
parent
1d993fb6cc
commit
6bbdb50ab8
7 changed files with 113 additions and 102 deletions
12
.env.example
12
.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
|
||||
|
|
|
|||
62
README.md
62
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.
|
|||
</head>
|
||||
<body>
|
||||
<div class="page-container">
|
||||
{{title}}
|
||||
=========
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
{{prompt}}
|
||||
{{form}}
|
||||
|
||||
entries
|
||||
=======
|
||||
<h1>entries</h1>
|
||||
{{entries}}
|
||||
</div>
|
||||
</body>
|
||||
|
|
@ -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; }
|
||||
```
|
||||
|
|
|
|||
18
module.nix
18
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.";
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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]
|
||||
|
|
|
|||
|
|
@ -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<label class=\"guestbook-label\" for=\"website\">{}</label>\n<input class=\"guestbook-input\" id=\"website\" name=\"website\">\n",
|
||||
config.label_website
|
||||
"\n<label class=\"guestbook-label\" for=\"website\">{label}</label>\n<input class=\"guestbook-input\" id=\"website\" name=\"website\" placeholder=\"{label}\">\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<label class=\"guestbook-label\" for=\"captcha\">{}</label>\n<input class=\"guestbook-input\" id=\"captcha\" name=\"captcha\" required>\n",
|
||||
config.captcha_question
|
||||
"\n<label class=\"guestbook-label\" for=\"captcha\">{label}</label>\n<input class=\"guestbook-input\" id=\"captcha\" name=\"captcha\" placeholder=\"{label}\" required>\n",
|
||||
label = config.captcha_question
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
|
|
@ -186,10 +186,10 @@ pub fn render_form(config: &Config) -> String {
|
|||
format!(
|
||||
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>
|
||||
<input class="guestbook-input" id="name" name="name" placeholder="{label_name}" required>
|
||||
{website_section}
|
||||
<label class="guestbook-label" for="message">{label_message}</label>
|
||||
<textarea class="guestbook-textarea" id="message" name="message" style="width:{tw}px;height:{th}px" required></textarea>
|
||||
<textarea class="guestbook-textarea" id="message" name="message" placeholder="{label_message}" style="width:{tw}px;height:{th}px" required></textarea>
|
||||
{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>"#,
|
||||
|
|
@ -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("<hr class=\"entry-separator\">");
|
||||
}
|
||||
if entries.is_empty() {
|
||||
return String::new();
|
||||
}
|
||||
let mut html = String::from("<dl class=\"entries\">");
|
||||
for entry in entries {
|
||||
html.push_str(&render_entry(entry, config));
|
||||
}
|
||||
html.push_str("</dl>");
|
||||
html
|
||||
}
|
||||
|
||||
|
|
@ -272,18 +273,15 @@ fn render_entry(entry: &Entry, config: &Config) -> String {
|
|||
} else {
|
||||
escape_html(&entry.meta.name)
|
||||
};
|
||||
let mut header = format!(
|
||||
"<header class=\"entry-header\"><span class=\"entry-date\">{}</span> - <span class=\"entry-name\">{}</span>",
|
||||
&entry.meta.date[..10], name
|
||||
);
|
||||
if config.enable_website_links && !entry.meta.website.is_empty() {
|
||||
let website = escape_html(&entry.meta.website);
|
||||
header.push_str(&format!(
|
||||
" (<a class=\"entry-website\" href=\"{}\">{}</a>)",
|
||||
website, website
|
||||
));
|
||||
}
|
||||
header.push_str("</header>");
|
||||
let name_html = if config.enable_website_links && !entry.meta.website.is_empty() {
|
||||
format!(
|
||||
"<a class=\"entry-website\" href=\"{}\">{}</a>",
|
||||
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!(
|
||||
"<img class=\"entry-drawing\" src=\"/drawings/{}\" alt=\"Drawing by {}\">",
|
||||
"<dd class=\"entry-drawing-wrap\"><img class=\"entry-drawing\" src=\"/drawings/{}\" alt=\"Drawing by {}\"></dd>",
|
||||
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!(
|
||||
"<span class=\"entry-voice-note\"><audio controls preload=\"metadata\" src=\"/voice_notes/{}\"></audio></span>",
|
||||
"<dd class=\"entry-voice-note-wrap\"><audio controls preload=\"metadata\" src=\"/voice_notes/{}\"></audio></dd>",
|
||||
escape_html(&entry.meta.voice_note)
|
||||
)
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
let body_html = if body.is_empty() {
|
||||
String::new()
|
||||
} else {
|
||||
format!("<dd class=\"entry-body\">{body}</dd>")
|
||||
};
|
||||
let date = &entry.meta.date[..10];
|
||||
format!(
|
||||
"<article class=\"entry\" id=\"{id}\">{header}{drawing_html}{voice_note_html}<div class=\"entry-body\">{body}</div></article>",
|
||||
id = escape_html(&entry.id)
|
||||
"<dt class=\"entry-header\" id=\"{id}\" title=\"{date}\"><span class=\"entry-date\">{date} </span><span class=\"entry-name\">{name_html}</span></dt>{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("<article class=\"entry\" id=\"test\">"));
|
||||
assert!(html.contains("id=\"test\""));
|
||||
assert!(html.contains("<dl class=\"entries\">"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -30,14 +30,12 @@
|
|||
</head>
|
||||
<body>
|
||||
<div class="page-container">
|
||||
{{title}}
|
||||
=========
|
||||
<h1>{{title}}</h1>
|
||||
|
||||
{{prompt}}
|
||||
{{form}}
|
||||
|
||||
entries
|
||||
=======
|
||||
<h1>entries</h1>
|
||||
{{entries}}
|
||||
</div>
|
||||
</body>
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue