Created
November 15, 2022 08:51
-
-
Save plexus/55f2f16d87ef6aefed6af9845e9fc9e2 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns co.gaiwan.slack-widgets.ui.components | |
(:require | |
[clojure.string :as str] | |
[clojure.walk :as walk] | |
[reagent.core :as reagent] | |
[reagent.ratom :as ratom] | |
[lambdaisland.glogi :as log] | |
[co.gaiwan.slack-widgets.ui.state :as state] | |
[lambdaisland.ornament :as o]) | |
(:require-macros [co.gaiwan.slack-widgets.ui.macros :refer [for!]])) | |
(defn emoji [code] | |
(if-let [unicode-or-url (state/lookup-emoji code)] | |
(if (str/starts-with? unicode-or-url "http") | |
[:img.emoji {:src unicode-or-url}] | |
[:span.emoji {:title code} unicode-or-url]) | |
[:span.emoji code])) | |
(o/defstyled reaction-bar :div | |
:mt-1 :flex :items-start :flex-wrap | |
[:.reaction :rounded :bg-gray-100 :mr-3 :px-2 :py-0.5 :text-xs | |
[:img :w-4 :inline]] | |
([{:keys [reactions reply-count]}] | |
[:<> | |
(for [[code count] reactions] | |
(when (> count 0) | |
^{:key code} | |
[:div.reaction [emoji code] " " count])) | |
(when (> reply-count 0) | |
[:div.replies reply-count " replies"])])) | |
(defn expand-markup [hiccup] | |
(walk/postwalk | |
(fn [item] | |
(cond | |
(seq? item) | |
(into [:<>] item) | |
(and (vector? item) (keyword? (first item))) | |
(case (first item) | |
:slack-widgets/emoji | |
[emoji (-> item second :name)] | |
:slack-widgets/user | |
[:span "@" (:user/real-name (second item))] | |
:slack-widgets/channel | |
[:span "#" (:channel/name (second item))] | |
item) | |
:else | |
item)) | |
hiccup)) | |
(o/defstyled message-item-social :div | |
[:.message :flex :items-start :mb-4 | |
[:>img :w-10 :h-10 :rounded :mr-3] | |
[:>.right | |
{:margin-top "-0.5rem"} | |
:flex-1 :overflow-hidden | |
[:>.content :text-black :leading-normal]] | |
[:.title | |
[:.display-name :font-bold :text-sm] | |
[:.ts :text-grey :text-xs :ml-2]]] | |
[:.score :text-gray-400] | |
([channel-id ts] | |
(let [{:message/keys [hiccup reactions permalink time replies timestamp] | |
:user/keys [name real-name] | |
:user-profile/keys [display-name image-48] | |
channel-link :channel/link | |
user-profile-link :user-profile/link | |
:as message} | |
@(state/message channel-id ts)] | |
[:div.message | |
{:data-ts timestamp} | |
[:img {:src image-48}] | |
[:div.right | |
[:div.title | |
[:span.display-name display-name] | |
[:a {:rel "nofollow" :href permalink :target "_blank"} | |
[:span.ts {:title "Open message in Slack"} @(state/ts->relative-time timestamp)]] | |
[:small.score (str " Score: " (state/pure-score message) | |
#_@(state/relevancy channel-id ts))]] | |
#_(log/trace :hiccup/rendering {:h hiccup | |
:e (expand-markup hiccup)}) | |
[:p.content (expand-markup hiccup)] | |
[reaction-bar {:reactions reactions | |
:reply-count (count replies)}]]]))) | |
(o/defstyled message-item-live :div | |
[:.message :flex :items-start :flex-col :mb-4 :bg-white :rounded :rounded-lg | |
:max-w-md :px-8 :py-8 :mx-auto | |
[:>.top :flex :items-start :items-center :justify-center :flex | |
[:>img :w-12 :h-12 :rounded :mr-4 :rounded :rounded-full] | |
[:>right :flex-1 :overflow-hidden | |
]] | |
[:>.bottom :mt-4 | |
[:>.content :text-black :leading-normal | |
{:font-size "1.625rem"}]] | |
[:.title | |
[:.display-name :font-bold] | |
[:.ts :text-grey :text-xs :font-light]]] | |
([channel-id ts] | |
(let [{:message/keys [hiccup reactions permalink time replies timestamp] | |
:user/keys [name real-name] | |
:user-profile/keys [display-name real-name image-48] | |
channel-link :channel/link | |
user-profile-link :user-profile/link | |
:as message} | |
@(state/message channel-id ts)] | |
[:div.message | |
{:data-ts timestamp} | |
[:div.top | |
[:img {:src image-48}] | |
[:div.right | |
[:div.title | |
[:div | |
[:div.display-name (or display-name real-name)] | |
[:a {:rel "nofollow" :href permalink :target "_blank"} | |
[:span.ts {:title "Open message in Slack"} @(state/ts->relative-time timestamp)]]]]]] | |
[:div.bottom | |
[:p.content (expand-markup hiccup)] | |
[reaction-bar {:reactions reactions | |
:reply-count (count replies)}]]]))) | |
(o/defstyled main :div | |
:p-2 :w-full :bg-black :mx-auto | |
[:h2 :text-4xl :text-white :text-center] | |
[:h2.title :mt-8 :mb-2] | |
[:h2.title-channel-name :text-2xl :font-bold :mt-8 :mb-8] | |
([channel-id] | |
[:<> | |
#_[:h2.title "top comments from"] | |
[:h2.title-channel-name (str "#" (:channel/name @(state/channel channel-id)))] | |
[:div.message-wrapper | |
(for! [ts @(state/relevant-message-ids channel-id)] | |
^{:key ts} | |
[message-item-live channel-id ts])]])) | |
(o/defstyled rounded-button :button | |
:inline-block | |
:px-2 :rounded :rounded-full :text-xs :bg-gray-200 :whitespace-nowrap | |
:shadow-lg | |
:leading-4 :py-2 :ml-1) | |
(o/defstyled tweetable-message-item :div | |
:relative | |
:flex | |
[:>.overlay-buttons :absolute :top-0 :right-0] | |
[message-item-social :flex-grow] | |
([channel-id ts] | |
[:<> | |
[message-item-social channel-id ts] | |
(let [{:message/keys [text-rendered]} @(state/message channel-id ts)] | |
[:div.overlay-buttons | |
[rounded-button | |
{:on-click (fn [_] (js/navigator.clipboard.writeText text-rendered))} | |
"Copy to clipboard"] | |
[:a {:class [rounded-button] | |
:href (str "https://twitter.com/intent/tweet?text=" | |
(js/encodeURIComponent (:message/text-rendered @(state/message channel-id ts)))) | |
:target "_blank"} | |
"Tweet"]])])) | |
(o/defstyled social-media-widget :div | |
:lg:container :mx-auto | |
:p-2 | |
[:h2 :text-lg :font-bold :mb-1] | |
[:.channel-id :text-gray-300 :text-sm] | |
[:.chan-name :mr-2 :px-1 :font-bold :text-lg :rounded] | |
[:.brief-explanation :text-sm :text-gray-600 :mb-2] | |
[:.active :text-white :bg-black] | |
[:.messages :mt-2] | |
([channel-ids !active-channel] | |
(let [active-channel @!active-channel] | |
[:<> | |
[:h2 "Social media tool" [:span.channel-id " #" active-channel]] | |
[:p.brief-explanation "Lists highest scoring messages, in chronological order. Score is calculated based on number of reactions and replies a message receives."] | |
[:p | |
(for! [chan-id channel-ids] | |
^{:key (str "chan-name-" chan-id)} | |
[:a.chan-name {:class (cond-> [] | |
(= chan-id active-channel) | |
(conj "active")) | |
:on-click #(reset! !active-channel chan-id)} | |
(:channel/name @(state/channel chan-id))])] | |
[:div.messages | |
(for! [ts @(state/channel-message-ids-by-ts active-channel)] | |
^{:key ts} | |
[tweetable-message-item active-channel ts])]]))) | |
(defn social-media-page [channel-ids] | |
(let [active-channel (reagent/atom (first channel-ids))] | |
(fn [channel-ids] | |
[social-media-widget channel-ids active-channel]))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment