;; 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"))))