From ff0150d1eb0ce3778310e67bb4ce87d0666a37d7 Mon Sep 17 00:00:00 2001 From: Benjamin Auder <benjamin.auder@somewhere> Date: Thu, 23 Apr 2020 19:05:43 +0200 Subject: [PATCH] Replace news by FAQ --- TODO | 1 + client/src/App.vue | 19 +-- client/src/router.js | 6 +- client/src/translations/en.js | 1 - client/src/translations/faq/en.pug | 158 +++++++++++++++++++ client/src/translations/faq/es.pug | 177 +++++++++++++++++++++ client/src/translations/faq/fr.pug | 171 ++++++++++++++++++++ client/src/translations/fr.js | 1 - client/src/variants/Teleport.js | 11 +- client/src/views/Faq.vue | 67 ++++++++ client/src/views/News.vue | 245 ----------------------------- server/db/create.sql | 8 - server/models/News.js | 78 --------- server/routes/all.js | 1 - server/routes/news.js | 55 ------- 15 files changed, 585 insertions(+), 414 deletions(-) create mode 100644 client/src/translations/faq/en.pug create mode 100644 client/src/translations/faq/es.pug create mode 100644 client/src/translations/faq/fr.pug create mode 100644 client/src/views/Faq.vue delete mode 100644 client/src/views/News.vue delete mode 100644 server/models/News.js delete mode 100644 server/routes/news.js diff --git a/TODO b/TODO index c525e789..ec7d9756 100644 --- a/TODO +++ b/TODO @@ -1,5 +1,6 @@ Issue: embedded rules language not updated when language is set (in Analyse, Game and Problems) Also: if new live game starts in background, "new game" notify OK but not first move (not too serious however) +On smartphone for Teleport, Chakart, Weiqi and some others: wait re-click to confirm "touch" move (in Board.vue) https://www.chessvariants.com/crossover.dir/koopachess.html --> Can a stunned piece capture? Maybe not. ...recover? After 5 moves? Never? diff --git a/client/src/App.vue b/client/src/App.vue index 02693a62..5729c380 100644 --- a/client/src/App.vue +++ b/client/src/App.vue @@ -33,7 +33,7 @@ .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 footer router-link.menuitem(to="/about") {{ st.tr["About"] }} - router-link.menuitem#newsMenu(to="/news") {{ st.tr["News"] }} + router-link.menuitem(to="/faq") F.A.Q. a.menuitem(href="https://discord.gg/a9ZFKBe") span Discord img(src="/images/icons/discord.svg") @@ -59,18 +59,6 @@ export default { data: function() { return { st: store.state }; }, - mounted: function() { - ajax( - "/newsts", - "GET", - { - success: (res) => { - if (this.st.user.newsRead < res.timestamp) - document.getElementById("newsMenu").classList.add("somenews"); - } - } - ); - }, computed: { userName: function() { return ( @@ -297,9 +285,4 @@ footer height: 55px display: block padding: 5px 0 - -.menuitem.somenews - color: red - &:link, &:visited, &:hover - color: red </style> diff --git a/client/src/router.js b/client/src/router.js index c5afb17d..c51c8862 100644 --- a/client/src/router.js +++ b/client/src/router.js @@ -62,9 +62,9 @@ const router = new Router({ component: loadView("About") }, { - path: "/news", - name: "news", - component: loadView("News") + path: "/faq", + name: "faq", + component: loadView("Faq") } ] }); diff --git a/client/src/translations/en.js b/client/src/translations/en.js index 6180f97b..909a3e35 100644 --- a/client/src/translations/en.js +++ b/client/src/translations/en.js @@ -84,7 +84,6 @@ export const translations = { "New correspondance game:": "New correspondance game:", "New game": "New game", "New problem": "New problem", - News: "News", "No challenges found :( Click on 'New game'!": "No challenges found :( Click on 'New game'!", "No games found :( Send a challenge!": "No games found :( Send a challenge!", "No more problems": "No more problems", diff --git a/client/src/translations/faq/en.pug b/client/src/translations/faq/en.pug new file mode 100644 index 00000000..0d5ae9ed --- /dev/null +++ b/client/src/translations/faq/en.pug @@ -0,0 +1,158 @@ +.question. + Where should I start? +.answer. + The "Variants" menu on top contains the list of all playable games. + If you know what you want, the "prefix" filter might be useful. + Then, read the rules, and optionally watch an example game or play a game + against the computer. Keep in mind that the "engine" is generally quite weak. + It's here for illustration and learning purpose only. + +.question. + The bot is too weak! Where should I continue? +.answer + | I'm glad you ask. Since I believe that a place is more fun with nice people + | around, the next step is to play against humans. + | Go to main "Hall" (upper left menu), and first look if a live or + | correspondance challenge interests you. If yes just click on it. Challenges + | highlighted in orange are targeted: someone wants to play against you, + | specifically, optionally from a custom starting position. + | If there aren't any interesting challenge, then click on "New game" in the + | upper right corner. Select a variant, and + ul + li. + Adjust the cadence: format is + 'main time + increment' with default units minutes and seconds. + If the main time is given in days then the game is considered by + correspondance. + li. + Select the randomness level: 'deterministic' always show the same setup, + the one you are generally used to. + | You can also click on "Who's there" and select a player to + | challenge. The "memorize" checkbox allows to store the challenge settings + | to re-issue it in one click later. + +.question. + I'm bored of being anonymous, I want a name! +.answer. + Very good idea: click on "Login" in the upper right corner, and then switch + to the registration view (using the link appearing in dark red). + Only a username and an email are required. + Once signed up, you should log in within the next 24 hours or your 'account' + will be deleted (you can re-do this process anytime later of course). + This will also allow you to play correspondance games. + Note: the authentication is passwordless, as most websites should be. + +.question. + How can I talk to my opponent? Ask rematch? +.answer. + Just click on the Chat icon on top. It turns purple when new messages arrive. + After the game ends, the Swords icon next to it is the rematch button: + it turns green when you receive a rematch offer. + +.question. + I made a bad move, I want to take it back! +.answer + | It's not possible for now. However, there is a way to continue the game: + ol + li Click on the Analyze button, and go back just before the bad move. + li Copy the FEN displayed below the board (the weird long string). + li. + Go to main Hall, open "New game" window, select your opponent, + and then paste the FEN in the appropriate field. + +.question. + I'm streaming a game, and would like to use arrows and circles. +.answer. + A right click on a square draws a purple circle inside, and a second right + click erases it. + 'Drag and drop' with the right mouse button from a square to another to draw + a purple arrow. Click anywhere with the left mouse button to erase all + drawings. + +.question. + I want to start from a custom position! +.answer. + If the desired position is on a board on the website, just click on the + Analyze button (microscope icon), and then copy the string appearing + below the board. If the position is in your mind or on a physical board, + then you can either try to understand the FEN format by trials and errors + from the Analysis mode, or ask me - using the Contact form or on Discord. + By the way, FEN are required to post in the "Problems" menu as well. + +.question. + I want a rating! I want tournaments! I want a new poney! +.answer. + In my experience, caring about a rating only complicate your life, + so there won't be any around here. There probably won't be any tournaments + support on the website, but some may be organized anyway. Do the pairings + somewhere else and ask people to challenge each other. + +.question. + You said "Problems" menu? What's that? +.answer. + An area where you can upload interesting positions, which could be studies, + (self-)mate in 3 and so on. For the moment there is no support for proof + games, but you could still provide the final diagram to let people search. + Start by looking at the existing problems, and try to solve them :-) + +.question. + I'm in Hall but cannot see my games! +.answer. + Your games are gathered in "My games" menu on top. + If a game is highlighted in orange, then it's your turn: click on it and + play! You can have as many running games as you like in either live or + correspondance. + +.question. + Clocks in live games sometimes freeze. +.answer + | The clocks in live games follow a non-standard logic - but sounded, I + | believe :-) + ul + li. + If you play a move and then quit the game, your clock will be + frozen at its current state until you come back in the game. After his move + your opponent will see your clock stopped; he could decide to abort or + resign, or + li. + If your opponent also quits the game after playing, then the time is + just frozen - and you can decide to continue it later. + | The rational behind this is that you don't know what the opponent played, + | so your clock shouldn't be running. Ans it also allows to take a break in + | long live games, like maybe 1h30 + 30s. + +.question. + I bookmarked a fascinating observed game, but the URL no longer works. +.answer + | Live games are stored locally, on browsers only. + | If you are only an observer, your browser doesn't even store it, so later + | the game won't be reachable if the players and all observers leave the game. + | Consequently, the right way to go is + ol + li Download the game (see the icon on the right), + li Import it using the button in "Imported games" tab in "My Games" menu. + +.question. + I cleaned the website data, and all my live games are gone! +.answer. + They are stored in your browser's database. + You just erased it, so the games are gone :-) + More flexible cleaning can be achieved: removing cookies is harmless (you'll + just need to re-login), as well as removing local storage data (your + preferences about board color and sounds will be reset). But touching + 'IndexedDB' will remove all local games. + +.question. + But I would like to remove this specific game, and this one too! +.answer. + Click on the game result area from "My Games" listings, and confirm deletion. + If the game is running this will abort it first. + Note that correspondance games deleted by only one player are still + reachable: they are just hidden for you. + +.question. + I've a question not answered here! +.answer. + If the answer isn't 42 (are you really sure?), then use the contact form, + or ask on Discord :-) + See the links in the website footer. diff --git a/client/src/translations/faq/es.pug b/client/src/translations/faq/es.pug new file mode 100644 index 00000000..2344cabc --- /dev/null +++ b/client/src/translations/faq/es.pug @@ -0,0 +1,177 @@ +.question. + ¿Por donde empiezo? +.answer. + El menú "Variantes" en la parte superior contiene la lista de todos los + juegos disponibles. + Si sabe cuál quiere, el filtro "prefijo" puede ser útil. + Luego lea las reglas y posiblemente vea una partida de ejemplo o + juega uno contra la computadora. Tenga en cuenta que este oponente es + en general bastante débil. + Se utiliza solo para ilustrar y aprender las reglas. + +.question. + ¡La computadora está jugando demasiado mal! ¿Dónde debo continuar? +.answer + | Me gusta esta pregunta. Para mà un lugar es más agradable con + | gente comprensivo, asà que el siguiente paso es jugar contra + | humanos. Vaya al "Salón" principal (menú superior izquierda) y + | primero averigua si estás interesado en un desafÃo en vivo o por + | correspondencia. En caso afirmativo, simplemente haga clic en él. + | Los desafÃos resaltados en naranja son apuntado: alguien quiere jugar + | contra ti, especÃficamente, tal vez desde una posición inicial particular. + | Si ningún desafÃo es interesante, haga clic en "Nueva partida" en + | la esquina superior derecha. Elija una variante, luego + ul + li. + Ajuste la cadencia: el formato es 'tiempo principal + incremento', por + defecto en minutos y segundos. Si el tiempo principal se da en dÃas, + la parte se considera por correspondencia. + li. + Seleccione el nivel de aleatoriedad: 'determinista' para tener siempre + el misma configuración inicial, probablemente en la que estás + acostumbrado a. + | También puedes hacer clic en "Quién está allÃ" y elegir un jugador para + | desafiar. El cuadro "memorizar" permite almacenar los parámetros del + | desafÃo para el relanzar más tarde. + +.question. + Estoy cansado de ser anónimo, ¡quiero un nombre! +.answer. + Gran idea: haga clic en "Login" en la esquina superior derecha, luego cambie + en la vista de registro (a través del enlace en rojo oscuro que aparece en + arriba). Solo se requiere su nombre de usuario y un correo electrónico. + Una vez registrado, debe iniciar sesión en las próximas 24 horas de lo + contrario su 'cuenta' se elimina (puede comenzar de nuevo en cualquier + momento tarde por supuesto). + Nota: la autenticación se realiza sin contraseña, como deberÃa + sea el caso en la mayorÃa de los sitios. + +.question. + ¿Cómo puedo hablar con el oponente? Solicitar venganza? +.answer. + Simplemente haga clic en el icono de Chat en la parte superior. + Se vuelve púrpura cuando llega un nuevo mensaje. Cuando la partida termina, + el Ãcono de Espadas al lado permite reiniciar un juego: + se vuelve verde cuando el oponente quiere repetición. + +.question. + Hice un mal movimiento, ¡quiero volver! +.answer + | No es posible por el momento. Sin embargo, aquà hay una manera de + | continuar el juego: + ol + li. + Haga clic en el botón Análisis y regrese justo antes del movimiento + incorrecto. + li + Copie el FEN que se muestra debajo del tablero de ajedrez (la cadena + larga y extraña). + li. + Vaya al Salón, abra la ventana "Nueva partida", seleccione + su oponente y luego pegue el FEN en el campo apropiado. + +.question. + Estoy transmitiendo un juego en vivo, y me gustarÃa usar flechas y + cÃrculos. +.answer. + Haga clic derecho en un cuadro dibuja un cÃrculo morado en el interior, y un + segundo clic derecho lo borra. + 'Arrastra y suelta' con el botón derecho de un cuadro a otro dibujo + una flecha morada. Haga clic izquierdo en cualquier lugar para + eliminar dibujos. + +.question. + ¡Quiero comenzar desde una posición especÃfica! +.answer. + Si la posición deseada es en un tablero en algún lugar del sitio, + simplemente haga clic en el botón Análisis (el icono del microscopio) y + copie el cadena que aparece debajo del tablero. Si la posición está en tu + cabeza o en un tablero de ajedrez fÃsico, entonces puedes buscar entender el + formato FEN por prueba y error en modo Análisis, o pregúntame a través del + formulario de contacto o en Discord. El pasaje, + estas cadenas FEN también son necesarias para publicar un problema. + +.question. + ¡Quiero un ranking! ¡Quiero torneos! ¡Quiero un nuevo pony! +.answer. + En mi experiencia, preocuparse por un ranking solo te hace + complicar la vida, por lo que no habrá ninguno en este sitio. + Nada esta planeado ya no se trata de torneos, pero puedes organizarlos de + todos modos. Haga los emparejamientos en otro lugar y pÃdale a la gente que + desafÃo. + +.question. + ¿Mencionaste el menú "Problemas"? Que es eso ? +.answer. + Un espacio donde puedes compartir posiciones interesantes, que podrÃan + ser estudios, mat (ayudado) en 3 etc. Actualmente no hay + soporte para análisis retrógrado, pero aún podrÃa enviar + el diagrama final para permitir que las personas busquen. + Comience mirando los problemas existentes e intente resolverlos. + :-) + +.question. + ¡Estoy en el Salón pero no veo mis partidas! +.answer. + Sus partidas se agrupan en el menú "Mis partidas" en la parte superior. + Si un juego está resaltado en naranja, entonces es tu turno: haga clic en + arriba y juega! El número de partidas en progreso en vivo o por + correspondencia no es limitada. + +.question. + En un juego en vivo, el péndulo a veces se detiene. +.answer + | Los péndulos en las partidas en vivo siguen una lógica no estándar + | - pero consistente, creo :-) + ul + li. + Si haces un movimiento y luego sales del juego, tu péndulo se congelará + en su estado actual hasta que vuelvas al juego. + Despues su movimiento, tu oponente verá tu tiempo detenido; + él podrÃa decidir para detener el juego o rendirse, o + li. + Si tu oponente también abandona el juego después de su movimiento, + entonces el tiempo está congelado y puede decidir reanudarlo más tarde. + | De hecho, ya que no sabes lo que jugó el oponente, es + | normal para que su péndulo se detenga. También te permite tomar un + | descanso durante una larga partida en vivo, como 1h30 + 30s, por ejemplo. + +.question. + Anoté la dirección de una partida fascinante, pero la URL ya no funciona. +.answer + | Los juegos en vivo se almacenan localmente en el navegador + | solamente. Si eres un simple espectador, tu navegador no registra + | ni siquiera el juego, por lo que será inaccesible cuando los jugadores + | asà como todos los observadores se habrán ido. + | La forma correcta de hacer esto es + ol + li Descargue la partida (vea el icono a la derecha), + li. + Importarlo usando el botón en la pestaña "Partidas importadas" + desde el menú "Mis partidas". + +.question. + ¡Eliminé los datos del sitio y mis partidas en vivo han desaparecido! +.answer. + Se almacenan en la base de datos del navegador. + Simplemente lo eliminó, por lo que ya no están allà :-) + Se requiere una limpieza más fina: eliminar las cookies es inofensivo + (solo tendrá que iniciar sesión de nuevo), asà como la eliminación de los + datos local (guardando sus preferencias como el color del tablero). + Sin embargo, tocar la base de datos 'IndexedDB' puede eliminar partidas. + +.question. + Pero me gustarÃa eliminar esta parte allÃ, ¡y esta también! +.answer. + Haz clic en el área de resultados del juego en la lista "Mis partidas", + y confirme la eliminación. Si el juego está en progreso, será primero + detuvo. Tenga en cuenta que las partidas de correspondencia borradas por + solo uno de los dos jugadores siempre están accesibles: simplemente están + ocultos para ti. + +.question. + Tengo una pregunta sin respuesta aquÃ! +.answer. + Si la respuesta no es 42 (¿estás seguro?), usa el formulario + de Contacta o pregunta en Discord :-) + Vea los enlaces al final de la página. diff --git a/client/src/translations/faq/fr.pug b/client/src/translations/faq/fr.pug new file mode 100644 index 00000000..e9ecd095 --- /dev/null +++ b/client/src/translations/faq/fr.pug @@ -0,0 +1,171 @@ +.question. + Par où dois-je commencer ? +.answer. + Le menu "Variantes" en haut contient la liste de touts les jeux disponibles. + Si vous savez lequel vous voulez, le filtre "préfixe" peut être utile. + Ensuite, lisez les règles, et éventuellement regardez une partie exemple ou + jouez-en une contre l'ordinateur. Gardez à l'esprit que cet adversaire est + en général plutôt faible. + Il sert à illustrer et à apprendre les règles seulement. + +.question. + L'ordinateur joue trop mal ! Où dois-je continuer ? +.answer + | Cette question me plaît. Pour moi un endroit est plus agréable avec des + | gens sympas autour, donc la prochaine étape est de jouer contre des + | humains. Allez dans le "Salon" principal (menu en haut à gauche), et + | regardez d'abord si un défi en direct ou par correspondance vous intéresse. + | Si oui cliquez simplement dessus. Les défis surlignés en orange sont + | ciblés : quelqu'un veut jouer contre vous, spécifiquement, peut-être + | depuis une position initiale particulière. + | Si aucun défi n'est intéressant, alors cliquez sur "Nouvelle partie" dans + | le coin en haut à droite. Choisissez une variante, puis + ul + li. + Ajustez la cadence : le format est 'temps principal + incrément', par + défaut en minutes et secondes. Si le temps principal est donnée en jours, + la partie est considérée par correspondance. + li. + Sélectionnez le niveau d'alea : 'déterministe' pour avoir toujours la + même configuration initiale, sans doute celle à laquelle vous êtes + habitués. + | Vous pouvez aussi cliquer sur "Qui est là " et choisir un joueur à défier. + | La case "mémoriser" permet de stocker les paramètres du défi pour le + | re-lancer plus tard. + +.question. + J'en ai marre d'être anonyme, je veux un nom ! +.answer. + Excellente idée : cliquez sur "Login" dans le coin haut droit, puis basculez + sur la vue d'enregistrement (via le lien en rouge foncé apparaissant en + haut). Seuls votre nom d'utilisateur ainsi qu'une adresse email sont requis. + Une fois inscrit, vous devez vous logger dans les prochaines 24 heures sinon + votre 'compte' est supprimé (vous pouvez recommencer n'importe quand plus + tard bien sûr). + Note : l'authentification s'effectue sans mot de passe, comme cela devrait + être le cas sur la plupart des sites. + +.question. + Comment puis-je parler à l'adversaire ? Demander une revanche ? +.answer. + Cliquez simplement sur l'icône Chat en haut. Il devient violet quand un + nouveau message arrive. Une fois la partie terminée, l'icône Ãpées à côté + permet de relancer une partie : il devient vert lorsque l'adversaire veut + rejouer. + +.question. + J'ai joué un mauvais coup, je veux revenir en arrière ! +.answer + | Ce n'est pas possible pour le moment. Cependant, voici une façon de + | continuer la partie : + ol + li Cliquez sur le bouton Analyse, et revenez juste avant le mauvais coup. + li Copiez la FEN indiquée sous l'échiquier (la longue chaîne bizarre). + li. + Allez dans le Salon, ouvrez la fenêtre "Nouvelle partie", sélectionnez + votre adversaire et collez ensuite la FEN dans le champ approprié. + +.question. + Je diffuse une partie en direct, et aimerais utiliser des flèches et des + cercles. +.answer. + Un clic droit sur une case dessine un cercle violet à l'intérieur, et un + second clic droit l'efface. + 'Glisser déposer' avec le bouton droit depuis une case vers une autre dessine + une flèche violette. Cliquez n'importe où avec le bouton gauche pour + effacer les dessins. + +.question. + Je veux démarrer depuis une position spécifique ! +.answer. + SI la position souhaitée est sur un échiquier quelque part sur le site, + cliquez simplement sur le bouton Analyse (l'icône microscope), et copiez la + chaîne apparaissant sous l'échiquier. Si la position est dans votre tête ou + sur un échiquier physique, alors vous pouvez soit chercher à comprendre le + format FEN par essais et erreurs dans le mode Analyse, ou bien + me demander - via le formulaire de contact ou sur Discord. Au passage, + ces chaînes FEN sont nécessaires également pour poster un problème. + +.question. + Je veux un classement ! Je veux des tournois ! Je veux un nouveau poney ! +.answer. + D'après mon expérience, s'inquiéter pour un classement ne fait que vous + compliquer la vie, donc il n'y en aura pas sur ce site. Rien n'est prévu + non plus concernant les tournois, mais vous pouvez en organiser quand-même. + Effectuez les appariements quelque part ailleurs et demandez aux gens de se + défier. + +.question. + T'as mentionné le menu "Problèmes" ? C'est quoi ça ? +.answer. + Un espace où vous pouvez partager des positions intéressantes, qui pourraient + être des études, des mat (aidés) en 3 etc. Actuellement il n'y a pas de + support pour l'analyse rétrograde, mais vous pourriez tout de même envoyer + le diagramme final pour permettre aux gens de chercher. + Commencez par regarder les problèmes existants, et essayez de les résoudre + :-) + +.question. + Je suis dans le Salon mais ne vois pas mes parties ! +.answer. + Vos parties sont rassemblées dans le menu "Mes parties" en haut. + Si une partie est surlignée en orange, alors c'est à vous de jouer : cliquez + dessus et jouez ! Le nombre de parties en cours en direct ou par + correspondance n'est pas limité. + +.question. + Dans une partie en direct, la pendule s'arrête parfois. +.answer + | Les pendules dans les parties en direct suivent une logique non standard + | - mais cohérente, je crois :-) + ul + li. + Si vous jouez un coup puis quittez la partie, votre pendule sera figée + dans son état courant jusqu'à ce que vous reveniez dans le jeu. Après + son coup, votre adversaire verra votre temps arrêté ; il pourrait décider + d'arrêter la partie ou d'abandonner, ou + li. + Si votre adversaire quitte lui aussi la partie après son coup, alors le + temps est juste figé - et vous pouvez décider de reprendre plus tard. + | En effet puisque vous ne savez pas ce qu'a joué l'adversaire, il est + | normal que votre pendule s'arrête. Cela permet aussi de faire une pause + | pendant une longue partie en direct, comme 1h30 + 30s par exemple. + +.question. + J'ai noté l'adresse d'une partie fascinante, mais l'URL ne fonctionne plus. +.answer + | Les parties en direct sont stockées localement, dans le navigateur + | seulement. Si vous êtes un simple spectateur, votre navigateur n'enregistre + | même pas la partie, donc celle-ci sera inaccessible lorsque les joueurs + | ainsi que tous les observateurs seront partis. + | La bonne manière de procéder consiste alors à + ol + li Télécharger la partie (cf. l'icône sur la droite), + li. + L'importer en utilisant le bouton dans l'onglet "Parties importées" + depuis le menu "Mes parties". + +.question. + J'ai effacé les données du site, et mes parties en direct ont disparu ! +.answer. + Elles sont stockées dans la base de données du navigateur. + Vous venez de l'effacer, donc elles ne sont plus là :-) + Un nettoyage plus fin est requis : supprimer les cookies est sans danger + (vous devrez juste vous re-logger), de même que la suppression des données + locales (enregistrant vos préférences comme la couleur de l'échiquier). + Cependant, toucher à la base 'IndexedDB' risque de supprimer des parties. + +.question. + Mais j'aimerais supprimer cette partie là , et celle-là aussi ! +.answer. + Cliquez sur la zone du résultat d'une partie depuis les listes "Mes parties", + et confirmez la suppression. Si la partie est en cours elle sera d'abord + arrêtée. Notez que les parties par correspondance supprimées par un seul des + deux joueurs sont toujours accessibles : elles vous sont juste cachées. + +.question. + J'ai une question sans réponse ici ! +.answer. + Si la réponse n'est pas 42 (êtes vous bien sûr ?), utilisez le formulaire de + Contact ou demandez sur Discord :-) + Cf. les liens en bas de la page. diff --git a/client/src/translations/fr.js b/client/src/translations/fr.js index 9ee109f5..f14632e3 100644 --- a/client/src/translations/fr.js +++ b/client/src/translations/fr.js @@ -84,7 +84,6 @@ export const translations = { "New correspondance game:": "Nouvelle partie par corespondance :", "New game": "Nouvelle partie", "New problem": "Nouveau problème", - News: "Nouvelles", "No challenges found :( Click on 'New game'!": "Aucun défi trouvé :( Cliquez sur 'Nouvelle partie' !", "No games found :( Send a challenge!": "Aucune partie trouvée :( Envoyez un défi !", "No more problems": "Plus de problèmes", diff --git a/client/src/variants/Teleport.js b/client/src/variants/Teleport.js index 2379692a..93648c48 100644 --- a/client/src/variants/Teleport.js +++ b/client/src/variants/Teleport.js @@ -299,10 +299,13 @@ export class TeleportRules extends ChessRules { moves2.forEach(m2 => { this.play(m2); const score = this.getCurrentScore(); - const mvEval = - ["1-0", "0-1"].includes(score) - ? (score == "1-0" ? 1 : -1) * maxeval - : (score == "1/2" ? 0 : initEval); + let mvEval = 0; + if (["1-0", "0-1"].includes(score)) + mvEval = (score == "1-0" ? 1 : -1) * maxeval; + else if (score == "*") + // Add small fluctuations to avoid dropping pieces always on the + // first square available. + mvEval = initEval + 0.05 - Math.random() / 10; if ( (color == 'w' && mvEval > m.eval) || (color == 'b' && mvEval < m.eval) diff --git a/client/src/views/Faq.vue b/client/src/views/Faq.vue new file mode 100644 index 00000000..a87e6bd7 --- /dev/null +++ b/client/src/views/Faq.vue @@ -0,0 +1,67 @@ +<template lang="pug"> +main + .row + .col-sm-12.col-md-8.col-md-offset-2.col-lg-6.col-lg-offset-3 + div#faqDiv(v-html="content") +</template> + +<script> +import { store } from "@/store"; +export default { + name: "my-faq", + data: function() { + return { st: store.state }; + }, + computed: { + content: function() { + // (AJAX) Request to get FAQ content (plain text, HTML) + return ( + require("raw-loader!@/translations/faq/" + this.st.lang + ".pug") + // Next two lines fix a weird issue after last update (2019-11) + .replace(/\\n/g, " ") + .replace(/\\"/g, '"') + .replace('module.exports = "', "") + .replace(/"$/, "") + ); + } + }, + mounted: function() { + this.re_setListeners(); + }, + updated: function() { + this.re_setListeners(); + }, + methods: { + re_setListeners: function() { + document.querySelectorAll(".answer").forEach(a => { + a.style.display = "none"; + }); + document.querySelectorAll(".question").forEach(q => { + q.addEventListener("click", (e) => { + let answerDiv = e.target.nextSibling; + const answerVisible = (answerDiv.style.display == "block"); + answerDiv.style.display = (answerVisible ? "none" : "block"); + }); + }); + } + } +}; +</script> + +<style lang="sass"> +#faqDiv + @media screen and (max-width: 767px) + margin-left: var(--universal-margin) + margin-right: var(--universal-margin) + +.question + color: darkblue + font-size: 1.1em + margin-top: 15px + cursor: pointer + +.answer + ol, ul + margin-top: 0 + margin-bottom: 0 +</style> diff --git a/client/src/views/News.vue b/client/src/views/News.vue deleted file mode 100644 index 664b5957..00000000 --- a/client/src/views/News.vue +++ /dev/null @@ -1,245 +0,0 @@ -<template lang="pug"> -main - input#modalNews.modal(type="checkbox") - div#newnewsDiv( - role="dialog" - data-checkbox="modalNews" - ) - .card#writeNews - label.modal-close(for="modalNews") - textarea#newsContent( - v-model="curnews.content" - :placeholder="st.tr['News go here']" - @input="adjustHeight" - ) - button(@click="sendNews()") {{ st.tr["Send"] }} - #dialog.text-center {{ st.tr[infoMsg] }} - .row - .col-sm-12.col-md-10.col-md-offset-1.col-lg-8.col-lg-offset-2 - button#writeNewsBtn( - v-if="devTeam" - @click="showModalNews" - ) - | {{ st.tr["Write news"] }} - .news( - v-for="n,idx in newsList" - :id="'n' + n.id" - :class="{margintop:idx>0}" - ) - span.ndt {{ formatDatetime(n.added) }} - .dev-buttons(v-if="devTeam") - button(@click="editNews(n)") {{ st.tr["Edit"] }} - button(@click="deleteNews(n)") {{ st.tr["Delete"] }} - button(@click="gotoPrevNext(n, 1)") {{ st.tr["Previous_n"] }} - button(@click="gotoPrevNext(n, -1)") {{ st.tr["Next_n"] }} - .news-content(v-html="parseHtml(n.content)") - button#loadMoreBtn( - v-if="hasMore" - @click="loadMore()" - ) - | {{ st.tr["Load more"] }} -</template> - -<script> -import { store } from "@/store"; -import { ajax } from "@/utils/ajax"; -import params from "@/parameters"; -import { getDate, getTime } from "@/utils/datetime"; -import { processModalClick } from "@/utils/modalClick"; -export default { - name: "my-news", - data: function() { - return { - st: store.state, - // timestamp of oldest showed news: - cursor: Number.MAX_SAFE_INTEGER, - // hasMore == TRUE: a priori there could be more news to load - hasMore: true, - curnews: { id: 0, content: "" }, - newsList: [], - infoMsg: "" - }; - }, - computed: { - devTeam: function() { - return params.devs.includes(this.st.user.id); - } - }, - created: function() { - ajax( - "/news", - "GET", - { - data: { cursor: this.cursor }, - success: (res) => { - // The returned list is sorted from most recent to oldest - this.newsList = res.newsList; - const L = res.newsList.length; - if (L > 0) this.cursor = res.newsList[L - 1].added; - else this.hasMore = false; - } - } - ); - }, - mounted: function() { - // Mark that I've read the news: - localStorage.setItem("newsRead", Date.now()); - if (this.st.user.id > 0) ajax("/newsread", "PUT"); - document.getElementById("newsMenu").classList.remove("somenews"); - document - .getElementById("newnewsDiv") - .addEventListener("click", processModalClick); - }, - methods: { - formatDatetime: function(dt) { - const dtObj = new Date(dt); - const timePart = getTime(dtObj); - // Show minutes but not seconds: - return ( - getDate(dtObj) + " " + timePart.substr(0, timePart.lastIndexOf(":")) - ); - }, - parseHtml: function(txt) { - return !txt.match(/<[/a-zA-Z]+>/) - ? txt.replace(/\n/g, "<br/>") //no HTML tag - : txt; - }, - adjustHeight: function() { - const newsContent = document.getElementById("newsContent"); - // https://stackoverflow.com/a/995374 - newsContent.style.height = "1px"; - newsContent.style.height = 10 + newsContent.scrollHeight + "px"; - }, - resetCurnews: function() { - this.curnews.id = 0; - this.curnews.content = ""; - // No need for added and uid fields: never updated - }, - gotoPrevNext: function(n, dir) { - document.getElementById("n" + n.id)[ - (dir < 0 ? "previous" : "next") + "ElementSibling"].scrollIntoView(); - }, - showModalNews: function() { - this.resetCurnews(); - window.doClick("modalNews"); - }, - sendNews: function() { - const edit = this.curnews.id > 0; - this.infoMsg = "Processing... Please wait"; - ajax( - "/news", - edit ? "PUT" : "POST", - { - data: { news: this.curnews }, - success: (res) => { - if (edit) { - let n = this.newsList.find(n => n.id == this.curnews.id); - if (!!n) n.content = this.curnews.content; - } else { - const newNews = { - content: this.curnews.content, - added: Date.now(), - uid: this.st.user.id, - id: res.id - }; - this.newsList = [newNews].concat(this.newsList); - } - document.getElementById("modalNews").checked = false; - this.infoMsg = ""; - this.resetCurnews(); - } - } - ); - }, - editNews: function(n) { - this.curnews.content = n.content; - this.curnews.id = n.id; - // No need for added and uid fields: never updated - window.doClick("modalNews"); - }, - deleteNews: function(n) { - if (confirm(this.st.tr["Are you sure?"])) { - this.infoMsg = "Processing... Please wait"; - ajax( - "/news", - "DELETE", - { - data: { id: n.id }, - success: () => { - const nIdx = this.newsList.findIndex(nw => nw.id == n.id); - this.newsList.splice(nIdx, 1); - this.infoMsg = ""; - document.getElementById("modalNews").checked = false; - } - } - ); - } - }, - loadMore: function() { - ajax( - "/news", - "GET", - { - data: { cursor: this.cursor }, - success: (res) => { - const L = res.newsList.length; - if (L > 0) { - this.newsList = this.newsList.concat(res.newsList); - this.cursor = res.newsList[L - 1].added; - } else this.hasMore = false; - } - } - ); - } - } -}; -</script> - -<style lang="sass" scoped> -[type="checkbox"].modal+div .card - max-width: 767px - max-height: 100% - -textarea#newsContent - margin: 0 - width: 100% - min-height: 200px - max-height: 100% - -#dialog - padding: 5px - color: blue - -#writeNews - padding-top: 50px - -button#writeNewsBtn, button#loadMoreBtn - margin-top: 0 - margin-bottom: 0 - -span.ndt - color: darkblue - padding: 0 5px 0 var(--universal-margin) - -.margintop - margin-top: 25px - border-top: 1px solid grey -@media screen and (max-width: 767px) - .margintop - margin-top: 10px -</style> - -<style lang="sass"> -.news - padding-top: 10px - & > .dev-buttons - display: inline-block - & > .news-content - margin: var(--universal-margin) - & > p - margin: 10px 0 - & > br - display: block - margin-top: 10px - content: " " -</style> diff --git a/server/db/create.sql b/server/db/create.sql index 56ae4f19..84b72b99 100644 --- a/server/db/create.sql +++ b/server/db/create.sql @@ -31,14 +31,6 @@ create table Problems ( foreign key (vid) references Variants(id) ); -create table News ( - id integer primary key, - uid integer, - added datetime, - content text, - foreign key (uid) references Users(id) -); - create table Challenges ( id integer primary key, added datetime, diff --git a/server/models/News.js b/server/models/News.js deleted file mode 100644 index c10f71f2..00000000 --- a/server/models/News.js +++ /dev/null @@ -1,78 +0,0 @@ -const db = require("../utils/database"); - -/* - * Structure: - * id: integer - * added: datetime - * uid: user id (int) - * content: text - */ - -const NewsModel = -{ - create: function(content, uid, cb) - { - db.serialize(function() { - const query = - "INSERT INTO News " + - "(added, uid, content) " + - "VALUES " + - "(" + Date.now() + "," + uid + ",?)"; - db.run(query, content, function(err) { - cb(err, { id: this.lastID }); - }); - }); - }, - - getNext: function(cursor, cb) - { - db.serialize(function() { - const query = - "SELECT * " + - "FROM News " + - "WHERE added < " + cursor + " " + - "ORDER BY added DESC " + - "LIMIT 10"; //TODO: 10 currently hard-coded - db.all(query, (err, newsList) => { - cb(err, newsList); - }); - }); - }, - - getTimestamp: function(cb) - { - db.serialize(function() { - const query = - "SELECT added " + - "FROM News " + - "ORDER BY added DESC " + - "LIMIT 1"; - db.get(query, (err, ts) => { - cb(err, ts); - }); - }); - }, - - update: function(news) - { - db.serialize(function() { - let query = - "UPDATE News " + - "SET content = ? " + - "WHERE id = " + news.id; - db.run(query, news.content); - }); - }, - - remove: function(id) - { - db.serialize(function() { - const query = - "DELETE FROM News " + - "WHERE id = " + id; - db.run(query); - }); - }, -} - -module.exports = NewsModel; diff --git a/server/routes/all.js b/server/routes/all.js index 0c02129f..979b0d9c 100644 --- a/server/routes/all.js +++ b/server/routes/all.js @@ -7,6 +7,5 @@ router.use("/", require("./messages")); router.use("/", require("./users")); router.use("/", require("./variants")); router.use("/", require("./problems")); -router.use("/", require("./news")); module.exports = router; diff --git a/server/routes/news.js b/server/routes/news.js deleted file mode 100644 index e78020ef..00000000 --- a/server/routes/news.js +++ /dev/null @@ -1,55 +0,0 @@ -let router = require("express").Router(); -const access = require("../utils/access"); -const params = require("../config/parameters"); -const NewsModel = require("../models/News"); -const sanitizeHtml = require('sanitize-html'); - -router.post("/news", access.logged, access.ajax, (req,res) => { - if (params.devs.includes(req.userId)) { - const content = sanitizeHtml(req.body.news.content); - NewsModel.create(content, req.userId, (err, ret) => { - res.json(err || ret); - }); - } -}); - -router.get("/news", access.ajax, (req,res) => { - const cursor = req.query["cursor"]; - if (!!cursor && !!cursor.match(/^[0-9]+$/)) { - NewsModel.getNext(cursor, (err, newsList) => { - res.json(err || { newsList: newsList }); - }); - } -}); - -router.get("/newsts", access.ajax, (req,res) => { - // Special query for footer: just return timestamp of last news - NewsModel.getTimestamp((err, ts) => { - res.json(err || { timestamp: !!ts ? ts.added : 0 }); - }); -}); - -router.put("/news", access.logged, access.ajax, (req,res) => { - let news = req.body.news; - if ( - params.devs.includes(req.userId) && - news.id.toString().match(/^[0-9]+$/) - ) { - news.content = sanitizeHtml(news.content); - NewsModel.update(news); - res.json({}); - } -}); - -router.delete("/news", access.logged, access.ajax, (req,res) => { - const nid = req.query.id; - if ( - params.devs.includes(req.userId) && - nid.toString().match(/^[0-9]+$/) - ) { - NewsModel.remove(nid); - res.json({}); - } -}); - -module.exports = router; -- 2.44.0