Unify post admin nav across all services
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m56s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m56s
Move post admin header into shared/sexp/helpers.py so blog, cart, events, and market all render the same admin row with identical nav: calendars | markets | payments | entries | data | edit | settings. All links are external (cross-service). The selected item shows highlighted on the right and as white text next to "admin" on the left. - blog: delegates to shared helper, removes blog-specific nav builder - cart: delegates to shared helper for payments admin - events: adds shared admin row (selected=calendars) to calendar admin - market: adds /<slug>/admin/ route + page_admin blueprint, delegates to shared helper (selected=markets). Fixes 404 on page-level admin. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,8 @@ from __future__ import annotations
|
||||
|
||||
from typing import Any
|
||||
|
||||
from markupsafe import escape
|
||||
|
||||
from .jinja_bridge import render
|
||||
from .page import SEARCH_HEADERS_MOBILE, SEARCH_HEADERS_DESKTOP
|
||||
|
||||
@@ -104,6 +106,62 @@ def post_header_html(ctx: dict, *, oob: bool = False) -> str:
|
||||
)
|
||||
|
||||
|
||||
def post_admin_header_html(ctx: dict, slug: str, *, oob: bool = False,
|
||||
selected: str = "", admin_href: str = "") -> str:
|
||||
"""Shared post admin header row with unified nav across all services.
|
||||
|
||||
Shows: calendars | markets | payments | entries | data | edit | settings
|
||||
All links are external (cross-service). The *selected* item is
|
||||
highlighted on the nav and shown in white next to the admin label.
|
||||
"""
|
||||
# Label: shield icon + "admin" + optional selected sub-page in white
|
||||
label_html = '<i class="fa fa-shield-halved" aria-hidden="true"></i> admin'
|
||||
if selected:
|
||||
label_html += f' <span class="text-white">{escape(selected)}</span>'
|
||||
|
||||
# Nav items — all external links to the appropriate service
|
||||
select_colours = ctx.get("select_colours", "")
|
||||
base_cls = ("justify-center cursor-pointer flex flex-row items-center"
|
||||
" gap-2 rounded bg-stone-200 text-black p-3")
|
||||
selected_cls = ("justify-center cursor-pointer flex flex-row items-center"
|
||||
" gap-2 rounded !bg-stone-500 !text-white p-3")
|
||||
nav_parts: list[str] = []
|
||||
items = [
|
||||
("events_url", f"/{slug}/admin/", "calendars"),
|
||||
("market_url", f"/{slug}/admin/", "markets"),
|
||||
("cart_url", f"/{slug}/admin/payments/", "payments"),
|
||||
("blog_url", f"/{slug}/admin/entries/", "entries"),
|
||||
("blog_url", f"/{slug}/admin/data/", "data"),
|
||||
("blog_url", f"/{slug}/admin/edit/", "edit"),
|
||||
("blog_url", f"/{slug}/admin/settings/", "settings"),
|
||||
]
|
||||
for url_key, path, label in items:
|
||||
url_fn = ctx.get(url_key)
|
||||
if not callable(url_fn):
|
||||
continue
|
||||
href = url_fn(path)
|
||||
is_sel = label == selected
|
||||
cls = selected_cls if is_sel else base_cls
|
||||
aria = ' aria-selected="true"' if is_sel else ""
|
||||
nav_parts.append(
|
||||
f'<div class="relative nav-group">'
|
||||
f'<a href="{escape(href)}"{aria}'
|
||||
f' class="{cls} {escape(select_colours)}">'
|
||||
f'{escape(label)}</a></div>'
|
||||
)
|
||||
nav_html = "".join(nav_parts)
|
||||
|
||||
if not admin_href:
|
||||
blog_fn = ctx.get("blog_url")
|
||||
admin_href = blog_fn(f"/{slug}/admin/") if callable(blog_fn) else f"/{slug}/admin/"
|
||||
|
||||
return render("menu-row",
|
||||
id="post-admin-row", level=2,
|
||||
link_href=admin_href, link_label_html=label_html,
|
||||
nav_html=nav_html, child_id="post-admin-header-child", oob=oob,
|
||||
)
|
||||
|
||||
|
||||
def oob_header_html(parent_id: str, child_id: str, row_html: str) -> str:
|
||||
"""Wrap a header row in an OOB swap div with child placeholder."""
|
||||
return render("oob-header",
|
||||
|
||||
Reference in New Issue
Block a user