;; Newsletter management components (defcomp ~newsletters/desc (&key (description :as string)) (when description (p :class "text-xs text-stone-500 mt-0.5 truncate" description))) (defcomp ~newsletters/toggle (&key (id :as string) (url :as string) (hdrs :as dict) (target :as string) (cls :as string) (checked :as string) (knob-cls :as string)) (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 ~newsletters/item (&key (name :as string) 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 ~newsletters/list (&key items) (div :class "divide-y divide-stone-100" items)) (defcomp ~newsletters/empty () (p :class "text-sm text-stone-500" "No newsletters available.")) (defcomp ~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 ~newsletters/content (&key (newsletter-list :as list) (account-url :as string?)) (let* ((csrf (csrf-token))) (if (empty? newsletter-list) (~newsletters/empty) (~newsletters/panel :list (~newsletters/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"))) (~newsletters/item :name (get nl "name") :desc (when (get nl "description") (~newsletters/desc :description (get nl "description"))) :toggle (~newsletters/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))))))