diff --git a/shared/static/wasm/sx/boot.sx b/shared/static/wasm/sx/boot.sx index 767400e0..a7cbbdeb 100644 --- a/shared/static/wasm/sx/boot.sx +++ b/shared/static/wasm/sx/boot.sx @@ -506,9 +506,14 @@ (when entry (let ((target (host-get entry "t"))) (when (and target (host-get target "isConnected")) + (dom-remove-class target "sx-pending") (host-call target "click"))))) (loop (+ i 1))))))) - (host-set! (dom-window) "_sxQ" nil)))))) + (host-set! (dom-window) "_sxQ" nil) + ;; Clear any remaining pending indicators + (for-each (fn (el) (dom-remove-class el "sx-pending")) + (dom-query-all (dom-body) ".sx-pending"))))))) + ;; -------------------------------------------------------------------------- diff --git a/shared/sx/templates/shell.sx b/shared/sx/templates/shell.sx index 08688ed7..e7e92e2f 100644 --- a/shared/sx/templates/shell.sx +++ b/shared/sx/templates/shell.sx @@ -77,7 +77,8 @@ details.group{overflow:hidden}details.group>summary{list-style:none}details.grou ;; Server-rendered HTML — visible immediately before JS loads (div :id "sx-root" (raw! (or body-html ""))) ;; Event buffer — captures clicks during hydration gap, replayed after boot - (script (raw! "document.addEventListener('click',function(e){var i=e.target.closest('[data-sx-island]');if(i&&!i['_sxBoundisland-hydrated']){e.stopPropagation();(window._sxQ=window._sxQ||[]).push({t:e.target,ts:Date.now()})}},true)")) + (style (raw! "@keyframes sx-pending-pulse{0%,100%{opacity:1}50%{opacity:.5}}.sx-pending{animation:sx-pending-pulse .8s ease-in-out infinite}")) + (script (raw! "document.addEventListener('click',function(e){var i=e.target.closest('[data-sx-island]');if(i&&!i['_sxBoundisland-hydrated']){e.stopPropagation();var t=e.target.closest('button,a,[role=button]')||e.target;t.classList.add('sx-pending');(window._sxQ=window._sxQ||[]).push({t:t,ts:Date.now()})}},true)")) (script :type "text/sx" :data-components true :data-hash component-hash (raw! (or component-defs ""))) (when init-sx diff --git a/web/boot.sx b/web/boot.sx index 767400e0..a7cbbdeb 100644 --- a/web/boot.sx +++ b/web/boot.sx @@ -506,9 +506,14 @@ (when entry (let ((target (host-get entry "t"))) (when (and target (host-get target "isConnected")) + (dom-remove-class target "sx-pending") (host-call target "click"))))) (loop (+ i 1))))))) - (host-set! (dom-window) "_sxQ" nil)))))) + (host-set! (dom-window) "_sxQ" nil) + ;; Clear any remaining pending indicators + (for-each (fn (el) (dom-remove-class el "sx-pending")) + (dom-query-all (dom-body) ".sx-pending"))))))) + ;; --------------------------------------------------------------------------