diff options
-rw-r--r-- | src/frontend/tau/views.cljs | 54 | ||||
-rw-r--r-- | src/frontend/tau/views/home.cljs | 7 | ||||
-rw-r--r-- | src/frontend/tau/views/player.cljs | 11 | ||||
-rw-r--r-- | src/frontend/tau/views/search.cljs | 38 | ||||
-rw-r--r-- | src/frontend/tau/views/stream.cljs | 27 |
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 "τ"}}]] + [: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)]]]])) |