Send all responses as sexp wire format with client-side rendering
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m35s
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m35s
- Server sends sexp source text, client (sexp.js) renders everything - SexpExpr marker class for nested sexp composition in serialize() - sexp_page() HTML shell with data-mount="body" for full page loads - sexp_response() returns text/sexp for OOB/partial responses - ~app-body layout component replaces ~app-layout (no raw!) - ~rich-text is the only component using raw! (for CMS HTML content) - Fragment endpoints return text/sexp, auto-wrapped in SexpExpr - All _*_html() helpers converted to _*_sexp() returning sexp source - Head auto-hoist: sexp.js moves meta/title/link/script[ld+json] from rendered body to document.head automatically - Unknown components render warning box instead of crashing page - Component kwargs preserve AST for lazy rendering (fixes <> in kwargs) - Fix unterminated paren in events/sexp/tickets.sexpr Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -20,9 +20,9 @@
|
||||
<div
|
||||
id="sentinel-{{ page }}"
|
||||
class="h-4 opacity-0 pointer-events-none"
|
||||
hx-get="{{ entries_url }}"
|
||||
hx-trigger="intersect once delay:250ms"
|
||||
hx-swap="outerHTML"
|
||||
sx-get="{{ entries_url }}"
|
||||
sx-trigger="intersect once delay:250ms"
|
||||
sx-swap="outerHTML"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
>
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
{% set tile_href = (current_local_href ~ {'view': 'tile'}|qs)|host %}
|
||||
<a
|
||||
href="{{ list_href }}"
|
||||
hx-get="{{ list_href }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{hx_select_search}}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-get="{{ list_href }}"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{hx_select_search}}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
class="p-1.5 rounded {{ 'bg-stone-200 text-stone-800' if view != 'tile' else 'text-stone-400 hover:text-stone-600' }}"
|
||||
title="List view"
|
||||
_="on click js localStorage.removeItem('events_view') end"
|
||||
onclick="localStorage.removeItem('events_view')"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16" />
|
||||
@@ -19,14 +19,14 @@
|
||||
</a>
|
||||
<a
|
||||
href="{{ tile_href }}"
|
||||
hx-get="{{ tile_href }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{hx_select_search}}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-get="{{ tile_href }}"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{hx_select_search}}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
class="p-1.5 rounded {{ 'bg-stone-200 text-stone-800' if view == 'tile' else 'text-stone-400 hover:text-stone-600' }}"
|
||||
title="Tile view"
|
||||
_="on click js localStorage.setItem('events_view','tile') end"
|
||||
onclick="localStorage.setItem('events_view','tile')"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM14 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1V5zM4 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1v-4zM14 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z" />
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div
|
||||
id="calendar-description-title"
|
||||
{% if oob %}
|
||||
hx-swap-oob="outerHTML"
|
||||
sx-swap-oob="outerHTML"
|
||||
{% endif %}
|
||||
class="text-base font-normal break-words whitespace-normal min-w-0 break-all w-full text-center block"
|
||||
>
|
||||
|
||||
@@ -10,14 +10,14 @@
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_year,
|
||||
month=month) }}"
|
||||
hx-get="{{ url_for('calendar.get',
|
||||
sx-get="{{ url_for('calendar.get',
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_year,
|
||||
month=month) }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
>
|
||||
«
|
||||
</a>
|
||||
@@ -29,14 +29,14 @@
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_month_year,
|
||||
month=prev_month) }}"
|
||||
hx-get="{{ url_for('calendar.get',
|
||||
sx-get="{{ url_for('calendar.get',
|
||||
calendar_slug=calendar.slug,
|
||||
year=prev_month_year,
|
||||
month=prev_month) }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
>
|
||||
‹
|
||||
</a>
|
||||
@@ -52,14 +52,14 @@
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_month_year,
|
||||
month=next_month) }}"
|
||||
hx-get="{{ url_for('calendar.get',
|
||||
sx-get="{{ url_for('calendar.get',
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_month_year,
|
||||
month=next_month) }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
>
|
||||
›
|
||||
</a>
|
||||
@@ -71,14 +71,14 @@
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_year,
|
||||
month=month) }}"
|
||||
hx-get="{{ url_for('calendar.get',
|
||||
sx-get="{{ url_for('calendar.get',
|
||||
calendar_slug=calendar.slug,
|
||||
year=next_year,
|
||||
month=month) }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
>
|
||||
»
|
||||
</a>
|
||||
@@ -115,15 +115,15 @@
|
||||
year=day.date.year,
|
||||
month=day.date.month,
|
||||
day=day.date.day) }}"
|
||||
hx-get="{{ url_for('calendar.day.show_day',
|
||||
sx-get="{{ url_for('calendar.day.show_day',
|
||||
calendar_slug=calendar.slug,
|
||||
year=day.date.year,
|
||||
month=day.date.month,
|
||||
day=day.date.day) }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
>
|
||||
{{ day.date.day }}
|
||||
</a>
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
<button
|
||||
type="button"
|
||||
class="mt-2 text-xs underline"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.admin.calendar_description_edit',
|
||||
calendar_slug=calendar.slug,
|
||||
) }}"
|
||||
hx-target="#calendar-description"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#calendar-description"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<i class="fas fa-edit"></i>
|
||||
</button>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<div id="calendar-description">
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
sx-post="{{ url_for(
|
||||
'calendar.admin.calendar_description_save',
|
||||
calendar_slug=calendar.slug,
|
||||
) }}"
|
||||
hx-target="#calendar-description"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#calendar-description"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
@@ -27,12 +27,12 @@
|
||||
<button
|
||||
type="button"
|
||||
class="px-3 py-1 rounded border"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.admin.calendar_description_view',
|
||||
calendar_slug=calendar.slug,
|
||||
) }}"
|
||||
hx-target="#calendar-description"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#calendar-description"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
<form
|
||||
id="calendar-form"
|
||||
method="post"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-on::before-request="document.querySelector('#cal-put-errors').textContent='';"
|
||||
hx-on::response-error="document.querySelector('#cal-put-errors').innerHTML = event.detail.xhr.responseText;"
|
||||
hx-on::after-request="if (event.detail.successful) this.reset()"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-on:beforeRequest="document.querySelector('#cal-put-errors').textContent='';"
|
||||
sx-on:responseError="if(event.detail.response){event.detail.response.clone().text().then(function(t){document.querySelector('#cal-put-errors').innerHTML=t})}"
|
||||
sx-on:afterRequest="if (event.detail.successful) this.reset()"
|
||||
|
||||
class="hidden space-y-4 mt-4"
|
||||
autocomplete="off"
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
<a
|
||||
class="flex items-baseline gap-3"
|
||||
href="{{ calendar_href }}"
|
||||
hx-get="{{ calendar_href }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select ="{{hx_select_search}}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-get="{{ calendar_href }}"
|
||||
sx-target="#main-panel"
|
||||
sx-select ="{{hx_select_search}}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
>
|
||||
<h3 class="font-semibold">{{ cal.name }}</h3>
|
||||
<h4 class="text-gray-500">/{{ cal.slug }}/</h4>
|
||||
@@ -27,12 +27,12 @@
|
||||
data-confirm-confirm-text="Yes, delete it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for('calendar.delete', calendar_slug=cal.slug) }}"
|
||||
hx-trigger="confirmed"
|
||||
hx-target="#calendars-list"
|
||||
hx-select="#calendars-list"
|
||||
hx-swap="outerHTML"
|
||||
hx-headers='{"X-CSRFToken":"{{ csrf_token() }}"}'
|
||||
sx-delete="{{ url_for('calendar.delete', calendar_slug=cal.slug) }}"
|
||||
sx-trigger="confirmed"
|
||||
sx-target="#calendars-list"
|
||||
sx-select="#calendars-list"
|
||||
sx-swap="outerHTML"
|
||||
sx-headers='{"X-CSRFToken":"{{ csrf_token() }}"}'
|
||||
>
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
|
||||
@@ -5,12 +5,12 @@
|
||||
|
||||
<form
|
||||
class="mt-4 flex gap-2 items-end"
|
||||
hx-post="{{ url_for('calendars.create_calendar') }}"
|
||||
hx-target="#calendars-list"
|
||||
hx-select="#calendars-list"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::before-request="document.querySelector('#cal-create-errors').textContent='';"
|
||||
hx-on::response-error="document.querySelector('#cal-create-errors').innerHTML = event.detail.xhr.responseText;"
|
||||
sx-post="{{ url_for('calendars.create_calendar') }}"
|
||||
sx-target="#calendars-list"
|
||||
sx-select="#calendars-list"
|
||||
sx-swap="outerHTML"
|
||||
sx-on:beforeRequest="document.querySelector('#cal-create-errors').textContent='';"
|
||||
sx-on:responseError="if(event.detail.response){event.detail.response.clone().text().then(function(t){document.querySelector('#cal-create-errors').innerHTML=t})}"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="flex-1">
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
<form
|
||||
class="mt-4 grid grid-cols-1 md:grid-cols-4 gap-2"
|
||||
hx-post="{{ url_for(
|
||||
sx-post="{{ url_for(
|
||||
'calendar.day.calendar_entries.add_entry',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
month=month,
|
||||
year=year,
|
||||
) }}"
|
||||
hx-target="#day-entries"
|
||||
hx-on::after-request="if (event.detail.successful) this.reset()"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#day-entries"
|
||||
sx-on:afterRequest="if (event.detail.successful) this.reset()"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
@@ -123,14 +123,14 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('calendar.day.calendar_entries.add_button',
|
||||
sx-get="{{ url_for('calendar.day.calendar_entries.add_button',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
month=month,
|
||||
year=year,
|
||||
) }}"
|
||||
hx-target="#entry-add-container"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#entry-add-container"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -2,15 +2,15 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.day.calendar_entries.add_form',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
month=month,
|
||||
year=year,
|
||||
) }}"
|
||||
hx-target="#entry-add-container"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#entry-add-container"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
+ Add entry
|
||||
</button>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% if confirmed_entries %}
|
||||
<div class="flex flex-col sm:flex-row sm:items-center gap-2 border-r border-stone-200 mr-2 sm:max-w-2xl"
|
||||
id="day-entries-nav-wrapper"
|
||||
hx-swap-oob="true">
|
||||
sx-swap-oob="true">
|
||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||
{% call(entry) scrolling_menu('day-entries-container', confirmed_entries) %}
|
||||
<a
|
||||
@@ -29,5 +29,5 @@
|
||||
</div>
|
||||
{% else %}
|
||||
{# Empty placeholder to remove nav entries when none are confirmed #}
|
||||
<div id="day-entries-nav-wrapper" hx-swap-oob="true"></div>
|
||||
<div id="day-entries-nav-wrapper" sx-swap-oob="true"></div>
|
||||
{% endif %}
|
||||
|
||||
@@ -6,14 +6,14 @@
|
||||
|
||||
<form
|
||||
class="space-y-3 mt-4"
|
||||
hx-put="{{ url_for(
|
||||
sx-put="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.put',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day, month=month, year=year,
|
||||
entry_id=entry.id
|
||||
) }}"
|
||||
hx-target="#entry-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#entry-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
@@ -161,14 +161,14 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{ styles.cancel_button }}"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.get',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day, month=month, year=year,
|
||||
entry_id=entry.id
|
||||
) }}"
|
||||
hx-target="#entry-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#entry-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -110,7 +110,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.get_edit',
|
||||
entry_id=entry.id,
|
||||
calendar_slug=calendar.slug,
|
||||
@@ -118,8 +118,8 @@
|
||||
month=month,
|
||||
year=year,
|
||||
) }}"
|
||||
hx-target="#entry-{{entry.id}}"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#entry-{{entry.id}}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
|
||||
{% include '_types/entry/_options.html' %}
|
||||
<div id="entry-title-{{entry.id}}" hx-swap-oob="innerHTML">
|
||||
<div id="entry-title-{{entry.id}}" sx-swap-oob="innerHTML">
|
||||
{% include '_types/entry/_title.html' %}
|
||||
</div>
|
||||
|
||||
<div id="entry-state-{{entry.id}}" hx-swap-oob="innerHTML">
|
||||
<div id="entry-state-{{entry.id}}" sx-swap-oob="innerHTML">
|
||||
{% include '_types/entry/_state.html' %}
|
||||
</div>
|
||||
@@ -1,7 +1,7 @@
|
||||
<div id="calendar_entry_options_{{ entry.id }}" class="flex flex-col md:flex-row gap-1">
|
||||
{% if entry.state == 'provisional' %}
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
sx-post="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.confirm_entry',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -9,9 +9,9 @@
|
||||
year=year,
|
||||
entry_id=entry.id
|
||||
) }}"
|
||||
hx-select="#calendar_entry_options_{{ entry.id }}"
|
||||
hx-target="#calendar_entry_options_{{entry.id}}"
|
||||
hx-swap="outerHTML"
|
||||
sx-select="#calendar_entry_options_{{ entry.id }}"
|
||||
sx-target="#calendar_entry_options_{{entry.id}}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button
|
||||
@@ -30,7 +30,7 @@
|
||||
</button>
|
||||
</form>
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
sx-post="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.decline_entry',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -38,9 +38,9 @@
|
||||
year=year,
|
||||
entry_id=entry.id
|
||||
) }}"
|
||||
hx-select="#calendar_entry_options_{{ entry.id }}"
|
||||
hx-target="#calendar_entry_options_{{entry.id}}"
|
||||
hx-swap="outerHTML"
|
||||
sx-select="#calendar_entry_options_{{ entry.id }}"
|
||||
sx-target="#calendar_entry_options_{{entry.id}}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<button
|
||||
@@ -61,7 +61,7 @@
|
||||
{% endif %}
|
||||
{% if entry.state == 'confirmed' %}
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
sx-post="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.provisional_entry',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -69,10 +69,10 @@
|
||||
year=year,
|
||||
entry_id=entry.id
|
||||
) }}"
|
||||
hx-target="#calendar_entry_options_{{ entry.id }}"
|
||||
hx-select="#calendar_entry_options_{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-trigger="confirmed"
|
||||
sx-target="#calendar_entry_options_{{ entry.id }}"
|
||||
sx-select="#calendar_entry_options_{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-trigger="confirmed"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{% for search_post in search_posts %}
|
||||
<form
|
||||
hx-post="{{ url_for(
|
||||
sx-post="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.add_post',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -8,8 +8,8 @@
|
||||
year=year,
|
||||
entry_id=entry.id
|
||||
) }}"
|
||||
hx-target="#entry-posts-{{entry.id}}"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#entry-posts-{{entry.id}}"
|
||||
sx-swap="innerHTML"
|
||||
class="p-2 hover:bg-stone-50 cursor-pointer rounded text-sm border-b"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
@@ -40,7 +40,7 @@
|
||||
{% if page < total_pages|int %}
|
||||
<div
|
||||
id="post-search-sentinel-{{ page }}"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.search_posts',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -50,42 +50,9 @@
|
||||
q=search_query,
|
||||
page=page + 1
|
||||
) }}"
|
||||
hx-trigger="intersect once delay:250ms, sentinel:retry"
|
||||
hx-swap="outerHTML"
|
||||
_="
|
||||
init
|
||||
if not me.dataset.retryMs then set me.dataset.retryMs to 1000 end
|
||||
|
||||
on sentinel:retry
|
||||
remove .hidden from .js-loading in me
|
||||
add .hidden to .js-neterr in me
|
||||
set me.style.pointerEvents to 'none'
|
||||
set me.style.opacity to '0'
|
||||
trigger htmx:consume on me
|
||||
call htmx.trigger(me, 'intersect')
|
||||
end
|
||||
|
||||
def backoff()
|
||||
add .hidden to .js-loading in me
|
||||
remove .hidden from .js-neterr in me
|
||||
set myMs to Number(me.dataset.retryMs)
|
||||
if myMs < 10000 then set me.dataset.retryMs to myMs * 2 end
|
||||
js setTimeout(() => htmx.trigger(me, 'sentinel:retry'), myMs)
|
||||
end
|
||||
|
||||
on htmx:beforeRequest
|
||||
set me.style.pointerEvents to 'none'
|
||||
set me.style.opacity to '0'
|
||||
end
|
||||
|
||||
on htmx:afterSwap
|
||||
set me.dataset.retryMs to 1000
|
||||
end
|
||||
|
||||
on htmx:sendError call backoff()
|
||||
on htmx:responseError call backoff()
|
||||
on htmx:timeout call backoff()
|
||||
"
|
||||
sx-trigger="intersect once delay:250ms"
|
||||
sx-swap="outerHTML"
|
||||
sx-retry="exponential:1000:30000"
|
||||
role="status"
|
||||
aria-live="polite"
|
||||
aria-hidden="true"
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
data-confirm-confirm-text="Yes, remove it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for(
|
||||
sx-delete="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.remove_post',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -31,10 +31,10 @@
|
||||
entry_id=entry.id,
|
||||
post_id=entry_post.id
|
||||
) }}"
|
||||
hx-trigger="confirmed"
|
||||
hx-target="#entry-posts-{{entry.id}}"
|
||||
hx-swap="innerHTML"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
sx-trigger="confirmed"
|
||||
sx-target="#entry-posts-{{entry.id}}"
|
||||
sx-swap="innerHTML"
|
||||
sx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
>
|
||||
<i class="fa fa-times"></i> Remove
|
||||
</button>
|
||||
@@ -54,7 +54,7 @@
|
||||
type="text"
|
||||
placeholder="Search posts..."
|
||||
class="w-full px-3 py-2 border rounded text-sm"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.search_posts',
|
||||
calendar_slug=calendar.slug,
|
||||
day=day,
|
||||
@@ -62,9 +62,9 @@
|
||||
year=year,
|
||||
entry_id=entry.id
|
||||
) }}"
|
||||
hx-trigger="keyup changed delay:300ms, load"
|
||||
hx-target="#post-search-results-{{entry.id}}"
|
||||
hx-swap="innerHTML"
|
||||
sx-trigger="keyup changed delay:300ms, load"
|
||||
sx-target="#post-search-results-{{entry.id}}"
|
||||
sx-swap="innerHTML"
|
||||
name="q"
|
||||
/>
|
||||
<div id="post-search-results-{{entry.id}}" class="mt-2 max-h-96 overflow-y-auto border rounded"></div>
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<form
|
||||
id="ticket-form-{{entry.id}}"
|
||||
class="{% if entry.ticket_price is not none %}hidden{% endif %} space-y-3 mt-2 p-3 border rounded bg-stone-50"
|
||||
hx-post="{{ url_for(
|
||||
sx-post="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.update_tickets',
|
||||
entry_id=entry.id,
|
||||
calendar_slug=calendar.slug,
|
||||
@@ -51,8 +51,8 @@
|
||||
month=month,
|
||||
year=year,
|
||||
) }}"
|
||||
hx-target="#entry-tickets-{{entry.id}}"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#entry-tickets-{{entry.id}}"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<div>
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
{% if entry_posts %}
|
||||
<div class="flex flex-col sm:flex-row sm:items-center gap-2 border-r border-stone-200 mr-2 sm:max-w-2xl"
|
||||
id="entry-posts-nav-wrapper"
|
||||
hx-swap-oob="true">
|
||||
sx-swap-oob="true">
|
||||
{% from 'macros/scrolling_menu.html' import scrolling_menu with context %}
|
||||
{% call(entry_post) scrolling_menu('entry-posts-container', entry_posts) %}
|
||||
<a
|
||||
@@ -27,5 +27,5 @@
|
||||
</div>
|
||||
{% else %}
|
||||
{# Empty placeholder to remove nav posts when all are disassociated #}
|
||||
<div id="entry-posts-nav-wrapper" hx-swap-oob="true"></div>
|
||||
<div id="entry-posts-nav-wrapper" sx-swap-oob="true"></div>
|
||||
{% endif %}
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
<form
|
||||
class="mt-4 flex gap-2 items-end"
|
||||
hx-post="{{ url_for('markets.create_market') }}"
|
||||
hx-target="#markets-list"
|
||||
hx-select="#markets-list"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::before-request="document.querySelector('#market-create-errors').textContent='';"
|
||||
hx-on::response-error="document.querySelector('#market-create-errors').innerHTML = event.detail.xhr.responseText;"
|
||||
sx-post="{{ url_for('markets.create_market') }}"
|
||||
sx-target="#markets-list"
|
||||
sx-select="#markets-list"
|
||||
sx-swap="outerHTML"
|
||||
sx-on:beforeRequest="document.querySelector('#market-create-errors').textContent='';"
|
||||
sx-on:responseError="if(event.detail.response){event.detail.response.clone().text().then(function(t){document.querySelector('#market-create-errors').innerHTML=t})}"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<div class="flex-1">
|
||||
|
||||
@@ -20,12 +20,12 @@
|
||||
data-confirm-confirm-text="Yes, delete it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for('markets.delete_market', market_slug=m.slug) }}"
|
||||
hx-trigger="confirmed"
|
||||
hx-target="#markets-list"
|
||||
hx-select="#markets-list"
|
||||
hx-swap="outerHTML"
|
||||
hx-headers='{"X-CSRFToken":"{{ csrf_token() }}"}'
|
||||
sx-delete="{{ url_for('markets.delete_market', market_slug=m.slug) }}"
|
||||
sx-trigger="confirmed"
|
||||
sx-target="#markets-list"
|
||||
sx-select="#markets-list"
|
||||
sx-swap="outerHTML"
|
||||
sx-headers='{"X-CSRFToken":"{{ csrf_token() }}"}'
|
||||
>
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
</button>
|
||||
|
||||
@@ -20,9 +20,9 @@
|
||||
<div
|
||||
id="sentinel-{{ page }}"
|
||||
class="h-4 opacity-0 pointer-events-none"
|
||||
hx-get="{{ entries_url }}"
|
||||
hx-trigger="intersect once delay:250ms"
|
||||
hx-swap="outerHTML"
|
||||
sx-get="{{ entries_url }}"
|
||||
sx-trigger="intersect once delay:250ms"
|
||||
sx-swap="outerHTML"
|
||||
role="status"
|
||||
aria-hidden="true"
|
||||
>
|
||||
|
||||
@@ -4,14 +4,14 @@
|
||||
{% set tile_href = (current_local_href ~ {'view': 'tile'}|qs)|host %}
|
||||
<a
|
||||
href="{{ list_href }}"
|
||||
hx-get="{{ list_href }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{hx_select_search}}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-get="{{ list_href }}"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{hx_select_search}}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
class="p-1.5 rounded {{ 'bg-stone-200 text-stone-800' if view != 'tile' else 'text-stone-400 hover:text-stone-600' }}"
|
||||
title="List view"
|
||||
_="on click js localStorage.removeItem('events_view') end"
|
||||
onclick="localStorage.removeItem('events_view')"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 6h16M4 12h16M4 18h16" />
|
||||
@@ -19,14 +19,14 @@
|
||||
</a>
|
||||
<a
|
||||
href="{{ tile_href }}"
|
||||
hx-get="{{ tile_href }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{hx_select_search}}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-get="{{ tile_href }}"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{hx_select_search}}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
class="p-1.5 rounded {{ 'bg-stone-200 text-stone-800' if view == 'tile' else 'text-stone-400 hover:text-stone-600' }}"
|
||||
title="Tile view"
|
||||
_="on click js localStorage.setItem('events_view','tile') end"
|
||||
onclick="localStorage.setItem('events_view','tile')"
|
||||
>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" class="h-5 w-5" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2">
|
||||
<path stroke-linecap="round" stroke-linejoin="round" d="M4 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1V5zM14 5a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1V5zM4 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1H5a1 1 0 01-1-1v-4zM14 15a1 1 0 011-1h4a1 1 0 011 1v4a1 1 0 01-1 1h-4a1 1 0 01-1-1v-4z" />
|
||||
|
||||
@@ -8,9 +8,9 @@
|
||||
<form
|
||||
action="{{ ticket_url }}"
|
||||
method="post"
|
||||
hx-post="{{ ticket_url }}"
|
||||
hx-target="#page-ticket-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ ticket_url }}"
|
||||
sx-target="#page-ticket-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<input type="hidden" name="entry_id" value="{{ entry.id }}">
|
||||
@@ -26,9 +26,9 @@
|
||||
<form
|
||||
action="{{ ticket_url }}"
|
||||
method="post"
|
||||
hx-post="{{ ticket_url }}"
|
||||
hx-target="#page-ticket-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ ticket_url }}"
|
||||
sx-target="#page-ticket-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<input type="hidden" name="entry_id" value="{{ entry.id }}">
|
||||
@@ -49,9 +49,9 @@
|
||||
<form
|
||||
action="{{ ticket_url }}"
|
||||
method="post"
|
||||
hx-post="{{ ticket_url }}"
|
||||
hx-target="#page-ticket-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ ticket_url }}"
|
||||
sx-target="#page-ticket-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
<input type="hidden" name="entry_id" value="{{ entry.id }}">
|
||||
|
||||
@@ -9,10 +9,10 @@
|
||||
</p>
|
||||
|
||||
<form
|
||||
hx-put="{{ url_for('payments.update_sumup') }}"
|
||||
hx-target="#payments-panel"
|
||||
hx-swap="outerHTML"
|
||||
hx-select="#payments-panel"
|
||||
sx-put="{{ url_for('payments.update_sumup') }}"
|
||||
sx-target="#payments-panel"
|
||||
sx-swap="outerHTML"
|
||||
sx-select="#payments-panel"
|
||||
class="space-y-3"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
@@ -15,12 +15,12 @@
|
||||
data-confirm-confirm-text="Yes, remove it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-post="{{ url_for('blog.post.admin.toggle_entry', slug=post.slug, entry_id=entry.id) }}"
|
||||
hx-trigger="confirmed"
|
||||
hx-target="#associated-entries-list"
|
||||
hx-swap="outerHTML"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
_="on htmx:afterRequest trigger entryToggled on body"
|
||||
sx-post="{{ url_for('blog.post.admin.toggle_entry', slug=post.slug, entry_id=entry.id) }}"
|
||||
sx-trigger="confirmed"
|
||||
sx-target="#associated-entries-list"
|
||||
sx-swap="outerHTML"
|
||||
sx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
sx-on:afterSwap="document.body.dispatchEvent(new CustomEvent('entryToggled'))"
|
||||
>
|
||||
<div class="flex items-center justify-between gap-3">
|
||||
{% if calendar.post.feature_image %}
|
||||
|
||||
@@ -8,14 +8,7 @@
|
||||
<h3 class="text-lg font-semibold">Browse Calendars</h3>
|
||||
{% for calendar in all_calendars %}
|
||||
<details class="border rounded-lg bg-white"
|
||||
_="on toggle
|
||||
if my.open
|
||||
for other in <details[open]/>
|
||||
if other is not me
|
||||
set other.open to false
|
||||
end
|
||||
end
|
||||
end">
|
||||
data-toggle-group="calendar-browser">
|
||||
<summary class="p-4 cursor-pointer hover:bg-stone-50 flex items-center gap-3">
|
||||
{% if calendar.post.feature_image %}
|
||||
<img src="{{ calendar.post.feature_image }}"
|
||||
@@ -35,8 +28,8 @@
|
||||
</div>
|
||||
</summary>
|
||||
<div class="p-4 border-t"
|
||||
hx-trigger="intersect once"
|
||||
hx-swap="innerHTML">
|
||||
sx-trigger="intersect once"
|
||||
sx-swap="innerHTML">
|
||||
<div class="text-sm text-stone-400">Loading calendar...</div>
|
||||
</div>
|
||||
</details>
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
<div
|
||||
id="slot-description-title"
|
||||
{% if oob %}
|
||||
hx-swap-oob="outerHTML"
|
||||
sx-swap-oob="outerHTML"
|
||||
{% endif %}
|
||||
class="text-base font-normal break-words whitespace-normal min-w-0 break-all w-full text-center block"
|
||||
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
<div id="slot-errors" class="mt-2 text-sm text-red-600"></div>
|
||||
<form
|
||||
class="space-y-3 mt-4"
|
||||
hx-put="{{ url_for('calendar.slots.slot.put',
|
||||
sx-put="{{ url_for('calendar.slots.slot.put',
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=slot.id) }}"
|
||||
hx-target="#slot-{{ slot.id }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::after-request="if (event.detail.successful) this.reset()"
|
||||
sx-target="#slot-{{ slot.id }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-on:afterRequest="if (event.detail.successful) this.reset()"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
@@ -153,11 +153,11 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('calendar.slots.slot.get_view',
|
||||
sx-get="{{ url_for('calendar.slots.slot.get_view',
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=slot.id) }}"
|
||||
hx-target="#slot-{{ slot.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#slot-{{ slot.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -53,13 +53,13 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.slots.slot.get_edit',
|
||||
slot_id=slot.id,
|
||||
calendar_slug=calendar.slug,
|
||||
) }}"
|
||||
hx-target="#slot-{{slot.id}}"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#slot-{{slot.id}}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
<form
|
||||
hx-post="{{ url_for('calendar.slots.post',
|
||||
sx-post="{{ url_for('calendar.slots.post',
|
||||
calendar_slug=calendar.slug) }}"
|
||||
hx-target="#slots-table"
|
||||
hx-select="#slots-table"
|
||||
hx-disinherit="hx-select"
|
||||
hx-swap="outerHTML"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
sx-target="#slots-table"
|
||||
sx-select="#slots-table"
|
||||
sx-disinherit="sx-select"
|
||||
sx-swap="outerHTML"
|
||||
sx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
class="space-y-3"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-4 gap-3">
|
||||
@@ -98,10 +98,10 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('calendar.slots.add_button',
|
||||
sx-get="{{ url_for('calendar.slots.add_button',
|
||||
calendar_slug=calendar.slug) }}"
|
||||
hx-target="#slot-add-container"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#slot-add-container"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for('calendar.slots.add_form',
|
||||
sx-get="{{ url_for('calendar.slots.add_form',
|
||||
calendar_slug=calendar.slug) }}"
|
||||
hx-target="#slot-add-container"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#slot-add-container"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
+ Add slot
|
||||
</button>
|
||||
|
||||
@@ -45,14 +45,14 @@
|
||||
data-confirm-confirm-text="Yes, delete it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for('calendar.slots.slot.slot_delete',
|
||||
sx-delete="{{ url_for('calendar.slots.slot.slot_delete',
|
||||
calendar_slug=calendar.slug,
|
||||
slot_id=s.id) }}"
|
||||
hx-target="#slots-table"
|
||||
hx-select="#slots-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
hx-trigger="confirmed"
|
||||
sx-target="#slots-table"
|
||||
sx-select="#slots-table"
|
||||
sx-swap="outerHTML"
|
||||
sx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
sx-trigger="confirmed"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
|
||||
@@ -43,9 +43,9 @@
|
||||
<td class="px-4 py-2">
|
||||
{% if ticket.state in ('confirmed', 'reserved') %}
|
||||
<form
|
||||
hx-post="{{ url_for('ticket_admin.do_checkin', code=ticket.code) }}"
|
||||
hx-target="#entry-ticket-row-{{ ticket.code }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('ticket_admin.do_checkin', code=ticket.code) }}"
|
||||
sx-target="#entry-ticket-row-{{ ticket.code }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<button
|
||||
|
||||
@@ -52,9 +52,9 @@
|
||||
<div id="checkin-action-{{ ticket.code }}">
|
||||
{% if ticket.state in ('confirmed', 'reserved') %}
|
||||
<form
|
||||
hx-post="{{ url_for('ticket_admin.do_checkin', code=ticket.code) }}"
|
||||
hx-target="#checkin-action-{{ ticket.code }}"
|
||||
hx-swap="innerHTML"
|
||||
sx-post="{{ url_for('ticket_admin.do_checkin', code=ticket.code) }}"
|
||||
sx-target="#checkin-action-{{ ticket.code }}"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<button
|
||||
|
||||
@@ -35,10 +35,10 @@
|
||||
name="code"
|
||||
placeholder="Enter or scan ticket code..."
|
||||
class="flex-1 px-4 py-2 border rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
|
||||
hx-get="{{ url_for('ticket_admin.lookup') }}"
|
||||
hx-trigger="keyup changed delay:300ms"
|
||||
hx-target="#lookup-result"
|
||||
hx-include="this"
|
||||
sx-get="{{ url_for('ticket_admin.lookup') }}"
|
||||
sx-trigger="keyup changed delay:300ms"
|
||||
sx-target="#lookup-result"
|
||||
sx-include="this"
|
||||
autofocus
|
||||
/>
|
||||
<button
|
||||
@@ -112,9 +112,9 @@
|
||||
<td class="px-4 py-3">
|
||||
{% if ticket.state in ('confirmed', 'reserved') %}
|
||||
<form
|
||||
hx-post="{{ url_for('ticket_admin.do_checkin', code=ticket.code) }}"
|
||||
hx-target="#ticket-row-{{ ticket.code }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('ticket_admin.do_checkin', code=ticket.code) }}"
|
||||
sx-target="#ticket-row-{{ ticket.code }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<button
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
<div id="ticket-errors" class="mt-2 text-sm text-red-600"></div>
|
||||
<form
|
||||
class="space-y-3 mt-4"
|
||||
hx-put="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.put',
|
||||
sx-put="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.put',
|
||||
calendar_slug=calendar.slug,
|
||||
year=year,
|
||||
month=month,
|
||||
day=day,
|
||||
entry_id=entry.id,
|
||||
ticket_type_id=ticket_type.id) }}"
|
||||
hx-target="#ticket-{{ ticket_type.id }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-on::after-request="if (event.detail.successful) this.reset()"
|
||||
sx-target="#ticket-{{ ticket_type.id }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-on:afterRequest="if (event.detail.successful) this.reset()"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}">
|
||||
|
||||
@@ -70,15 +70,15 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_view',
|
||||
sx-get="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_view',
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
year=year,
|
||||
month=month,
|
||||
day=day,
|
||||
ticket_type_id=ticket_type.id) }}"
|
||||
hx-target="#ticket-{{ ticket_type.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#ticket-{{ ticket_type.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -32,7 +32,7 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.pre_action_button}}"
|
||||
hx-get="{{ url_for(
|
||||
sx-get="{{ url_for(
|
||||
'calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.get_edit',
|
||||
ticket_type_id=ticket_type.id,
|
||||
calendar_slug=calendar.slug,
|
||||
@@ -41,8 +41,8 @@
|
||||
day=day,
|
||||
entry_id=entry.id,
|
||||
) }}"
|
||||
hx-target="#ticket-{{ticket_type.id}}"
|
||||
hx-swap="outerHTML"
|
||||
sx-target="#ticket-{{ticket_type.id}}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
<form
|
||||
hx-post="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.post',
|
||||
sx-post="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.post',
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
year=year,
|
||||
month=month,
|
||||
day=day,
|
||||
) }}"
|
||||
hx-target="#tickets-table"
|
||||
hx-select="#tickets-table"
|
||||
hx-disinherit="hx-select"
|
||||
hx-swap="outerHTML"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
sx-target="#tickets-table"
|
||||
sx-select="#tickets-table"
|
||||
sx-disinherit="sx-select"
|
||||
sx-swap="outerHTML"
|
||||
sx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
class="space-y-3"
|
||||
>
|
||||
<div class="grid grid-cols-1 md:grid-cols-3 gap-3">
|
||||
@@ -55,15 +55,15 @@
|
||||
<button
|
||||
type="button"
|
||||
class="{{styles.cancel_button}}"
|
||||
hx-get="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.add_button',
|
||||
sx-get="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.add_button',
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
year=year,
|
||||
month=month,
|
||||
day=day,
|
||||
) }}"
|
||||
hx-target="#ticket-add-container"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#ticket-add-container"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
Cancel
|
||||
</button>
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
<button
|
||||
class="{{styles.action_button}}"
|
||||
hx-get="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.add_form',
|
||||
sx-get="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.add_form',
|
||||
calendar_slug=calendar.slug,
|
||||
entry_id=entry.id,
|
||||
year=year,
|
||||
month=month,
|
||||
day=day,
|
||||
) }}"
|
||||
hx-target="#ticket-add-container"
|
||||
hx-swap="innerHTML"
|
||||
sx-target="#ticket-add-container"
|
||||
sx-swap="innerHTML"
|
||||
>
|
||||
<i class="fa fa-plus"></i>
|
||||
Add ticket type
|
||||
|
||||
@@ -35,18 +35,18 @@
|
||||
data-confirm-confirm-text="Yes, delete it"
|
||||
data-confirm-cancel-text="Cancel"
|
||||
data-confirm-event="confirmed"
|
||||
hx-delete="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete',
|
||||
sx-delete="{{ url_for('calendar.day.calendar_entries.calendar_entry.ticket_types.ticket_type.delete',
|
||||
calendar_slug=calendar.slug,
|
||||
year=year,
|
||||
month=month,
|
||||
day=day,
|
||||
entry_id=entry.id,
|
||||
ticket_type_id=tt.id) }}"
|
||||
hx-target="#tickets-table"
|
||||
hx-select="#tickets-table"
|
||||
hx-swap="outerHTML"
|
||||
hx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
hx-trigger="confirmed"
|
||||
sx-target="#tickets-table"
|
||||
sx-select="#tickets-table"
|
||||
sx-swap="outerHTML"
|
||||
sx-headers='{"X-CSRFToken": "{{ csrf_token() }}"}'
|
||||
sx-trigger="confirmed"
|
||||
type="button"
|
||||
>
|
||||
<i class="fa-solid fa-trash"></i>
|
||||
|
||||
@@ -39,9 +39,9 @@
|
||||
{% if type_count == 0 %}
|
||||
{# Add to basket button #}
|
||||
<form
|
||||
hx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
hx-target="#ticket-buy-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
sx-target="#ticket-buy-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
class="flex items-center"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
@@ -59,9 +59,9 @@
|
||||
{# +/- controls #}
|
||||
<div class="flex items-center gap-2">
|
||||
<form
|
||||
hx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
hx-target="#ticket-buy-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
sx-target="#ticket-buy-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<input type="hidden" name="entry_id" value="{{ entry.id }}" />
|
||||
@@ -90,9 +90,9 @@
|
||||
</a>
|
||||
|
||||
<form
|
||||
hx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
hx-target="#ticket-buy-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
sx-target="#ticket-buy-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<input type="hidden" name="entry_id" value="{{ entry.id }}" />
|
||||
@@ -128,9 +128,9 @@
|
||||
{% if qty == 0 %}
|
||||
{# Add to basket button #}
|
||||
<form
|
||||
hx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
hx-target="#ticket-buy-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
sx-target="#ticket-buy-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
class="flex items-center"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
@@ -149,9 +149,9 @@
|
||||
{# +/- controls #}
|
||||
<div class="flex items-center gap-2">
|
||||
<form
|
||||
hx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
hx-target="#ticket-buy-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
sx-target="#ticket-buy-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<input type="hidden" name="entry_id" value="{{ entry.id }}" />
|
||||
@@ -179,9 +179,9 @@
|
||||
</a>
|
||||
|
||||
<form
|
||||
hx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
hx-target="#ticket-buy-{{ entry.id }}"
|
||||
hx-swap="outerHTML"
|
||||
sx-post="{{ url_for('tickets.adjust_quantity') }}"
|
||||
sx-target="#ticket-buy-{{ entry.id }}"
|
||||
sx-swap="outerHTML"
|
||||
>
|
||||
<input type="hidden" name="csrf_token" value="{{ csrf_token() }}" />
|
||||
<input type="hidden" name="entry_id" value="{{ entry.id }}" />
|
||||
|
||||
@@ -1,22 +1,22 @@
|
||||
{# Account nav items: tickets + bookings links for the account dashboard #}
|
||||
<div class="relative nav-group">
|
||||
<a href="{{ account_url('/tickets/') }}"
|
||||
hx-get="{{ account_url('/tickets/') }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-get="{{ account_url('/tickets/') }}"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
class="{{styles.nav_button}}">
|
||||
tickets
|
||||
</a>
|
||||
</div>
|
||||
<div class="relative nav-group">
|
||||
<a href="{{ account_url('/bookings/') }}"
|
||||
hx-get="{{ account_url('/bookings/') }}"
|
||||
hx-target="#main-panel"
|
||||
hx-select="{{ hx_select_search }}"
|
||||
hx-swap="outerHTML"
|
||||
hx-push-url="true"
|
||||
sx-get="{{ account_url('/bookings/') }}"
|
||||
sx-target="#main-panel"
|
||||
sx-select="{{ hx_select_search }}"
|
||||
sx-swap="outerHTML"
|
||||
sx-push-url="true"
|
||||
class="{{styles.nav_button}}">
|
||||
bookings
|
||||
</a>
|
||||
|
||||
Reference in New Issue
Block a user