aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/tubo/events.cljs1
-rw-r--r--src/frontend/tubo/layout/events.cljs81
-rw-r--r--src/frontend/tubo/layout/subs.cljs25
-rw-r--r--src/frontend/tubo/layout/views.cljs78
-rw-r--r--src/frontend/tubo/subs.cljs1
-rw-r--r--src/frontend/tubo/views.cljs10
6 files changed, 168 insertions, 28 deletions
diff --git a/src/frontend/tubo/events.cljs b/src/frontend/tubo/events.cljs
index f0edf47..ca3d864 100644
--- a/src/frontend/tubo/events.cljs
+++ b/src/frontend/tubo/events.cljs
@@ -11,6 +11,7 @@
[tubo.channel.events]
[tubo.comments.events]
[tubo.kiosks.events]
+ [tubo.layout.events]
[tubo.main-player.events]
[tubo.modals.events]
[tubo.navigation.events]
diff --git a/src/frontend/tubo/layout/events.cljs b/src/frontend/tubo/layout/events.cljs
new file mode 100644
index 0000000..5b968e6
--- /dev/null
+++ b/src/frontend/tubo/layout/events.cljs
@@ -0,0 +1,81 @@
+(ns tubo.layout.events
+ (:require
+ [nano-id.core :refer [nano-id]]
+ [re-frame.core :as rf]
+ [clojure.string :as str]))
+
+(rf/reg-event-db
+ :layout/show-bg-overlay
+ (fn [db [_ {:keys [on-click] :as data} remain-open?]]
+ (assoc db
+ :layout/bg-overlay
+ (assoc data
+ :show? true
+ :on-click #(do (when on-click (on-click))
+ (when-not remain-open?
+ (rf/dispatch [:layout/hide-bg-overlay])))))))
+
+(rf/reg-event-db
+ :layout/hide-bg-overlay
+ (fn [db _]
+ (assoc-in db [:layout/bg-overlay :show?] false)))
+
+(rf/reg-event-fx
+ :layout/show-mobile-tooltip
+ (fn [{:keys [db]} [_ data]]
+ {:db (assoc db :layout/mobile-tooltip (assoc data :show? true))
+ :fx [[:dispatch [:layout/register-tooltip {:id (:id data)}]]
+ [:dispatch [:layout/show-bg-overlay {:extra-classes ["z-30"]}]]]}))
+
+(defn default-tooltip-data
+ []
+ {:id (nano-id)
+ :destroy-on-click-out? true})
+
+(rf/reg-event-db
+ :layout/register-tooltip
+ (fn [db [_ data]]
+ (let [full-data (merge (default-tooltip-data) data)]
+ (assoc-in db [:layout/tooltips (:id data)] full-data))))
+
+(rf/reg-event-fx
+ :layout/destroy-tooltip-by-id
+ (fn [{:keys [db]} [_ id]]
+ {:db (update db :layout/tooltips dissoc id)}))
+
+(rf/reg-event-db
+ :layout/destroy-tooltips-by-ids
+ (fn [db [_ ids]]
+ (update db :layout/tooltips #(apply dissoc % ids))))
+
+(defonce tooltip-controller-class-prefix "tooltip-controller-")
+
+(defn find-tooltip-controller-class-in-node
+ [node]
+ (some->> (.-className node)
+ (re-find (re-pattern (str tooltip-controller-class-prefix
+ "([\\w\\-]+)")))
+ (first)))
+
+(defn find-tooltip-controller-class
+ [node]
+ (or (find-tooltip-controller-class-in-node node)
+ (some-> (.-parentNode node)
+ (find-tooltip-controller-class))))
+
+(rf/reg-event-fx
+ :layout/destroy-tooltips-on-click-out
+ (fn [{:keys [db]} [_ clicked-node]]
+ (when (seq (:layout/tooltips db))
+ (let [clicked-controller (some->
+ (find-tooltip-controller-class clicked-node)
+ (str/split tooltip-controller-class-prefix)
+ (second))
+ tooltip-ids (->> (:layout/tooltips db)
+ (vals)
+ (filter :destroy-on-click-out?)
+ (map :id)
+ (set))]
+ {:fx [[:dispatch
+ [:layout/destroy-tooltips-by-ids
+ (disj tooltip-ids clicked-controller)]]]}))))
diff --git a/src/frontend/tubo/layout/subs.cljs b/src/frontend/tubo/layout/subs.cljs
new file mode 100644
index 0000000..87d6b27
--- /dev/null
+++ b/src/frontend/tubo/layout/subs.cljs
@@ -0,0 +1,25 @@
+(ns tubo.layout.subs
+ (:require
+ [re-frame.core :as rf]))
+
+(rf/reg-sub
+ :layout/bg-overlay
+ (fn [db]
+ (:layout/bg-overlay db)))
+
+(rf/reg-sub
+ :layout/mobile-tooltip
+ (fn [db]
+ (:layout/mobile-tooltip db)))
+
+(rf/reg-sub
+ :layout/tooltips
+ (fn [db]
+ (:layout/tooltips db)))
+
+(rf/reg-sub
+ :layout/tooltip-by-id
+ (fn []
+ (rf/subscribe [:layout/tooltips]))
+ (fn [tooltips [_ id]]
+ (get tooltips id)))
diff --git a/src/frontend/tubo/layout/views.cljs b/src/frontend/tubo/layout/views.cljs
index 6537765..77bcf56 100644
--- a/src/frontend/tubo/layout/views.cljs
+++ b/src/frontend/tubo/layout/views.cljs
@@ -1,6 +1,7 @@
(ns tubo.layout.views
(:require
[clojure.string :as str]
+ [nano-id.core :refer [nano-id]]
[re-frame.core :as rf]
[reitit.frontend.easy :as rfe]
[reagent.core :as r]
@@ -38,13 +39,15 @@
{:class classes
:style {:color service-color}}]])
-(defn focus-overlay
- [on-click active? transparent? extra-classes]
- [:div.w-full.fixed.min-h-screen.right-0.top-0.transition-all.delay-75.ease-in-out.z-20
- {:class (conj extra-classes (when-not transparent? "bg-black"))
- :style {:visibility (when-not active? "hidden")
- :opacity (if active? "0.5" "0")}
- :on-click on-click}])
+(defn background-overlay
+ []
+ (when-let [{:keys [show?] :as overlay} @(rf/subscribe [:layout/bg-overlay])]
+ [:div.w-full.fixed.min-h-screen.right-0.top-0.z-20
+ {:class (conj (:extra-classes overlay)
+ (when-not (:transparent? overlay) "bg-black"))
+ :style {:visibility (when-not show? "hidden")
+ :opacity (if show? "0.5" "0")}
+ :on-click (:on-click overlay)}]))
(defn content-container
[& children]
@@ -138,7 +141,7 @@
[:option.dark:bg-neutral-900.border-none {:value option :key i}
option])]])
-(defn menu-item
+(defn tooltip-item
[{:keys [label icon on-click link] :as item}]
(let [content [:<>
(when icon
@@ -160,27 +163,50 @@
:class (str/join " " classes)}
(if (vector? item) item content)])))
-(defn menu
- [active? items & {:keys [extra-classes]}]
+(defn tooltip
+ [items & {:keys [extra-classes]}]
(when-not (empty? (remove nil? items))
- [:ul.xs:absolute.bg-neutral-100.dark:bg-neutral-800.rounded-t.rounded-b.z-20.flex.flex-col.text-neutral-800.dark:text-white.shadow.shadow-neutral-400.dark:shadow-neutral-900.bottom-2.left-2.right-2.fixed
- {:class (conj extra-classes (when-not active? "hidden"))}
+ [:ul.absolute.bg-neutral-100.dark:bg-neutral-800.rounded-t.rounded-b.flex.flex-col.text-neutral-800.dark:text-white.shadow.shadow-neutral-400.dark:shadow-neutral-900.z-30
+ {:class (conj extra-classes)}
(for [[i item] (map-indexed vector (remove nil? items))]
- ^{:key i} [menu-item item])]))
+ ^{:key i} [tooltip-item item])]))
-(defn popover-menu
- [!menu-active? items &
- {:keys [menu-classes extra-classes]
- :or {extra-classes [:p-3]
- menu-classes ["xs:bottom-auto" "xs:left-auto" "xs:right-auto"]}}]
- [:div.flex.items-center
- [focus-overlay #(reset! !menu-active? false) @!menu-active? true
- ["bg-black" "xs:bg-transparent"]]
- [:button.focus:outline-none.xs:relative
- {:on-click #(reset! !menu-active? (not @!menu-active?))
- :class extra-classes}
- [:i.fa-solid.fa-ellipsis-vertical]
- [menu @!menu-active? items :extra-classes menu-classes]]])
+(defn mobile-tooltip
+ []
+ (let [{:keys [id items show?]} @(rf/subscribe [:layout/mobile-tooltip])
+ tooltip-data (rf/subscribe [:layout/tooltip-by-id id])]
+ (when @tooltip-data
+ [:div.xs:hidden
+ {:class (str "tooltip-controller-" id)
+ :on-click #(do (rf/dispatch [:layout/destroy-tooltip-by-id id])
+ (rf/dispatch [:layout/hide-bg-overlay]))}
+ (when-not (empty? (remove nil? items))
+ [:ul.bg-neutral-100.dark:bg-neutral-800.rounded-t.rounded-b.z-30.flex.flex-col.text-neutral-800.dark:text-white.shadow.shadow-neutral-400.dark:shadow-neutral-900.bottom-4.left-2.right-2.fixed
+ {:class (when-not show? "hidden")}
+ (for [[i item] (map-indexed vector (remove nil? items))]
+ ^{:key i} [tooltip-item item])])])))
+
+(defn popover
+ []
+ (let [tooltip-id (nano-id)
+ tooltip-data (rf/subscribe [:layout/tooltip-by-id tooltip-id])]
+ (fn [items &
+ {:keys [extra-classes tooltip-classes] :or {extra-classes ["p-3"]}}]
+ [:div.flex.items-center.tooltip-controller
+ {:class (str "tooltip-controller-" tooltip-id)}
+ [:button.focus:outline-none.relative.hidden.xs:block
+ {:on-click #(if @tooltip-data
+ (rf/dispatch [:layout/destroy-tooltip-by-id tooltip-id])
+ (rf/dispatch [:layout/register-tooltip {:id tooltip-id}]))
+ :class extra-classes}
+ [:i.fa-solid.fa-ellipsis-vertical]
+ (when @tooltip-data
+ [tooltip items :extra-classes tooltip-classes])]
+ [:button.focus:outline-none.relative.xs:hidden
+ {:on-click #(rf/dispatch [:layout/show-mobile-tooltip
+ {:items items :id tooltip-id}])
+ :class extra-classes}
+ [:i.fa-solid.fa-ellipsis-vertical]]])))
(defn accordeon
[{:keys [label on-open open? left-icon right-button]} & content]
diff --git a/src/frontend/tubo/subs.cljs b/src/frontend/tubo/subs.cljs
index 8c0575f..1a11893 100644
--- a/src/frontend/tubo/subs.cljs
+++ b/src/frontend/tubo/subs.cljs
@@ -6,6 +6,7 @@
[tubo.bookmarks.subs]
[tubo.channel.subs]
[tubo.kiosks.subs]
+ [tubo.layout.subs]
[tubo.main-player.subs]
[tubo.modals.subs]
[tubo.navigation.subs]
diff --git a/src/frontend/tubo/views.cljs b/src/frontend/tubo/views.cljs
index 188c90b..074596e 100644
--- a/src/frontend/tubo/views.cljs
+++ b/src/frontend/tubo/views.cljs
@@ -2,6 +2,7 @@
(:require
[re-frame.core :as rf]
[tubo.bg-player.views :as bg-player]
+ [tubo.layout.views :as layout]
[tubo.main-player.views :as main-player]
[tubo.modals.views :as modals]
[tubo.navigation.views :as navigation]
@@ -12,9 +13,14 @@
[]
(let [current-match @(rf/subscribe [:navigation/current-match])
dark-theme? @(rf/subscribe [:dark-theme])]
- [:div {:class (when dark-theme? :dark)}
- [:div.font-nunito-sans.min-h-screen.h-full.relative.flex.flex-col.dark:text-white.bg-neutral-100.dark:bg-neutral-900
[modals/modal]
+ [:div
+ {:class (when dark-theme? :dark)
+ :on-click #(rf/dispatch [:layout/destroy-tooltips-on-click-out
+ (.. % -target)])}
+ [:div.font-nunito-sans.min-h-screen.h-full.relative.flex.flex-col.dark:text-white.bg-neutral-100.dark:bg-neutral-900.z-10
+ [layout/background-overlay]
+ [layout/mobile-tooltip]
[navigation/navbar current-match]
[notifications/notifications-panel]
[:div.flex.flex-col.flex-auto.justify-between.relative