cleaner form layout: CSS, forum-form class, remove hardcoded sizes/br tags

This commit is contained in:
lichenblankie 2026-06-05 02:07:31 +00:00
parent 6ea664cbf6
commit ec9e1754e4

View file

@ -16,6 +16,17 @@ def esc(s):
return html.escape(str(s)) return html.escape(str(s))
FORUM_CSS = """
<style>
.forum-form { max-width: 500px; }
.forum-form input, .forum-form textarea { width: 100%; box-sizing: border-box; padding: 6px; margin-bottom: 8px; }
.forum-form button { padding: 6px 16px; }
.forum-form label { display: block; margin-bottom: 8px; }
.forum-form small { display: block; margin-bottom: 8px; }
</style>
"""
class ForumHandlers: class ForumHandlers:
def __init__(self, fdb, sync, identity, reticulum, site_name="me"): def __init__(self, fdb, sync, identity, reticulum, site_name="me"):
self.fdb = fdb self.fdb = fdb
@ -53,7 +64,7 @@ class ForumHandlers:
return { return {
"status": status, "status": status,
"content_type": "text/html; charset=utf-8", "content_type": "text/html; charset=utf-8",
"body": body_html, "body": FORUM_CSS + body_html,
"headers": {}, "headers": {},
} }
@ -223,14 +234,14 @@ class ForumHandlers:
def handle_new_form(self, msg=""): def handle_new_form(self, msg=""):
return self._respond( return self._respond(
f"<h1>new thread</h1>" f"<h1>new thread</h1>"
f'<form method="post" action="/forum/new">' f'<form class="forum-form" method="post" action="/forum/new">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<input name="title" placeholder="title" size="50" required><br>' f'<input name="title" placeholder="title" required>'
f"<small>max {MAX_TITLE_LENGTH} characters</small><br><br>" f"<small>max {MAX_TITLE_LENGTH} characters</small>"
f'<input name="url" placeholder="URL you want to share (optional)" size="50"><br><br>' f'<input name="url" placeholder="URL you want to share (optional)">'
f'<textarea name="body" rows="6" cols="50" placeholder="details or context (optional)"></textarea><br>' f'<textarea name="body" rows="6" placeholder="details or context (optional)"></textarea>'
f"<small>max {MAX_BODY_LENGTH} characters</small><br><br>" f"<small>max {MAX_BODY_LENGTH} characters</small>"
f'<input name="tags" placeholder="tags, comma-separated (optional)" size="50"><br><br>' f'<input name="tags" placeholder="tags, comma-separated (optional)">'
f'<button type="submit">post</button>' f'<button type="submit">post</button>'
f"</form>" f"</form>"
f"<p>{msg}</p>" f"<p>{msg}</p>"
@ -315,10 +326,10 @@ class ForumHandlers:
) )
reply_form = ( reply_form = (
f'<form method="post" action="/forum/t/{thread["id"]}/reply">' f'<form class="forum-form" method="post" action="/forum/t/{thread["id"]}/reply">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<textarea name="body" rows="4" cols="50" placeholder="share a URL or reply..." required></textarea><br>' f'<textarea name="body" rows="4" placeholder="share a URL or reply..." required></textarea>'
f"<small>max {MAX_BODY_LENGTH} characters</small><br><br>" f"<small>max {MAX_BODY_LENGTH} characters</small>"
f'<button type="submit">reply</button>' f'<button type="submit">reply</button>'
f"</form>" f"</form>"
) )
@ -374,14 +385,14 @@ class ForumHandlers:
return self._error(403) return self._error(403)
return self._respond( return self._respond(
f"<h1>edit thread</h1>" f"<h1>edit thread</h1>"
f'<form method="post" action="/forum/t/{thread_id}/edit">' f'<form class="forum-form" method="post" action="/forum/t/{thread_id}/edit">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<input name="title" value="{esc(thread["title"])}" size="50" required><br>' f'<input name="title" value="{esc(thread["title"])}" required>'
f"<small>max {MAX_TITLE_LENGTH} characters</small><br><br>" f"<small>max {MAX_TITLE_LENGTH} characters</small>"
f'<input name="url" value="{esc(thread["url"] or "")}" placeholder="URL" size="50"><br><br>' f'<input name="url" value="{esc(thread["url"] or "")}" placeholder="URL">'
f'<textarea name="body" rows="6" cols="50" placeholder="details or context">{esc(thread["body"] or "")}</textarea><br>' f'<textarea name="body" rows="6" placeholder="details or context">{esc(thread["body"] or "")}</textarea>'
f"<small>max {MAX_BODY_LENGTH} characters</small><br><br>" f"<small>max {MAX_BODY_LENGTH} characters</small>"
f'<input name="tags" value="{esc(thread["tags"] or "")}" placeholder="tags, comma-separated" size="50"><br><br>' f'<input name="tags" value="{esc(thread["tags"] or "")}" placeholder="tags, comma-separated">'
f'<button type="submit">save</button>' f'<button type="submit">save</button>'
f"</form>" f"</form>"
f"<p>{msg}</p>" f"<p>{msg}</p>"
@ -513,50 +524,50 @@ class ForumHandlers:
f"<p>{msg}</p>" f"<p>{msg}</p>"
f'<p><a class="forum-action" href="/forum/sync/now">sync now</a></p>' f'<p><a class="forum-action" href="/forum/sync/now">sync now</a></p>'
f"<h2>auto-discovery</h2>" f"<h2>auto-discovery</h2>"
f'<form method="post" action="/forum/auto_discover">' f'<form class="forum-form" method="post" action="/forum/auto_discover">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<label><input type="checkbox" name="enabled" value="1"{auto_discover_checked}>' f'<label><input type="checkbox" name="enabled" value="1"{auto_discover_checked}>'
f" automatically discover other forum instances on the mesh</label><br><br>" f" automatically discover other forum instances on the mesh</label>"
f'<button>save</button>' f'<button>save</button>'
f"</form>" f"</form>"
f"<h2>auto-sync</h2>" f"<h2>auto-sync</h2>"
f'<form method="post" action="/forum/auto_sync">' f'<form class="forum-form" method="post" action="/forum/auto_sync">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<label><input type="checkbox" name="enabled" value="1"{auto_sync_checked}>' f'<label><input type="checkbox" name="enabled" value="1"{auto_sync_checked}>'
f" automatically sync content every 5 minutes</label><br><br>" f" automatically sync content every 5 minutes</label>"
f'<button>save</button>' f'<button>save</button>'
f"</form>" f"</form>"
f"<h2>storage</h2>" f"<h2>storage</h2>"
f'<form method="post" action="/forum/storage">' f'<form class="forum-form" method="post" action="/forum/storage">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<label>Keep threads for ' f'<label>Keep threads for '
f'<input name="retention_days" value="{esc(retention_days)}" size="4"> days</label>' f'<input name="retention_days" value="{esc(retention_days)}" size="4"> days</label>'
f"<br><small>Older threads are pruned automatically (default: 30). Set to 0 to keep everything.</small><br><br>" f"<small>Older threads are pruned automatically (default: 30). Set to 0 to keep everything.</small>"
f'<button>save</button>' f'<button>save</button>'
f"</form>" f"</form>"
f"<h2>blocked instances</h2>" f"<h2>blocked instances</h2>"
f"{blocked_items}" f"{blocked_items}"
f'<form method="post" action="/forum/block">' f'<form class="forum-form" method="post" action="/forum/block">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<input name="instance" placeholder="instance hash (32 hex chars)" size="40"><br><br>' f'<input name="instance" placeholder="instance hash (32 hex chars)">'
f'<button>block</button>' f'<button>block</button>'
f"</form>" f"</form>"
f"<h2>peer reports</h2>" f"<h2>peer reports</h2>"
f"{self._peer_reports_html()}" f"{self._peer_reports_html()}"
f"<h2>keyword filters</h2>" f"<h2>keyword filters</h2>"
f'<form method="post" action="/forum/filters">' f'<form class="forum-form" method="post" action="/forum/filters">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<input name="keywords" value="{esc(filters_str)}" placeholder="comma-separated keywords" size="50"><br><br>' f'<input name="keywords" value="{esc(filters_str)}" placeholder="comma-separated keywords">'
f'<button>save</button>' f'<button>save</button>'
f"</form>" f"</form>"
f"<h2>synced instances</h2>" f"<h2>synced instances</h2>"
f"{synced_items}" f"{synced_items}"
f"<p><small>Instances are discovered automatically via mesh announces. " f"<p><small>Instances are discovered automatically via mesh announces. "
f"You can also manually add a friend's instance hash to bootstrap.</small></p>" f"You can also manually add a friend's instance hash to bootstrap.</small></p>"
f'<form method="post" action="/forum/sync/add">' f'<form class="forum-form" method="post" action="/forum/sync/add">'
f'{self._csrf_field()}' f'{self._csrf_field()}'
f'<input name="instance" placeholder="instance hash" size="40"><br><br>' f'<input name="instance" placeholder="instance hash">'
f'<input name="name" placeholder="label (optional)" size="20"><br><br>' f'<input name="name" placeholder="label (optional)">'
f'<button>add</button>' f'<button>add</button>'
f"</form>" f"</form>"
f'<hr>' f'<hr>'