sites/randogoth.com/pelicanconf.py
randogoth 4f77f16191 feat: replies on every article, in the board's own chrome
A message base is a thing people answer, and until now this one could only be
read. The site already calls its articles messages in areas, so replies are the
feature the metaphor was asking for rather than a comment box bolted onto it.

Talks to the comment server's API directly instead of loading its widget. The
widget is a React app in an iframe and would arrive with its own fonts, spacing
and avatars; an iframe cannot inherit the page's font in any case. Rules are
drawn the way the guestbook draws them, padded to exactly 80 cells, so a reply
is indistinguishable from any other row on the board. All five pre elements in
the section measure 80 in a real browser.

Two things this surfaced, both verified by driving a browser rather than curl:

The command handler took every letter key as a command, which was harmless when
there was nothing on the board to type into. With a message box, typing `i`
navigated to the index mid-sentence. It now ignores keys aimed at an input or
textarea.

bbs.js already says the bracket chrome is a promise rather than decoration, and
[P]ost was drawn without wiring P to anything. P now focuses the message box.

Handles are checked here as well as at the server, since remark42 wants three
or more characters and only letters, numbers, underscores and spaces; failing
in the page is better than a refusal with no explanation.

Without JS the section is simply absent, which is honest, and the capsule never
sees it since Gemini has no way to render it.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-06 18:10:23 +03:00

106 lines
4 KiB
Python

AUTHOR = 'randogoth'
SITENAME = 'RANDOGOTH'
SITEURL = ''
PATH = 'content'
TIMEZONE = 'Asia/Jerusalem'
DEFAULT_LANG = 'en'
# An ANSI bulletin board. The TuiCSS theme that came over from TRL was a DOS
# *application*: grey chrome, dialogs, a menu bar. A board is a different thing,
# and the one actually wanted here. mc-pelican stays in the tree as the fallback.
THEME = 'bbs'
PLUGIN_PATHS = ['plugins', '../plugins']
PLUGINS = ['crtimages', 'smolnet', 'lostimages']
# Hosts that no longer exist, so their hotlinked images can never resolve.
# Checked against Wayback: of twelve such images only one was ever captured,
# and it now lives in content/library/. See lostimages.py.
LOSTIMAGES_DEAD_HOSTS = [
'visualberlin.org', 'mutanten.org', 'web.mac.com',
'kino.web.de', 'lh4.google.it', 'l.yimg.com',
]
# The sections are message areas, numbered so they can be dialled by key the way
# a board's main menu works. No descriptions: the names are the whole listing,
# as they were on a real board, and working out what an area holds is the point.
BBS_AREAS = {
'RANDOM': 1, 'PLACE': 2, 'MINIMAL': 3,
'MACHINES': 4, 'GONZO': 5, 'ENDTIMES': 6,
}
# The capsule mirrors the board: same areas, same order, same words. Gemini
# clients number link lines themselves, so an area is still dialled by number
# over there without the plugin writing a single bracket.
SMOLNET_SECTION_DIR = 'area'
SMOLNET_SECTION_ORDER = BBS_AREAS
SMOLNET_LABELS = {
'sections': 'Message areas', 'latest': 'Latest messages',
'archive': 'All messages', 'back': 'Main menu', 'pages': 'System',
}
# The address is rot13 in the HTML because of web crawlers. That defence needs
# JavaScript, which Gemini does not have, and the renderer drops raw HTML, so
# without this the one thing the Connect page exists to carry would vanish.
SMOLNET_ROT13_ATTR = 'data-r'
# Articles live flat in content/; assets are carved out of that.
ARTICLE_PATHS = ['']
ARTICLE_EXCLUDES = ['pages', 'library', 'images', 'files']
PAGE_PATHS = ['pages']
STATIC_PATHS = ['library', 'images', 'files']
# Flat slugs, for the reason TRL learned the hard way: sections get reworked and
# every reassignment moves a URL. The section lives in the listing, not the path.
ARTICLE_URL = '{slug}.html'
ARTICLE_SAVE_AS = '{slug}.html'
PAGE_URL = '{slug}.html'
PAGE_SAVE_AS = '{slug}.html'
CATEGORY_URL = 'section/{slug}.html'
CATEGORY_SAVE_AS = 'section/{slug}.html'
CATEGORIES_SAVE_AS = 'sections.html'
TAG_URL = 'tag/{slug}.html'
TAG_SAVE_AS = 'tag/{slug}.html'
TAGS_SAVE_AS = 'tags.html'
ARCHIVES_SAVE_AS = 'archives.html'
AUTHOR_SAVE_AS = ''
AUTHORS_SAVE_AS = ''
# Unlike the other two sites, this one is a blog, so it is paginated and it has
# feeds. People should be able to subscribe to a devlog without visiting it.
DEFAULT_PAGINATION = 15
FEED_ALL_ATOM = 'feeds/all.atom.xml'
FEED_ALL_RSS = 'feeds/all.rss.xml'
CATEGORY_FEED_ATOM = 'feeds/{slug}.atom.xml'
CATEGORY_FEED_RSS = 'feeds/{slug}.rss.xml'
TRANSLATION_FEED_ATOM = None
AUTHOR_FEED_ATOM = None
AUTHOR_FEED_RSS = None
# The eight sections are the navigation, the way a file manager shows directories.
DISPLAY_CATEGORIES_ON_MENU = True
DISPLAY_PAGES_ON_MENU = False
MENUITEMS = [
('ARCHIVES', '/archives.html'),
('TAGS', '/tags.html'),
]
# No nl2br. The recovered bodies are hard wrapped at roughly 70 characters, so it
# turns every source line into a forced break and the prose stops reflowing.
MARKDOWN = {
'extension_configs': {
'markdown.extensions.tables': {},
'markdown.extensions.footnotes': {},
'markdown.extensions.codehilite': {'css_class': 'highlight'},
'markdown.extensions.extra': {},
},
'output_format': 'html5',
}
DELETE_OUTPUT_DIRECTORY = True
CACHE_CONTENT = False
# The comment server. One instance serves three sites, keyed on COMMENTS_SITE,
# so this is the id rather than the hostname. Unset it and the replies section
# disappears from every article, which is the off switch.
COMMENTS_HOST = 'https://comments.randogoth.com'
COMMENTS_SITE = 'randogoth'