Phase 4: add container-nav/cards fragment handlers, use market fragment
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m4s

Events provides container-nav (calendar entries + links) and
container-cards (batch entries for blog listing) as fragments.
Day and entry routes fetch market container-nav via fragment instead
of widget registry.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
giles
2026-02-24 13:33:25 +00:00
parent de80c393e4
commit 503f7ca7d8
7 changed files with 165 additions and 47 deletions

View File

@@ -0,0 +1,33 @@
{# Calendar entries for blog listing cards — served as fragment from events app.
Each post's entries are delimited by comment markers so the consumer can
extract per-post HTML via simple string splitting. #}
{% for post_id in post_ids %}
<!-- card-widget:{{ post_id }} -->
{% set widget_entries = batch.get(post_id, []) %}
{% if widget_entries %}
<div class="mt-4 mb-2">
<h3 class="text-sm font-semibold text-stone-700 mb-2 px-2">Events:</h3>
<div class="overflow-x-auto scrollbar-hide" style="scroll-behavior: smooth;">
<div class="flex gap-2 px-2">
{% for entry in widget_entries %}
{% set _post_slug = slug_map.get(post_id, '') %}
{% set _entry_path = '/' + _post_slug + '/calendars/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
<a
href="{{ events_url(_entry_path) }}"
class="flex flex-col gap-1 px-3 py-2 bg-stone-50 hover:bg-stone-100 rounded border border-stone-200 transition text-sm whitespace-nowrap flex-shrink-0 min-w-[180px]">
<div class="font-medium text-stone-900 truncate">{{ entry.name }}</div>
<div class="text-xs text-stone-600">
{{ entry.start_at.strftime('%a, %b %d') }}
</div>
<div class="text-xs text-stone-500">
{{ entry.start_at.strftime('%H:%M') }}
{% if entry.end_at %} {{ entry.end_at.strftime('%H:%M') }}{% endif %}
</div>
</a>
{% endfor %}
</div>
</div>
</div>
{% endif %}
<!-- /card-widget:{{ post_id }} -->
{% endfor %}

View File

@@ -0,0 +1,10 @@
{# Calendar links nav — served as fragment from events app #}
{% for calendar in calendars %}
{% set local_href=events_url('/' + post_slug + '/calendars/' + calendar.slug + '/') %}
<a
href="{{ local_href }}"
class="{{styles.nav_button_less_pad}}">
<i class="fa fa-calendar" aria-hidden="true"></i>
<div>{{calendar.name}}</div>
</a>
{% endfor %}

View File

@@ -0,0 +1,28 @@
{# Calendar entries nav — served as fragment from events app #}
{% for entry in entries %}
{% set _entry_path = '/' + post_slug + '/calendars/' + entry.calendar_slug + '/' + entry.start_at.year|string + '/' + entry.start_at.month|string + '/' + entry.start_at.day|string + '/entries/' + entry.id|string + '/' %}
<a
href="{{ events_url(_entry_path) }}"
class="{{styles.nav_button_less_pad}}"
>
<div class="w-8 h-8 rounded bg-stone-200 flex-shrink-0"></div>
<div class="flex-1 min-w-0">
<div class="font-medium truncate">{{ entry.name }}</div>
<div class="text-xs text-stone-600 truncate">
{{ entry.start_at.strftime('%b %d, %Y at %H:%M') }}
{% if entry.end_at %} {{ entry.end_at.strftime('%H:%M') }}{% endif %}
</div>
</div>
</a>
{% endfor %}
{# Infinite scroll sentinel — URL points back to the consumer app #}
{% if has_more and paginate_url_base %}
<div id="entries-load-sentinel-{{ page }}"
hx-get="{{ paginate_url_base }}?page={{ page + 1 }}"
hx-trigger="intersect once"
hx-swap="beforebegin"
_="on htmx:afterRequest trigger scroll on #associated-entries-container"
class="flex-shrink-0 w-1">
</div>
{% endif %}