+++ /dev/null
-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 ............
+++ /dev/null
-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>
- `,
-});
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>
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")
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>
--- /dev/null
+<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>
--- /dev/null
+<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>
-const NbPlayers =
+export const NbPlayers =
{
"Alice": [2,3,4],
"Antiking": [2,3,4],
"Wildebeest": [2],
"Zen": [2,3,4],
};
-
-try { module.exports = NbPlayers; } catch (e) { } //for server
// mounted: function() {
// feather.replace();
// },
+ // "mounted" and not "created", because modalWelcome must be filled
mounted: function() {
store.initialize();
},
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
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:
"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",
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")
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 }}
.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>
// 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 {
},
};
},
- 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
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...
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>
<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>
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;