All checks were successful
Build and Deploy / build-and-deploy (push) Successful in 1m20s
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>
122 lines
5.6 KiB
Plaintext
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"))))
|