All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 2m6s
sx-headers attributes now use native SX dict format {:key val} instead of
JSON strings. Eliminates manual JSON string construction in both .sx files
and Python callers.
- sx.js: parse sx-headers/sx-vals as SX dict ({: prefix) with JSON fallback,
add _serializeDict for dict→attribute serialization, fix verbInfo scope in
_doFetch error handler
- html.py: serialize dict attribute values via SX serialize() not str()
- All .sx files: {:X-CSRFToken csrf} replaces (str "{\"X-CSRFToken\": ...}")
- All Python callers: {"X-CSRFToken": csrf} dict replaces f-string JSON
- Blog like: extract ~blog-like-toggle, fix POST returning wrong component,
fix emoji escapes in .sx (parser has no \U support), fix card :hx-headers
keyword mismatch, wrap sx_content in SxExpr for evaluation
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
63 lines
2.9 KiB
Plaintext
63 lines
2.9 KiB
Plaintext
;; Newsletter management components
|
|
|
|
(defcomp ~account-newsletter-desc (&key description)
|
|
(when description
|
|
(p :class "text-xs text-stone-500 mt-0.5 truncate" description)))
|
|
|
|
(defcomp ~account-newsletter-toggle (&key id url hdrs target cls checked knob-cls)
|
|
(div :id id :class "flex items-center"
|
|
(button :sx-post url :sx-headers hdrs :sx-target target :sx-swap "outerHTML"
|
|
:class cls :role "switch" :aria-checked checked
|
|
(span :class knob-cls))))
|
|
|
|
|
|
(defcomp ~account-newsletter-item (&key name desc toggle)
|
|
(div :class "flex items-center justify-between py-4 first:pt-0 last:pb-0"
|
|
(div :class "min-w-0 flex-1"
|
|
(p :class "text-sm font-medium text-stone-800" name)
|
|
desc)
|
|
(div :class "ml-4 flex-shrink-0" toggle)))
|
|
|
|
(defcomp ~account-newsletter-list (&key items)
|
|
(div :class "divide-y divide-stone-100" items))
|
|
|
|
(defcomp ~account-newsletter-empty ()
|
|
(p :class "text-sm text-stone-500" "No newsletters available."))
|
|
|
|
(defcomp ~account-newsletters-panel (&key list)
|
|
(div :class "w-full max-w-3xl mx-auto px-4 py-6"
|
|
(div :class "bg-white/70 backdrop-blur rounded-2xl shadow border border-stone-200 p-6 sm:p-8 space-y-6"
|
|
(h1 :class "text-xl font-semibold tracking-tight" "Newsletters")
|
|
list)))
|
|
|
|
;; Assembled newsletters content — replaces Python _newsletters_panel_sx
|
|
;; Takes pre-fetched newsletter-list from page helper
|
|
(defcomp ~account-newsletters-content (&key newsletter-list account-url)
|
|
(let* ((csrf (csrf-token)))
|
|
(if (empty? newsletter-list)
|
|
(~account-newsletter-empty)
|
|
(~account-newsletters-panel
|
|
:list (~account-newsletter-list
|
|
:items (map (lambda (item)
|
|
(let* ((nl (get item "newsletter"))
|
|
(un (get item "un"))
|
|
(nid (get nl "id"))
|
|
(subscribed (get item "subscribed"))
|
|
(toggle-url (str (or account-url "") "/newsletter/" nid "/toggle/"))
|
|
(bg (if subscribed "bg-emerald-500" "bg-stone-300"))
|
|
(translate (if subscribed "translate-x-6" "translate-x-1"))
|
|
(checked (if subscribed "true" "false")))
|
|
(~account-newsletter-item
|
|
:name (get nl "name")
|
|
:desc (when (get nl "description")
|
|
(~account-newsletter-desc :description (get nl "description")))
|
|
:toggle (~account-newsletter-toggle
|
|
:id (str "nl-" nid)
|
|
:url toggle-url
|
|
:hdrs {:X-CSRFToken csrf}
|
|
:target (str "#nl-" nid)
|
|
:cls (str "relative inline-flex h-6 w-11 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-emerald-500 focus:ring-offset-2 " bg)
|
|
:checked checked
|
|
:knob-cls (str "inline-block h-4 w-4 rounded-full bg-white shadow transform transition-transform " translate)))))
|
|
newsletter-list))))))
|