From 8d216c6003cba9352af63fff69887c8d924967e0 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Fri, 29 Jan 2021 09:52:59 -0500 Subject: [PATCH 1/7] Move back button to a better position in game log --- src/cljs/nr/stats.cljs | 3 ++- src/css/base.styl | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/cljs/nr/stats.cljs b/src/cljs/nr/stats.cljs index 17a6d59f4b..029cccc577 100644 --- a/src/cljs/nr/stats.cljs +++ b/src/cljs/nr/stats.cljs @@ -46,6 +46,7 @@ (defn game-details [state] (let [game (:view-game @state)] [:div.games.panel + [:p.return-button [:button {:on-click #(swap! state dissoc :view-game)} "Return to stats screen"]] [:h4 (:title game) (when (:replay-shared game) " ⭐")] [:div [:div (str (tr [:stats.lobby "Lobby"]) ": " (capitalize (tr-lobby (:room game))))] @@ -56,7 +57,7 @@ [:div (str (tr [:stats.ended "Ended"]) ": " (:end-date game))] (when (:stats game) [build-game-stats (get-in game [:stats :corp]) (get-in game [:stats :runner])]) - [:p [:button {:on-click #(swap! state dissoc :view-game)} (tr [:stats.view-games "View games"])] + [:p (when (and (:replay game) (not (:replay-shared game))) [:button {:on-click #(share-replay state (:gameid game))} (tr [:stats.share "Share replay"])]) diff --git a/src/css/base.styl b/src/css/base.styl index c879997591..11c51cbec7 100644 --- a/src/css/base.styl +++ b/src/css/base.styl @@ -1333,6 +1333,9 @@ input.url display-flex() flex-direction(column) + .return-button + margin-bottom: 20px + .game-panel border-left: 1px solid white padding: 0 15px From 738afd2abe8a0aa436eedacfb9db08ef0c6f5a27 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Fri, 29 Jan 2021 13:17:14 -0500 Subject: [PATCH 2/7] Add date to log list --- src/cljs/nr/stats.cljs | 43 ++++++++++++++++++++++++------------------ src/css/base.styl | 13 +++++++++++++ 2 files changed, 38 insertions(+), 18 deletions(-) diff --git a/src/cljs/nr/stats.cljs b/src/cljs/nr/stats.cljs index 029cccc577..2383fb8c28 100644 --- a/src/cljs/nr/stats.cljs +++ b/src/cljs/nr/stats.cljs @@ -49,12 +49,13 @@ [:p.return-button [:button {:on-click #(swap! state dissoc :view-game)} "Return to stats screen"]] [:h4 (:title game) (when (:replay-shared game) " ⭐")] [:div - [:div (str (tr [:stats.lobby "Lobby"]) ": " (capitalize (tr-lobby (:room game))))] - [:div (str (tr [:stats.format "Format"]) ": " (capitalize (tr-format (:format game))))] - [:div (str (tr [:stats.winner "Winner"]) ": " (capitalize (tr-side (:winner game))))] - [:div (str (tr [:stats.win-method "Win method"]) ": " (:reason game))] - [:div (str (tr [:stats.started "Started"]) ": " (:start-date game))] - [:div (str (tr [:stats.ended "Ended"]) ": " (:end-date game))] + [:div.game-details-table + [:div (str (tr [:stats.lobby "Lobby"]) ": " (capitalize (tr-lobby (:room game))))] + [:div (str (tr [:stats.format "Format"]) ": " (capitalize (tr-format (:format game))))] + [:div (str (tr [:stats.winner "Winner"]) ": " (capitalize (tr-side (:winner game))))] + [:div (str (tr [:stats.win-method "Win method"]) ": " (:reason game))] + [:div (str (tr [:stats.started "Started"]) ": " (:start-date game))] + [:div (str (tr [:stats.ended "Ended"]) ": " (:end-date game))]] (when (:stats game) [build-game-stats (get-in game [:stats :corp]) (get-in game [:stats :runner])]) [:p @@ -62,10 +63,12 @@ (not (:replay-shared game))) [:button {:on-click #(share-replay state (:gameid game))} (tr [:stats.share "Share replay"])]) (if (:replay game) - [:a.button {:href (str "/profile/history/full/" (:gameid game)) :download (str (:title game) ".json")} (tr [:stats.download "Download replay"])] - (tr [:stats.unavailable "Replay unavailable"]))] - (when (:replay-shared game) - [:p [:input.share-link {:type "text" :read-only true :value (str (.-origin (.-location js/window)) "/play?" (:gameid game))}]])]])) + [:span + [:button "Launch Replay"] + [:a.button {:href (str "/profile/history/full/" (:gameid game)) :download (str (:title game) ".json")} (tr [:stats.download "Download replay"])] + (tr [:stats.unavailable "Replay unavailable"])])] + (when (:replay-shared game) + [:p [:input.share-link {:type "text" :read-only true :value (str (.-origin (.-location js/window)) "/play?" (:gameid game))}]])]])) (defn clear-user-stats [] (authenticated @@ -151,7 +154,7 @@ (swap! state assoc :view-game (assoc game :log json)))))) (defn game-row - [state {:keys [title corp runner turn winner reason replay-shared] :as game} log-scroll-top] + [state {:keys [title corp runner turn winner reason replay-shared start-date] :as game} log-scroll-top] (let [corp-id (first (filter #(= (:title %) (:identity corp)) @all-cards)) runner-id (first (filter #(= (:title %) (:identity runner)) @all-cards))] [:div.gameline {:style {:min-height "auto"}} @@ -160,10 +163,12 @@ (fetch-log state game) (reset! log-scroll-top 0))} (tr [:stats.view-log "View log"])] - [:h4 + [:h4.log-title {:title (when replay-shared "Replay shared")} title " (" (tr [:stats.turn-count] turn) ")" (when replay-shared " ⭐")] + [:div.log-date (-> start-date js/Date. js/moment (.format "dddd MMM Do - HH:mm"))] + [:div [:span.player [avatar (:player corp) {:opts {:size 24}}] @@ -186,21 +191,23 @@ :component-will-unmount #(store-scroll-top % list-scroll-top) :reagent-render (fn [state list-scroll-top log-scroll-top] - (let [games (reverse (:games @state))] + (let [rev-games (reverse (:games @state)) + games (if (:filter-replays @state) (filter #(:replay-shared %) rev-games) rev-games) + cnt (count games) + log-str (if (= cnt 1) "Log" "Logs")] [:div.game-list [:div.controls - [:button {:on-click #(swap! state update :filter-replays not)} + [:button {:on-click #(swap! state update :filter-replays not)} (if (:filter-replays @state) (tr [:stats.all-games "Show all games"]) (tr [:stats.shared-games "Only show shared"]))]] + [:span.log-count (str cnt " " log-str (when (:filter-replays @state) " (filtered)"))] (if (empty? games) [:h4 (tr [:stats.no-games "No games"])] (doall (for [game games] - (when (or (not (:filter-replays @state)) - (:replay-shared game)) - ^{:key (:gameid game)} - [game-row state game log-scroll-top]))))]))})) + ^{:key (:gameid game)} + [game-row state game log-scroll-top])))]))})) (defn right-panel [state list-scroll-top log-scroll-top] (if (:view-game @state) diff --git a/src/css/base.styl b/src/css/base.styl index 11c51cbec7..a6ffb233fb 100644 --- a/src/css/base.styl +++ b/src/css/base.styl @@ -1336,6 +1336,19 @@ input.url .return-button margin-bottom: 20px + .game-details-table + margin-bottom: 10px + + .log-title + margin-bottom: 0px + + .log-date + margin-bottom: 10px + + .log-count + font-weight: bold + margin-left: 8px + .game-panel border-left: 1px solid white padding: 0 15px From be84e589436aa19c837f2c1e40073dbdfca79221 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Fri, 29 Jan 2021 14:03:37 -0500 Subject: [PATCH 3/7] Add Launch Replay functionality --- src/cljs/nr/stats.cljs | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/cljs/nr/stats.cljs b/src/cljs/nr/stats.cljs index 2383fb8c28..518df0b96e 100644 --- a/src/cljs/nr/stats.cljs +++ b/src/cljs/nr/stats.cljs @@ -43,6 +43,11 @@ (swap! state assoc :view-game (assoc (:view-game @state) :replay-shared true)))))) +(defn- replay-link [game] + (str (.-origin (.-location js/window)) "/play?" (:gameid game))) + +(defn launch-replay [game] (set! (.-location js/window) (replay-link game))) + (defn game-details [state] (let [game (:view-game @state)] [:div.games.panel @@ -64,11 +69,11 @@ [:button {:on-click #(share-replay state (:gameid game))} (tr [:stats.share "Share replay"])]) (if (:replay game) [:span - [:button "Launch Replay"] + [:button {:on-click #(launch-replay game)} "Launch Replay"] [:a.button {:href (str "/profile/history/full/" (:gameid game)) :download (str (:title game) ".json")} (tr [:stats.download "Download replay"])] (tr [:stats.unavailable "Replay unavailable"])])] - (when (:replay-shared game) - [:p [:input.share-link {:type "text" :read-only true :value (str (.-origin (.-location js/window)) "/play?" (:gameid game))}]])]])) + (when (:replay-shared game) + [:p [:input.share-link {:type "text" :read-only true :value (replay-link game)}]])]])) (defn clear-user-stats [] (authenticated From 50ac6d7e176a24ae49a9b65445ff4e35ffae3688 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Fri, 29 Jan 2021 17:05:19 -0500 Subject: [PATCH 4/7] Added Open Graph headers for main jnet page --- src/clj/web/pages.clj | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/clj/web/pages.clj b/src/clj/web/pages.clj index db46934067..c7b9e93a1f 100644 --- a/src/clj/web/pages.clj +++ b/src/clj/web/pages.clj @@ -18,6 +18,12 @@ [:meta {:charset "utf-8"}] [:meta {:name "viewport" :content "width=device-width, initial-scale=0.6, minimal-ui"}] [:meta {:name "apple-mobile-web-app-capable" :content "yes"}] + [:meta {:property "og:type" :content "website"}] + [:meta {:property "og:url" :content "https://jinteki.net"}] + [:meta {:property "og:image" :content "https://www.jinteki.net/img/icons/jinteki_167.png"}] + [:meta {:property "og:title" :content "Play Android: Netrunner in your browser"}] + [:meta {:property "og:site_name" :content "jinteki.net"}] + [:meta {:property "og:description" :content "Build decks and test them online against other players."}] [:link {:rel "apple-touch-icon" :href "img/icons/jinteki_167.png"}] [:title "Jinteki"] (hiccup/include-css "/css/carousel.css") From 7708e07063afdebd66f705abe639f2f2893798a9 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Sat, 30 Jan 2021 11:48:32 -0500 Subject: [PATCH 5/7] Moved replays to /replay path --- project.clj | 2 +- src/clj/web/api.clj | 1 + src/clj/web/pages.clj | 101 +++++++++++++++++++------------------ src/clj/web/stats.clj | 26 +++++++++- src/cljs/nr/chat.cljs | 6 --- src/cljs/nr/gameboard.cljs | 4 +- src/cljs/nr/gamelobby.cljs | 30 +++++------ src/cljs/nr/main.cljs | 16 +++++- src/cljs/nr/stats.cljs | 2 +- 9 files changed, 111 insertions(+), 77 deletions(-) diff --git a/project.clj b/project.clj index e82a80469b..17df188bc1 100644 --- a/project.clj +++ b/project.clj @@ -95,7 +95,7 @@ :compiler {:output-to "resources/public/cljs/app10.js" :output-dir "resources/public/cljs" :main "dev.nr" - :asset-path "cljs" + :asset-path "/cljs" :optimizations :none :source-map-timestamp true :npm-deps false diff --git a/src/clj/web/api.clj b/src/clj/web/api.clj index 95dc1e6beb..a16799e9aa 100644 --- a/src/clj/web/api.clj +++ b/src/clj/web/api.clj @@ -47,6 +47,7 @@ (GET "/ws" req ws/handshake-handler) (POST "/ws" req ws/post-handler) + (GET "/replay/:gameid" [] stats/replay-handler) (GET "/*" [] pages/index-page)) (defroutes public-routes diff --git a/src/clj/web/pages.clj b/src/clj/web/pages.clj index c7b9e93a1f..c9ce900fe3 100644 --- a/src/clj/web/pages.clj +++ b/src/clj/web/pages.clj @@ -12,56 +12,59 @@ [web.config :refer [server-config frontend-version]] [web.utils :refer [response]])) -(defn index-page [{:keys [user] :as req} & content] - (hiccup/html5 - [:head - [:meta {:charset "utf-8"}] - [:meta {:name "viewport" :content "width=device-width, initial-scale=0.6, minimal-ui"}] - [:meta {:name "apple-mobile-web-app-capable" :content "yes"}] - [:meta {:property "og:type" :content "website"}] - [:meta {:property "og:url" :content "https://jinteki.net"}] - [:meta {:property "og:image" :content "https://www.jinteki.net/img/icons/jinteki_167.png"}] - [:meta {:property "og:title" :content "Play Android: Netrunner in your browser"}] - [:meta {:property "og:site_name" :content "jinteki.net"}] - [:meta {:property "og:description" :content "Build decks and test them online against other players."}] - [:link {:rel "apple-touch-icon" :href "img/icons/jinteki_167.png"}] - [:title "Jinteki"] - (hiccup/include-css "/css/carousel.css") - (hiccup/include-css (str "/css/netrunner.css?v=" @frontend-version)) - (hiccup/include-css "/lib/toastr/toastr.min.css") - (hiccup/include-css "/lib/jqueryui/themes/base/jquery-ui.min.css")] - [:body - [:div {:style {:display "hidden"} - :id "server-originated-data" - :data-version @frontend-version}] - [:div#main-content] - [:audio#ting - [:source {:src "/sound/ting.mp3" :type "audio/mp3"}] - [:source {:src "/sound/ting.ogg" :type "audio/ogg"}]] - (hiccup/include-js "/lib/jquery/jquery.min.js") - (hiccup/include-js "/lib/jqueryui/jquery-ui.min.js") - (hiccup/include-js "/lib/bootstrap/dist/js/bootstrap.js") - (hiccup/include-js "/lib/moment/min/moment.min.js") - (hiccup/include-js "/lib/toastr/toastr.min.js") - (hiccup/include-js "/lib/howler/dist/howler.min.js") - (when user - [:div#sente-csrf-token {:data-csrf-token anti-forgery/*anti-forgery-token*}]) - [:script {:type "text/javascript"} - (str "var user=" (json/generate-string user) ";")] +(defn index-page + ([req] (index-page req nil nil)) + ([{:keys [user] :as req} og replay-id] + (hiccup/html5 + [:head + [:meta {:charset "utf-8"}] + [:meta {:name "viewport" :content "width=device-width, initial-scale=0.6, minimal-ui"}] + [:meta {:name "apple-mobile-web-app-capable" :content "yes"}] + [:meta {:property "og:type" :content (:type og "website")}] + [:meta {:property "og:url" :content (:url og "https://jinteki.net")}] + [:meta {:property "og:image" :content (:image og "https://www.jinteki.net/img/icons/jinteki_167.png")}] + [:meta {:property "og:title" :content (:title og "Play Android: Netrunner in your browser")}] + [:meta {:property "og:site_name" :content (:site_name og "jinteki.net")}] + [:meta {:property "og:description" :content (:description og "Build Netrunner decks and test them online against other players.")}] + [:link {:rel "apple-touch-icon" :href "/img/icons/jinteki_167.png"}] + [:title "Jinteki"] + (hiccup/include-css "/css/carousel.css") + (hiccup/include-css (str "/css/netrunner.css?v=" @frontend-version)) + (hiccup/include-css "/lib/toastr/toastr.min.css") + (hiccup/include-css "/lib/jqueryui/themes/base/jquery-ui.min.css")] + [:body + [:div {:style {:display "hidden"} + :id "server-originated-data" + :data-version @frontend-version + :data-replay-id replay-id}] + [:div#main-content] + [:audio#ting + [:source {:src "/sound/ting.mp3" :type "audio/mp3"}] + [:source {:src "/sound/ting.ogg" :type "audio/ogg"}]] + (hiccup/include-js "/lib/jquery/jquery.min.js") + (hiccup/include-js "/lib/jqueryui/jquery-ui.min.js") + (hiccup/include-js "/lib/bootstrap/dist/js/bootstrap.js") + (hiccup/include-js "/lib/moment/min/moment.min.js") + (hiccup/include-js "/lib/toastr/toastr.min.js") + (hiccup/include-js "/lib/howler/dist/howler.min.js") + (when user + [:div#sente-csrf-token {:data-csrf-token anti-forgery/*anti-forgery-token*}]) + [:script {:type "text/javascript"} + (str "var user=" (json/generate-string user) ";")] - (if (= "dev" @web.config/server-mode) - (list (hiccup/include-js "/cljs/goog/base.js") - (hiccup/include-js (str "cljs/app10.js?v=" @frontend-version)) - [:script - (for [req ["dev.figwheel"]] - (str "goog.require(\"" req "\");"))]) - (list (hiccup/include-js (str "js/app10.js?v=" @frontend-version)) - [:script - "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - ga('create', 'UA-20250150-2', 'www.jinteki.net');" - (when user - (str "ga('set', '&uid', '" (:username user) "');")) - "ga('send', 'pageview');"]))])) + (if (= "dev" @web.config/server-mode) + (list (hiccup/include-js "/cljs/goog/base.js") + (hiccup/include-js (str "/cljs/app10.js?v=" @frontend-version)) + [:script + (for [req ["dev.figwheel"]] + (str "goog.require(\"" req "\");"))]) + (list (hiccup/include-js (str "/js/app10.js?v=" @frontend-version)) + [:script + "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)})(window,document,'script','//www.google-analytics.com/analytics.js','ga'); + ga('create', 'UA-20250150-2', 'www.jinteki.net');" + (when user + (str "ga('set', '&uid', '" (:username user) "');")) + "ga('send', 'pageview');"]))]))) (defn reset-password-page [{{:keys [token]} :params}] diff --git a/src/clj/web/stats.clj b/src/clj/web/stats.clj index 56fe14038a..86a64c5fba 100644 --- a/src/clj/web/stats.clj +++ b/src/clj/web/stats.clj @@ -4,13 +4,16 @@ [monger.result :refer [acknowledged?]] [monger.operators :refer :all] [monger.query :as mq] + [web.pages :as pages] [web.ws :as ws] [web.utils :refer [response json-response]] [game.utils :refer [dissoc-in]] [clojure.set :refer [rename-keys]] [clojure.string :refer [lower-case]] [clj-time.core :as t] - [cheshire.core :as json]) + [cheshire.core :as json] + [hiccup.page :as hiccup] + [ring.util.response :refer [redirect]]) (:import org.bson.types.ObjectId)) @@ -250,3 +253,24 @@ (println "Caught exception sharing game: " (.getMessage e)) (response 500 {:message "Server error"})))) (response 401 {:message "Unauthorized"}))) + +(defn replay-handler [{{:keys [gameid n d]} :params + scheme :scheme + headers :headers + :as req}] + ;; gameid could have additional offsets into the replay encoded (ie. n=8&d=1) + (let [{:keys [replay winner corp runner title]} (mc/find-one-as-map db :game-logs {:gameid gameid} ["replay"]) + replay (or replay {}) + gameid-str (if (and n d) (str gameid "?n=" n "&d=" d) gameid)] + (if (empty? replay) + (response 404 {:message "Replay not found"}) + (let [corp-user (get-in [:player :username] corp) + runner-user (get-in [:player :username] runner) + title (str "REPLAY: " corp-user " vs " runner-user) + og {:type "website" + :url "https://jinteki.net" + ;; :image nil + :title title + :site_name "jinteki.net" + :description "more test"}] + (pages/index-page req og gameid-str))))) diff --git a/src/cljs/nr/chat.cljs b/src/cljs/nr/chat.cljs index af6d90ce9d..536ff39143 100644 --- a/src/cljs/nr/chat.cljs +++ b/src/cljs/nr/chat.cljs @@ -290,12 +290,6 @@ [:div [msg-input-view (:channel @s)]])]]])}))) -(defn get-data - [tag] - (-> (.getElementById js/document "server-originated-data") - (.getAttribute (str "data-" tag)) - (cljs.reader/read-string))) - (defn chat-page [] (let [active (r/cursor app-state [:active-page]) s (r/atom {:channel :general diff --git a/src/cljs/nr/gameboard.cljs b/src/cljs/nr/gameboard.cljs index e2e7188aa1..da956827b5 100644 --- a/src/cljs/nr/gameboard.cljs +++ b/src/cljs/nr/gameboard.cljs @@ -51,7 +51,7 @@ (let [n (:n @replay-status) d (- (count (get-in @replay-timeline [n :diffs])) (count (:diffs @replay-status)))] - (str origin "/play?" (:gameid @game-state) "&n=" n "&d=" d))) + (str origin "/replay/" (:gameid @game-state) "?n=" n "&d=" d))) (defn set-replay-side [side] (reset! replay-side side) @@ -2222,4 +2222,4 @@ [:button {:on-click #(swap! show-replay-link not)} "Share"]) (when-not (= "replay" (:gameid @game-state)) [:input {:style (if @show-replay-link {:display "block"} {:display "none"}) - :type "text" :value (generate-replay-link (.-origin (.-location js/window)))}])]]])])))}))))) + :type "text" :read-only true :value (generate-replay-link (.-origin (.-location js/window)))}])]]])])))}))))) diff --git a/src/cljs/nr/gamelobby.cljs b/src/cljs/nr/gamelobby.cljs index b9595fd898..ed56511d1a 100644 --- a/src/cljs/nr/gamelobby.cljs +++ b/src/cljs/nr/gamelobby.cljs @@ -362,21 +362,21 @@ (defn games-list-panel [s games gameid password-gameid user] [:div.games - (let [params (.-search (.-location js/window))] - (when (not-empty params) - (let [id-match (re-find #"([0-9a-f\-]+)" params) - n-match (re-find #"n=(\d+)" params) - d-match (re-find #"d=(\d+)" params) - replay-id (nth id-match 1) - n (when n-match (js/parseInt (nth n-match 1))) - d (when d-match (js/parseInt (nth d-match 1)))] - (when replay-id - (.replaceState (.-history js/window) {} "" "/play") ; remove GET parameters from url - (if (and n d) - (start-shared-replay s replay-id {:n n :d d}) - (start-shared-replay s replay-id)) - (resume-sound) - nil)))) + (when-let [params (:replay-id @app-state)] + (swap! app-state dissoc :replay-id) + (let [id-match (re-find #"([0-9a-f\-]+)" params) + n-match (re-find #"n=(\d+)" params) + d-match (re-find #"d=(\d+)" params) + replay-id (nth id-match 1) + n (when n-match (js/parseInt (nth n-match 1))) + d (when d-match (js/parseInt (nth d-match 1)))] + (when replay-id + (.replaceState (.-history js/window) {} "" "/play") ; remove query parameters from url + (if (and n d) + (start-shared-replay s replay-id {:n n :d d}) + (start-shared-replay s replay-id)) + (resume-sound) + nil))) [:div.button-bar [:div.rooms [room-tab user s games "tournament" (tr [:lobby.tournament "Tournament"])] diff --git a/src/cljs/nr/main.cljs b/src/cljs/nr/main.cljs index 8cc2de3c97..f61c6264fa 100644 --- a/src/cljs/nr/main.cljs +++ b/src/cljs/nr/main.cljs @@ -9,7 +9,7 @@ [nr.gameboard :refer [concede gameboard game-state mute-spectators stack-servers flip-runner-board set-replay-side]] [nr.gamelobby :refer [filter-blocked-games game-lobby leave-game]] [nr.help :refer [help]] - [nr.history :refer [navigate-to-current]] + [nr.history :refer [navigate-to-current navigate]] [nr.navbar :refer [navbar]] [nr.player-view :refer [player-view]] [nr.stats :refer [stats]] @@ -72,12 +72,24 @@ ^{:key (get-in p [:user :_id])} [player-view p game])]]))))])) +(defn- get-server-data + [tag] + (-> (.getElementById js/document "server-originated-data") + (.getAttribute (str "data-" tag)))) + (defn pages [] (r/create-class {:display-name "main-pages" :component-did-mount - (fn [] (navigate-to-current)) + (fn [] + (let [ver (get-server-data "version") + rid (get-server-data "replay-id")] + (swap! app-state assoc :app-version ver) + (swap! app-state assoc :replay-id rid) + (if rid + (navigate "/play") + (navigate-to-current)))) :reagent-render (fn [] diff --git a/src/cljs/nr/stats.cljs b/src/cljs/nr/stats.cljs index 518df0b96e..820ea75c63 100644 --- a/src/cljs/nr/stats.cljs +++ b/src/cljs/nr/stats.cljs @@ -44,7 +44,7 @@ (assoc (:view-game @state) :replay-shared true)))))) (defn- replay-link [game] - (str (.-origin (.-location js/window)) "/play?" (:gameid game))) + (str (.-origin (.-location js/window)) "/replay/" (:gameid game))) (defn launch-replay [game] (set! (.-location js/window) (replay-link game))) From 9db50027a9c27fda2b73534156e14194c21a0aec Mon Sep 17 00:00:00 2001 From: John Warwick Date: Sat, 30 Jan 2021 14:35:18 -0500 Subject: [PATCH 6/7] Added Open Graph headers for replays --- src/clj/web/stats.clj | 30 ++++++++++++++++++++---------- src/cljs/nr/stats.cljs | 8 ++++---- 2 files changed, 24 insertions(+), 14 deletions(-) diff --git a/src/clj/web/stats.clj b/src/clj/web/stats.clj index 86a64c5fba..5c7f082737 100644 --- a/src/clj/web/stats.clj +++ b/src/clj/web/stats.clj @@ -8,12 +8,13 @@ [web.ws :as ws] [web.utils :refer [response json-response]] [game.utils :refer [dissoc-in]] + [jinteki.cards :refer [all-cards]] [clojure.set :refer [rename-keys]] [clojure.string :refer [lower-case]] [clj-time.core :as t] [cheshire.core :as json] [hiccup.page :as hiccup] - [ring.util.response :refer [redirect]]) + [ring.util.request :refer [request-url]]) (:import org.bson.types.ObjectId)) @@ -254,23 +255,32 @@ (response 500 {:message "Server error"})))) (response 401 {:message "Unauthorized"}))) +(defn- get-winner-card + [winner corp runner host] + (let [win-id (:identity ((keyword winner) {:corp corp :runner runner})) + win-card (:code (@all-cards win-id))] + (if win-card + (str host "img/cards/" win-card ".png") + (str host "img/icons/jinteki_167.png")))) + (defn replay-handler [{{:keys [gameid n d]} :params scheme :scheme headers :headers :as req}] - ;; gameid could have additional offsets into the replay encoded (ie. n=8&d=1) - (let [{:keys [replay winner corp runner title]} (mc/find-one-as-map db :game-logs {:gameid gameid} ["replay"]) + (let [{:keys [replay winner corp runner title]} (mc/find-one-as-map db :game-logs {:gameid gameid}) replay (or replay {}) gameid-str (if (and n d) (str gameid "?n=" n "&d=" d) gameid)] (if (empty? replay) (response 404 {:message "Replay not found"}) - (let [corp-user (get-in [:player :username] corp) - runner-user (get-in [:player :username] runner) - title (str "REPLAY: " corp-user " vs " runner-user) + (let [corp-user (get-in corp [:player :username] "Unknown") + corp-id (:identity corp) + runner-user (get-in runner [:player :username] "Unknown") + runner-id (:identity runner) + host (str (name scheme) "://" (get headers "host") "/") og {:type "website" - :url "https://jinteki.net" - ;; :image nil - :title title + :url (request-url req) + :image (get-winner-card winner corp runner host) + :title (str "REPLAY: " title) :site_name "jinteki.net" - :description "more test"}] + :description (str corp-user " (" corp-id ") vs. " runner-user " (" runner-id ")")}] (pages/index-page req og gameid-str))))) diff --git a/src/cljs/nr/stats.cljs b/src/cljs/nr/stats.cljs index 820ea75c63..10f7f13259 100644 --- a/src/cljs/nr/stats.cljs +++ b/src/cljs/nr/stats.cljs @@ -17,11 +17,11 @@ (def state (r/atom {:games nil})) (defn- fetch-game-history [] - (go (let [{:keys [status json]} ( Date: Mon, 1 Feb 2021 10:29:18 -0500 Subject: [PATCH 7/7] Cleanup --- src/cljs/nr/chat.cljs | 2 +- src/cljs/nr/stats.cljs | 16 ++++++++-------- src/cljs/nr/translations.cljs | 10 ++++++++-- src/css/base.styl | 4 ---- 4 files changed, 17 insertions(+), 15 deletions(-) diff --git a/src/cljs/nr/chat.cljs b/src/cljs/nr/chat.cljs index 536ff39143..99c2a81185 100644 --- a/src/cljs/nr/chat.cljs +++ b/src/cljs/nr/chat.cljs @@ -309,4 +309,4 @@ [:h1 (tr [:chat.title "Play Android: Netrunner in your browser"])] [news] [chat s old scroll-top] - [:div#version [:span (str "Version " (get-data "version"))]]])))) + [:div#version [:span (str "Version " (:app-version @app-state "Unknown"))]]])))) diff --git a/src/cljs/nr/stats.cljs b/src/cljs/nr/stats.cljs index 10f7f13259..5844fc8d70 100644 --- a/src/cljs/nr/stats.cljs +++ b/src/cljs/nr/stats.cljs @@ -51,7 +51,7 @@ (defn game-details [state] (let [game (:view-game @state)] [:div.games.panel - [:p.return-button [:button {:on-click #(swap! state dissoc :view-game)} "Return to stats screen"]] + [:p.return-button [:button {:on-click #(swap! state dissoc :view-game)} (tr [:stats.view-games "Return to stats screen"])]] [:h4 (:title game) (when (:replay-shared game) " ⭐")] [:div [:div.game-details-table @@ -69,9 +69,9 @@ [:button {:on-click #(share-replay state (:gameid game))} (tr [:stats.share "Share replay"])]) (if (:replay game) [:span - [:button {:on-click #(launch-replay game)} "Launch Replay"] - [:a.button {:href (str "/profile/history/full/" (:gameid game)) :download (str (:title game) ".json")} (tr [:stats.download "Download replay"])] - (tr [:stats.unavailable "Replay unavailable"])])] + [:button {:on-click #(launch-replay game)} (tr [:stats.launch "Launch Replay"])] + [:a.button {:href (str "/profile/history/full/" (:gameid game)) :download (str (:title game) ".json")} (tr [:stats.download "Download replay"])]] + (tr [:stats.unavailable "Replay unavailable"]))] (when (:replay-shared game) [:p [:input.share-link {:type "text" :read-only true :value (replay-link game)}]])]])) @@ -198,15 +198,15 @@ (fn [state list-scroll-top log-scroll-top] (let [rev-games (reverse (:games @state)) games (if (:filter-replays @state) (filter #(:replay-shared %) rev-games) rev-games) - cnt (count games) - log-str (if (= cnt 1) "Log" "Logs")] + cnt (count games)] [:div.game-list [:div.controls [:button {:on-click #(swap! state update :filter-replays not)} (if (:filter-replays @state) (tr [:stats.all-games "Show all games"]) - (tr [:stats.shared-games "Only show shared"]))]] - [:span.log-count (str cnt " " log-str (when (:filter-replays @state) " (filtered)"))] + (tr [:stats.shared-games "Only show shared"]))] + [:span.log-count (str (tr [:stats.log-count] cnt) (when (:filter-replays @state) + (str " " (tr [:stats.filtered "(filtered)"]))))]] (if (empty? games) [:h4 (tr [:stats.no-games "No games"])] (doall diff --git a/src/cljs/nr/translations.cljs b/src/cljs/nr/translations.cljs index e08620e9a5..4d5803f4ed 100644 --- a/src/cljs/nr/translations.cljs +++ b/src/cljs/nr/translations.cljs @@ -281,10 +281,13 @@ :lobby "Lobby" :format "Format" :win-method "Win method" - :view-games "View games" + :view-games "Return to stats screen" :share "Share replay" + :launch "Launch Replay" :download "Download replay" :unavailable "Replay unavailable" + :filtered "(filtered)" + :log-count (fn [[cnt]] (str cnt " Log" (when (not= cnt 1) "s"))) :clicks-gained "Clicks Gained" :credits-gained "Credits Gained" :credits-spent "Credits Spent" @@ -667,10 +670,13 @@ :lobby "Obbylay" :format "Ormatfay" :win-method "Inway ethodmay" - :view-games "Iewvay amesgay" + :view-games "Eturnray otay atsstay eenscray" :share "Areshay eplayray" + :launch "Aunchlay Eplayray" :download "Ownloadday eplayray" :unavailable "Eplayray unavailableyay" + :filtered "(ilteredfay)" + :log-count (fn [[cnt]] (str cnt " Oglay" (when (not= cnt 1) "s"))) :clicks-gained "Icksclay Ainedgay" :credits-gained "Editscray Ainedgay" :credits-spent "Editscray Entspay" diff --git a/src/css/base.styl b/src/css/base.styl index a6ffb233fb..6f1f0027d1 100644 --- a/src/css/base.styl +++ b/src/css/base.styl @@ -925,9 +925,6 @@ nav ul .heading, .type font-weight: bold - .card-body - padding-top: 20px - .pack font-style: italic margin-top: 8px @@ -1040,7 +1037,6 @@ nav ul .text position: absolute - bottom: 10px left: 10px right: 10px height: 245px