Browse Source

feat(frontend): add show-more layout component

Miguel Ángel Moreno 1 year ago
parent
commit
9ef93c8d66

+ 34 - 0
src/frontend/tubo/components/layout.cljs

@@ -1,5 +1,6 @@
 (ns tubo.components.layout
   (:require
+   [reagent.core :as r]
    [re-frame.core :as rf]))
 
 (defn logo []
@@ -87,3 +88,36 @@
     right-button]
    (when open?
      (map-indexed #(with-meta %2 {:key %1}) content))])
+
+(defn show-more-container
+  [open? text on-open]
+  (let [!text-container (atom nil)
+        !resize-observer (atom nil)
+        text-clamped? (r/atom nil)]
+    (r/create-class
+     {:display-name "ShowMoreContainer"
+      :component-did-mount
+      (fn [_]
+        (when @!text-container
+          (.observe
+           (reset! !resize-observer
+                   (js/ResizeObserver.
+                    #(let [target (.-target (first %))]
+                       (reset! text-clamped?
+                               (> (.-scrollHeight target)
+                                  (.-clientHeight target))))))
+           @!text-container)))
+      :component-will-unmount
+      #(when (and @!resize-observer @!text-container)
+         (.unobserve @!resize-observer @!text-container))
+      :reagent-render
+      (fn [open? text on-open]
+        [:div.py-3.flex.flex-wrap.min-w-full
+         [:div {:dangerouslySetInnerHTML {:__html text}
+                :class                   (when-not open? "line-clamp-2")
+                :ref                     #(reset! !text-container %)}]
+         (when (or @text-clamped? open?)
+           [:div.flex.justify-center.min-w-full.py-4
+            [secondary-button
+             (if (not open?) "Show More" "Show Less")
+             on-open]])])})))

+ 31 - 27
src/frontend/tubo/views/channel.cljs

@@ -1,35 +1,39 @@
 (ns tubo.views.channel
   (:require
+   [reagent.core :as r]
    [re-frame.core :as rf]
    [tubo.components.items :as items]
    [tubo.components.layout :as layout]
    [tubo.events :as events]))
 
 (defn channel
-  [{{:keys [url]} :query-params}]
-  (let [{:keys [banner avatar name description subscriber-count
-                related-streams next-page]} @(rf/subscribe [:channel])
-        next-page-url (:url next-page)
-        service-color @(rf/subscribe [:service-color])
-        scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])]
-    (when scrolled-to-bottom?
-      (rf/dispatch [::events/channel-pagination url next-page-url]))
-    [layout/content-container
-     (when banner
-       [:div.flex.justify-center
-        [:img.min-w-full {:src banner}]])
-     [:div.flex.items-center.justify-between
-      [:div.flex.items-center.my-4.mx-2
-       [layout/uploader-avatar avatar name]
-       [:div.m-4
-        [:h1.text-xl name]
-        (when subscriber-count
-          [:div.flex.my-2.items-center
-           [:i.fa-solid.fa-users.text-xs]
-           [:span.mx-2 (.toLocaleString subscriber-count)]])]]
-      [layout/primary-button "Enqueue"
-       #(rf/dispatch [::events/enqueue-related-streams related-streams service-color])
-       "fa-solid fa-headphones"]]
-     [:div.my-2
-      [:p description]]
-     [items/related-streams related-streams next-page-url]]))
+  [query-params]
+  (let [!show-description? (r/atom false)]
+    (fn [{{:keys [url]} :query-params}]
+      (let [{:keys [banner avatar name description subscriber-count
+                    related-streams next-page
+                    donation-links] :as channel} @(rf/subscribe [:channel])
+            next-page-url            (:url next-page)
+            service-color            @(rf/subscribe [:service-color])
+            scrolled-to-bottom?      @(rf/subscribe [:scrolled-to-bottom])]
+        (when scrolled-to-bottom?
+          (rf/dispatch [::events/channel-pagination url next-page-url]))
+        [layout/content-container
+         (when banner
+           [:div.flex.justify-center.h-24
+            [:img.min-w-full.min-h-full.object-cover {:src banner}]])
+         [:div.flex.items-center.justify-between
+          [:div.flex.items-center.my-4.mx-2
+           [layout/uploader-avatar avatar name]
+           [:div.m-4
+            [:h1.text-xl name]
+            (when subscriber-count
+              [:div.flex.my-2.items-center
+               [:i.fa-solid.fa-users.text-xs]
+               [:span.mx-2 (.toLocaleString subscriber-count)]])]]
+          [layout/primary-button "Enqueue"
+           #(rf/dispatch [::events/enqueue-related-streams related-streams service-color])
+           "fa-solid fa-headphones"]]
+         [layout/show-more-container @!show-description? description
+          #(reset! !show-description? (not @!show-description?))]
+         [items/related-streams related-streams next-page-url]]))))

+ 8 - 13
src/frontend/tubo/views/stream.cljs

@@ -99,22 +99,17 @@
             [:i.fa-solid.fa-calendar]
             [:span.ml-2 (util/format-date-string upload-date)]])]]
        (when (and show-description? (not (empty? description)))
-         [:div.py-3.flex.flex-wrap.min-w-full
-          [:div {:dangerouslySetInnerHTML {:__html description}
-                 :class                   (when (not show-description) "line-clamp-2")}]
-          [:div.flex.justify-center.font-bold.min-w-full.py-4.cursor-pointer
-           [layout/secondary-button
-            (if (not show-description) "Show More" "Show Less")
-            #(rf/dispatch [::events/toggle-stream-layout :show-description])]]])
+         [layout/show-more-container show-description description
+          #(rf/dispatch [::events/toggle-stream-layout :show-description])])
        (when (and comments-page (not (empty? (:comments comments-page))) show-comments?)
          [layout/accordeon
-          {:label "Comments"
-           :on-open #(if show-comments
-                       (rf/dispatch [::events/toggle-stream-layout :show-comments])
-                       (if comments-page
+          {:label     "Comments"
+           :on-open   #(if show-comments
                          (rf/dispatch [::events/toggle-stream-layout :show-comments])
-                         (rf/dispatch [::events/get-comments url])))
-           :open? show-comments
+                         (if comments-page
+                           (rf/dispatch [::events/toggle-stream-layout :show-comments])
+                           (rf/dispatch [::events/get-comments url])))
+           :open?     show-comments
            :left-icon "fa-solid fa-comments"}
           (if show-comments-loading
             [layout/loading-icon service-color "text-2xl"]