aboutsummaryrefslogtreecommitdiff
path: root/src/frontend/tau
diff options
context:
space:
mode:
authorMiguel Ángel Moreno <mail@migalmoreno.com>2023-01-17 13:17:40 +0100
committerMiguel Ángel Moreno <mail@migalmoreno.com>2023-01-17 13:17:40 +0100
commit81f03c0b449bec1fa60cf2936bfc3f66a5ad58c1 (patch)
treea2a7aa01f61dd71b511dd3729a9f4b28c35b531f /src/frontend/tau
parent5e995881dd0c431ae63b1a50c2d03e59962241f1 (diff)
chore: Rename project
Diffstat (limited to 'src/frontend/tau')
-rw-r--r--src/frontend/tau/api.cljs15
-rw-r--r--src/frontend/tau/components/comments.cljs77
-rw-r--r--src/frontend/tau/components/items.cljs93
-rw-r--r--src/frontend/tau/components/loading.cljs8
-rw-r--r--src/frontend/tau/components/navigation.cljs12
-rw-r--r--src/frontend/tau/components/player.cljs70
-rw-r--r--src/frontend/tau/core.cljs22
-rw-r--r--src/frontend/tau/events.cljs382
-rw-r--r--src/frontend/tau/routes.cljs58
-rw-r--r--src/frontend/tau/subs.cljs98
-rw-r--r--src/frontend/tau/util.cljs24
-rw-r--r--src/frontend/tau/views.cljs98
-rw-r--r--src/frontend/tau/views/channel.cljs41
-rw-r--r--src/frontend/tau/views/kiosk.cljs26
-rw-r--r--src/frontend/tau/views/playlist.cljs40
-rw-r--r--src/frontend/tau/views/search.cljs28
-rw-r--r--src/frontend/tau/views/stream.cljs122
17 files changed, 0 insertions, 1214 deletions
diff --git a/src/frontend/tau/api.cljs b/src/frontend/tau/api.cljs
deleted file mode 100644
index e69bc9c..0000000
--- a/src/frontend/tau/api.cljs
+++ /dev/null
@@ -1,15 +0,0 @@
-(ns tau.api
- (:require
- [ajax.core :as ajax]))
-
-(defn get-request
- ([uri on-success on-failure]
- (get-request uri on-success on-failure {}))
- ([uri on-success on-failure params]
- {:http-xhrio {:method :get
- :uri uri
- :params params
- :format (ajax/json-request-format)
- :response-format (ajax/json-response-format {:keywords? true})
- :on-success on-success
- :on-failure on-failure}}))
diff --git a/src/frontend/tau/components/comments.cljs b/src/frontend/tau/components/comments.cljs
deleted file mode 100644
index bfbf822..0000000
--- a/src/frontend/tau/components/comments.cljs
+++ /dev/null
@@ -1,77 +0,0 @@
-(ns tau.components.comments
- (:require
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tau.components.loading :as loading]
- [tau.events :as events]
- [tau.util :as util]))
-
-(defn comment-item
- [{:keys [id text uploader-name uploader-avatar uploader-url stream-position
- upload-date uploader-verified? like-count hearted-by-uploader?
- pinned? replies reply-count key show-replies author-name author-avatar]}]
- [:div.flex.my-4 {:key key}
- (when uploader-avatar
- [:div.flex.items-center.py-3.box-border.h-12
- (when uploader-url
- [:div.w-12
- [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title uploader-name}
- [:img.rounded-full.object-cover.min-w-full.min-h-full {:src uploader-avatar}]]])])
- [:div.ml-4
- [:div.flex.items-center
- (when pinned?
- [:i.fa-solid.fa-thumbtack.mr-2.text-xs])
- (when uploader-name
- [:div.flex.items-center
- [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title uploader-name}
- [:h1.text-gray-300.font-bold uploader-name]]
- (when stream-position
- [:p.mx-1.text-xs (str "at " (util/format-duration stream-position))])])
- (when uploader-verified?
- [:i.fa-solid.fa-circle-check.ml-2])]
- [:div.my-2
- [:p text]]
- [:div..flex.items-center.my-2
- [:div.mr-4
- [:p (util/format-date upload-date)]]
- (when (and like-count (> like-count 0))
- [:div.flex.items-center.my-2
- [:i.fa-solid.fa-thumbs-up.text-xs]
- [:p.mx-1 like-count]])
- (when hearted-by-uploader?
- [:div.relative.w-4.h-4.mx-2
- [:i.fa-solid.fa-heart.absolute.-bottom-1.-right-1.text-xs.text-red-500]
- [:img.rounded-full.object-covermax-w-full.min-h-full
- {:src author-avatar :title (str author-name " hearted this comment")}]])]
- [:div.flex.items-center.cursor-pointer
- {:on-click #(rf/dispatch [::events/toggle-comment-replies id])}
- (when replies
- (if show-replies
- [:<>
- [:p.font-bold "Hide replies"]
- [:i.fa-solid.fa-turn-up.mx-2.text-xs]]
- [:<>
- [:p.font-bold (str reply-count (if (= reply-count 1) " reply" " replies"))]
- [:i.fa-solid.fa-turn-down.mx-2.text-xs]]))]]])
-
-(defn comments
- [{:keys [comments next-page disabled?]} author-name author-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}
- [comment-item (assoc comment :key i :author-name author-name :author-avatar author-avatar)]
- (when (and replies show-replies)
- [:div {:style {:marginLeft "32px"}}
- (for [[i reply] (map-indexed vector (:items replies))]
- [comment-item (assoc reply :key i :author-name author-name :author-avatar author-avatar)])])])]
- (when (:url next-page)
- (if pagination-loading?
- (loading/loading-icon service-color)
- [:div.flex.items-center.justify-center
- {:style {:cursor "pointer"}
- :on-click #(rf/dispatch [::events/comments-pagination url (:url next-page)])}
- [:i.fa-solid.fa-plus]
- [:p.px-2 "Show more comments"]]))]))
diff --git a/src/frontend/tau/components/items.cljs b/src/frontend/tau/components/items.cljs
deleted file mode 100644
index dccd43f..0000000
--- a/src/frontend/tau/components/items.cljs
+++ /dev/null
@@ -1,93 +0,0 @@
-(ns tau.components.items
- (:require
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tau.components.loading :as loading]
- [tau.util :as util]))
-
-(defn thumbnail
- [thumbnail-url route url name duration]
- [:div.flex.py-2.box-border.h-44.xs:h-28
- [:div.relative.min-w-full
- [:a.absolute.min-w-full.min-h-full.z-10 {:href route :title name}]
- [:img.rounded.object-cover.min-h-full.max-h-full.min-w-full {:src thumbnail-url}]
- (when duration
- [:div.rounded.p-2.absolute {:style {:bottom 5 :right 5 :background "rgba(0,0,0,.7)" :zIndex "0"}}
- [:p {:style {:fontSize "14px"}}
- (if (= duration 0)
- "LIVE"
- (util/format-duration duration))]])]])
-
-(defn item-content
- [{:keys [url name thumbnail-url description subscriber-count
- stream-count verified? key uploader-name uploader-url
- uploader-avatar upload-date short-description view-count]} item-route]
- [:<>
- (when name
- [:div.my-2
- [:a {:href item-route :title name}
- [:h1.line-clamp-2.my-1 name]]])
- (when-not (empty? uploader-name)
- [:div.flex.items-center.my-2
- (if uploader-url
- [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title uploader-name}
- [:h1.line-clamp-1.text-gray-300.font-bold.pr-2 uploader-name]]
- [:h1.line-clamp-1.text-gray-300.font-bold.pr-2 uploader-name])
- (when verified?
- [:i.fa-solid.fa-circle-check])])
- (when subscriber-count
- [:div.flex.items-center
- [:i.fa-solid.fa-users.text-xs]
- [:p.mx-2 subscriber-count]])
- (when stream-count
- [:div.flex.items-center
- [:i.fa-solid.fa-video.text-xs]
- [:p.mx-2 stream-count]])
- [:div.flex.my-1.justify-between
- [:p (util/format-date upload-date)]
- (when view-count
- [:div.flex.items-center.h-full.pl-2
- [:i.fa-solid.fa-eye.text-xs]
- [:p.pl-1.5 (util/format-quantity view-count)]])]])
-
-(defn stream-item
- [{:keys [url name thumbnail-url duration] :as item}]
- [:<>
- [thumbnail thumbnail-url (rfe/href :tau.routes/stream nil {:url url}) url name duration]
- [item-content item (rfe/href :tau.routes/stream nil {:url url})]])
-
-(defn channel-item
- [{:keys [url name thumbnail-url] :as item}]
- [:<>
- [thumbnail thumbnail-url (rfe/href :tau.routes/channel nil {:url url}) url name nil]
- [item-content item (rfe/href :tau.routes/channel nil {:url url})]])
-
-(defn playlist-item
- [{:keys [url name thumbnail-url] :as item}]
- [:<>
- [thumbnail thumbnail-url (rfe/href :tau.routes/playlist nil {:url url}) url name nil]
- [item-content item (rfe/href :tau.routes/playlist nil {:url url})]])
-
-(defn generic-item
- [item]
- [:div.w-full.xs:w-56.h-80.xs:h-72.my-2 {:key key}
- [:div.px-5.py-2.m-2.flex.flex-col.max-w-full.min-h-full.max-h-full
- (case (:type item)
- "stream" [stream-item item]
- "channel" [channel-item item]
- "playlist" [playlist-item item])]])
-
-(defn related-streams
- [related-streams next-page-url]
- (let [service-color @(rf/subscribe [:service-color])
- pagination-loading? @(rf/subscribe [:show-pagination-loading])]
- [:div.flex.flex-col.justify-center.items-center.flex-auto.my-2.md:my-8
- (if (empty? related-streams)
- [:div.flex.items-center
- [:p "No available streams"]]
- [:div.flex.justify-center.flex-wrap
- (for [[i item] (map-indexed vector related-streams)
- :let [keyed-item (assoc item :key i)]]
- [generic-item keyed-item])])
- (when-not (empty? next-page-url)
- [loading/loading-icon service-color "text-2xl" (when-not pagination-loading? "invisible")])]))
diff --git a/src/frontend/tau/components/loading.cljs b/src/frontend/tau/components/loading.cljs
deleted file mode 100644
index 40f6db3..0000000
--- a/src/frontend/tau/components/loading.cljs
+++ /dev/null
@@ -1,8 +0,0 @@
-(ns tau.components.loading)
-
-(defn loading-icon
- [service-color & styles]
- [:div.w-full.flex.justify-center.items-center.flex-auto
- [:i.fas.fa-circle-notch.fa-spin
- {:class (apply str (if (> (count styles) 1) (interpose " " styles) styles))
- :style {:color service-color}}]])
diff --git a/src/frontend/tau/components/navigation.cljs b/src/frontend/tau/components/navigation.cljs
deleted file mode 100644
index 87e6dc5..0000000
--- a/src/frontend/tau/components/navigation.cljs
+++ /dev/null
@@ -1,12 +0,0 @@
-(ns tau.components.navigation
- (:require
- [re-frame.core :as rf]
- [tau.events :as events]))
-
-(defn back-button [service-color]
- [:div.flex.items-center
- [:button.py-4.px-2
- {:on-click #(rf/dispatch [::events/history-back])}
- [:i.fa-solid.fa-chevron-left
- {:style {:color service-color}}]
- [:span " Back"]]])
diff --git a/src/frontend/tau/components/player.cljs b/src/frontend/tau/components/player.cljs
deleted file mode 100644
index 11cc9c5..0000000
--- a/src/frontend/tau/components/player.cljs
+++ /dev/null
@@ -1,70 +0,0 @@
-(ns tau.components.player
- (:require
- [reagent.core :as r]
- [reagent.dom :as rdom]
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tau.events :as events]
- ["video.js" :as videojs]))
-
-(defn global-player
- []
- (let [!player (r/atom nil)
- !loop? (r/atom nil)]
- (fn []
- (let [{:keys [uploader-name uploader-url name stream url service-color]} @(rf/subscribe [:global-stream])
- show-global-player? @(rf/subscribe [:show-global-player])]
- (when show-global-player?
- [:div.sticky.bottom-0.z-50.bg-neutral-900.p-5.absolute.box-border.m-0
- {:style {:borderColor service-color :borderTopWidth "2px" :borderStyle "solid"}}
- [:div.flex.items-center.justify-between
- [:div.flex.flex-wrap.items-center
- [:div.flex.flex-col
- [:a.text-xs
- {:href (rfe/href :tau.router/stream nil {:url url})} name]
- [:a.text-xs.text-gray-300
- {:href (rfe/href :tau.router/channel nil {:url uploader-url})} uploader-name]]
- [:div.px-2.py-0.md:pt-4
- [:audio {:src stream :ref #(reset! !player %) :loop @!loop?}]]
- [:div.mx-2
- [:button.focus:ring-transparent.mx-2
- {:on-click (fn [] (swap! !loop? #(not %)))}
- [:i.fa-solid.fa-repeat
- {:style {:color (when @!loop? service-color)}}]]
- [:button.focus:ring-transparent.mx-2
- {:on-click #(when-let [player @!player]
- (if (.-paused player)
- (.play player)
- (.pause player)))}
- (if @!player
- (if (.-paused @!player)
- [:i.fa-solid.fa-play]
- [:i.fa-solid.fa-pause])
- [:i.fa-solid.fa-play])]]]
- [:div.px-2
- [:i.fa-solid.fa-close.cursor-pointer
- {:on-click (fn []
- (rf/dispatch [::events/toggle-global-player])
- (.pause @!player))}]]]])))))
-
-(defn stream-player
- [options url]
- (let [!player (atom nil)]
- (r/create-class
- {:display-name "StreamPlayer"
- :component-did-mount
- (fn [this]
- (reset! !player (videojs (rdom/dom-node this) (clj->js options))))
- :component-did-update
- (fn [this [_ prev-argv prev-more]]
- (when (and @!player (not= prev-more (first (r/children this))))
- (.src @!player (apply array (map #(js-obj "type" % "src" (first (r/children this)))
- ["video/mp4" "video/webm"])))
- (.ready @!player #(.play @!player))))
- :component-will-unmount
- (fn [_]
- (when @!player
- (.dispose @!player)))
- :reagent-render
- (fn [options url]
- [:video-js.vjs-default-skin.vjs-big-play-centered.bottom-0.object-cover.min-h-full.max-h-full.min-w-full])})))
diff --git a/src/frontend/tau/core.cljs b/src/frontend/tau/core.cljs
deleted file mode 100644
index 7665a20..0000000
--- a/src/frontend/tau/core.cljs
+++ /dev/null
@@ -1,22 +0,0 @@
-(ns tau.core
- (:require
- ["react-dom/client" :as rdom]
- [reagent.core :as r]
- [re-frame.core :as rf]
- [tau.events :as events]
- [tau.routes :as routes]
- [tau.subs]
- [tau.views :as views]))
-
-(defonce root (rdom/createRoot (.querySelector js/document "#app")))
-
-(defn ^:dev/after-load mount-root
- []
- (rf/clear-subscription-cache!)
- (routes/start-routes!)
- (.render root (r/as-element [views/app])))
-
-(defn ^:export init
- []
- (rf/dispatch-sync [::events/initialize-db])
- (mount-root))
diff --git a/src/frontend/tau/events.cljs b/src/frontend/tau/events.cljs
deleted file mode 100644
index d854b0e..0000000
--- a/src/frontend/tau/events.cljs
+++ /dev/null
@@ -1,382 +0,0 @@
-(ns tau.events
- (:require
- [day8.re-frame.http-fx]
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [reitit.frontend.controllers :as rfc]
- [tau.api :as api]))
-
-(rf/reg-event-db
- ::initialize-db
- (fn [_ _]
- {:global-search ""
- :service-id 0
- :service-color "#cc0000"
- :stream {}
- :search-results []
- :services []
- :current-match nil
- :page-scroll 0}))
-
-(rf/reg-fx
- ::scroll-to-top
- (fn [_]
- (.scrollTo js/window #js {"top" 0 "behavior" "smooth"})))
-
-(rf/reg-fx
- ::history-back!
- (fn [_]
- (.back js/window.history)))
-
-(rf/reg-event-fx
- ::history-back
- (fn [_ _]
- {::history-back! nil}))
-
-(rf/reg-event-db
- ::page-scroll
- (fn [db _]
- (when (> (.-scrollY js/window) 0)
- (assoc db :page-scroll (+ (.-scrollY js/window) (.-innerHeight js/window))))))
-
-(rf/reg-event-db
- ::reset-page-scroll
- (fn [db _]
- (assoc db :page-scroll 0)))
-
-(rf/reg-event-db
- ::toggle-mobile-nav
- (fn [db _]
- (assoc db :show-mobile-nav (not (:show-mobile-nav db)))))
-
-(rf/reg-event-fx
- ::navigated
- (fn [{:keys [db]} [_ new-match]]
- (let [old-match (:current-match db)
- controllers (rfc/apply-controllers (:controllers old-match) new-match)
- match (assoc new-match :controllers controllers)]
- {:db (-> db
- (assoc :current-match match)
- (assoc :show-pagination-loading false))
- ::scroll-to-top nil})))
-
-(rf/reg-event-fx
- ::navigate
- (fn [_ [_ route]]
- {::navigate! route}))
-
-(rf/reg-fx
- ::navigate!
- (fn [{:keys [name params query]}]
- (rfe/push-state name params query)))
-
-(rf/reg-event-db
- ::bad-response
- (fn [db [_ res]]
- (js/console.log res)
- (assoc db :http-response (get-in res [:response :error]))))
-
-(rf/reg-event-db
- ::change-global-search
- (fn [db [_ res]]
- (assoc db :global-search res)))
-
-(rf/reg-event-db
- ::change-service-color
- (fn [db [_ service-id]]
- (assoc db :service-color
- (case service-id
- 0 "#cc0000"
- 1 "#ff7700"
- 2 "#333333"
- 3 "#F2690D"
- 4 "#629aa9"))))
-
-(rf/reg-event-fx
- ::change-service-id
- (fn [{:keys [db]} [_ service-id]]
- {:db (assoc db :service-id service-id)
- :fx [[:dispatch [::change-service-color service-id]]]}))
-
-(rf/reg-event-db
- ::load-paginated-channel-results
- (fn [db [_ res]]
- (-> db
- (update-in [:channel :related-streams] #(apply conj %1 %2)
- (:related-streams (js->clj res :keywordize-keys true)))
- (assoc-in [:channel :next-page]
- (:next-page (js->clj res :keywordize-keys true)))
- (assoc :show-pagination-loading false))))
-
-(rf/reg-event-fx
- ::channel-pagination
- (fn [{:keys [db]} [_ uri next-page-url]]
- (if (empty? next-page-url)
- {:db (assoc db :show-pagination-loading false)}
- (assoc
- (api/get-request
- (str "/api/channels/" (js/encodeURIComponent uri) )
- [::load-paginated-channel-results] [::bad-response]
- {:nextPage (js/encodeURIComponent next-page-url)})
- :db (assoc db :show-pagination-loading true)))))
-
-(rf/reg-event-db
- ::load-paginated-playlist-results
- (fn [db [_ res]]
- (-> db
- (update-in [:playlist :related-streams] #(apply conj %1 %2)
- (:related-streams (js->clj res :keywordize-keys true)))
- (assoc-in [:playlist :next-page]
- (:next-page (js->clj res :keywordize-keys true)))
- (assoc :show-pagination-loading false))))
-
-(rf/reg-event-fx
- ::playlist-pagination
- (fn [{:keys [db]} [_ uri next-page-url]]
- (if (empty? next-page-url)
- {:db (assoc db :show-pagination-loading false)}
- (assoc
- (api/get-request
- (str "/api/playlists/" (js/encodeURIComponent uri))
- [::load-paginated-playlist-results] [::bad-response]
- {:nextPage (js/encodeURIComponent next-page-url)})
- :db (assoc db :show-pagination-loading true)))))
-
-(rf/reg-event-db
- ::load-paginated-search-results
- (fn [db [_ res]]
- (-> db
- (update-in [:search-results :items] #(apply conj %1 %2)
- (:items (js->clj res :keywordize-keys true)))
- (assoc-in [:search-results :next-page]
- (:next-page (js->clj res :keywordize-keys true)))
- (assoc :show-pagination-loading false))))
-
-(rf/reg-event-fx
- ::search-pagination
- (fn [{:keys [db]} [_ query id next-page-url]]
- (if (empty? next-page-url)
- {:db (assoc db :show-pagination-loading false)}
- (assoc
- (api/get-request
- (str "/api/services/" id "/search")
- [::load-paginated-search-results] [::bad-response]
- {:q query
- :nextPage (js/encodeURIComponent next-page-url)})
- :db (assoc db :show-pagination-loading true)))))
-
-(rf/reg-event-db
- ::change-global-stream
- (fn [db [_ global-stream]]
- (assoc db :global-stream global-stream)))
-
-(rf/reg-event-db
- ::toggle-global-player
- (fn [db _]
- (assoc db :show-global-player (not (:show-global-player db)))))
-
-(rf/reg-event-fx
- ::switch-to-global-player
- (fn [{:keys [db]} [_ global-stream]]
- {:db (assoc db :show-global-player true)
- :fx [[:dispatch [::change-global-stream global-stream]]]}))
-
-(rf/reg-event-db
- ::load-services
- (fn [db [_ res]]
- (assoc db :services (js->clj res :keywordize-keys true))))
-
-(rf/reg-event-fx
- ::get-services
- (fn [{:keys [db]} _]
- (api/get-request "/api/services" [::load-services] [::bad-response])))
-
-(rf/reg-event-db
- ::load-comments
- (fn [db [_ res]]
- (-> db
- (assoc-in [:stream :comments-page] (js->clj res :keywordize-keys true))
- (assoc-in [:stream :show-comments-loading] false))))
-
-(rf/reg-event-fx
- ::get-comments
- (fn [{:keys [db]} [_ url]]
- (assoc
- (api/get-request (str "/api/comments/" (js/encodeURIComponent url))
- [::load-comments] [::bad-response])
- :db (-> db
- (assoc-in [:stream :show-comments-loading] true)
- (assoc-in [:stream :show-comments] true)))))
-
-(rf/reg-event-db
- ::toggle-comments
- (fn [db _]
- (assoc-in db [:stream :show-comments] (not (-> db :stream :show-comments)))))
-
-(rf/reg-event-db
- ::toggle-comment-replies
- (fn [db [_ comment-id]]
- (update-in db [:stream :comments-page :comments]
- (fn [comments]
- (map #(if (= (:id %) comment-id)
- (assoc % :show-replies (not (:show-replies %)))
- %)
- comments)))))
-
-(rf/reg-event-db
- ::load-paginated-comments
- (fn [db [_ res]]
- (-> db
- (update-in [:stream :comments-page :comments] #(apply conj %1 %2)
- (:comments (js->clj res :keywordize-keys true)))
- (assoc-in [:stream :comments-page :next-page]
- (:next-page (js->clj res :keywordize-keys true)))
- (assoc :show-pagination-loading false))))
-
-(rf/reg-event-fx
- ::comments-pagination
- (fn [{:keys [db]} [_ url next-page-url]]
- (if (empty? next-page-url)
- {:db (assoc db :show-pagination-loading false)}
- (assoc
- (api/get-request (str "/api/comments/" (js/encodeURIComponent url))
- [::load-paginated-comments] [::bad-response]
- {:nextPage (js/encodeURIComponent next-page-url)})
- :db (assoc db :show-pagination-loading true)))))
-
-(rf/reg-event-db
- ::load-kiosks
- (fn [db [_ res]]
- (assoc db :kiosks (js->clj res :keywordize-keys true))))
-
-(rf/reg-event-fx
- ::get-kiosks
- (fn [{:keys [db]} [_ id]]
- (api/get-request (str "/api/services/" id "/kiosks") [::load-kiosks] [::bad-response])))
-
-(rf/reg-event-db
- ::load-kiosk
- (fn [db [_ res]]
- (assoc db :kiosk (js->clj res :keywordize-keys true)
- :show-page-loading false)))
-
-(rf/reg-event-fx
- ::get-default-kiosk
- (fn [{:keys [db]} [_ service-id]]
- (assoc
- (api/get-request (str "/api/services/" service-id "/default-kiosk")
- [::load-kiosk] [::bad-response])
- :db (assoc db :show-page-loading true))))
-
-(rf/reg-event-fx
- ::get-kiosk
- (fn [{:keys [db]} [_ service-id kiosk-id]]
- (if kiosk-id
- (assoc
- (api/get-request (str "/api/services/" service-id "/kiosks/"
- (js/encodeURIComponent kiosk-id))
- [::load-kiosk] [::bad-response])
- :db (assoc db :show-page-loading true))
- {:fx [[:dispatch [::get-default-kiosk service-id]]]})))
-
-(rf/reg-event-fx
- ::change-service
- (fn [{:keys [db]} [_ service-id]]
- {:fx [[:dispatch
- [::navigate {:name :tau.routes/kiosk
- :params {}
- :query {:serviceId service-id}}]]]}))
-
-(rf/reg-event-db
- ::load-paginated-kiosk-results
- (fn [db [_ res]]
- (-> db
- (update-in [:kiosk :related-streams] #(apply conj %1 %2)
- (:related-streams (js->clj res :keywordize-keys true)))
- (assoc-in [:kiosk :next-page]
- (:next-page (js->clj res :keywordize-keys true)))
- (assoc :show-pagination-loading false))))
-
-(rf/reg-event-fx
- ::kiosk-pagination
- (fn [{:keys [db]} [_ service-id kiosk-id next-page-url]]
- (if (empty? next-page-url)
- {:db (assoc db :show-pagination-loading false)}
- (assoc
- (api/get-request
- (str "/api/services/" service-id "/kiosks/" (js/encodeURIComponent kiosk-id))
- [::load-paginated-kiosk-results] [::bad-response]
- {:nextPage (js/encodeURIComponent next-page-url)})
- :db (assoc db :show-pagination-loading true)))))
-
-(rf/reg-event-fx
- ::load-stream
- (fn [{:keys [db]} [_ res]]
- (let [stream-res (js->clj res :keywordize-keys true)]
- {:db (assoc db :stream stream-res
- :show-page-loading false)
- :fx [[:dispatch [::change-stream-format nil]]
- [:dispatch [::get-comments (:url stream-res)]]]})))
-
-(rf/reg-event-fx
- ::get-stream
- (fn [{:keys [db]} [_ uri]]
- (assoc
- (api/get-request (str "/api/streams/" (js/encodeURIComponent uri))
- [::load-stream] [::bad-response])
- :db (assoc db :show-page-loading true))))
-
-(rf/reg-event-db
- ::change-stream-format
- (fn [{:keys [stream] :as db} [_ format-id]]
- (let [{:keys [audio-streams video-streams]} stream]
- (if format-id
- (assoc db :stream-format
- (first (filter #(= format-id (:id %)) (apply conj audio-streams video-streams))))
- (assoc db :stream-format (-> (if (empty? video-streams) audio-streams video-streams)
- last))))))
-
-(rf/reg-event-db
- ::load-channel
- (fn [db [_ res]]
- (assoc db :channel (js->clj res :keywordize-keys true)
- :show-page-loading false)))
-
-(rf/reg-event-fx
- ::get-channel
- (fn [{:keys [db]} [_ uri]]
- (assoc
- (api/get-request
- (str "/api/channels/" (js/encodeURIComponent uri))
- [::load-channel] [::bad-response])
- :db (assoc db :show-page-loading true))))
-
-(rf/reg-event-db
- ::load-playlist
- (fn [db [_ res]]
- (assoc db :playlist (js->clj res :keywordize-keys true)
- :show-page-loading false)))
-
-(rf/reg-event-fx
- ::get-playlist
- (fn [{:keys [db]} [_ uri]]
- (assoc
- (api/get-request (str "/api/playlists/" (js/encodeURIComponent uri))
- [::load-playlist] [::bad-response])
- :db (assoc db :show-page-loading true))))
-
-(rf/reg-event-db
- ::load-search-results
- (fn [db [_ res]]
- (assoc db :search-results (js->clj res :keywordize-keys true)
- :show-page-loading false
- :global-search "")))
-
-(rf/reg-event-fx
- ::get-search-results
- (fn [{:keys [db]} [_ service-id query]]
- (assoc
- (api/get-request (str "/api/services/" service-id "/search")
- [::load-search-results] [::bad-response]
- {:q query})
- :db (assoc db :show-page-loading true))))
diff --git a/src/frontend/tau/routes.cljs b/src/frontend/tau/routes.cljs
deleted file mode 100644
index a5fb579..0000000
--- a/src/frontend/tau/routes.cljs
+++ /dev/null
@@ -1,58 +0,0 @@
-(ns tau.routes
- (:require
- [reitit.frontend :as ref]
- [reitit.frontend.easy :as rfe]
- [re-frame.core :as rf]
- [tau.events :as events]
- [tau.views.channel :as channel]
- [tau.views.kiosk :as kiosk]
- [tau.views.playlist :as playlist]
- [tau.views.search :as search]
- [tau.views.stream :as stream]))
-
-(def routes
- (ref/router
- [["/" {:view kiosk/kiosk
- :name ::home
- :controllers [{:start (fn [_]
- (rf/dispatch [::events/change-service-id 0])
- (rf/dispatch [::events/get-default-kiosk 0])
- (rf/dispatch [::events/get-kiosks 0]))}]}]
- ["/search" {:view search/search
- :name ::search
- :controllers [{:parameters {:query [:q :serviceId]}
- :start (fn [{{:keys [serviceId q]} :query}]
- (rf/dispatch [::events/change-service-id (js/parseInt serviceId)])
- (rf/dispatch [::events/get-search-results serviceId q]))}]}]
- ["/stream" {:view stream/stream
- :name ::stream
- :controllers [{:parameters {:query [:url]}
- :start (fn [{{:keys [url]} :query}]
- (rf/dispatch [::events/get-stream url]))}]}]
- ["/channel" {:view channel/channel
- :name ::channel
- :controllers [{:parameters {:query [:url]}
- :start (fn [{{:keys [url]} :query}]
- (rf/dispatch [::events/get-channel url]))}]}]
- ["/playlist" {:view playlist/playlist
- :name ::playlist
- :controllers [{:parameters {:query [:url]}
- :start (fn [{{:keys [url]} :query}]
- (rf/dispatch [::events/get-playlist url]))}]}]
- ["/kiosk" {:view kiosk/kiosk
- :name ::kiosk
- :controllers [{:parameters {:query [:kioskId :serviceId]}
- :start (fn [{{:keys [serviceId kioskId]} :query}]
- (rf/dispatch [::events/change-service-id (js/parseInt serviceId)])
- (rf/dispatch [::events/get-kiosk serviceId kioskId])
- (rf/dispatch [::events/get-kiosks serviceId]))}]}]]))
-
-(defn on-navigate
- [new-match]
- (rf/dispatch [::events/reset-page-scroll])
- (when new-match
- (rf/dispatch [::events/navigated new-match])))
-
-(defn start-routes!
- []
- (rfe/start! routes on-navigate {:use-fragment false}))
diff --git a/src/frontend/tau/subs.cljs b/src/frontend/tau/subs.cljs
deleted file mode 100644
index 41bbb67..0000000
--- a/src/frontend/tau/subs.cljs
+++ /dev/null
@@ -1,98 +0,0 @@
-(ns tau.subs
- (:require
- [re-frame.core :as rf]))
-
-(rf/reg-sub
- :http-response
- (fn [db _]
- (:http-response db)))
-
-(rf/reg-sub
- :search-results
- (fn [db _]
- (:search-results db)))
-
-(rf/reg-sub
- :stream
- (fn [db _]
- (:stream db)))
-
-(rf/reg-sub
- :stream-format
- (fn [db _]
- (:stream-format db)))
-
-(rf/reg-sub
- :playlist
- (fn [db _]
- (:playlist db)))
-
-(rf/reg-sub
- :channel
- (fn [db _]
- (:channel db)))
-
-(rf/reg-sub
- :global-search
- (fn [db _]
- (:global-search db)))
-
-(rf/reg-sub
- :service-id
- (fn [db _]
- (:service-id db)))
-
-(rf/reg-sub
- :service-color
- (fn [db _]
- (:service-color db)))
-
-(rf/reg-sub
- :services
- (fn [db _]
- (:services db)))
-
-(rf/reg-sub
- :kiosks
- (fn [db _]
- (:kiosks db)))
-
-(rf/reg-sub
- :kiosk
- (fn [db _]
- (:kiosk db)))
-
-(rf/reg-sub
- :current-match
- (fn [db _]
- (:current-match db)))
-
-(rf/reg-sub
- :page-scroll
- (fn [db _]
- (:page-scroll db)))
-
-(rf/reg-sub
- :global-stream
- (fn [db _]
- (:global-stream db)))
-
-(rf/reg-sub
- :show-global-player
- (fn [db _]
- (:show-global-player db)))
-
-(rf/reg-sub
- :show-page-loading
- (fn [db _]
- (:show-page-loading db)))
-
-(rf/reg-sub
- :show-pagination-loading
- (fn [db _]
- (:show-pagination-loading db)))
-
-(rf/reg-sub
- :show-mobile-nav
- (fn [db _]
- (:show-mobile-nav db)))
diff --git a/src/frontend/tau/util.cljs b/src/frontend/tau/util.cljs
deleted file mode 100644
index d23ef9a..0000000
--- a/src/frontend/tau/util.cljs
+++ /dev/null
@@ -1,24 +0,0 @@
-(ns tau.util
- (:require
- ["timeago.js" :as timeago]))
-
-(defn format-date
- [date]
- (if (-> date js/Date.parse js/isNaN)
- date
- (timeago/format date)))
-
-(defn format-quantity
- [num]
- (.format
- (js/Intl.NumberFormat
- "en-US" #js {"notation" "compact" "maximumFractionDigits" 1})
- num))
-
-(defn format-duration
- [num]
- (let [duration (js/Date. (* num 1000))
- slice (if (> (.getHours duration) 1)
- #(.slice % 11 19)
- #(.slice % 14 19))]
- (-> duration (.toISOString) slice)))
diff --git a/src/frontend/tau/views.cljs b/src/frontend/tau/views.cljs
deleted file mode 100644
index 6a4789f..0000000
--- a/src/frontend/tau/views.cljs
+++ /dev/null
@@ -1,98 +0,0 @@
-(ns tau.views
- (:require
- [reitit.frontend.easy :as rfe]
- [re-frame.core :as rf]
- [reagent.ratom :as ratom]
- [tau.components.navigation :as navigation]
- [tau.components.player :as player]
- [tau.events :as events]
- [tau.routes :as routes]))
-
-(defonce scroll-hook (.addEventListener js/window "scroll" #(rf/dispatch [::events/page-scroll])))
-(defonce mobile-touch-hook (.addEventListener js/document.body "touchmove" #(rf/dispatch [::events/page-scroll])))
-(defonce services (rf/dispatch [::events/get-services]))
-(defonce kiosks (rf/dispatch [::events/get-kiosks 0]))
-
-(defn navbar
- [{{:keys [serviceId]} :query-params}]
- (let [service-id @(rf/subscribe [:service-id])
- service-color @(rf/subscribe [:service-color])
- global-search @(rf/subscribe [:global-search])
- services @(rf/subscribe [:services])
- id (js/parseInt (or serviceId service-id))
- mobile-nav? @(rf/subscribe [:show-mobile-nav])
- {:keys [available-kiosks default-kiosk]} @(rf/subscribe [:kiosks])]
- [:nav.flex.px-2.py-2.5.items-center.sticky.top-0.z-50.font-nunito
- {:style {:background service-color}}
- [:div.flex.items-center.justify-between.flex-auto
- [:div.py-2
- [:a.px-5.text-white.font-bold.font-nunito
- {:href (rfe/href ::routes/home) :dangerouslySetInnerHTML {:__html "&tau;"}}]]
- [:form.flex.items-center.relative
- {:on-submit (fn [e]
- (.preventDefault e)
- (rf/dispatch [::events/navigate
- {:name ::routes/search
- :params {}
- :query {:q global-search :serviceId service-id}}]))}
- [:div
- [:input.bg-transparent.border-none.rounded.py-2.px-1.focus:ring-transparent.placeholder-white.box-border.w-40.xs:w-auto
- {:type "text"
- :value global-search
- :on-change #(rf/dispatch [::events/change-global-search (.. % -target -value)])
- :placeholder "Search for something"}]]
- [:div.flex.items-center.px-2
- [:button.text-white
- {:type "submit"}
- [:i.fas.fa-search]]]]
- [:div.cursor-pointer.px-2.ml:hidden
- {:on-click #(rf/dispatch [::events/toggle-mobile-nav])}
- [:i.fa-solid.fa-bars]]
- [:div.bg-neutral-900.items-center.fixed.overflow-x-hidden.min-h-screen.w-60.top-0.shadow-xl.shadow-black.pt-8
- {:class (str "ease-in-out delay-75 transition-[right] "
- "ml:w-full ml:flex ml:min-h-0 ml:relative ml:text-white ml:bg-transparent ml:shadow-none ml:p-0 ml:right-0 "
- (if mobile-nav? "right-0" "right-[-245px]"))}
- [:div.cursor-pointer.px-2.ml:hidden.absolute.top-1.right-2
- {:on-click #(rf/dispatch [::events/toggle-mobile-nav])}
- [:i.fa-solid.fa-close.text-xl]]
- [:div.relative.flex.flex-col.items-center.justify-center.ml:flex-row
- [:div.w-full.box-border.z-10
- [:select.border-none.focus:ring-transparent.bg-blend-color-dodge.font-bold.font-nunito.px-5.w-full
- {:on-change #(rf/dispatch [::events/change-service (js/parseInt (.. % -target -value))])
- :value service-id
- :style {:background "transparent"}}
- (when services
- (for [service services]
- [:option.bg-neutral-900.border-none {:value (:id service) :key (:id service)}
- (-> service :info :name)]))]]
- [:div.flex.absolute.min-h-full.top-0.right-4.ml:right-0.items-center.justify-end.z-0
- [:i.fa-solid.fa-caret-down]]]
- [:div.relative.flex-auto.ml:pl-4
- [:ul.flex.font-roboto.flex-col.ml:flex-row
- (for [kiosk available-kiosks]
- [:li.px-5.py-2 {:key kiosk}
- [:a {:href (rfe/href ::routes/kiosk nil {:serviceId service-id
- :kioskId kiosk})}
- kiosk]])]]]]]))
-
-(defn footer
- []
- [:footer
- [:div.bg-black.text-gray-300.p-5.text-center.w-full
- [:div.flex.flex-col.justify-center
- [:div
- [:p.px-2 (str "Tau " (.getFullYear (js/Date.)))]]
- [:div.pt-4
- [:a {:href "https://sr.ht/~conses/tau"}
- [:i.fa-solid.fa-code]]]]]])
-
-(defn app
- []
- (let [current-match @(rf/subscribe [:current-match])]
- [:div.min-h-screen.flex.flex-col.h-full.text-white.bg-neutral-900.relative
- [navbar current-match]
- [:div.flex.flex-col.justify-between.relative.font-nunito {:class "min-h-[calc(100vh-58px)]"}
- (when-let [view (-> current-match :data :view)]
- [view current-match])
- [footer]
- [player/global-player]]]))
diff --git a/src/frontend/tau/views/channel.cljs b/src/frontend/tau/views/channel.cljs
deleted file mode 100644
index 205474d..0000000
--- a/src/frontend/tau/views/channel.cljs
+++ /dev/null
@@ -1,41 +0,0 @@
-(ns tau.views.channel
- (:require
- [re-frame.core :as rf]
- [tau.components.items :as items]
- [tau.components.loading :as loading]
- [tau.components.navigation :as navigation]
- [tau.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])
- page-loading? @(rf/subscribe [:show-page-loading])
- pagination-loading? @(rf/subscribe [:show-pagination-loading])
- page-scroll @(rf/subscribe [:page-scroll])
- scrolled-to-bottom? (= page-scroll (.-scrollHeight js/document.body))]
- (when scrolled-to-bottom?
- (rf/dispatch [::events/channel-pagination url next-page-url]))
- [:div.flex.flex-col.items-center.px-5.py-2.flex-auto
- (if page-loading?
- [loading/loading-icon service-color "text-5xl"]
- [:div.flex.flex-col.flex-auto {:class "ml:w-4/5 xl:w-3/5"}
- [navigation/back-button service-color]
- (when banner
- [:div.flex.justify-center
- [:img {:src banner}]])
- [:div.flex.items-center.my-4.mx-2
- (when avatar
- [:div.relative.w-16.h-16
- [:img.rounded-full.object-cover.max-w-full.min-h-full {:src avatar :alt 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)]])]]
- [:div.my-2
- [:p description]]
- [items/related-streams related-streams next-page-url]])]))
diff --git a/src/frontend/tau/views/kiosk.cljs b/src/frontend/tau/views/kiosk.cljs
deleted file mode 100644
index 824d85b..0000000
--- a/src/frontend/tau/views/kiosk.cljs
+++ /dev/null
@@ -1,26 +0,0 @@
-(ns tau.views.kiosk
- (:require
- [re-frame.core :as rf]
- [tau.components.items :as items]
- [tau.components.loading :as loading]
- [tau.components.navigation :as navigation]
- [tau.events :as events]))
-
-(defn kiosk
- [{{:keys [serviceId kioskId]} :query-params}]
- (let [{:keys [id url related-streams next-page]} @(rf/subscribe [:kiosk])
- next-page-url (:url next-page)
- service-color @(rf/subscribe [:service-color])
- page-loading? @(rf/subscribe [:show-page-loading])
- page-scroll @(rf/subscribe [:page-scroll])
- scrolled-to-bottom? (= page-scroll (.-scrollHeight js/document.body))]
- (when scrolled-to-bottom?
- (rf/dispatch [::events/kiosk-pagination serviceId id next-page-url]))
- [:div.flex.flex-col.items-center.px-5.py-2.flex-auto
- (if page-loading?
- [loading/loading-icon service-color "text-5xl"]
- [:div.flex.flex-col.flex-auto.w-full {:class "lg:w-4/5"}
- [:div.flex.justify-center.items-center.my-4.mx-2
- [:div.m-4
- [:h1.text-2xl id]]]
- [items/related-streams related-streams next-page-url]])]))
diff --git a/src/frontend/tau/views/playlist.cljs b/src/frontend/tau/views/playlist.cljs
deleted file mode 100644
index 756846c..0000000
--- a/src/frontend/tau/views/playlist.cljs
+++ /dev/null
@@ -1,40 +0,0 @@
-(ns tau.views.playlist
- (:require
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tau.components.items :as items]
- [tau.components.loading :as loading]
- [tau.components.navigation :as navigation]
- [tau.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])
- page-loading? @(rf/subscribe [:show-page-loading])
- page-scroll @(rf/subscribe [:page-scroll])
- scrolled-to-bottom? (= page-scroll (.-scrollHeight js/document.body))]
- (when scrolled-to-bottom?
- (rf/dispatch [::events/playlist-pagination url next-page-url]))
- [:div.flex.flex-col.items-center.px-5.pt-4.flex-auto
- (if page-loading?
- [loading/loading-icon service-color "text-5xl"]
- [:div.flex.flex-col.flex-auto.w-full {:class "ml:w-4/5"}
- [navigation/back-button service-color]
- (when banner-url
- [:div
- [:img {:src banner-url}]])
- [:div.flex.items-center.justify-center.my-4.mx-2
- [:div.flex.flex-col.justify-center.items-center
- [:h1.text-2xl.font-bold name]
- [:div.flex.items-center.pt-4
- [:span.mr-2 "By"]
- [:div.flex.items-center.py-3.box-border.h-12
- [:div.w-12
- [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title uploader-name}
- [:img.rounded-full.object-cover.min-h-full.min-w-full {:src uploader-avatar :alt uploader-name}]]]]]
- [:p.pt-4 (str stream-count " streams")]]]
- [items/related-streams related-streams next-page-url]])]))
diff --git a/src/frontend/tau/views/search.cljs b/src/frontend/tau/views/search.cljs
deleted file mode 100644
index bfb0b20..0000000
--- a/src/frontend/tau/views/search.cljs
+++ /dev/null
@@ -1,28 +0,0 @@
-(ns tau.views.search
- (:require
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tau.components.items :as items]
- [tau.components.loading :as loading]
- [tau.events :as events]))
-
-(defn search
- [{{:keys [q serviceId]} :query-params}]
- (let [{:keys [items next-page] :as search-results} @(rf/subscribe [:search-results])
- next-page-url (:url next-page)
- services @(rf/subscribe [:services])
- service-id @(rf/subscribe [:service-id])
- service-color @(rf/subscribe [:service-color])
- page-scroll @(rf/subscribe [:page-scroll])
- page-loading? @(rf/subscribe [:show-page-loading])
- scrolled-to-bottom? (= page-scroll (.-scrollHeight js/document.body))]
- (when scrolled-to-bottom?
- (rf/dispatch [::events/search-pagination q serviceId next-page-url]))
- [:div.flex.flex-col.items-center.flex-auto
- [:div.flex.flex-col.items-center.w-full.pt-4.flex-initial
- [:h2 (str "Showing search results for: \"" q "\"")]
- [:h1 (str "Number of search results: " (count items))]]
- (if page-loading?
- [loading/loading-icon service-color "text-5xl"]
- [:div.flex.flex-col.flex-auto.w-full {:class "lg:w-4/5"}
- [items/related-streams items next-page-url]])]))
diff --git a/src/frontend/tau/views/stream.cljs b/src/frontend/tau/views/stream.cljs
deleted file mode 100644
index 3363d6a..0000000
--- a/src/frontend/tau/views/stream.cljs
+++ /dev/null
@@ -1,122 +0,0 @@
-(ns tau.views.stream
- (:require
- [re-frame.core :as rf]
- [reitit.frontend.easy :as rfe]
- [tau.events :as events]
- [tau.components.items :as items]
- [tau.components.loading :as loading]
- [tau.components.navigation :as navigation]
- [tau.components.comments :as comments]
- [tau.components.player :as player]
- [tau.util :as util]))
-
-(defn stream
- [match]
- (let [{:keys [name url video-streams audio-streams view-count
- subscriber-count like-count dislike-count
- description uploader-avatar uploader-name
- uploader-url upload-date related-streams
- thumbnail-url show-comments-loading comments-page
- show-comments service-id] :as stream} @(rf/subscribe [:stream])
- available-streams (apply conj audio-streams video-streams)
- {:keys [content id] :as stream-format} @(rf/subscribe [:stream-format])
- page-loading? @(rf/subscribe [:show-page-loading])
- service-color @(rf/subscribe [:service-color])]
- [:div.flex.flex-col.items-center.justify-center.text-white.flex-auto
- (if page-loading?
- [loading/loading-icon service-color "text-5xl"]
- [:div.w-full.pb-4.relative {:class "ml:w-4/5 xl:w-3/5"}
- [navigation/back-button service-color]
- [:div.flex.justify-center.relative
- {:class "ml:h-[450px] lg:h-[600px]"}
- (when stream-format
- [player/stream-player {"sources" [{"src" content "type" "video/mp4"}
- {"src" content "type" "video/webm"}]
- "poster" thumbnail-url
- "controls" true}
- content])]
- [:div.px-4.ml:p-0
- [:div.flex.flex.w-full.mt-3
- (when stream-format
- [:div.relative.flex.bg-stone-800.flex-col.items-center.justify-center.z-10.mr-2.border.rounded.border-black
- [:select.border-none.focus:ring-transparent.bg-blend-color-dodge.pl-4.pr-8.w-full
- {:on-change #(rf/dispatch [::events/change-stream-format (.. % -target -value)])
- :value id
- :style {:background "transparent"}}
- (when available-streams
- (for [[i {:keys [id format resolution averageBitrate]}] (map-indexed vector available-streams)]
- [:option.bg-neutral-900.border-none {:value id :key i}
- (str (or resolution "audio-only") " " format (when-not resolution (str " " averageBitrate "kbit/s")))]))]
- [:div.flex.absolute.min-h-full.top-0.right-4.items-center.justify-end
- {:style {:zIndex "-1"}}
- [:i.fa-solid.fa-caret-down]]])
- [:button.border.rounded.border-black.px-3.py-1.bg-stone-800
- {:on-click #(rf/dispatch [::events/switch-to-global-player
- {:uploader-name uploader-name :uploader-url uploader-url
- :name name :url url :stream content :service-color service-color}])}
- [:i.fa-solid.fa-headphones]]
- [:button.border.rounded.border-black.px-3.py-1.bg-stone-800.mx-2
- [:a {:href url}
- [:i.fa-solid.fa-external-link-alt]]]]
- [:div.flex.flex-col.py-1.comments
- [:div.min-w-full.py-3
- [:h1.text-2xl.font-extrabold.line-clamp-1 name]]
- [:div.flex.justify-between.py-2
- [:div.flex.items-center.flex-auto
- (when uploader-avatar
- [:div.relative.w-16.h-16
- [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url}) :title uploader-name}
- [:img.rounded-full.object-cover.max-w-full.min-h-full {:src uploader-avatar :alt uploader-name}]]])
- [:div.mx-2
- [:a {:href (rfe/href :tau.routes/channel nil {:url uploader-url})} uploader-name]
- (when subscriber-count
- [:div.flex.my-2.items-center
- [:i.fa-solid.fa-users.text-xs]
- [:p.mx-2 (util/format-quantity subscriber-count)]])]]
- [:div.flex.flex-col.items-end
- (when view-count
- [:div
- [:i.fa-solid.fa-eye.text-xs]
- [:span.ml-2 (.toLocaleString view-count)]])
- [:div.flex
- (when like-count
- [:div.items-center
- [:i.fa-solid.fa-thumbs-up.text-xs]
- [:span.ml-2 (.toLocaleString like-count)]])
- (when dislike-count
- [:div.ml-2.items-center
- [:i.fa-solid.fa-thumbs-down.text-xs]
- [:span.ml-2 dislike-count]])]
- (when upload-date
- [:div
- [:i.fa-solid.fa-calendar.mx-2.text-xs]
- [:span
- (-> upload-date
- js/Date.parse
- js/Date.
- .toDateString)]])]]
- [:div.min-w-full.py-3
- [:h1 name]
- [:div {:dangerouslySetInnerHTML {:__html description}}]]
- [:div.py-6
- [:div.flex.items-center
- [:i.fa-solid.fa-comments]
- [:p.px-2.py-4 "Comments"]
- (if show-comments
- [:i.fa-solid.fa-chevron-up {:on-click #(rf/dispatch [::events/toggle-comments])
- :style {:cursor "pointer"}}]
- [:i.fa-solid.fa-chevron-down {:on-click #(if (or show-comments comments-page)
- (rf/dispatch [::events/toggle-comments])
- (rf/dispatch [::events/get-comments url]))
- :style {:cursor "pointer"}}])]
- [:div
- (if show-comments-loading
- [loading/loading-icon service-color "text-2xl"]
- (when (and show-comments comments-page)
- [comments/comments comments-page uploader-name uploader-avatar url]))]]
- (when-not (empty? related-streams)
- [:div.py-3
- [:div.flex.items-center
- [:i.fa-solid.fa-list]
- [:h1.px-2.text-lg.bold "Related Results"]]
- [items/related-streams related-streams nil]])]]])]))