From b955c65b942d09d24b5c3bed0d755d4f2f8f71f1 Mon Sep 17 00:00:00 2001
From: Benjamin Auder <benjamin.auder@somewhere>
Date: Sat, 19 Jan 2019 20:49:34 +0100
Subject: [PATCH] Step toward a one-page application

---
 public/javascripts/{layout.js => app.js} |  12 ++
 routes/index.js                          |   1 -
 views/app.pug                            | 157 +++++++++++++++++++++++
 views/contactForm.pug                    |  18 ---
 views/index.pug                          |  48 -------
 views/langNames.pug                      |   6 -
 views/layout.pug                         |  64 ---------
 views/modalLang.pug                      |  11 --
 views/{modalSettings.pug => modals.pug}  |  31 +++++
 views/userMenu.pug                       |  10 --
 views/variant.pug                        |  60 ---------
 11 files changed, 200 insertions(+), 218 deletions(-)
 rename public/javascripts/{layout.js => app.js} (53%)
 create mode 100644 views/app.pug
 delete mode 100644 views/contactForm.pug
 delete mode 100644 views/index.pug
 delete mode 100644 views/langNames.pug
 delete mode 100644 views/layout.pug
 delete mode 100644 views/modalLang.pug
 rename views/{modalSettings.pug => modals.pug} (62%)
 delete mode 100644 views/userMenu.pug
 delete mode 100644 views/variant.pug

diff --git a/public/javascripts/layout.js b/public/javascripts/app.js
similarity index 53%
rename from public/javascripts/layout.js
rename to public/javascripts/app.js
index 8cb79e0d..28c086b9 100644
--- a/public/javascripts/layout.js
+++ b/public/javascripts/app.js
@@ -3,3 +3,15 @@
 //
 //TODO: si une partie en cours dans storage, rediriger vers cette partie
 //(à condition que l'URL n'y corresponde pas déjà !)
+
+
+	created
+	script.
+		const variant = !{JSON.stringify(variant)};
+		// Just 'V' because this variable is often used:
+		const V = eval(variant.name + "Rules");
+
+
+mounted: function() {
+	feather.replace();
+}
diff --git a/routes/index.js b/routes/index.js
index d510068e..547ae6d1 100644
--- a/routes/index.js
+++ b/routes/index.js
@@ -9,7 +9,6 @@ router.get('/', function(req, res, next) {
 		if (!!err)
 			return next(err);
 		res.render('index', {
-			title: 'club',
 			variantArray: variants,
 			lang: selectLanguage(req, res),
 		});
diff --git a/views/app.pug b/views/app.pug
new file mode 100644
index 00000000..fb9853a3
--- /dev/null
+++ b/views/app.pug
@@ -0,0 +1,157 @@
+doctype html
+html
+
+	head
+		meta(charset="UTF-8")
+		title vchess - club
+		meta(name="viewport" content="width=device-width, initial-scale=1")
+		meta(name="msapplication-config"
+			content="/images/favicon/browserconfig.xml")
+		meta(name="theme-color" content="#ffffff")
+		link(rel="stylesheet"
+			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")
+		link(rel="apple-touch-icon" sizes="180x180"
+			href="/images/favicon/apple-touch-icon.png")
+		link(rel="icon" type="image/png" sizes="32x32"
+			href="/images/favicon/favicon-32x32.png")
+		link(rel="icon" type="image/png" sizes="16x16"
+			href="/images/favicon/favicon-16x16.png")
+		link(rel="manifest" href="/images/favicon/manifest.json")
+		link(rel="mask-icon" href="/images/favicon/safari-pinned-tab.svg"
+			color="#5bbad5")
+		link(rel="shortcut icon" href="/images/favicon/favicon.ico")
+		link(rel="stylesheet" href="/stylesheets/app.css")
+
+	// TODO: on-demand components, do not load all at startup
+	body
+		-
+			var langName = {
+				"en": "English",
+				"es": "Español",
+				"fr": "Français",
+			};
+		case lang
+			when "en"
+				include translations/en
+				include welcome/en
+			when "es"
+				include translations/es
+				include welcome/es
+			when "fr"
+				include translations/fr
+				include welcome/fr
+		include modals
+		main#VueElement
+			my-upsert-user
+			.container
+				// Header (on index only)
+				.row(v-show="display=='index'")
+					.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+						header
+							img(src="/images/index/unicorn.svg")
+							.info-container
+								p vchess.club
+							img(src="/images/index/wildebeest.svg")
+				// Menu (top of page)
+				.row
+					.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+						label.drawer-toggle(for="drawerControl")
+						input#drawerControl.drawer(type="checkbox")
+						#menuBar
+							label.drawer-close(for="drawerControl")
+							a.icon-link(href="/")
+								i(data-feather="home")
+							a(href="#room")
+								=translations["Hall"]
+							a(href="#tabGames")
+								=translations["My games"]
+							a(href="#rules")
+								=translations["Rules"]
+							a(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")
+						#mainTitle.clickable(onClick="doClick('modalWelcome')")
+							.info-container
+								p Introduction
+				.row
+					.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
+				.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"
+						v-bind:vobj="v" v-bind:index="idx" v-bind:key="v.name")
+				.row(v-show="display=='correspondance'")
+					my-correspondance
+				.row
+					my-room(v-show="display=='room'" :conn="conn" :settings="settings")
+					my-tab-games(v-show="display=='tabGames'")
+					my-rules(v-show="display=='rules'" :settings="settings")
+					my-problems(v-show="display=='problems'" :prob-id="probId" :settings="settings")
+					my-game(v-show="display=='game'" :game-ref="gameRef" :conn="conn"
+						:allow-chat="allowChat" :allow-movelist="allowMovelist"
+						:mode="mode" :settings="settings" @game-over="archiveGame")
+
+		footer.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2.text-center
+			div
+				a(href="https://github.com/yagu0/vchess") Source code
+				p.clickable(onClick="document.getElementById('modalContact').checked=true")
+					=translations["Contact form"]
+
+		script.
+			const translations = !{JSON.stringify(translations)};
+			const user = !{JSON.stringify(user)};
+			const variantArray = !{JSON.stringify(variantArray)};
+		// TODO: get rid of underscore
+		// (used essentially for _.random(), _.sample() and _.range())
+		script(src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js")
+		// TODO: add only the necessary icons to mini-css custom build
+		script(src="//unpkg.com/feather-icons")
+		if development
+			script(src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js")
+		else
+			script(src="https://cdn.jsdelivr.net/npm/vue")
+		script(src="/javascripts/utils/printDiagram.js")
+		script(src="/javascripts/utils/datetime.js")
+		script(src="/javascripts/utils/squareId.js")
+		script(src="/javascripts/utils/misc.js")
+		script(src="/javascripts/utils/ajax.js")
+		script(src="/javascripts/utils/array.js")
+		script(src="/javascripts/shared/nbPlayers.js")
+		script(src="/javascripts/shared/challengeCheck.js")
+		script(src="/javascripts/shared/userCheck.js")
+		script(src="/javascripts/components/upsertUser.js")
+		script(src="/javascripts/components/variantSummary.js")
+		script(src="/javascripts/components/correspondance.js")
+		script(src="/javascripts/components/board.js")
+		script(src="/javascripts/components/chat.js")
+		script(src="/javascripts/components/gameList.js")
+		script(src="/javascripts/components/challengeList.js")
+		script(src="/javascripts/components/moveList.js")
+		script(src="/javascripts/components/game.js")
+		script(src="/javascripts/components/rules.js")
+		script(src="/javascripts/components/room.js")
+		script(src="/javascripts/components/tabGames.js")
+		script(src="/javascripts/components/problemSummary.js")
+		script(src="/javascripts/components/problems.js")
+		script(src="/javascripts/base_rules.js")
+		script(src="/javascripts/contactForm.js")
+		script(src="/javascripts/socket_url.js")
+		script(src="/javascripts/index.js")
+		script(src="/javascripts/variant.js")
+		script(src="/javascripts/app.js")
diff --git a/views/contactForm.pug b/views/contactForm.pug
deleted file mode 100644
index a07369e3..00000000
--- a/views/contactForm.pug
+++ /dev/null
@@ -1,18 +0,0 @@
-input#modalContact.modal(type="checkbox")
-div(role="dialog" aria-labelledby="contactTitle")
-	form.card.smallpad
-		label.modal-close(for="modalContact")
-		h3#contactTitle.section= translations["Contact form"]
-		fieldset
-			label(for="userEmail")= translations["Email"]
-			input#userEmail(type="email")
-		fieldset
-			label(for="mailSubject")= translations["Subject"]
-			input#mailSubject(type="text")
-		fieldset
-			label(for="mailContent")= translations["Content"]
-			br
-			textarea#mailContent
-		fieldset
-			button(type="button" onClick="trySendMessage()") Send
-			p#emailSent= translations["Email sent!"]
diff --git a/views/index.pug b/views/index.pug
deleted file mode 100644
index 6ea45166..00000000
--- a/views/index.pug
+++ /dev/null
@@ -1,48 +0,0 @@
-extends layout
-
-block css
-	link(rel="stylesheet", href="/stylesheets/index.css")
-
-block content
-	.container
-		case lang
-			when "en"
-				include welcome/en
-			when "es"
-				include welcome/es
-			when "fr"
-				include welcome/fr
-		.row
-			#header.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
-				#mainTitle.clickable(onClick="doClick('modalWelcome')")
-					img(src="/images/index/unicorn.svg")
-					.info-container
-						p vchess.club
-					img(src="/images/index/wildebeest.svg")
-				#flagMenu.clickable(onClick="doClick('modalLang')")
-					img(src="/images/flags/" + lang + ".svg")
-				include userMenu
-				a.right-menu(v-show="display=='variants'" href="#correspondance")
-					.info-container
-						p Correspondance
-				a.right-menu(v-show="display=='correspondance'" href="#variants")
-					.info-container
-						p Variants
-		.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"
-				v-bind:vobj="v" v-bind:index="idx" v-bind:key="v.name")
-		.row(v-show="display=='correspondance'")
-			my-correspondance
-
-block javascripts
-	script.
-		const variantArray = !{JSON.stringify(variantArray)};
-	script(src="/javascripts/socket_url.js")
-	script(src="/javascripts/components/variantSummary.js")
-	script(src="/javascripts/components/gameList.js")
-	script(src="/javascripts/components/challengeList.js")
-	script(src="/javascripts/components/correspondance.js")
-	script(src="/javascripts/index.js")
diff --git a/views/langNames.pug b/views/langNames.pug
deleted file mode 100644
index 997e5830..00000000
--- a/views/langNames.pug
+++ /dev/null
@@ -1,6 +0,0 @@
--
-	var langName = {
-		"en": "English",
-		"es": "Español",
-		"fr": "Français",
-	};
diff --git a/views/layout.pug b/views/layout.pug
deleted file mode 100644
index b2b1d526..00000000
--- a/views/layout.pug
+++ /dev/null
@@ -1,64 +0,0 @@
-doctype html
-html
-
-	head
-		meta(charset="UTF-8")
-		title vchess - #{title}
-		meta(name="viewport" content="width=device-width, initial-scale=1")
-		meta(name="msapplication-config" content="/images/favicon/browserconfig.xml")
-		meta(name="theme-color" content="#ffffff")
-		link(rel="stylesheet"
-			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")
-		link(rel="apple-touch-icon" sizes="180x180"
-			href="/images/favicon/apple-touch-icon.png")
-		link(rel="icon" type="image/png" sizes="32x32"
-			href="/images/favicon/favicon-32x32.png")
-		link(rel="icon" type="image/png" sizes="16x16"
-			href="/images/favicon/favicon-16x16.png")
-		link(rel="manifest" href="/images/favicon/manifest.json")
-		link(rel="mask-icon" href="/images/favicon/safari-pinned-tab.svg" color="#5bbad5")
-		link(rel="shortcut icon" href="/images/favicon/favicon.ico")
-		link(rel="stylesheet" href="/stylesheets/layout.css")
-		link(rel="stylesheet" href="//fonts.googleapis.com/icon?family=Material+Icons")
-		block css
-
-	body
-		include langNames
-		case lang
-			when "en"
-				include translations/en
-			when "es"
-				include translations/es
-			when "fr"
-				include translations/fr
-		include modalLang
-		include contactForm
-		main#VueElement
-			my-upsert-user()
-			block content
-		footer.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2.text-center
-			div
-				a(href="https://github.com/yagu0/vchess") Source code
-				p.clickable(onClick="document.getElementById('modalContact').checked=true")
-					=translations["Contact form"]
-
-		script(src="//cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js")
-		script(src="/javascripts/utils/misc.js")
-		script(src="/javascripts/utils/ajax.js")
-		script(src="/javascripts/utils/array.js")
-		script(src="/javascripts/base_rules.js")
-		script(src="/javascripts/layout.js")
-		script(src="/javascripts/contactForm.js")
-		if development
-			script(src="https://cdn.jsdelivr.net/npm/vue/dist/vue.js")
-		else
-			script(src="https://cdn.jsdelivr.net/npm/vue")
-		script(src="/javascripts/shared/nbPlayers.js")
-		script(src="/javascripts/shared/challengeCheck.js")
-		script(src="/javascripts/shared/userCheck.js")
-		script(src="/javascripts/components/upsertUser.js")
-		script.
-			const translations = !{JSON.stringify(translations)};
-			const user = !{JSON.stringify(user)};
-		block javascripts
diff --git a/views/modalLang.pug b/views/modalLang.pug
deleted file mode 100644
index b6311829..00000000
--- a/views/modalLang.pug
+++ /dev/null
@@ -1,11 +0,0 @@
-input#modalLang.modal(type="checkbox")
-div(role="dialog")
-	#language.card
-		label.modal-close(for="modalLang")
-		form
-			fieldset
-				label(for="langSelect")= translations["Language"]
-				select#langSelect
-					each language,langCode in langName
-						option(value=langCode selected=(lang==langCode))
-							=language
diff --git a/views/modalSettings.pug b/views/modals.pug
similarity index 62%
rename from views/modalSettings.pug
rename to views/modals.pug
index 3c22c359..e24a7389 100644
--- a/views/modalSettings.pug
+++ b/views/modals.pug
@@ -1,3 +1,15 @@
+input#modalLang.modal(type="checkbox")
+div(role="dialog")
+	#language.card
+		label.modal-close(for="modalLang")
+		form
+			fieldset
+				label(for="langSelect")= translations["Language"]
+				select#langSelect
+					each language,langCode in langName
+						option(value=langCode selected=(lang==langCode))
+							=language
+
 input#modalSettings.modal(type="checkbox")
 div(role="dialog" aria-labelledby="settingsTitle")
 	.card.smallpad(@change="updateSettings")
@@ -33,3 +45,22 @@ div(role="dialog" aria-labelledby="settingsTitle")
 				option(value="0")= translations["None"]
 				option(value="1")= translations["New game"]
 				option(value="2")= translations["All"]
+
+input#modalContact.modal(type="checkbox")
+div(role="dialog" aria-labelledby="contactTitle")
+	form.card.smallpad
+		label.modal-close(for="modalContact")
+		h3#contactTitle.section= translations["Contact form"]
+		fieldset
+			label(for="userEmail")= translations["Email"]
+			input#userEmail(type="email")
+		fieldset
+			label(for="mailSubject")= translations["Subject"]
+			input#mailSubject(type="text")
+		fieldset
+			label(for="mailContent")= translations["Content"]
+			br
+			textarea#mailContent
+		fieldset
+			button(type="button" onClick="trySendMessage()") Send
+			p#emailSent= translations["Email sent!"]
diff --git a/views/userMenu.pug b/views/userMenu.pug
deleted file mode 100644
index 5a0b0743..00000000
--- a/views/userMenu.pug
+++ /dev/null
@@ -1,10 +0,0 @@
-#userMenu.clickable.right-menu(onClick="doClick('modalUser')")
-	.info-container
-		if !user.email
-			p
-				span Login
-				i.material-icons person
-		else
-			p
-				span Update
-				i.material-icons person
diff --git a/views/variant.pug b/views/variant.pug
deleted file mode 100644
index 7e57bbf5..00000000
--- a/views/variant.pug
+++ /dev/null
@@ -1,60 +0,0 @@
-extends layout
-
-block css
-	link(rel="stylesheet" href="/stylesheets/variant.css")
-
-block content
-	include modalSettings
-	.container
-		.row
-			.col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2
-				label.drawer-toggle(for="drawer-control")
-				input#drawer-control.drawer(type="checkbox")
-				#menuBar
-					label.drawer-close(for="drawer-control")
-					a.icon-link(href="/")
-						i.material-icons home
-					a(href="#room")
-						=translations["Hall"]
-					a(href="#tabGames")
-						=translations["My games"]
-					a(href="#rules")
-						=translations["Rules"]
-					a(href="#problems")
-						=translations["Problems"]
-					#flagMenu.clickable(onClick="doClick('modalLang')")
-						img(src="/images/flags/" + lang + ".svg")
-					#settings.clickable(onClick="doClick('modalSettings')")
-						i.material-icons settings
-					include userMenu
-		.row
-			my-room(v-show="display=='room'" :conn="conn" :settings="settings")
-			my-tab-games(v-show="display=='tabGames'")
-			my-rules(v-show="display=='rules'" :settings="settings")
-			my-problems(v-show="display=='problems'" :prob-id="probId" :settings="settings")
-			my-game(v-show="display=='game'" :game-ref="gameRef" :conn="conn"
-				:allow-chat="allowChat" :allow-movelist="allowMovelist"
-				:mode="mode" :settings="settings" @game-over="archiveGame")
-
-block javascripts
-	script(src="/javascripts/utils/printDiagram.js")
-	script(src="/javascripts/utils/datetime.js")
-	script(src="/javascripts/utils/squareId.js")
-	script(src="/javascripts/socket_url.js")
-	script(src="/javascripts/variants/" + variant.name + ".js")
-	script.
-		const variant = !{JSON.stringify(variant)};
-		// Just 'V' because this variable is often used:
-		const V = eval(variant.name + "Rules");
-	script(src="/javascripts/components/board.js")
-	script(src="/javascripts/components/chat.js")
-	script(src="/javascripts/components/gameList.js")
-	script(src="/javascripts/components/challengeList.js")
-	script(src="/javascripts/components/moveList.js")
-	script(src="/javascripts/components/game.js")
-	script(src="/javascripts/components/rules.js")
-	script(src="/javascripts/components/room.js")
-	script(src="/javascripts/components/tabGames.js")
-	script(src="/javascripts/components/problemSummary.js")
-	script(src="/javascripts/components/problems.js")
-	script(src="/javascripts/variant.js")
-- 
2.44.0