From 0efab725aa38fc8a2072d41c50801a7df9771a41 Mon Sep 17 00:00:00 2001 From: Miguel Ángel Moreno Date: Sun, 1 Dec 2024 13:20:15 +0100 Subject: feat: add tabs component for stream metadata --- src/frontend/tubo/comments/views.cljs | 40 +++++---- src/frontend/tubo/layout/views.cljs | 21 +++++ src/frontend/tubo/main_player/views.cljs | 2 +- src/frontend/tubo/stream/views.cljs | 137 ++++++++++++++++++------------- 4 files changed, 124 insertions(+), 76 deletions(-) (limited to 'src/frontend') diff --git a/src/frontend/tubo/comments/views.cljs b/src/frontend/tubo/comments/views.cljs index 2b1bf7f..b148f46 100644 --- a/src/frontend/tubo/comments/views.cljs +++ b/src/frontend/tubo/comments/views.cljs @@ -70,24 +70,28 @@ {:keys [uploader-name uploader-avatar url]}] (let [pagination-loading? @(rf/subscribe [:show-pagination-loading]) service-color @(rf/subscribe [:service-color])] - [:div.flex.flex-col - [:div - (for [[i {:keys [replies show-replies] :as comment}] - (map-indexed vector comments)] - [:div.flex.flex-col {:key i} - [:div.flex - [comment-item - (assoc comment - :author-name uploader-name - :author-avatar uploader-avatar)]] - (when (and replies show-replies) - [:div {:style {:marginLeft "32px"}} - (for [[i reply] (map-indexed vector (:items replies))] - ^{:key i} - [comment-item - (assoc reply - :author-name uploader-name - :author-avatar uploader-avatar)])])])] + [:div.flex.flex-col.py-4 + (if (empty? comments) + [:div.flex.items-center.flex-auto.flex-col.justify-center.gap-y-4.h-44 + [:i.fa-solid.fa-ghost.text-3xl] + [:p.text-lg "No available comments"]] + [:div + (for [[i {:keys [replies show-replies] :as comment}] + (map-indexed vector comments)] + [:div.flex.flex-col {:key i} + [:div.flex + [comment-item + (assoc comment + :author-name uploader-name + :author-avatar uploader-avatar)]] + (when (and replies show-replies) + [:div {:style {:marginLeft "32px"}} + (for [[i reply] (map-indexed vector (:items replies))] + ^{:key i} + [comment-item + (assoc reply + :author-name uploader-name + :author-avatar uploader-avatar)])])])]) (when (:url next-page) (if pagination-loading? [layout/loading-icon service-color] diff --git a/src/frontend/tubo/layout/views.cljs b/src/frontend/tubo/layout/views.cljs index d50c066..f088eef 100644 --- a/src/frontend/tubo/layout/views.cljs +++ b/src/frontend/tubo/layout/views.cljs @@ -236,3 +236,24 @@ [:div.flex.justify-center.gap-x-6 [primary-button "Go Back" #(rf/dispatch [:navigation/history-go -1])] [secondary-button "Retry" #(rf/dispatch cb)]]]]) + +(defn tabs + [tabs] + (let [!current (r/atom (nth tabs 0))] + (fn [tabs & {:keys [on-change]}] + [:div + (into + [:ul.w-full.flex.justify-center.items-center] + (for [[i tab] (map-indexed vector tabs)] + (let [selected? (= (:id tab) (:id @!current))] + (when tab + [:li.flex-auto.flex.justify-center.items-center.font-semibold.border-b-2.border-transparent + {:class (if selected? :border-white :border-transparent) :key i} + [:button.flex-auto.py-4 + {:on-click (when (not selected?) + (fn [] + (reset! !current tab) + (on-change (:id @!current))))} + (if (:label-fn tab) + ((:label-fn tab) (:label tab)) + (:label tab))]]))))]))) diff --git a/src/frontend/tubo/main_player/views.cljs b/src/frontend/tubo/main_player/views.cljs index be4c223..a06164a 100644 --- a/src/frontend/tubo/main_player/views.cljs +++ b/src/frontend/tubo/main_player/views.cljs @@ -30,4 +30,4 @@ [stream/metadata stream] [stream/description stream] [stream/comments stream] - [stream/suggested stream]]])])) + [stream/related-items stream]]])])) diff --git a/src/frontend/tubo/stream/views.cljs b/src/frontend/tubo/stream/views.cljs index c78cfc9..51896f0 100644 --- a/src/frontend/tubo/stream/views.cljs +++ b/src/frontend/tubo/stream/views.cljs @@ -79,80 +79,103 @@ (defn metadata [{:keys [name] :as stream}] [:<> - [:div.flex.items-center.justify-between.my-3 + [:div.flex.items-center.justify-between.mt-3 [:h1.text-lg.sm:text-2xl.font-bold.line-clamp-1 {:title name} name] [:div.hidden.lg:block [metadata-popover stream]]] - [:div.flex.justify-between.py-2.flex-nowrap + [:div.flex.justify-between.py-6.flex-nowrap [metadata-uploader stream] [metadata-stats stream]]]) (defn description - [{:keys [description show-description]}] + [{:keys [description show-description tags]}] (let [show? (:show-description @(rf/subscribe [:settings]))] (when (and show? (seq description)) - [layout/show-more-container show-description description - #(rf/dispatch [(if @(rf/subscribe [:main-player/show]) - :main-player/toggle-layout - :stream/toggle-layout) - :show-description])]))) + [:div + [layout/show-more-container show-description description + #(rf/dispatch [(if @(rf/subscribe [:main-player/show]) + :main-player/toggle-layout + :stream/toggle-layout) + :show-description])] + [:div.flex.gap-2.py-2 + (for [[i tag] (map-indexed vector tags)] + ^{:key i} + [:span.bg-neutral-300.dark:bg-neutral-800.rounded-md.p-2.text-sm + (str "#" tag)])]]))) (defn comments - [{:keys [comments-page show-comments show-comments-loading url] :as stream}] + [{:keys [comments-page show-comments show-comments-loading] :as stream}] (let [show? (:show-comments @(rf/subscribe [:settings])) service-color @(rf/subscribe [:service-color])] - (when (and comments-page (seq (:comments comments-page)) show?) - [layout/accordeon - {:label "Comments" - :on-open #(if show-comments - (rf/dispatch [:stream/toggle-layout :show-comments]) - (if comments-page - (rf/dispatch [:stream/toggle-layout :show-comments]) - (rf/dispatch [:comments/fetch-page url]))) - :open? show-comments - :left-icon "fa-solid fa-comments"} - (if show-comments-loading - [layout/loading-icon service-color "text-2xl"] - (when (and show-comments comments-page) - [comments/comments comments-page stream]))]))) + (when show? + (if show-comments-loading + [layout/loading-icon service-color "text-2xl"] + (when (and show-comments comments-page) + [comments/comments comments-page stream]))))) -(defn suggested +(defn related-items [_] - (let [!menu-active? (r/atom nil)] - (fn [{:keys [related-streams show-related]}] + (let [!menu-active? (r/atom nil) + !layout (r/atom :list)] + (fn [{:keys [related-streams]}] (let [show? (:show-related @(rf/subscribe [:settings]))] (when (and show? (seq related-streams)) - [layout/accordeon - {:label "Suggested" - :on-open #(rf/dispatch [(if @(rf/subscribe [:main-player/show]) - :main-player/toggle-layout - :stream/toggle-layout) - :show-related]) - :open? (not show-related) - :left-icon "fa-solid fa-list" - :right-button [layout/popover-menu !menu-active? - [{:label "Add to queue" - :icon [:i.fa-solid.fa-headphones] - :on-click #(rf/dispatch [:queue/add-n - related-streams true])} - {:label "Add to playlist" - :icon [:i.fa-solid.fa-plus] - :on-click #(rf/dispatch [:modals/open - [modals/add-to-bookmark - related-streams]])}]]} - [items/related-streams related-streams nil]]))))) + [:div + [:div.flex.flex-wrap.items-center.justify-between.mt-8.min-w-full + [:div.flex.gap-2.items-center + [:span.font-semibold.text-xl "Next Up"]] + [:div.flex.gap-4 + [layout/popover-menu !menu-active? + [{:label "Add to queue" + :icon [:i.fa-solid.fa-headphones] + :on-click #(rf/dispatch [:queue/add-n + related-streams + true])} + {:label "Add to playlist" + :icon [:i.fa-solid.fa-plus] + :on-click #(rf/dispatch [:modals/open + [modals/add-to-bookmark + related-streams]])}]] + [items/layout-switcher !layout]] + [items/related-streams related-streams nil !layout]]]))))) (defn stream [] - (let [stream @(rf/subscribe [:stream]) - !player @(rf/subscribe [:main-player]) - page-loading? @(rf/subscribe [:show-page-loading])] - [:<> - (when-not page-loading? - [:div.flex.flex-col.justify-center.items-center.xl:pt-4 - [player/video-player stream !player]]) - [layout/content-container - [metadata stream] - [description stream] - [comments stream] - [suggested stream]]])) + (let [!active-tab (r/atom :comments)] + (fn [] + (let [stream @(rf/subscribe [:stream]) + !player @(rf/subscribe [:main-player]) + page-loading? @(rf/subscribe [:show-page-loading]) + comments-length (-> stream + :comments-page + :comments + count)] + [:<> + (when-not page-loading? + [:div.flex.flex-col.justify-center.items-center.xl:pt-4 + [player/video-player stream !player]]) + [layout/content-container + [metadata stream] + [description stream] + [:div.mt-10 + [layout/tabs + [{:id :comments + :label "Comments" + :label-fn (fn [label] + [:div.flex.gap-3.items-center.justify-center + [:i.fa-solid.fa-comments] + [:span label] + [:span.dark:bg-neutral-800.rounded.px-2 + comments-length]])} + {:id :related-items + :label "Related Items" + :label-fn (fn [label] + [:div.flex.gap-3.items-center.justify-center + [:i.fa-solid.fa-table-list] + [:span label]])}] + :selected-id @!active-tab + :on-change #(reset! !active-tab %)]] + (case @!active-tab + :comments [comments stream] + :related-items [related-items stream] + [comments stream])]])))) -- cgit v1.2.3