Files
giles 22802bd36b
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 5m35s
Send all responses as sexp wire format with client-side rendering
- 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>
2026-03-01 09:45:07 +00:00

84 lines
2.6 KiB
HTML

{# Shared search input macros for filter UIs #}
{% macro search_mobile(current_local_href, search, search_count, hx_select) -%}
<div
id="search-mobile-wrapper"
class="flex flex-row gap-2 items-center flex-1 min-w-0 pr-2"
>
<input
id="search-mobile"
type="text"
name="search"
aria-label="search"
class="text-base md:text-sm col-span-5 rounded-md px-3 py-2 mb-2 w-full min-w-0 max-w-full border-2 border-stone-200 placeholder-shown:border-stone-200 [&:not(:placeholder-shown)]:border-yellow-200"
sx-preserve
value="{{ search|default('', true) }}"
placeholder="search"
sx-trigger="input changed delay:300ms"
sx-target="#main-panel"
sx-select="{{hx_select}}, #search-mobile-wrapper, #search-desktop-wrapper"
sx-get="{{ (current_local_href ~ {'search': None}|qs)|host }}"
sx-swap="outerHTML"
sx-push-url="true"
sx-headers='{"X-Origin":"search-mobile", "X-Search":"true"}'
sx-sync="this:replace"
autocomplete="off"
>
<div
id="search-count-mobile"
aria-label="search count"
{% if not search_count %}
class="text-xl text-red-500"
{% endif %}
>
{% if search %}
{{search_count}}
{% endif %}
</div>
</div>
{%- endmacro %}
{% macro search_desktop(current_local_href, search, search_count, hx_select) -%}
<div
id="search-desktop-wrapper"
class="flex flex-row gap-2 items-center"
>
<input
id="search-desktop"
type="text"
name="search"
aria-label="search"
class="w-full mx-1 my-3 px-3 py-2 text-md rounded-xl border-2 shadow-sm border-white placeholder-shown:border-white [&:not(:placeholder-shown)]:border-yellow-200"
sx-preserve
value="{{ search|default('', true) }}"
placeholder="search"
sx-trigger="input changed delay:300ms"
sx-target="#main-panel"
sx-select="{{hx_select}}, #search-mobile-wrapper, #search-desktop-wrapper"
sx-get="{{ (current_local_href ~ {'search': None}|qs)|host}}"
sx-swap="outerHTML"
sx-push-url="true"
sx-headers='{"X-Origin":"search-desktop", "X-Search":"true"}'
sx-sync="this:replace"
autocomplete="off"
>
<div
id="search-count-desktop"
aria-label="search count"
{% if not search_count %}
class="text-xl text-red-500"
{% endif %}
>
{% if search %}
{{search_count}}
{% endif %}
{{zap_filter}}
</div>
</div>
{%- endmacro %}