aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/tubo
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/tubo')
-rw-r--r--src/frontend/tubo/components/layout.cljs32
-rw-r--r--src/frontend/tubo/views/channel.cljs61
-rw-r--r--src/frontend/tubo/views/playlist.cljs72
3 files changed, 102 insertions, 63 deletions
diff --git a/src/frontend/tubo/components/layout.cljs b/src/frontend/tubo/components/layout.cljs
index 9d387f6..2dc552f 100644
--- a/src/frontend/tubo/components/layout.cljs
+++ b/src/frontend/tubo/components/layout.cljs
@@ -106,6 +106,38 @@
(for [[i option] (map-indexed vector options)]
^{:key i} [:option.dark:bg-neutral-900.border-none {:value option :key i} option])]])
+(defn menu-item
+ [{:keys [label icon on-click link]}]
+ (let [content [:<>
+ [:span.text-xs icon]
+ [:span.whitespace-nowrap label]]]
+ (if link
+ [:a.flex.gap-x-3.items-center.hover:bg-gray-100.dark:hover:bg-stone-800.py-2.px-3.rounded
+ {:href (:route link) :target (when (:external? link) "_blank")}
+ content]
+ [:li.flex.gap-x-3.items-center.hover:bg-gray-100.dark:hover:bg-stone-800.py-2.px-3.rounded
+ {:on-click on-click}
+ content])))
+
+(defn menu
+ [active? items & {:keys [right top bottom left] :or {right "15px" top "0px"}}]
+ (when-not (empty? (remove nil? items))
+ [:ul.absolute.bg-white.dark:bg-neutral-900.border.border-neutral-300.dark:border-stone-700.rounded-t.rounded-b.z-20.p-2.flex.flex-col
+ {:class (when-not active? "hidden")
+ :style {:right right :left left :top top :bottom bottom}}
+ (for [[i item] (map-indexed vector (remove nil? items))]
+ ^{:key i} [menu-item item])]))
+
+(defn more-menu
+ [!menu-active? items & {:keys [menu-styles extra-classes]}]
+ [:div.flex.items-center
+ [focus-overlay #(reset! !menu-active? false) @!menu-active? true]
+ [:button.focus:outline-none.relative.pl-4
+ {:on-click #(reset! !menu-active? (not @!menu-active?))
+ :class extra-classes}
+ [:i.fa-solid.fa-ellipsis-vertical]
+ [menu @!menu-active? items menu-styles]]])
+
(defn accordeon
[{:keys [label on-open open? left-icon right-button]} & content]
[:div.py-4
diff --git a/src/frontend/tubo/views/channel.cljs b/src/frontend/tubo/views/channel.cljs
index 63668bd..f55653a 100644
--- a/src/frontend/tubo/views/channel.cljs
+++ b/src/frontend/tubo/views/channel.cljs
@@ -8,32 +8,35 @@
(defn channel
[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.rounded {: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-2xl.font-nunito-semibold.line-clamp-1 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]]))))
+ (let [!menu-active? (r/atom nil)]
+ (fn [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]
+ :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.rounded {: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-2xl.font-nunito-semibold.line-clamp-1 name]
+ (when subscriber-count
+ [:div.flex.my-2.items-center
+ [:i.fa-solid.fa-users.text-xs]
+ [:span.mx-2 (.toLocaleString subscriber-count)]])]]
+ (when related-streams
+ [layout/more-menu !menu-active?
+ [{:label "Add to queue"
+ :icon [:i.fa-solid.fa-headphones]
+ :on-click #(rf/dispatch [::events/enqueue-related-streams related-streams])}]])]
+ [layout/show-more-container @!show-description? description
+ #(reset! !show-description? (not @!show-description?))]
+ [items/related-streams related-streams next-page-url]]))))))
diff --git a/src/frontend/tubo/views/playlist.cljs b/src/frontend/tubo/views/playlist.cljs
index 4bc7164..a36dbf3 100644
--- a/src/frontend/tubo/views/playlist.cljs
+++ b/src/frontend/tubo/views/playlist.cljs
@@ -1,34 +1,38 @@
-(ns tubo.views.playlist
- (:require
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tubo.components.items :as items]
- [tubo.components.layout :as layout]
- [tubo.events :as events]))
-
-(defn playlist
- [{{:keys [url]} :query-params}]
- (let [{:keys [id name playlist-type thumbnail-url banner-url
- uploader-name uploader-url uploader-avatar
- stream-count next-page
- related-streams]} @(rf/subscribe [:playlist])
- 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/playlist-pagination url next-page-url]))
- [layout/content-container
- [:div.flex.flex-col.justify-center
- [layout/content-header name
- [layout/primary-button "Enqueue"
- #(rf/dispatch [::events/enqueue-related-streams related-streams service-color])
- "fa-solid fa-headphones"]]
- [:div.flex.items-center.justify-between.my-4.gap-x-4
- [:div.flex.items-center
- [layout/uploader-avatar uploader-avatar uploader-name uploader-url]
- [:a.line-clamp-1.ml-2
- {:href (rfe/href :tubo.routes/channel nil {:url uploader-url})
- :title uploader-name}
- uploader-name]]
- [:span.whitespace-nowrap (str stream-count " streams")]]]
- [items/related-streams related-streams next-page-url]]))
+(ns tubo.views.playlist
+ (:require
+ [reagent.core :as r]
+ [re-frame.core :as rf]
+ [reitit.frontend.easy :as rfe]
+ [tubo.components.items :as items]
+ [tubo.components.layout :as layout]
+ [tubo.events :as events]))
+
+(defn playlist
+ [{{:keys [url]} :query-params}]
+ (let [!menu-active? (r/atom nil)]
+ (fn []
+ (let [{:keys [id name playlist-type thumbnail-url banner-url
+ uploader-name uploader-url uploader-avatar
+ stream-count next-page
+ related-streams]} @(rf/subscribe [:playlist])
+ next-page-url (:url next-page)
+ scrolled-to-bottom? @(rf/subscribe [:scrolled-to-bottom])]
+ (when scrolled-to-bottom?
+ (rf/dispatch [::events/playlist-pagination url next-page-url]))
+ [layout/content-container
+ [:div.flex.flex-col.justify-center
+ [layout/content-header name
+ (when related-streams
+ [layout/more-menu !menu-active?
+ [{:label "Add to queue"
+ :icon [:i.fa-solid.fa-headphones]
+ :on-click #(rf/dispatch [::events/enqueue-related-streams related-streams])}]])]
+ [:div.flex.items-center.justify-between.my-4.gap-x-4
+ [:div.flex.items-center
+ [layout/uploader-avatar uploader-avatar uploader-name uploader-url]
+ [:a.line-clamp-1.ml-2
+ {:href (rfe/href :tubo.routes/channel nil {:url uploader-url})
+ :title uploader-name}
+ uploader-name]]
+ [:span.text-sm.whitespace-nowrap (str stream-count " streams")]]]
+ [items/related-streams related-streams next-page-url]]))))