-
-
Félicitations
-
Bravo, tu as gagné. Reviens demain pour une nouvelle grille.
+
+
-
-
Perdu
-
- Le mot a trouver était :
- Peut être feras-tu mieux demain ?
-
-
-
Résumé de ta partie Partager
-
Chargement de la grille en cours…
-
-
- Vous avez six essais pour deviner le mot du jour.
- Vous ne pouvez proposer que des mots commençant par la même lettre que le mot recherché, et qui se trouvent dans notre dictionnaire.
- Les lettres entourées d'un carré rouge sont bien placées,
- les lettres entourées d'un cercle jaune sont mal placées (mais présentes dans le mot).
- Les lettres qui restent sur fond bleu ne sont pas dans le mot.
- Il y a un mot par jour, entre 6 et 9 lettres, et il est identique pour tout le monde. Évitez donc les spoils et privilégiez le bouton de partage.
- En cas de soucis, vous pouvez contacter @Jonamaths sur twitter. −
- Page du projet
- Basé sur l'excellent Wordle et le regretté Motus.
- Merci à Emmanuel pour l'aide sur les mots à trouver, et à GaranceAmarante pour l'aide sur le dictionnaire.
-
-
-
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/public/jeu.css b/public/jeu.css
index 60ecea7..3399c14 100644
--- a/public/jeu.css
+++ b/public/jeu.css
@@ -7,6 +7,8 @@
--couleur-fond-grille: #0077c7;
--couleur-non-trouve: rgb(112, 112, 112);
--couleur-icone: rgb(200, 200, 200);
+ --couleur-fond-rgb: 43, 43, 43;
+ --couleur-fond: rgb(var(--couleur-fond-rgb));
}
@font-face {
@@ -17,7 +19,7 @@
body {
font-family: "Roboto Medium", Ubuntu, Arial, Helvetica, sans-serif;
font-size: 32px;
- background-color: #2b2b2b;
+ background-color: var(--couleur-fond);
height: 100vh;
text-align: center;
color: white;
@@ -52,7 +54,7 @@ body {
header {
display: grid;
- grid-template-columns: 1fr 6fr 1fr;
+ grid-template-columns: 2fr 6fr 2fr;
align-items: center;
justify-content: space-between;
width: 100%;
@@ -65,9 +67,17 @@ h1 {
margin: 0;
}
+.header-icones {
+ display: flex;
+ justify-content: space-around;
+}
+
+#configuration-regles-icone,
+#configuration-config-icone,
+#configuration-stats-icone,
#configuration-audio-icone {
height: 32px;
- width: 40px;
+ width: 32px;
}
#grille {
@@ -93,7 +103,7 @@ h1 {
}
#grille td:not(.resultat) {
- background-color: #0077c7;
+ background-color: var(--couleur-fond-grille);
}
#grille td.resultat::after {
@@ -119,9 +129,7 @@ h1 {
background-color: var(--couleur-fond-grille);
}
-#fin-de-partie-panel,
-#victoire-panel,
-#defaite-panel {
+#panel-area {
display: none;
font-size: 24px;
@@ -192,15 +200,13 @@ h1 {
cursor: initial;
}
-#regles-panel {
+.regles-panel #panel-fenetre {
font-size: 14px;
text-align: left;
}
-#regles-panel a,
-#regles-panel a:visited,
-#fin-de-partie-panel a,
-#fin-de-partie-panel a:visited {
+#panel-area a,
+#panel-area a:visited {
color: white;
}
@@ -208,3 +214,59 @@ h1 {
opacity: 0;
transition: opacity linear 1s;
}
+
+#panel-area {
+ position: fixed;
+ top: 0;
+ left: 0;
+ background-color: rgba(var(--couleur-fond-rgb), 0.45);
+ width: 100vw;
+ height: 100vh;
+ z-index: 10;
+}
+
+#panel-fenetre {
+ background-color: var(--couleur-fond);
+ width: 50%;
+ margin-left: auto;
+ margin-right: auto;
+ min-height: 400px;
+ border: 1px solid white;
+ border-radius: 0.25em;
+ margin-top: 3em;
+ display: flex;
+ flex-direction: column;
+ padding: 0.5em;
+}
+
+#panel-fenetre-header {
+ display: flex;
+ align-content: center;
+ justify-content: space-between;
+ width: calc(100% - 1em);
+ height: calc(36px + 0.75em);
+ margin-left: 0.5em;
+ margin-right: 0.5em;
+ margin-top: 0.25em;
+ margin-bottom: 0.5em;
+}
+
+#panel-fenetre-titre {
+ font-size: 36px;
+ margin: 0;
+}
+
+#panel-fenetre-bouton-fermeture {
+ text-decoration: none;
+}
+
+#panel-fenetre-bouton-fermeture-icone {
+ width: 32px;
+ height: 32px;
+}
+
+@media (max-width: 1024px) {
+ #panel-fenetre {
+ width: 90%;
+ }
+}
diff --git a/ts/configuration.ts b/ts/configuration.ts
index bfdc684..197b065 100644
--- a/ts/configuration.ts
+++ b/ts/configuration.ts
@@ -1,5 +1,6 @@
export default class Configuration {
- public static Default: Configuration = { hasAudio: false };
+ public static Default: Configuration = { hasAudio: false, afficherRegles: true };
hasAudio: boolean = false;
+ afficherRegles: boolean = true;
}
diff --git a/ts/configurationPanel.ts b/ts/configurationPanel.ts
new file mode 100644
index 0000000..bea5f31
--- /dev/null
+++ b/ts/configurationPanel.ts
@@ -0,0 +1,29 @@
+import Configuration from "./configuration";
+import PanelManager from "./panelManager";
+import Sauvegardeur from "./sauvegardeur";
+
+export default class ConfigurationPanel {
+ private readonly _panelManager: PanelManager;
+ private readonly _configBouton: HTMLElement;
+
+ public constructor(panelManager: PanelManager) {
+ this._panelManager = panelManager;
+ this._configBouton = document.getElementById("configuration-config-bouton") as HTMLElement;
+
+ this._configBouton.addEventListener(
+ "click",
+ (() => {
+ this.afficher();
+ }).bind(this)
+ );
+ }
+
+ public afficher(): void {
+ let titre = "Configuration";
+ let contenu = "";
+
+ this._panelManager.setContenu(titre, contenu);
+ this._panelManager.setClasses(["config-panel"]);
+ this._panelManager.afficherPanel();
+ }
+}
diff --git a/ts/finDePartiePanel.ts b/ts/finDePartiePanel.ts
index 30d94e2..c150340 100644
--- a/ts/finDePartiePanel.ts
+++ b/ts/finDePartiePanel.ts
@@ -1,46 +1,32 @@
import LettreResultat from "./lettreResultat";
import { LettreStatut } from "./lettreStatut";
import NotificationMessage from "./notificationMessage";
+import PanelManager from "./panelManager";
export default class FinDePartiePanel {
- private readonly _finDePartiePanel: HTMLElement;
- private readonly _victoirePanel: HTMLElement;
- private readonly _defaitePanel: HTMLElement;
- private readonly _defaitePanelMot: HTMLElement;
- private readonly _resume: HTMLPreElement;
- private readonly _resumeBouton: HTMLElement;
private readonly _datePartie: Date;
+ private readonly _panelManager: PanelManager;
+ private readonly _statsButton: HTMLElement;
private _resumeTexte: string = "";
+ private _motATrouver: string = "";
+ private _estVictoire: boolean = false;
+ private _partieEstFinie: boolean = false;
- public constructor(datePartie: Date) {
- this._finDePartiePanel = document.getElementById("fin-de-partie-panel") as HTMLElement;
- this._victoirePanel = document.getElementById("victoire-panel") as HTMLElement;
- this._defaitePanel = document.getElementById("defaite-panel") as HTMLElement;
- this._defaitePanelMot = document.getElementById("defaite-panel-mot") as HTMLElement;
- this._resume = document.getElementById("fin-de-partie-panel-resume") as HTMLPreElement;
- this._resumeBouton = document.getElementById("fin-de-partie-panel-resume-bouton") as HTMLElement;
-
+ public constructor(datePartie: Date, panelManager: PanelManager) {
this._datePartie = datePartie;
+ this._panelManager = panelManager;
+ this._statsButton = document.getElementById("configuration-stats-bouton") as HTMLElement;
- this._resumeBouton.addEventListener("click", (event) => {
- event.stopPropagation();
- if (!navigator.clipboard) {
- NotificationMessage.ajouterNotification("Votre navigateur n'est pas compatible");
- }
-
- navigator.clipboard
- .writeText(this._resumeTexte + "\n\nhttps://sutom.nocle.fr")
- .then(() => {
- NotificationMessage.ajouterNotification("Résumé copié dans le presse papier");
- })
- .catch((raison) => {
- NotificationMessage.ajouterNotification("Votre navigateur n'est pas compatible");
- });
- });
+ this._statsButton.addEventListener(
+ "click",
+ (() => {
+ this.afficher();
+ }).bind(this)
+ );
}
- public genererResume(estBonneReponse: boolean, resultats: Array
>): void {
+ public genererResume(estBonneReponse: boolean, motATrouver: string, resultats: Array>): void {
let resultatsEmojis = resultats.map((mot) =>
mot
.map((resultat) => resultat.statut)
@@ -57,20 +43,60 @@ export default class FinDePartiePanel {
);
let dateGrille = this._datePartie.getTime();
let origine = new Date(2022, 0, 8).getTime();
+ this._motATrouver = motATrouver;
+ this._estVictoire = estBonneReponse;
+ this._partieEstFinie = true;
let numeroGrille = Math.floor((dateGrille - origine) / (24 * 3600 * 1000)) + 1;
this._resumeTexte = "SUTOM #" + numeroGrille + " " + (estBonneReponse ? resultats.length : "-") + "/6\n\n" + resultatsEmojis.join("\n");
- this._resume.innerText = this._resumeTexte;
}
- public afficher(estVictoire: boolean, motATrouver: string): void {
- this._finDePartiePanel.style.display = "block";
+ private attacherPartage(): void {
+ let resumeBouton = document.getElementById("fin-de-partie-panel-resume-bouton") as HTMLElement;
+ resumeBouton.addEventListener("click", (event) => {
+ event.stopPropagation();
+ if (!navigator.clipboard) {
+ NotificationMessage.ajouterNotification("Votre navigateur n'est pas compatible");
+ }
- if (estVictoire) this._victoirePanel.style.display = "block";
- else {
- this._defaitePanelMot.innerText = motATrouver;
- this._defaitePanel.style.display = "block";
+ navigator.clipboard
+ .writeText(this._resumeTexte + "\n\nhttps://sutom.nocle.fr")
+ .then(() => {
+ NotificationMessage.ajouterNotification("Résumé copié dans le presse papier");
+ })
+ .catch((raison) => {
+ NotificationMessage.ajouterNotification("Votre navigateur n'est pas compatible");
+ });
+ });
+ }
+
+ public afficher(): void {
+ let titre: string;
+ let contenu: string;
+ if (!this._partieEstFinie) {
+ titre = "Statistiques";
+ contenu = "Vous n'avez pas encore fini votre partie du jour";
+ } else {
+ if (this._estVictoire) {
+ titre = "Félicitations";
+ contenu = "Bravo, tu as gagné. Reviens demain pour une nouvelle grille.
";
+ } else {
+ titre = "Perdu";
+ contenu = " \
+ Le mot a trouver était : " + this._motATrouver + " \
+ Peut être feras-tu mieux demain ? \
+
";
+ }
+ contenu +=
+ 'Résumé de ta partie Partager
\
+ ' +
+ this._resumeTexte +
+ " ";
}
+ this._panelManager.setContenu(titre, contenu);
+ this._panelManager.setClasses(["fin-de-partie-panel"]);
+ if (this._partieEstFinie) this.attacherPartage();
+ this._panelManager.afficherPanel();
}
}
diff --git a/ts/gestionnaire.ts b/ts/gestionnaire.ts
index 32a0fb2..6d1648e 100644
--- a/ts/gestionnaire.ts
+++ b/ts/gestionnaire.ts
@@ -9,14 +9,20 @@ import SauvegardeStats from "./sauvegardeStats";
import Sauvegardeur from "./sauvegardeur";
import Configuration from "./configuration";
import PartieEnCours from "./partieEnCours";
+import PanelManager from "./panelManager";
+import ReglesPanel from "./reglesPanel";
+import ConfigurationPanel from "./configurationPanel";
export default class Gestionnaire {
private readonly _dictionnaire: Dictionnaire;
private readonly _grille: Grille;
private readonly _input: Input;
- private readonly _victoirePanel: FinDePartiePanel;
+ private readonly _reglesPanel: ReglesPanel;
+ private readonly _finDePartiePanel: FinDePartiePanel;
+ private readonly _configurationPanel: ConfigurationPanel;
private readonly _propositions: Array;
private readonly _resultats: Array>;
+ private readonly _panelManager: PanelManager;
private _motATrouver: string;
private _compositionMotATrouver: { [lettre: string]: number };
@@ -43,9 +49,14 @@ export default class Gestionnaire {
this._propositions = new Array();
this._resultats = new Array>();
this._compositionMotATrouver = this.decompose(this._motATrouver);
- this._victoirePanel = new FinDePartiePanel(this._datePartieEnCours);
+ this._panelManager = new PanelManager();
+ this._reglesPanel = new ReglesPanel(this._panelManager);
+ this._finDePartiePanel = new FinDePartiePanel(this._datePartieEnCours, this._panelManager);
+ this._configurationPanel = new ConfigurationPanel(this._panelManager);
this.chargerPropositions(partieEnCours.propositions);
+
+ this.afficherReglesSiNecessaire();
}
private chargerPartieEnCours(): PartieEnCours {
@@ -110,19 +121,20 @@ export default class Gestionnaire {
let isBonneReponse = resultats.every((item) => item.statut === LettreStatut.BienPlace);
this._propositions.push(mot);
this._resultats.push(resultats);
+
+ if (isBonneReponse || this._propositions.length === this._maxNbPropositions) {
+ this._finDePartiePanel.genererResume(isBonneReponse, this._motATrouver, this._resultats);
+ this.enregistrerPartieDansStats();
+ }
+
this._grille.validerMot(mot, resultats, isBonneReponse, skipAnimation, () => {
this._input.updateClavier(resultats);
if (isBonneReponse || this._propositions.length === this._maxNbPropositions) {
this._input.bloquer();
- this._victoirePanel.afficher(isBonneReponse, this._motATrouver);
+ this._finDePartiePanel.afficher();
}
});
- if (isBonneReponse || this._propositions.length === this._maxNbPropositions) {
- this._victoirePanel.genererResume(isBonneReponse, this._resultats);
- this.enregistrerPartieDansStats();
- }
-
this.sauvegarderPartieEnCours();
}
@@ -170,4 +182,10 @@ export default class Gestionnaire {
return resultats;
}
+
+ private afficherReglesSiNecessaire(): void {
+ if (this._config.afficherRegles !== undefined && !this._config.afficherRegles) return;
+
+ this._reglesPanel.afficher();
+ }
}
diff --git a/ts/panelManager.ts b/ts/panelManager.ts
new file mode 100644
index 0000000..074c21e
--- /dev/null
+++ b/ts/panelManager.ts
@@ -0,0 +1,66 @@
+export default class PanelManager {
+ private readonly _panelArea: HTMLElement;
+ private readonly _panelFenetre: HTMLElement;
+ private readonly _panelTitre: HTMLElement;
+ private readonly _panelContenu: HTMLElement;
+ private readonly _panelFermetureBouton: HTMLElement;
+
+ public constructor() {
+ this._panelArea = document.getElementById("panel-area") as HTMLElement;
+ this._panelFenetre = document.getElementById("panel-fenetre") as HTMLElement;
+ this._panelTitre = document.getElementById("panel-fenetre-titre") as HTMLElement;
+ this._panelContenu = document.getElementById("panel-fenetre-contenu") as HTMLElement;
+ this._panelFermetureBouton = document.getElementById("panel-fenetre-bouton-fermeture") as HTMLElement;
+
+ this._panelArea.addEventListener(
+ "click",
+ ((event: Event) => {
+ event.stopPropagation();
+ this.cacherPanel();
+ }).bind(this)
+ );
+
+ this._panelFenetre.addEventListener(
+ "click",
+ ((event: Event) => {
+ event.stopPropagation(); // On évite ainsi de fermer le panel en appuyant sur la fenêtre
+ }).bind(this)
+ );
+
+ this._panelFermetureBouton.addEventListener(
+ "click",
+ ((event: Event) => {
+ event.stopPropagation();
+ this.cacherPanel();
+ }).bind(this)
+ );
+ }
+
+ public afficherPanel(): void {
+ this._panelArea.style.display = "block";
+ }
+
+ public cacherPanel(): void {
+ this._panelArea.style.display = "none";
+ }
+
+ public setContenu(titre: string, contenu: string): void {
+ this._panelTitre.innerText = titre;
+ this._panelContenu.innerHTML = contenu;
+ }
+
+ public setClasses(classes: Array): void {
+ this._panelArea.className = "";
+ classes.forEach((nomClasse) => this._panelArea.classList.add(nomClasse));
+ }
+
+ public setCallbackFermeture(callback: () => void): void {
+ this._panelFermetureBouton.addEventListener(
+ "click",
+ ((event: Event) => {
+ callback();
+ }).bind(this),
+ { once: true }
+ );
+ }
+}
diff --git a/ts/reglesPanel.ts b/ts/reglesPanel.ts
new file mode 100644
index 0000000..d4d6552
--- /dev/null
+++ b/ts/reglesPanel.ts
@@ -0,0 +1,47 @@
+import Configuration from "./configuration";
+import PanelManager from "./panelManager";
+import Sauvegardeur from "./sauvegardeur";
+
+export default class ReglesPanel {
+ private readonly _panelManager: PanelManager;
+ private readonly _rulesBouton: HTMLElement;
+
+ public constructor(panelManager: PanelManager) {
+ this._panelManager = panelManager;
+ this._rulesBouton = document.getElementById("configuration-regles-bouton") as HTMLElement;
+
+ this._rulesBouton.addEventListener(
+ "click",
+ (() => {
+ this.afficher();
+ }).bind(this)
+ );
+ }
+
+ public afficher(): void {
+ let titre = "Règles";
+ let contenu =
+ ' \
+ Vous avez six essais pour deviner le mot du jour. \
+ Vous ne pouvez proposer que des mots commençant par la même lettre que le mot recherché, et qui se trouvent dans notre dictionnaire. \
+ Les lettres entourées d\'un carré rouge sont bien placées, \
+ les lettres entourées d\'un cercle jaune sont mal placées (mais présentes dans le mot). \
+ Les lettres qui restent sur fond bleu ne sont pas dans le mot. \
+ Il y a un mot par jour, entre 6 et 9 lettres, et il est identique pour tout le monde. Évitez donc les spoils et privilégiez le bouton de partage. \
+ En cas de soucis, vous pouvez contacter @Jonamaths sur twitter. − \
+ Page du projet \
+ Basé sur l\'excellent Wordle et le regretté Motus. \
+ Merci à Emmanuel pour l\'aide sur les mots à trouver, et à GaranceAmarante pour l\'aide sur le dictionnaire. \
+
';
+
+ this._panelManager.setContenu(titre, contenu);
+ this._panelManager.setClasses(["regles-panel"]);
+ this._panelManager.setCallbackFermeture(() => {
+ Sauvegardeur.sauvegarderConfig({
+ ...(Sauvegardeur.chargerConfig() ?? Configuration.Default),
+ afficherRegles: false,
+ });
+ });
+ this._panelManager.afficherPanel();
+ }
+}