computersandblues.lodestone/src/main/computersandblues/lodestone/app.cljs
2025-11-08 16:10:16 +01:00

108 lines
4 KiB
Clojure

(ns computersandblues.lodestone.app
(:require [reagent.core :as r]
[reagent.dom.client :as rd]
[clojure.string :as str]
[clojure.pprint :as pprint]))
(defonce state (r/atom {:root nil
:query nil
; TODO: Handle other lists
:favorites []}))
; TODO: Login / Landing Page / Store bearer token in localstorage
(defn fetch-favs [{:keys [server-url bearer-token]}]
; TODO: Pagination
(let [url (str server-url "/api/v1/favourites")
auth-header (str "Bearer " bearer-token)]
(.. (js/fetch url
#js {:method "GET"
:headers #js {"Authorization" auth-header}})
(then (fn [res]
(if (.-ok res)
(.then (.json res)
(fn [body]
{:raw res
:body (js->clj body {:keywordize-keys true})}))
(do
(println res)
(throw (ex-info "Could not fetch favorites" {:response res})))))))))
(defn search []
[:input {:placeholder "Start typing to search…"
:on-change (fn [e]
(let [query (.. e -target -value)]
(swap! state assoc :query (if (str/blank? query) nil query))))
:value (:query @state)}])
(defn debug [obj]
(let [pprinted (r/atom nil)]
(fn []
[:details.debug {:on-toggle (fn [_]
(when-not @pprinted
(reset! pprinted (with-out-str (pprint/pprint obj)))))}
[:summary "Inspect"]
[:pre @pprinted]])))
(defn user [{:keys [user]}]
(:username user))
(defn attachment [{:keys [attachment]}]
(prn attachment)
(case (:type attachment)
"image" [:img {:src (:preview_url attachment)
:alt (:description attachment)}]))
(defn post [{:keys [post]}]
; TODO: handle (:sensitive post)
; TODO: handle attachments
[:article
[:div.users
[user {:user (:account post)}]
(when (seq (:mentions post))
[:span.mentions
{:style #js {:color "#777"}}
" (mentioining " (->> (map-indexed (fn [idx account]
^{:key idx} [user {:user account}])
(:mentions post))
(interleave (repeat ", "))
(drop 1)) ")"])]
[:div.url [:a {:href (:url post)} (:url post)]]
[:div.content {:dangerouslySetInnerHTML (r/unsafe-html (:content post))}]
(when (seq (:media_attachments post))
[:div.attachments (map-indexed (fn [idx item]
^{:key idx} [attachment {:attachment item}])
(:media_attachments post))])
#_[debug post]])
(defn app []
(let [favorites (:favorites @state)
query (:query @state)
matches? (if query
(partial re-find (js/RegExp. query "i"))
(constantly true))
matches (filter (fn [post]
(or (matches? (:content post))
(matches? (-> post :account :acct)) ; search for url + username of poster
(some #(matches? (:username %)) (:mentions post)))) ; search only for username of mentions
favorites)]
[:div#app
[:h1 "Lodestone"]
[:h2 "Favorites"]
[:span (str "Loaded " (count favorites) " favorites"
(when query
(str ", displaying " (count matches) " matches")))]
[:div [search]]
[:ul (map-indexed (fn [idx favorite]
^{:key idx} [:li [post {:post favorite}]]) matches)]]))
(defn ^:dev/after-load render []
(rd/render (:root @state) [app]))
(defn init []
(-> (fetch-favs {:server-url "https://post.lurk.org"
:bearer-token "CHANGEME"})
(.then #(swap! state assoc :favorites (:body %))))
(swap! state assoc :root (rd/create-root (.-body js/document)))
(render))