(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))