// Header (on index only)
header
.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
- img(src="./assets/images/index/unicorn.svg")
- .info-container
- p vchess.club
- img(src="./assets/images/index/wildebeest.svg")
+ 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(v-if="$route.path != '/'" to="/")
- | Home
- router-link(:href="getLink('/hall')")
- | getLink function : suffix ==> /variant + suffix
- =translations["Hall"]
- router-link(href="#tabGames")
- =translations["My games"]
- router-link(href="#rules")
- =translations["Rules"]
- router-link(href="#problems")
- =translations["Problems"]
- #userMenu.clickable.right-menu(onClick="doClick('modalUser')")
- .info-container
- if !user.email
- p
- span Login
- span.icon-user
- else
- p
- span Update
- span.icon-user
- #flagMenu.clickable.right-menu(onClick="doClick('modalLang')")
- img(src="/images/flags/" + lang + ".svg")
- #settings.clickable(v-show="display!='index'" onClick="doClick('modalSettings')")
- i(data-feather="settings")
+ // 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")
+ | {{ $tr["My games"] }}
+ router-link(to="/rules")
+ // Boxes OK for rules/Atomic/ ...etc
+ | {{ $tr["Rules"] }}
+ router-link(to="/problems")
+ | {{ $tr["Problems"] }}
+ #userMenu.clickable.right-menu(onClick="doClick('modalUser')")
+ .info-container
+ p
+ span {{ !$user.email ? "Login" : "Update" }}
+ span.icon-user
+ #flagMenu.clickable.right-menu(onClick="doClick('modalLang')")
+ img(src="/images/flags/" + lang + ".svg")
+ #settings.clickable(onClick="doClick('modalSettings')")
+ i(data-feather="settings")
.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
- p.clickable(onClick="doClick('modalContact')")
- = translations["Contact form"]
+ 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
+ p.clickable(onClick="doClick('modalContact')")
+ | {{ $tr["Contact form"] }}
//my-game(:game-ref="gameRef" :mode="mode" :settings="settings" @game-over="archiveGame")
//// TODO: add only the necessary icons to mini-css custom build
//script(src="//unpkg.com/feather-icons")
import { ajax } from "../utils/ajax";
export default {
name: "ContactForm",
- methods: {
+ methods: {
// Note: not using Vue here, but would be possible
trySendMessage: function() {
let email = document.getElementById("userEmail");
+++ /dev/null
-<template>
- <div class="hello">
-
-
-
-
-//Index: rename into Home
- .row(v-show="display=='variants'")
- .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")
- my-variant-summary(v-for="(v,idx) in sortedCounts"
-
-
-
-
-
- <h1>{{ msg }}</h1>
- <p>
- For a guide and recipes on how to configure / customize this project,<br>
- check out the
- <a href="https://cli.vuejs.org" target="_blank" rel="noopener">vue-cli documentation</a>.
- </p>
- <h3>Installed CLI Plugins</h3>
- <ul>
- <li><a href="https://github.com/vuejs/vue-cli/tree/dev/packages/%40vue/cli-plugin-eslint" target="_blank" rel="noopener">eslint</a></li>
- </ul>
- <h3>Essential Links</h3>
- <ul>
- <li><a href="https://vuejs.org" target="_blank" rel="noopener">Core Docs</a></li>
- <li><a href="https://forum.vuejs.org" target="_blank" rel="noopener">Forum</a></li>
- <li><a href="https://chat.vuejs.org" target="_blank" rel="noopener">Community Chat</a></li>
- <li><a href="https://twitter.com/vuejs" target="_blank" rel="noopener">Twitter</a></li>
- <li><a href="https://news.vuejs.org" target="_blank" rel="noopener">News</a></li>
- </ul>
- <h3>Ecosystem</h3>
- <ul>
- <li><a href="https://router.vuejs.org" target="_blank" rel="noopener">vue-router</a></li>
- <li><a href="https://vuex.vuejs.org" target="_blank" rel="noopener">vuex</a></li>
- <li><a href="https://github.com/vuejs/vue-devtools#vue-devtools" target="_blank" rel="noopener">vue-devtools</a></li>
- <li><a href="https://vue-loader.vuejs.org" target="_blank" rel="noopener">vue-loader</a></li>
- <li><a href="https://github.com/vuejs/awesome-vue" target="_blank" rel="noopener">awesome-vue</a></li>
- </ul>
- </div>
-</template>
-
-<script>
-export default {
- name: "HelloWorld",
- props: {
- msg: String
- },
-// created: function() {
-// alert("test");
-// },
- methods: {
-
- },
-};
-</script>
-
-
-
-
-
-
-
-
-// Javascript for index page: mostly counters updating
-new Vue({
- el: "#VueElement",
- data: {
- counts: {},
- curPrefix: "",
- conn: null,
- display: "variants",
- },
- computed: {
- sortedCounts: function () {
- const capitalizedPrefix = this.curPrefix.replace(/^\w/, c => c.toUpperCase());
- const variantsCounts = variantArray
- .filter( v => {
- return v.name.startsWith(capitalizedPrefix);
- })
- .map( v => {
- return {
- name: v.name,
- desc: v.description,
- count: this.counts[v.name] || 0,
- };
- });
- return variantsCounts.sort((a,b) => {
- if (a.count != b.count)
- return b.count - a.count;
- // Else, alphabetic ordering
- return a.name.localeCompare(b.name);
- });
- },
- },
- created: function() {
- this.setDisplay();
- window.onhashchange = this.setDisplay;
-
- const url = socketUrl;
- const sid = getRandString();
- this.conn = new WebSocket(url + "/?sid=" + sid + "&page=index");
- const socketMessageListener = msg => {
- const data = JSON.parse(msg.data);
- if (data.code == "counts")
- this.counts = data.counts;
- else if (data.code == "increase")
- this.counts[data.vid]++;
- else if (data.code == "decrease")
- this.counts[data.vid]--;
- };
- const socketCloseListener = () => {
- this.conn = new WebSocket(url + "/?sid=" + sid + "&page=index");
- this.conn.addEventListener('message', socketMessageListener);
- this.conn.addEventListener('close', socketCloseListener);
- };
- this.conn.onmessage = socketMessageListener;
- this.conn.onclose = socketCloseListener;
-
- // TODO: AJAX call get corr games (all variants)
- // si dernier lastMove sur serveur n'est pas le mien et nextColor == moi, alors background orange
- // ==> background orange si à moi de jouer par corr (sur main index)
- // (helper: static fonction "GetNextCol()" dans base_rules.js)
-
- },
- methods: {
- setDisplay: function() {
- if (!location.hash)
- location.hash = "#variants"; //default
- this.display = location.hash.substr(1);
- },
-
- },
-});
-
-
-
-
-
-
-
-
-<!-- Add "scoped" attribute to limit CSS to this component only -->
-<style scoped lang="scss">
-h3 {
- margin: 40px 0 0;
-}
-ul {
- list-style-type: none;
- padding: 0;
-}
-li {
- display: inline-block;
- margin: 0 10px;
-}
-a {
- color: #42b983;
-}
-</style>
render: function(h) {
return h(App);
},
- watch: {
- $lang: async function(newLang) {
- // Fill modalWelcome, and import translations from "./translations/$lang.js"
- document.getElementById("modalWelcome").innerHTML =
- require("raw-loader!pug-plain-loader!./modals/welcome/" + newLang + ".pug");
- const tModule = await import("./translations/" + newLang + ".js");
- Vue.prototype.$tr = tModule.translations;
- //console.log(tModule.translations);
- },
- $route: function(newRoute) {
- console.log(this.$route.params);
- //TODO: conn.send("enter", newRoute)
- },
- },
+// watch: {
+// $lang: async function(newLang) {
+// // Fill modalWelcome, and import translations from "./translations/$lang.js"
+// document.getElementById("modalWelcome").innerHTML =
+// require("raw-loader!pug-plain-loader!./modals/welcome/" + newLang + ".pug");
+// const tModule = await import("./translations/" + newLang + ".js");
+// Vue.prototype.$tr = tModule.translations;
+// //console.log(tModule.translations);
+// },
+// $route: function(newRoute) {
+// //console.log(this.$route.params);
+// console.log("navig to " + newRoute);
+// //TODO: conn.send("enter", newRoute)
+// },
+// },
created: function() {
const supportedLangs = ["en","es","fr"];
Vue.prototype.$lang = localStorage["lang"] ||
supportedLangs.includes(navigator.language)
? navigator.language
: "en";
+ Vue.prototype.$variants = []; //avoid runtime error
ajax("/variants", "GET", res => { Vue.prototype.$variants = res.variantArray; });
Vue.prototype.$tr = {}; //to avoid a compiler error
+ Vue.prototype.$user = {}; //TODO: from storage
// TODO: if there is a socket ID in localStorage, it means a live game was interrupted (and should resume)
const myid = localStorage["myid"] || util.getRandString();
// NOTE: in this version, we don't say on which page we are, yet
name: "home",
component: Home,
},
- {
- path: "/about",
- name: "about",
- // route level code-splitting
- // this generates a separate chunk (about.[hash].js) for this route
- // which is lazy-loaded when the route is visited.
- component: loadView('About'),
- //function() {
- // return import(/* webpackChunkName: "about" */ "./views/About.vue");
- //}
- },
- {
- path: "/test",
- name: "test",
- component: loadView("Test"),
- },
+// {
+// path: "/about",
+// name: "about",
+// // route level code-splitting
+// // this generates a separate chunk (about.[hash].js) for this route
+// // which is lazy-loaded when the route is visited.
+// component: loadView('About'),
+// //function() {
+// // return import(/* webpackChunkName: "about" */ "./views/About.vue");
+// //}
+// },
+// {
+// path: "/test",
+// name: "test",
+// component: loadView("Test"),
+// },
// TODO: gameRef, problemId: https://router.vuejs.org/guide/essentials/dynamic-matching.html
]
});
range: function(max)
{
return [...Array(max).keys()];
- }
+ },
// TODO: rename into "cookie" et supprimer les deux ci-dessous
// Random (enough) string for socket and game IDs
-<template>
- <div class="home">
- <Home msg="Welcome to Your Vue.js Apppp"/>
- </div>
+<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 sortedCounts"
+ :class="{'col-md-offset-1': idx%2==0, 'col-lg-offset-2': idx%2==0}"
+ )
+ a(:href="v.name")
+ h4.boxtitle.text-center {{ v.name }}
+ span.count-players / {{ v.count }}
+ p.description.text-center {{ $tr(v.desc) }}
</template>
<script>
-// @ is an alias to /src
-import HelloWorld from "@/components/HelloWorld.vue";
-
export default {
name: "home",
- components: {
- HelloWorld,
- }
-};
-</script>
-
-// Show a variant summary on index
-Vue.component('my-variant-summary', {
- props: ['vobj','index'],
- template: `
- <div class="variant col-sm-12 col-md-5 col-lg-4" :id="vobj.name"
- :class="{'col-md-offset-1': index%2==0, 'col-lg-offset-2': index%2==0}">
- <a :href="url">
- <h4 class="boxtitle text-center">
- {{ vobj.name }}
- <span class="count-players">
- / {{ vobj.count }}
- </span>
- </h4>
- <p class="description text-center">
- {{ translate(vobj.desc) }}
- </p>
- </a>
- </div>
- `,
+ data: function() {
+ return {
+ counts: {},
+ curPrefix: "",
+ };
+ },
computed: {
- url: function() {
- return "/" + this.vobj.name;
+ sortedCounts: function () {
+ const capitalizedPrefix = this.curPrefix.replace(/^\w/, c => c.toUpperCase());
+ const variantsCounts = this.$variants
+ .filter( v => {
+ return v.name.startsWith(capitalizedPrefix);
+ })
+ .map( v => {
+ return {
+ name: v.name,
+ desc: v.description,
+ count: this.counts[v.name] || 0,
+ };
+ });
+ return variantsCounts.sort((a,b) => {
+ if (a.count != b.count)
+ return b.count - a.count;
+ // Else, alphabetic ordering
+ return a.name.localeCompare(b.name);
+ });
},
},
- methods: {
- translate: function(text) {
- return translations[text];
- },
+ created: function() {
+ const socketMessageListener = msg => {
+ const data = JSON.parse(msg.data);
+ if (data.code == "counts")
+ this.counts = data.counts;
+ else if (data.code == "increase")
+ this.counts[data.vid]++;
+ else if (data.code == "decrease")
+ this.counts[data.vid]--;
+ };
+ const socketCloseListener = () => {
+ this.$conn.addEventListener('message', socketMessageListener);
+ this.$conn.addEventListener('close', socketCloseListener);
+ };
+ this.$conn.onmessage = socketMessageListener;
+ this.$conn.onclose = socketCloseListener;
+ // TODO: AJAX call get corr games (all variants)
+ // si dernier lastMove sur serveur n'est pas le mien et nextColor == moi, alors background orange
+ // ==> background orange si à moi de jouer par corr (sur main index)
+ // (helper: static fonction "GetNextCol()" dans base_rules.js)
},
-})
+};
+</script>
+
+<!-- Add "scoped" attribute to limit CSS to this component only -->
+<style scoped lang="scss">
+h3 {
+ margin: 40px 0 0;
+}
+ul {
+ list-style-type: none;
+ padding: 0;
+}
+li {
+ display: inline-block;
+ margin: 0 10px;
+}
+a {
+ color: #42b983;
+}
+</style>
-
var wikipediaUrl = "https://en.wikipedia.org/wiki/" +
"List_of_chess_variants#/media/File:Hexagonal_chess.svg";
- p.
- For informations about hundreds (if not thousands) of variants, you
- can visit the excellent
- #[a(href="https://www.chessvariants.com/") chessvariants] website.
- p.smallfont Image credit: #[a(href=wikipediaUrl) Wikipedia]
+ p
+ | For informations about hundreds (if not thousands) of variants, you
+ | can visit the excellent
+ a(href="https://www.chessvariants.com/" _target="blank" rel="noopener")
+ | chessvariants
+ | website.
+ p.smallfont
+ | Image credit:
+ a(href=wikipediaUrl _target="blank" rel="noopener") Wikipedia