Eliminate post sub-admin rows, highlight active nav on admin row
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m15s

Remove the separate sub-admin header rows (data, entries, edit, settings)
that caused duplicate/stale rows on HTMX navigation and font styling breaks.
Instead, pass selected= to the admin row to highlight the active nav item
via aria-selected styling. External nav items (calendars, markets, payments)
also gain is-selected and select-colours support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-28 20:40:03 +00:00
parent 3dd62bd9bf
commit 8cfa12de6b
2 changed files with 27 additions and 85 deletions

View File

@@ -10,8 +10,12 @@
(defcomp ~blog-admin-label ()
(<> (i :class "fa fa-shield-halved" :aria-hidden "true") " admin"))
(defcomp ~blog-admin-nav-item (&key href nav-btn-class label)
(div :class "relative nav-group" (a :href href :class nav-btn-class label)))
(defcomp ~blog-admin-nav-item (&key href nav-btn-class label is-selected select-colours)
(div :class "relative nav-group"
(a :href href
:aria-selected (when is-selected "true")
:class (str (or nav-btn-class "justify-center cursor-pointer flex flex-row items-center gap-2 rounded bg-stone-200 text-black p-3") " " (or select-colours ""))
label)))
(defcomp ~blog-sub-settings-label (&key icon label)
(<> (i :class icon :aria-hidden "true") " " label))

View File

@@ -86,7 +86,7 @@ def _post_header_html(ctx: dict, *, oob: bool = False) -> str:
# Post admin header
# ---------------------------------------------------------------------------
def _post_admin_header_html(ctx: dict, *, oob: bool = False) -> str:
def _post_admin_header_html(ctx: dict, *, oob: bool = False, selected: str = "") -> str:
"""Post admin header row with admin icon and nav links."""
from quart import url_for as qurl
@@ -100,7 +100,7 @@ def _post_admin_header_html(ctx: dict, *, oob: bool = False) -> str:
admin_href = qurl("blog.post.admin.admin", slug=slug)
label_html = render("blog-admin-label")
nav_html = _post_admin_nav_html(ctx)
nav_html = _post_admin_nav_html(ctx, selected=selected)
return render("menu-row",
id="post-admin-row", level=2,
@@ -109,7 +109,7 @@ def _post_admin_header_html(ctx: dict, *, oob: bool = False) -> str:
)
def _post_admin_nav_html(ctx: dict) -> str:
def _post_admin_nav_html(ctx: dict, *, selected: str = "") -> str:
"""Post admin desktop nav: calendars, markets, payments, entries, data, edit, settings."""
from quart import url_for as qurl
@@ -136,6 +136,7 @@ def _post_admin_nav_html(ctx: dict) -> str:
href = url_fn(path)
parts.append(render("blog-admin-nav-item",
href=href, nav_btn_class=nav_btn, label=label,
is_selected=(label == selected), select_colours=select_colours,
))
# HTMX links
@@ -148,6 +149,7 @@ def _post_admin_nav_html(ctx: dict) -> str:
href = qurl(endpoint, slug=slug)
parts.append(render("nav-link",
href=href, label=label, select_colours=select_colours,
is_selected=(label == selected),
))
return "".join(parts)
@@ -1415,32 +1417,16 @@ async def render_post_admin_oob(ctx: dict) -> str:
async def render_post_data_page(ctx: dict) -> str:
root_hdr = root_header_html(ctx)
post_hdr = _post_header_html(ctx)
admin_hdr = _post_admin_header_html(ctx)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
data_hdr = _post_sub_admin_header_html(
"post_data-row", "post_data-header-child",
qurl("blog.post.admin.data", slug=slug),
"database", "data", ctx,
)
header_rows = root_hdr + post_hdr + admin_hdr + data_hdr
admin_hdr = _post_admin_header_html(ctx, selected="data")
header_rows = root_hdr + post_hdr + admin_hdr
content = ctx.get("data_html", "")
return full_page(ctx, header_rows_html=header_rows, content_html=content)
async def render_post_data_oob(ctx: dict) -> str:
admin_hdr_oob = _post_admin_header_html(ctx, oob=True)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
data_hdr = _post_sub_admin_header_html(
"post_data-row", "post_data-header-child",
qurl("blog.post.admin.data", slug=slug),
"database", "data", ctx,
)
data_oob = _oob_header_html("post-admin-header-child", "post_data-header-child",
data_hdr)
admin_hdr_oob = _post_admin_header_html(ctx, oob=True, selected="data")
content = ctx.get("data_html", "")
return oob_page(ctx, oobs_html=admin_hdr_oob + data_oob, content_html=content)
return oob_page(ctx, oobs_html=admin_hdr_oob, content_html=content)
# ---- Post entries ----
@@ -1448,32 +1434,16 @@ async def render_post_data_oob(ctx: dict) -> str:
async def render_post_entries_page(ctx: dict) -> str:
root_hdr = root_header_html(ctx)
post_hdr = _post_header_html(ctx)
admin_hdr = _post_admin_header_html(ctx)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
entries_hdr = _post_sub_admin_header_html(
"post_entries-row", "post_entries-header-child",
qurl("blog.post.admin.entries", slug=slug),
"clock", "entries", ctx,
)
header_rows = root_hdr + post_hdr + admin_hdr + entries_hdr
admin_hdr = _post_admin_header_html(ctx, selected="entries")
header_rows = root_hdr + post_hdr + admin_hdr
content = ctx.get("entries_html", "")
return full_page(ctx, header_rows_html=header_rows, content_html=content)
async def render_post_entries_oob(ctx: dict) -> str:
admin_hdr_oob = _post_admin_header_html(ctx, oob=True)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
entries_hdr = _post_sub_admin_header_html(
"post_entries-row", "post_entries-header-child",
qurl("blog.post.admin.entries", slug=slug),
"clock", "entries", ctx,
)
entries_oob = _oob_header_html("post-admin-header-child", "post_entries-header-child",
entries_hdr)
admin_hdr_oob = _post_admin_header_html(ctx, oob=True, selected="entries")
content = ctx.get("entries_html", "")
return oob_page(ctx, oobs_html=admin_hdr_oob + entries_oob, content_html=content)
return oob_page(ctx, oobs_html=admin_hdr_oob, content_html=content)
# ---- Post edit ----
@@ -1481,15 +1451,8 @@ async def render_post_entries_oob(ctx: dict) -> str:
async def render_post_edit_page(ctx: dict) -> str:
root_hdr = root_header_html(ctx)
post_hdr = _post_header_html(ctx)
admin_hdr = _post_admin_header_html(ctx)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
edit_hdr = _post_sub_admin_header_html(
"post_edit-row", "post_edit-header-child",
qurl("blog.post.admin.edit", slug=slug),
"pen-to-square", "edit", ctx,
)
header_rows = root_hdr + post_hdr + admin_hdr + edit_hdr
admin_hdr = _post_admin_header_html(ctx, selected="edit")
header_rows = root_hdr + post_hdr + admin_hdr
content = ctx.get("edit_html", "")
body_end = ctx.get("body_end_html", "")
return full_page(ctx, header_rows_html=header_rows, content_html=content,
@@ -1497,18 +1460,9 @@ async def render_post_edit_page(ctx: dict) -> str:
async def render_post_edit_oob(ctx: dict) -> str:
admin_hdr_oob = _post_admin_header_html(ctx, oob=True)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
edit_hdr = _post_sub_admin_header_html(
"post_edit-row", "post_edit-header-child",
qurl("blog.post.admin.edit", slug=slug),
"pen-to-square", "edit", ctx,
)
edit_oob = _oob_header_html("post-admin-header-child", "post_edit-header-child",
edit_hdr)
admin_hdr_oob = _post_admin_header_html(ctx, oob=True, selected="edit")
content = ctx.get("edit_html", "")
return oob_page(ctx, oobs_html=admin_hdr_oob + edit_oob, content_html=content)
return oob_page(ctx, oobs_html=admin_hdr_oob, content_html=content)
# ---- Post settings ----
@@ -1516,32 +1470,16 @@ async def render_post_edit_oob(ctx: dict) -> str:
async def render_post_settings_page(ctx: dict) -> str:
root_hdr = root_header_html(ctx)
post_hdr = _post_header_html(ctx)
admin_hdr = _post_admin_header_html(ctx)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
settings_hdr = _post_sub_admin_header_html(
"post_settings-row", "post_settings-header-child",
qurl("blog.post.admin.settings", slug=slug),
"cog", "settings", ctx,
)
header_rows = root_hdr + post_hdr + admin_hdr + settings_hdr
admin_hdr = _post_admin_header_html(ctx, selected="settings")
header_rows = root_hdr + post_hdr + admin_hdr
content = ctx.get("settings_html", "")
return full_page(ctx, header_rows_html=header_rows, content_html=content)
async def render_post_settings_oob(ctx: dict) -> str:
admin_hdr_oob = _post_admin_header_html(ctx, oob=True)
from quart import url_for as qurl
slug = (ctx.get("post") or {}).get("slug", "")
settings_hdr = _post_sub_admin_header_html(
"post_settings-row", "post_settings-header-child",
qurl("blog.post.admin.settings", slug=slug),
"cog", "settings", ctx,
)
settings_oob = _oob_header_html("post-admin-header-child", "post_settings-header-child",
settings_hdr)
admin_hdr_oob = _post_admin_header_html(ctx, oob=True, selected="settings")
content = ctx.get("settings_html", "")
return oob_page(ctx, oobs_html=admin_hdr_oob + settings_oob, content_html=content)
return oob_page(ctx, oobs_html=admin_hdr_oob, content_html=content)
# ---- Settings home ----