Styled layout. TODO: variants page, and then index
authorBenjamin Auder <benjamin.auder@somewhere>
Thu, 31 Jan 2019 18:32:09 +0000 (19:32 +0100)
committerBenjamin Auder <benjamin.auder@somewhere>
Thu, 31 Jan 2019 18:32:09 +0000 (19:32 +0100)
12 files changed:
client/next_src/components/challengeList.js [deleted file]
client/next_src/components/gameList.js [deleted file]
client/public/index.html
client/src/App.vue
client/src/components/ChallengeList.vue [new file with mode: 0644]
client/src/components/GameList.vue [new file with mode: 0644]
client/src/data/nbPlayers.js
client/src/main.js
client/src/stylesheets/layout.sass
client/src/translations/fr.js
client/src/views/Home.vue
client/src/views/Variants.vue

diff --git a/client/next_src/components/challengeList.js b/client/next_src/components/challengeList.js
deleted file mode 100644 (file)
index 2c997b7..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-Vue.component("my-challenge-list", {
-       props: ["challenges"],
-       computed: {
-               showVariant: function() {
-                       this.challenges.length > 0 && !!this.challenges[0].variant;
-               },
-               showNbPlayers: function() {
-                       this.challenges.length > 0 && !!this.challenges[0].nbPlayers;
-               },
-       },
-       template: `
-               <table>
-                       <tr>
-                               <th v-if="showVariant">Variant</th>
-                               <th>From</th>
-                               <th>To</th>
-                               <th>Cadence</th>
-                               <th v-if="showNbPlayers">Number of players</th>
-                       </tr>
-                       <tr v-for="c in challenges" @click="$emit('click-challenge',c)">
-                               <td v-if="showVariant">{{ c.variant }}</td>
-                               <td>{{ c.from.name }}</td>
-                               <td>
-                                       <span v-for="p in c.to">{{ p.name }}</span>
-                               </td>
-                               <td>{{ c.mainTime }} + {{ c.increment }}</td>
-                               <td v-if="showNbPlayers">{{ c.nbPlayers }}</td>
-                       </tr>
-               </table>
-       `,
-});
-
-// TODO: challenge format from/to ou uid/players ............
diff --git a/client/next_src/components/gameList.js b/client/next_src/components/gameList.js
deleted file mode 100644 (file)
index 9b66982..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-Vue.component("my-game-list", {
-       props: ["games"],
-       computed: {
-               showVariant: function() {
-                       return this.games.length > 0 && !!this.games[0].vname;
-               },
-               showResult: function() {
-                       return this.games.length > 0 && this.games[0].score != "*";
-               },
-       },
-       template: `
-               <table>
-                       <tr>
-                               <th v-if="showVariant">Variant</th>
-                               <th>Players names</th>
-                               <th>Cadence</th>
-                               <th v-if="showResult">Result</th>
-                       </tr>
-                       <tr v-for="g in games" @click="$emit('show-game',g)">
-                               <td v-if="showVariant">{{ g.vname }}</td>
-                               <td>
-                                       <span v-for="p in g.players">{{ p.name }}</span>
-                               </td>
-                               <td>{{ g.mainTime }} + {{ g.increment }}</td>
-                               <td v-if="showResult">{{ g.score }}</td>
-                       </tr>
-               </table>
-       `,
-});
index 6549d7a..af506cd 100644 (file)
                        href="//cdnjs.cloudflare.com/ajax/libs/mini.css/3.0.0/mini-default.min.css">
                <link rel="stylesheet"
                        href="//fonts.googleapis.com/css?family=Open+Sans:400,700">
+    <style>
+      body {
+        --fore-color: #2c3e50;
+        --back-color: #f2f2f2;
+      }
+    </style>
   </head>
   <body>
     <div id="app"></div>
index 2b13127..dd45b34 100644 (file)
@@ -8,48 +8,46 @@
   UpsertUser
   .container
     .row(v-show="$route.path == '/'")
-      // Header (on index only ?!)
-      header
-        .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+      .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+        // Header (on index only)
+        header
           img(src="./assets/images/index/unicorn.svg")
           .info-container
             p vchess.club
           img(src="./assets/images/index/wildebeest.svg")
     .row
-      // Menu (top of page):
-      // shared: Home + flags, userMenu
-      // variant: hall, problems, rules, my games + settings
-      nav
-        label.drawer-toggle(for="drawerControl")
-        input#drawerControl.drawer(type="checkbox")
-        #menuBar
-          label.drawer-close(for="drawerControl")
-          router-link(to="/")
-            // select options all variants + filter possible (as in problems)
-            | Home
-          router-link(to="/myGames")
-            | {{ st.tr["My games"] }}
-          router-link(to="/rules")
-            // Boxes OK for rules/Atomic/ ...etc
-            | {{ st.tr["Rules"] }}
-          router-link(to="/problems")
-            | {{ st.tr["Problems"] }}
-          #userMenu.clickable.right-menu(onClick="doClick('modalUser')")
-            .info-container
-              p
-                span {{ !st.user.id ? "Login" : "Update" }}
-                span.icon-user
-          #flagMenu.clickable.right-menu(onClick="doClick('modalLang')")
-          img(src="/images/flags/" + lang + ".svg")
-        #settings.clickable(onClick="doClick('modalSettings')")
-          | Settings
-          i(data-feather="settings")
+      .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+        // Menu (top of page):
+        // Left: home, variants, mygames, problems
+        // Right: usermenu, settings, flag
+        nav
+          label.drawer-toggle(for="drawerControl")
+          input#drawerControl.drawer(type="checkbox")
+          #menuBar
+            label.drawer-close(for="drawerControl")
+            #leftMenu
+              router-link(to="/")
+                | {{ st.tr["Home"] }}
+              router-link(to="/variants")
+                | {{ st.tr["Variants"] }}
+              router-link(to="/mygames")
+                | {{ st.tr["My games"] }}
+              router-link(to="/problems")
+                | {{ st.tr["Problems"] }}
+            #rightMenu
+              .clickable(onClick="doClick('modalUser')")
+                | {{ !st.user.id ? "Login" : "Update" }}
+              .clickable(onClick="doClick('modalSettings')")
+                | {{ st.tr["Settings"] }}
+              .clickable(onClick="doClick('modalLang')")
+                img(v-if="!!st.lang"
+                  :src="require(`@/assets/images/flags/${st.lang}.svg`)")
     .row
       router-view
     .row
-      footer
-        .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2.text-center
-          a(href="https://github.com/yagu0/vchess") Source code
+      .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+        footer
+          a(href="https://github.com/yagu0/vchess") {{ st.tr["Source code"] }}
           p.clickable(onClick="doClick('modalContact')")
             | {{ st.tr["Contact form"] }}
   //my-game(:game-ref="gameRef" :mode="mode" :settings="settings" @game-over="archiveGame")
@@ -84,14 +82,75 @@ export default {
   font-family: "Avenir", Helvetica, Arial, sans-serif
   -webkit-font-smoothing: antialiased
   -moz-osx-font-smoothing: grayscale
-  text-align: center
-  color: #2c3e50
 
-#nav
-  padding: 30px
-  a
-    font-weight: bold
-    color: #2c3e50
-    &.router-link-exact-active
-      color: #42b983
+.container
+  @media screen and (max-width: 767px)
+    padding: 0
+
+header
+  width: 100%
+  display: flex
+  align-items: center
+  justify-content: center
+  margin: 0 auto
+  & > img
+    width: 30px
+    height: 30px
+
+.clickable
+  cursor: pointer
+
+nav
+  width: 100%
+  padding: 0
+  & > #menuBar
+    width: 100%
+    padding: 0
+    & > #leftMenu
+      padding: 0
+      width: 50%
+      display: inline-flex
+      align-items: center
+      justify-content: flex-start
+      & > a
+        display: inline-block
+        color: #2c3e50
+        &.router-link-exact-active
+          color: #42b983
+    & > #rightMenu
+      padding: 0
+      width: 50%
+      display: inline-flex
+      align-items: center
+      justify-content: flex-end
+      & > div
+        display: inline-block
+        & > img
+          padding: 0
+          width: 30px
+          height: 30px
+
+// TODO: drawer, until 600px wide OK (seemingly)
+// After, zone where left and right just go on top of another
+// Then, on narrow screen put everything on one line
+[type="checkbox"].drawer+*
+  right: -767px
+
+footer
+  //background-color: #000033
+  font-size: 1rem
+  width: 100%
+  display: inline-flex
+  align-items: center
+  justify-content: center
+  & > a
+    display: inline-block
+    margin: 0 10px 0 0
+    &:link
+      color: #2c3e50
+    &:hover
+      text-decoration: none
+  & > p
+    display: inline-block
+    margin: 0 0 0 10px
 </style>
diff --git a/client/src/components/ChallengeList.vue b/client/src/components/ChallengeList.vue
new file mode 100644 (file)
index 0000000..a52e0ca
--- /dev/null
@@ -0,0 +1,36 @@
+<template lang="pug">
+table
+  tr
+    th(v-if="showVariant") Variant
+    th From
+    th To
+    th Cadence
+    th(v-if="showNbPlayers") Number of players
+  tr(v-for="c in challenges" @click="$emit('click-challenge',c)")
+    td(v-if="showVariant") {{ c.variant }}
+    td {{ c.from.name }}
+    td
+      span(v-for="p in c.to") {{ p.name }}
+      td {{ c.mainTime }} + {{ c.increment }}
+      td(v-if="showNbPlayers") {{ c.nbPlayers }}
+</template>
+
+<script>
+export default {
+  name: "my-challenge-list",
+       props: ["challenges"],
+       computed: {
+               showVariant: function() {
+                       this.challenges.length > 0 && !!this.challenges[0].variant;
+               },
+               showNbPlayers: function() {
+                       this.challenges.length > 0 && !!this.challenges[0].nbPlayers;
+               },
+       },
+};
+// TODO: challenge format from/to ou uid/players ............
+</script>
+
+<style lang="sass">
+// TODO: affichage bizarre sur petits écrans <=767px
+</style>
diff --git a/client/src/components/GameList.vue b/client/src/components/GameList.vue
new file mode 100644 (file)
index 0000000..c7f661c
--- /dev/null
@@ -0,0 +1,29 @@
+<template lang="pug">
+table
+  tr
+    th(v-if="showVariant") Variant
+    th Players names
+    th Cadence
+    th(v-if="showResult") Result
+  tr(v-for="g in games" @click="$emit('show-game',g)")
+    td(v-if="showVariant") {{ g.vname }}
+    td
+      span(v-for="p in g.players") {{ p.name }}
+    td {{ g.mainTime }} + {{ g.increment }}
+    td(v-if="showResult") {{ g.score }}
+</template>
+
+<script>
+export default {
+  name: "my-game-list",
+       props: ["games"],
+       computed: {
+               showVariant: function() {
+                       return this.games.length > 0 && !!this.games[0].vname;
+               },
+               showResult: function() {
+                       return this.games.length > 0 && this.games[0].score != "*";
+               },
+       },
+};
+</script>
index 8c0cc86..2f58d16 100644 (file)
@@ -1,4 +1,4 @@
-const NbPlayers =
+export const NbPlayers =
 {
        "Alice": [2,3,4],
        "Antiking": [2,3,4],
@@ -19,5 +19,3 @@ const NbPlayers =
        "Wildebeest": [2],
        "Zen": [2,3,4],
 };
-
-try { module.exports = NbPlayers; } catch (e) { } //for server
index 97bad75..703ff74 100644 (file)
@@ -38,6 +38,7 @@ new Vue({
 //  mounted: function() {
 //    feather.replace();
 //  },
+  // "mounted" and not "created", because modalWelcome must be filled
   mounted: function() {
     store.initialize();
   },
index 5639c7b..b744675 100644 (file)
@@ -55,26 +55,6 @@ a.right-menu
   color: blue
   display: none
 
-footer
-  height: 77px
-  background-color: #000033
-  div
-    line-height: 77px
-    a
-      margin: 0 10px 0 0
-      display: inline-block
-      &:visited, &:link
-        color: white
-    p
-      margin: 0 0 0 10px
-      display: inline-block
-      color: white
-      text-decoration: underline
-  @media screen and (max-width: 767px)
-    height: 43px
-    div
-      line-height: 43px
-
 a
   text-decoration: underline
 
index ee65449..4d242c2 100644 (file)
@@ -1,5 +1,12 @@
 export const translations =
 {
+  "Home": "Accueil",
+  "Variants": "Variantes",
+  "My games": "Mes parties",
+  "Problems": "Problèmes",
+  "Contact form": "Formulaire de contact",
+  "Source code": "Code source",
+
   "Language": "Langue",
 
   // Index page:
@@ -31,7 +38,6 @@ export const translations =
   "Waiting for opponent...": "En attente d'un adversaire...",
   "Rules": "Règles",
   "Play": "Jouer",
-  "Problems": "Problèmes",
   "White win": "Les blancs gagnent",
   "Black win": "Les noirs gagnent",
   "Draw": "Match nul",
index c2c5b44..f0f6a5c 100644 (file)
@@ -7,7 +7,7 @@ div
       fieldset
         label(for="selectVariant") {{ st.tr["Variant"] }}
         select#selectVariant(v-model="newgameInfo.vid")
-          option(v-for="v in variants" :value="v.id") {{ v.name }}
+          option(v-for="v in st.variants" :value="v.id") {{ v.name }}
       fieldset
         label(for="selectNbPlayers") {{ st.tr["Number of players"] }}
         select#selectNbPlayers(v-model="newgameInfo.nbPlayers")
@@ -31,14 +31,14 @@ div
             v-model="newgameInfo.players[2].name")
       fieldset
         label(for="inputFen")
-          {{ st.tr["FEN (ignored if players fields are blank)"] }}
+          {{ st.tr["FEN (ignored if players fields are blank)"] }}
         input#inputFen(type="text" v-model="newgameInfo.fen")
       button(@click="newGame") Launch game
       p TODO: cadence, adversaire (pre-filled if click on name)
       p cadence 2m+12s ou 7d+1d (m,s ou d,d) --> main, increment
       p Note: leave FEN blank for random; FEN only for targeted challenge
   div
-    my-challenge-list(:challenges="challenges" @click-challenge="clickChallenge")
+    ChallengeList(:challenges="challenges" @click-challenge="clickChallenge")
     div(style="border:1px solid black")
       h3 Online players
       div(v-for="p in players" @click="challenge(p)") {{ p.name }}
@@ -47,9 +47,9 @@ div
     .button-group
       button(@click="gdisplay='live'") Live games
       button(@click="gdisplay='corr'") Correspondance games
-    my-game-list(v-show="gdisplay=='live'" :games="liveGames"
+    GameList(v-show="gdisplay=='live'" :games="liveGames"
       @show-game="showGame")
-    my-game-list(v-show="gdisplay=='corr'" :games="corrGames"
+    GameList(v-show="gdisplay=='corr'" :games="corrGames"
       @show-game="showGame")
 </template>
 
@@ -65,6 +65,7 @@ fin de partie corr: supprimer partie du serveur au bout de 7 jours (arbitraire)
 // TODO: au moins l'échange des coups en P2P ? et game chat ?
 // TODO: objet game, objet challenge ? et player ?
 import { store } from "@/store";
+import { NbPlayers } from "@/data/nbPlayers";
 import GameList from "@/components/GameList.vue";
 import ChallengeList from "@/components/ChallengeList.vue";
 export default {
@@ -92,46 +93,48 @@ export default {
                        },
                };
        },
-       created: function() {
-               // TODO: ask server for current corr games (all but mines: names, ID, time control)
-               const socketMessageListener = msg => {
-                       const data = JSON.parse(msg.data);
-                       switch (data.code)
-                       {
-                               case "newgame":
-                                       // TODO: new game just started: data contain all informations
-                                       // (id, players, time control, fenStart ...)
-                                       break;
-                               // TODO: also receive live games summaries (update)
-                               // (just players names, time control, and ID + player ID)
-                               case "acceptchallenge":
-                                       // oppid: opponent socket ID (or DB id if registered)
-                                       if (true) //TODO: if challenge is full
-                                               this.newGame(data.challenge, data.user); //user.id et user.name
-                                       break;
-                               case "withdrawchallenge":
-                                       // TODO
-                                       break;
-                               case "cancelchallenge":
-                                       // TODO
-                                       break;
-                               // TODO: distinguish these (dis)connect events from their analogs in game.js
-                               case "connect":
-                                       this.players.push({name:data.name, id:data.uid});
-                                       break;
-                               case "disconnect":
-                                       const pIdx = this.players.findIndex(p => p.id == data.uid);
-                                       this.players.splice(pIdx);
-                                       break;
-                       }
-               };
-               const socketCloseListener = () => {
-                       this.st.conn.addEventListener('message', socketMessageListener);
-                       this.st.conn.addEventListener('close', socketCloseListener);
-               };
-               this.st.conn.onmessage = socketMessageListener;
-               this.st.conn.onclose = socketCloseListener;
-       },
+  watch: {
+    "st.conn": function() {
+      // TODO: ask server for current corr games (all but mines: names, ID, time control)
+      const socketMessageListener = msg => {
+        const data = JSON.parse(msg.data);
+        switch (data.code)
+        {
+          case "newgame":
+            // TODO: new game just started: data contain all informations
+            // (id, players, time control, fenStart ...)
+            break;
+          // TODO: also receive live games summaries (update)
+          // (just players names, time control, and ID + player ID)
+          case "acceptchallenge":
+            // oppid: opponent socket ID (or DB id if registered)
+            if (true) //TODO: if challenge is full
+              this.newGame(data.challenge, data.user); //user.id et user.name
+            break;
+          case "withdrawchallenge":
+            // TODO
+            break;
+          case "cancelchallenge":
+            // TODO
+            break;
+          // TODO: distinguish these (dis)connect events from their analogs in game.js
+          case "connect":
+            this.players.push({name:data.name, id:data.uid});
+            break;
+          case "disconnect":
+            const pIdx = this.players.findIndex(p => p.id == data.uid);
+            this.players.splice(pIdx);
+            break;
+        }
+      };
+      const socketCloseListener = () => {
+        this.st.conn.addEventListener('message', socketMessageListener);
+        this.st.conn.addEventListener('close', socketCloseListener);
+      };
+      this.st.conn.onmessage = socketMessageListener;
+      this.st.conn.onclose = socketCloseListener;
+    },
+  },
        methods: {
                showGame: function(game) {
       // NOTE: if we are an observer, the game will be found in main games list
@@ -207,8 +210,8 @@ export default {
                                                                uid: user.id,
                                                                added: Date.now(),
                                                                vname: vname,
-                                                       },
-                                               this.challenges.push(response.challenge);
+                                                       });
+                                               this.challenges.push(chall);
                                        }
                                );
         // TODO: else, if live game: send infos (socket), and...
@@ -233,10 +236,15 @@ export default {
                possibleNbplayers: function(nbp) {
                        if (this.newgameInfo.vid == 0)
                                return false;
+      const variants = this.st.variants;
                        const idxInVariants =
-                               variantArray.findIndex(v => v.id == this.newgameInfo.vid);
-                       return NbPlayers[variantArray[idxInVariants].name].includes(nbp);
+                               variants.findIndex(v => v.id == this.newgameInfo.vid);
+                       return NbPlayers[variants[idxInVariants].name].includes(nbp);
                },
        },
-});
+};
 </script>
+
+<style lang="sass">
+// TODO
+</style>
index 0390357..f521429 100644 (file)
@@ -1,15 +1,15 @@
 <template lang="pug">
 div
-       .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
-               label(for="prefixFilter") Type first letters...
-               input#prefixFilter(v-model="curPrefix")
-       .variant.col-sm-12.col-md-5.col-lg-4(
-               v-for="(v,idx) in filteredVariants"
-               :class="{'col-md-offset-1': idx%2==0, 'col-lg-offset-2': idx%2==0}"
-       )
-               router-link(:to="getLink(v.name)")
-                       h4.boxtitle.text-center {{ v.name }}
-                       p.description.text-center {{ st.tr(v.desc) }}
+  .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+    label(for="prefixFilter") Type first letters...
+    input#prefixFilter(v-model="curPrefix")
+  .variant.col-sm-12.col-md-5.col-lg-4(
+    v-for="(v,idx) in filteredVariants"
+    :class="{'col-md-offset-1': idx%2==0, 'col-lg-offset-2': idx%2==0}"
+  )
+    router-link(:to="getLink(v.name)")
+      h4.boxtitle.text-center {{ v.name }}
+      p.description.text-center {{ st.tr[v.desc] }}
 </template>
 
 <script>
@@ -18,29 +18,29 @@ export default {
   name: "variants",
   data: function() {
     return {
-                 curPrefix: "",
+      curPrefix: "",
       st: store.state,
     };
-       },
-       computed: {
-               filteredVariants: function () {
-                       const capitalizedPrefix = this.curPrefix.replace(/^\w/, c => c.toUpperCase());
-                       const variants = this.st.variants
-                       .filter( v => {
-                               return v.name.startsWith(capitalizedPrefix);
-                       })
-                       .map( v => {
-                               return {
-                                       name: v.name,
-                                       desc: v.description,
-                               };
-                       })
+  },
+  computed: {
+    filteredVariants: function () {
+      const capitalizedPrefix = this.curPrefix.replace(/^\w/, c => c.toUpperCase());
+      const variants = this.st.variants
+      .filter( v => {
+        return v.name.startsWith(capitalizedPrefix);
+      })
+      .map( v => {
+        return {
+          name: v.name,
+          desc: v.description,
+        };
+      })
       .sort((a,b) => {
-                               return a.name.localeCompare(b.name);
-                       });
+        return a.name.localeCompare(b.name);
+      });
       return variants;
-               },
-       },
+    },
+  },
   methods: {
     getLink: function(vname) {
       return "/variants/" + vname;