aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/frontend/tubo/components/navigation.cljs95
-rw-r--r--src/frontend/tubo/navigation/views.cljs193
-rw-r--r--src/frontend/tubo/player/views.cljs5
-rw-r--r--src/frontend/tubo/search/views.cljs43
-rw-r--r--src/frontend/tubo/views.cljs2
5 files changed, 194 insertions, 144 deletions
diff --git a/src/frontend/tubo/components/navigation.cljs b/src/frontend/tubo/components/navigation.cljs
deleted file mode 100644
index c5e58ed..0000000
--- a/src/frontend/tubo/components/navigation.cljs
+++ /dev/null
@@ -1,95 +0,0 @@
-(ns tubo.components.navigation
- (:require
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tubo.components.layout :as layout]
- [tubo.kiosks.views :as kiosks]
- [tubo.search.views :as search]
- [tubo.services.views :as services]))
-
-(defn mobile-nav-item
- [route icon label & {:keys [new-tab? active?]}]
- [:li.px-5.py-2
- [:a.flex {:href route :target (when new-tab? "_blank")}
- [:div.w-6.flex.justify-center.items-center.mr-4
- (conj icon {:class ["text-neutral-600" "dark:text-neutral-300"]})]
- [:span {:class (when active? "font-bold")} label]]])
-
-(defn mobile-nav
- [show-mobile-nav? service-color services available-kiosks &
- {:keys [service-id] :as kiosk-args}]
- [:<>
- [layout/focus-overlay #(rf/dispatch [:toggle-mobile-nav]) show-mobile-nav?]
- [:div.fixed.overflow-x-hidden.min-h-screen.w-60.top-0.transition-all.ease-in-out.delay-75.bg-white.dark:bg-neutral-900.z-20
- {:class [(if show-mobile-nav? "left-0" "left-[-245px]")]}
- [:div.flex.justify-center.py-4.items-center.text-white
- {:style {:background service-color}}
- [layout/logo :height 75 :width 75]
- [:h3.text-3xl.font-bold "Tubo"]]
- [services/services-dropdown services service-id service-color]
- [:div.relative.py-4
- [:ul.flex.flex-col
- (for [[i kiosk] (map-indexed vector available-kiosks)]
- ^{:key i}
- [mobile-nav-item
- (rfe/href :kiosk-page nil {:serviceId service-id :kioskId kiosk})
- [:i.fa-solid.fa-fire] kiosk
- :active? (kiosks/kiosk-active? (assoc kiosk-args :kiosk kiosk))])]]
- [:div.relative.dark:border-neutral-800.border-gray-300.pt-4
- {:class "border-t-[1px]"}
- [:ul.flex.flex-col
- [mobile-nav-item (rfe/href :bookmarks-page) [:i.fa-solid.fa-bookmark]
- "Bookmarks"]
- [mobile-nav-item (rfe/href :settings-page) [:i.fa-solid.fa-cog]
- "Settings"]]]]])
-
-(defn navbar
- [{{:keys [kioskId]} :query-params path :path}]
- (let [service-id @(rf/subscribe [:service-id])
- service-color @(rf/subscribe
- [:service-color])
- services @(rf/subscribe [:services])
- show-mobile-nav? @(rf/subscribe
- [:show-mobile-nav])
- show-search-form? @(rf/subscribe
- [:show-search-form])
- {:keys [default-service]} @(rf/subscribe [:settings])
- {:keys [available-kiosks default-kiosk]} @(rf/subscribe [:kiosks])]
- [:nav.sticky.flex.items-center.px-2.h-14.top-0.z-20
- {:style {:background service-color}}
- [:div.flex.flex-auto.items-center
- [:button.ml-2.invisible.absolute.lg:visible.lg:relative
- [:a.font-bold {:href (rfe/href :homepage)}
- [layout/logo :height 35 :width 35]]]
- [:button.text-white.mx-3.lg:hidden
- {:on-click #(rf/dispatch [:toggle-mobile-nav])}
- [:i.fa-solid.fa-bars]]
- [search/search-form]
- [:div.flex.flex-auto.justify-end.lg:justify-between
- {:class (when show-search-form? :hidden)}
- [:div.hidden.lg:flex
- [services/services-dropdown services service-id service-color]
- [kiosks/kiosks-menu
- :kiosks available-kiosks
- :service-id service-id
- :kiosk-id kioskId
- :default-service default-service
- :default-kiosk default-kiosk
- :path path]]
- [:div.flex.items-center.text-white.justify-end
- (when-not show-search-form?
- [:button.mx-3
- {:on-click #(rf/dispatch [:search/show-form true])}
- [:i.fa-solid.fa-search]])
- [:a.mx-3.hidden.lg:block
- {:href (rfe/href :settings-page)}
- [:i.fa-solid.fa-cog]]
- [:a.mx-3.hidden.lg:block
- {:href (rfe/href :bookmarks-page)}
- [:i.fa-solid.fa-bookmark]]]
- [mobile-nav show-mobile-nav? service-color services available-kiosks
- :kiosk-id kioskId
- :service-id service-id
- :default-service default-service
- :default-kiosk default-kiosk
- :path path]]]]))
diff --git a/src/frontend/tubo/navigation/views.cljs b/src/frontend/tubo/navigation/views.cljs
new file mode 100644
index 0000000..c8ef085
--- /dev/null
+++ b/src/frontend/tubo/navigation/views.cljs
@@ -0,0 +1,193 @@
+(ns tubo.navigation.views
+ (:require
+ [re-frame.core :as rf]
+ [reagent.core :as r]
+ [reitit.frontend.easy :as rfe]
+ [tubo.bookmarks.modals :as modals]
+ [tubo.components.layout :as layout]
+ [tubo.kiosks.views :as kiosks]
+ [tubo.services.views :as services]
+ [tubo.utils :as utils]
+ [tubo.stream.views :as stream]
+ [tubo.channel.views :as channel]))
+
+(defn search-form
+ []
+ (let [!query (r/atom "")
+ !input (r/atom nil)]
+ (fn []
+ (let [search-query @(rf/subscribe [:search-query])
+ show-search-form? @(rf/subscribe [:show-search-form])
+ service-id @(rf/subscribe [:service-id])]
+ [:form.relative.text-white.flex.items-center.flex-auto.lg:flex-1
+ {:class (when-not show-search-form? "hidden")
+ :on-submit #(do (.preventDefault %)
+ (when-not (empty? @!query)
+ (rf/dispatch [:navigate
+ {:name :search-page
+ :params {}
+ :query {:q search-query
+ :serviceId service-id}}])))}
+ [:div.flex.justify-center.flex-auto.lg:flex-1
+ [:button.mx-2
+ {:on-click #(rf/dispatch [:search/show-form false])}
+ [:i.fa-solid.fa-arrow-left]]
+ [:input.w-full.lg:w-96.bg-transparent.py-2.pl-0.pr-6.mx-2.border-none.focus:ring-transparent.placeholder-white
+ {:type "text"
+ :ref #(do (reset! !input %)
+ (when %
+ (.focus %)))
+ :default-value @!query
+ :on-change #(let [input (.. % -target -value)]
+ (when-not (empty? input)
+ (rf/dispatch [:search/change-query input]))
+ (reset! !query input))
+ :placeholder "Search"}]
+ [:button.mx-4 {:type "submit"} [:i.fa-solid.fa-search]]
+ [:button.mx-4.text-xs.absolute.right-8.top-3
+ {:on-click #(when @!input
+ (set! (.-value @!input) "")
+ (reset! !query "")
+ (.focus @!input))
+ :class (when (empty? @!query) :invisible)}
+ [:i.fa-solid.fa-circle-xmark]]]]))))
+
+(defn mobile-nav-item
+ [route icon label & {:keys [new-tab? active?]}]
+ [:li.px-5.py-2
+ [:a.flex {:href route :target (when new-tab? "_blank")}
+ [:div.w-6.flex.justify-center.items-center.mr-4
+ (conj icon {:class ["text-neutral-600" "dark:text-neutral-300"]})]
+ [:span {:class (when active? "font-bold")} label]]])
+
+(defn mobile-nav
+ [show-mobile-nav? service-color services available-kiosks &
+ {:keys [service-id] :as kiosk-args}]
+ [:<>
+ [layout/focus-overlay #(rf/dispatch [:toggle-mobile-nav]) show-mobile-nav?]
+ [:div.fixed.overflow-x-hidden.min-h-screen.w-60.top-0.transition-all.ease-in-out.delay-75.bg-white.dark:bg-neutral-900.z-20
+ {:class [(if show-mobile-nav? "left-0" "left-[-245px]")]}
+ [:div.flex.justify-center.py-4.items-center.text-white
+ {:style {:background service-color}}
+ [layout/logo :height 75 :width 75]
+ [:h3.text-3xl.font-bold "Tubo"]]
+ [services/services-dropdown services service-id service-color]
+ [:div.relative.py-4
+ [:ul.flex.flex-col
+ (for [[i kiosk] (map-indexed vector available-kiosks)]
+ ^{:key i}
+ [mobile-nav-item
+ (rfe/href :kiosk-page nil {:serviceId service-id :kioskId kiosk})
+ [:i.fa-solid.fa-fire] kiosk
+ :active? (kiosks/kiosk-active? (assoc kiosk-args :kiosk kiosk))])]]
+ [:div.relative.dark:border-neutral-800.border-gray-300.pt-4
+ {:class "border-t-[1px]"}
+ [:ul.flex.flex-col
+ [mobile-nav-item (rfe/href :bookmarks-page) [:i.fa-solid.fa-bookmark]
+ "Bookmarks"]
+ [mobile-nav-item (rfe/href :settings-page) [:i.fa-solid.fa-cog]
+ "Settings"]]]]])
+
+(defn nav-left-content
+ [title]
+ (let [show-search-form? @(rf/subscribe [:show-search-form])
+ show-queue? @(rf/subscribe [:show-queue])
+ show-main-player? @(rf/subscribe [:main-player/show])]
+ [:div.flex.items-center.gap-x-4
+ (when-not (or show-queue? show-main-player?)
+ [:button.ml-2.invisible.absolute.lg:visible.lg:relative
+ [:a.font-bold {:href (rfe/href :homepage)}
+ [layout/logo :height 35 :width 35]]])
+ (when (and show-queue? (not show-search-form?))
+ [:button.mx-2
+ {:on-click #(rf/dispatch [:queue/show
+ false])}
+ [:i.fa-solid.fa-arrow-left]])
+ (when (and show-main-player? (not show-search-form?))
+ [:button.mx-2
+ {:on-click #(rf/dispatch [:player/switch-from-main nil])}
+ [:i.fa-solid.fa-arrow-left]])
+ (when-not (or show-queue? show-main-player? show-search-form?)
+ [:button.text-white.mx-3.lg:hidden
+ {:on-click #(rf/dispatch
+ [:toggle-mobile-nav])}
+ [:i.fa-solid.fa-bars]])
+ (when-not (or show-queue? show-main-player? show-search-form?)
+ [:h1.text-lg.sm:text-xl.font-bold.line-clamp-1.lg:hidden title])
+ (when (and show-queue? (not show-search-form?))
+ [:h1.text-lg.sm:text-xl.font-bold.line-clamp-1
+ "Play Queue"])
+ (when (and show-main-player? (not show-search-form?))
+ [:h1.text-lg.sm:text-xl.font-bold.line-clamp-1
+ "Main Player"])]))
+
+(defn nav-right-content
+ [{{:keys [kioskId]} :query-params path :path :as match}]
+ (let [show-search-form? @(rf/subscribe [:show-search-form])
+ show-main-player? @(rf/subscribe [:main-player/show])
+ show-queue? @(rf/subscribe [:show-queue])
+ service-id @(rf/subscribe [:service-id])
+ service-color @(rf/subscribe [:service-color])
+ services @(rf/subscribe [:services])
+ settings @(rf/subscribe [:settings])
+ kiosks @(rf/subscribe [:kiosks])]
+ [:div.flex.flex-auto.justify-end.lg:justify-between
+ {:class (when show-search-form? :hidden)}
+ (when-not (or show-queue? show-main-player?)
+ [:div.hidden.lg:flex
+ [services/services-dropdown services service-id service-color]
+ [kiosks/kiosks-menu
+ :kiosks (:available-kiosks kiosks)
+ :service-id service-id
+ :kiosk-id kioskId
+ :default-service (:default-service settings)
+ :default-kiosk (:default-kiosk kiosks)
+ :path path]])
+ [:div.flex.flex-auto.items-center.text-white.justify-end
+ [:button.mx-3
+ {:on-click #(rf/dispatch [:search/show-form true])}
+ [:i.fa-solid.fa-search]]
+ (when-not (or show-queue? show-main-player?)
+ [:div.lg:hidden
+ (case (-> match
+ :data
+ :name)
+ :channel-page [channel/metadata-popover
+ @(rf/subscribe [:channel])]
+ :stream-page [stream/metadata-popover @(rf/subscribe [:stream])]
+ [:<>])])
+ [:a.mx-3.hidden.lg:block
+ {:href (rfe/href :settings-page)}
+ [:i.fa-solid.fa-cog]]
+ [:a.mx-3.hidden.lg:block
+ {:href (rfe/href :bookmarks-page)}
+ [:i.fa-solid.fa-bookmark]]]]))
+
+(defn navbar
+ [{{:keys [kioskId]} :query-params path :path :as match}]
+ (let [service-id @(rf/subscribe [:service-id])
+ service-color @(rf/subscribe [:service-color])
+ services @(rf/subscribe [:services])
+ show-mobile-nav? @(rf/subscribe [:show-mobile-nav])
+ settings @(rf/subscribe [:settings])
+ kiosks @(rf/subscribe [:kiosks])]
+ [:nav.sticky.flex.items-center.px-2.h-14.top-0.z-20
+ {:style {:background service-color}}
+ [:div.flex.flex-auto.items-center
+ [mobile-nav show-mobile-nav? service-color services
+ (:available-kiosks kiosks)
+ :kiosk-id kioskId
+ :service-id service-id
+ :default-service (:default-service settings)
+ :default-kiosk (:default-kiosk kiosks)
+ :path path]
+ [nav-left-content
+ (case (-> match
+ :data
+ :name)
+ :channel-page (:name @(rf/subscribe [:channel]))
+ :kiosk-page (:id @(rf/subscribe [:kiosk]))
+ :stream-page (:name @(rf/subscribe [:stream]))
+ nil)]
+ [search-form]
+ [nav-right-content match]]]))
diff --git a/src/frontend/tubo/player/views.cljs b/src/frontend/tubo/player/views.cljs
index 6a87242..075f675 100644
--- a/src/frontend/tubo/player/views.cljs
+++ b/src/frontend/tubo/player/views.cljs
@@ -177,11 +177,6 @@
[:div.fixed.w-full.bg-neutral-100.dark:bg-neutral-900.overflow-auto.z-10.transition-all.ease-in-out
{:class ["h-[calc(100%-56px)]"
(if show-player? "translate-y-0" "translate-y-full")]}
- [:div.sticky.z-10.right-0.top-0
- [:button.absolute.text-white.m-8.text-2xl.z-10.right-0
- {:on-click #(rf/dispatch [:player/switch-from-main nil])}
- [:i.fa-solid.fa-close
- {:class "drop-shadow-[0_0_1px_#000]"}]]]
(when (and show-player? stream)
[:div
[:div.flex.flex-col.items-center.w-full.xl:py-6
diff --git a/src/frontend/tubo/search/views.cljs b/src/frontend/tubo/search/views.cljs
index a121568..4fdc6d6 100644
--- a/src/frontend/tubo/search/views.cljs
+++ b/src/frontend/tubo/search/views.cljs
@@ -1,52 +1,9 @@
(ns tubo.search.views
(:require
[re-frame.core :as rf]
- [reagent.core :as r]
[tubo.components.items :as items]
[tubo.components.layout :as layout]))
-(defn search-form
- []
- (let [!query (r/atom "")
- !input (r/atom nil)]
- (fn []
- (let [search-query @(rf/subscribe [:search-query])
- show-search-form? @(rf/subscribe [:show-search-form])
- service-id @(rf/subscribe [:service-id])]
- [:form.relative.flex.items-center.text-white.ml-4
- {:class (when-not show-search-form? "hidden")
- :on-submit #(do (.preventDefault %)
- (when-not (empty? @!query)
- (rf/dispatch [:navigate
- {:name :search-page
- :params {}
- :query {:q search-query
- :serviceId service-id}}])))}
- [:div.flex
- [:button.mx-2
- {:on-click #(rf/dispatch [:search/show-form false]) :type "button"}
- [:i.fa-solid.fa-arrow-left]]
- [:input.w-full.sm:w-96.bg-transparent.py-2.pl-0.pr-6.mx-2.border-none.focus:ring-transparent.placeholder-white
- {:type "text"
- :ref #(do (reset! !input %)
- (when %
- (.focus %)))
- :default-value @!query
- :on-change #(let [input (.. % -target -value)]
- (when-not (empty? input)
- (rf/dispatch [:search/change-query input]))
- (reset! !query input))
- :placeholder "Search"}]
- [:button.mx-4 {:type "submit"} [:i.fa-solid.fa-search]]
- [:button.mx-4.text-xs.absolute.right-8.top-3
- {:type "button"
- :on-click #(when @!input
- (set! (.-value @!input) "")
- (reset! !query "")
- (.focus @!input))
- :class (when (empty? @!query) :invisible)}
- [:i.fa-solid.fa-circle-xmark]]]]))))
-
(defn search
[{{:keys [q serviceId]} :query-params}]
(let [{:keys [items next-page]} @(rf/subscribe [:search-results])
diff --git a/src/frontend/tubo/views.cljs b/src/frontend/tubo/views.cljs
index 3a68b65..a0bc34c 100644
--- a/src/frontend/tubo/views.cljs
+++ b/src/frontend/tubo/views.cljs
@@ -1,7 +1,7 @@
(ns tubo.views
(:require
[re-frame.core :as rf]
- [tubo.components.navigation :as navigation]
+ [tubo.navigation.views :as navigation]
[tubo.notifications.views :as notifications]
[tubo.player.views :as player]
[tubo.queue.views :as queue]))