aboutsummaryrefslogtreecommitdiff
path: root/src/frontend
diff options
context:
space:
mode:
authorMiguel Ángel Moreno <mail@migalmoreno.com>2022-12-20 00:49:47 +0100
committerMiguel Ángel Moreno <mail@migalmoreno.com>2022-12-20 00:55:16 +0100
commitf2f9ab53c28a0fe63dfbbc09780ad4c0e9c40ba0 (patch)
treed32cbc72534f04d1652bac301d71b566eb824047 /src/frontend
parent49ed8afbdddac61815807cbb8a811ecbd41cd973 (diff)
feat: Add initial frontend views
Diffstat (limited to 'src/frontend')
-rw-r--r--src/frontend/tau/views.cljs54
-rw-r--r--src/frontend/tau/views/home.cljs7
-rw-r--r--src/frontend/tau/views/player.cljs11
-rw-r--r--src/frontend/tau/views/search.cljs38
-rw-r--r--src/frontend/tau/views/stream.cljs27
5 files changed, 137 insertions, 0 deletions
diff --git a/src/frontend/tau/views.cljs b/src/frontend/tau/views.cljs
new file mode 100644
index 0000000..139bb83
--- /dev/null
+++ b/src/frontend/tau/views.cljs
@@ -0,0 +1,54 @@
+(ns tau.views
+ (:require
+ [tau.views.player :as player]
+ [reitit.frontend.easy :as rfe]
+ [re-frame.core :as rf]))
+
+(defn footer
+ []
+ [:footer.bg-slate-900.text-gray-300.p-5.text-center
+ [:div
+ [:p (str "Tau " (.getFullYear (js/Date.)))]]])
+
+(defn search-bar
+ []
+ (let [global-search @(rf/subscribe [:global-search])
+ services @(rf/subscribe [:services])
+ service-id @(rf/subscribe [:service-id])]
+ [:div.flex
+ [:form {:on-submit (fn [e]
+ (.preventDefault e)
+ (rfe/push-state :tau.routes/search {} {:q global-search :serviceId service-id}))}
+ [:input.bg-slate-900.border.border-solid.border-black.rounded.py-2.px-1.mx-2.text-gray-500
+ {:type "text"
+ :value global-search
+ :on-change #(rf/dispatch [:change-global-search (.. % -target -value)])
+ :placeholder "Search for something"}]
+ [:select.mx-2.bg-gray-50.border.border-gray-900.text-gray-900
+ {:on-change #(rf/dispatch [:change-service-id (js/parseInt (.. % -target -value))])}
+ (for [service services]
+ [:option {:value (:id service) :key (:id service) :selected (= (:id service) service-id)}
+ (-> service :info :name)])]
+ [:button..bg-slate-900.border.border-black.rounded.border-solid.text-gray-500.p-2.mx-2
+ {:type "submit"} "Search"]]]))
+
+(defn navbar []
+ [:nav.bg-slate-800.flex.p-2.content-center.sticky.top-0.z-50
+ [:div.px-5.text-white.p-2
+ [:a {:href (rfe/href :tau.routes/home) :dangerouslySetInnerHTML {:__html "&tau;"}}]]
+ [:ul.flex.content-center.text-white.p-2
+ [:li.px-5 [:a {:href (rfe/href :tau.routes/home)} "Home"]]
+ [:li.px-5 [:a {:href (rfe/href :tau.routes/search)} "Search"]]]
+ [search-bar]])
+
+(defn app
+ []
+ (rf/dispatch [:get-services])
+ (let [current-match @(rf/subscribe [:current-match])]
+ [:div.font-sans.bg-slate-700.min-h-screen.flex.flex-col.h-full
+ [navbar]
+ [:div.flex.flex-col.justify-between {:class "min-h-[calc(100vh-58px)]"}
+ (when-let [view (-> current-match :data :view)]
+ [view current-match])
+ [player/global-player]
+ [footer]]]))
diff --git a/src/frontend/tau/views/home.cljs b/src/frontend/tau/views/home.cljs
new file mode 100644
index 0000000..0d42d7d
--- /dev/null
+++ b/src/frontend/tau/views/home.cljs
@@ -0,0 +1,7 @@
+(ns tau.views.home)
+
+(defn home-page
+ []
+ [:div.flex.justify-center.content-center.flex-col.text-center.text-white.text-lg.flex-auto
+ [:p.text-5xl.p-5 "Welcome to Tau"]
+ [:p.text-2xl "A web front-end for Newpipe"]])
diff --git a/src/frontend/tau/views/player.cljs b/src/frontend/tau/views/player.cljs
new file mode 100644
index 0000000..732e542
--- /dev/null
+++ b/src/frontend/tau/views/player.cljs
@@ -0,0 +1,11 @@
+(ns tau.views.player
+ (:require
+ [re-frame.core :as rf]))
+
+(defn global-player
+ []
+ (let [global-stream @(rf/subscribe [:global-stream])
+ show-global-player? @(rf/subscribe [:show-global-player])]
+ [:div
+ [:audio {:src global-stream
+ :class (when-not show-global-player? "hidden")}]]))
diff --git a/src/frontend/tau/views/search.cljs b/src/frontend/tau/views/search.cljs
new file mode 100644
index 0000000..64bddf3
--- /dev/null
+++ b/src/frontend/tau/views/search.cljs
@@ -0,0 +1,38 @@
+(ns tau.views.search
+ (:require
+ [re-frame.core :as rf]
+ [reitit.frontend.easy :as rfe]))
+
+(defn search-result
+ [title author url thumbnail id]
+ [:div.w-56.h-64.my-2 {:key id}
+ [:div.p-5.border.rounded.border-slate-900.m-2.bg-slate-600.flex.flex-col.max-w-full.min-h-full.max-h-full
+ [:a.overflow-hidden {:href (rfe/href :tau.routes/stream {} {:url url}) :title title}
+ [:div.flex.justify-center.min-w-full.py-3.box-border
+ [:div.h-28.min-w-full.flex.justify-center
+ [:img.rounded.object-cover.max-h-full {:src thumbnail}]]]
+ [:div.overflow-hidden
+ [:h1.text-gray-300.font-bold author]
+ [:h1 title]]]]])
+
+(defn search
+ [m]
+ (let [search-results (rf/subscribe [:search-results])
+ services (rf/subscribe [:services])
+ service-id (rf/subscribe [:service-id])]
+ [:div.text-gray-300.text-center.py-5.relative
+ [:h2 (str "Showing search results for: \"" (-> m :query-params :q) "\"")]
+ [:h1 (str "Number of search results: " (count (:items @search-results)))]
+ ;; TODO: Create loadable component that wraps other components that need to fetch from API
+ ;; or use a :loading key to show a spinner component instead
+ (if (empty? @search-results)
+ [:p "Loading"]
+ [:div.flex.justify-center.align-center.flex-wrap
+ (for [[i result] (map-indexed vector (:items @search-results))]
+ ;; TODO: Add a component per result type
+ [search-result
+ (:name result)
+ (:upload-author result)
+ (:url result)
+ (:thumbnail-url result)
+ i])])]))
diff --git a/src/frontend/tau/views/stream.cljs b/src/frontend/tau/views/stream.cljs
new file mode 100644
index 0000000..ccc53eb
--- /dev/null
+++ b/src/frontend/tau/views/stream.cljs
@@ -0,0 +1,27 @@
+(ns tau.views.stream
+ (:require
+ [re-frame.core :as rf]))
+
+(defn stream
+ [m]
+ (let [current-stream @(rf/subscribe [:stream])
+ stream-type (-> (if (empty? (:video-streams current-stream))
+ (:audio-streams current-stream)
+ (:video-streams current-stream))
+ last
+ :content)]
+ [:div.flex.flex-col.justify-center.p-5.items-center
+ [:div.flex.justify-center.py-2
+ [:div.flex.justify-center {:class "w-4/5"}
+ [:video.min-w-full.h-auto {:src stream-type :controls true}]]]
+ [:div.flex.text-white
+ [:button.border.rounded.border-slate-900.p-2.bg-slate-800
+ {:on-click #(rf/dispatch [:switch-to-global-player current-stream])}
+ "Add to global stream"]
+ [:a {:href (:url current-stream)}
+ "Open original source"]]
+ [:div.flex.flex-col.items-center.py-2 {:class "w-4/5"}
+ [:div.min-w-full.py-2
+ [:h1.text-xl.font-extrabold (:name current-stream)]]
+ [:div.min-w-full.py-2
+ [:p (:description current-stream)]]]]))