<feed xmlns='http://www.w3.org/2005/Atom'>
<title>blogspace/internal/web/theme.go, branch master</title>
<subtitle>blogspace</subtitle>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/'/>
<entry>
<title>Remove the menu fold</title>
<updated>2026-09-18T21:04:08+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-18T21:04:08+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=c42c56108ebac6673ec5c86f9f0d51f31e8eb2bd'/>
<id>c42c56108ebac6673ec5c86f9f0d51f31e8eb2bd</id>
<content type='text'>
The header menu no longer folds into a ☰ button: the nav_fold and
nav_fold_label options, Layout.Fold/BurgerAt, the burger markup and its
checkbox, the fold rules in blog.css and the measuring script on the
public page are gone, and the Design tab's preview only sizes its frame
again. The public page runs no script of its own once more.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The header menu no longer folds into a ☰ button: the nav_fold and
nav_fold_label options, Layout.Fold/BurgerAt, the burger markup and its
checkbox, the fold rules in blog.css and the measuring script on the
public page are gone, and the Design tab's preview only sizes its frame
again. The public page runs no script of its own once more.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Show a live preview of the header on the Design tab's Menu card</title>
<updated>2026-09-18T16:34:35+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-18T16:34:35+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=96336d8bacd2bdf81acf9a18e2fe57be9d4e9b4f'/>
<id>96336d8bacd2bdf81acf9a18e2fe57be9d4e9b4f</id>
<content type='text'>
The menu options had grown to a dozen switches with nothing to look at
but the blog after a save. A new POST /b/{sub}/design/preview reads the
form as a save would and renders the header alone — the real blog.css
and theme CSS, the modules in their order, the menu as edited — into a
sandboxed frame that refreshes shortly after every change, with a Wide
screen / Phone toggle. Nothing is stored.

The frame keeps the dashboard's origin (allow-same-origin, no scripts)
so the blog's logo and fonts, linked through /b/&lt;sub&gt;/media since the
root host's /media is the root blog's, get the session cookie; that is
safe because no header module is owner HTML. The frame runs no scripts,
so the page's own script folds the menu in it the way the blog does.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The menu options had grown to a dozen switches with nothing to look at
but the blog after a save. A new POST /b/{sub}/design/preview reads the
form as a save would and renders the header alone — the real blog.css
and theme CSS, the modules in their order, the menu as edited — into a
sandboxed frame that refreshes shortly after every change, with a Wide
screen / Phone toggle. Nothing is stored.

The frame keeps the dashboard's origin (allow-same-origin, no scripts)
so the blog's logo and fonts, linked through /b/&lt;sub&gt;/media since the
root host's /media is the root blog's, get the session cookie; that is
safe because no header module is owner HTML. The frame runs no scripts,
so the page's own script folds the menu in it the way the blog does.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Fold the header menu into a button when its links do not fit</title>
<updated>2026-09-18T16:29:30+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-18T16:29:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=63f9fdff6e5bdf6333a4b7813ebeb5b797838b6d'/>
<id>63f9fdff6e5bdf6333a4b7813ebeb5b797838b6d</id>
<content type='text'>
A long menu wrapped onto two or three lines on phones and narrow
windows. With the new Design switch the header menu folds into a ☰
button (an icon, the word Menu, or both) carried by the title or logo
block just above it, at the right end of its row, or by the menu bar
when nothing is above it; the button opens the links as a stacked list
with the search box on top.

The open/closed state is a hidden checkbox and the button its label,
so opening needs no script and works in old browsers. Whether to fold
is decided by a small inline script — any link on a second line means
the menu does not fit — re-checked on resize; without it blog.css folds
on phones only, and browsers too old for that keep the wrapping menu.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
A long menu wrapped onto two or three lines on phones and narrow
windows. With the new Design switch the header menu folds into a ☰
button (an icon, the word Menu, or both) carried by the title or logo
block just above it, at the right end of its row, or by the menu bar
when nothing is above it; the button opens the links as a stacked list
with the search box on top.

The open/closed state is a hidden checkbox and the button its label,
so opening needs no script and works in old browsers. Whether to fold
is decided by a small inline script — any link on a second line means
the menu does not fit — re-checked on resize; without it blog.css folds
on phones only, and browsers too old for that keep the wrapping menu.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Add menu link size, spacing, a current-page mark and a spread alignment</title>
<updated>2026-09-18T16:18:30+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-18T16:18:30+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=0a248d9a0e6ef6439fca25aa854968b6b5dac2ef'/>
<id>0a248d9a0e6ef6439fca25aa854968b6b5dac2ef</id>
<content type='text'>
Size and spacing selects, a choice of how the current page's link is
marked (underlined as before, bold, boxed or not at all) and a fourth
alignment that spreads the header's links across the bar. Alignment
joins the other menu classes on the body, so the theme CSS no longer
sets it; spread is justified text with a full-width last line, which
old browsers lay out too, and stays out of the column menus.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Size and spacing selects, a choice of how the current page's link is
marked (underlined as before, bold, boxed or not at all) and a fourth
alignment that spreads the header's links across the bar. Alignment
joins the other menu classes on the body, so the theme CSS no longer
sets it; spread is justified text with a full-width last line, which
old browsers lay out too, and stays out of the column menus.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Make the menu link styles switches that combine</title>
<updated>2026-09-18T16:17:17+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-18T16:17:17+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=b88a7d22c8d79b30de3403c631dd2c5f67669537'/>
<id>b88a7d22c8d79b30de3403c631dd2c5f67669537</id>
<content type='text'>
The one "Link style" select (normal, uppercase, plain) could not give
uppercase links without the bold, or underlined bold links. Bold,
uppercase and the underline (never, on hover, always) are now separate
switches, drawn by blog.css from body classes (Theme.NavClass) so the
theme CSS only colours the links. A stored nav_style is mapped onto the
switches when the theme is read and dropped on the next save; themes
without either keep the bold, underline-on-hover look blog.css always had.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The one "Link style" select (normal, uppercase, plain) could not give
uppercase links without the bold, or underlined bold links. Bold,
uppercase and the underline (never, on hover, always) are now separate
switches, drawn by blog.css from body classes (Theme.NavClass) so the
theme CSS only colours the links. A stored nav_style is mapped onto the
switches when the theme is read and dropped on the next save; themes
without either keep the bold, underline-on-hover look blog.css always had.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Add switches to keep announcements off a page or off post pages</title>
<updated>2026-09-18T08:22:25+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-18T08:22:25+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=ac125593efe689fabd1e48a7023249c8973698b8'/>
<id>ac125593efe689fabd1e48a7023249c8973698b8</id>
<content type='text'>
Announcements showed on every public page. Now each page has a "Show
announcements on this page" checkbox (pages.show_notices, on by default)
that covers the page and its posts, and the Design tab's Content section
has "Show announcements on post pages" (theme.post_notices, on by default)
for bloggers who want notices only on listings, not while reading a post.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Announcements showed on every public page. Now each page has a "Show
announcements on this page" checkbox (pages.show_notices, on by default)
that covers the page and its posts, and the Design tab's Content section
has "Show announcements on post pages" (theme.post_notices, on by default)
for bloggers who want notices only on listings, not while reading a post.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Add Fira Code as a built-in font choice</title>
<updated>2026-09-17T19:54:19+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-17T19:54:19+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=ad30b38759dc222a7137598559998acbd0c06740'/>
<id>ad30b38759dc222a7137598559998acbd0c06740</id>
<content type='text'>
The variable face (v6.2, OFL, licence alongside) is bundled in static/ and
declared as @font-face whenever the text or heading font is "fira"; the
stack falls back through Fira Mono, Menlo and Consolas to Courier.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The variable face (v6.2, OFL, licence alongside) is bundled in static/ and
declared as @font-face whenever the text or heading font is "fira"; the
stack falls back through Fira Mono, Menlo and Consolas to Courier.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Make the blog text a little smaller and tighter</title>
<updated>2026-09-17T19:48:37+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-17T19:48:37+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=9d3ab1b781a712b73311d2f2b0b822ae02de99ff'/>
<id>9d3ab1b781a712b73311d2f2b0b822ae02de99ff</id>
<content type='text'>
Normal is 16px on 1.5 lines (was 17px on 1.55), small 14px and large 18px,
matching the owner's reference site.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
Normal is 16px on 1.5 lines (was 17px on 1.55), small 14px and large 18px,
matching the owner's reference site.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Add a page width: cap the columns at so many pixels, centred or at the left</title>
<updated>2026-09-17T19:29:43+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-17T19:29:43+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=51ca573ef0c1ce4bd2ef7b7525e5543800fd1988'/>
<id>51ca573ef0c1ce4bd2ef7b7525e5543800fd1988</id>
<content type='text'>
The header's and footer's text follows the cap when they already follow
the main column; their backgrounds stay full width. The inset that lines
them up with the main column is now exact — the wrap's 1em plus the
column's share of the wrap's content box — and, with a page width, uses
min() so it is right whether the page or the screen is the narrower.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
The header's and footer's text follows the cap when they already follow
the main column; their backgrounds stay full width. The inset that lines
them up with the main column is now exact — the wrap's 1em plus the
column's share of the wrap's content box — and, with a page width, uses
min() so it is right whether the page or the screen is the narrower.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
<entry>
<title>Replace the colons title rule with a double dotted border</title>
<updated>2026-09-17T18:54:38+00:00</updated>
<author>
<name>grm</name>
<email>grm@eyesin.space</email>
</author>
<published>2026-09-17T18:54:38+00:00</published>
<link rel='alternate' type='text/html' href='https://git.eyesin.space/blogspace/commit/?id=b83e241a331d24718527467e70ae9879f16a71d1'/>
<id>b83e241a331d24718527467e70ae9879f16a71d1</id>
<content type='text'>
A row of ":" characters did not read as a rule. "Double dots" is what the
reference site does: the 3px dotted border and an absolutely positioned
::after carrying a second one 2px above it.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</content>
<content type='xhtml'>
<div xmlns='http://www.w3.org/1999/xhtml'>
<pre>
A row of ":" characters did not read as a rule. "Double dots" is what the
reference site does: the 3px dotted border and an absolutely positioned
::after carrying a second one 2px above it.

Co-Authored-By: Claude Opus 5 &lt;noreply@anthropic.com&gt;
Claude-Session: https://claude.ai/code/session_01Sd8UPWrvyYCLj97JexNw3A
</pre>
</div>
</content>
</entry>
</feed>
