Files
rose-ash/federation/sexp/social.sexpr
giles f9d9697c67
All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m20s
Externalize sexp to .sexpr files + render() API
Replace all 676 inline sexp() string calls across 7 services with
render(component_name, **kwargs) calls backed by 46 external .sexpr
component definition files (587 defcomps total).

- Add render() function to shared/sexp/jinja_bridge.py
- Add load_service_components() helper and update load_sexp_dir() for *.sexpr
- Update parser keyword regex to support HTMX hx-on::event syntax
- Convert remaining inline HTML in route files to render() calls
- Add shared/sexp/templates/misc.sexp for cross-service utility components

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-28 16:14:58 +00:00

122 lines
5.6 KiB
Plaintext

;; Social navigation, header, post cards, timeline, compose
;; --- Navigation ---
(defcomp ~federation-nav-choose-username (&key url)
(nav :class "flex gap-3 text-sm items-center"
(a :href url :class "px-2 py-1 rounded hover:bg-stone-200 font-bold" "Choose username")))
(defcomp ~federation-nav-link (&key href cls label)
(a :href href :class cls (raw! label)))
(defcomp ~federation-nav-notification-link (&key href cls count-url)
(a :href href :class cls "Notifications"
(span :hx-get count-url :hx-trigger "load, every 30s" :hx-swap "innerHTML"
:class "absolute -top-2 -right-3 text-xs bg-red-500 text-white rounded-full px-1 empty:hidden")))
(defcomp ~federation-nav-bar (&key items-html)
(nav :class "flex gap-3 text-sm items-center flex-wrap" (raw! items-html)))
(defcomp ~federation-social-header (&key nav-html)
(div :id "social-row" :class "flex flex-col items-center md:flex-row justify-center md:justify-between w-full p-1 bg-sky-400"
(div :class "w-full flex flex-row items-center gap-2 flex-wrap" (raw! nav-html))))
(defcomp ~federation-header-child (&key inner-html)
(div :id "root-header-child" :class "flex flex-col w-full items-center" (raw! inner-html)))
;; --- Post card ---
(defcomp ~federation-boost-label (&key name)
(div :class "text-sm text-stone-500 mb-2" "Boosted by " (raw! name)))
(defcomp ~federation-avatar-img (&key src cls)
(img :src src :alt "" :class cls))
(defcomp ~federation-avatar-placeholder (&key cls initial)
(div :class cls (raw! initial)))
(defcomp ~federation-content-cw (&key summary content)
(details :class "mt-2"
(summary :class "text-stone-500 cursor-pointer" "CW: " (raw! summary))
(div :class "mt-2 prose prose-sm prose-stone max-w-none" (raw! content))))
(defcomp ~federation-content-plain (&key content)
(div :class "mt-2 prose prose-sm prose-stone max-w-none" (raw! content)))
(defcomp ~federation-original-link (&key url)
(a :href url :target "_blank" :rel "noopener"
:class "text-sm text-stone-400 hover:underline mt-1 inline-block" "original"))
(defcomp ~federation-interactions-wrap (&key id buttons-html)
(div :id id (raw! buttons-html)))
(defcomp ~federation-post-card (&key boost-html avatar-html actor-name actor-username domain-html time-html content-html original-html interactions-html)
(article :class "bg-white rounded-lg shadow-sm border border-stone-200 p-4 mb-4"
(raw! boost-html)
(div :class "flex items-start gap-3"
(raw! avatar-html)
(div :class "flex-1 min-w-0"
(div :class "flex items-baseline gap-2"
(span :class "font-semibold text-stone-900" (raw! actor-name))
(span :class "text-sm text-stone-500" "@" (raw! actor-username) (raw! domain-html))
(span :class "text-sm text-stone-400 ml-auto" (raw! time-html)))
(raw! content-html) (raw! original-html) (raw! interactions-html)))))
;; --- Interaction buttons ---
(defcomp ~federation-reply-link (&key url)
(a :href url :class "hover:text-stone-700" "Reply"))
(defcomp ~federation-like-form (&key action target oid ainbox csrf cls icon count)
(form :hx-post action :hx-target target :hx-swap "innerHTML"
(input :type "hidden" :name "object_id" :value oid)
(input :type "hidden" :name "author_inbox" :value ainbox)
(input :type "hidden" :name "csrf_token" :value csrf)
(button :type "submit" :class cls (span (raw! icon)) " " (raw! count))))
(defcomp ~federation-boost-form (&key action target oid ainbox csrf cls count)
(form :hx-post action :hx-target target :hx-swap "innerHTML"
(input :type "hidden" :name "object_id" :value oid)
(input :type "hidden" :name "author_inbox" :value ainbox)
(input :type "hidden" :name "csrf_token" :value csrf)
(button :type "submit" :class cls (span "\u21bb") " " (raw! count))))
(defcomp ~federation-interaction-buttons (&key like-html boost-html reply-html)
(div :class "flex items-center gap-4 mt-3 text-sm text-stone-500"
(raw! like-html) (raw! boost-html) (raw! reply-html)))
;; --- Timeline ---
(defcomp ~federation-scroll-sentinel (&key url)
(div :hx-get url :hx-trigger "revealed" :hx-swap "outerHTML"))
(defcomp ~federation-compose-button (&key url)
(a :href url :class "bg-stone-800 text-white px-4 py-2 rounded hover:bg-stone-700" "Compose"))
(defcomp ~federation-timeline-page (&key label compose-html timeline-html)
(div :class "flex items-center justify-between mb-6"
(h1 :class "text-2xl font-bold" (raw! label) " Timeline")
(raw! compose-html))
(div :id "timeline" (raw! timeline-html)))
;; --- Compose ---
(defcomp ~federation-compose-reply (&key reply-to)
(input :type "hidden" :name "in_reply_to" :value reply-to)
(div :class "text-sm text-stone-500" "Replying to " (span :class "font-mono" (raw! reply-to))))
(defcomp ~federation-compose-form (&key action csrf reply-html)
(h1 :class "text-2xl font-bold mb-6" "Compose")
(form :method "post" :action action :class "space-y-4"
(input :type "hidden" :name "csrf_token" :value csrf)
(raw! reply-html)
(textarea :name "content" :rows "6" :maxlength "5000" :required true
:class "w-full border border-stone-300 rounded-lg p-3 focus:outline-none focus:ring-2 focus:ring-stone-500"
:placeholder "What's on your mind?")
(div :class "flex items-center justify-between"
(select :name "visibility" :class "border border-stone-300 rounded px-3 py-1.5 text-sm"
(option :value "public" "Public")
(option :value "unlisted" "Unlisted")
(option :value "followers" "Followers only"))
(button :type "submit" :class "bg-stone-800 text-white px-6 py-2 rounded hover:bg-stone-700" "Publish"))))