From: Benjamin Auder Date: Fri, 6 Mar 2020 16:49:38 +0000 (+0100) Subject: Improve style, implement 'next' for corr games. TODO: rematch logic X-Git-Url: https://git.auder.net/js/current/app_dev.php/index.css?a=commitdiff_plain;h=feaf1bf73fa8c6054e353585dee0b8a4fdcfbc4e;p=vchess.git Improve style, implement 'next' for corr games. TODO: rematch logic --- diff --git a/TODO b/TODO index b5142264..49091c12 100644 --- a/TODO +++ b/TODO @@ -9,7 +9,6 @@ From MyGames page: send "mconnect" to all online players (me included: potential # Misc: Rematch button (change colors, re-apply randomness params (which should be saved somehow somewhere)) --> need a bit more duplicated logic: in Game page, listen for newgame, and add a "launchGame" function -Next button in corr game (only if accessed from "MyGames" tab, by giving list of gids) # New variants 8-pieces https://www.youtube.com/watch?v=XZ8K02Da7Ps&list=PLRyjH8DPuzTBiym6lA0r84P8N0HnTtZyN&index=6&t=0s diff --git a/client/public/images/icons/SOURCE b/client/public/images/icons/SOURCE index ee8510e7..b1c82815 100644 --- a/client/public/images/icons/SOURCE +++ b/client/public/images/icons/SOURCE @@ -2,7 +2,13 @@ https://www.onlinewebfonts.com/icon/519460 https://www.onlinewebfonts.com/icon/322704 https://www.flaticon.com/free-icon/play_254434?term=play&page=1&position=1 https://www.flaticon.com/free-icon/fast-forward_660276?term=fast%20forward&page=1&position=7 - -# Unused for now: +https://www.flaticon.com/free-icon/comment_1380338?term=chat&page=1&position=3 +https://www.flaticon.com/free-icon/flags_455582?term=flag&page=1&position=49 +https://www.flaticon.com/free-icon/microscope_482743?term=microscope&page=1&position=10 +https://www.flaticon.com/free-icon/hand_1612618?term=hand&page=1&position=34 +https://www.onlinewebfonts.com/icon/256756 +https://www.flaticon.com/free-icon/forward_2413353?term=forward&page=1&position=59 +https://www.flaticon.com/free-icon/right_565870?term=forward&page=1&position=31 +https://www.flaticon.com/free-icon/download_724933?term=download&page=1&position=3 https://www.flaticon.com/free-icon/resize_512182?term=resize&page=1&position=49 -https://www.flaticon.com/free-icon/undo_725004?term=undo&page=1&position=4 +https://www.flaticon.com/free-icon/clear_565313?term=delete&page=1&position=33 diff --git a/client/public/images/icons/abort.svg b/client/public/images/icons/abort.svg new file mode 100644 index 00000000..44b52a58 --- /dev/null +++ b/client/public/images/icons/abort.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/client/public/images/icons/analyse.svg b/client/public/images/icons/analyse.svg new file mode 100644 index 00000000..29804c40 --- /dev/null +++ b/client/public/images/icons/analyse.svg @@ -0,0 +1,115 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/public/images/icons/chat.svg b/client/public/images/icons/chat.svg new file mode 100644 index 00000000..63050012 --- /dev/null +++ b/client/public/images/icons/chat.svg @@ -0,0 +1,65 @@ + + + + + + image/svg+xml + + + + + + + + + + + + diff --git a/client/public/images/icons/download.svg b/client/public/images/icons/download.svg new file mode 100644 index 00000000..834f6834 --- /dev/null +++ b/client/public/images/icons/download.svg @@ -0,0 +1,126 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/public/images/icons/draw.svg b/client/public/images/icons/draw.svg new file mode 100644 index 00000000..1a9f98ee --- /dev/null +++ b/client/public/images/icons/draw.svg @@ -0,0 +1,56 @@ + + + + + + image/svg+xml + + + + + + + + + diff --git a/client/public/images/icons/fast-forward.svg b/client/public/images/icons/fast-forward.svg index 411b157c..ee79c23b 100644 --- a/client/public/images/icons/fast-forward.svg +++ b/client/public/images/icons/fast-forward.svg @@ -1,44 +1,56 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + image/svg+xml + + + + + + + + + diff --git a/client/public/images/icons/fast-forward_rev.svg b/client/public/images/icons/fast-forward_rev.svg index 6d4728d1..41bc9f7f 100644 --- a/client/public/images/icons/fast-forward_rev.svg +++ b/client/public/images/icons/fast-forward_rev.svg @@ -1,6 +1,4 @@ - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file + inkscape:version="0.92.4 5da689c313, 2019-01-14"> + + + + image/svg+xml + + + + + + + + + diff --git a/client/public/images/icons/flip.svg b/client/public/images/icons/flip.svg index be39895c..bea39cbb 100644 --- a/client/public/images/icons/flip.svg +++ b/client/public/images/icons/flip.svg @@ -1,7 +1,54 @@ - - - - - Svg Vector Icons : http://www.onlinewebfonts.com/icon - + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon image/svg+xml + \ No newline at end of file diff --git a/client/public/images/icons/play.svg b/client/public/images/icons/play.svg index d34a3680..0d72fcc2 100644 --- a/client/public/images/icons/play.svg +++ b/client/public/images/icons/play.svg @@ -1,10 +1,99 @@ - - - - - - - + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/public/images/icons/play_rev.svg b/client/public/images/icons/play_rev.svg index 8d562e90..50f2ef8c 100644 --- a/client/public/images/icons/play_rev.svg +++ b/client/public/images/icons/play_rev.svg @@ -10,18 +10,18 @@ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" version="1.1" - id="Layer_1" + id="Capa_1" x="0px" y="0px" - viewBox="0 0 494.148 494.148" - style="enable-background:new 0 0 494.148 494.148;" + viewBox="0 0 256 256" + style="enable-background:new 0 0 256 256;" xml:space="preserve" sodipodi:docname="play_rev.svg" inkscape:version="0.92.4 5da689c313, 2019-01-14">image/svg+xml - - + inkscape:current-layer="Capa_1" /> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/public/images/icons/rematch.svg b/client/public/images/icons/rematch.svg new file mode 100644 index 00000000..37b2d8c6 --- /dev/null +++ b/client/public/images/icons/rematch.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/client/public/images/icons/resign.svg b/client/public/images/icons/resign.svg new file mode 100644 index 00000000..fcee08dd --- /dev/null +++ b/client/public/images/icons/resign.svg @@ -0,0 +1,115 @@ + + + +image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/client/public/images/icons/settings.svg b/client/public/images/icons/settings.svg index d7839216..37a724cb 100644 --- a/client/public/images/icons/settings.svg +++ b/client/public/images/icons/settings.svg @@ -1,7 +1,51 @@ - - - - - Svg Vector Icons : http://www.onlinewebfonts.com/icon - + + + + + Svg Vector Icons : http://www.onlinewebfonts.com/icon image/svg+xml + \ No newline at end of file diff --git a/client/public/images/icons/undo.svg b/client/public/images/icons/undo.svg deleted file mode 100644 index 3ab78b89..00000000 --- a/client/public/images/icons/undo.svg +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - diff --git a/client/src/components/BaseGame.vue b/client/src/components/BaseGame.vue index 5c556563..ac8b3236 100644 --- a/client/src/components/BaseGame.vue +++ b/client/src/components/BaseGame.vue @@ -33,29 +33,19 @@ div#baseGame img.inline(src="/images/icons/play.svg") button(@click="gotoEnd()") img.inline(src="/images/icons/fast-forward.svg") - #belowControls - #downloadDiv(v-if="allowDownloadPGN") - a#download(href="#") - button(@click="download()") {{ st.tr["Download"] }} PGN - button( - v-if="canAnalyze" - @click="analyzePosition()" - ) - | {{ st.tr["Analyse"] }} - // NOTE: variants pages already have a "Rules" link on top - button( - v-if="!$route.path.match('/variants/')" - @click="showRules()" - ) - | {{ st.tr["Rules"] }} #movesList MoveList( :show="showMoves" + :canAnalyze="canAnalyze" + :canDownload="allowDownloadPGN" :score="game.score" :message="game.scoreMsg" :firstNum="firstMoveNumber" :moves="moves" :cursor="cursor" + @download="download" + @showrules="showRules" + @analyze="analyzePosition" @goto-move="gotoMove" ) .clearer @@ -535,29 +525,19 @@ export default { display: inline-block width: 20% margin: 0 - img.inline - height: 24px - padding-top: 5px - @media screen and (max-width: 767px) - img.inline - height: 18px + padding-top: 5px + padding-bottom: 5px + +img.inline + height: 24px + padding-top: 5px + @media screen and (max-width: 767px) + height: 18px #turnIndicator text-align: center font-weight: bold -#belowControls - border-top: 1px solid #2f4f4f - text-align: center - margin: 0 auto - & > #downloadDiv - margin: 0 - & > button - margin: 0 - & > button - border-left: 1px solid #2f4f4f - margin: 0 - #boardContainer float: left // TODO: later, maybe, allow movesList of variable width diff --git a/client/src/components/MoveList.vue b/client/src/components/MoveList.vue index c0a15dff..6f7b4dce 100644 --- a/client/src/components/MoveList.vue +++ b/client/src/components/MoveList.vue @@ -15,12 +15,34 @@ div value="50" @input="adjustBoard()" ) - div#boardSizeBtnContainer - button#boardSizeBtn(onClick="window.doClick('modalAdjust')") - | {{ st.tr["Set board size"] }} + #aboveMoves + // NOTE: variants pages already have a "Rules" link on top + span#rulesBtn( + v-if="!$route.path.match('/variants/')" + @click="$emit('showrules')" + ) + | {{ st.tr["Rules"] }} + button.tooltip( + onClick="window.doClick('modalAdjust')" + :aria-label="st.tr['Resize board']" + ) + img.inline(src="/images/icons/resize.svg") + #downloadDiv(v-if="canDownload") + a#download(href="#") + button.tooltip( + @click="$emit('download')" + :aria-label="st.tr['Download'] + ' PGN'" + ) + img.inline(src="/images/icons/download.svg") + button.tooltip( + v-if="canAnalyze" + @click="$emit('analyze')" + :aria-label="st.tr['Analyse']" + ) + img.inline(src="/images/icons/analyse.svg") #scoreInfo(v-if="score!='*'") - p {{ score }} - p {{ st.tr[message] }} + span.score {{ score }} + span.score-msg {{ st.tr[message] }} .moves-list(v-if="!['none','highlight'].includes(show)") .tr(v-for="moveIdx in evenNumbers") .td {{ firstNum + moveIdx / 2 + 1 }} @@ -43,7 +65,9 @@ import { getFullNotation } from "@/utils/notation"; import { processModalClick } from "@/utils/modalClick"; export default { name: "my-move-list", - props: ["moves", "show", "cursor", "score", "message", "firstNum"], + props: [ + "moves", "show", "canAnalyze", "canDownload", + "cursor", "score", "message", "firstNum"], data: function() { return { st: store.state @@ -156,9 +180,34 @@ export default { width: 100% text-align: center -button#boardSizeBtn - margin: 0 - [type="checkbox"]#modalAdjust+div .card padding: 5px + +img.inline + height: 24px + @media screen and (max-width: 767px) + height: 18px + +span.score + display: inline-block + margin-left: 10px + font-weight: bold + +span.score-msg + display: inline-block + margin-left: 10px + font-style: italic + +#downloadDiv + display: inline-block + margin: 0 + +span#rulesBtn + cursor: pointer + display: inline-block + margin: 0 10px + font-weight: bold + +button + margin: 0 diff --git a/client/src/translations/en.js b/client/src/translations/en.js index e16a6a3a..6676ad89 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -70,7 +70,8 @@ export const translations = { "My problems": "My problems", "Name: alphanumerics, hyphen and underscore": "Name: alphanumerics, hyphen and underscore", "Name or Email": "Name or Email", - Next: "Next", + Next_p: "Next", + Next_g: "Next", "New connexion detected: tab now offline": "New connexion detected: tab now offline", "New correspondance game:": "New correspondance game:", "New game": "New game", @@ -102,15 +103,16 @@ export const translations = { Refuse: "Refuse", Register: "Register", "Registration complete! Please check your emails now": "Registration complete! Please check your emails now", + Rematch: "Rematch", "Remove game?": "Remove game?", Resign: "Resign", "Resign the game?": "Resign the game?", + "Resize board": "Resize board", Result: "Result", Rules: "Rules", Send: "Send", "Self-challenge is forbidden": "Self-challenge is forbidden", "Send challenge": "Send challenge", - "Set board size": "Set board size", Settings: "Settings", "Show possible moves?": "Show possible moves?", "Show solution": "Show solution", diff --git a/client/src/translations/es.js b/client/src/translations/es.js index 38d90227..c5ee0935 100644 --- a/client/src/translations/es.js +++ b/client/src/translations/es.js @@ -70,7 +70,8 @@ export const translations = { "My problems": "Mis problemas", "Name: alphanumerics, hyphen and underscore": "Nombre: alfanuméricos, guión y underscore", "Name or Email": "Nombre o Email", - Next: "Próximo", + Next_p: "Siguiente", + Next_g: "Siguiente", "New connexion detected: tab now offline": "Nueva conexión detectada: pestaña ahora desconectada", "New correspondance game:": "Nueva partida por correspondencia:", "New game": "Nueva partida", @@ -102,15 +103,16 @@ export const translations = { Refuse: "Rechazar", Register: "Registrarse", "Registration complete! Please check your emails now": "¡Registro completo! Revise sus correos electrónicos ahora", + Rematch: "Revancha", "Remove game?": "¿Eliminar la partida?", Resign: "Abandonar", "Resign the game?": "¿Abandonar la partida?", + "Resize board": "Redimensionar el tablero", Result: "Resultado", Rules: "Reglas", Send: "Enviar", "Self-challenge is forbidden": "Auto desafío está prohibido", "Send challenge": "Enviar desafío", - "Set board size": "Ajustar el tamaño del tablero", Settings: "Configuraciones", "Show possible moves?": "¿Mostrar posibles movimientos?", "Show solution": "Mostrar la solución", diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index 4460097b..270f604c 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -70,7 +70,8 @@ export const translations = { "My problems": "Mes problèmes", "Name: alphanumerics, hyphen and underscore": "Nom: alphanumériques, tiret et underscore", "Name or Email": "Nom ou Email", - Next: "Suivant", + Next_p: "Suivant", + Next_g: "Suivante", "New connexion detected: tab now offline": "Nouvelle connexion détectée : onglet désormais hors ligne", "New correspondance game:": "Nouvelle partie par corespondance :", "New game": "Nouvelle partie", @@ -102,15 +103,16 @@ export const translations = { Refuse: "Refuser", Register: "S'enregistrer", "Registration complete! Please check your emails now": "Enregistrement terminé ! Allez voir vos emails maintenant", + Rematch: "Rejouer", "Remove game?": "Supprimer la partie ?", Resign: "Abandonner", "Resign the game?": "Abandonner la partie ?", + "Resize board": "Redimensionner l'échiquier", Result: "Résultat", Rules: "Règles", Send: "Envoyer", "Self-challenge is forbidden": "Interdit de s'auto-défier", "Send challenge": "Envoyer défi", - "Set board size": "Régler la taille de l'échiquier", Settings: "Réglages", "Show possible moves?": "Montrer les coups possibles ?", "Show solution": "Montrer la solution", diff --git a/client/src/views/Game.vue b/client/src/views/Game.vue index 91e6b6af..5c4630b0 100644 --- a/client/src/views/Game.vue +++ b/client/src/views/Game.vue @@ -30,23 +30,41 @@ main #aboveBoard.col-sm-12.col-md-9.col-md-offset-3.col-lg-10.col-lg-offset-2 span.variant-cadence {{ game.cadence }} span.variant-name {{ game.vname }} - button#chatBtn(onClick="window.doClick('modalChat')") Chat + span#nextGame( + v-if="nextIds.length > 0" + @click="showNextGame()" + ) + | {{ st.tr["Next_g"] }} + button#chatBtn.tooltip( + onClick="window.doClick('modalChat')" + aria-label="Chat" + ) + img(src="/images/icons/chat.svg") #actions(v-if="game.score=='*'") - button( + button.tooltip( @click="clickDraw()" :class="{['draw-' + drawOffer]: true}" + :aria-label="st.tr['Draw']" ) - | {{ st.tr["Draw"] }} - button( + img(src="/images/icons/draw.svg") + button.tooltip( v-if="!!game.mycolor" @click="abortGame()" + :aria-label="st.tr['Abort']" ) - | {{ st.tr["Abort"] }} - button( + img(src="/images/icons/abort.svg") + button.tooltip( v-if="!!game.mycolor" @click="resign()" + :aria-label="st.tr['Resign']" ) - | {{ st.tr["Resign"] }} + img(src="/images/icons/resign.svg") + button.tooltip( + v-else-if="!!game.mycolor" + @click="rematch()" + :aria-label="st.tr['Rematch']" + ) + img(src="/images/icons/rematch.svg") #playersInfo p span.name(:class="{connected: isConnected(0)}") @@ -112,6 +130,7 @@ export default { chats: [], rendered: false }, + nextIds: [], virtualClocks: [[0,0], [0,0]], //initialized with true game.clocks vr: null, //"variant rules" object initialized from FEN drawOffer: "", @@ -149,7 +168,11 @@ export default { const my = this.st.user; this.$set(this.people, my.sid, { id: my.id, name: my.name }); this.gameRef.id = this.$route.params["id"]; - this.gameRef.rid = this.$route.query["rid"]; //may be undefined + // rid = remote ID to find an observed live game, + // next = next corr games IDs to navigate faster + // (Both might be undefined) + this.gameRef.rid = this.$route.query["rid"]; + this.nextIds = JSON.parse(this.$route.query["next"] || "[]"); // Initialize connection this.connexionString = params.socketUrl + @@ -254,6 +277,18 @@ export default { (color == "b" && movesCount % 2 == 1); this.send("turnchange", { target: sid, yourTurn: yourTurn }); }, + showNextGame: function() { + // Did I play in current game? If not, add it to nextIds list + if (this.game.score == "*" && this.vr.turn == this.game.mycolor) + this.nextIds.unshift(this.game.id); + const nextGid = this.nextIds.pop(); + this.$router.push( + "/game/" + nextGid + "/?next=" + JSON.stringify(this.nextIds)); + }, + rematch: function() { + alert("Unimplemented yet (soon :) )"); + // TODO: same logic as for draw, but re-click remove rematch offer (toggle) + }, askGameAgain: function() { this.gameIsLoading = true; const doAskGame = () => { @@ -602,10 +637,10 @@ export default { } // NOTE: clocks in seconds, initime in milliseconds game.moves.sort((m1, m2) => m1.idx - m2.idx); //in case of + game.clocks = [tc.mainTime, tc.mainTime]; const L = game.moves.length; if (game.score == "*") { // Set clocks + initime - game.clocks = [tc.mainTime, tc.mainTime]; game.initime = [0, 0]; if (L >= 1) { const gameLastupdate = game.moves[L-1].played; @@ -963,9 +998,16 @@ export default { #actions display: inline-block margin: 0 - button - display: inline-block - margin: 0 + +button + display: inline-block + margin: 0 + display: inline-flex + img + height: 24px + display: flex + @media screen and (max-width: 767px) + height: 18px @media screen and (max-width: 767px) #aboveBoard @@ -981,6 +1023,12 @@ export default { font-weight: bold padding-right: 10px +span#nextGame + background-color: #edda99 + cursor: pointer + display: inline-block + margin-right: 10px + span.name font-size: 1.5rem padding: 0 3px @@ -1014,9 +1062,6 @@ span.yourturn max-width: 767px border: none; -#chatBtn - margin: 0 10px 0 0 - .draw-sent, .draw-sent:hover background-color: lightyellow diff --git a/client/src/views/MyGames.vue b/client/src/views/MyGames.vue index c1430f89..d1f3e38a 100644 --- a/client/src/views/MyGames.vue +++ b/client/src/views/MyGames.vue @@ -87,8 +87,33 @@ export default { classifyObject: function(o) { return o.cadence.indexOf("d") === -1 ? "live" : "corr"; }, - showGame: function(g) { - this.$router.push("/game/" + g.id); + showGame: function(game) { + // TODO: "isMyTurn" is duplicated (see GameList component). myColor also + const isMyTurn = (g) => { + const myColor = + g.players[0].uid == this.st.user.id || + g.players[0].sid == this.st.user.sid + ? "w" + : "b"; + const rem = g.movesCount % 2; + return ( + (rem == 0 && myColor == "w") || + (rem == 1 && myColor == "b") + ); + }; + if (game.type == "live" || !isMyTurn(game)) + this.$router.push("/game/" + game.id); + // It's my turn in this game. Are there others? + let nextIds = ""; + let otherCorrGamesMyTurn = this.corrGames.filter( + g => g.id != game.id && isMyTurn(g)); + if (otherCorrGamesMyTurn.length > 0) { + nextIds += "/?next=["; + otherCorrGamesMyTurn.forEach(g => { nextIds += g.id + ","; }); + // Remove last comma and close array: + nextIds = nextIds.slice(0, -1) + "]"; + } + this.$router.push("/game/" + game.id + nextIds); }, socketMessageListener: function(msg) { const data = JSON.parse(msg.data); diff --git a/client/src/views/Problems.vue b/client/src/views/Problems.vue index 7621fe35..a1c3e83c 100644 --- a/client/src/views/Problems.vue +++ b/client/src/views/Problems.vue @@ -56,7 +56,7 @@ main button.nomargin(@click="gotoPrevNext($event,curproblem,1)") | {{ st.tr["Previous"] }} button.nomargin(@click="gotoPrevNext($event,curproblem,-1)") - | {{ st.tr["Next"] }} + | {{ st.tr["Next_p"] }} p.oneInstructions.clickable( v-html="parseHtml(curproblem.instruction)" @click="curproblem.showSolution=!curproblem.showSolution"