fix: make randogoth.com's bbs theme readable on narrow viewports

This commit is contained in:
randogoth 2026-10-06 08:45:13 +03:00
parent 05be426f91
commit c3864287cf
11 changed files with 150 additions and 8 deletions

View file

@ -69,7 +69,8 @@ body {
color: var(--grey);
font-family: 'Classic Console', ui-monospace, monospace;
/* clamp so 80ch always fits the viewport, phone to desktop */
font-size: clamp(7px, 2.32vw, 17px);
--cell: clamp(7px, 2.32vw, 17px);
font-size: var(--cell);
/* Exactly one cell per row. Each box row is its own <pre>, so any leading at
all opens a gap between them and the vertical box-drawing characters stop
meeting. Prose gets its leading back on .msgbody below. */
@ -180,6 +181,49 @@ a:visited { color: var(--lcyan); }
.msgbody hr { border: 0; border-top: 1px solid var(--blue); margin: 1.4em 0; }
.msgbody a { text-decoration: underline; }
/* ── mobile: read content is one size, not two ───────────────────────────
* 80 real characters cannot be legible and fit a phone's width at the same
* time, so below this breakpoint every piece of actual content (prose,
* the message header, the listing tables) renders at one fixed size
* instead of inheriting --cell. Box-drawn tables that packed two columns
* into 80 characters get a second, narrower rendering built for this
* width instead: see .desktop-only/.mobile-only below, toggled by the
* matching (min-width: 601px) block further down. The masthead logo and
* the plain ──── rule dividers are graphics, not content, and are left on
* --cell exactly as before.
*/
@media (max-width: 600px) {
.msgbody,
.cloud,
.pagehdr,
.sysline,
.tagline,
.prompt,
.mobile-only { font-size: 1rem; }
/* The desktop article header packs two fields per row with hand-counted
padding; the mobile rows (and a page's single Subj row) are one field
each, so they just need to wrap like normal text instead of running
off the edge under white-space: pre. The sysline, tagline and the
bottom command bar are actual words, not a repeating-character rule,
so they wrap too. */
.msghdr.mobile-only,
.pagehdr,
.sysline,
.tagline,
.prompt { white-space: normal; }
/* Box drawing embedded in prose (a pull-quote box, if one is ever used)
is a rigid character grid and must stay at the chrome size or its
columns stop lining up against their own border characters. */
.msgbody .box, .msgbody .gb-rule, .msgbody .rule { font-size: var(--cell); }
.desktop-only { display: none; }
}
@media (min-width: 601px) {
.mobile-only { display: none; }
}
/* the Fidonet tagline that closed every message */
.tagline { color: var(--dgrey); margin-top: 1.6em; }
.tagline .origin { color: var(--green); }

View file

@ -1,8 +1,18 @@
{% extends "base.html" %}
{% block title %}NO CARRIER · {{ SITENAME }}{% endblock %}
{% block content %}
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">ERROR</span> ──────────────────────────────────────────────────────────────────────┐</pre>
<pre class="box">│ <span class="new">{{ "%-76s"|format("NO CARRIER") }}</span> │</pre>
<pre class="box">│ <span class="desc">{{ "%-76s"|format("That message does not exist on this board.") }}</span> │</pre>
<pre class="box">└──────────────────────────────────────────────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">ERROR</span> ──────────────────────────────┐</pre>
<pre class="box">│ <span class="new">{{ "%-36s"|format("NO CARRIER") }}</span> │</pre>
<pre class="box">│ <span class="desc">{{ "%-36s"|format("That message does not exist") }}</span> │</pre>
<pre class="box">│ <span class="desc">{{ "%-36s"|format("on this board.") }}</span> │</pre>
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
{% endblock %}

View file

@ -1,10 +1,22 @@
{% extends "base.html" %}
{% block title %}Message Index · {{ SITENAME }}{% endblock %}
{% block content %}
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">MESSAGE INDEX</span> ──────────────────────────────────────────────────────────────┐</pre>
{%- for a in dates %}
{%- set n = loop.index %}
<pre class="box">│ <span class="key">[<b>{{ "%2d"|format(n) }}</b>]</span> <span class="date">{{ a.date.strftime('%d %b %y')|lower }}</span> <span class="sect">{{ "%-8s"|format(a.category|string) }}</span> <a data-key="{{ n }}" href="{{ SITEURL }}/{{ a.url }}">{{ "%-52s"|format(a.title|striptags|truncate(52, true, '')) }}</a> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────────────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">MESSAGE INDEX</span> ──────────────────────┐</pre>
{%- for a in dates %}
{%- set n = loop.index %}
<pre class="box">│ <a data-key="{{ n }}" href="{{ SITEURL }}/{{ a.url }}"><span class="key">[<b>{{ "%2d"|format(n) }}</b>]</span> {{ "%-31s"|format(a.title|striptags|truncate(31, true, '', 0)) }}</a> │</pre>
<pre class="box">│ <span class="date">{{ a.date.strftime('%d %b %y')|lower }}</span> · <span class="sect">{{ "%-8s"|format(a.category|string) }}</span> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
{% endblock %}

View file

@ -2,10 +2,18 @@
{% block title %}{{ article.title|striptags }} · {{ SITENAME }}{% endblock %}
{% block content %}
<pre class="rule">════════════════════════════════════════════════════════════════════════════════</pre>
<pre class="msghdr"> Msg : <b>{{ "%-44s"|format(article.slug) }}</b> Area : <b>{{ article.category }}</b>
<pre class="msghdr desktop-only"> Msg : <b>{{ "%-44s"|format(article.slug) }}</b> Area : <b>{{ article.category }}</b>
From : <b>{{ "%-44s"|format(article.author|default(AUTHOR, true)|string) }}</b> Date : <b>{{ article.date.strftime('%d %b %Y') }}</b>
Subj : <span class="subj">{{ article.title|striptags }}</span>{% if article.tags %}
Keys : {% for t in article.tags %}<a href="{{ SITEURL }}/{{ t.url }}">{{ t }}</a>{% if not loop.last %}, {% endif %}{% endfor %}{% endif %}</pre>
<pre class="msghdr mobile-only"> Msg : <b>{{ article.slug }}</b></pre>
<pre class="msghdr mobile-only"> Area : <b>{{ article.category }}</b></pre>
<pre class="msghdr mobile-only"> From : <b>{{ article.author|default(AUTHOR, true)|string }}</b></pre>
<pre class="msghdr mobile-only"> Date : <b>{{ article.date.strftime('%d %b %Y') }}</b></pre>
<pre class="msghdr mobile-only"> Subj : <span class="subj">{{ article.title|striptags }}</span></pre>
{%- if article.tags %}
<pre class="msghdr mobile-only"> Keys : {% for t in article.tags %}<a href="{{ SITEURL }}/{{ t.url }}">{{ t }}</a>{% if not loop.last %}, {% endif %}{% endfor %}</pre>
{%- endif %}
<pre class="rule">════════════════════════════════════════════════════════════════════════════════</pre>
<div class="msgbody">{{ article.content }}</div>

View file

@ -29,7 +29,7 @@
{% block content %}{% endblock %}
<pre class="rule">────────────────────────────────────────────────────────────────────────────────</pre>
<pre class="prompt"> <a data-key="I" href="{{ SITEURL }}/archives.html"><span class="key">[<b>I</b>]</span>ndex</a> <a data-key="K" href="{{ SITEURL }}/tags.html"><span class="key">[<b>K</b>]</span>eywords</a> <a data-key="F" href="{{ FEED_DOMAIN }}/{{ FEED_ALL_RSS }}"><span class="key">[<b>F</b>]</span>eed</a> <a data-key="M" href="{{ SITEURL }}/">Main <span class="key">[<b>M</b>]</span>enu</a> <span id="themecmd"></span>
<pre class="prompt"> <a data-key="I" href="{{ SITEURL }}/archives.html"><span class="key">[<b>I</b>]</span>ndex</a> <a data-key="K" href="{{ SITEURL }}/tags.html"><span class="key">[<b>K</b>]</span>eywords</a> <a data-key="F" href="{{ FEED_DOMAIN }}/{{ FEED_ALL_RSS }}"><span class="key">[<b>F</b>]</span>eed</a> <a data-key="M" href="{{ SITEURL }}/">Main <span class="key">[<b>M</b>]</span>enu</a> <span id="themecmd"></span><br>
Command: <span id="typed"></span><span class="cursor"> </span></pre>
</div>

View file

@ -5,10 +5,20 @@
{%- for cat, arts in categories %}{% set _ = rows.append((BBS_AREAS.get(cat|string, 99), cat, arts)) %}{% endfor %}
{%- set ordered = rows|sort(attribute='0') %}
{%- set half = (ordered|length + 1) // 2 %}
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">MESSAGE AREAS</span> ───────────────────────┬──────────────────────────────────────┐</pre>
{%- for i in range(half) %}
{%- set a = ordered[i] %}
<pre class="box">│ <span class="key">[<b>{{ a[0] }}</b>]</span> <a data-key="{{ a[0] }}" href="{{ SITEURL }}/{{ a[1].url }}"><span class="area">{{ "%-9s"|format(a[1]|string) }}</span></a> <span class="count">{{ "%3d"|format(a[2]|length) }}</span> │ {% if ordered|length > i + half %}{% set b = ordered[i + half] %}<span class="key">[<b>{{ b[0] }}</b>]</span> <a data-key="{{ b[0] }}" href="{{ SITEURL }}/{{ b[1].url }}"><span class="area">{{ "%-9s"|format(b[1]|string) }}</span></a> <span class="count">{{ "%3d"|format(b[2]|length) }}</span>{% else %} {% endif %} │</pre>
{%- endfor %}
<pre class="box">└───────────────────────────────────────┴──────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">MESSAGE AREAS</span> ──────────────────────┐</pre>
{%- for a in ordered %}
<pre class="box">│ <span class="key">[<b>{{ "%2d"|format(a[0]) }}</b>]</span> <a data-key="{{ a[0] }}" href="{{ SITEURL }}/{{ a[1].url }}"><span class="area">{{ "%-28s"|format(a[1]|string) }}</span></a><span class="count">{{ "%3d"|format(a[2]|length) }}</span> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
{% endblock %}

View file

@ -3,13 +3,25 @@
{% block content %}
{% set info = BBS_AREAS.get(category|string, 0) %}
{% set t = "AREA " ~ info ~ ": " ~ category %}
{%- set total = articles_paginator.object_list|length %}
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (75 - t|length) }}┐</pre>
<pre class="box">├──────────────────────────────────────────────────────────────────────────────┤</pre>
{%- set total = articles_paginator.object_list|length %}
{%- for a in articles_page.object_list %}
{%- set n = total - (loop.index0 + (articles_page.number - 1) * articles_paginator.per_page) %}
<pre class="box">│ <span class="key">[<b>{{ "%3d"|format(n) }}</b>]</span> <span class="date">{{ a.date.strftime('%d %b %y')|lower }}</span> <a data-key="{{ n }}" href="{{ SITEURL }}/{{ a.url }}">{{ "%-60s"|format(a.title|striptags|truncate(60, true, '')) }}</a> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────────────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (35 - t|length) }}┐</pre>
{%- for a in articles_page.object_list %}
{%- set n = total - (loop.index0 + (articles_page.number - 1) * articles_paginator.per_page) %}
<pre class="box">│ <a data-key="{{ n }}" href="{{ SITEURL }}/{{ a.url }}"><span class="key">[<b>{{ "%2d"|format(n) }}</b>]</span> {{ "%-31s"|format(a.title|striptags|truncate(31, true, '', 0)) }}</a> │</pre>
<pre class="box">│ <span class="date">{{ a.date.strftime('%d %b %y')|lower }}</span> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
{% include 'pagination.html' %}
{% endblock %}

View file

@ -4,20 +4,40 @@
{%- for cat, arts in categories %}{% set _ = rows.append((BBS_AREAS.get(cat|string, 99), cat, arts)) %}{% endfor %}
{%- set ordered = rows|sort(attribute='0') %}
{%- set half = (ordered|length + 1) // 2 %}
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">MESSAGE AREAS</span> ───────────────────────┬──────────────────────────────────────┐</pre>
{%- for i in range(half) %}
{%- set a = ordered[i] %}
<pre class="box">│ <span class="key">[<b>{{ a[0] }}</b>]</span> <a data-key="{{ a[0] }}" href="{{ SITEURL }}/{{ a[1].url }}"><span class="area">{{ "%-9s"|format(a[1]|string) }}</span></a> <span class="count">{{ "%3d"|format(a[2]|length) }}</span> │ {% if ordered|length > i + half %}{% set b = ordered[i + half] %}<span class="key">[<b>{{ b[0] }}</b>]</span> <a data-key="{{ b[0] }}" href="{{ SITEURL }}/{{ b[1].url }}"><span class="area">{{ "%-9s"|format(b[1]|string) }}</span></a> <span class="count">{{ "%3d"|format(b[2]|length) }}</span>{% else %} {% endif %} │</pre>
{%- endfor %}
<pre class="box">└───────────────────────────────────────┴──────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">MESSAGE AREAS</span> ──────────────────────┐</pre>
{%- for a in ordered %}
<pre class="box">│ <span class="key">[<b>{{ "%2d"|format(a[0]) }}</b>]</span> <a data-key="{{ a[0] }}" href="{{ SITEURL }}/{{ a[1].url }}"><span class="area">{{ "%-28s"|format(a[1]|string) }}</span></a><span class="count">{{ "%3d"|format(a[2]|length) }}</span> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
{# GUESTBOOK is commented out of the menu until it is built; the page and its
mockup stay in the tree. Restoring it means a third column here and
dropping Status: draft from content/pages/guestbook.md. #}
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">SYSTEM</span> ──────────────────────────────┬──────────────────────────────────────┐</pre>
<pre class="box">│ <a data-key="A" href="{{ SITEURL }}/about.html"><span class="key">[<b>A</b>]</span> <span class="area">ABOUT</span></a> │ <a data-key="C" href="{{ SITEURL }}/connect.html"><span class="key">[<b>C</b>]</span> <span class="area">CONNECT</span></a> │</pre>
<pre class="box">└───────────────────────────────────────┴──────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">SYSTEM</span> ─────────────────────────────┐</pre>
<pre class="box">│ <a data-key="A" href="{{ SITEURL }}/about.html"><span class="key">[<b>A</b>]</span> <span class="area">{{ "%-32s"|format("ABOUT") }}</span></a> │</pre>
<pre class="box">│ <a data-key="C" href="{{ SITEURL }}/connect.html"><span class="key">[<b>C</b>]</span> <span class="area">{{ "%-32s"|format("CONNECT") }}</span></a> │</pre>
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">LATEST</span> ─────────────────────────────────────────────────────────────────────┐</pre>
{%- set base = BBS_AREAS|length %}
{%- for article in articles_page.object_list %}
@ -25,5 +45,17 @@
<pre class="box">│ <span class="key">[<b>{{ "%2d"|format(n) }}</b>]</span> <span class="date">{{ article.date.strftime('%d %b %y')|lower }}</span> <span class="sect">{{ "%-8s"|format(article.category|string) }}</span> <a data-key="{{ n }}" href="{{ SITEURL }}/{{ article.url }}">{{ "%-52s"|format(article.title|striptags|truncate(52, true, '')) }}</a> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────────────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">LATEST</span> ─────────────────────────────┐</pre>
{%- set base = BBS_AREAS|length %}
{%- for article in articles_page.object_list %}
{%- set n = base + loop.index %}
<pre class="box">│ <a data-key="{{ n }}" href="{{ SITEURL }}/{{ article.url }}"><span class="key">[<b>{{ "%2d"|format(n) }}</b>]</span> {{ "%-31s"|format(article.title|striptags|truncate(31, true, '', 0)) }}</a> │</pre>
<pre class="box">│ <span class="date">{{ article.date.strftime('%d %b %y')|lower }}</span> · <span class="sect">{{ "%-8s"|format(article.category|string) }}</span> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
{% include 'pagination.html' %}
{% endblock %}

View file

@ -2,7 +2,7 @@
{% block title %}{{ page.title|striptags }} · {{ SITENAME }}{% endblock %}
{% block content %}
<pre class="rule">════════════════════════════════════════════════════════════════════════════════</pre>
<pre class="msghdr"> Subj : <span class="subj">{{ page.title|striptags }}</span></pre>
<pre class="msghdr pagehdr"> Subj : <span class="subj">{{ page.title|striptags }}</span></pre>
<pre class="rule">════════════════════════════════════════════════════════════════════════════════</pre>
<div class="msgbody">{{ page.content }}</div>
{% endblock %}

View file

@ -2,12 +2,24 @@
{% block title %}{{ tag }} · {{ SITENAME }}{% endblock %}
{% block content %}
{% set t = "KEYWORD: " ~ tag %}
<pre class="box">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (75 - t|length) }}┐</pre>
{%- set total = articles_paginator.object_list|length %}
<div class="desktop-only">
<pre class="box">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (75 - t|length) }}┐</pre>
{%- for a in articles_page.object_list %}
{%- set n = loop.index0 + 1 + (articles_page.number - 1) * articles_paginator.per_page %}
<pre class="box">│ <span class="key">[<b>{{ "%2d"|format(n) }}</b>]</span> <span class="date">{{ a.date.strftime('%d %b %y')|lower }}</span> <span class="sect">{{ "%-8s"|format(a.category|string) }}</span> <a data-key="{{ n }}" href="{{ SITEURL }}/{{ a.url }}">{{ "%-52s"|format(a.title|striptags|truncate(52, true, '')) }}</a> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────────────────────────────────────────────┘</pre>
</div>
<div class="mobile-only">
<pre class="box">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (35 - t|length) }}┐</pre>
{%- for a in articles_page.object_list %}
{%- set n = loop.index0 + 1 + (articles_page.number - 1) * articles_paginator.per_page %}
<pre class="box">│ <a data-key="{{ n }}" href="{{ SITEURL }}/{{ a.url }}"><span class="key">[<b>{{ "%2d"|format(n) }}</b>]</span> {{ "%-31s"|format(a.title|striptags|truncate(31, true, '', 0)) }}</a> │</pre>
<pre class="box">│ <span class="date">{{ a.date.strftime('%d %b %y')|lower }}</span> · <span class="sect">{{ "%-8s"|format(a.category|string) }}</span> │</pre>
{%- endfor %}
<pre class="box">└──────────────────────────────────────┘</pre>
</div>
{% include 'pagination.html' %}
{% endblock %}

View file

@ -2,7 +2,9 @@
{% block title %}Keywords · {{ SITENAME }}{% endblock %}
{% block content %}
{% set t = "KEYWORDS" %}
<pre class="box">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (75 - t|length) }}┐</pre>
<pre class="box desktop-only">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (75 - t|length) }}┐</pre>
<pre class="box mobile-only">┌─ <span class="boxtitle">{{ t }}</span> {{ "─" * (35 - t|length) }}┐</pre>
<div class="cloud">{% for tg, arts in tags|sort %}<span class="key">[<b>{{ loop.index }}</b>]</span><a data-key="{{ loop.index }}" href="{{ SITEURL }}/{{ tg.url }}">{{ tg }}</a><span class="num">({{ arts|length }})</span> {% endfor %}</div>
<pre class="box">└──────────────────────────────────────────────────────────────────────────────┘</pre>
<pre class="box desktop-only">└──────────────────────────────────────────────────────────────────────────────┘</pre>
<pre class="box mobile-only">└──────────────────────────────────────┘</pre>
{% endblock %}